彬婧的月亮2

文章目录

  • 前言
  • 项目介绍
  • 技术架构
  • 后端构建及部署
    • 下载docker windows 桌面版
    • 本地环境docker部署hasura+postgresql(数据库+api自动生成)
    • 创建数据库,创建表,字段都可以按照官方文档来做
    • 绑定表之间的查询关系
    • api接口测试
    • 准备一个本地连接数据库工具(方便写触发器函数)
    • 编写触发器函数
    • 绑定触发器
    • hasura数据异常解决方法(与数据库不同步会出现异常情况)
    • 添加定时任务事件(发送订阅,获取微信登录接口token,定时查询用户任务完成情况)
    • 后端action(特殊功能api:获取token,定时任务,发送订阅消息,用户头像存储等)
      • 初始化node项目
      • node服务器时间与本地不同步的问题
      • 更新用户自定义头像,用户名,性别
      • 获取头像
      • 获取openID
      • 定时任务计算用户当天分数
      • 获取微信接口调用凭证
      • 定时任务发送微信小程序订阅消息
      • Dockerfile文件
      • 构建镜像
      • 保存镜像
    • hasura+postgresql+action部署到服务器
      • 购买服务器,安装宝塔面板,安装docker
      • 配置端口
    • 构建action
    • 创建compose
      • compose模板(docker-compose.yml文件内容追加进来)
      • 添加compose项目
    • 数据卷同步数据
    • 接口地址修改
    • 访问线上服务
    • 修改为小程序能使用的https接口
      • 购买及解析域名
      • 小程序后台添加域名地址
      • 添加站点
      • 申请ssl
      • Nginx反向代理
    • 测试地址
      • 好像可以了就可以了的样子
  • 前端
    • 创建项目
    • 依赖
    • colorUI
    • mescroll-body
    • uview2.0
    • 小程序分享功能
    • 请求接口
    • 检查订阅消息权限,请求订阅消息
    • 登录
  • 审核不通过
  • 源码地址

前言

有始有终,即使礼物她收不到了

项目介绍

一个待办小程序,自己可以制定一些计划,有了计划就有待办任务,任务需要每天循环来执行
任务前半个小时,系统会发送微信订阅提醒用户去执行计划
每天可以备注任务阶段性总结信息
当天的计划没有完成的,系统将在0:00自动计算并扣除分值
添加一条计划需要1分,没有分就需要分享转发来赚取
小项目就没有做权限验证,仅仅做了微信登录而已

技术架构

前端采用vue2.0脚手架构建 uniapp
ui组件采用colorUI+uview2.0
数据存储采用hasura+postgresql
api接口采用graphql查询语言
一些特殊的接口采用nodejs+fastify来完成
项目采用docker+宝塔面板部署

后端构建及部署

下载docker windows 桌面版

彬婧的月亮2_第1张图片

本地环境docker部署hasura+postgresql(数据库+api自动生成)

彬婧的月亮2_第2张图片
Quickstart with Docker

  • 获取compose文件
    curl https://raw.githubusercontent.com/hasura/graphql-engine/stable/install-manifests/docker-compose/docker-compose.yaml -o docker-compose.yml
  • docker-compose.yml文件内容
version: '3.6'
services:
  postgres:
    image: postgres:12
    ports:
    - "5432:5432"
    restart: always
    environment:
      POSTGRES_PASSWORD: postgrespassword
  graphql-engine:
    image: hasura/graphql-engine:v2.0.10
    ports:
    - "8080:8080"
    depends_on:
    - "postgres"
    restart: always
    environment:
      ## postgres database to store Hasura metadata
      HASURA_GRAPHQL_METADATA_DATABASE_URL: postgres://postgres:postgrespassword@postgres:5432/postgres
      ## this env var can be used to add the above postgres database to Hasura as a data source. this can be removed/updated based on your needs
      PG_DATABASE_URL: postgres://postgres:postgrespassword@postgres:5432/postgres
      ## enable the console served by server
      HASURA_GRAPHQL_ENABLE_CONSOLE: "true" # set to "false" to disable console
      ## enable debugging mode. It is recommended to disable this in production
      HASURA_GRAPHQL_DEV_MODE: "true"
      HASURA_GRAPHQL_ENABLED_LOG_TYPES: startup, http-log, webhook-log, websocket-log, query-log
      ## uncomment next line to run console offline (i.e load console assets from server instead of CDN)
      # HASURA_GRAPHQL_CONSOLE_ASSETS_DIR: /srv/console-assets
      ## uncomment next line to set an admin secret
      # HASURA_GRAPHQL_ADMIN_SECRET: myadminsecretkey
