共享充电宝技术方案

t

后台地址

http://zzsh.bhsc.cc:5500

通信地址
http://zzsh.bhsc.cc:5600

微信公众号
http://zzsh.bhsc.cc/default.html?type=scan&deviceno=JUDT062207071514

http://zzsh.bhsc.cc/swagger/index.html

后台地址
http://42.194.142.223:5500

扫码租借
http://42.194.142.223/default.html?type=scan&deviceno=WSTD088888888888&testflg=1

一 web管理后台

1、登录管理后台

共享充电宝技术方案_第1张图片

2、首页

共享充电宝技术方案_第2张图片

3. 设备管理

3.1 设备 & 卡口 & 电池自动注册

3.2 设备日志

共享充电宝技术方案_第3张图片

共享充电宝技术方案_第4张图片

共享充电宝技术方案_第5张图片

 4、电池管理

 5、代理管理

共享充电宝技术方案_第6张图片

 6、店铺管理(可批量绑定设备)

共享充电宝技术方案_第7张图片

共享充电宝技术方案_第8张图片

共享充电宝技术方案_第9张图片

 7、系统用户管理

共享充电宝技术方案_第10张图片

 二、通信后台

共享充电宝技术方案_第11张图片

三 扫码租借

共享充电宝技术方案_第12张图片

预先充值

共享充电宝技术方案_第13张图片

    

 店铺信息

共享充电宝技术方案_第14张图片

我的订单 (使用中 & 已完成)

共享充电宝技术方案_第15张图片

 我的流水

共享充电宝技术方案_第16张图片

四 运维管理

共享充电宝技术方案_第17张图片

  

 添加店铺

共享充电宝技术方案_第18张图片

绑定设备

共享充电宝技术方案_第19张图片

  

设备维护

共享充电宝技术方案_第20张图片

   

五 充电宝模拟程序

模拟注册

共享充电宝技术方案_第21张图片

模拟租借

共享充电宝技术方案_第22张图片

 模拟归还

共享充电宝技术方案_第23张图片

设备通信协议

共享充电宝技术方案_第24张图片

使用redis+mysql方式,当设备定时上传注册,心跳,机柜信息时,采用redis查缓存数据,有变化再更新mysql数据,以增强并发能力

using PBCommon;
using PBCommon.db.model;
using PBCommon.redis;
using PBService.Utility;
using PBService.Utilty.db;
using System;

namespace PBService.Utilty
{
    /// 
    /// 业务处理类
    /// 
    public class Business
    {
        /// 
        /// 添加设备日志
        /// 
        public static void InsertDeviceLog(string deviceno, int logtype, string logcontent)
        {
            FreeSqlHelper.InsertDeviceLog(new DeviceLog() { LogTime = DateTime.Now, DeviceNo = deviceno, LogType = logtype, LogContent = logcontent });
        }

        /// 
        /// 添加电池日志
        /// 
        public static void InsertBatteryLog(string deviceno, int slotid, string batteryno, string orderno, int logtype, string logcontent)
        {
            FreeSqlHelper.InsertDeviceLog(new DeviceLog() { LogTime = DateTime.Now, DeviceNo = deviceno, SlotId = slotid, BatteryNo = batteryno, OrderNo = orderno, LogType = logtype, LogContent = logcontent });
        }

        /// 
        /// 设备注册
        /// 
        public static void Reg(string deviceno, int devicetype, string serverip, int port, int slotcount)
        {
            // query -> redis&&mysql
            var key_device = RedisKey.ExistDevice(deviceno);

            var device = RedisHelper.Get(key_device);

            if (null == device)
            {
                device = FreeSqlHelper.GetDevice(deviceno);

                if (null == device)
                {
                    device = new Device() { DeviceNo = deviceno, DeviceType = devicetype, OnTime = DateTime.Now, OffTime = null, ShopId = 0, BorrowUrl = Program.Domain + deviceno, ServerIp = serverip, ServerPort = port };

                    FreeSqlHelper.InsertDevice(device);
                }

                RedisHelper.Set(key_device, device);// 添加redis默认数据
            }

            // datachange update -> redis&&mysql
            if (device.OnLine != BaseEnum.Statue_ON || device.ServerIp != serverip || device.ServerPort != port || device.SlotCount != slotcount) 
            {
                device.OnLine = BaseEnum.Statue_ON; 
                device.ServerIp = serverip;
                device.ServerPort = port;
                device.SlotCount = slotcount;
                RedisHelper.Set(key_device, device);

                FreeSqlHelper.UpdateDeviceOnLine(deviceno, serverip, port, slotcount);

                InsertDeviceLog(deviceno, BaseEnum.DeviceLog_ON, "设备上线");
            } 
        }

