5.Abp vNext 地磅无人值守 微信小程序

地磅无人值守项目 系列文章目录



前言

客户提出新需求:车辆驾人员能在手机上查看自己车辆过磅记录。开搞…
人手一个微信,那就用微信小程序。
在这里插入图片描述
之前搞过vue,有很多相似的地方。
在这里插入图片描述在这里插入图片描述


一、开发微信页面

页面及代码示例:

index.wxml


<!--index.wxml-->
<view class="page">
  <view class="page-body">
    <swiper class="swiper" indicator-dots="{{indicatorDots}}"
      autoplay="{{autoplay}}" interval="{{interval}}" duration="{{duration}}" circular="true">
      <block wx:for="{{background}}" wx:key="*this">
        <swiper-item>
          <image src="{{imgPath + item}}" class="slide-image" mode="aspectFill" />
        </swiper-item>
      </block>
    </swiper>
  </view>
	<view class="weui-grids">
		<navigator class="weui-grid" aria-role="button" url="/pages/records/list">
			<view class="weui-grid__icon">
				<icon class="iconfont icon-dingdan" />
			</view>
			<view class="weui-grid__label">历史单据</view>
		</navigator>
		<navigator class="weui-grid" aria-role="button" url="/pages/cars/create/create">
			<view class="weui-grid__icon">
				<icon class="iconfont icon-wuliu" />
			</view>
			<view class="weui-grid__label">车辆录入</view>
		</navigator>
		<navigator class="weui-grid" aria-role="button" url="#">
			<view class="weui-grid__icon">
				<icon class="iconfont icon-bingtutubiao" />
			</view>
			<view class="weui-grid__label">单据统计<text style="font-style:italic;font-size: 26rpx;">待开放</text></view>
		</navigator>
		<navigator class="weui-grid" aria-role="button" url="/pages/cars/list">
			<view class="weui-grid__icon">
				<icon class="iconfont icon-auto" />
			</view>
			<view class="weui-grid__label">车辆管理</view>
		</navigator>
  </view>
</view>

index.js

const {urlList} = require('../../utils/config.js');

Page({
  data: {
    imgPath: urlList.advertPicListUrl,
    background: ['/banner01.png', '/banner02.png'],
    indicatorDots: true,
    vertical: false,
    autoplay: true,
    circular: false,
    interval: 5000,
    duration: 500,
    previousMargin: 0,
    nextMargin: 0
  },
  onShareAppMessage: function(){
    return{
      title: "转发给好友",
      path: "/pages/index/index"
    }
   },
  changeProperty: function (e) {
    var propertyName = e.currentTarget.dataset.propertyName
    var newData = {}
    newData[propertyName] = e.detail.value
    this.setData(newData)
  },
  changeIndicatorDots: function (e) {
    this.setData({
      indicatorDots: !this.data.indicatorDots
    })
  },
  changeAutoplay: function (e) {
    this.setData({
      autoplay: !this.data.autoplay
    })
  },
  intervalChange: function (e) {
    this.setData({
      interval: e.detail.value
    })
  },
  durationChange: function (e) {
    this.setData({
      duration: e.detail.value
    })
  }
})

二、2.Abp vNext 开放登录接口

1.Abp vNext 开放登录接口

using FloorScale.Base.Cars;
using FloorScale.Base.CarTypes;
using FloorScale.Base.MaterialFormats;
using FloorScale.Base.Materials;
using FloorScale.Base.MaterialTypes;
using FloorScale.Base.ReceivingUnits;
using FloorScale.Base.Shippers;
using FloorScale.Base.WeightRecords;
using FloorScale.Base.WeightTypes;
using FloorScale.Base.WeightUnits;
using FloorScale.Tenants;
using FloorScale.ThirdParty.WechatMinis.Dtos;
using IdentityModel.Client;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Data;
using Volo.Abp.Identity;
using Volo.Abp.Uow;

namespace FloorScale.ThirdParty.WechatMinis
{
    /// <summary>
    /// 微信小程序
    /// </summary>
    [ApiExplorerSettings(GroupName = FloorScaleAppService.SwaggerDocWechatMiniApi)]
    [Authorize]
    public partial class WechatMiniService : FloorScaleAppService
    {
        private const string ProviderName = "WeChatMiniProgram";
        private const string FixedPassword = ".*_0W@";
        private readonly IConfiguration _configuration;
        private readonly IdentityUserManager _userManager;
        private readonly IWechatMiniRepository _wechatRepository;
        private readonly IUnitOfWorkManager _unitOfWorkManager;
        private readonly IDataFilter _dataFilter;
        //private readonly ITenantRepository _tenantsRepository;

