【微信小程序开发】小程序微信用户授权登录(用户信息&手机号)

🥳🥳Welcome Huihui's Code World ! !🥳🥳

接下来看看由辉辉所写的关于小程序的相关操作吧

目录

🥳🥳Welcome Huihui's Code World ! !🥳🥳

授权流程讲解

一.用户信息授权登录

1.wx.login

2.wx.getUserProfile

3.代码

WXML

JS

二.用户信息授权登录之后台交互

前期准备

①准备数据接口

②密钥以及appid

后端代码

WXML

JS

utils/user.js【封装的代码块】

三.手机号授权登录之后台交互

后端代码

WXML

JS

四.投票界面与后台交互

1.效果预览

2.代码演示

vote/list.wxml

 vote/list.wxss

vote/list.js

vote/addvote.wxml

 vote/addvote.wxss

vote/addvote.js

vote/many.wxml

 vote/many.wxss

vote/many.js


授权流程讲解

我们在使用微信中的小程序时,都会要我们进行授权,例如下面这样

那么这样的用户授权时怎么实现的呢,这一篇主要就是讲解用户授权登录的流程!!!

图片说明:

1.客户端调用 wx.login() 获取 临时登录凭证code,通过 wx.request() 发起网络请求,将 code 传给服务端
2、服务端使用 code + appid + appsecret 向微信换取 (调用 auth.code2Session 接口)用户唯一标识openid 会话密钥session_key
3、服务端自定义 登录状态token(与openid、session_key关联)返回客户端
4、客户端将 登录状态token 存入 缓存storage(推荐使用 wx.setStorageSync(‘key’, ‘value’) 同步存储)
5、客户端wx.request() 发起请求时,携带登录状态token (推荐使用 wx.getStorageSync(‘key’) 同步获取)
6、服务端通过 登录状态token 查询到对应 openid 和 session_key
7、验证成功后返回业务数据给客户端

一.用户信息授权登录

其中有两种方法,第一种方法是点击登录之后便直接获取了用户的个人信息,而第二种会询问用户是否同意授权,这样的话,会更具安全性

1.wx.login

这个方法主要用于获取用户的登录凭证(code)。在用户进入小程序时,前端会调用wx.login来获取这个code,然后将这个code发送给后台服务器。后台服务器再向微信发送请求,通过这个code来获取用户的唯一标识(openid)以及本次登录的会话密钥(session_key)。之后,后台服务器将这两个信息传回前台,用于自定义登录状态和用户唯一标识

2.wx.getUserProfile

这个方法主要用于获取用户的更多详细信息,如昵称、头像等。在使用这个方法之前,需要先调用wx.authorize接口来发起授权请求,请求用户授权提供这些信息。如果用户同意授权,就可以通过调用wx.getUserProfile方法来获取这些详细信息

3.代码

WXML

<!--pages/index/index.wxml-->
<view>
  <button wx:if="{{canIUseGetUserProfile}}" type="primary" class="wx-login-btn" bindtap="getUserProfile">微信直接登录1</button>
  <button wx:else open-type="getUserInfo" type="primary" class="wx-login-btn" bindgetuserinfo="wxLogin">微信直接登录2</button>
  <image mode="scaleToFill" src="{{userInfo.avatarUrl}}" />
  <text>昵称:{{userInfo.nickName}}</text>
</view>

JS