        /// 
        /// 设备注销
        /// 
        public static void UnReg(string deviceno)
        {
            var key_device = RedisKey.ExistDevice(deviceno);
            var device = RedisHelper.Get(key_device);

            if (null != device)
            {
                device.OnLine = BaseEnum.Statue_OFF;
                RedisHelper.Set(key_device, device);
            }

            FreeSqlHelper.UpdateDeviceOFFLine(deviceno);

            InsertDeviceLog(deviceno, BaseEnum.DeviceLog_OFF, "设备离线");
        }

        /// 
        /// 更新固件版本信息
        /// 
        public static void Version(string deviceno, string ver)
        {
            var key_device = RedisKey.ExistDevice(deviceno);
            var device = RedisHelper.Get(key_device); if (null == device) return;

            // datachange update -> redis&&mysql
            if (device.Version != ver)
            {
                device.Version = ver;

                RedisHelper.Set(key_device, device);

                FreeSqlHelper.UpdateDeviceVersion(deviceno, ver);

                InsertDeviceLog(deviceno, BaseEnum.DeviceLog_Control, $"变更固件版本:{ver}");
            }
        } 

        /// 
        /// 更新设备充电宝公开数量
        /// 
        public static void SlotPublishCount(string deviceno, int canborrow, int[] arrSlotId)
        {
            var key_device = RedisKey.ExistDevice(deviceno);
            var device = RedisHelper.Get(key_device); if (null == device) return;

            //if (device.CanBorrow != canborrow) // redis数据有变更时才更新mysql数据
            //{ 
            device.CanBorrow = canborrow; if (device.SlotCount == 0) device.SlotCount = device.CanBorrow;

            device.CanReturn = device.SlotCount - device.CanBorrow; if (device.CanReturn < 0) device.CanReturn = 0;

            RedisHelper.Set(key_device, device);

            FreeSqlHelper.UpdateDeviceSlotPublishCount(deviceno, device.SlotCount, device.CanBorrow, device.CanReturn);
             
            if (arrSlotId.Length > 0)
            {
                // 卡口内没有电池的数据置空
                var items = FreeSqlHelper.GetSlotWithoutBattery(deviceno, arrSlotId);
                foreach (var item in items)
                {
                    item.BatteryNo = string.Empty;
                    RedisHelper.Set(RedisKey.ExistSlot(deviceno, item.SlotId), item);
                }

                FreeSqlHelper.ClearSlotWithoutBattery(deviceno, arrSlotId);
            }

            //InsertDeviceLog(deviceno, BaseEnum.DeviceLog_Control, $"变更设备充电宝数量:{count}");
            //}
        }

        /// 
        /// 更新机柜信息
        ///  
        public static void Info(string deviceno, int slotid, string batteryno, int level)
        {
            if (string.IsNullOrEmpty(deviceno)) return;

            // query -> redis&&mysql
            var key_slot = RedisKey.ExistSlot(deviceno, slotid);

            var slot = RedisHelper.Get(key_slot);

            if (null == slot)
            {
                slot = FreeSqlHelper.GetSlot(deviceno, slotid);

                if (null == slot)
                {
                    slot = new Slot() { DeviceNo = deviceno, SlotId = slotid, BatteryNo = batteryno, LockStatus = BaseEnum.Statue_OFF };

                    FreeSqlHelper.InsertSlot(slot);
                }

                RedisHelper.Set(key_slot, slot);// 添加redis默认数据
            }

            // datachange update -> redis&&mysql
            if (slot.DeviceNo != deviceno || slot.SlotId != slotid || slot.BatteryNo != batteryno)
            {
                slot.DeviceNo = deviceno; slot.SlotId = slotid; slot.BatteryNo = batteryno;

                RedisHelper.Set(key_slot, slot);

                FreeSqlHelper.UpdateSlot(deviceno, slotid, batteryno); 
            }

            // query -> redis&&mysql
            var key_battery = RedisKey.ExistBattery(batteryno);

            var battery = RedisHelper.Get(key_battery);

            if (null == battery)
            {
                battery = FreeSqlHelper.GetBattery(batteryno);

                if (null == battery)
                { 
                    battery = new Battery() { BatteryNo = batteryno, Level = level, UseStatus = BaseEnum.UseStatus_Free };

                    FreeSqlHelper.InsertBattery(battery);
                }

                RedisHelper.Set(key_battery, battery);// 添加redis默认数据
            }

            // datachange update -> redis&&mysql
            if (battery.Level != level)
            {
                battery.Level = level;

                RedisHelper.Set(key_battery, battery);

                FreeSqlHelper.UpdateBatteryLevel(batteryno, level);
            }

            // 在仓标识空闲
            if (battery.UseStatus != BaseEnum.UseStatus_Free)
            {
                battery.UseStatus = BaseEnum.UseStatus_Free;

                RedisHelper.Set(key_battery, battery);

                FreeSqlHelper.UpdateBatteryFreeStatus(batteryno);
            }

            // 离线归还,结算计费
            var key_order = RedisKey.GetBorrowBattery(batteryno); 
            var order = RedisHelper.Get(key_order);

            if (null != order)
            { 
                if (FreeSqlHelper.IsOffReturnOrder(batteryno))
                {
                    ReturnResult(deviceno, slotid, batteryno, "离线归还");
                }
            }
        }