        private readonly IEfCoreTenantRepository _tenantRepository;
        private readonly ICarRepository _carRepository;
        private readonly ICarTypeRepository _typeRepository;
        private readonly IShipperRepository _shipperRepository;
        private readonly IReceivingUnitRepository _receivingUnitRepository;
        private readonly IMaterialTypeRepository _materialTypeRepository;
        private readonly IMaterialRepository _materialRepository;
        private readonly IMaterialFormatRepository _formatRepository;
        private readonly IWeightTypeRepository _weightTypeRepository;

        private readonly IWeightRecordRepository _weightRecordRepository;
        private readonly IWeightUnitRepository _weightUnitRepository;

        public WechatMiniService(
            IConfiguration configuration,
            IdentityUserManager userManager,
            IWechatMiniRepository wechatRepository,
            IUnitOfWorkManager unitOfWorkManager,
            IDataFilter dataFilter,

            IEfCoreTenantRepository tenantRepository,
            ICarRepository carRepository,
            ICarTypeRepository typeRepository,
            IShipperRepository shipperRepository,
            IReceivingUnitRepository receivingUnitRepository,
            IMaterialTypeRepository materialTypeRepository,
            IMaterialRepository materialRepository,
            IMaterialFormatRepository formatRepository,
            IWeightTypeRepository weightTypeRepository,

            IWeightRecordRepository weightRecordRepository,
            IWeightUnitRepository weightUnitRepository)
        {
            _configuration = configuration;
            _userManager = userManager;
            _wechatRepository = wechatRepository;
            _unitOfWorkManager = unitOfWorkManager;
            _dataFilter = dataFilter;

            _tenantRepository = tenantRepository;
            _carRepository = carRepository;
            _typeRepository = typeRepository;
            _shipperRepository = shipperRepository;
            _receivingUnitRepository = receivingUnitRepository;
            _materialTypeRepository = materialTypeRepository;
            _materialRepository = materialRepository;
            _formatRepository = formatRepository;
            _weightTypeRepository = weightTypeRepository;

            _weightRecordRepository = weightRecordRepository;
            _weightUnitRepository = weightUnitRepository;
        }

        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="login"></param>
        /// <returns></returns>
        [AllowAnonymous]
        public async Task<WeChatToken> GetLoginAsync(GetWechatLoginDto login)
        {
            var result = new WeChatToken();

            // 调用第三方服务通过小程序内部登录后的Code获取微信Session信息
            //var wechatSession = await GetWechatSession(login.Code);
            //if (wechatSession == null)
            //{
            //    throw new BusinessException("wechatFail", "获取Openid失败");
            //}
            login.ClientId = "FloorScale_App";
            login.ClientSecret = "****";
            WechatCode2Session wechatSession = new WechatCode2Session()
            {
                Openid = "abcef06",
            };
            var tenantId = Guid.Parse(_configuration["WeChatMini:tenantId"]);
            using (CurrentTenant.Change(tenantId))
            {
                // 通过Provider和Openid获取用户的登录信息
                var wechatLogin = await _userManager.FindByLoginAsync(ProviderName, wechatSession.Openid);

                var userId = Guid.Empty;
                // 首次微信登陆
                if (wechatLogin == null)
                {
                    var idUserLoginInfo = new Microsoft.AspNetCore.Identity.UserLoginInfo(
                        ProviderName,
                        wechatSession.Openid,
                        "微信小程序");
                    if (!CurrentUser.Id.HasValue)
                    {
                        userId = GuidGenerator.Create();
                        // 注册用户登录
                        var iduser = new IdentityUser(
                            userId,
                            wechatSession.Openid,
                            email: $"{wechatSession.Openid}@qq.com",
                            tenantId: tenantId);
                        iduser.ExtraProperties.Add(nameof(wechatSession.Openid), wechatSession.Openid);
                        iduser.AddLogin(idUserLoginInfo);

                        // 添加用户信息
                        await _userManager.CreateAsync(iduser, $"{wechatSession.Openid}{FixedPassword}");
                        var wechatUser = new WechatMini()
                        {
                            UserId = iduser.Id,
                            OpenId = wechatSession.Openid,
                            Phone = string.Empty,
                            Email = string.Empty,
                            NickName = string.Empty,
                            Address = string.Empty,
                            AvatarUrl = string.Empty,
                            Birthday = null,
                            Gender = 0,
                            Status = true,
                            TenantId = tenantId
                        };
                        result.NeedUpdate = true;
                        await _wechatRepository.InsertAsync(wechatUser);
                    }
                    else
                    {
                        userId = CurrentUser.Id.Value;
                        var user = await _userManager.GetByIdAsync(CurrentUser.Id.Value);
                        await _userManager.AddLoginAsync(user, idUserLoginInfo);
                    }
                }
                else
                {
                    userId = wechatLogin.Id;
                }
                var tokenResponse = await GetTokenByOpenIdAsync(
                    wechatSession.Openid,
                    wechatSession.Openid,
                    login);
                result.UserId = userId;
                result.AccessToken = tokenResponse.AccessToken;
                result.ExpiresIn = tokenResponse.ExpiresIn;
                result.TokenType = tokenResponse.TokenType;
                result.Scope = tokenResponse.Scope;
                result.RefreshToken = tokenResponse.RefreshToken;

                return result;
            }
        }