volumes:
  db_data:


  • 进入docker-compose.yml文件所在目录,运行命令构建compose
    docker compose up -d

  • docker ps -a 可以查看容器状态,或者在docker桌面工具也可以查看
    在这里插入图片描述

  • 访问控制台
    http://localhost:8080/console

创建数据库,创建表,字段都可以按照官方文档来做

彬婧的月亮2_第3张图片

绑定表之间的查询关系

彬婧的月亮2_第4张图片
彬婧的月亮2_第5张图片

api接口测试

彬婧的月亮2_第6张图片

彬婧的月亮2_第7张图片

准备一个本地连接数据库工具(方便写触发器函数)

彬婧的月亮2_第8张图片
彬婧的月亮2_第9张图片

编写触发器函数

彬婧的月亮2_第10张图片

绑定触发器

彬婧的月亮2_第11张图片
彬婧的月亮2_第12张图片

  • 在hasura中修改触发器(修改完之后点击run,数据库也会同步)
    彬婧的月亮2_第13张图片
    彬婧的月亮2_第14张图片

hasura数据异常解决方法(与数据库不同步会出现异常情况)

彬婧的月亮2_第15张图片

添加定时任务事件(发送订阅,获取微信登录接口token,定时查询用户任务完成情况)

彬婧的月亮2_第16张图片
彬婧的月亮2_第17张图片

彬婧的月亮2_第18张图片
彬婧的月亮2_第19张图片

后端action(特殊功能api:获取token,定时任务,发送订阅消息,用户头像存储等)

初始化node项目

彬婧的月亮2_第20张图片

node服务器时间与本地不同步的问题

// const moment = require("moment"); // 不需要 const moment = require("moment-timezone"); // moment-timezone包含了moment moment.tz.setDefault("Asia/Shanghai");

更新用户自定义头像,用户名,性别

 fastify.post("/upload", async function (req, reply) {
    fastify.pg.connect(onConnect);
    // process a single file
    // also, consider that if you allow to upload multiple files
    // you must consume all files otherwise the promise will never fulfill
    const data = await req.file();

    // 获取到的fieldname是用户id+用户昵称
    //把id和昵称拆分开
    const gender = data.fieldname.match(/(\S*)\+/)[1].slice(0, 1);
    const user_id = data.fieldname.match(/(\S*)\+/)[1].slice(1);
    const user_name = data.fieldname.match(/\+(\S*)/)[1];

    // 将文件名与后缀拼接 所有类型的图片都转化为.jpg 前台显示头像统一用 性别+user_id.jpg user_id的第一个字符为性别
    const fileName = user_id + ".jpg";

    // 图片保存路径
    const pathSave = path.join(__dirname, "/upload/", fileName);

    await pump(data.file, fs.createWriteStream(pathSave));

    // be careful of permission issues on disk and not overwrite
    // sensitive files that could cause security risks

    // also, consider that if the file stream is not consumed, the promise will never fulfill

    // 把用户信息更新到数据库

    async function onConnect(err, client, release) {
      if (err) {
        console.log(err, "数据库错误");
        return await err;
      }

      client.query(
        `UPDATE public."user"
      SET  user_name='${user_name}', user_gender='${gender}', "avatarUrl"='${baseUrl}/getImg?id=${fileName}'
      WHERE id='${user_id}';`,
        async function onResult(err, result) {
          // release();
          const resData = await (err || result.rows);

        
          if (resData) {
            console.log(resData, "数据库resdata");
          }

          release();
        }
      );
    }


    reply.send({ user_name, gender, fileName, pathSave });
  });

获取头像

// 获取头像
  fastify.get("/getImg", async (request, reply) => {
   
    const fileName = request.query.id;
    const filePath = path.join(__dirname, "/upload/", fileName);
 
    //格式必须为 binary 否则会出错
    var content = fs.readFileSync(filePath);

    // response.send(content);
    reply.code(200).header("Content-Type", "image/png").send(content);

  });