        /// 
        /// 更新出的设备信息
        /// 
        public static void HandleOut(bool result, string deviceno, int slotid, string batteryno, string orderno, int logtype, string logcontent)
        {
            if (result)
            {
                UpdateDeviceSlotInfo(deviceno, -1);// 数量-1

                UpdateSlotBattery(deviceno, slotid, string.Empty);

                UpdateBatteryStatus(batteryno, BaseEnum.UseStatus_Use);
            }

            InsertBatteryLog(deviceno, slotid, batteryno, orderno, logtype, logcontent);
        }

        /// 
        /// 更新入的设备信息
        /// 
        public static void HandleIn(string deviceno, int slotid, string batteryno, string orderno, int logtype, string logcontent)
        { 
            UpdateDeviceSlotInfo(deviceno, 1);// 数量+1

            UpdateSlotBattery(deviceno, slotid, batteryno);

            UpdateBatteryStatus(batteryno, BaseEnum.UseStatus_Free);

            InsertBatteryLog(deviceno, slotid, batteryno, orderno, logtype, logcontent);
        }

        /// 
        /// 更新设备可借数量(mysql+resid)
        /// 
        public static void UpdateDeviceSlotInfo(string deviceno, int num)
        {
            var key_device = RedisKey.ExistDevice(deviceno);
            var device = RedisHelper.Get(key_device); if (null == device) { device = FreeSqlHelper.GetDevice(deviceno); RedisHelper.Set(key_device, device); }

            device.CanBorrow = device.CanBorrow + num;
            device.CanReturn = device.SlotCount - device.CanBorrow; if (device.CanReturn < 0) device.CanReturn = 0;

            RedisHelper.Set(key_device, device);
            FreeSqlHelper.UpdateDeviceSlotPublishCount(deviceno, device.SlotCount, device.CanBorrow, device.CanReturn);
        }

        /// 
        /// 更新卡口电池(mysql+resid)
        /// 
        public static void UpdateSlotBattery(string deviceno, int slotid, string batteryno)
        {
            var key_slot = RedisKey.ExistSlot(deviceno, slotid);
            var slot = RedisHelper.Get(key_slot); if (null == slot) { slot = FreeSqlHelper.GetSlot(deviceno, slotid); RedisHelper.Set(key_slot, slot); }

            slot.DeviceNo = deviceno;
            slot.SlotId = slotid;
            slot.BatteryNo = batteryno;

            RedisHelper.Set(key_slot, slot);
            FreeSqlHelper.UpdateSlotBattery(deviceno, slotid, batteryno);
        }

        /// 
        /// 更新电池状态(mysql+resid)
        /// 
        public static void UpdateBatteryStatus(string batteryno, int usestatus)
        {
            var key_battery = RedisKey.ExistBattery(batteryno);
            var battery = RedisHelper.Get(key_battery); if (null == battery) { battery = FreeSqlHelper.GetBattery(batteryno); RedisHelper.Set(key_battery, battery); }

            battery.BatteryNo = batteryno;
            battery.UseStatus = usestatus;

            RedisHelper.Set(key_battery, battery);
            FreeSqlHelper.UpdateBatteryStatus(batteryno, usestatus);
        }