        private async Task<TokenResponse> GetTokenByOpenIdAsync(string userName, string password, GetWechatLoginDto login)
        {
            var disco = await new HttpClient().GetDiscoveryDocumentAsync(_configuration["AuthServer:Authority"]);
            using (var tokenClient = new HttpClient())
            {
                tokenClient.DefaultRequestHeaders.Add("__tenant", _configuration["WeChatMini:tenantId"]);
                var tokenResponse = await tokenClient.RequestPasswordTokenAsync(new PasswordTokenRequest
                {
                    Address = disco.TokenEndpoint,
                    ClientId = login.ClientId,
                    ClientSecret = login.ClientSecret,
                    UserName = userName,
                    Password = $"{password}{FixedPassword}"
                });
                tokenClient.SetBearerToken(tokenResponse.AccessToken);
                return tokenResponse;
            }
        }

        private async Task<WechatCode2Session> GetWechatSession(string code)
        {
            WechatCode2Session result = null;
            var appid = _configuration["WeChatMini:appid"];
            var secret = _configuration["WeChatMini:secret"];

            var httpClient = new HttpClient();
            var urlWeixin = string.Format(
                    _configuration["WeChatMini:WeixinSessionUri"],
                    appid,
                    secret,
                    code);
            try
            {
                var token = await httpClient.GetStringAsync(urlWeixin);
                result = JsonConvert.DeserializeObject<WechatCode2Session>(token);
            }
            catch { }

            return result;
        }

        /// <summary>
        /// 获取用户信息
        /// </summary>
        /// <param name="uid"></param>
        /// <returns></returns>
        public async Task<WechatMiniDto> GetUserInfoAsync(Guid uid)
        {
            using (CurrentTenant.Change(Guid.Parse(_configuration["WeChatMini:tenantId"])))
            {
                var model = await _wechatRepository.GetAsync(p => p.UserId == uid);
                return ObjectMapper.Map<WechatMini, WechatMiniDto>(model);
            }
        }

        /// <summary>
        /// 更新用户信息
        /// </summary>
        /// <param name="uid"></param>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task UpdateUserInfoAsync(Guid uid, [FromBody] UpdateWechatMiniDto input)
        {
            using (CurrentTenant.Change(Guid.Parse(_configuration["WeChatMini:tenantId"])))
            {
                var modelUser = await _wechatRepository.GetAsync(p => p.UserId == uid);
                modelUser.Phone = input.Phone;
                modelUser.NickName = input.NickName;
                if (!string.IsNullOrWhiteSpace(input.AvatarUrl))
                    modelUser.AvatarUrl = input.AvatarUrl;
                modelUser.Address = input.Address;
                modelUser.Birthday = input.Birthday;
                modelUser.Gender = input.Gender;
                var result = await _wechatRepository.UpdateAsync(modelUser);
            }
        }

        /// <summary>
        /// 删除实体
        /// </summary>
        /// <param name="id">编号</param>
        /// <returns></returns>
        public async Task DeleteAsync(Guid id)
        {
            await _wechatRepository.DeleteAsync(id);
        }
    }
}

2.微信端登录示例

utils/config.js