获取openID

  // 微信登录获取openID
  fastify.route({
    method: "POST",
    url: "/wxLogin",
    handler: async function (request, reply) {
     
      const options = {
        method: "get",
        url: "https://api.weixin.qq.com/sns/jscode2session",
        qs: {
          appid: appid,
          secret: sss,
          js_code: request.body.code,
          grant_type: "authorization_code",
        },
      };

      let sessionData = await rp(options);

      if (sessionData) {
        return reply.send(sessionData);
      }
    },
  });

定时任务计算用户当天分数

 // 定时任务计算用户当天分数
  fastify.route({
    method: "POST",
    url: "/action/selectUserToDoStatus",
    handler: function (request, reply) {
      let resData = null;

  
      fastify.pg.connect(onConnect);
      async function onConnect(err, client, release) {
        if (err) return await err;

        client.query(
          `SELECT  user_id ,count(todo_date)
          FROM public.todo_item_need_do WHERE todo_date='${moment().format(
            "yyyy-MM-DD"
          )}' AND todo_status=false
          GROUP BY user_id 
          ;`,
          async function onResult(err, result) {
            resData = await (err || result.rows);

            // 如果查询到有未完成的任务,就给用户减去对应分值,添加一条减分记录
            if (resData.length > 0) {
          
              //生成插入语句
              let insertStr = "";

              for (const item of resData) {
                insertStr += `INSERT INTO public.score_item(
                  score_item_number,  scores_source,  user_id,  scores_source_des)
                 VALUES ( -${item.count}, 6, '${item.user_id}', '每日任务完成情况统计');`;
              }
              await client.query(insertStr, function onResult(err, result) {
                release();
                reply.send(err || result);
              });
            }
          }
        );
      }
    },
  });

获取微信接口调用凭证

 async function getToken() {
    //数据库连接成功 请求token-------------
    // GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
    const options = {
      method: "get",
      url: "https://api.weixin.qq.com/cgi-bin/token",
      qs: {
        appid: appid,
        secret: sss,
        grant_type: "client_credential",
      },
    };

    let sessionData = await rp(options);

    if (sessionData) {

      return JSON.parse(sessionData).access_token;
    } else {
      return "getTokeError";
    }
  }

  // 获取微信接口调用凭证 
  fastify.route({
    method: "POST",
    url: "/get_access_token",
    handler: async function (request, reply) {
      try {
    

        const client = await fastify.pg.connect();

        const accessToken = await getToken();

        if (accessToken) {
         
          const updateRes = await client.query(
            `
        UPDATE public."acc_tok "
        SET acc_tok = '${acc_tok }',nums=nums+1
            WHERE id='a5c24b324r1-43af-43ghu33308d-9815oy8f-c052hg57e1212a6d';
          `
          );
          if (updateRes) {
            return `${moment().format("yyyy-MM-DD HH:mm:ss")}:获取token成功!`;
          } else {
            return `${moment().format("yyyy-MM-DD HH:mm:ss")}:获取token失败!`;
          }
        }
      } catch (r) {
        request.log.error("获取微信接口调用凭证");
        throw new Error(e);
      }
    },
  });

定时任务发送微信小程序订阅消息