// pages/index/index.js
Page({
  data: {
    userInfo: {},
    canIUseGetUserProfile: false,
  },
  onLoad() {
    // if (wx.getUserProfile) {
    //   this.setData({
    //     canIUseGetUserProfile: true
    //   })
    // }
  },
  getUserProfile(e) {
    console.log('getUserProfile')
    // 推荐使用 wx.getUserProfile 获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认
    // 开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
    wx.getUserProfile({
      desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
      success: (res) => {
        console.log(res);
        this.setData({
          userInfo: res.userInfo,
          hasUserInfo: true
        })
      }
    })
  },
  wxLogin: function(e) {
    debugger
    console.log('wxLogin')
    console.log(e.detail.userInfo);
    this.setData({
      userInfo: e.detail.userInfo
    })
    if (e.detail.userInfo == undefined) {
      app.globalData.hasLogin = false;
      util.showErrorToast('微信登录失败');
      return;
    }
    
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady() {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow() {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide() {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload() {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh() {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom() {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage() {

  }
})

用户授权登录后,后台便会保存用户的信息

二.用户信息授权登录之后台交互

前期准备

①准备数据接口

②密钥以及appid

后端代码

package com.zking.ssm.wxcontroller;

/**
 * @Autho donkee
 * @Since 2022/6/27
 */

import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import com.alibaba.fastjson.JSONObject;
import com.zking.ssm.annotation.LoginUser;
import com.zking.ssm.model.UserInfo;
import com.zking.ssm.model.WxLoginInfo;
import com.zking.ssm.model.WxUser;
import com.zking.ssm.service.UserToken;
import com.zking.ssm.service.UserTokenManager;
import com.zking.ssm.service.WxUserService;
import com.zking.ssm.util.JacksonUtil;
import com.zking.ssm.util.ResponseUtil;
import com.zking.ssm.util.UserTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import javax.servlet.http.HttpServletRequest;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 鉴权服务
 */
@Slf4j
@RestController
@RequestMapping("/wx/auth")
public class WxAuthController {
    @Autowired
    private WxMaService wxService;
    @Autowired
    private WxUserService userService;
    /**
     * 微信登录
     *
     * @param wxLoginInfo
     *            请求内容,{ code: xxx, userInfo: xxx }
     * @param request
     *            请求对象
     * @return 登录结果
     */
    @PostMapping("login_by_weixin")
    public Object loginByWeixin(@RequestBody WxLoginInfo wxLoginInfo, HttpServletRequest request) {

        //客户端需携带code与userInfo信息
        String code = wxLoginInfo.getCode();
        UserInfo userInfo = wxLoginInfo.getUserInfo();
        if (code == null || userInfo == null) {
            return ResponseUtil.badArgument();
        }
        //调用微信sdk获取openId及sessionKey
        String sessionKey = null;
        String openId = null;
        try {
            long beginTime = System.currentTimeMillis();
            //
            WxMaJscode2SessionResult result = this.wxService.getUserService().getSessionInfo(code);
//            Thread.sleep(6000);
            long endTime = System.currentTimeMillis();
            log.info("响应时间:{}",(endTime-beginTime));
            sessionKey = result.getSessionKey();//session id
            openId = result.getOpenid();//用户唯一标识 OpenID
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (sessionKey == null || openId == null) {
            log.error("微信登录,调用官方接口失败:{}", code);
            return ResponseUtil.fail();
        }else{
            log.info("openId={},sessionKey={}",openId,sessionKey);
        }
        //根据openId查询wx_user表
        //如果不存在,初始化wx_user,并保存到数据库中
        //如果存在,更新最后登录时间
        WxUser user = userService.queryByOid(openId);

        if (user == null) {
            user = new WxUser();
            user.setUsername(openId);
            user.setPassword(openId);
            user.setWeixinOpenid(openId);
            user.setAvatar(userInfo.getAvatarUrl());
            user.setNickname(userInfo.getNickName());
            user.setGender(userInfo.getGender());
            user.setUserLevel((byte) 0);
            user.setStatus((byte) 0);
            user.setLastLoginTime(new Date());
            user.setLastLoginIp(IpUtil.client(request));
            user.setShareUserId(1);

            userService.add(user);

        } else {
            user.setLastLoginTime(new Date());
            user.setLastLoginIp(IpUtil.client(request));
            if (userService.updateById(user) == 0) {
                log.error("修改失败:{}", user);
                return ResponseUtil.updatedDataFailed();
            }
        }
        // token
        UserToken userToken = null;
        try {
            userToken = UserTokenManager.generateToken(user.getId());
        } catch (Exception e) {
            log.error("微信登录失败,生成token失败:{}", user.getId());
            e.printStackTrace();
            return ResponseUtil.fail();
        }
        userToken.setSessionKey(sessionKey);
        log.info("SessionKey={}",UserTokenManager.getSessionKey(user.getId()));
        Map<Object, Object> result = new HashMap<Object, Object>();
        result.put("token", userToken.getToken());
        result.put("tokenExpire", userToken.getExpireTime().toString());
        userInfo.setUserId(user.getId());
        if (!StringUtils.isEmpty(user.getMobile())) {// 手机号存在则设置
            userInfo.setPhone(user.getMobile());
        }
        try {
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            String registerDate = df.format(user.getAddTime() != null ? user.getAddTime() : new Date());
            userInfo.setRegisterDate(registerDate);
            userInfo.setStatus(user.getStatus());
            userInfo.setUserLevel(user.getUserLevel());// 用户层级
            userInfo.setUserLevelDesc(UserTypeEnum.getInstance(user.getUserLevel()).getDesc());// 用户层级描述
        } catch (Exception e) {
            log.error("微信登录:设置用户指定信息出错:"+e.getMessage());
            e.printStackTrace();
        }
        result.put("userInfo", userInfo);


        log.info("【请求结束】微信登录,响应结果:{}", JSONObject.toJSONString(result));

        return ResponseUtil.ok(result);
    }


   }
}

WXML

<!--pages/auth/login/login.wxml-->
<view class="container">
  <view class="login-box">
    <button wx:if="{{canIUseGetUserProfile}}" type="primary" class="wx-login-btn" bindtap="getUserProfile">微信直接登录</button>
    <button wx:else open-type="getUserInfo" type="primary" class="wx-login-btn" bindgetuserinfo="wxLogin">微信直接登录</button>
    <button type="primary" class="account-login-btn" bindtap="accountLogin">账号登录</button>
  </view>
</view>

JS

// pages/auth/login/login.js
var util = require('../../../utils/util.js');
var user = require('../../../utils/user.js');
const app = getApp();
Page({

    /**
     * 页面的初始数据
     */
    data: {
        canIUseGetUserProfile: false, // 用于向前兼容
        lock:false
    },
    onLoad: function(options) {
        // 页面初始化 options为页面跳转所带来的参数
        // 页面渲染完成
        if (wx.getUserProfile) {
          this.setData({
            canIUseGetUserProfile: true
          })
        }
        //console.log('login.onLoad.canIUseGetUserProfile='+this.data.canIUseGetUserProfile)
    },

    /**
     * 生命周期函数--监听页面初次渲染完成
     */
    onReady() {

    },

    /**
     * 生命周期函数--监听页面显示
     */
    onShow() {

    },
    getUserProfile(e) {
        console.log('getUserProfile');
        // 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认
        // 开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
        wx.getUserProfile({
            desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
            success: (res) => {
                //console.log(res);
                user.checkLogin().catch(() => {
                    user.loginByWeixin(res.userInfo).then(res => {
                      app.globalData.hasLogin = true;
                      wx.navigateBack({
                        delta: 1
                      })
                    }).catch((err) => {
                      app.globalData.hasLogin = false;
                      if(err.errMsg=="request:fail timeout"){
                        util.showErrorToast('微信登录超时');
                      }else{
                        util.showErrorToast('微信登录失败');
                      }
                      this.setData({
                        lock:false
                      })
                    });
                  });
            },
            fail: (res) => {
                app.globalData.hasLogin = false;
                console.log(res);
                util.showErrorToast('微信登录失败');
            }
        });
    },
    wxLogin: function(e) {
        console.log('wxLogin');
        if (e.detail.userInfo == undefined) {
          app.globalData.hasLogin = false;
          util.showErrorToast('微信登录失败');
          return;
        }
        user.checkLogin().catch(() => {
            user.loginByWeixin(e.detail.userInfo).then(res => {
              app.globalData.hasLogin = true;
              wx.navigateBack({
                delta: 1
              })
            }).catch((err) => {
              app.globalData.hasLogin = false;
              if(err.errMsg=="request:fail timeout"){
                util.showErrorToast('微信登录超时');
              }else{
                util.showErrorToast('微信登录失败');
              }
            });
      
          });
    },
    accountLogin() {
        console.log('开发中....')
    }

})

utils/user.js【封装的代码块】

/**
 * 用户相关服务
 */
const util = require('../utils/util.js');
const api = require('../config/api.js');

/**
 * Promise封装wx.checkSession
 */
function checkSession() {
  return new Promise(function(resolve, reject) {
    wx.checkSession({
      success: function() {
        resolve(true);
      },
      fail: function() {
        reject(false);
      }
    })
  });
}
/**
 * Promise封装wx.login
 */
function login() {
  return new Promise(function(resolve, reject) {
    wx.login({
      success: function(res) {
        if (res.code) {
          resolve(res);
        } else {
          reject(res);
        }
      },
      fail: function(err) {
        reject(err);
      }
    });
  });
}
/**
 * 调用微信登录
 */
function loginByWeixin(userInfo) {
  return new Promise(function(resolve, reject) {
    return login().then((res) => {
      //登录远程服务器
      util.request(api.AuthLoginByWeixin, {
        code: res.code,
        userInfo: userInfo
      }, 'POST').then(res => {
        if (res.errno === 0) {
          //存储用户信息
          wx.setStorageSync('userInfo', res.data.userInfo);
          wx.setStorageSync('token', res.data.token);
          resolve(res);
        } else {
          reject(res);
        }
      }).catch((err) => {
        reject(err);
      });
    }).catch((err) => {
      reject(err);
    })
  });
}

/**
 * 判断用户是否登录
 */
function checkLogin() {
  return new Promise(function(resolve, reject) {
    if (wx.getStorageSync('userInfo') && wx.getStorageSync('token')) {
      checkSession().then(() => {
        resolve(true);
      }).catch(() => {
        reject(false);
      });
    } else {
      reject(false);
    }
  });
}

module.exports = {
  loginByWeixin,
  checkLogin,
};

三.手机号授权登录之后台交互

手机号授权登录的流程与用户信息授权登录流程是一样的,只不过向微信调用的接口有所不同

后端代码

package com.zking.ssm.wxcontroller;

/**
 * @Autho donkee
 * @Since 2022/6/27
 */

import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import com.alibaba.fastjson.JSONObject;
import com.zking.ssm.annotation.LoginUser;
import com.zking.ssm.model.UserInfo;
import com.zking.ssm.model.WxLoginInfo;
import com.zking.ssm.model.WxUser;
import com.zking.ssm.service.UserToken;
import com.zking.ssm.service.UserTokenManager;
import com.zking.ssm.service.WxUserService;
import com.zking.ssm.util.JacksonUtil;
import com.zking.ssm.util.ResponseUtil;
import com.zking.ssm.util.UserTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import javax.servlet.http.HttpServletRequest;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 鉴权服务
 */
@Slf4j
@RestController
@RequestMapping("/wx/auth")
public class WxAuthController {
  
    /**
     * 绑定手机号码
     *
     * @param userId
     * @param body
     * @return
     */
    @PostMapping("bindPhone")
    public Object bindPhone(@LoginUser Integer userId, @RequestBody String body) {
        log.info("【请求开始】绑定手机号码,请求参数,body:{}", body);

        String sessionKey = UserTokenManager.getSessionKey(userId);
        String encryptedData = JacksonUtil.parseString(body, "encryptedData");
        String iv = JacksonUtil.parseString(body, "iv");
        WxMaPhoneNumberInfo phoneNumberInfo = null;
        try {
            phoneNumberInfo = this.wxService.getUserService().getPhoneNoInfo(sessionKey, encryptedData, iv);
        } catch (Exception e) {
            log.error("绑定手机号码失败,获取微信绑定的手机号码出错:{}", body);
            e.printStackTrace();
            return ResponseUtil.fail();
        }
        String phone = phoneNumberInfo.getPhoneNumber();
        WxUser user = userService.selectByPrimaryKey(userId);
        user.setMobile(phone);
        if (userService.updateById(user) == 0) {
            log.error("绑定手机号码,更新用户信息出错,id:{}", user.getId());
            return ResponseUtil.updatedDataFailed();
        }
        Map<Object, Object> data = new HashMap<Object, Object>();
        data.put("phone", phone);

        log.info("【请求结束】绑定手机号码,响应结果:{}", JSONObject.toJSONString(data));
        return ResponseUtil.ok(data);
    }
  
    }
}

WXML

<!--pages/ucenter/user/user.wxml-->
<form bindsubmit="formSubmit">
    <view class='personal-data'>
        <view class='list'>
            <view class='item acea-row row-between-wrapper'>
                <view>头像</view>
                <view class='pictrue'>
                    <image src='{{userInfo.avatarUrl}}'></image>
                </view>
            </view>
            <view class='item acea-row row-between-wrapper'>
                <view>名字</view>
                <view class='input'><input type='text' disabled='true' name='nickname' value='{{userInfo.nickName}}'></input></view>
            </view>
            <view class='item acea-row row-between-wrapper'>
                <view>手机号码</view>
                <button name='phone' class='phoneW' value='{{userInfo.phone}}' wx:if="{{!userInfo.phone}}" bindgetphonenumber="getPhoneNumber" hover-class='none' open-type='getPhoneNumber'>
                    点击获取
                </button>
                <view class='input acea-row row-between-wrapper' wx:else>
                    <input type='text' disabled='true' name='phone' value='{{userInfo.phone}}' class='id'></input>
                    <text class='iconfont icon-suozi'></text>
                </view>
            </view>

            <view class='item acea-row row-between-wrapper'>
                <view>ID号</view>
                <view class='input acea-row row-between-wrapper'>
                    <input type='text' value='1000{{userInfo.userId}}' disabled='true' class='id'></input>
                    <text class='iconfont icon-suozi'></text>
                </view>
            </view>
        </view>
        <button class='modifyBnt' bindtap="exitLogin">退 出</button>
    </view>
</form>

JS

var util = require('../../../utils/util.js');
var api = require('../../../config/api.js');
var user = require('../../../utils/user.js');
var app = getApp();
Page({

  /**
   * 页面的初始数据
   */
  data: {
    userInfo: {},
    hasLogin: false,
    userSharedUrl: ''
  },

  /**
      * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {

  },
  onShow: function () {
    let that = this;
    //获取用户的登录信息
    let userInfo = wx.getStorageSync('userInfo');
    this.setData({
      userInfo: userInfo,
      hasLogin: true
    });

  },
  getPhoneNumber: function (e) {
      console.log(e);
    let that = this;
    if (e.detail.errMsg !== "getPhoneNumber:ok") {
      // 拒绝授权
      return;
    }

    if (!this.data.hasLogin) {
      wx.showToast({
        title: '绑定失败:请先登录',
        icon: 'none',
        duration: 2000
      });
      return;
    }

    util.request(api.AuthBindPhone, {
      iv: e.detail.iv,
      encryptedData: e.detail.encryptedData
    }, 'POST').then(function (res) {
      if (res.errno === 0) {
        let userInfo = wx.getStorageSync('userInfo');
        userInfo.phone = res.data.phone;//设置手机号码
        wx.setStorageSync('userInfo', userInfo);
        that.setData({
          userInfo: userInfo,
          hasLogin: true
        });
        wx.showToast({
          title: '绑定手机号码成功',
          icon: 'success',
          duration: 2000
        });
      }
    });
  },
  exitLogin: function () {
    wx.showModal({
      title: '',
      confirmColor: '#b4282d',
      content: '退出登录?',
      success: function (res) {
        if (!res.confirm) {
          return;
        }

        util.request(api.AuthLogout, {}, 'POST');
        app.globalData.hasLogin = false;
        wx.removeStorageSync('token');
        wx.removeStorageSync('userInfo');
        wx.reLaunch({
          url: '/pages/index/index'
        });
      }
    })
  }
})

四.投票界面与后台交互

1.效果预览

2.代码演示

数据库

后端代码

package com.zking.minoa.wxcontroller;

import com.zking.minoa.mapper.InfoMapper;
import com.zking.minoa.mapper.OptionMapper;
import com.zking.minoa.model.Info;
import com.zking.minoa.model.Option;
import com.zking.minoa.util.ResponseUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Autho donkee
 * @Since 2022/6/29
 */
@RestController
@RequestMapping("/wx/home")
public class WxHomeController {
    @Autowired
    private InfoMapper infoMapper;
    @Autowired
    private OptionMapper optionMapper;

    @RequestMapping("/add")
    public String add(@RequestBody Map<String, Object> obj) {
        System.out.println(obj);
        //获取选项数组的长度来控制新增的次数
        int optionsLength = ((List)obj.get("optionText")).size();
        //循环添加投票数据
        for (int i = 0; i < optionsLength; i++) {
            //初始化option
            Option option = new Option();
            List<String> options = (List<String>) obj.get("optionText");
            option.setMeetingId((Integer) obj.get("meetingId"));//会议id
            String firstOption = options.get(i);
            option.setOptionValue((String)obj.get("optionValue"));//投票标题
            option.setOptionText(firstOption);//选项内容
            //调取添加的方法
            int insert = optionMapper.insertSelective(option);
        }
            return "投票发布成功";

        
    }

 
}

vote/list.wxml

<!--pages/vote/list/list.wxml-->
<wxs src="../../../utils/comm.wxs" module="tools" />

<view class="info-title">
  <image class="img-title"  src="../../../static/vote/sousuo.png"></image>
  <input  type="text" placeholder="选择所属会议" bindtap="showModal" />
</view>
<view class="modal-container {{modalVisible ? '' : 'hidden'}}">
  <view class="modal-content">
    <view>
      <view class="table-header">
    <text class="grid-title">标题</text>
    <text class="grid-location">地点</text>
    <text class="grid-time">开始时间</text>
  </view>
  <block wx:for="{{lists}}" wx:key="item.id" >
    <view class="table-row {{item.id == selectedId ? 'selected' : ''}}" data-id="{{item.id}}" data-value="{{item.title}}" bindtap="handleClick" style="margin-top: 10px;">
        <text>{{item.title}}</text>
        <text>{{item.location}}</text>
        <text>{{tools.formatDate(item.starttime)}}</text>
    </view>
</block>

    </view>
 
    <button bindtap="hideModal" class="modal-btn">确认</button>
  </view>
</view>

<view class="vote-button" bindtap="jumpToFoodPage">
  <block wx:for="{{myvotelist}}" wx:key="index">
    <view class="myvotes">
      <view class="myimg">
        <image class="vote-icon" src="{{item.img}}"></image>
      </view>
      <view class="myview">
        <text class="vote-label">{{item.name}}</text>
      </view>
    </view>
  </block>
  <image class="vote-add" src="../../../static/vote/addvote.png" bindtap="addvote"></image>
</view>

 vote/list.wxss

/* pages/vote/list/list.wxss */
.vote-button {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  /* 使元素在一行中超出容器宽度时自动换行 */
}

.myvotes {
  padding-top: 50px;
  padding-left: 5px;
  height: 430rpx;
  width: 360rpx;
  display: flex;
  flex-direction: column;
}
.myimg{
  display: flex;
  justify-content: center;
}
.myview{

}
.vote-icon {
  margin: 5px;
  width: 320rpx;
  height: 300rpx;
  border-radius:25px;
  border: 10px solid rgb(247, 198, 66);
}
.img-title{
  width: 32px;
  height: 32px;
}

.vote-label {
 font-weight: 800;
 font-family: YouYuan;
  width: 350rpx;
  padding-left: 65px;
  
  /* 将文字放在图标的正下方 */

}
.info-title{
  display: flex;
  align-items: center;
  margin-left:65px ;
  width: 300px;
  border-radius:25px;
  border: 2px solid rgb(247, 198, 66);
}

.vote-add {
  margin-left: 340px;
  margin-top: 35px;
  width: 120rpx;
  height: 120rpx;
}







/* --------------------- */
/* pages/vote/list/list.wxss */
.hidden {
  display: none;
}

.title-view {
  background-color: beige;
  font-weight: 700;
  padding-left: 7px;
}

.info-title {
  padding: 5px 5px 10px 5px;
  border-top: 1px solid rgb(129, 129, 127);
}

.info-text {
  height: 100px;
  padding: 5px 5px 10px 5px;
  border-top: 1px solid rgb(129, 129, 127);
}

.image {
  padding-left: 55px;
  display: flex;
  align-items: center;
}

.time {
  border-top: 1px solid rgb(129, 129, 127);
  padding: 5px 0px 5px 0px;
  display: flex;
  align-items: center;
}

.image-container {
  padding-left: 60px;
}

.info-sousuo {
  margin-left: 85px;
  padding-left: 20px;
  border-radius: 25px;
  border: 4px solid rgb(214, 214, 98);
  width: 250px;
}


/* pages/meeting/list/list.wxss */
.section{
  color: #aaa;
  display: flex;
  justify-content: center;
}

.list-info {
  margin-top: 10px;
  color: #aaa;
}

.list-num {
  color: #e40909;
  font-weight: 700;
}

.join {
  padding: 0px 0px 0px 10px;
  color: #aaa;
}

.state {
  margin: 0px 6px 0px 6px;
  border: 1px solid #93b9ff;
  color: #93b9ff;
}

.list-tag {
  padding: 3px 0px 10px 0px;
  display: flex;
  align-items: center;
}

.list-title {
  display: flex;
  justify-content: space-between;
  color: #333;
  font-weight: 900;


}
.yyy{
  display: flex;
  align-items: center;
}
.list-img{
  height: 300rpx;
  width: 90%;
  border-radius: 50rpx;
  margin: 5px 5px 5px 20px;
}
.centered {
  display: flex;  /* 设置为弹性容器 */
  justify-content: center;  /* 子元素水平方向居中对齐 */
}


.video-img {
  width: 100px;
  height: 100px;
}

.list {

  border-bottom: 1px solid #6b6e74;
  padding: 10px;
}

.mobi-text {
  font-weight: 700;
  padding: 15px;
}

.mobi-icon {
  border-left: 5px solid #e40909;
}

.mobi-title {
  background-color: rgba(158, 158, 142, 0.678);
  margin: 10px 0px 10px 0px;
}

.swiper-item {
  height: 300rpx;
  width: 100%;
  border-radius: 10rpx;
}

.userinfo {
  display: flex;
  flex-direction: column;
  align-items: center;
  color: #aaa;
}

.userinfo-avatar {
  overflow: hidden;
  width: 128rpx;
  height: 128rpx;
  margin: 20rpx;
  border-radius: 50%;
}

.usermotto {
  margin-top: 200px;
}


.filx{
  display: flex;
  align-items: center;
}
.container {
  padding: 20px;
}

.modal-container {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background-color: #fff;
  width: 80%;
  max-height: 80%;
  overflow-y: auto;
  padding: 20px;
}

.mask {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
}

button {
  display: block;
  margin-top: 10px;
}

.content {
  margin-top: 10px;
  border: 1px solid #ccc;
  padding: 10px;
}

vote/list.js

// pages/vote/list/list.js
// 获取应用实例
const app = getApp()
const api = require("../../../config/api")
const utils = require("../../../utils/util")
Page({
  /**
   * 页面的初始数据
   */
  data: {
    myvotelist: [{
        index: 1,
        name: '投票统计',
        img: '../../../static/vote/totaldata-active.png'
      },
      {
        index: 3,
        name: '历史投票',
        img: '../../../static/vote/voterecords-active.png'
      },
      {
        index: 2,
        name: '赞成人数',
        img: '../../../static/vote/yes-active.png'
      },
      {
        index: 3,
        name: '反对人数',
        img: '../../../static/vote/no-active.png'
      },

    ],
    modalVisible: false, // 模态框是否可见
    lists: [],
    selectedId: '', // 存储选中数据的id
    state:false
  },
  addvote: function () {
    if (!this.data.state) {
      wx.showModal({
          title: '提示',
          content: '请先选择会议',
          showCancel: false,  // 取消按钮不显示
          success (res) {
              if (res.confirm) {
                  console.log('用户点击确定')
              }
          }
      })
  } else {
      // 如果state为true
      wx.navigateTo({
        //id:selectedId,
        //url: '/pages/vote/addvote/addvote?id='+id // 跳转到目标页面的路径
        url: '/pages/vote/addvote/addvote' // 跳转到目标页面的路径
      })
  }
  
  },
  loadMeetingInfos() {
    let that = this;
    utils.request(api.IndexUrl).then(res => {
      this.setData({
        lists: res.data.infoList
      })
    });
  },
  // 点击数据行触发的事件
  handleClick(event) {
    // console.log(event)
    const id = event.currentTarget.dataset.id;
    const title = event.currentTarget.dataset.value;
    // console.log('传递的值:', title);
    // console.log('现在已经拿到id了', id)
    var obj = {
      id: id,
      title:title
    };
    wx.setStorageSync('key', JSON.stringify(obj));
    this.setData({
      selectedId: id,
      state:true
    });
  },

  // 点击事件,显示模态框
  showModal() {
    this.setData({
      modalVisible: true,
    });
    this.loadMeetingInfos();
  },
  // 点击事件,隐藏模态框
  hideModal() {
    this.setData({
      modalVisible: false
    });
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {

  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady() {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow() {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide() {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload() {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh() {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom() {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage() {

  }
})

vote/addvote.wxml

<view class="container">
    <button class="title" bindtap="single">单选投票</button>
  
    <button class="title" bindtap="many">多选投票</button>
    


  
</view>

 vote/addvote.wxss

.container {
  padding: 20rpx;
}



button {
  margin-top: 60px;
  background-color: rgb(247, 198, 66);
  color: #fff;
  padding: 10rpx 20rpx;
  border-radius: 4rpx;
  text-align: center;

} 


 .title {
  font-size: 30rpx;
  font-weight: bold;
  margin-bottom: 10rpx;
}

vote/addvote.js

Page({
  many: function () {
    console.log(111)
    wx.navigateTo ({
    
      url: '/pages/vote/many/many' // 跳转到目标页面的路径
    })
  },
  data: {
    radioOptions: ['选项1', '选项2', '选项3'],
    checkboxOptions: ['选项A', '选项B', '选项C'],
    voteTitle: '',
    voteDescription: '',
    selectedRadioIndex: -1,
    selectedCheckboxIndexes: []
  },

  onTitleInput(e) {
    this.setData({
      voteTitle: e.detail.value
    });
  },

  onDescriptionInput(e) {
    this.setData({
      voteDescription: e.detail.value
    });
  },

  onRadioChange(e) {
    this.setData({
      selectedRadioIndex: e.detail.value
    });
  },

  onCheckboxChange(e) {
    this.setData({
      selectedCheckboxIndexes: e.detail.value
    });
  },

  submitVote() {
    // 获取投票的标题、描述以及选择的选项
    const { voteTitle, voteDescription, selectedRadioIndex, selectedCheckboxIndexes } = this.data;

    // TODO: 处理提交投票逻辑,可以发送请求给服务器等

    // 打印投票结果
    console.log('投票标题:', voteTitle);
    console.log('投票描述:', voteDescription);
    console.log('单选投票选项:', selectedRadioIndex);
    console.log('多选投票选项:', selectedCheckboxIndexes);
  },



  /**
   * 页面的初始数据
   */
  data: {

  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {

  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady() {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow() {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide() {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload() {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh() {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom() {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage() {

  }
})

vote/many.wxml

<!--pages/vote/many/many.wxml-->

<view class="container" >  
  <input class="title" placeholder="会议标题" value="{{title}}" disabled/>
 <!-- <input class="title" value="{{title}}" disabled /> -->
 <view class="line"></view>
 <input class="info" placeholder="投票标题" bindinput="titleChange"/>
 <view class="line"></view>
 
 <view id="scrollContainer">
  <view wx:for="{{inputList}}" wx:key="index" class="select">
    <image class="select-add" src="../../../static/vote/减.png" bindtap="hideInput"
      data-index="{{index}}"></image>
    <input class="vote-content" placeholder="请输入内容" data-index="{{index}}"
      value="{{item.value}}" bindinput="inputChange"></input>
  </view>


  <view class="select" style="margin-left: 4px;">
  <image class="select-add" src="../../../static/vote/添加_填充.png" bindtap="showInput"></image>
 <view class="select-content" bindtap="showInput"> 添加选项</view>
 </view>


  <button class="submit-button" style="top: {{buttonTop}}rpx;" bindtap="submitVote">提交</button>
</view>




 


  </view>

 vote/many.wxss

/* pages/vote/many/many.wxss */
.container {
  display: flex;
  flex-direction: column;
  align-items: center;
} 

.title{
  height: 200px;
  font-weight: bolder;
  font-size: 70rpx;
 margin-left: 20px;
 margin-top: -160px;
 margin-bottom: -50px;
}
.line {
  width: 100%;
  height: 1px;
  background-color: #ccc;
}
.info{
height: 70px;
width:380px;
}
.select{
  display: flex;
flex-direction: row;
align-self: start;
}
.select-add {
margin-left: 15px;
  margin-top: 15px;
  width: 50rpx;
  height: 50rpx;
}
.select-content{
  margin-top: 10px;
  margin-left: 7px;
  display: flex;
  align-items: center;
}

.vote-content {
  width: 200rpx;
  height: 30rpx;
  margin-top: 17px;
  margin-left: 7px;
  display: flex;
  align-items: center;
}
.scroll-container {
  height: 500rpx; /* 设置合适的高度,使其可以滚动 */
}

.submit-button {
margin-top: 20px;
  width: 200rpx;
  height: 60rpx;
  background-color: rgb(241, 189, 46);
}


vote/many.js

const app = getApp()
const api = require("../../../config/api.js")
const util = require("../../../utils/util")
 
Page({
  data: {
    inputList: [],
    title:'',
    voteTitle: '',
    id:''
    },
 
  // 显示输入框
  showInput: function () {
    const length = this.data.inputList.length;
    const newInputList = [...this.data.inputList];
    newInputList.push({
      value: ''
    });
    this.setData({
      inputList: newInputList
    });
  },
 
  // 输入框内容改变
  inputChange: function (event) {
    const index = event.currentTarget.dataset.index;
    const value = event.detail.value;
    const newInputList = [...this.data.inputList];
    newInputList[index].value = value;
    this.setData({
      inputList: newInputList
    });
  },
 
  // 删除输入框
  hideInput: function (event) {
    const index = event.currentTarget.dataset.index;
    const newInputList = [...this.data.inputList];
    newInputList.splice(index, 1);
    this.setData({
      inputList: newInputList
    });
  },
 
  // 投票标题改变
  titleChange: function (event) {
    const value = event.detail.value;
    this.setData({
      voteTitle: value
    });
  },
 
  // 提交投票
  submitVote: function () {
    // 获取投票标题和选项内容
    const meetingId = this.data.id;
    const optionValue = this.data.voteTitle;
    const optionText = this.data.inputList.map(item => item.value);

   
    // 打印标题和选项

    let data = {
      meetingId: meetingId,
      optionValue: optionValue,
      optionText:optionText
    };
    console.log(data)
 
    util.request(api.VoteADD, data, 'POST').then(res => {
      console.log(res)
      // 清空投票标题和选项内容
      this.setData({
        voteTitle: '',
        inputList: []
      });
    })
 
 
  },
 
 
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {
var objStr = wx.getStorageSync('key');
var obj = JSON.parse(objStr);
console.log("这个是父页面的值",obj.id,obj.title)
this.setData({
  id: obj.id,
  title:obj.title
});
  },
 
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady() {
 
  },
 
  /**
   * 生命周期函数--监听页面显示
   */
  onShow() {
 
  },
 
  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide() {
 
  },
 
  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload() {
 
  },
 
  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh() {
 
  },
 
  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom() {
 
  },
 
  /**
   * 用户点击右上角分享
   */
  onShareAppMessage() {
 
  }
})

好啦,今天的分享就到这了,希望能够帮到你呢!😊😊  

  • 43
    点赞
  • 91
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
要在PHP中实现微信小程序授权获取用户信息并绑定手机号登录,可以按照以下步骤进行操作: 1. 在微信小程序端,通过`wx.login`获取到用户的临时登录凭证`code`。 2. 将获取到的`code`发送到服务器端,使用`https`接口调用`code2Session`接口,获取到`openid`和`session_key`。 3. 将`openid`和`session_key`保存至服务器端数据库或缓存中。 4. 在小程序端,使用`wx.getUserInfo`获取用户信息,包括`nickName`、`avatarUrl`等,并将用户信息传输到服务器端。 5. 在服务器端,接收到用户信息后,将用户信息保存到服务器数据库中,可以使用`openid`作为用户的唯一标识。 6. 在小程序端,点击绑定手机号的按钮,调用`wx.request`向服务器发送请求,请求获取手机号的能力。 7. 在服务器端,接收到手机号请求后,可以返回一个包含手机号获取能力的`code`给小程序端。 8. 小程序端收到`code`后,调用`wx.request`向服务器发送请求,请求获取手机号。 9. 服务器端接收到获取手机号的请求后,可以通过调用微信开放平台提供的解密能力,解密包含手机号的数据,并将解密得到的手机号用户信息进行绑定。 10. 绑定成功后,返回相应的状态给小程序端。 总结:通过以上步骤,我们可以在PHP中实现微信小程序授权获取用户信息并绑定手机号登录的功能。在小程序端,用户使用微信授权登录后,将用户信息传输到服务器端保存,并通过绑定手机号使用户能够更便捷地登录和使用小程序。同时,在服务器端需要进行数据加密和解密的操作,确保用户的信息安全。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是辉辉啦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值