// const basePath = 'https://localhost:44385';
const basePath = 'https://scaleapi.caishiben.com';
const urlList = {
  basePath: basePath,
  // 刷新token
  refreshTokeUrl: basePath + '/refreshToke',//token
  // 登录和首页轮播
  loginUrl: basePath + '/wxappLogin',//登录
  advertPicListUrl: basePath + '/wechat',//轮播列表
}
const globalConfig = {
  clientId: 'FloorScale_App',
  clientSecret: '********'
}

module.exports = {
  urlList,
  globalConfig
}

utils/auth.js


import http from './business/login'
import userApi from './business/user'
const {globalConfig} = require('config.js')

async function checkSession(){
  return new Promise((resolve, reject) => {
    wx.checkSession({
      success() {
        return resolve(true)
      },
      fail() {
        return resolve(false)
      }
    })
  })
}

// 检测登录状态,返回 true / false
async function checkHasLogined() {
  const token = wx.getStorageSync('token')
  if (!token) {
    return false
  }
  const loggined = await checkSession()
  if (!loggined) {
    wx.removeStorageSync('token')
    wx.removeStorageSync('userInfo')
    wx.removeStorageSync('uid')
    wx.removeStorageSync('rememberTenant')
    return false
  }
  return true
}

async function register(page) {
  let _this = this;
  
  return new Promise((resolve, reject) => {
    wx.getUserProfile({
      desc: '用于完善会员资料',
      fail: () => {resolve(false)},
      success: (resUser) => {
        wx.login({
          fail: () => {resolve(false)},
          success: resLogin => {
            http.getLoginToken({
              data: {
                code: resLogin.code,
                clientId: globalConfig.clientId,
                clientSecret: globalConfig.clientSecret
              },
              success: function (resToken) {
                wx.setStorageSync('token', resToken.access_token)
                wx.setStorageSync('uid', resToken.uid)

                if (resToken.needUpdate) {
                  updateUser(resUser.userInfo)
                }
                if(page) {
                  page.onShow()
                }
                resolve(true)
              },
              complete : function(resToken){},
              fail: function (resToken) {resolve(false)}
            })
          }
        })
      }
    })
  })
}

function updateUser(data) {
  let _this = this;
  let passData = {
    "userId": wx.getStorageSync('uid'),
    "phone": "",
    "nickName": data.nickName,
    "address": "",
    "avatarUrl": data.avatarUrl,
    "birthday": null,
    "gender": data.gender,
    "remark": ""
  }
  userApi.updateUserInfo({
    data: passData,
    success: function (res) {},
    complete : function(res){},
    fail: function (res) {}
  })
}

module.exports = {
  checkHasLogined: checkHasLogined,
  register: register
}

utils/http.js


module.exports = {
  http(url, method, params) {
    let requestHeader = {
      'content-type': 'application/json'
    }
    // 获取token
    let token = wx.getStorageSync('token')
    if (token){
      requestHeader.authorization = 'Bearer ' + token
    }
    // 在这里判断一下data是否存在,params表示前端需要传递的数据,params是一个对象,有三组键值对,
    // data:表示请求要发送的数据,success:成功的回调,fail:失败的回调,这三个字段可缺可无,其余字段会忽略
    if(params.data){
      for (let key in params.data) { // 在这里判断传过来的参数值为null,就删除这个属性
        if (params.data[key] == null || params.data[key] == 'null') {
          delete params.data[key]
        }
      }
    }
    wx.request({
      url: urlList.basePath + url,
      method: method === '' ? 'get' : method,
      data: params.data,
      header: requestHeader,
      success(res) {
        params.success && params.success(res.data)
      },
      fail(err) {
        params.fail && params.fail(err)
      },
      complete(err) {
        params.complete && params.complete(err)
      }
    })
  }
}

utils/business/login.js


function getSession(params){
  http('/api/app/wechat-mini/session', 'get', params)
}

function getLoginToken(params){
  http('/api/app/wechat-mini/login', 'get', params)
}

export default {
  getLoginToken,
  getSession
}

总结

Abp vNext 开放登录接口调通后,剩下的工作就是功能叠加。这个工作有点枯燥。

微信上打开小程序:#小程序://尧安称重/NxgTDIoRdkAWE7g
前端:https://dibang.caishiben.com
接口服务:https://scaleapi.caishiben.com
接口文档:https://scaleapi.caishiben.com/swagger/index.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值