// 定时任务发送微信小程序订阅消息
  fastify.route({
    method: "POST",
    url: "/sendSub",
    handler: async function (request, reply) {
   
      try {
        const client = await fastify.pg.connect();
        const nowTime = moment().format("HH:mm");
        const addTime = moment().add(30, "minutes").format("HH:mm");
        const { rows } = await client.query(
          `
            select i.id as item_id,i.todo_item_name,
            i.todo_item_description,
            i.todo_remind_time,
            i.todo_start_time,
            i.todo_end_time,
            i.todo_item_remind,
            n.id  as need_id,
            n.todo_date  as need_date,
            o.openid  as open_id,
            t.access_token  as token
            from public.todo_item_need_do n,
            public.todo_item i,
            public.user o,
            public.access_token t
            where
            n.todo_status = false 
            and n.todo_date = '${moment().format("yyyy-MM-DD")}'
            and n.todo_item_id = i.id
            and i.user_id = o.id
            and i.todo_item_remind = true
            and i.todo_remind_time between '${nowTime}' and '${addTime}'
          `
        );
        client.release();

        if (rows.length == 0) {
          return `${moment().format(
            "yyyy-MM-DD HH:mm:ss"
          )}:数据库没有查询到相关记录!`;
        }

        // 循环发送订阅
        const resData = await sendSubfor(rows).then((res) => {
          return res;
        });

        console.log(resData);
        let array = [];

        for (const item of resData) {
          let sessionData = null;
          sessionData = await rp(item);
          if (sessionData) {
            array.push(sessionData);
          }
        }

        if (array.length == resData.length) {
          return array;
        }
      } catch (e) {
        request.log.error("定时任务发送微信小程序订阅消息");
        throw new Error(e);
      }
    },
  });
  async function sendSubfor(data) {
    return new Promise(async function (resolve, reject) {
      try {
        let item = null;
        let options = null;
        let token = data[0].token;
        let resData = [];
        for (let index = 0; index < data.length; index++) {
          //  console.log(data[index],index,data.length);
          item = data[index];

          options = {
            method: "POST",
            url: `https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=${token}`,
            body: {
              touser: item.open_id,
              template_id: "bAgG6FsdI8SJTJ7BYMffqPbmdeSwAqB_ufp967yeBEhyDbUjY",
              data: {
                thing1: {
                  value: item.todo_item_name.substring(0, 19), //20个以内字符	可汉字、数字、字母或符号组合
                },
                thing4: {
                  value: item.todo_item_description.substring(0, 19),
                },
                time10: {
                  value: moment(item.todo_start_time).format("yyyy年MM月DD日"),
                },
                time11: {
                  value: moment(item.todo_end_time).format("yyyy年MM月DD日"),
                },
              },
            },
            json: true, // Automatically stringifies the body to JSON
          };

          resData.push(options);
        }

        if (resData?.length == data.length) {
        
          resolve(resData);
        }
      } catch (e) {
        reject(e);
      }
    });
  }

Dockerfile文件

在当前目录创建Dockerfile文件


FROM node:current-alpine3.12

# 创建并切换到应用目录。
WORKDIR /todo_action_home/



WORKDIR /todo_action_home/todo_action


# 复制本地代码到容器镜像。

COPY ./server.js /todo_action_home/todo_action
COPY ./routes.js /todo_action_home/todo_action


COPY package*.json ./

# 安装生产环境依赖。
RUN npm install

VOLUME ["/todo_action_home/todo_action"]


EXPOSE 3000

# 启动容器时运行服务。 
CMD [ "node", "server.js" ]

构建镜像

docker build -t todo_action:1.0 .

保存镜像

docker save -o todo_action_1.0.tar todo_action:1.0

hasura+postgresql+action部署到服务器

购买服务器,安装宝塔面板,安装docker

彬婧的月亮2_第21张图片

配置端口

彬婧的月亮2_第22张图片

构建action

  • 上传action镜像到服务器
    彬婧的月亮2_第23张图片
  • 命令行加载镜像
    docker load -i todo_action_1.0.tar

创建compose

compose模板(docker-compose.yml文件内容追加进来)

彬婧的月亮2_第24张图片

version: '3.6'
services:
  action:
    image: todo_action:1.0
    ports:
    - "3000:3000"
    depends_on:
    - "postgres"
    restart: always
  postgres:
    image: postgres:12
    ports:
    - "5432:5432"
    restart: always
    environment:
      POSTGRES_PASSWORD: postgrespassword
  graphql-engine:
    image: hasura/graphql-engine:v2.18.0
    ports:
    - "8080:8080"
    depends_on:
    - "postgres"
    restart: always
    environment:
      ## postgres database to store Hasura metadata
      HASURA_GRAPHQL_METADATA_DATABASE_URL: postgres://postgres:postgrespassword@postgres:5432/postgres
      ## this env var can be used to add the above postgres database to Hasura as a data source. this can be removed/updated based on your needs
      PG_DATABASE_URL: postgres://postgres:postgrespassword@postgres:5432/postgres
      ## enable the console served by server
      HASURA_GRAPHQL_ENABLE_CONSOLE: "true" # set to "false" to disable console
      ## enable debugging mode. It is recommended to disable this in production
      HASURA_GRAPHQL_DEV_MODE: "true"
      HASURA_GRAPHQL_ENABLED_LOG_TYPES: startup, http-log, webhook-log, websocket-log, query-log
      ## uncomment next line to run console offline (i.e load console assets from server instead of CDN)
      # HASURA_GRAPHQL_CONSOLE_ASSETS_DIR: /srv/console-assets
      ## uncomment next line to set an admin secret
      ## HASURA_GRAPHQL_ADMIN_SECRET: myadminsecretkeyweipengyu
