技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-7.分类的模型关联和通用CRUD接口
技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-7.分类的模型关联和通用CRUD接口
技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-1.工具和本地环境
技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-2.启动项目
技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-3.路由、模型与数据库操作
技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-4.跨域且传输数据,并优化后端接口
技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-5.用户登录(一),密码的bcrypt(hash)加密与验证
技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-6.用户登录(二),token验证
技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-7.分类的模型关联和通用CRUD接口
技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-8.使用mavoneditor(vue的markdown编辑器),并批量上传图片
1.制作通用CRUD接口
分类内容的接口与管理员接口相同,都是增删改查,如果每个接口都复制一遍再稍作改动,接口页面内容会太多。所以我们对两个接口进行比对,找不同:
只有这里不同,所以我们只要在路由中把这个辨别值改为动态即可:
将这个辨别值当作模型名处理,因为后续数据接口操作实际上就是模型不同,增删改查方法都一样。
接口函数接收模型名(以查找所有数据接口为例):
public function findall(){// 接收数据$data = request() -> param();// return $data;// 根据模型名判断if($data['model'] == "admin"){$db_data = Admin::select();// 返回查找到的数据return $db_data;}else if($data['model'] == "category"){$db_data = Category::select();// 返回查找到的数据return $db_data;}}
因为php语言以命名空间为主,所以无法直接使用传值做模型方法使用,故我们需要判断后再用模型方法进行数据操作。
测试原管理员接口:
没问题,仿照管理员功能做出CategorySet.vue和CategoryList.vue:
CategorySet.vue:
<template><div><h1>{{id ? '编辑' : '创建'}}分类</h1><el-form label-width="80px" style="margin-top:20px;" @submit.native.prevent="save"><el-form-item label="用户名"><el-input v-model="model.name"></el-input></el-form-item><el-form-item><el-button type="primary" native-type="submit">保存</el-button></el-form-item></el-form></div>
</template>
<script>
export default {props: {id: {}},data(){return {model: {},parentOptions: [],}},methods: {async save(){let resif(this.id){res = await this.$http.put('rest/category/' + this.id, this.model)}else{res = await this.$http.post('rest/category', this.model)}console.log("en?",res)this.$router.push('/categories/list')this.$message({type: 'success',message: '保存成功'})},async fetch(){const res = await this.$http.get('rest/category/' + this.id)this.model = res.data},},created(){this.id && this.fetch()}
}
</script>
CategoryList.vue:
<template><div><h1>分类列表</h1><el-table :data="items"><el-table-column prop="id" label="ID" width="220"></el-table-column><el-table-column prop="name" label="分类名称"></el-table-column><el-table-columnfixed="right"label="操作"width="100"><template slot-scope="scope"><el-button type="text" size="small" @click="$router.push('/categories/edit/' + scope.row.id)">编辑</el-button><el-button @click="remove(scope.row)" type="text" size="small">删除</el-button></template></el-table-column></el-table></div>
</template>
<script>
export default {data() {return {items: []}},methods: {async fetch(){const res = await this.$http.get('rest/category')this.items = res.data},remove(row){this.$confirm('是否确定要删除分类"' + row.name + '"?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(async () => {// 要想使用await,函数必须使用async// await异步执行,待调用接口获取数据完成后再将值传给res,进行下一步操作const res = await this.$http.delete('rest/category/' + row.id)this.$message({type: 'success',message: '删除成功!'});if(res.status == 200){// 接口调用成功后,刷新页面this.fetch()}}).catch(() => {this.$message({type: 'info',message: '已取消删除'}); });}},created() {this.fetch()}
}
</script>
然后制作Category模型:
<?php
namespace app\admin\model;use think\Model;class Category extends Model{// 设置字段信息protected $schema = ['id' => 'int','name' => 'string',// 父级分类'parent' => 'string',];public function category(){// 用于后续数据关联使用(分类的无限层级关联)return $this -> hasMany(Category::class);}
}
新建数据表:
刷新页面查看:
没有报错,应该成功了,下面我们将全部接口函数改造:
<?php
declare (strict_types = 1);namespace app\admin\controller;use app\admin\model\Admin;
use app\admin\model\Category;class Index
{public function index(){return '您好!这是一个[index]示例应用';}public function add(){// 获取前端传值$data = request() -> param();if($data['model'] == "admin"){// 密码加密$data['password'] = password_hash($data['password'], PASSWORD_DEFAULT);// 使用模型格式化传来的数据$admin = new Admin;// 利用模型将数据传到数据库$admin->save(['username' => $data['username'],'password' => $data['password']]);// 返回结果return '新增数据成功';}else if($data['model'] == "category"){$admin = new Admin;// 利用模型将数据传到数据库$admin->save(['name' => $data['name'],]);// 返回结果return '新增数据成功';}}public function findall(){// 接收数据$data = request() -> param();// return $data;// 根据模型名判断if($data['model'] == "admin"){$db_data = Admin::select();// 返回查找到的数据return $db_data;}else if($data['model'] == "category"){$db_data = Category::select();// 返回查找到的数据return $db_data;}}public function find(){// 获取前端传值$data = request() -> param();if($data['model'] == "admin"){$db_data = Admin::find($data['id']);// 返回查找到的数据return $db_data;}else if($data['model'] == "category"){$db_data = Category::find($data['id']);// 返回查找到的数据return $db_data;} }public function update(){// 获取前端传值$data = request() -> param();// return $data;if($data['model'] == "admin"){// 密码加密$data['password'] = password_hash($data['password'], PASSWORD_DEFAULT);// 静态方法直接更新$db_data = Admin::update($data, ['id' => $data['id']]);return '修改数据成功';}else if($data['model'] == "category"){// 静态方法直接更新$db_data = Category::update($data, ['id' => $data['id']]);return '修改数据成功';}}public function delete(){// 获取前端传值$data= request() -> param();if($data['model'] == "admin"){$db_data = Admin::find($data['id']);$db_data->delete();return '删除数据成功';}else if($data['model'] == "category"){$db_data = Category::find($data['id']);$db_data->delete();return '删除数据成功';}}
}
新增数据测试:
修改测试:
成功,都没问题,到此通用接口完成。
2.无限层级分类
(1)更改新建分类页面
CategorySet.vue设置上级分类parent,位于分类名之上:
<el-form-item label="上级分类"><el-select v-model="model.parent"><!-- 使用select获取分类名name和该分类的id,后期如果修改分类名自动更新子分类的上级分类 --><!-- 其中label获取分类名,发送到数据库的值为该分类的id————以id为分类寻找依据 --><el-option v-for="item in parentOptions" :key="item.id" :label="item.name" :value="item.id"></el-option></el-select>
</el-form-item>
(2)使用查询接口
下方js使用categories查询分类接口获取分类信息,将获取到的数据传入分类数据parentOptions中:
async fetchParentOptions(){const res = await this.$http.get('rest/category')this.parentOptions = res.data
}
此时页面已接收到分类信息,并可以显示分类名了。
因为是直接复制的,所以还是用户名,改一下:
修改添加数据接口,添加parent字段:
此时新建分类:
成功:
这时候修改列表页,将上级分类显示出来:
保存后页面将显示上级分类:
此时我们需要让上级分类以分类名形式显示。
修改查询所有内容接口:
此时刷新页面得到关联分类内容:
但这并不是我们需要的内容,我们要的是上级分类,但是现在给我们查找的是上级分类的所有下级分类,所以再次改动,添加反向查询父级的方法:
改动find_all接口函数:
刷新页面测试:
成功查询到上级分类数据。
修改前端页面:
保存查看页面:
成功。很好。
此时我们再次修改上级分类php1改回php:
由于是id关联,所以上级分类变动后名字一起变化。
3.关联上级多个分类
此时我们再创建一个vue分类:
居然报错,看来我们之前的代码是将parent当作了必填项?找一下原因:
经过排查,是前端的原因,parent进入页面时被parentOptions: []定义成了数组,所以如果为空的话就是字符串格式。
所以我们需要在数据模型中提前让parent定义成数组格式:
保存再次测试:
没问题,下面正式开始多个上级分类关联,例如加一个分类名为vue.js+tp6全栈开发的题目,上级分类为vue.js和tp6。
只需要修改前端页面,在下拉框中加入一个属性multiple:
又因为我们上一步已经将parent改为数组格式,所以可以放心上传。
测试:
虽然成功了,但是列表页一个都没有显示,查找原因:
然后我试了一下午,都没有成功,摊牌了,我不会,大神教教我!
经过又半天的研究,我转变了思路,部分有些复杂,数据表字段也变了一些,给大家展示下,大家自行研究一段时间研究不出来可以参照一下:
下篇文章学习图片的上传。
Category模型:
<?php
namespace app\admin\model;use think\Model;class Category extends Model{// // 定义json数据protected $json = ['parent_'];// // 定义json数据查询时返回数组protected $jsonAssoc = true;// 设置字段信息protected $schema = ['id' => 'int','name' => 'string','parent0' => 'string','parent1' => 'string','parent2' => 'string','parent3' => 'string','parent4' => 'string','parent0_' => 'string','parent1_' => 'string','parent2_' => 'string','parent3_' => 'string','parent4_' => 'string','parent_' => 'string'];// 查找下级分类public function children(){return $this -> hasMany(Category::class, 'parent', 'id');}// 查找上级分类public function parent0(){return $this -> belongsTo(Category::class, 'parent0', 'id');}public function parent1(){return $this -> belongsTo(Category::class, 'parent1', 'id');}public function parent2(){return $this -> belongsTo(Category::class, 'parent2', 'id');}public function parent3(){return $this -> belongsTo(Category::class, 'parent3', 'id');}public function parent4(){return $this -> belongsTo(Category::class, 'parent4', 'id');}
}
接口函数:
<?php
declare (strict_types = 1);namespace app\admin\controller;use app\admin\model\Admin;
use app\admin\model\Category;
use app\admin\model\News;class Index
{public function index(){return '您好!这是一个[index]示例应用';}public function add(){// 获取前端传值$data = request() -> param();if($data['model'] == "admin"){// 密码加密$data['password'] = password_hash($data['password'], PASSWORD_DEFAULT);// 使用模型格式化传来的数据$db_data = new Admin;// 利用模型将数据传到数据库$db_data->save(['username' => $data['username'],'password' => $data['password']]);// 返回结果return '新增数据成功';}else if($data['model'] == "category"){$db_data = new Category;// 利用模型将数据传到数据库$db_data -> name = $data['name'];$db_data -> parent_ = $data['parent_'];error_reporting(E_ERROR | E_WARNING | E_PARSE);if($data['parent_'][0]){$db_data -> parent0 = $data['parent_'][0];}else{$data['parent_'][0] = '0';$db_data -> parent0 = $data['parent_'][0];}if($data['parent_'][1]){$db_data -> parent1 = $data['parent_'][1];}else{$data['parent_'][1] = '0';$db_data -> parent1 = $data['parent_'][1];}if($data['parent_'][2]){$db_data -> parent2 = $data['parent_'][2];}else{$data['parent_'][2] = '0';$db_data -> parent2 = $data['parent_'][2];}if($data['parent_'][3]){$db_data -> parent3 = $data['parent_'][3];}else{$data['parent_'][3] = '0';$db_data -> parent3 = $data['parent_'][3];}if($data['parent_'][4]){$db_data -> parent4 = $data['parent_'][4];}else{$data['parent_'][4] = '0';$db_data -> parent4 = $data['parent_'][4];}$db_data -> save();// 返回结果return '新增数据成功';}}public function findall(){// 接收数据$data = request() -> param();// return $data;// 根据模型名判断if($data['model'] == "admin"){$db_data = Admin::select();// 返回查找到的数据return $db_data;}else if($data['model'] == "category"){$db_data = Category::with(['parent0','parent1','parent2','parent3','parent4'])->select()->toArray();for($i = 0; $i<sizeof($db_data); $i++){$db_data[$i]['parent'] = array();if(is_array($db_data[$i]['parent0'])){array_push($db_data[$i]['parent'], $db_data[$i]['parent0']);}if(is_array($db_data[$i]['parent1'])){array_push($db_data[$i]['parent'], $db_data[$i]['parent1']);}if(is_array($db_data[$i]['parent2'])){array_push($db_data[$i]['parent'], $db_data[$i]['parent2']);}if(is_array($db_data[$i]['parent3'])){array_push($db_data[$i]['parent'], $db_data[$i]['parent3']);}if(is_array($db_data[$i]['parent4'])){array_push($db_data[$i]['parent'], $db_data[$i]['parent4']);}}// $db_data['parent'] = explode($db_data[$i]['parent0'],$db_data[$i]['parent1'],$db_data[$i]['parent2'],$db_data[$i]['parent3'],$db_data[$i]['parent4']);return json($db_data);}}public function find(){// 获取前端传值$data = request() -> param();if($data['model'] == "admin"){$db_data = Admin::find($data['id']);// 返回查找到的数据return $db_data;}else if($data['model'] == "category"){$db_data = Category::with(['parent0','parent1','parent2','parent3','parent4'])->find($data['id'])->toArray();$db_data['parent'] = array();if(is_array($db_data['parent0'])){array_push($db_data['parent'], $db_data['parent0']);}if(is_array($db_data['parent1'])){array_push($db_data['parent'], $db_data['parent1']);}if(is_array($db_data['parent2'])){array_push($db_data['parent'], $db_data['parent2']);}if(is_array($db_data['parent3'])){array_push($db_data['parent'], $db_data['parent3']);}if(is_array($db_data['parent4'])){array_push($db_data['parent'], $db_data['parent4']);}// 返回查找到的数据return $db_data;}}public function update(){// 获取前端传值$data = request() -> param();// return $data;if($data['model'] == "admin"){// 密码加密$data['password'] = password_hash($data['password'], PASSWORD_DEFAULT);// 静态方法直接更新$db_data = Admin::update($data, ['id' => $data['id']]);return '修改数据成功';}else if($data['model'] == "category"){error_reporting(E_ERROR | E_WARNING | E_PARSE);$db_data = Category::where('id', $data['id'])->find();// 利用模型将数据传到数据库$db_data -> name = $data['name'];$db_data -> content = $data['content'];$db_data -> parent_ = $data['parent_'];if($data['parent_'][0]){$db_data -> parent0 = $data['parent_'][0];}else{$data['parent_'][0] = '0';$db_data -> parent0 = $data['parent_'][0];}if($data['parent_'][1]){$db_data -> parent1 = $data['parent_'][1];}else{$data['parent_'][1] = '0';$db_data -> parent1 = $data['parent_'][1];}if($data['parent_'][2]){$db_data -> parent2 = $data['parent_'][2];}else{$data['parent_'][2] = '0';$db_data -> parent2 = $data['parent_'][2];}if($data['parent_'][3]){$db_data -> parent3 = $data['parent_'][3];}else{$data['parent_'][3] = '0';$db_data -> parent3 = $data['parent_'][3];}if($data['parent_'][4]){$db_data -> parent4 = $data['parent_'][4];}else{$data['parent_'][4] = '0';$db_data -> parent4 = $data['parent_'][4];}// 静态方法直接更新$db_data -> save();return '修改数据成功';}}public function delete(){// 获取前端传值$data = request() -> param();if($data['model'] == "admin"){$db_data = Admin::find($data['id']);$db_data->delete();return '删除数据成功';}else if($data['model'] == "category"){$db_data = Category::find($data['id']);$db_data->delete();return '删除数据成功';}}
}
CategorySet.vue:
<template><div><h1>{{ id ? "编辑" : "创建" }}分类</h1><el-formlabel-width="80px"style="margin-top: 20px"@submit.native.prevent="save"><el-form-item label="上级分类"><el-select v-model="model.parent_" multiple><!-- 使用select获取分类名name和该分类的id,后期如果修改分类名自动更新子分类的上级分类 --><!-- 其中label获取分类名,发送到数据库的值为该分类的id————以id为分类寻找依据 --><el-optionv-for="item in parentOptions":key="item.id":label="item.name":value="item.id"></el-option></el-select></el-form-item><el-form-item label="分类名"><el-input v-model="model.name"></el-input></el-form-item><el-form-item><el-button type="primary" native-type="submit">保存</el-button></el-form-item></el-form></div>
</template>
<script>
export default {props: {id: {},},data() {return {model: {parent_: []},parentOptions: [],};},methods: {async save() {let res;if (this.id) {res = await this.$http.put("rest/category/" + this.id, this.model);} else {res = await this.$http.post("rest/category", this.model);}console.log("en?", res);this.$router.push("/categories/list");this.$message({type: "success",message: "保存成功",});},async fetch() {const res = await this.$http.get("rest/category/" + this.id);this.model = res.data;},async fetchParentOptions() {const res = await this.$http.get("rest/category");this.parentOptions = res.data;},},created() {this.id && this.fetch();this.fetchParentOptions();},
};
</script>
CategoryList.vue:
<template><div><h1>分类列表</h1><el-table :data="items"><el-table-column prop="id" label="ID" width="220"></el-table-column><el-table-column prop="parent[0].name,parent[1].name,parent[2].name,parent[3].name,parent[4].name" label="上级分类" width="220"><template slot-scope="scope"> {{scope.row.parent[0].name}} {{scope.row.parent[1].name}} {{scope.row.parent[2].name}} {{scope.row.parent[3].name}} {{scope.row.parent[4].name}} </template></el-table-column><el-table-column prop="name" label="分类名称"></el-table-column><el-table-columnfixed="right"label="操作"width="100"><template slot-scope="scope"><el-button type="text" size="small" @click="$router.push('/categories/edit/' + scope.row.id)">编辑</el-button><el-button @click="remove(scope.row)" type="text" size="small">删除</el-button></template></el-table-column></el-table></div>
</template>
<script>
export default {data() {return {items: []}},methods: {async fetch(){const res = await this.$http.get('rest/category')this.items = res.data},remove(row){this.$confirm('是否确定要删除分类"' + row.name + '"?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(async () => {// 要想使用await,函数必须使用async// await异步执行,待调用接口获取数据完成后再将值传给res,进行下一步操作const res = await this.$http.delete('rest/category/' + row.id)this.$message({type: 'success',message: '删除成功!'});if(res.status == 200){// 接口调用成功后,刷新页面this.fetch()}}).catch(() => {this.$message({type: 'info',message: '已取消删除'}); });}},created() {this.fetch()}
}
</script>
结果页面:
更多设计、功能的学习经验,大家也可以去我的公众号查看!
————
技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-7.分类的模型关联和通用CRUD接口相关推荐
- 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-3.路由、模型与数据库操作
技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-3.路由.模型与数据库操作 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-1.工具和本地环境 ...
- 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-4.跨域且传输数据,并优化后端接口
技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-4.优化后端接口,前端使用axios实现接口功能 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站 ...
- 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-2.启动项目
技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-2.启动项目 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-1.工具和本地环境 技能学习:学习 ...
- 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-8.使用mavoneditor(vue的markdown编辑器),并批量上传图片
技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-8.使用mavoneditor(vue的markdown编辑器),并批量上传图片 技能学习:学习使用php(tp6框架) + ...
- 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-6.用户登录(二),token验证
技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-6.用户登录(二),token验证 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-1.工具和本 ...
- 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-5.用户登录,密码的bcrypt(hash)加密与验证
技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-5.用户登录,密码的bcrypt(hash)加密与验证 技能学习:学习使用php(tp6框架) + vue.js,开发前端全 ...
- 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-1.工具和本地环境
技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-1.工具和本地环境 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-1.工具和本地环境 技能学习 ...
- 两个读书笔记:springboot+vue.js分布式组件全栈开发训练营 + 大数据开发基础
(springboot+vue.js分布式组件全栈开发训练营原文在notion中, 大数据开发在思维导图中, 这个博客只是保存, 无法阅读. ) what is different between s ...
- mpvue 微信小程序_使用Vue.js开发微信小程序:开源框架mpvue解析
戳蓝字"CSDN云计算"关注我们哦! 作者 | 成全 责编 | 阿秃 转自 | 美团技术团队企业博客 前言 mpvue是一款使用Vue.js开发微信小程序的前端框架.使用此框架,开 ...
最新文章
- jQuery计数子元素
- python将数字转变为中文读法-Python实现把数字转换成中文
- FE.ES-JavaScript的模块化历史
- Deepin下配置JDK8
- IPSec的安全性如何?—微云MPLS
- java的知识点33——死锁及解决方案
- jmeter监控服务资源
- 电商网站(Django框架)—— 大纲内容与基本功能分析
- 2008年具有高校自主选拔录取资格的考生名单 - 江苏版
- php抽奖概率算法(刮刮卡,大转盘)
- 编写跨浏览器兼容的 CSS 代码的金科玉律
- assert.notDeepEqual()
- 经典扫雷游戏Web版
- 关于小凡模拟器设置完后找不到所要配置文件的问题
- 转载GIT 学习--活灵活现用Git(二)
- 企业python面试题
- Word2016怎么制作目录
- MySQL约束和表的复杂查询操作
- 2、java语言基础课程2
- Final Cut Pro资源库占用内存太大如何释放磁盘空间?
热门文章
- vue的method函数互引用_vue 在methods中调用mounted的实现操作
- methods中方法互相调用
- 查看linux操作系统的基本命令
- SQL基本表的 查找 练习篇
- 马云回应“乌镇饭局”:他们没请我;美拍禁止未成年人直播;传陆金所明年赴港IPO丨价值早报
- 达芬奇模板-梦幻棱镜光效折射视觉特效预设Prismatic Effects
- chrome Stalled时间过长
- 机械师F117毒药 评测怎么样
- c++11 shared_ptr 与 make_shared源码剖析
- Pico Neo 3 VR开发(Unity XR SDK)1