        /// 
        ///  强制弹出结果
        /// 
        public static void PopUpResult(string deviceno, int slotid, string batteryno, bool result)
        {
            HandleOut(result, deviceno, slotid, batteryno, "", BaseEnum.DeviceLog_Force, result ? "强制弹出成功" : "强制弹出失败");
        }

        /// 
        /// 借充电宝结果
        /// 
        public static void BorrowResult(string deviceno, int slotid, string batteryno, bool result)
        {
            var time = DataHelper.GetNowTimeEntity(); string orderno = string.Empty;

            if (result)
            {
                var key_device = RedisKey.GetBorrowDevice(deviceno, slotid, batteryno);
                var order = RedisHelper.Get(key_device);

                if (null == order)
                {
                    order = FreeSqlHelper.GetBorrowOrder(deviceno, slotid, batteryno, BaseEnum.OrderStatus_BorrowStart);
                }
                orderno = order.OrderNo;
                order.BorrowTime = time.Time;
                order.BorrowTimeStamp = time.TimeStamp;
                order.OrderStatus = BaseEnum.OrderStatus_BorrowSuccess;
                RedisHelper.Set(RedisKey.GetBorrowBattery(order.BatteryNo), order);
            }

            // 更新数据库租借信息
            FreeSqlHelper.UpdateOrderBorrowStatus(deviceno, slotid, batteryno, time.Time, time.TimeStamp, (result ? BaseEnum.OrderStatus_BorrowSuccess : BaseEnum.OrderStatus_BorrowFail));

            HandleOut(result, deviceno, slotid, batteryno, orderno, BaseEnum.DeviceLog_Brrow, result ? "租借成功" : "租借失败");
        }