volumes:
  db_data:


添加compose项目

彬婧的月亮2_第25张图片
彬婧的月亮2_第26张图片

数据卷同步数据

彬婧的月亮2_第27张图片

  • 找到本地docker数据存储位置
    \\wsl$\docker-desktop-data\mnt\wsl\docker-desktop-data\data\docker\volumes

  • 上传数据到服务器数据卷对应位置进行覆盖
    postgresql
    彬婧的月亮2_第28张图片
    action
    彬婧的月亮2_第29张图片

  • hasura更新数据元
    彬婧的月亮2_第30张图片

  • 重启容器
    彬婧的月亮2_第31张图片

接口地址修改

  • 三个容器之间互相访问要用容器网络地址
    彬婧的月亮2_第32张图片
  • hasura 访问 action
    彬婧的月亮2_第33张图片

访问线上服务

  • 主机地址+端口号
    彬婧的月亮2_第34张图片
    彬婧的月亮2_第35张图片

修改为小程序能使用的https接口

购买及解析域名

小程序后台添加域名地址

添加站点

彬婧的月亮2_第36张图片

申请ssl

彬婧的月亮2_第37张图片

Nginx反向代理

彬婧的月亮2_第38张图片
彬婧的月亮2_第39张图片


#PROXY-START/apiv

location /apiv
{
    proxy_pass http://127.0.0.1:8080/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header REMOTE-HOST $remote_addr;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    proxy_http_version 1.1;
    # proxy_hide_header Upgrade;

    add_header X-Cache $upstream_cache_status;
    #Set Nginx Cache

    set $static_filetPztmqon 0;
    if ( $uri ~* "\.(gif|png|jpg|css|js|woff|woff2)$" )
    {
        set $static_filetPztmqon 1;
        expires 1m;
    }
    if ( $static_filetPztmqon = 0 )
    {
        add_header Cache-Control no-cache;
    }
}
#PROXY-END/


#PROXY-START/apiv

location /action
{
    proxy_pass http://127.0.0.1:3000;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header REMOTE-HOST $remote_addr;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    proxy_http_version 1.1;
    # proxy_hide_header Upgrade;

    add_header X-Cache $upstream_cache_status;
    #Set Nginx Cache

    set $static_filetPztmqon 0;
    if ( $uri ~* "\.(gif|png|jpg|css|js|woff|woff2)$" )
    {
        set $static_filetPztmqon 1;
        expires 1m;
    }
    if ( $static_filetPztmqon = 0 )
    {
        add_header Cache-Control no-cache;
    }
}
#PROXY-END/

彬婧的月亮2_第40张图片

测试地址

好像可以了就可以了的样子

彬婧的月亮2_第41张图片

前端

创建项目

彬婧的月亮2_第42张图片
彬婧的月亮2_第43张图片

依赖

彬婧的月亮2_第44张图片

colorUI

彬婧的月亮2_第45张图片

mescroll-body

彬婧的月亮2_第46张图片

uview2.0

小程序分享功能

  • 在main.js引入
    // 小程序分享功能 import share from '@/common/share.js' // 分享朋友圈 Vue.mixin(share)
// :data-item='item' 是传给onShareAppMessage的数据
						<view class=" flex padding-sm justify-between align-center bg-white" >
							<button class="cu-btn  shareBtn sm" type="default" :data-item='item' data-name="shareBtn" open-type="share">
								<text class="cuIcon-weixin text-olive">text> 转发button>
						view>
