南京航空航天大学《数据库原理与安全》实验报告
前言
本篇报告主要分享《数据库原理与安全》的大报告,其中部分图片有缺失,需要完整版和源码的请私信博主哦~
文章目录
实验一:安装SQL Server及相应工具
1.SQL Server的下载与安装
首先,到官方网站下载相应版本
https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads
按照官网步骤安装即可,具体的安装步骤参考以下链接:
https://blog.csdn.net/m0_51126511/article/details/126971149
实验二:启动SQL Server 和建数据库、表
1.启动SQL Server Management Studio
在home栏找到SQL Server Management Studio,点击打开。
打开后,显示需要连接到服务器,这里为方便演示,选择Windows身份验证。
点击连接后进入主界面。
2.建数据库、表
选中数据库,右键点击新建数据库,输入数据库名称为GOODS,点击确定。
在该GOODS数据库中需要建立三张表:categories(商品类别表)、products(商品名称表)、ratings(商品评论表),三张表的具体信息如下:
- categories(商品类别表):
列名 | 数据类型 | 允许Null值 | 信息 |
---|---|---|---|
catId | int | no | 商品类别id |
category | varchar(50) | no | 商品类别名称 |
- products(商品名称表):
列名 | 数据类型 | 允许Null值 | 信息 |
---|---|---|---|
productId | int | no | 商品名称id |
name | varchar(MAX) | no | 商品名称 |
catIds | int | no | 商品所属类别id |
- ratings(商品评论表):
列名 | 数据类型 | 允许Null值 | 信息 |
---|---|---|---|
userId | int | no | 用户Id |
productId | int | no | 商品id |
rating | varchar(50) | yes | 用户评分 |
timestamp | varchar(50) | no | 时间戳 |
title | varchar(50) | yes | 评论标题 |
comment | varchar(50) | yes | 评论内容 |
代码如下:
--创建categories表
DROP TABLE IF EXIT 'categories';
CREATE TABLE categories (
catId int primary key not null,
category varchar(50) not null
);
--创建products表
DROP TABLE IF EXIT 'products';
CREATE TABLE products(
productId int primary key not null,
name varchar(MAX) not null,
catIds int not null
);
--创建ratings表
DROP TABLE IF EXIT 'ratings';
CREATE TABLE ratings(
userId int not null;
productId int not null;
rating vatchar(50) null;
timestamp varchar(50) not null;
title varchar(50) null;
comment varchar(50) null;
);
实验三:SQL语言的DDL
-
本次实验了解DDL语言的CREATE、DROP、ALTER对表、索引、视图的操作,学会MySQL中用
DDL语言进行对表、索引、视图的增加、删除和改动。
-
创建表:详见实验二。
-
创建索引:在表的数据量较大的时候,索引能够有效加快查询速度。数据库提供多种索引模式,在
数据库系统内部实现。下面演示在categories表和products中建立索引:
CREATE UNIQUE INDEX idx_catId ON categories(catId ASC);
CREATE UNIQUE INDEX idx_productId ON products(productId ASC);
- 删除索引:
DROP INDEX idx_catId;
DROP INDEX idx_productId;
- 创建视图:可以使用以下 SQL 语句来创建一个视图,以统计每个分类下的商品总数
CREATE VIEW category_product_count AS
SELECT c.category_id, c.category_name, COUNT(p.product_id) AS product_count
FROM categories c
LEFT JOIN products p ON c.category_id = p.category_id
GROUP BY c.category_id, c.category_name;
在上述 SQL 语句中,我们使用了 LEFT JOIN 来保证即便某个分类下没有商品,也能在视图中显示 0 个商品总数。对于每个分类,我们使用了 COUNT 函数来计算其下所有商品的总数,并将该结果命名为 product_count。最后通过 GROUP BY 对结果进行分组,以便将各个分类的商品数量统计结果合并。
创建完成后,我们可以通过下面的语句查询视图中的数据:
SELECT * FROM category_product_count;
实验四:SQL语言的DML初步
-
DML包括数据查询和数据更新两种数据操作语句。其中,数据查询指对数据库中的数据查询、统计、分组、排序等操作;数据更新指数据的插入、删除和修改等数据维护操作。
-
向表中插入数据(数据来源于github上关于近期amazon商品开源评论集,以下将展示插入部分数据到products表和ratings表中):
-- ---------------------------- -- Records of products -- ---------------------------- INSERT INTO `products` VALUES (0, 'CSSMs Biology: Control in Cells and in Organisms Unit 5', 832); INSERT INTO `products` VALUES (1, 'Treasure Island', 832); INSERT INTO `products` VALUES (2, 'Collins Primary Dictionaries – Collins Junior Illustrated Dictionary', 832); INSERT INTO `products` VALUES (3, 'Partners in Crime', 832); INSERT INTO `products` VALUES (4, 'The Hobbit', 832); INSERT INTO `products` VALUES (5, 'Caps for Sale Book and CD', 832); INSERT INTO `products` VALUES (6, 'The Gulag Archipelago Volume 3: An Experiment in Literary Investigation', 832); INSERT INTO `products` VALUES (7, '150 Best Bathroom Ideas', 832); INSERT INTO `products` VALUES (8, 'The Forgotten Warrior', 832); INSERT INTO `products` VALUES (9, 'Free Fall', 832); INSERT INTO `products` VALUES (10, 'What\s So Bad About Gasoline?', 832); INSERT INTO `products` VALUES (11, 'Barbarians at the Gate: The Fall of RJR Nabisco', 832); INSERT INTO `products` VALUES (12, 'The Secret Circle: The Initiation and The Captive Part I', 832); INSERT INTO `products` VALUES (13, 'Alex & Me: How a Scientist and a Parrot Discovered a Hidden World of Animal Intelligence--And Formed a Deep Bond in the Process', 832); INSERT INTO `products` VALUES (14, 'Knocking on Heaven\'s Door: How Physics and Scientific Thinking Illuminate the Universe and the Modern World', 832); INSERT INTO `products` VALUES (15, 'The Boy Who Harnessed the Wind: Creating Currents of Electricity and Hope', 832); INSERT INTO `products` VALUES (16, 'My Booky Wook: A Memoir of Sex, Drugs, and Stand-Up', 832); INSERT INTO `products` VALUES (17, 'Alex & Me: How a Scientist and a Parrot Discovered a Hidden World of Animal Intelligence--And Formed a Deep Bond in the Process', 832); INSERT INTO `products` VALUES (18, 'Power: Why Some People Have It-and Others Don\'t', 832); INSERT INTO `products` VALUES (19, 'If You Have to Cry, Go Outside: and Other Things Your Mother Never Told You', 832); INSERT INTO `products` VALUES (20, 'The Concise Roget\'s International Thesaurus, Revised and Updated, 7th Edition', 832); ...... -- ---------------------------- -- Records of ratings -- ---------------------------- INSERT INTO `ratings` VALUES (0, 0, 5, '1332172800', '不错的复习资料', '简洁、明了、没有废话'); INSERT INTO `ratings` VALUES (0, 1650, 5, '1263139200', 'DSC', NULL); INSERT INTO `ratings` VALUES (0, 34489, 5, '1379001600', '还不错', '不错 我还没看 书很好 很新'); INSERT INTO `ratings` VALUES (0, 36709, 1, '1380729600', '电视机质量差不能换', '我想打0分的 可惜不行 电视机用1个月黑屏自动关机又不能换,修的人也不知道电视机哪里坏了,让我们电视机用的彻底坏了再去修,质量实在太差,这电视机我现在开都不想开,有时候10分钟,有时候1小时自动关机,浪费'); INSERT INTO `ratings` VALUES (0, 38334, 5, '1390233600', '好!', NULL); INSERT INTO `ratings` VALUES (0, 50679, 5, '1311350400', '好', NULL); INSERT INTO `ratings` VALUES (0, 51702, 4, '1365091200', '不错', NULL); INSERT INTO `ratings` VALUES (0, 59268, 5, '1321286400', '不错', NULL); INSERT INTO `ratings` VALUES (0, 75687, 5, '1255968000', 'DSC', NULL); INSERT INTO `ratings` VALUES (0, 102883, 4, '1302105600', '内容详细,准确性较高', NULL); INSERT INTO `ratings` VALUES (0, 131713, 5, '1268496000', 'DSC', NULL); INSERT INTO `ratings` VALUES (0, 142899, 2, '1375113600', '字好小 看着压抑', NULL); INSERT INTO `ratings` VALUES (0, 152355, 4, '1376841600', '个人感觉不错', NULL); INSERT INTO `ratings` VALUES (0, 155731, 5, '1365523200', '经典,很好', '经典,睡不着就看看的'); INSERT INTO `ratings` VALUES (0, 180511, 3, '1302796800', '有点贵', NULL); INSERT INTO `ratings` VALUES (0, 180619, 5, '1375718400', '货真价实', '很不错,质量有保证!'); INSERT INTO `ratings` VALUES (0, 185916, 5, '1371484800', 'jklhjlhjlhjk', NULL); INSERT INTO `ratings` VALUES (0, 196282, 5, '1365523200', '经典,很好', '经典,睡不着就看看的'); INSERT INTO `ratings` VALUES (0, 214139, 5, '1388332800', '不错', NULL); INSERT INTO `ratings` VALUES (0, 277735, 5, '1376236800', '实用', '这本书不错,丰富的分离方法,比较详细的参考书。'); INSERT INTO `ratings` VALUES (0, 286203, 5, '1252598400', 'DSC-2009第三季信息港评选十组代表艺人', NULL); INSERT INTO `ratings` VALUES (0, 300752, 5, '1318176000', '书的内容非常好!', '书的内容非常好!是“爱的教育”好素材!想象力更是出人意料!很值得珍藏的一本书,我是和孩子都看完后才买的。我经常推荐给别的孩子,也让孩子推荐给她的同学,“一只蜘蛛怎样救一头猪呢”,没有人能想象出更好的答案!'); INSERT INTO `ratings` VALUES (0, 360192, 5, '1378396800', '挺好的', NULL); INSERT INTO `ratings` VALUES (0, 364433, 5, '1367942400', '强烈推荐', '物美价廉,质量上乘。');
导入所有数据后,每个表显示为:
-
categories(商品类别表)
-
products(商品名称表)
-
ratings(商品评论表)
-
实验五:DML的数据查询
-
DML的数据查询指对数据库中的数据查询、统计、分组、排序等操作。查询语句可以分为简单查询、连接查询、嵌套查询和组合查询。
-
简单查询
SELECT * FROM categories WHERE category = '图书音像'
- 连接查询
SELECT categories.catId,categories.category,products.name FROM categories FULL JOIN products ON categories.catId = products.catIds;
- 嵌套查询
SELECT products.productId,products.name,catIds FROM products
WHERE catIds IN
(SELECT categories.catId FROM categories WHERE category = '图书音像');
实验六:SQL语言的DCL
-
SQL的数据控制通过DCL(数据控制语言) 实现。DCL通过对数据库用户的授权和收权命令来实现有关数据的存取控制,以保证数据库的安全性。
-
实验步骤:
-
使用最高权限的账号登录数据库,在安全性→登录名(鼠标右击)→新建登录名
-
在弹出新建登录名窗口的“常规”中,输入登录名test1和密码。
-
点击左边选择页中的“服务器角色”,来给新建用户授予权限。
-
点击左边选择页中的“用户映射”,选择用户可以登录的数据库、选择用户拥有的登录数据库的权限。
-
最后点击“状态”,授予连接到数据库引擎,登录名启用,最后点击确定就可以了。
-
实验七:商品评论平台小程序的设计与实现
1.实验背景
- 随着电商平台的盛行,越来越多的消费者在网上购物,而商品评论是消费者决定购买的重要参考。
- 然而,现有的商品评论往往存在着一些问题,如评论不真实、评论存在一定的偏差等。面对这些问题,很多电商平台开始采用匿名评论的方式,以便消费者可以更加自由地、真实地表达自己的观点。
- 因此,为了提高消费者的购物体验,我开发了一款商品评论平台小程序。该小程序可以让消费者查看自己想要购买的商品评分、大众评价并对已有的商品上传使用感受,从而方便消费者提前了解商品的大致情况,以做出更准确的判断。
2.实验开发环境
- 操作系统:win11/Ubuntu(64-bit)
- 开发工具:微信开发者工具等
- 服务器:云服务器ESC(1核(vCPU) 2 GiB)
- 数据库工具:SQLServer19.0.2、Navicat Preminum绿色版
3.实验主要技术
-
小程序框架:小程序原生框架可以快速实现视图层、逻辑层和数据层的分离和交互。
-
组件库:小程序提供了大量的原生组件,如按钮、文本输入框、图片、音视频等组件,还有其他第三方组件库,如weUI、vant等。
-
API和SDK:小程序提供了一系列API和SDK,便于调用微信提供的底层能力,如获取用户信息、请求网络等功能。
-
云开发:小程序提供了云开发服务,包括云函数、云数据库、云存储、云托管等功能,可以方便地进行后端开发和管理。
-
ES6及以上版本:小程序支持ES6及以上版本的JavaScript语法,包括箭头函数、let和const、模板字符串等。
-
CSS:小程序支持CSS3及以上的语法,例如flex、border-radius等, 方便开发者进行页面布局和美化。
简要流程:
-
用户在微信小程序中点击按钮,触发前端事件。微信小程序前端将触发事件和需要传递的数据发送给后端服务器,后端服务器接收到请求。后端服务器根据接收到的请求,在数据库中进行相关数据的查询或修改,将结果返回给小程序前端。微信小程序前端解析后端返回的数据,根据数据更新小程序视图的显示内容,用户看到更新后的小程序页面。
-
在整个流程中,前端主要负责小程序的视图渲染和与用户的交互,后端负责对数据库进行操作,服务器则负责连接前后端并进行数据的传递。
4.核心功能
-
用户验证
采用微信官方认证方式,微信小程序需要接入微信开放平台的认证功能,通过微信开放平台给小程序授权,获取用户身份信息。这种方式可以从微信的后台验证用户身份,并获取微信开放平台提供的session_key和openid等信息,以确保用户的安全和隐私。
-
查询模块
-
添加模块
5.系统设计
(1)数据库设计
- 创建数据库categories、products、ratings,具体内容见实验二。
- 该数据库的E-R图如下:
(2)登录设计
import { HttpRequest } from '../../utils/requests/index'
import type { LoginResult } from '../../utils/requests/typing'
Component({
/**
* 组件的属性列表
*/
properties: {
show: {
type: Boolean,
value: false
},
title: {
type: String,
value: "登录"
},
buttons: {
type: Array,
value: [
{ "text": "取消" },
{ "text": "确认" }
]
}
},
/**
* 组件的初始数据
*/
data: {
login_code: '',
encrypted_data: '',
iv: ''
},
/**
* 组件的方法列表
*/
methods: {
/**
* 获取用户信息
*/
getUserProfile() {
return new Promise((resolve: any, reject: any) => {
wx.getUserProfile({
desc: '展示用户信息',
success: (res) => {
this.setData({
encrypted_data: res.encryptedData,
iv: res.iv
});
resolve();
},
fail: reject
})
})
},
// 获取登陆的code
getLoginCode() {
return new Promise((resolve: any, reject: any) => {
wx.login({
success: (res) => {
this.setData({
"login_code": res.code,
})
resolve();
},
fail: reject
})
})
},
/**
* 展示轻提示
*/
showToast(message: string, icon: any = "success", duration: number = 15000) {
wx.hideToast()
wx.showToast({
title: message,
icon: icon,
duration: duration,
mask: true
})
},
/**
* 登录
*/
login() {
// 判断是否获取到了登录code和用户信息
Promise.all([this.getLoginCode(), this.getUserProfile()]).then(async () => {
// 展示登陆中
this.showToast("登陆中...", "loading", 60000)
// 获取请求对象单例
let requests = HttpRequest.getInstance()
// 获取登录code
let login_code = this.data.login_code
// 获取用户信息密文
let encrypted_data = this.data.encrypted_data
// 获取盐
let iv = this.data.iv
// 发起请求
let result = await requests.login(login_code, encrypted_data, iv)
// 判断登录是否成功
if (result) {
result as unknown as LoginResult
// 将token取出
const { token } = result.data.data
// 将token存储
wx.setStorageSync("token", token)
// 提示登录成功
this.showToast("登陆成功", "success", 15000)
// 收起登录框
this.setData({show:false})
// 跳转回上个页面
wx.navigateBack()
} else {
// 提示登录失败
this.showToast("登录失败", "error", 15000)
// 收起登录框
this.setData({show:false})
}
}).catch((e) => {
this.showToast("用户拒绝授权", "error", 1500)
this.setData({ show: false })
console.log(e);
})
},
/**
* 点击了按钮
*/
onClicked(e: any) {
// 判断点击的是哪个按钮
// 点击取消
if (e.detail.index === 0) {
this.setData({
show: false
})
return
}
// 点击了确认,登录
this.login()
}
}
})
(3)查询设计
import { HttpRequest } from '../../utils/requests/index'
import type { SearchCategoriesResult, SearchProductsResult, SearchProductsListRequestConfig, SearchProductsListResult } from '../../utils/requests/typing'
Component({
// 数据监听器
observers: {
/**
* 当商品列表发生变化时触发
* @param value 新的数据
*/
'products_list': function (value: Array<SearchProductsListResult>) {
this.triggerEvent('productsListChange', value)
}
},
/**
* 组件生命周期
*/
lifetimes: {
/**
* 在组件实例进入页面节点树时执行
*/
attached: function () {
this.setData({
search: this.onSearch.bind(this),
search_result: []
})
},
},
/**
* 组件的属性列表
*/
properties: {
// 当前商品列表的页码
page_num: {
type: Number,
value: 0
},
// 当前商品列表每页显示数量
page_amount: {
type: Number,
value: 10
},
// 当前商品名称id列表
c_id: {
type: Number,
value: undefined
},
// 当前商品种类id
p_id: {
type: Array,
value: []
},
// 是否最新一页
last_page: {
type: Boolean,
value: false
},
// 商品列表
products_list: {
type: Array,
value: [{ productId: null, name: null, catId: null, category: null }]
}
},
/**
* 组件的初始数据
*/
data: {
// 当前搜索框内容
search_inp_value: '',
// 搜索框的提示内容
placeholder: '请输入要搜索的商品类别',
// 搜索方法
search: (_value: string): void => { },
// 是否展示搜索结果
showResult: false,
// 搜索结果
search_result: [{}],
// 是否展示搜索项菜单
show_action_sheet: false,
// 当前搜索项下标
currIndex: 0,
// 当前类别
currCategories: { value: null, text: null },
// 搜索项
action_sheet_groups: [
{ text: '商品类别', value: 1 },
{ text: '商品名称', value: 2 },
{ text: '清空类别', value: 3 }
],
},
/**
* 组件的方法列表
*/
methods: {
/**
* 当用户点击搜索框触发
*/
onSearchFocus() {
this.setData({
showResult: true
})
},
/**
* 当用户点击搜索框以外触发
*/
onSearchBlur() {
this.setData({
showResult: false
})
},
/**
* 当用户点击搜索框清空触发
*/
onSearchClear() {
this.setData({
showResult: false,
search_result: []
})
},
/**
* 展示搜索项
*/
showActionsheet() {
this.setData({ show_action_sheet: true })
},
/**
* 当用户点击遮罩层关闭搜索项
*/
onClose() {
this.setData({ show_action_sheet: false })
},
/**
* 当用户点击搜索项的时候触发
* @param e
*/
onActiontap(e: any) {
let placeholder;
let currIndex = 0;
switch (e.detail.value) {
case 1:
currIndex = 0
break
case 2:
currIndex = 1
break
case 3:
currIndex = this.data.currIndex
this.setData({ currCategories: { text: null, value: null } })
}
placeholder = `请输入要搜索的${this.data.action_sheet_groups[currIndex].text}`
this.setData({ show_action_sheet: false, placeholder: placeholder, currIndex: currIndex })
},
/**
* 搜索商品类别
* @param keyword 关键字
*/
searchCategories(keyword: string): Promise<Array<object>> {
return new Promise<Array<object>>(async () => {
// 获取请求对象单例
let requests = HttpRequest.getInstance()
// 发送请求
let result = await requests.searchCategories(keyword)
// 判断结果是否有效
if (result) {
// 处理结果
let items = result.data.data.map((item: SearchCategoriesResult) => {
return { text: item.category, value: item.catId }
})
// 将结果处理
this.setData({
search_result: items
})
} else {
this.setData({
search_result: []
})
}
})
},
/**
* 搜索商品名字
* @param _keyword
*/
searchProducts(keyword: string): Promise<Array<object>> {
return new Promise<Array<object>>(async () => {
// 获取请求对象单例
let requests = HttpRequest.getInstance()
// 发送请求
let result = await requests.SearchProducts(keyword)
// 判断结果是否有效
if (result) {
// 将结果处理
let items = result.data.data.map((item: SearchProductsResult) => {
return { text: item.name, value: item.productId, catId: item.catIds }
})
// 获取当前的商品类别
let currCategories = this.data.currCategories
// 判断是否选择了商品类别
if (currCategories.value !== null) {
// 将符合当前类别的选项挑出来
items = items.filter((item) => {
return item.catId === currCategories.value
})
}
// 将结果展示
this.setData({
search_result: items
})
} else {
this.setData({
search_result: []
})
}
})
},
/**
* 当用户搜索输入时触发
*/
onSearch(value: string): Promise<null> {
// 判断用户搜索的是商品还是
if (this.data.currIndex === 0) {
this.searchCategories(value)
} else {
this.searchProducts(value)
}
return new Promise(() => { })
},
/**
* 下一页
*/
nextPage() {
if (this.data.last_page){
// 展示轻提示
this.showToast("已经是最新一页", "none", 1500)
return;
}
this.setData({
page_num: this.data.page_num + 1
})
this.getProductsList()
},
/**
* 展示轻提示
*/
showToast(message: string, icon: any = "success", duration: number = 15000) {
wx.hideToast()
wx.showToast({
title: message,
icon: icon,
duration: duration,
mask: true
})
},
/**
* 请求商品列表
*/
getProductsList() {
const option: SearchProductsListRequestConfig = {
page_num: this.data.page_num,
amount: this.data.page_amount
}
// 如果选择了分类
if (this.data.c_id) option['category_id'] = this.data.c_id;
// 如果有商品id数组
if (this.data.p_id.length > 0) option['id_list'] = this.data.p_id;
// 展示轻提示
this.showToast("加载中...", "loading", 60000)
new Promise(async () => {
// 获取请求实例
let requests = HttpRequest.getInstance()
// 发起请求
let result = await requests.SearchProductsList(option)
// 判断结果是否有效
if (result) {
let data = result.data.data
let is_last = false
if (data.length === 0) {
is_last = true
}
// 将结果保存
this.setData({
products_list: this.data.products_list.concat(result.data.data),
last_page: is_last
})
// 展示轻提示
this.showToast("加载完成", "success", 1500)
} else {
this.setData({
search_result: []
})
// 展示轻提示
this.showToast("加载失败", "error", 1500)
}
})
},
/**
* 当用户点击了搜索结果项之后触发
* @param 事件对象
*/
onSelectresult(e: any) {
// 提取点击的结果项
let dataset = e.currentTarget.dataset
// 判断点击的是什么
if (this.data.currIndex === 0) {
// 设置当前的搜索参数
this.setData({
// 要搜索的商品种类id
c_id: dataset.value,
// 要搜索的商品id列表
p_id: [],
// 要搜索的商品的页码
page_num: 1,
// 要搜索的商品的每页数量
page_amound: 10,
// 当前商品列表
products_list: [],
// 保存当前选择的类别
currCategories: dataset,
// 清空搜索结果
search_result: [],
// 保存当前选择类别的名字
search_inp_value: dataset.text
})
} else {
// 点击的是商品名字
// 设置当前的搜索参数
this.setData({
// 要搜索的商品id列表
p_id: [dataset.value],
// 要搜索的商品的页码
page_num: 1,
// 要搜索的商品的每页数量
page_amound: 10,
// 当前商品列表
products_list: [],
// 清空搜索结果
search_result: [],
// 保存当前选择类别的名字
search_inp_value: dataset.text
})
}
// 发送请求
this.getProductsList();
}
}
})
(4)添加分类
import { HttpRequest } from '../../utils/requests/index'
const backend_app = getApp<IAppOption>();
Page({
/**
* 页面的初始数据
*/
data: {
category_input: '',
categories: [{ catId: -1, category: "无" }],
select_categories: { catId: -1, category: "无" },
product_input: '',
product_image: '',
domain: ''
},
/**
* 生命周期函数--监听页面加载
*/
onLoad() {
this.setData({
domain: backend_app.globalData.domain
})
// 获取所有的商品分类
new Promise(async () => {
const request = HttpRequest.getInstance()
const result = await request.GetCategory()
if (result) {
this.setData({
categories: result.data.data
})
}
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
},
/**
* 展示轻提示
*/
showToast(message: string, icon: any = "success", duration: number = 15000) {
wx.hideToast()
wx.showToast({
title: message,
icon: icon,
duration: duration,
mask: true
})
},
/**
* 当添加商品分类输入
*/
onCategoryInput(e: any) {
this.setData({
category_input: e.detail.value
})
},
/**
* 添加分类按钮
*/
onAddCategory() {
if (!this.data.category_input.trim()) {
this.showToast("请输入分类名称", "none", 1000)
return
}
this.showToast("发起请求", "loding", 60000)
new Promise(async () => {
const request = HttpRequest.getInstance()
const result = await request.AddCategory({
category_name: this.data.category_input
})
if (result?.data.code === 0) {
this.showToast("添加成功", "success", 1000)
} else {
this.showToast("添加失败", "error", 1000)
}
})
},
/**
* 选择了商品分类
* @param e
*/
onCategoryChange(e: any) {
this.setData({
select_categories: this.data.categories[e.detail.value]
})
},
/**
* 输入了商品名称
* @param e
*/
onProductInput(e: any) {
this.setData({
product_input: e.detail.value
})
},
/**
* 选择图片
*/
onChooseImage() {
const self = this;
wx.chooseMedia({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success(res) {
wx.uploadFile({
url: `${backend_app.globalData.domain}/goods/upload_image`,
filePath: res.tempFiles[0].tempFilePath,
name: 'image',
header: {token:wx.getStorageSync("token")},
success: (res:any) => {
let data = JSON.parse(res.data)
if (data.code === 0) {
self.setData({
product_image: data.data.file_name
})
}
},
fail: () => {
self.showToast("上传图片失败", "error", 1000)
}
});
},
fail() {
self.showToast("选择图片失败", "error", 1000)
}
});
},
/**
* 添加商品
*/
onAddProduct() {
if (this.data.select_categories.catId === -1) {
this.showToast("请选择商品分类", "none", 1000)
return
}
if (this.data.product_input === '') {
this.showToast("请填写商品名称", "none", 1000)
return
}
if (this.data.product_image === '') {
this.showToast("请选择商品图片", "none", 1000)
return
}
this.showToast("添加中...", "loding", 60000)
new Promise(async () => {
const request = HttpRequest.getInstance()
const result = await request.AddProduct({
image:this.data.product_image,
name: this.data.product_input,
category_id: this.data.select_categories.catId
})
if (result) {
this.showToast("添加成功", "success", 1000)
}else {
this.showToast("添加失败", "error", 1000)
}
})
}
})
(5)添加评论
import { HttpRequest } from '../../utils/requests/index'
const comment_app = getApp<IAppOption>()
Page({
/**
* 页面的初始数据
*/
data: {
// 商品id
productId: 0,
// 当前查询结果
ratings_list: [{}],
// 每个评论的展开状态
show_list: [],
// 评论总数量
count: 0,
// 当前页码
page_num: 1,
// 每页显示多少
page_amount: 10,
// 是否最新页
is_last: false,
// 展示评论列表的高度
list_view_height: ['height: calc(100vh - 200rpx);', 'height: calc(100vh - 100rpx - 100rpx - 0px);'],
// 评论操作台的展开状态
console_show: false,
// 键盘高度
keyboard_height: 0,
// 输入的评论内容
input_value: { title: '', comment: '', rating: 5 },
// 域名
domain:''
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(option: any) {
// 监听键盘高度变化事件
wx.onKeyboardHeightChange((res) => {
let list_height = this.data.list_view_height
list_height[1] = `height: calc(100vh - 100rpx - 100rpx - ${res.height}px);`
this.setData({
keyboard_height: res.height,
list_view_height: list_height
});
});
// 保存当前商品id
this.setData({
productId: option.productId,
domain:comment_app.globalData.domain
})
this.requestRatings()
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
},
/**
* 下一页
*/
nextPage() {
if (this.data.is_last) {
// 展示轻提示
this.showToast("已经是最新一页", "none", 1500)
return;
}
this.setData({
page_num: this.data.page_num + 1
})
this.requestRatings()
},
/**
* 请求商品评论
*/
requestRatings() {
this.showToast("加载中...", "loding", 1000)
// 请求商品id
new Promise(async () => {
// 获取请求实例
const request = HttpRequest.getInstance()
// 发起请求
let result = await request.GetRatingList({
product_id: this.data.productId,
page_num: this.data.page_num,
amount: this.data.page_amount
})
// 判断是否可以用
if (result) {
this.showToast("加载完成", "success", 1000)
// 将其保存
this.setData({
ratings_list: this.data.ratings_list.concat(result.data.data.list),
count: result.data.data.count
})
if (result.data.data.list.length === 0) {
this.setData({
is_last: true
})
}
} else {
this.showToast("加载失败", "error", 1000)
}
})
},
/**
* 评论视图滑到底
*/
onScrolltolower() {
this.nextPage()
},
/**
* 展示轻提示
*/
showToast(message: string, icon: any = "success", duration: number = 15000) {
wx.hideToast()
wx.showToast({
title: message,
icon: icon,
duration: duration,
mask: true
})
},
/**
* 评论输入框获得焦点触发
*/
onInputFocus() {
this.setData({
console_show: true
})
},
/**
* 评论输入框失去焦点触发
*/
onInputBlur(e: any) {
const input_value = this.data.input_value
switch (e.currentTarget.dataset.type) {
case 'title':
input_value.title = e.detail.value
break
case 'comment':
input_value.comment = e.detail.value
break
case 'rating':
let num = parseFloat(e.detail.value); // 将输入框的值转换为数字
if (isNaN(num)) { // 如果转换失败就将其设置为5
num = 5;
} else if (num < 0) { // 如果小于0就将其设置为0
num = 0;
} else if (num > 5) { // 如果大于5就将其设置为5
num = 5;
}
input_value.rating = num
}
// 当输入框失去焦点时,保存输入的值
this.setData({
console_show: false,
input_value: input_value,
})
},
// 发送评论
sendComment: function () {
const { input_value } = this.data;
if (!input_value.title.trim()) {
wx.showToast({
title: '请输入评论标题',
icon: 'none',
duration: 2000,
});
return;
} else if (!input_value.comment.trim()) {
wx.showToast({
title: '请输入评论内容',
icon: 'none',
duration: 2000,
});
return;
}
this.showToast('提交中...', 'loding', 60000)
// 在这里处理发送评论的逻辑,例如调用后端接口发送评论
new Promise(async () => {
const request = HttpRequest.getInstance()
const result = await request.AddRating({
product_id: this.data.productId,
title: this.data.input_value.title,
comment: this.data.input_value.comment,
rating: this.data.input_value.rating
})
if (result?.data.code === 0) {
this.showToast('成功', 'success', 1000)
this.setData({
ratings_list: this.data.ratings_list.concat([{
title: this.data.input_value.title,
comment: this.data.input_value.comment,
user_avatar_url: result.data.data.avatar_url,
user_name: result.data.data.nickName,
timestamp: result.data.data.timestamp,
rating: this.data.input_value.rating
}])
})
} else {
this.showToast('失败', 'error', 1000)
}
})
},
})