技能学习:学习使用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}}&nbsp;&nbsp;{{scope.row.parent[1].name}}&nbsp;&nbsp;{{scope.row.parent[2].name}}&nbsp;&nbsp;{{scope.row.parent[3].name}}&nbsp;&nbsp;{{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接口相关推荐

  1. 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-3.路由、模型与数据库操作

    技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-3.路由.模型与数据库操作 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-1.工具和本地环境 ...

  2. 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-4.跨域且传输数据,并优化后端接口

    技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-4.优化后端接口,前端使用axios实现接口功能 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站 ...

  3. 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-2.启动项目

    技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-2.启动项目 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-1.工具和本地环境 技能学习:学习 ...

  4. 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-8.使用mavoneditor(vue的markdown编辑器),并批量上传图片

    技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-8.使用mavoneditor(vue的markdown编辑器),并批量上传图片 技能学习:学习使用php(tp6框架) + ...

  5. 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-6.用户登录(二),token验证

    技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-6.用户登录(二),token验证 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-1.工具和本 ...

  6. 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-5.用户登录,密码的bcrypt(hash)加密与验证

    技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-5.用户登录,密码的bcrypt(hash)加密与验证 技能学习:学习使用php(tp6框架) + vue.js,开发前端全 ...

  7. 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-1.工具和本地环境

    技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-1.工具和本地环境 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-1.工具和本地环境 技能学习 ...

  8. 两个读书笔记:springboot+vue.js分布式组件全栈开发训练营 + 大数据开发基础

    (springboot+vue.js分布式组件全栈开发训练营原文在notion中, 大数据开发在思维导图中, 这个博客只是保存, 无法阅读. ) what is different between s ...

  9. mpvue 微信小程序_使用Vue.js开发微信小程序:开源框架mpvue解析

    戳蓝字"CSDN云计算"关注我们哦! 作者 | 成全 责编 | 阿秃 转自 | 美团技术团队企业博客 前言 mpvue是一款使用Vue.js开发微信小程序的前端框架.使用此框架,开 ...

最新文章

  1. jQuery计数子元素
  2. python将数字转变为中文读法-Python实现把数字转换成中文
  3. FE.ES-JavaScript的模块化历史
  4. Deepin下配置JDK8
  5. IPSec的安全性如何?—微云MPLS
  6. java的知识点33——死锁及解决方案
  7. jmeter监控服务资源
  8. 电商网站(Django框架)—— 大纲内容与基本功能分析
  9. 2008年具有高校自主选拔录取资格的考生名单 - 江苏版
  10. php抽奖概率算法(刮刮卡,大转盘)
  11. 编写跨浏览器兼容的 CSS 代码的金科玉律
  12. assert.notDeepEqual()
  13. 经典扫雷游戏Web版
  14. 关于小凡模拟器设置完后找不到所要配置文件的问题
  15. 转载GIT 学习--活灵活现用Git(二)
  16. 企业python面试题
  17. Word2016怎么制作目录
  18. MySQL约束和表的复杂查询操作
  19. 2、java语言基础课程2
  20. Final Cut Pro资源库占用内存太大如何释放磁盘空间?

热门文章

  1. vue的method函数互引用_vue 在methods中调用mounted的实现操作
  2. methods中方法互相调用
  3. 查看linux操作系统的基本命令
  4. SQL基本表的 查找 练习篇
  5. 马云回应“乌镇饭局”:他们没请我;美拍禁止未成年人直播;传陆金所明年赴港IPO丨价值早报
  6. 达芬奇模板-梦幻棱镜光效折射视觉特效预设Prismatic Effects
  7. chrome Stalled时间过长
  8. 机械师F117毒药 评测怎么样
  9. c++11 shared_ptr 与 make_shared源码剖析
  10. Pico Neo 3 VR开发(Unity XR SDK)1