// share.js
export default {
	data() {
		return {
shareUrl:'/uploads/20230207/4f8cd2699d32510f732267b0221bb6ad.jpg',
userInfo:null
		}
	},
	
	onLoad: function() {
		this.userInfo=uni.getStorageSync('userInfo');
		this.shareUrl = this.$imageURL
		wx.showShareMenu({
			withShareTicket: true,
			menus: ["shareAppMessage", "shareTimeline"]
		})
	},
	onShareAppMessage(res) {
		this.addScores()
		let that = this;
		console.log(res,'++++',that.$scope,"转发-->");
		let imageUrl = that.shareUrl || '';
		if (res.from === 'button') {
			let item = res.target.dataset.item
			console.log(item,"utem");
		//这块需要传参,不然链接地址进去获取不到数据
			let path = `/pages/todo_item_note/index` + `?todo_item_id=` + item.id;
			
			return {
				title: item.todo_item_name,
				path: path,
				imageUrl: item.user.avatarUrl
			};
		}
		if (res.from === 'menu') {
		
			return {
				title: '我正在靠近自己的愿望...你来监督我吧!',
				path: '/pages/index/index',
				imageUrl: imageUrl
			};
		}
		
	},
	// 分享到朋友圈
	onShareTimeline(res) {
	
		console.log(res,"分享到朋友圈");
		this.addScores()
		return {
			title: '我正在靠近自己的愿望...你来监督我吧!',
			path: '/pages/index/index',
			imageUrl: this.shareUrl
		};
	},
	methods: {
	// 分享成不成功积分都加1,腾讯把回调函数关闭了,没有办法
	addScores(){
		this.$addScore(this.userInfo.id).then(res=>{
			console.log(res,"分享添加积分成功!");
			
		}).catch(err=>{
			
			console.log(err,"分享添加积分失败");
		})
	}
	}
}

请求接口


import Request from 'luch-request'

const httpGraphql = new Request()


//请求拦截器
httpGraphql.interceptors.request.use((config) => { // 可使用async await 做异步操作
	//const token = uni.getStorageSync('token');
	// if (token) {
	config.header = {
		Authorization: "xxxxxxx",
		"x-hasura-admin-secret":''
	}
	//}

	if (config.method === 'POST') {
	    config.data = JSON.stringify(config.data);
	}

    // console.log("请求拦截器");
	return config
}, error => {
	return Promise.resolve(error)
})

// 响应拦截器
httpGraphql.interceptors.response.use((response) => {

	console.log(response,"响应拦截器");

	let res = {}
	if(response&&response.statusCode===200){
		res.code = 200,
		res.msg="ok",
		res.data=response.data.data
	}else{
		res.code = 0,
		res.msg="error",
		res.data=''
	}

   
	return res
}, (error) => {
	//未登录时清空缓存跳转
	// if (error.statusCode == 401) {
	//     uni.clearStorageSync();
	//     uni.switchTab({
	//         url: "/pages/index/index.vue"
	//     })
	// }

  

	return Promise.resolve(error)
})


export default httpGraphql




import httpGraphql from "./graphql";
import gql from "graphql-tag";
import moment from 'moment'
import {
	print
} from "graphql";


const graphqlUrl = "/apiv/v1/graphql";
// 注册及更新用户,注册时送10分
export function checkUser(variables) {
	let postData = gql`
  mutation insert_user_one_on_conflict($openid: String = "", $scores_number: Int = 10) {
    insert_user_one(object: {openid: $openid, scores: {data: {scores_number: $scores_number}, on_conflict: {constraint: scores_user_id_key}}}, on_conflict: {constraint: user_openid_key, where: {}, update_columns: openid}) {
      avatarUrl
      user_name
      user_gender
      user_status
      openid
      id
    }
  }

  `;
	return httpGraphql.post(graphqlUrl, {
		query: print(postData),
		variables,

	});
}

检查订阅消息权限,请求订阅消息

import Vue from 'vue'

