目录
前言
这是一款模拟饮品点餐系统的软件,基于鸿蒙,使用了数据库,主要功能有:
- 用户注册
- 用户登录
- 搜索饮品
- 选择饮品规格后加入购物车
- 计算总价
- 清空购物车
- 删除购物车的某一项
- 微信支付进行结算后清空购物车、增加订单项
- 查看订单详细信息
- 删除订单项
- 修改密码
- 退出登录
一、关键技术
- 数据库操作(包括增、删、改、查)。
- @State、@Link、@Prop、@Provide、@Consume、@Observed、@ObjectLink等装饰器的使用。
- Tabs 组件的使用。
- List 组件的使用。
- Panel组件的使用。
- 通过systemDateTime库获取系统当前时间。
- @Extend修饰器全局通用样式的使用。
- @Styles修饰器的使用。
二、效果展示
三、实验过程
1.创建数据库
(1)构思数据库
设计数据库表结构如下(外边框虚线为主键,内边框实线为外键)。
为什么没有饮品表?因为我的思路是前期先将饮品数据固定写死,每次加载应用都将固定数据push进数组teas[],后期如果时间充足可以加网络连接进行网络获取数据,现在不用数据库修改更为方便,若没有时间我觉得也不适合用数据库存储茶品,实际情况中茶品会根据管理员的修改而变动。
(2)初始化数据库及数据表
由于没有数据库的可视化工具并且模拟器的报错并不明显导致很多操作极不方便,特别是最开始创建数据库时,插入购物车表数据时出错,找了一下午,最后发现varchar写成了verchar
代码如下:
initData(context) {
const config = {
name: 'MyData.db',
// 数据库安全级别
securityLevel: relationalStore.SecurityLevel.S1
}
// 若数据表不存在则创建
const createUserSql = `create table if not exists user(
Uno varchar(20) primary key,
Uname varchar(50),
Upassword varchar(20)
)`
const createBuyCarSql = `create table if not exists buy_car(
Ctime varchar(50),
Uno varchar(20),
Tname varchar(50),
Csum int,
Ccup int,
Ctemp int,
Csweetness int,
Ctno int,
primary key(Ctime,Uno),
FOREIGN KEY (Uno) REFERENCES user(Uno)
)`
const createBoughtSql = `create table if not exists bought(
Bno varchar(70) primary key,
Btime varchar(50),
Btype varchar(10),
Bprice double,
Uno varchar(20),
Bdno int,
Bsum int,
FOREIGN KEY (Uno) REFERENCES user(Uno)
)`
relationalStore.getRdbStore(context,config,(err,rdbStore) => {
if(err){
console.log('testLog','获取rdbStore失败')
return
}
// 执行SQL,若数据表存在则不会重复创建
rdbStore.executeSql(createUserSql)
rdbStore.executeSql(createBuyCarSql)
rdbStore.executeSql(createBoughtSql)
// 保存rdbStore
this.rdbStore = rdbStore
})
console.log('08808','数据库加载成功')
}
(3)定义数据库操作函数
这里需要注意方法的同步和异步,防止发生逻辑错误。
// 用户注册
insertUser(Uno: string,Upassword: string,Uname: string): Promise<number>{
console.log('08808','用户注册函数运行')
return this.rdbStore.insert('user',{Uno,Upassword,Uname})
}
// 用户登录查询
async selectUser(Uno: string,Upassword: string): Promise<boolean>{
let predicates = new relationalStore.RdbPredicates('user')
// 绑定条件
predicates.equalTo('Uno',Uno)
// 定义结果集
let res = await this.rdbStore.query(predicates)
// 只要不是最后一行就循环
while(!res.isAtLastRow){
res.goToNextRow()
let password = res.getString(res.getColumnIndex('Upassword'))
// 密码正确
if(password == Upassword){
console.log('08808','密码正确!')
return true
}
}
// 账号错误或者密码错误
return false
}
// 用户注册查询
async selectUser_(Uno: string): Promise<boolean>{
let predicates = new relationalStore.RdbPredicates('user')
// 绑定条件
predicates.equalTo('Uno',Uno)
// 定义结果集
let res = await this.rdbStore.query(predicates)
// 此账号唯一
if(res.isAtLastRow){
return true
}
else{
// 此账号已存在
return false
}
}
// 用户昵称查询
async selectUserName(Uno): Promise<string>{
let predicates = new relationalStore.RdbPredicates('user')
// 绑定条件
predicates.equalTo('Uno',Uno)
// 定义结果集
let res = await this.rdbStore.query(predicates)
if(!res.isAtLastRow){
res.goToNextRow()
return res.getString(res.getColumnIndex('Uname'))
}
}
// 用户密码修改
async updataPassword(Uno,newPassword){
let data = {'Upassword': newPassword}
let predicates = new relationalStore.RdbPredicates('user')
predicates.equalTo('Uno',Uno)
await this.rdbStore.update(data,predicates)
console.log('08808','用户数据更新完成')
}
// 购物车表插入数据
async insertBuy_car(Ctime: string,Uno: string,Tname: string,Csum: number,Ccup: number,Ctemp: number,Csweetness: number,Ctno: number): Promise<number>{
return await this.rdbStore.insert('buy_car',{Ctime,Uno,Tname,Csum,Ccup,Ctemp,Csweetness,Ctno})
}
// 读取购物车表的数据
async readBuy_car(): Promise<Tea[]> {
let predicates = new relationalStore.RdbPredicates('buy_car')
// 绑定条件
predicates.equalTo('Uno',User.Uno)
let res = await this.rdbStore.query(predicates)
let teas: Tea[] = []
while(!res.isAtLastRow){
res.goToNextRow()
let Ctno: number = res.getLong(res.getColumnIndex('Ctno'))
// 构建规格
let norms: object = {
cup: res.getLong(res.getColumnIndex('Ccup')),
temp: res.getLong(res.getColumnIndex('Ctemp')),
sweetness: res.getLong(res.getColumnIndex('Csweetness'))
}
let tea: Tea = new Tea(
// 饮品名称
res.getString(res.getColumnIndex('Tname')),
// 饮品图片地址
StaticValue.teas[Ctno].image,
// 饮品简介
StaticValue.teas[Ctno].about,
// 饮品总价 数量*单价
StaticValue.teas[Ctno].price * res.getLong(res.getColumnIndex('Csum')),
// 饮品类型
StaticValue.teas[Ctno].type,
// 饮品数量
res.getLong(res.getColumnIndex('Csum')),
// 客户备注 暂且不用
'',
// 饮品规格
norms
)
tea.Ctime = res.getString(res.getColumnIndex('Ctime'))
teas.push(tea)
}
return teas
}
// 修改购物车数据
async updateBuyCar(Uno: string,Ctime: string,Csum: number){
let data = {'Csum': Csum}
let predicates = new relationalStore.RdbPredicates('buy_car')
predicates.equalTo('Uno',Uno)
predicates.equalTo('Ctime',Ctime)
await this.rdbStore.update(data,predicates)
console.log('08808','购物车数据更新完成')
}
// 清空购物车
deleteBuyCar(){
let predicates = new relationalStore.RdbPredicates('buy_car')
this.rdbStore.delete(predicates)
// 购物车全部清空
console.log('08808','购物车清空!')
}
// 删除购物车中的一项
deleteBuyCarTo(Ctime: string,Uno: string){
let predicates = new relationalStore.RdbPredicates('buy_car')
predicates.equalTo('Ctime',Ctime)
predicates.equalTo('Uno',Uno)
this.rdbStore.delete(predicates)
// 购物车指定条目删除
console.log('08808','此项删除')
}
// 插入订单表数据
async insertBought(Bno: string,Btime: string,Btype: string,Bprice: number,Uno: string,Bdno: number,Bsum: number): Promise<number>{
// console.log('08808',Bprice)
return await this.rdbStore.insert('bought',{Bno,Btime,Btype,Bprice,Uno,Bdno,Bsum})
}
// 删除一条订单
deleteBill(Bno){
let predicates = new relationalStore.RdbPredicates('bought')
predicates.equalTo('Bno',Bno)
this.rdbStore.delete(predicates)
// 订单表指定条目删除
console.log('08808','此项删除')
}
// 读取订单表的数据
async readBought(): Promise<Bill[]> {
let predicates = new relationalStore.RdbPredicates('bought')
// 绑定条件
predicates.equalTo('Uno',User.Uno)
let res = await this.rdbStore.query(predicates)
let bills: Bill[] = []
while(!res.isAtLastRow){
res.goToNextRow()
let bill: Bill = new Bill(
res.getString(res.getColumnIndex('Bno')),
res.getString(res.getColumnIndex('Btime')),
res.getString(res.getColumnIndex('Btype')),
res.getDouble(res.getColumnIndex('Bprice')),
res.getLong(res.getColumnIndex('Bdno')),
res.getLong(res.getColumnIndex('Bsum'))
)
bills.push(bill)
}
return bills
}
2.构建类
根据应用功能的实际需求创建出适合的类。
(1)饮品类 Tea
这里的饮品类属性较多,主要是因为此类算是一个较为通用的类,包括程序加载时读数据用到、读取购物车数据库后封装用到……
import resourceManager from '@ohos.resourceManager'
@Observed
export class Tea {
// 编号:在数组中的位置
no: number
// 首字母
firstI: string
name: string
image: resourceManager.Resource
// 简介
about: string
// 总价格
price: number
// 数量
sum: number
// 顾客备注
notes: string
// 类型,标记属于四类中的哪一类
type: number
// 时间
Ctime: string
// 规格
norms: object = {
cup: 0,
temp: 0,
sweetness: 0
}
constructor(name: string,image: resourceManager.Resource,about: string,price: number,type: number,sum?: number,notes?: string,norms?: object,firstI?: string,no?: number) {
this.name = name
this.image = image
this.about = about
this.price = price
this.type = type
if(sum){
this.sum = sum
}
if(notes){
this.notes = notes
}
if(norms){
this.norms = norms
}
if(firstI){
this.firstI = firstI
}
if(no){
this.no = no
}
}
}
(2)用户类 User
用于存储当前登陆账户的信息。
export class User{
public static Uno: string
public static Upassword: string
public static Uname: string
}
(3)订单类 Bill
export class Bill {
Bno: string
Btime: string
Btype: string
Bprice: number
Bdno: number
Bsum: number
constructor(Bno,Btime,Btype,Bprice,Bdno,Bsum) {
this.Bno = Bno
this.Btime = Btime
this.Btype = Btype
this.Bprice = Bprice
this.Bdno = Bdno
this.Bsum = Bsum
}
}
(4)静态变量类 StaticValue
用于存储全局通用的静态变量
import { Tea } from './Tea'
export class StaticValue {
// 总饮品集合
public static teas: Tea[] =[]
// 服务费
public static sumF_: number = 0.2
}
四、遇到问题
正如前面所说,由于没有数据库的可视化工具并且模拟器的报错并不明显导致很多操作极不方便,特别是最开始创建数据库时,插入购物车表数据时出错,找了一下午,最后发现varchar写成了verchar。
总结
以上就是本章的主要内容,包括了数据库的构建流程、各种通用类的创建和一些细节。