1.1项目场景和分析
在电动汽车的技术不断进步,成本逐渐下降的情况下,许多国家纷纷出台了鼓励购买电动汽车的政策,使得更多人能够接受和购买电动汽车。 家用电动汽车的普及和拥有量的激增,车主在充电方面遇到了一些问题。车主对于使用公共充电桩存在疑虑,包括快充可能对电池造成损害、排队等待时间过长、价格贵等问题。私人充电桩资源闲置,未能有效利用,导致资源浪费和未能实现最大化价值。
1.2项目的意义
- 环境保护:随着电动汽车的普及,传统的燃油车逐渐被替代,从而减少了化石燃料的消耗和温室气体的排放。这不仅有助于改善空气质量,还能减少对环境的污染,为可持续发展做出贡献。共享充电桩的建立可以避免重复建设充电设施,节约了大量的资源和成本。此外,通过优化充电桩的分布和使用效率,可以进一步减少能源消耗和环境污染。
- 经济效益:私人共享充电桩系统为桩主提供了额外的收入来源,鼓励个人投资充电桩,推动了共享经济的发展。这种模式既能够降低用户的充电成本,又能够提高充电桩的使用效率,实现资源的优化配置。充电桩的普及和便利性的提高,更多的人愿意选择购买电动汽车,从而推动了电动汽车市场的发展。这对于汽车行业和相关产业链的发展具有积极的推动作用。
- 社会效益:私人共享充电桩系统提高了充电桩的可达性和便利性,特别是在公共充电桩不足的地区。用户可以根据自己的需求随时随地找到充电桩,不再受限于地理位置和充电桩的分布。这有助于提高用户的满意度和便利性,推动电动汽车的普及。电动汽车的普及有助于减少城市交通拥堵和噪音污染,改善城市居民的生活质量。同时,共享充电桩的建立也有助于促进城市可持续发展,推动绿色出行成为主流。
- 技术发展:私人共享充电桩系统的建立推动了充电技术的创新和发展。例如,无线充电技术和快速充电技术的应用,使得充电更加便捷和高效。这有助于提高充电桩的竞争力和用户体验。共享充电桩系统需要运用物联网、移动支付、大数据分析等先进技术,这些技术的应用不仅提高了充电桩的智能化水平,也为其他行业提供了技术借鉴和应用场景。
- 能源管理:私人共享充电桩系统可以通过智能管理系统实现充电桩的远程监控和能源需求管理。这有助于优化电网负荷,减少能源浪费,提高能源利用效率。通过鼓励在非高峰时段充电,共享充电桩系统有助于平衡电网供需,减轻电网压力。这有助于提高能源系统的稳定性和可靠性,促进能源的可持续发展。
1.3解决方案
为了解决电动汽车充电需求与公共充电桩不足的问题,我们提出了一套私人共享充电桩系统。该系统通过整合私人充电桩资源,提供给有需要的电动汽车用户使用,同时为桩主带来一定的收入。系统包括小程序、桩主端管理平台和系统管理员端监控系统,采用移动支付、扫一扫分析等技术,实现充电桩的远程监控、预约、支付和管理等功能。
2.1功能
图1:系统框架图
2.1.1充电用户功能
用户可以通过微信号进行注册登录。
用户搜索可通过地图功能查看附近的充电桩位置。系统会根据用户的位置信息提供最近的充电桩列表。用户可以查看充电桩的详细信息。
用户可以查看自己的充电历史记录,包括充电时间、充电时长、费用等。系统提供时间筛选功能,方便用户查找特定时间段的充电记录。
可以查看自己的预约历史,包括预约时间、充电桩编号等。系统提供时间筛选功能,方便用户查找特定时间段的预约记录。
用户可以查看自己的支付历史,包括支付时间、支付金额、支付方式等。系统提供时间筛选功能,方便用户查找特定时间段的支付记录。
用户可以修改个人资料,如联系方式、邮箱等。用户可以修改密码,确保账户安全。用户可以设置账户偏好,如充电偏好、支付方式等。
2.1.2桩主功能
桩主需要注册账户以管理他们的充电桩。注册时,桩主需提供个人信息和充电桩的基本信息。
桩主可以查看和管理他们拥有的所有充电桩。商家可以查看充电桩的实时状态,如空闲、使用中、故障等。商家可以修改充电桩的设置,如价格、可用时间等。
桩主可以选择将充电桩授权给其他用户使用。可以设置授权用户的权限,如是否允许充电、预约等。
桩主可以查看所有充电桩的收入记录。可以查看每笔交易的详细信息,如交易时间、交易金额、用户信息等。
桩主经过审核成功成为区域代理后,可以查看他们作为区域代理的充电桩列表。鼓励在该区域商家投放更多充电桩,并提高分红。
桩主在热门充电区域可以申请成为某个区域的代理,以便管理和监控该区域的充电桩,需要提供相关资质和承诺,以获得区域代理的资格。
2.1.3管理员功能
管理员可以查看所有区域代理人的基本信息,如电话号、充电桩编号等。管理员可以对区域代理人进行增删改操作。
管理员可以查看所有充电桩的基本信息,如桩号、位置、充电功率、空闲状态等。管理员可以对充电桩进行增删改操作。
管理员可以查看所有注册用户的个人信息,包括姓名、联系方式、车辆信息等。管理员可以对用户进行增删改操作。
管理员可以查看所有充电桩的预约记录,包括预约时间、用户信息、预约状态等。管理员可以对预约记录进行查询、导出等操作。
管理员可以查看所有充电桩的支付记录,包括交易时间、交易金额、用户信息等。可以对支付记录进行查询、导出等操作。
管理员可以查看所有充电桩的充电记录,包括充电时间、充电时长、用户信息等。管理员可以对充电记录进行查询、导出等操作。
管理员可以查看所有充电桩的电子授权记录,包括授权时间、授权用户、授权状态等。可以对电子授权记录进行查询、导出等操作。
管理员可以查看所有桩主的区域代理申请记录,包括充电桩编号,桩主个人信息等。可以对申请区域代理记录进行查询、导出等操作。
管理员可以查看所有地区充电桩的充电次数和用电量。管理员可以对充电次数高的地区给予桩主更高的电价,以起激励作用。
2.2业务逻辑
图2:充电预约业务流程
2.3数据字典
2.3.1用户基本信息表
数据编号 | 数据名 | 数据类型 | 数据描述 |
A01 | 用户ID (UserID) | 整数 | 唯一标识用户的数字标识符 |
A02 | 昵称 (Nickname) | 字符串 (String) | 用户的账号昵称 |
A03 | 真实姓名 (Full Name) | 字符串 (String) | 用户的真实姓名 |
A04 | 身份证 | 整数 (String) | 用户的身份证号信息 |
A05 | 账号 (Username) | 字符串 (String) | 用户用于登录的微信号名称 |
A06 | 账号密码 (Password) | 字符串 (String) | 用户的登录密码,应当进行安全加密存储 |
2.3.2充电桩信息表
数据编号 | 数据名 | 数据类型 | 数据描述 |
B01 | 充电桩ID | 整数 | 唯一标识充电桩的数字标识符 |
B02 | 地址 | 文本 | 充电桩地址 |
B03 | 状态 | 枚举 | 充电桩的状态 |
B04 | 可充电时间 | 日期 | 充电桩的可充电时间 |
B05 | 每度电价格 | 浮点数 | 充电桩的每度电价格 |
2.3.3充电记录表
数据编号 | 数据名 | 数据类型 | 数据描述 |
C01 | 充电桩ID | 文本 | 唯一标识充电桩的数字标识符 |
C02 | 地址 | 文本 | 充电桩地址 |
C03 | 实际充电时间 | 日期 | 实际充电桩的充电时间 |
C04 | 价格 | 浮点数 | 充电桩的价格 |
C05 | 充电状态 | 枚举 | 充电桩充电状态 |
2.3.4预约记录表
数据编号 | 数据名 | 数据类型 | 数据描述 |
D01 | 充电桩ID | 文本 | 唯一标识充电桩的数字标识符 |
D02 | 地址 | 文本 | 充电桩地址 |
D03 | 预约状态 | 枚举 | 充电桩的预约状态 |
D04 | 充电时间 | 日期 | 充电桩的充电时间 |
D05 | 每度电价格 | 浮点数 | 充电桩的每度电价格 |
2.3.5支付记录表
数据编号 | 数据名 | 数据类型 | 数据描述 |
E01 | 充电桩ID | 文本 | 唯一标识充电桩的数字标识符 |
E02 | 地址 | 文本 | 充电桩地址 |
E03 | 充电时间 | 日期 | 充电桩的充电时间 |
E04 | 总价格 | 浮点数 | 充电桩的总价格 |
E05 | 支付状态 | 枚举 | 充电桩的支付状态 |
2.3.6授权充电桩表
数据编号 | 数据名 | 数据类型 | 数据描述 |
F01 | 充电桩ID | 整数 | 唯一标识充电桩的数字标识符 |
F02 | 地址 | 文本 | 充电桩地址 |
F03 | 充电预约时间 | 日期 | 充电桩的充电预约时间 |
F04 | 授权状态 | 枚举 | 是否允许充电桩授权 |
2.3.7区域代理表
数据编号 | 数据名 | 数据类型 | 数据描述 |
G01 | 充电桩ID | 文本 | 唯一标识充电桩的数字标识符 |
G02 | 桩主ID | 文本 | 桩主的名称 |
G03 | 地址 | 文本 | 充电桩地址 |
G04 | 价格 | 浮点数 | 充电桩的每度点的充电价格 |
G05 | 代理分成 | 浮点数 | 充电桩代理的分成 |
2.3.8管理申请区域代理表
数据编号 | 数据名 | 数据类型 | 数据描述 |
H01 | 申请充电桩ID | 文本 | 唯一标识充电桩的数字标识符 |
H02 | 桩主ID | 文本 | 桩主的名称 |
H03 | 地址 | 文本 | 充电桩地址 |
2.3.9统计区域充电次数表
数据编号 | 数据名 | 数据类型 | 数据描述 |
I01 | 充电桩地址总充电数 | 整数 | 统计充电桩近俩个月的总充电数 |
I02 | 充电桩ID | 文本 | 充电桩的名称 |
I03 | 充电桩地址 | 文本 | 充电桩地址 |
2.4数据流图
图3:数据流图
三、数据库设计
3.1概念设计
它的概念设计中包含4个实体:
车主(用户ID、姓名、身份证、电话、名称)
桩主(桩主ID、身份证、电话、名称、真实姓名)
充电桩信息(充电桩ID、可充电时间、地址、空闲状态、每度电价格)
充电记录(充电桩ID、充电总价格、实际充电时间)
根据他们属性画出他们的部分E-R图
图4:E-R图部分设计——车主预约充电桩信息
图5:E-R部分设计——车主申请桩主充授权
图6:E-R部分设计——桩主申管理充电桩
图7:整体E-R图
3.2逻辑设计
它的概念设计中包含4个实体,6种关系,根据属性得出他们的逻辑分别如下:
车主(用户ID、姓名、身份证、电话、名称)
桩主(桩主ID、身份证、电话、名称、真实姓名)
充电桩信息(充电桩ID、可充电时间、地址、空闲状态、每度电价格)
充电记录(充电桩ID、充电总价格、实际充电时间)
管理(充电桩ID、桩主ID)
申请授权(预约时间、授权状态、地址、充电桩ID)
支付(用户ID、桩主ID、支付时间、价格、支付状态)
预约(充电桩ID、车主ID、预约时间)
申请区域代理管理(桩主ID、充电桩ID、每度点分成)
授权(桩主ID、车主ID、充电桩ID、实际充电时间、充电总价格)
3.3物理设计
私人共享充电桩系统的数据库物理设计中,我们小组使用了MySQL数据库管理系统。并考虑了以下因素:
(1)将数据文件存储在SSD硬盘上,以提高查询和写入性能。数据文件应根据数据量进行分割,以避免单个文件过大导致性能瓶颈。将日志文件存储在独立的机械硬盘上,避免对数据文件性能的影响。日志文件应根据日志量进行分割,避免单个文件过大导致性能瓶颈。
(2)设计各表的存储引擎,提高读取速率和数据安全性,各表设计引如下:
用户信息表:设计为MyISAM存储引擎,以支持高速读取。
充电桩表:设计为InnoDB存储引擎,适合需要事务支持的场景、支持事务处理和外键约束。
预约记录表:设计为InnoDB存储引擎,保证预约和充电操作的一致性
支付记录表:设计为InnoDB存储引擎,需要支持事务处理,确保支付操作的完整性
充电记录表:设计为InnoDB存储引擎,以支持事务处理和外键约束。
电子授权表:设计为MyISAM存储引擎,以支持高速读取。
管理申请区域代理表表:设计为MyISAM存储引擎,以支持高速读取。
电子授权表:设计为MyISAM存储引擎,以支持高速读取。
统计区域充电次数表:虽然这个表可能主要用于统计充电次数,但考虑到可能需要进行复杂的查询操作,以及可能涉及的事务处理和外键约束,InnoDB存储引擎更适合。
(3)并更改索引设计,提高查询性能与数据完整性 :
用户信息表 :以用户ID字段创建索引,加快用户查询速度。
充电桩表:以充电桩ID字段创建索引,加快充电桩查询速度。
预约记录表:以充电桩ID字段创建索引,加快预约查询速度。
支付记录表 :以充电桩ID字段创建索引,加快支付查询速度。
充电记录表 :以充电桩ID字段创建索引,加快充电记录查询速度。
电子授权表 :以用户ID字段创建索引,加快电子授权查询速度。
管理申请区域代理表 :以用户ID字段创建索引,加快管理申请查询速度。
统计区域充电次数表 :以充电桩ID字段创建索引,加快区域充电次数的查询速
(4)查询优化:分析查询执行计划,优化查询语句,对于频繁查询的字段,使用覆盖索引。
- 数据备份与恢复:定期进行全量备份和增量备份,并将备份存储在安全的存储设备上。全量备份每周进行一次,设计恢复机制,以快速恢复数据,确保数据安全性。使用mysqldump进行备份,使用mysql进行恢复。
(6)安全与权限控制:开启了用户认证机制,只有管理员用户能够访问数据库。我们使用了MySQL的插件mysql_native_password设置不同用户和角色的访问权限,以保护敏感数据。
四、系统功能设计
4.1功能层次
4.1.1用户界面
桩主和车主的各个功能按钮和管理员登录按钮
图8:用户界面
4.1.2我的界面
图9:我的界面
4.1.3管理员界面
图10:管理员界面
4.1.4地图界面
图11:地图界面
4.1.5充电记录界面
图12:充电记录界面
4.1.6预约界面
图13:预约界面
4.1.7聊天界面
图14:聊天界面
4.1.8预约记录界面
图15:预约记录界面
4.1.9我的充电桩界面
图16:我的充电桩界面
4.1.10收款记录界面
图17:收款记录界面
4.1.11我的区域代理界面
图18:区域代理界面
4.1.12用户信息界面
图19:用户信息界面
4.1.13充电桩信息界面
图20:充电桩信息界面
4.1.14充电记录界面
图20:充电记录界面
4.1.15钱包界面
图21:钱包界面
4.1.16个人信息界面
图22:个人信息界面
4.1.17桩主授权界面
图23:桩主授权界面
4.1.18申请区域代理界面
图24:申请区域代理界面
4.2功能流程
图25:功能流程界面
4.3功能模块设计
主要包括车主、桩主和管理员三大功能模块。
26:功能模块设计
五、项目开发和运行的技术环境
5.1微信开发者工具
微信开发者工具是微信官方提供的针对微信小程序的开发工具,集中了开发,调试,预览,上传等功能。微信团队发布了微信小程序开发者工具、微信小程序开发文档和微信小程序设计指南,全新的开发者工具,集成了开发调试、代码编辑及程序发布等功能,帮助开发者简单和高效地开发微信小程序。
启动工具时,开发者需要使用已在后台绑定成功的微信号扫描二维码登录,后续所有的操作都会基于这个微信的帐号
5.2 MySQL
MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。
5.3 idea
IDEA 全称IntelliJ IDEA,是用于java语言开发的集成环境(也可用于其他语言),IntelliJ在业界被公认为最好的java开发工具之一,尤其在智能代码助手、代码自动提示、重构、J2EE支持、Ant、JUnit、CVS整合、代码审查、 创新的GUI设计等方面的功能可以说是超常的。
六、系统实现
6.1小程序配置和描述小程序页面的结构、样式、数据代码
{
"pages": [
"pages/index/index",
"pages/logs/logs",
"pages/admin/admin",
"pages/chargerList/chargerList",
"pages/charge/charge",
"pages/user/user",
"pages/mapPage/mapPage",
"pages/reservationList/reservationList",
"pages/chargeRecords/chargeRecords",
"pages/paymentRecords/paymentRecords",
"pages/mine/mine",
"pages/reservationDetail/reservationDetail",
"pages/wallet/wallet",
"pages/collectionRecords/collectionRecords",
"pages/myCharge/myCharge",
"pages/editCharger/editCharger",
"pages/myAgent/myAgent"
],
"window": {
"navigationBarTextStyle": "black",
"navigationStyle": "custom",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTitleText": "",
"backgroundColor": "#eeeeee",
"backgroundTextStyle": "light"
},
"style": "v2",
"rendererOptions": {
"skyline": {
"defaultDisplayBlock": true,
"disableABTest": true,
"sdkVersionBegin": "3.0.0",
"sdkVersionEnd": "15.255.255"
}
},
"permission": {
"scope.userLocation": {
"desc": "你的位置信息将用于显示当前位置"
}
},
"requiredPrivateInfos": [
"getLocation"
],
"componentFramework": "glass-easel",
"sitemapLocation": "sitemap.json",
"lazyCodeLoading": "requiredComponents"
}
6.2管理员
此页面实现跳转充电桩表、用户信息表、预约记录表、支付记录表、充电记录表和电子授权表功能
界面代码:
<view class="container">
<view class="title">管理员界面</view>
<view class="button-grid">
<button class="menu-button" bindtap="onChargerListTap">充电桩表</button>
<button class="menu-button" bindtap="onUserInfoTap">用户信息表</button>
<button class="menu-button" bindtap="onReservationRecordsTap">预约记录表</button>
<button class="menu-button" bindtap="onPaymentRecordsTap">支付记录表</button>
<button class="menu-button" bindtap="onChargeRecordsTap">充电记录表</button>
<button class="menu-button" bindtap="onAuthorizationRecordsTap">电子授权表</button>
</view>
</view>
逻辑代码:
Page({
data: {},
onChargerListTap() {
wx.navigateTo({
url: '/pages/chargerList/chargerList'
});
},
onUserInfoTap() {
wx.navigateTo({
url: '/pages/userInfo/userInfo'
});
},
onReservationRecordsTap() {
wx.navigateTo({
url: '/pages/reservationRecords/reservationRecords'
});
},
onPaymentRecordsTap() {
wx.navigateTo({
url: '/pages/paymentRecords/paymentRecords'
});
},
onChargeRecordsTap() {
wx.navigateTo({
url: '/pages/chargeRecords/chargeRecords'
});
},
onAuthorizationRecordsTap() {
wx.navigateTo({
url: '/pages/authorizationRecords/authorizationRecords'
});
}
});
6.3用户功能
实现了地图查找充电桩功能、充电、预约和支付记录功能
界面代码:
<view class="container">
<view class="title">私人充电桩共享系统</view>
<view class="button-grid">
<button class="menu-button" bindtap="onNearbyChargersTap">附近的充电桩</button>
<button class="menu-button" bindtap="onChargeRecordsTap">充电记录</button>
<button class="menu-button" bindtap="onReservationRecordsTap">预约记录</button>
<button class="menu-button" bindtap="onPaymentRecordsTap">支付记录</button>
<button class="menu-button" bindtap="onMyChargersTap">我的充电桩</button>
<button class="menu-button" bindtap="onAuthorizeChargersTap">授权充电桩</button>
<button class="menu-button" bindtap="onCollectionRecordsTap">收款记录</button>
<button class="menu-button" bindtap="onMyAgentTap">我的区域代理</button>
<button class="menu-button" bindtap="onApplyAgentTap">申请区域代理</button>
</view>
<view class="bottom-buttons">
<button bindtap="onUserHomeTap" class="{{activePage == 'user' ? 'active' : ''}}">user主页</button>
<button bindtap="onMineTap" class="{{activePage == 'mine' ? 'active' : ''}}">我的</button>
</view>
<button class="admin-login-button" bindtap="showAdminLoginDialog">管理员登录</button>
<view wx:if="{{showAuthorizeDialog}}" class="dialog">
<view class="dialog-content">
<text class="dialog-text">{{authorizeMessage}}</text>
<button class="menu-button" bindtap="onAuthorizeTap">授权</button>
<button class="menu-button" bindtap="onChatTap">聊天</button>
<button class="menu-button" bindtap="onCloseDialogTap">关闭</button>
</view>
</view>
<view wx:if="{{showApplyAgentDialog}}" class="dialog">
<view class="dialog-content">
<text class="dialog-text" wx:if="{{!applicationSubmitted}}">充电桩的名字</text>
<text class="dialog-text" wx:if="{{applicationSubmitted}}">待审核</text>
<input class="input" value="{{applyAgentName}}" bindinput="onInputChange" wx:if="{{!applicationSubmitted}}"/>
<button class="menu-button" bindtap="onApplyAgentSubmitTap" wx:if="{{!applicationSubmitted}}">申请</button>
<button class="menu-button" bindtap="onCloseApplyAgentDialogTap">关闭</button>
</view>
</view>
<view wx:if="{{showAdminDialog}}" class="dialog">
<view class="dialog-content">
<text class="dialog-text">管理员密码:</text>
<input class="input" type="password" placeholder="请输入密码" bindinput="onAdminPasswordInput"/>
<button class="dialog-button" bindtap="adminLogin">登录</button>
<button class="dialog-button" bindtap="closeAdminLoginDialog">关闭</button>
<text class="error-text" wx:if="{{adminLoginError}}">密码错误</text>
</view>
</view>
</view>
逻辑代码:
Page({
data: {
activePage: 'user',
showAuthorizeDialog: false,
authorizeMessage: '',
showApplyAgentDialog: false,
applyAgentMessage: '',
applyAgentName: '',
applicationSubmitted: false,
showAdminDialog: false,
adminPassword: '',
adminLoginError: false
},
onNearbyChargersTap() {
wx.navigateTo({
url: '/pages/mapPage/mapPage'
});
},
onReservationRecordsTap() {
wx.navigateTo({
url: '/pages/reservationList/reservationList'
});
},
onChargeRecordsTap() {
wx.navigateTo({
url: '/pages/chargeRecords/chargeRecords'
});
},
onPaymentRecordsTap() {
wx.navigateTo({
url: '/pages/paymentRecords/paymentRecords'
});
},
onMyChargersTap() {
wx.navigateTo({
url: '/pages/myCharge/myCharge'
});
},
onAuthorizeChargersTap() {
const randomCharger = `充电桩${Math.floor(Math.random() * 10 + 1)}`;
this.setData({
authorizeMessage: `${randomCharger} 正在申请授权`,
showAuthorizeDialog: true
});
},
onCollectionRecordsTap() {
wx.navigateTo({
url: '/pages/collectionRecords/collectionRecords'
});
},
onMyAgentTap() {
wx.navigateTo({
url: '/pages/myAgent/myAgent'
});
},
onApplyAgentTap() {
const randomCharger = `充电桩${Math.floor(Math.random() * 10 + 1)}`;
this.setData({
applyAgentMessage: `${randomCharger} 申请代理`,
showApplyAgentDialog: true,
applicationSubmitted: false
});
},
onUserHomeTap() {
this.setData({ activePage: 'user' });
wx.navigateTo({
url: '/pages/user/user'
});
},
onMineTap() {
this.setData({ activePage: 'mine' });
wx.navigateTo({
url: '/pages/mine/mine'
});
},
onAuthorizeTap() {
wx.showToast({
title: '授权成功',
icon: 'success',
duration: 2000
});
this.setData({ showAuthorizeDialog: false });
},
onCloseDialogTap() {
this.setData({ showAuthorizeDialog: false });
},
onChatTap() {
wx.navigateTo({
url: '/pages/charge/charge'
});
},
onInputChange(event: any) {
this.setData({ applyAgentName: event.detail.value });
},
onApplyAgentSubmitTap() {
wx.showToast({
title: '申请已提交',
icon: 'success',
duration: 2000
});
this.setData({ applicationSubmitted: true });
},
onCloseApplyAgentDialogTap() {
this.setData({ showApplyAgentDialog: false });
},
showAdminLoginDialog() {
this.setData({
showAdminDialog: true,
adminLoginError: false
});
},
closeAdminLoginDialog() {
this.setData({
showAdminDialog: false,
adminPassword: '',
adminLoginError: false
});
},
onAdminPasswordInput(e: any) {
this.setData({
adminPassword: e.detail.value
});
},
adminLogin() {
if (this.data.adminPassword === 'root') {
wx.navigateTo({
url: '/pages/admin/admin' // 请确保管理员页面的路径正确
});
} else {
this.setData({
adminLoginError: true
});
}
}
});
6.4充电功能
页面代码:
<view class="container">
<view class="header">
<text>聊天</text>
<button bindtap="endCharge">结束充电</button>
<button bindtap="callOwner">电话呼叫</button>
</view>
<view class="chat-window" wx:for="{{messages}}" wx:key="index">
<text>{{item}}</text>
</view>
<view class="input-bar">
<input class="input" value="{{inputMessage}}" bindinput="onInputChange" />
<button bindtap="sendMessage">发送</button>
</view>
</view>
逻辑代码:
Page({
data: {
messages: [] as string[],
inputMessage: ''
},
onInputChange(e: any) {
this.setData({
inputMessage: e.detail.value
});
},
sendMessage() {
const { inputMessage, messages } = this.data;
if (inputMessage.trim()) {
this.setData({
messages: [...messages, inputMessage],
inputMessage: ''
});
}
},
endCharge() {
wx.navigateBack();
},
callOwner() {
wx.makePhoneCall({
phoneNumber: '1234567890' // 请替换为实际电话号码
});
}
});
6.5充电记录信息显示功能
页面代码:
<view class="container">
<view class="details">
<text class="label">名称: {{charger.name}}</text>
<text class="label">地址: {{charger.address}}</text>
<text class="label">充电时间: {{charger.chargeTime}}</text>
<text class="label">总价格: {{charger.totalPrice}} 元</text>
</view>
<button class="button" bindtap="onPayTap">支付</button>
</view>
逻辑代码:
Page({
data: {
charger: {
name: '',
address: '',
chargeTime: '',
totalPrice: 0
}
},
onLoad() {
const charger = this.generateRandomCharger();
this.setData({
charger: charger
});
},
generateRandomCharger() {
const randomTotalPrice = Math.floor(Math.random() * 26) + 25; // 生成 25 到 50 之间的随机数
const chargeTime = this.generateChargeTime();
return {
name: `充电桩${Math.floor(Math.random() * 10 + 1)}`,
address: `地址${Math.floor(Math.random() * 10 + 1)}`,
chargeTime: chargeTime,
totalPrice: randomTotalPrice
};
},
generateChargeTime(): string {
const startHour = Math.floor(Math.random() * 24);
const startMinute = Math.floor(Math.random() * 60);
const endHour = startHour + Math.floor(Math.random() * (24 - startHour));
const endMinute = Math.floor(Math.random() * 60);
const formatTime = (hour: number, minute: number) => {
return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;
};
const startTime = formatTime(startHour, startMinute);
const endTime = formatTime(endHour, endMinute);
return `${startTime}至${endTime}`;
},
onPayTap() {
wx.showToast({
title: '支付成功',
icon: 'success',
duration: 2000
});
}
});
6.6充电桩列表显示功能
页面代码:
<view class="container">
<input class="search-input" placeholder="搜索地址" bindinput="onSearchInput" />
<view wx:for="{{filteredChargers}}" wx:key="id" class="charger-item">
<view class="charger-details">
<text>名称: </text><input value="{{item.name}}" data-index="{{index}}" bindinput="onInputChange" data-field="name" />
<text>地址: </text><input value="{{item.address}}" data-index="{{index}}" bindinput="onInputChange" data-field="address" />
<text>状态: </text><input value="{{item.status}}" data-index="{{index}}" bindinput="onInputChange" data-field="status" />
<text>每日可充电时间: </text><input value="{{item.chargeTime}}" data-index="{{index}}" bindinput="onInputChange" data-field="chargeTime" />
<text>价格: </text><input value="{{item.price}}" data-index="{{index}}" bindinput="onInputChange" data-field="price" />
</view>
<view class="charger-owner">
<text>桩主id: </text><input value="{{item.ownerId}}" data-index="{{index}}" bindinput="onInputChange" data-field="ownerId" />
<text>桩主电话: </text><input value="{{item.ownerPhone}}" data-index="{{index}}" bindinput="onInputChange" data-field="ownerPhone" />
</view>
</view>
</view>
逻辑代码:
Page({
data: {
chargers: [] as any[],
filteredChargers: [] as any[],
searchQuery: ''
},
onLoad() {
const chargers = this.generateRandomChargers(5);
this.setData({
chargers: chargers,
filteredChargers: chargers
});
},
generateRandomChargers(count: number) {
const statuses = ["充电桩空闲", "充电桩已被预约"];
const chargers = [];
for (let i = 1; i <= count; i++) {
chargers.push({
id: i,
name: `充电桩${i}`,
address: `地址${i}`,
status: statuses[Math.floor(Math.random() * statuses.length)],
chargeTime: this.generateRandomChargeTime(),
price: (Math.random() * 1.5 + 0.5).toFixed(2),
ownerId: Math.random().toString().slice(2, 12),
ownerPhone: '1' + Math.random().toString().slice(2, 12)
});
}
return chargers;
},
generateRandomChargeTime() {
const startHour = Math.floor(Math.random() * 24);
const startMinute = Math.floor(Math.random() * 60);
const endHour = startHour + Math.floor(Math.random() * (24 - startHour));
const endMinute = Math.floor(Math.random() * 60);
const formatTime = (hour: number, minute: number) => {
return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;
};
return `${formatTime(startHour, startMinute)}至${formatTime(endHour, endMinute)}`;
},
onInputChange(e: any) {
const { index, field } = e.currentTarget.dataset;
const value = e.detail.value;
const chargers = this.data.chargers;
chargers[index][field] = value;
this.setData({
chargers,
filteredChargers: this.filterChargers(chargers, this.data.searchQuery)
});
},
onSearchInput(e: any) {
const searchQuery = e.detail.value.toLowerCase();
this.setData({
searchQuery: searchQuery,
filteredChargers: this.filterChargers(this.data.chargers, searchQuery)
});
},
filterChargers(chargers: any[], query: string) {
if (!query) {
return chargers;
}
return chargers.filter(charger => {
return charger.address.toLowerCase().includes(query);
});
}
});
6.7收款记录显示功能
页面代码:
<view class="container">
<block wx:for="{{chargers}}" wx:key="index">
<view class="details">
<text class="label">支付状态: {{item.paymentStatus}}</text>
<text class="label">名称: {{item.name}}</text>
<text class="label">地址: {{item.address}}</text>
<text class="label">充电时间: {{item.chargeTime}}</text>
<text class="label">总价格: {{item.totalPrice}} 元</text>
</view>
</block>
</view>
逻辑代码:
Page({
data: {},
onChargerListTap() {
wx.navigateTo({
url: '/pages/chargerList/chargerList'
});
},
onUserInfoTap() {
wx.navigateTo({
url: '/pages/userInfo/userInfo'
});
},
onReservationRecordsTap() {
wx.navigateTo({
url: '/pages/reservationRecords/reservationRecords'
});
},
onPaymentRecordsTap() {
wx.navigateTo({
url: '/pages/paymentRecords/paymentRecords'
});
},
onChargeRecordsTap() {
wx.navigateTo({
url: '/pages/chargeRecords/chargeRecords'
});
},
onAuthorizationRecordsTap() {
wx.navigateTo({
url: '/pages/authorizationRecords/authorizationRecords'
});
},
onChargingListTap() {
wx.navigateTo({
url: '/pages/chargingList/chargingList'
});
},
onManageAgentRequestsTap() {
wx.navigateTo({
url: '/pages/manageAgentRequests/manageAgentRequests'
});
},
onRegionalAgentsTap() {
wx.navigateTo({
url: '/pages/regionalAgents/regionalAgents'
});
},
onRegionalChargeStatsTap() {
wx.navigateTo({
url: '/pages/regionalChargeStats/regionalChargeStats'
});
}
});
6.8充电桩信息编辑修改功能
页面代码:
<view class="container">
<view class="details">
<label class="label">名称:</label>
<input class="input" value="{{charger.name}}" data-field="name" bindinput="onInputChange"/>
<label class="label">地址:</label>
<input class="input" value="{{charger.address}}" data-field="address" bindinput="onInputChange"/>
<label class="label">充电时间:</label>
<input class="input" value="{{charger.chargeTime}}" data-field="chargeTime" bindinput="onInputChange"/>
<label class="label">价格:</label>
<input class="input" type="number" value="{{charger.pricePerKWh}}" data-field="pricePerKWh" bindinput="onInputChange"/>
<button class="menu-button" bindtap="onSaveTap">保存</button>
</view>
</view>
逻辑代码:
Page({
data: {
charger: {} as Charger,
index: -1,
isNew: false
},
onLoad(options: any) {
const { index, isNew } = options;
const pages = getCurrentPages();
const prevPage = pages[pages.length - 2];
const charger = prevPage.data.chargers[index];
this.setData({ charger, index, isNew: isNew === 'true' });
},
onInputChange(event: any) {
const field = event.currentTarget.dataset.field;
const value = event.detail.value;
this.setData({ [`charger.${field}`]: value });
},
onSaveTap() {
const pages = getCurrentPages();
const prevPage = pages[pages.length - 2];
const chargers = prevPage.data.chargers;
chargers[this.data.index] = this.data.charger;
prevPage.setData({ chargers });
wx.navigateBack();
}
});
interface Charger {
name: string;
address: string;
chargeTime: string;
pricePerKWh: number;
}
6.9登录功能
可以填写昵称以及头像
页面代码:
<!-- miniprogram\pages\index\index.wxml -->
<navigation-bar title="Weixin" back="{{false}}" color="black" background="#FFF"></navigation-bar>
<scroll-view class="scrollarea" scroll-y type="list">
<view class="container">
<view class="userinfo">
<block wx:if="{{canIUseNicknameComp && !hasUserInfo}}">
<button class="avatar-wrapper" open-type="chooseAvatar" bind:chooseavatar="onChooseAvatar">
<image class="avatar" src="{{userInfo.avatarUrl}}"></image>
</button>
<view class="nickname-wrapper">
<text class="nickname-label">昵称</text>
<input type="nickname" class="nickname-input" placeholder="请输入昵称" bind:change="onInputChange" />
</view>
</block>
<block wx:elif="{{!hasUserInfo}}">
<button wx:if="{{canIUseGetUserProfile}}" bindtap="getUserProfile"> 获取头像昵称 </button>
<view wx:else> 请使用2.10.4及以上版本基础库 </view>
</block>
<block wx:else>
<image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image>
<text class="userinfo-nickname">{{userInfo.nickName}}</text>
</block>
</view>
<view class="usermotto">
<text class="user-motto">{{motto}}</text>
</view>
<button class="login-button" bindtap="navigateToHome">登录</button>
</view>
</scroll-view>
逻辑代码:
// 获取应用实例
const app = getApp<IAppOption>()
const defaultAvatarUrl = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'
Component({
data: {
motto: '私人共享充电桩系统',
userInfo: {
avatarUrl: defaultAvatarUrl,
nickName: '',
},
hasUserInfo: false,
canIUseGetUserProfile: wx.canIUse('getUserProfile'),
canIUseNicknameComp: wx.canIUse('input.type.nickname'),
},
methods: {
// 事件处理函数
bindViewTap() {
wx.navigateTo({
url: '../logs/logs',
})
},
onChooseAvatar(e: any) {
const { avatarUrl } = e.detail
const { nickName } = this.data.userInfo
this.setData({
"userInfo.avatarUrl": avatarUrl,
hasUserInfo: nickName && avatarUrl && avatarUrl !== defaultAvatarUrl,
})
},
onInputChange(e: any) {
const nickName = e.detail.value
const { avatarUrl } = this.data.userInfo
this.setData({
"userInfo.nickName": nickName,
hasUserInfo: nickName && avatarUrl && avatarUrl !== defaultAvatarUrl,
})
},
getUserProfile() {
// 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认,开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
wx.getUserProfile({
desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
success: (res) => {
console.log(res)
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
})
}
})
},
navigateToHome() {
wx.navigateTo({
url: '/pages/user/user',
});
}
},
})
6.10日志功能
可以查看每次登录的时间
页面代码:
<!--logs.wxml-->
<navigation-bar title="查看启动日志" back="{{true}}" color="black" background="#FFF"></navigation-bar>
<scroll-view class="scrollarea" scroll-y type="list">
<block wx:for="{{logs}}" wx:key="timeStamp" wx:for-item="log">
<view class="log-item">{{index + 1}}. {{log.date}}</view>
</block>
</scroll-view>
逻辑代码:
// logs.ts
// const util = require('../../utils/util.js')
import { formatTime } from '../../utils/util'
Component({
data: {
logs: [],
},
lifetimes: {
attached() {
this.setData({
logs: (wx.getStorageSync('logs') || []).map((log: string) => {
return {
date: formatTime(new Date(log)),
timeStamp: log
}
}),
})
}
},
})
6.11地图功能
用于查找充电桩的位置
页面代码:
<view class="container">
<!-- 搜索框 -->
<view class="search-container">
<input type="text" placeholder="请输入地址" bindinput="onSearchInput" value="{{searchQuery}}" />
<button bindtap="onSearch">搜索</button>
</view>
<map
id="map"
latitude="{{latitude}}"
longitude="{{longitude}}"
markers="{{markers}}"
show-location
style="width: 100%; height: {{showDetails ? '50%' : '100%'}};"
bindmarkertap="onMarkerTap"
></map>
<view wx:if="{{showDetails}}" class="details-container">
<view class="details">
<text>名称: {{selectedCharger.name}}</text>
<text>地址: {{selectedCharger.address}}</text>
<text>状态: {{selectedCharger.status}}</text>
<text>每日可充电时间: {{selectedCharger.chargeTime}}</text>
<text>价格: {{selectedCharger.pricePerKWh}} 元/度</text>
<button bindtap="onReserveTap">预约</button>
<button bindtap="onScanCode" class="scan-button">扫码充电</button>
<button bindtap="onChargeTap" class="charge-button">聊天</button>
<button bindtap="onCloseDetails">关闭</button>
</view>
</view>
</view>
逻辑代码:
interface Marker {
id: number;
latitude: number;
longitude: number;
iconPath: string;
width: number;
height: number;
callout?: {
content: string;
display: string;
};
name?: string;
address?: string;
status?: string;
chargeTime?: string;
pricePerKWh?: number;
}
Page({
data: {
longitude: 0,
latitude: 0,
markers: [] as Marker[],
selectedCharger: null as Marker | null,
showDetails: false,
searchQuery: ''
},
onLoad() {
const that = this;
console.log('onLoad: 获取当前位置');
wx.getLocation({
type: 'gcj02',
success(res) {
console.log('获取位置成功:', res);
const latitude = res.latitude;
const longitude = res.longitude;
const randomChargers = that.generateRandomChargers(latitude, longitude, 5);
that.setData({
latitude: latitude,
longitude: longitude,
markers: [{
id: 0,
latitude: latitude,
longitude: longitude,
iconPath: '/assets/icons/charger.png',
width: 50,
height: 50,
callout: {
content: '当前地点',
display: 'ALWAYS'
}
} as Marker, ...randomChargers]
});
console.log('地图更新成功:', that.data);
},
fail(err) {
console.error('获取位置失败:', err);
wx.showToast({
title: '无法获取当前位置',
icon: 'none'
});
}
});
},
generateRandomChargers(lat: number, lon: number, count: number): Marker[] {
const markers: Marker[] = [];
let lastPrice = Math.random() * 2 + 0.5;
const statuses = ["充电桩空闲", "充电桩已被预约"];
for (let i = 1; i <= count; i++) {
const deltaLat = (Math.random() - 0.5) / 100;
const deltaLon = (Math.random() - 0.5) / 100;
const pricePerKWh = Math.max(0.1, lastPrice + (Math.random() - 0.5) * 0.2);
lastPrice = pricePerKWh;
const chargeTime = this.generateRandomChargeTime();
const status = statuses[Math.floor(Math.random() * statuses.length)];
const marker = {
id: i,
latitude: lat + deltaLat,
longitude: lon + deltaLon,
iconPath: '/assets/icons/charger.png',
width: 30,
height: 30,
callout: {
content: `充电桩${i}`,
display: 'ALWAYS'
},
name: `充电桩${i}`,
address: `地址${i}`,
status: status,
chargeTime: chargeTime,
pricePerKWh: Math.round(pricePerKWh * 100) / 100
} as Marker;
markers.push(marker);
}
return markers;
},
generateRandomChargeTime(): string {
const startHour = Math.floor(Math.random() * 24);
const startMinute = Math.floor(Math.random() * 60);
let endHour = startHour + Math.floor(Math.random() * (24 - startHour));
let endMinute = Math.floor(Math.random() * 60);
const formatTime = (hour: number, minute: number) => {
return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;
};
const startTime = formatTime(startHour, startMinute);
const endTime = formatTime(endHour, endMinute);
return `${startTime}至${endTime}`;
},
onMarkerTap(event: any) {
const markerId = event.markerId;
const marker = this.data.markers.find(m => m.id === markerId);
if (marker) {
this.setData({
selectedCharger: marker,
showDetails: true
});
}
},
onCloseDetails() {
this.setData({
showDetails: false
});
},
onReserveTap() {
wx.navigateTo({
url: `/pages/reservationDetail/reservationDetail?selectedCharger=${encodeURIComponent(JSON.stringify(this.data.selectedCharger))}`
});
},
onScanCode() {
wx.scanCode({
success: (res) => {
wx.showToast({
title: '扫码成功',
icon: 'success',
duration: 2000
});
console.log('扫码结果:', res);
},
fail: (err) => {
wx.showToast({
title: '扫码失败',
icon: 'none'
});
console.error('扫码失败:', err);
}
});
},
onChargeTap() {
wx.navigateTo({
url: '/pages/charge/charge'
});
},
onSearchInput(e: WechatMiniprogram.Input) {
this.setData({
searchQuery: e.detail.value
});
},
onSearch() {
const query = this.data.searchQuery;
if (!query) {
wx.showToast({
title: '请输入地址',
icon: 'none'
});
return;
}
// 模拟搜索功能,这里需要集成实际的搜索API
wx.request({
url: 'https://example.com/search', // 替换为实际的搜索API
data: {
address: query
},
success: (res) => {
const results = (res.data as { results: any[] }).results;
const markers = results.map((result: any, index: number) => ({
id: index + 1,
latitude: result.latitude,
longitude: result.longitude,
iconPath: '/assets/icons/charger.png',
width: 30,
height: 30,
callout: {
content: result.name,
display: 'ALWAYS'
},
name: result.name,
address: result.address,
status: result.status,
chargeTime: result.chargeTime,
pricePerKWh: result.pricePerKWh
} as Marker));
this.setData({
markers: markers
});
},
fail: (err) => {
wx.showToast({
title: '搜索失败',
icon: 'none'
});
console.error('搜索失败:', err);
}
});
}
});
6.12个人主页功能
查询个人信息以及钱包
页面代码:
<view class="container">
<view class="profile">
<image src="/assets/icons/head.jpg" class="avatar"></image>
<view class="info">
<text class="label">名称: {{name}}</text>
<text class="label">ID: {{id}}</text>
</view>
</view>
<button class="menu-button" bindtap="onPersonalInfoTap">个人信息</button>
<button class="menu-button" bindtap="onWalletTap">我的钱包</button>
<text class="customer-service">客服电话: 1233333</text>
</view>
<view class="bottom-buttons">
<button bindtap="onUserHomeTap" class="{{activePage == 'user' ? 'active' : ''}}">user主页</button>
<button bindtap="onMineTap" class="{{activePage == 'mine' ? 'active' : ''}}">我的</button>
</view>
<!-- 个人信息弹窗 -->
<view wx:if="{{showPersonalInfo}}" class="popup">
<view class="popup-content">
<text class="popup-title">个人信息</text>
<view class="popup-item">
<text>ID: {{id}}</text>
</view>
<view class="popup-item">
<text>真实姓名: {{realName}}</text>
</view>
<view class="popup-item">
<text>身份证: {{idNumber}}</text>
</view>
<view class="popup-item">
<text>电话:</text>
<input value="{{phone}}" bindinput="onPhoneInput" data-field="phone" />
</view>
<view class="popup-item">
<text>名称:</text>
<input value="{{name}}" bindinput="onNameInput" data-field="name" />
</view>
<button bindtap="onClosePopup">关闭</button>
</view>
</view>
逻辑代码:
Page({
data: {
name: '',
id: '',
realName: '',
idNumber: '',
phone: '',
showPersonalInfo: false,
activePage: 'mine'
},
onLoad() {
const name = this.generateRandomName();
const id = this.generateRandomId();
const realName = this.generateRandomRealName();
const idNumber = this.generateRandomIdNumber();
const phone = this.generateRandomPhone();
this.setData({
name: name,
id: id,
realName: realName,
idNumber: idNumber,
phone: phone
});
},
generateRandomName() {
const names = ['Alice', 'Bob', 'Charlie', 'David', 'Eva'];
const index = Math.floor(Math.random() * names.length);
return names[index];
},
generateRandomId() {
return Math.floor(Math.random() * 10000000000).toString().padStart(10, '0');
},
generateRandomRealName() {
const realNames = ['张三', '李四', '王五', '赵六', '孙七'];
const index = Math.floor(Math.random() * realNames.length);
return realNames[index];
},
generateRandomIdNumber() {
const chars = '0123456789';
let idNumber = '';
for (let i = 0; i < 18; i++) {
idNumber += chars[Math.floor(Math.random() * chars.length)];
}
return idNumber;
},
generateRandomPhone() {
const prefix = '1';
const chars = '0123456789';
let phone = prefix;
for (let i = 0; i < 10; i++) {
phone += chars[Math.floor(Math.random() * chars.length)];
}
return phone;
},
onPersonalInfoTap() {
this.setData({
showPersonalInfo: true
});
},
onClosePopup() {
this.setData({
showPersonalInfo: false
});
},
onPhoneInput(e: WechatMiniprogram.Input) {
this.setData({
phone: e.detail.value
});
},
onNameInput(e: WechatMiniprogram.Input) {
this.setData({
name: e.detail.value
});
},
onWalletTap() {
wx.navigateTo({
url: '/pages/wallet/wallet'
});
},
onUserHomeTap() {
wx.navigateTo({
url: '/pages/user/user'
});
},
onMineTap() {
wx.navigateTo({
url: '/pages/mine/mine'
});
}
});
6.13区域代理功能
显示我的区域代理充电桩的信息
页面代码:
<view class="container">
<block wx:for="{{agents}}" wx:key="index">
<view class="details">
<text class="label">名称: {{item.name}}</text>
<text class="label">地址: {{item.address}}</text>
<text class="label">充电时间: {{item.chargeTime}}</text>
<text class="label">价格: {{item.pricePerKWh}} 元/度</text>
<view class="profit">
<text class="label">代理每度电分成: {{item.profitShare}} 元/度</text>
</view>
</view>
</block>
</view>
逻辑代码:
Page({
data: {
agents: [] as Agent[]
},
onLoad() {
const agents = this.generateRandomAgents(5); // 生成 5 个随机代理信息
this.setData({ agents });
},
generateRandomAgents(count: number): Agent[] {
const agents: Agent[] = [];
for (let i = 0; i < count; i++) {
agents.push(this.generateRandomAgent(i + 1));
}
return agents;
},
generateRandomAgent(id: number): Agent {
const randomPricePerKWh = parseFloat((Math.random() * 2 + 0.5).toFixed(2));
const chargeTime = this.generateChargeTime();
const randomProfitShare = parseFloat((Math.random() * 0.2 + 0.1).toFixed(2));
return {
name: `充电桩${id}`,
address: `地址${id}`,
chargeTime,
pricePerKWh: randomPricePerKWh,
profitShare: randomProfitShare
};
},
generateChargeTime(): string {
const startHour = Math.floor(Math.random() * 24);
const startMinute = Math.floor(Math.random() * 60);
const endHour = startHour + Math.floor(Math.random() * (24 - startHour));
const endMinute = Math.floor(Math.random() * 60);
const formatTime = (hour: number, minute: number) => {
return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;
};
const startTime = formatTime(startHour, startMinute);
const endTime = formatTime(endHour, endMinute);
return `${startTime}至${endTime}`;
}
});
interface Agent {
name: string;
address: string;
chargeTime: string;
pricePerKWh: number;
profitShare: number;
}
6.14我的充电桩功能
可以添加和编辑充电桩
页面代码:
<view class="container">
<view class="title">添加新的充电桩</view>
<button class="menu-button" bindtap="onAddNewChargerTap">添加新的充电桩</button>
<view class="title">管理我的充电桩</view>
<block wx:for="{{chargers}}" wx:key="index">
<view class="details">
<text class="label">名称: {{item.name}}</text>
<text class="label">地址: {{item.address}}</text>
<text class="label">充电时间: {{item.chargeTime}}</text>
<text class="label">价格: {{item.pricePerKWh}} 元/度</text>
<button class="menu-button" data-index="{{index}}" bindtap="onEditChargerTap">编辑</button>
</view>
</block>
<view class="bottom-buttons">
<button bindtap="onUserHomeTap" class="{{activePage == 'user' ? 'active' : ''}}">user主页</button>
<button bindtap="onMineTap" class="{{activePage == 'mine' ? 'active' : ''}}">我的</button>
</view>
</view>
逻辑代码:
Page({
data: {
chargers: [] as Charger[],
activePage: 'myCharge'
},
onLoad() {
const chargers = this.generateRandomChargers(3); // 生成 3 个随机充电桩信息
this.setData({ chargers });
},
generateRandomChargers(count: number): Charger[] {
const chargers: Charger[] = [];
for (let i = 0; i < count; i++) {
chargers.push(this.generateRandomCharger(i + 1));
}
return chargers;
},
generateRandomCharger(id: number): Charger {
const randomPricePerKWh = parseFloat((Math.random() * 2 + 0.5).toFixed(2));
const chargeTime = this.generateChargeTime();
return {
name: `充电桩${id}`,
address: `地址${id}`,
chargeTime,
pricePerKWh: randomPricePerKWh
};
},
generateChargeTime(): string {
const startHour = Math.floor(Math.random() * 24);
const startMinute = Math.floor(Math.random() * 60);
const endHour = startHour + Math.floor(Math.random() * (24 - startHour));
const endMinute = Math.floor(Math.random() * 60);
const formatTime = (hour: number, minute: number) => {
return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;
};
const startTime = formatTime(startHour, startMinute);
const endTime = formatTime(endHour, endMinute);
return `${startTime}至${endTime}`;
},
onAddNewChargerTap() {
const newCharger = this.generateRandomCharger(this.data.chargers.length + 1);
this.setData({ chargers: [...this.data.chargers, newCharger] });
const index = this.data.chargers.length - 1;
wx.navigateTo({
url: `/pages/editCharger/editCharger?index=${index}&isNew=true`
});
},
onEditChargerTap(event: any) {
const index = event.currentTarget.dataset.index;
wx.navigateTo({
url: `/pages/editCharger/editCharger?index=${index}`
});
},
onUserHomeTap() {
this.setData({ activePage: 'user' });
wx.navigateTo({
url: '/pages/user/user'
});
},
onMineTap() {
this.setData({ activePage: 'mine' });
wx.navigateTo({
url: '/pages/mine/mine'
});
}
});
interface Charger {
name: string;
address: string;
chargeTime: string;
pricePerKWh: number;
}
6.15支付记录功能
显示历史支付信息
页面代码:
<view class="container">
<view class="status" style="background-color: {{statusColor}}">{{paymentStatus}}</view>
<view class="details">
<text class="label">名称: {{charger.name}}</text>
<text class="label">地址: {{charger.address}}</text>
<text class="label">充电时间: {{charger.chargeTime}}</text>
<text class="label">总价格: {{charger.totalPrice}} 元</text>
</view>
</view>
逻辑代码:
Page({
data: {
charger: {
name: '',
address: '',
chargeTime: '',
totalPrice: 0
},
paymentStatus: '',
statusColor: ''
},
onLoad() {
const charger = this.generateRandomCharger();
const { paymentStatus, statusColor } = this.generatePaymentStatus();
this.setData({
charger: charger,
paymentStatus: paymentStatus,
statusColor: statusColor
});
},
generateRandomCharger() {
const randomTotalPrice = Math.floor(Math.random() * 26) + 25; // 生成 25 到 50 之间的随机数
const chargeTime = this.generateChargeTime();
return {
name: `充电桩${Math.floor(Math.random() * 10 + 1)}`,
address: `地址${Math.floor(Math.random() * 10 + 1)}`,
chargeTime: chargeTime,
totalPrice: randomTotalPrice
};
},
generateChargeTime(): string {
const startHour = Math.floor(Math.random() * 24);
const startMinute = Math.floor(Math.random() * 60);
const endHour = startHour + Math.floor(Math.random() * (24 - startHour));
const endMinute = Math.floor(Math.random() * 60);
const formatTime = (hour: number, minute: number) => {
return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;
};
const startTime = formatTime(startHour, startMinute);
const endTime = formatTime(endHour, endMinute);
return `${startTime}至${endTime}`;
},
generatePaymentStatus() {
const statuses = ['已支付', '未支付'];
const colors = ['#4CAF50', '#FF5722']; // 绿色和红色
const index = Math.floor(Math.random() * 2);
return {
paymentStatus: statuses[index],
statusColor: colors[index]
};
}
});
6.16预约记录功能
显示正在预约的充电桩信息
页面代码:
->
<view class="container">
<view class="details">
<text class="label">名称: {{charger.name}}</text>
<text class="label">地址: {{charger.address}}</text>
<text class="label">充电时间: {{charger.chargeTime}}</text>
<text class="label">价格: {{charger.pricePerKWh}} 元/度</text>
<button class="menu-button" bindtap="onCancelReservationTap">取消预约</button>
</view>
</view>
逻辑代码:
// miniprogram/pages/reservationList/reservationList.ts
interface Charger {
name: string;
address: string;
chargeTime: string;
pricePerKWh: number;
}
Page({
data: {
charger: {
name: '',
address: '',
chargeTime: '',
pricePerKWh: 0
} as Charger
},
onLoad() {
const charger = this.generateRandomCharger();
this.setData({
charger: charger
});
},
generateRandomCharger(): Charger {
const randomPricePerKWh = parseFloat((Math.random() * 2 + 0.5).toFixed(2)); // 随机生成价格
const chargeTime = this.generateChargeTime();
return {
name: `充电桩${Math.floor(Math.random() * 10 + 1)}`,
address: `地址${Math.floor(Math.random() * 10 + 1)}`,
chargeTime: chargeTime,
pricePerKWh: randomPricePerKWh
};
},
generateChargeTime(): string {
const startHour = Math.floor(Math.random() * 24);
const startMinute = Math.floor(Math.random() * 60);
const endHour = startHour + Math.floor(Math.random() * (24 - startHour));
const endMinute = Math.floor(Math.random() * 60);
const formatTime = (hour: number, minute: number) => {
return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;
};
const startTime = formatTime(startHour, startMinute);
const endTime = formatTime(endHour, endMinute);
return `${startTime}至${endTime}`;
},
onCancelReservationTap() {
wx.showToast({
title: '预约已取消',
icon: 'none',
duration: 2000
});
}
});
6.17用户信息功能
显示用户的姓名、身份证和电话号等功能
页面代码:
<view class="container">
<view class="user-info-list">
<block wx:for="{{userInfos}}" wx:key="id">
<view class="user-info">
<view class="info-item">
<text class="label">id:</text>
<text class="value">{{item.id}}</text>
</view>
<view class="info-item">
<text class="label">真实姓名:</text>
<text class="value">{{item.realName}}</text>
</view>
<view class="info-item">
<text class="label">身份证:</text>
<text class="value">{{item.idNumber}}</text>
</view>
<view class="info-item">
<text class="label">电话:</text>
<input class="input-field" value="{{item.phone}}" bindinput="onInputChange" data-index="{{index}}" data-field="phone"/>
</view>
<view class="info-item">
<text class="label">名称:</text>
<input class="input-field" value="{{item.name}}" bindinput="onInputChange" data-index="{{index}}" data-field="name"/>
</view>
</view>
</block>
</view>
</view>
逻辑代码:
interface UserInfo {
id: string;
realName: string;
idNumber: string;
phone: string;
name: string;
}
Page({
data: {
userInfos: [] as UserInfo[]
},
onLoad() {
this.generateUserInfos();
},
generateUserInfos() {
const userInfos: UserInfo[] = [];
for (let i = 0; i < 9; i++) {
userInfos.push({
id: this.generateRandomId(),
realName: this.generateRandomRealName(),
idNumber: this.generateRandomIdNumber(),
phone: this.generateRandomPhone(),
name: this.generateRandomName()
});
}
this.setData({ userInfos });
},
generateRandomName() {
const names = ['Alice', 'Bob', 'Charlie', 'David', 'Eva'];
const index = Math.floor(Math.random() * names.length);
return names[index];
},
generateRandomId() {
return Math.floor(Math.random() * 10000000000).toString().padStart(10, '0');
},
generateRandomRealName() {
const realNames = ['张三', '李四', '王五', '赵六', '孙七'];
const index = Math.floor(Math.random() * realNames.length);
return realNames[index];
},
generateRandomIdNumber() {
const chars = '0123456789';
let idNumber = '';
for (let i = 0; i < 18; i++) {
idNumber += chars[Math.floor(Math.random() * chars.length)];
}
return idNumber;
},
generateRandomPhone() {
const prefix = '1';
const chars = '0123456789';
let phone = prefix;
for (let i = 0; i < 10; i++) {
phone += chars[Math.floor(Math.random() * chars.length)];
}
return phone;
},
onInputChange(e: WechatMiniprogram.Input) {
const { index, field } = e.currentTarget.dataset;
const value = e.detail.value;
const userInfos = [...this.data.userInfos];
userInfos[index][field as keyof UserInfo] = value;
this.setData({ userInfos });
}
});
6.18钱包功能
可以显示余额,可以充值和提现
页面代码:
<view class="container">
<text class="label">我的余额: {{balance}} 元</text>
<view class="form-group">
<text class="label">充值金额:</text>
<input class="input" type="number" placeholder="请输入充值金额"/>
<button class="menu-button" bindtap="onRechargeTap">充值</button>
</view>
<view class="form-group">
<text class="label">提现金额:</text>
<input class="input" type="number" placeholder="请输入提现金额"/>
<button class="menu-button" bindtap="onWithdrawTap">提现</button>
</view>
</view>
<view class="bottom-buttons">
<button bindtap="onUserHomeTap" class="{{activePage == 'user' ? 'active' : ''}}">user主页</button>
<button bindtap="onMineTap" class="{{activePage == 'mine' ? 'active' : ''}}">我的</button>
</view>
逻辑代码:
Page({
data: {
balance: 0,
activePage: 'mine'
},
onLoad() {
const balance = this.generateRandomBalance();
this.setData({
balance: balance
});
},
generateRandomBalance() {
return Math.floor(Math.random() * 251) + 50; // 生成 50 到 300 之间的随机数
},
onRechargeTap() {
wx.showToast({
title: '充值成功',
icon: 'none',
duration: 2000
});
},
onWithdrawTap() {
wx.showToast({
title: '提现成功',
icon: 'none',
duration: 2000
});
},
onUserHomeTap() {
wx.navigateTo({
url: '/pages/user/user'
});
},
onMineTap() {
wx.navigateTo({
url: '/pages/mine/mine'
});
}
});