// 用户点击添加按钮之前检查订阅消息权限,未开启提示前往开启,已开启请求订阅消息
export function checkAndRequestSubscribeMessage() {

// 为了保证用户返回到页面再添加数据,采用promise
	return new Promise(function(resolve, reject) { 
	
		uni.getSetting({
			withSubscriptions: true,
			success(res) {


				// 订阅消息总开关是否开启
				if (!res?.subscriptionsSetting?.mainSwitch) {

					uni.showModal({
						title: '提示',
						content: '当前暂未开启接消息提醒,是否前往设置页开启?',
						success(res) {
							if (res.confirm) {
								wx.openSetting().then(res => {

									resolve('ok')
								}).catch(err => {
									resolve('ok')
								})
							} else {
								resolve('ok')
							}
						},
						fail() {
							resolve('ok')
						}

					})
				} else {


					uni.requestSubscribeMessage({
						tmplIds: Vue.prototype.$get_tmplIds,
						complete() {
							resolve('ok')
						}

					})
				}
			}
		})
	})

}

			// 添加或者修改任务时调用订阅
			sbumitBefore(){
				checkAndRequestSubscribeMessage().then(res=>{
					
					// 只要res == ok 说明已经返回到该页面,继续添加任务
				}).catch(err=>{
					
				}).finally(e=>{
					
					// 说明已经返回到该页面,继续添加任务,同不同意接受订阅消息都要给用户添加数据
					this.submit()
				})
			},

登录

uni.getUserProfile({
					desc: "用于完善用户资料",
					lang: "zh_CN",
					success: (res) => {
						// console.log(res)
						// that.wxlogin(res.userInfo);
						if (res.errMsg === "getUserProfile:ok" && res.userInfo != undefined) {
							let userInfo = res.userInfo
							// 调用接口请求openID
							uni.login({
								success(codeData) {
										// 请求action,获取openID
									console.log(codeData, "uni.login-codeData")
								
									
									const {
									
										openid,
									
									} = userInfo
								
									uni.request({
										url: that.$baseUrl+'/wxLogin',
										method: 'POST',
										header:{
											'Content-Type' : 'application/json'
										},
										data: {
											
											openid,
										
											code:codeData.code,
											key:''
										},
										success: res => {
											console.log(res,"wxLogin------------>>");
											if(res.statusCode===200&&res.data.openid){
												let variables = {
													openid:res.data.openid,
													scores_number: 10,
												}
												checkUser(variables).then(res => {
													console.log(res, "checkUser");
													if (res.code === 200 && res.data
														.insert_user_one
														.user_status === 1) {
														// 登录成功,保存用户数据,跳转到首页
														uni.setStorageSync('userInfo',
															res.data
															.insert_user_one)
														getApp().globalData.userInfo =
															res.data.insert_user_one
												
													
														that.gotoPage()
													} else if (res.code === 200 && res
														.data.insert_user_one
														.user_status === 0) {
														try {
															uni.clearStorageSync();
														} catch (e) {
															// error
														}
														// 账号禁用,提示用户
														uni.showModal({
															title: "账号禁用",
															content: "请联系管理员!"
														})
													} else {
														try {
															uni.clearStorageSync();
														} catch (e) {
															// error
														}
														// 获取用户信息失败,提示重试
														uni.showModal({
															title: "提示",
															content: "获取用户信息失败,请重试!"
														})
													}
												}).catch(err => {
													console.log(err, "checkUser");
												})
											}else{
												uni.showModal({
													title: "提示0",
													content: "action未返回openID"
												})
											}
										},
										fail: err => {
											console.log(err,"wxLogin------------>>");
											uni.showModal({
												title: "提示2",
												content: "获取微信接口失败,请重试!"
											})
										},
										complete: () => {}
									});

								
								},
							});
						} else {
							uni.showModal({
								content: "uni.getUserProfile获取用户信息失败!",
								title: "提示"
							})
						}
					},
					fail(err) {
						console.log(err, "err");
						uni.showModal({
							content: '网络状况不佳或者基础库高于2.7.0',
							title: "uni.getUserProfile-fail获取用户信息失败!"
						})
					},
				});

送给彬婧
2023年2月17日04:25:08

审核不通过

彬婧的月亮2_第47张图片
彬婧的月亮2_第48张图片

  • 由于审核通不过,砍了一些功能
  • 小程序码
    彬婧的月亮2_第49张图片

源码地址

todo
action

你可能感兴趣的:(彬婧的月亮,微信小程序,graphql,node.js,postgresql,docker)