一、回顾案例5
案例5连接:CSDN
案例5中我前端的数据都是写在js里面的data的,现在通过egg服务器来连接数据库,设计数据库表,来实现动态渲染微信小程序前端页面,为了节省时间精力,前端代码大都不改变,只需要把数据库获取的数据格式改编成js的data里面的数据格式即可。
二、egg服务器代码
1、配置mysql数据库
egg服务器要下载mysql数据库的模块:npm i --save egg-mysql
接着在config文件夹里面的config.default.js里面配置:
config.mysql = {
client:{
host:'localhost',
port:"3306",
user:"root",
password:"123456",
database:"sx"
},
app:true,
agent:false
}
2、创建接口
3、在控制层中编写每一个接口函数
4、在服务层中编写具体实现代码
三、egg服务器具体代码
接口层
'use strict';
/**
* @param {Egg.Application} app - egg application
*/
// 接口,也就是前端请求的地址,请求的哪一个接口方法,就去调用
module.exports = app => {
const { router, controller } = app;
router.post('/',controller.home.index);
router.post('/chat',controller.home.chat);
router.post('/setUserInfo',controller.home.setUserInfo);
router.post('/getUserinfo',controller.home.getUserinfo);
router.post('/getCategory',controller.home.getCategory);
router.post('/getProducts',controller.home.getProducts);
};
控制层
'use strict';
const Controller = require('egg').Controller;
class HomeController extends Controller {
async index() {
const { ctx } = this;
ctx.body = 'hi, egg';// ctx.body返回数据到前端
}
// 结合腾讯AI开发平台的智能对话,首先前端发送聊天内容后端服务器接收到后再通过InputText把聊天数据发送到腾讯服务器获取智能AI的回复聊天内容,再把该内容返回到前端
async chat() {
const { ctx } = this;
//下面这段代码是腾讯AI开发平台生成的
console.log(ctx.request.body);
var myMsg = ctx.request.body.myMsg //从前端接收到的数据
// Depends on tencentcloud-sdk-nodejs version 4.0.3 or higher
const tencentcloud = require("tencentcloud-sdk-nodejs");
//该代码表示需要去下载tencentcloud-sdk-nodejs这个模块
const TbpClient = tencentcloud.tbp.v20190627.Client;
// 实例化一个认证对象,入参需要传入腾讯云账户secretId,secretKey,此处还需注意密钥对的保密
// 密钥可前往https://console.cloud.tencent.com/cam/capi网站进行获取
const clientConfig = {
credential: {
secretId: "AKIDSkmY4LM8euue8MK2UgcIismQTHq9CzWn",
secretKey: "3qMddNr55qMccNs76pIVR7XhaEclfIn2",
},
region: "",
profile: {
httpProfile: {
endpoint: "tbp.tencentcloudapi.com",
},
},
};
// 实例化要请求产品的client对象,clientProfile是可选的
const client = new TbpClient(clientConfig);
const params = {
"BotId": "c472c9ea-8edf-4486-a58d-560c5e14c814",
"BotEnv": "dev",
"TerminalId": "1447608208",
"InputText": myMsg
// 前端传过来的数据,再传给腾讯服务器,以获取智能AI回复的数据
};
// await是等待执行,等返回数据后再执行
await client.TextProcess(params).then(
(data) => {
console.log(data);
ctx.body = data; //返回到前端的数据
},
(err) => {
console.error("error", err);
}
);
}
// 根据接口的方法来到这里,又去服务层调用index(),该方法里面是获取数据库数据的具体代码
async getUserinfo() {
const { ctx } = this;
ctx.body = await ctx.service.home.index();
}
async setUserInfo() {
const { ctx } = this;
// console.log(ctx.request.body);
var data = ctx.request.body
ctx.body = await ctx.service.home.setUserInfo(data)
// ctx.body = "hi body"
// ctx.body = await ctx.service.home.setUserInfo();
}
// 获取父级类别
async getCategory() {
const { ctx } = this;
ctx.body = await ctx.service.home.getCategory();
}
// 获取选中菜单产品内容
async getProducts() {
const { ctx } = this;
const order_id=ctx.request.body.order_id;//根据前端传来的order_id查询选中菜单的产品内容,
console.log(order_id+" 前端传来的order_id");
ctx.body = await ctx.service.home.getProducts(order_id);
}
}
module.exports = HomeController;
服务层
'use strict';
const Service = require('egg').Service;
class HomeService extends Service {
async index() {
const { app } = this;
let res = await app.mysql.get("userinfo",{id:1})
console.log(res);
return res
}
// 获取父级类别
async getCategory() {
const { app } = this;
// let res = await app.mysql.get("product_category",{parent_id:0})
let res = await this.app.mysql.select('product_category', { // 搜索 post 表
where: { parent_id: '0'}, // WHERE 条件
columns: ['name','select','order_id']})// 要查询的表字段
console.log(res);
return res
}
// 获取选中菜单的产品内容
async getProducts(order_id) {
const { app } = this;
// 由于数据从两个表获取,所以组合起来自定义返回数据类型
const res={
name:'',
imgUrl:'',
navigator:'',
container:[]
}
let selectMenu = await this.app.mysql.select('product_category', { // 搜索 post 表
where: { order_id: order_id}, // WHERE 条件
columns: ['name','id','imgUrl']})// 要查询的表字段
res.name=selectMenu[0].name;
res.imgUrl=selectMenu[0].imgUrl;
let id=selectMenu[0].id; //获取选中菜单的id,接着根据这个父id寻找子菜单
let navigator = await this.app.mysql.select('product_category', { // 搜索 post 表
where: { parent_id: id}, // WHERE 条件
columns: ['name','id','select']})// 要查询的表字段
for(let i=0;i<navigator.length;i++){
const container={
title:'',
goods:[],
}
res.navigator=navigator;//把数据库获取的navigator导航数组赋值给res的navigator数组
let navigator_item = await this.app.mysql.select('product', { // 搜索 post 表
where: { category_id: navigator[i].id}, // WHERE 条件
columns: ['image','title','price']})// 要查询的表字段
container.title=navigator[i].name;
container.goods=navigator_item;
res.container.push(container);
}
console.log(res);
return res
}
async setUserInfo(data) {
const { app } = this;
var openid = await app.mysql.get('userinfo',{openid:data.openid});
if(openid) {
return {
code:100
}
}else {
var res = await app.mysql.insert('userinfo',{name:data.name,hdsrc:data.hdSrc,openid:data.openid});
if(res.affectedRows) {
return {
code:102
}
}
}
}
}
module.exports = HomeService;
四、前端
wxml代码
<!--
项目:仿小米Lite小程序的分类板块
时间:2022/09/17-18
-->
<view class="parent">
<!-- 左侧滚动区域 -->
<scroll-view style="height:calc(100vh);width:25vw;" scroll-y>
<view class="fa">
<view class="son" wx:for="{{itemList}}" bindtap="selected" data-id="{{item.order_id}}"><span class="{{item.select !=0 ? 'active' : ''}}">{{item.name}}</span></view>
</view>
</scroll-view>
<!-- 右侧滚动区域 -->
<scroll-view style="height:calc(100vh);width:75vw;" scroll-y scroll-into-view="{{ intoindex }}" bindscroll="scroll" class="right">
<view class="fa" id="fa">
<view style="text-align: center;">
<image src="{{product.imgUrl}}" mode="aspectFit" style="height: 100px;width: 275px;"></image>
</view>
<!-- 右侧中间导航栏 -->
<scroll-view style="height:36px; border-bottom: 1px solid #EBEBEB;" scroll-x class="{{navigator!=0 ? 'navigator':''}}">
<view class="xiaoMiMeau">
<view class="{{item.select !=0 ? 'XiaomiSelect' : ''}} " wx:for="{{product.navigator}}" bindtap="jumpToselect" data-id="{{index}}">{{item.name}}</view>
</view>
</scroll-view>
<!-- 小板块 -->
<view class="item" wx:for="{{product.container}}" id="text{{index}}">
<view>
<view class="XiaomiMIXTitle" >{{item.title}}</view>
<view>
<view class="xiaomiMixItem" wx:for="{{item.goods}}">
<view class="xiaomiMixPic">
<image src="{{item.image}}"></image>
</view>
<view class="xiaomiMixText">
<view class="title">{{item.title}}</view>
<view class="price">¥{{item.price}}起 </view>
</view>
</view>
</view>
</view>
</view>
<!-- 小板块结束 -->
</view> <!-- fa结束 -->
</scroll-view> <!-- 右侧滚动区域结束 -->
</view><!-- parent结束 -->
js代码
Page({
/**
* 页面的初始数据
*/
selected:function(e){
this.setData({
intoindex: "fa"
})
//先把之前选中的变为0,只能循环遍历了
for(var i=0;i<15;i++){
var item=this.data.itemList[i]
var flag=item.select
if(flag) {
var select = 'itemList['+i+'].select'
this.setData({
[select]:0
})
}
}
//获取wxml自定义数据data-id的值,点击事件会把当前选中的id传过来
var id = e.currentTarget.dataset.id
var select = 'itemList['+id+'].select'
this.setData({
[select]:1
})
//获取当前选中的页面产品数据
wx.request({
url: 'http://127.0.0.1:7001/getProducts',
method: 'POST',
data:{
order_id:id
},
success:(res)=>{
this.setData({
product:res.data
})
console.log(res.data)
}
})
},
jumpToselect: function (e) {
//改变右侧滚动区域的scroll-into-view="{{ intoindex }}"的值
console.log(e)
this.setData({
intoindex: "text" + e.currentTarget.dataset.id
})
// 改变导航的select值,当前选中的select由0改为1,而之前选中的由1改为0
//先把之前选中的变为0,只能循环遍历了
let navigator=this.data.product.navigator
console.log(navigator)
let length=this.data.product.navigator.length
console.log(length)
for(var i=0;i<length;i++){
var item=navigator[i]
var flag=item.select
if(flag==1) {
var select = 'product.navigator['+i+'].select'
console.log("select:"+select)
this.setData({
[select]:0
})
console.log(navigator[0].select)
}
}
//获取wxml自定义数据data-id的值,点击事件会把当前选中的id传过来
var id = e.currentTarget.dataset.id
console.log("自定义数据前端传来:"+id)
var select = 'product.navigator['+id+'].select'
this.setData({
[select]:1
})
},
scroll(e) {
console.log(e.detail.scrollTop)
let scrollTop=e.detail.scrollTop
if(scrollTop>100){
this.setData({
navigator:1
})}
else{
this.setData({
navigator:0
})
}
},
data: {
navigator:0 //表示右侧中间导航栏在未滚动前的状态,滚动100距离后由0变为1
} ,
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
wx.request({
url: 'http://127.0.0.1:7001/getProducts',
method: 'POST',
data:{
order_id:1
},
success:(res)=>{
this.setData({
product:res.data
})
console.log(res.data)
}
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
wx.request({
url: 'http://127.0.0.1:7001/getCategory',
method: 'POST',
success:(res)=>{
// console.log(res)
this.setData({
itemList:res.data
})
console.log(this.data.itemList)
}
})
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
}
})