        /// 
        /// 归还电宝结果
        /// 
        public static void ReturnResult(string deviceno, int slotid, string batteryno, string note)
        { 
            bool exist_order = true;

            var time = DataHelper.GetNowTimeEntity();

            // 根据batteryno查询订单信息(redis && mysql)
            var key_order = RedisKey.GetBorrowBattery(batteryno);

            var order = RedisHelper.Get(key_order);

            if (null == order)
            {
                order = FreeSqlHelper.GetBorrowOrder("", -1, batteryno, BaseEnum.OrderStatus_BorrowSuccess);

                if (null == order)
                {
                    exist_order = false;
                }
            }

            HandleIn(deviceno, slotid, batteryno, (exist_order ? order.OrderNo : string.Empty), BaseEnum.DeviceLog_Return, (exist_order ? $"{note}成功" : $"{note}失败,未找到租借订单"));

            if (!exist_order) return;// 不存在订单则跳出

            // 根据deviceno查询店铺信息(redis && mysql)
            var key_shop = RedisKey.ExistShop(deviceno);
            var shop = RedisHelper.Get(key_shop);
            if (null == shop)
            {
                shop = FreeSqlHelper.GetShop(deviceno); if (null != shop) RedisHelper.Set(key_shop, shop);
            }

            // 计算费用
            decimal moneyTotal = 0; string timeTotal = string.Empty;
            PayMoney.GetMoney(time.TimeStamp, order.BorrowTimeStamp, shop, ref moneyTotal, ref timeTotal);

            // 费用入账
            var dtNow = DateTime.Now;
            var timestamp = DataHelper.GetTimestamp(dtNow);
            var player = FreeSqlHelper.GetPlayer(order.OpenId);
            var openid = player.OpenId;

            // 添加交易日志
            // 用户扣款 + 更新账户余额
            if (0 != moneyTotal)
            {
                int excute_result = FreeSqlHelper.freeSql.Ado.ExecuteNonQuery($"update player set Money=Money-{moneyTotal} where OpenId='{openid}'");

                if (0 == excute_result)
                {
                    Logger.Info($"用户扣款失败,orderno={order.OrderNo},openid={openid},moneyTotal={moneyTotal},excute_result={excute_result}");
                }
                else
                {
                    Logger.Info($"用户扣款成功,orderno={order.OrderNo},openid={openid},moneyTotal={moneyTotal},excute_result={excute_result}");
                    FreeSqlHelper.InstertFundLog(new FundLog() { TradeNo = "", Account = openid, LogTimeStamp = timestamp, LogTime = dtNow, FundMoney = moneyTotal, FundType = BaseEnum.FundLog_Customer_Remove });

                    if (null == shop)
                    {
                        // 钱直接进平台
                        excute_result = FreeSqlHelper.freeSql.Ado.ExecuteNonQuery($"update player set Money=Money+{moneyTotal} where Account='{BaseEnum.PlatformAccount}'");
                        if (0 == excute_result)
                        {
                            Logger.Info($"平台收益失败,orderno={order.OrderNo},Account={BaseEnum.PlatformAccount},moneyTotal={moneyTotal},excute_result={excute_result},分成比例=10");
                        }
                        else
                        {
                            Logger.Info($"平台收益成功,orderno={order.OrderNo},Account={BaseEnum.PlatformAccount},moneyTotal={moneyTotal},excute_result={excute_result},分成比例=10");
                            FreeSqlHelper.InstertFundLog(new FundLog() { TradeNo = "", Account = BaseEnum.PlatformAccount, LogTimeStamp = timestamp, LogTime = dtNow, FundMoney = moneyTotal, FundType = BaseEnum.FundLog_Platform_Add });
                        }
                    }
                    else
                    {
                        // 跟商户分
                        var moneyTotal1 = Math.Round(moneyTotal * Convert.ToDecimal(shop.Ratio / 10.0), 2);
                        excute_result = FreeSqlHelper.freeSql.Ado.ExecuteNonQuery($"update player set Money=Money+{moneyTotal1} where Account='{shop.Account}'");
                        if (0 == excute_result)
                        {
                            Logger.Info($"商户收益失败,orderno={order.OrderNo},Account={shop.Account},moneyTotal={moneyTotal1},excute_result={excute_result}");
                        }
                        else
                        {
                            Logger.Info($"商户收益成功,orderno={order.OrderNo},Account={shop.Account},moneyTotal={moneyTotal1},excute_result={excute_result},分成比例={shop.Ratio}");
                            FreeSqlHelper.InstertFundLog(new FundLog() { TradeNo = "", Account = shop.Account, LogTimeStamp = timestamp, LogTime = dtNow, FundMoney = moneyTotal1, FundType = BaseEnum.FundLog_Shop_Add });
                        }

                        var moneyTotal2 = Convert.ToDecimal(moneyTotal) - moneyTotal1;
                        excute_result = FreeSqlHelper.freeSql.Ado.ExecuteNonQuery($"update player set Money=Money+{moneyTotal2} where Account='{BaseEnum.PlatformAccount}'");

                        if (0 == excute_result)
                        {
                            Logger.Info($"平台收益失败,orderno={order.OrderNo},Account={BaseEnum.PlatformAccount},moneyTotal={moneyTotal2},excute_result={excute_result},分成比例={ 10 - shop.Ratio }");
                        }
                        else
                        {
                            Logger.Info($"平台收益成功,orderno={order.OrderNo},Account={BaseEnum.PlatformAccount},moneyTotal={moneyTotal2},excute_result={excute_result},分成比例={ 10 - shop.Ratio }");
                            FreeSqlHelper.InstertFundLog(new FundLog() { TradeNo = "", Account = BaseEnum.PlatformAccount, LogTimeStamp = timestamp, LogTime = dtNow, FundMoney = moneyTotal2, FundType = BaseEnum.FundLog_Platform_Add });
                        }
                    }
                }
            } 

            // 清除redis中的订单数据
            RedisHelper.Remove(RedisKey.GetBorrowBattery(batteryno));

            // 更新数据库归还信息
            long shopid = 0; string shopname = ""; if (null != shop) { shopid = shop.Id; shopname = shop.ShopName; }
            FreeSqlHelper.UpdateOrderReturn(batteryno, deviceno, slotid, shopid, shopname, time.Time, time.TimeStamp, moneyTotal, moneyTotal, timeTotal); 
        }
        
        /// 
        /// 是否能租借
        /// 
        public static string IsCanBorrow(string deviceno, string openid)
        {
            var key_shop = RedisKey.ExistShop(deviceno);
            var shop = RedisHelper.Get(key_shop);
            if (null == shop)
            {
                shop = FreeSqlHelper.GetShop(deviceno); if (null != shop) RedisHelper.Set(key_shop, shop);
            }
            if (null == shop) return "";// 店铺未绑定设备,可免费使用
            if (null != shop && BaseEnum.Statue_OFF == shop.IsPremium) return "";// 店铺设置免费

            // 收费需要用户注册
            var player = FreeSqlHelper.GetPlayer(openid);
            if (null == player) return "未找到用户信息";

            if (player.Money < shop.Pledge) return "用户余额不足";

            return "";
        }
    }
}

你可能感兴趣的:(共享充电宝,net6,mysql,+,redis)