首页
课程
圈子
文章
交流群
文档
工具
vscode代码片段
字幕提取
图片切割
登录
首页
课程
圈子
文章
交流群
文档
工具
vscode代码片段
字幕提取
图片切割
fastadmin在前台会员中心里添加后台CRUD生成的表格
2024-10-10 19:56:56
1572
0
0
0
登录后可以对文章进行评论
文章目录
开通会员
解锁全部文章权限
立即开通
小程序码
扫一扫在小程序看此文章
热门文章
php基础入门课程资料文档课件实战源码
5902
vscode里如果出现中文空格标出黄色突出显示,怎么去掉?
5509
wordpress主题开发文档资料下载
5246
2025新版fastadmin新手小白入门课 免费文档
5075
vscode插件code runner详细配置说明
4069
php进阶课程文档资料下载
3952
使用ffmpeg将mp4格式转为m3u8
2730
phpstudy怎么手动安装php8.3.0版本?
2491
推荐2款mac电脑里非常好用的php集成开发环境
2401
把php加入系统环境变量
2252
视频教程:https://www.bilibili.com/video/BV1Ee41197RX/ 如图所示,在前台会员中心增加一个表格,功能和后台的一模一样,具有新增 修改 删除 批量删除 搜索 分页 等完整功能!  ## 实现逻辑: 一个字:“**复制**”! 先在后台一键crud生成表格,然后在前台对应位置复制粘贴对应的功能即可!当然有一些地方是要修改的,否则会报方法错误! ### 1.新建数据表fa_ceshi,然后一键crud 这个很简单,不做具体演示了。 下面的例子里,我们这里生成的是Ceshi,前台要增加的是Mstable。 ### 2.新建模型 Mstable.php 在index文件夹下,新建文件夹model,然后在model文件夹下新建Mstable.php文件,作为模型,复制上面生成的模型文件,注意修改namespace为 namespace app\index\model ,table表名为 mstable。 代码如下: ```php namespace app\index\model; use think\Model; class Mstable extends Model { // 表名 protected $name = 'mstable'; // 自动写入时间戳字段 protected $autoWriteTimestamp = 'integer'; // 定义时间戳字段名 protected $createTime = 'createtime'; protected $updateTime = 'updatetime'; protected $deleteTime = false; // 追加属性 protected $append = []; } ``` ### 3.新建控制器Mstable.php 在index->controller文件夹下新建Mstable.php文件,作为控制器,然后接下来是复制代码。 首先要复制一个会员中心的user控制器代码; 然后去`application/admin/library/traits/Backend.php`里面复制`index add edit del` 方法到当前控制器里,这里需要注意,一定要删除关于管理员验证的一些代码,具体我们在视频里有讲解; 然后我们需要在_initialize里加上model: `$this->model = new \app\index\model\Mstable;` 最后一定记得引入需要的东西 ```php use Exception; use think\Db; use think\exception\DbException; use think\exception\PDOException; use think\exception\ValidateException; use think\response\Json; ``` 最终的控制器代码如下: ```php namespace app\index\controller; use app\common\controller\Frontend; use Exception; use think\Db; use think\exception\DbException; use think\exception\PDOException; use think\exception\ValidateException; use think\response\Json; class Mstable extends Frontend { protected $layout = 'default'; protected $noNeedLogin = []; protected $noNeedRight = ['*']; protected $model = null; public function _initialize() { parent::_initialize(); // $auth = $this->auth; $this->model = new \app\index\model\Mstable; } /** * 查看 * * @return string|Json * @throws \think\Exception * @throws DbException */ public function index() { //设置过滤方法 $this->request->filter(['strip_tags', 'trim']); if (false === $this->request->isAjax()) { $this->view->assign('title', "表格"); return $this->view->fetch(); } //如果发送的来源是 Selectpage,则转发到 Selectpage if ($this->request->request('keyField')) { return $this->selectpage(); } [$where, $sort, $order, $offset, $limit] = $this->buildparams(); $list = $this->model ->where($where) ->order($sort, $order) ->paginate($limit); $result = ['total' => $list->total(), 'rows' => $list->items()]; return json($result); } /** * 前台提交过来,需要排除的字段数据 */ protected $excludeFields = ""; /** * 是否开启Validate验证 */ protected $modelValidate = false; /** * 排除前台提交过来的字段 * @param $params * @return array */ protected function preExcludeFields($params) { if (is_array($this->excludeFields)) { foreach ($this->excludeFields as $field) { if (array_key_exists($field, $params)) { unset($params[$field]); } } } else if (array_key_exists($this->excludeFields, $params)) { unset($params[$this->excludeFields]); } return $params; } /** * 添加 * * @return string * @throws \think\Exception */ public function add() { if (false === $this->request->isPost()) { return $this->view->fetch(); } $params = $this->request->post('row/a'); if (empty($params)) { $this->error(__('Parameter %s can not be empty', '')); } $params = $this->preExcludeFields($params); if ($this->dataLimit && $this->dataLimitFieldAutoFill) { $params[$this->dataLimitField] = $this->auth->id; } $result = false; Db::startTrans(); try { //是否采用模型验证 if ($this->modelValidate) { $name = str_replace("\\model\\", "\\validate\\", get_class($this->model)); $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.add' : $name) : $this->modelValidate; $this->model->validateFailException()->validate($validate); } $result = $this->model->allowField(true)->save($params); Db::commit(); } catch (ValidateException|PDOException|Exception $e) { Db::rollback(); $this->error($e->getMessage()); } if ($result === false) { $this->error(__('No rows were inserted')); } $this->success(); } /** * 编辑 * * @param $ids * @return string * @throws DbException * @throws \think\Exception */ public function edit($ids = null) { $row = $this->model->get($ids); if (!$row) { $this->error(__('No Results were found')); } if (false === $this->request->isPost()) { $this->view->assign('row', $row); return $this->view->fetch(); } $params = $this->request->post('row/a'); if (empty($params)) { $this->error(__('Parameter %s can not be empty', '')); } $params = $this->preExcludeFields($params); $result = false; Db::startTrans(); try { //是否采用模型验证 if ($this->modelValidate) { $name = str_replace("\\model\\", "\\validate\\", get_class($this->model)); $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.edit' : $name) : $this->modelValidate; $row->validateFailException()->validate($validate); } $result = $row->allowField(true)->save($params); Db::commit(); } catch (ValidateException|PDOException|Exception $e) { Db::rollback(); $this->error($e->getMessage()); } if (false === $result) { $this->error(__('No rows were updated')); } $this->success(); } /** * 删除 * * @param $ids * @return void * @throws DbException * @throws DataNotFoundException * @throws ModelNotFoundException */ public function del($ids = null) { if (false === $this->request->isPost()) { $this->error(__("Invalid parameters")); } $ids = $ids ?: $this->request->post("ids"); if (empty($ids)) { $this->error(__('Parameter %s can not be empty', 'ids')); } $pk = $this->model->getPk(); $list = $this->model->where($pk, 'in', $ids)->select(); $count = 0; Db::startTrans(); try { foreach ($list as $item) { $count += $item->delete(); } Db::commit(); } catch (PDOException|Exception $e) { Db::rollback(); $this->error($e->getMessage()); } if ($count) { $this->success(); } $this->error(__('No rows were deleted')); } } ``` ### 4.新建视图(html代码) 在index的view文件夹下新建文件夹mstable,然后把后台ceshi里的index.html add.html和edit.html文件复制进来,index.html里删除关于auth验证的代码。  其他两个文件无需修改,index.html改完的代码如下: ```html
{include file="common/sidenav" /}
测试表格
{:__('Add')}
{:__('Edit')}
{:__('Delete')}
``` ### 5.新建js文件 在文件夹public/assets/js/frontend下新建mstable.js文件,把后台生成的ceshi.js复制进来,把里面的ceshi改为mstable即可 ### 6.修改左侧菜单栏 在会员中心左侧的菜单栏内加入当前的菜单,application/index/view/common/sidenav.html,加入如下代码: ```html
测试表格
```  ### 7.修改Frontend文件 `application/common/controller/Frontend.php` 这里面要改的东西比较多,我们在视频内详细说明,下面是改完后的代码: ```php request->filter('trim,strip_tags,htmlspecialchars'); $modulename = $this->request->module(); $controllername = Loader::parseName($this->request->controller()); $actionname = strtolower($this->request->action()); // 检测IP是否允许 check_ip_allowed(); // 定义是否Dialog请求 !defined('IS_DIALOG') && define('IS_DIALOG', input("dialog") ? true : false); // 如果有使用模板布局 if ($this->layout) { $this->view->engine->layout('layout/' . $this->layout); } $this->auth = Auth::instance(); // token $token = $this->request->server('HTTP_TOKEN', $this->request->request('token', \think\Cookie::get('token'))); $path = str_replace('.', '/', $controllername) . '/' . $actionname; // 设置当前请求的URI $this->auth->setRequestUri($path); // 检测是否需要验证登录 if (!$this->auth->match($this->noNeedLogin)) { //初始化 $this->auth->init($token); //检测是否登录 if (!$this->auth->isLogin()) { $this->error(__('Please login first'), 'index/user/login'); } // 判断是否需要验证权限 if (!$this->auth->match($this->noNeedRight)) { // 判断控制器和方法判断是否有对应权限 if (!$this->auth->check($path)) { $this->error(__('You have no permission')); } } } else { // 如果有传递token才验证是否登录状态 if ($token) { $this->auth->init($token); } } $this->view->assign('user', $this->auth->getUser()); // 语言检测 $lang = $this->request->langset(); $lang = preg_match("/^([a-zA-Z\-_]{2,10})\$/i", $lang) ? $lang : 'zh-cn'; $site = Config::get("site"); $upload = \app\common\model\Config::upload(); // 上传信息配置后 Hook::listen("upload_config_init", $upload); // 配置信息 $config = [ 'site' => array_intersect_key($site, array_flip(['name', 'cdnurl', 'version', 'timezone', 'languages'])), 'upload' => $upload, 'modulename' => $modulename, 'controllername' => $controllername, 'actionname' => $actionname, 'jsname' => 'frontend/' . str_replace('.', '/', $controllername), 'moduleurl' => rtrim(url("/{$modulename}", '', false), '/'), 'language' => $lang ]; $config = array_merge($config, Config::get("view_replace_str")); Config::set('upload', array_merge(Config::get('upload'), $upload)); // 配置信息后 Hook::listen("config_init", $config); // 加载当前控制器语言包 $this->loadlang($controllername); $this->assign('site', $site); $this->assign('config', $config); } /** * 加载语言文件 * @param string $name */ protected function loadlang($name) { $name = Loader::parseName($name); $name = preg_match("/^([a-zA-Z0-9_\.\/]+)\$/i", $name) ? $name : 'index'; $lang = $this->request->langset(); $lang = preg_match("/^([a-zA-Z\-_]{2,10})\$/i", $lang) ? $lang : 'zh-cn'; Lang::load(APP_PATH . $this->request->module() . '/lang/' . $lang . '/' . str_replace('.', '/', $name) . '.php'); } /** * 渲染配置信息 * @param mixed $name 键名或数组 * @param mixed $value 值 */ protected function assignconfig($name, $value = '') { $this->view->config = array_merge($this->view->config ? $this->view->config : [], is_array($name) ? $name : [$name => $value]); } /** * 快速搜索时执行查找的字段 */ protected $searchFields = 'id'; /** * 是否是关联查询 */ protected $relationSearch = false; /** * 是否开启数据限制 * 支持auth/personal * 表示按权限判断/仅限个人 * 默认为禁用,若启用请务必保证表中存在admin_id字段 */ protected $dataLimit = false; /** * 数据限制字段 */ protected $dataLimitField = 'admin_id'; /** * 数据限制开启时自动填充限制字段值 */ protected $dataLimitFieldAutoFill = true; /** * Selectpage的实现方法 * * 当前方法只是一个比较通用的搜索匹配,请按需重载此方法来编写自己的搜索逻辑,$where按自己的需求写即可 * 这里示例了所有的参数,所以比较复杂,实现上自己实现只需简单的几行即可 * */ protected function selectpage() { //设置过滤方法 $this->request->filter(['trim', 'strip_tags', 'htmlspecialchars']); //搜索关键词,客户端输入以空格分开,这里接收为数组 $word = (array)$this->request->request("q_word/a"); //当前页 $page = $this->request->request("pageNumber"); //分页大小 $pagesize = $this->request->request("pageSize"); //搜索条件 $andor = $this->request->request("andOr", "and", "strtoupper"); //排序方式 $orderby = (array)$this->request->request("orderBy/a"); //显示的字段 $field = $this->request->request("showField"); //主键 $primarykey = $this->request->request("keyField"); //主键值 $primaryvalue = $this->request->request("keyValue"); //搜索字段 $searchfield = (array)$this->request->request("searchField/a"); //自定义搜索条件 $custom = (array)$this->request->request("custom/a"); //是否返回树形结构 $istree = $this->request->request("isTree", 0); $ishtml = $this->request->request("isHtml", 0); if ($istree) { $word = []; $pagesize = 999999; } $order = []; foreach ($orderby as $k => $v) { $order[$v[0]] = $v[1]; } $field = $field ? $field : 'name'; //如果有primaryvalue,说明当前是初始化传值 if ($primaryvalue !== null) { $where = [$primarykey => ['in', $primaryvalue]]; $pagesize = 999999; } else { $where = function ($query) use ($word, $andor, $field, $searchfield, $custom) { $logic = $andor == 'AND' ? '&' : '|'; $searchfield = is_array($searchfield) ? implode($logic, $searchfield) : $searchfield; $searchfield = str_replace(',', $logic, $searchfield); $word = array_filter(array_unique($word)); if (count($word) == 1) { $query->where($searchfield, "like", "%" . reset($word) . "%"); } else { $query->where(function ($query) use ($word, $searchfield) { foreach ($word as $index => $item) { $query->whereOr(function ($query) use ($item, $searchfield) { $query->where($searchfield, "like", "%{$item}%"); }); } }); } if ($custom && is_array($custom)) { foreach ($custom as $k => $v) { if (is_array($v) && 2 == count($v)) { $query->where($k, trim($v[0]), $v[1]); } else { $query->where($k, '=', $v); } } } }; } $list = []; $total = $this->model->where($where)->count(); if ($total > 0) { $fields = is_array($this->selectpageFields) ? $this->selectpageFields : ($this->selectpageFields && $this->selectpageFields != '*' ? explode(',', $this->selectpageFields) : []); //如果有primaryvalue,说明当前是初始化传值,按照选择顺序排序 if ($primaryvalue !== null && preg_match("/^[a-z0-9_\-]+$/i", $primarykey)) { $primaryvalue = array_unique(is_array($primaryvalue) ? $primaryvalue : explode(',', $primaryvalue)); //修复自定义data-primary-key为字符串内容时,给排序字段添加上引号 $primaryvalue = array_map(function ($value) { return '\'' . $value . '\''; }, $primaryvalue); $primaryvalue = implode(',', $primaryvalue); $this->model->orderRaw("FIELD(`{$primarykey}`, {$primaryvalue})"); } else { $this->model->order($order); } $datalist = $this->model->where($where) ->page($page, $pagesize) ->select(); foreach ($datalist as $index => $item) { unset($item['password'], $item['salt']); if ($this->selectpageFields == '*') { $result = [ $primarykey => $item[$primarykey] ?? '', $field => $item[$field] ?? '', ]; } else { $result = array_intersect_key(($item instanceof Model ? $item->toArray() : (array)$item), array_flip($fields)); } $result['pid'] = isset($item['pid']) ? $item['pid'] : (isset($item['parent_id']) ? $item['parent_id'] : 0); $list[] = $result; } if ($istree && !$primaryvalue) { $tree = Tree::instance(); $tree->init(collection($list)->toArray(), 'pid'); $list = $tree->getTreeList($tree->getTreeArray(0), $field); if (!$ishtml) { foreach ($list as &$item) { $item = str_replace(' ', ' ', $item); } unset($item); } } } //这里一定要返回有list这个字段,total是可选的,如果total<=list的数量,则会隐藏分页按钮 return json(['list' => $list, 'total' => $total]); } /** * 生成查询所需要的条件,排序方式 * @param mixed $searchfields 快速查询的字段 * @param boolean $relationSearch 是否关联查询 * @return array */ protected function buildparams($searchfields = null, $relationSearch = null) { $searchfields = is_null($searchfields) ? $this->searchFields : $searchfields; $relationSearch = is_null($relationSearch) ? $this->relationSearch : $relationSearch; $search = $this->request->get("search", ''); $filter = $this->request->get("filter", ''); $op = $this->request->get("op", '', 'trim'); $sort = $this->request->get("sort", !empty($this->model) && $this->model->getPk() ? $this->model->getPk() : 'id'); $order = $this->request->get("order", "DESC"); $offset = $this->request->get("offset/d", 0); $limit = $this->request->get("limit/d", 999999); //新增自动计算页码 $page = $limit ? intval($offset / $limit) + 1 : 1; if ($this->request->has("page")) { $page = $this->request->get("page/d", 1); } $this->request->get([config('paginate.var_page') => $page]); $filter = (array)json_decode($filter, true); $op = (array)json_decode($op, true); $filter = $filter ? $filter : []; $where = []; $alias = []; $bind = []; $name = ''; $aliasName = ''; if (!empty($this->model) && $relationSearch) { $name = $this->model->getTable(); $alias[$name] = Loader::parseName(basename(str_replace('\\', '/', get_class($this->model)))); $aliasName = $alias[$name] . '.'; } $sortArr = explode(',', $sort); foreach ($sortArr as $index => & $item) { $item = stripos($item, ".") === false ? $aliasName . trim($item) : $item; } unset($item); $sort = implode(',', $sortArr); if ($search) { $searcharr = is_array($searchfields) ? $searchfields : explode(',', $searchfields); foreach ($searcharr as $k => &$v) { $v = stripos($v, ".") === false ? $aliasName . $v : $v; } unset($v); $where[] = [implode("|", $searcharr), "LIKE", "%{$search}%"]; } $index = 0; foreach ($filter as $k => $v) { if (!preg_match('/^[a-zA-Z0-9_\-\.]+$/', $k)) { continue; } $sym = $op[$k] ?? '='; if (stripos($k, ".") === false) { $k = $aliasName . $k; } $v = !is_array($v) ? trim($v) : $v; $sym = strtoupper($op[$k] ?? $sym); //null和空字符串特殊处理 if (!is_array($v)) { if (in_array(strtoupper($v), ['NULL', 'NOT NULL'])) { $sym = strtoupper($v); } if (in_array($v, ['""', "''"])) { $v = ''; $sym = '='; } } switch ($sym) { case '=': case '<>': $where[] = [$k, $sym, (string)$v]; break; case 'LIKE': case 'NOT LIKE': case 'LIKE %...%': case 'NOT LIKE %...%': $where[] = [$k, trim(str_replace('%...%', '', $sym)), "%{$v}%"]; break; case '>': case '>=': case '<': case '<=': $where[] = [$k, $sym, intval($v)]; break; case 'FINDIN': case 'FINDINSET': case 'FIND_IN_SET': $v = is_array($v) ? $v : explode(',', str_replace(' ', ',', $v)); $findArr = array_values($v); foreach ($findArr as $idx => $item) { $bindName = "item_" . $index . "_" . $idx; $bind[$bindName] = $item; $where[] = "FIND_IN_SET(:{$bindName}, `" . str_replace('.', '`.`', $k) . "`)"; } break; case 'IN': case 'IN(...)': case 'NOT IN': case 'NOT IN(...)': $where[] = [$k, str_replace('(...)', '', $sym), is_array($v) ? $v : explode(',', $v)]; break; case 'BETWEEN': case 'NOT BETWEEN': $arr = array_slice(explode(',', $v), 0, 2); if (stripos($v, ',') === false || !array_filter($arr, function ($v) { return $v != '' && $v !== false && $v !== null; })) { continue 2; } //当出现一边为空时改变操作符 if ($arr[0] === '') { $sym = $sym == 'BETWEEN' ? '<=' : '>'; $arr = $arr[1]; } elseif ($arr[1] === '') { $sym = $sym == 'BETWEEN' ? '>=' : '<'; $arr = $arr[0]; } $where[] = [$k, $sym, $arr]; break; case 'RANGE': case 'NOT RANGE': $v = str_replace(' - ', ',', $v); $arr = array_slice(explode(',', $v), 0, 2); if (stripos($v, ',') === false || !array_filter($arr)) { continue 2; } //当出现一边为空时改变操作符 if ($arr[0] === '') { $sym = $sym == 'RANGE' ? '<=' : '>'; $arr = $arr[1]; } elseif ($arr[1] === '') { $sym = $sym == 'RANGE' ? '>=' : '<'; $arr = $arr[0]; } $tableArr = explode('.', $k); if (count($tableArr) > 1 && $tableArr[0] != $name && !in_array($tableArr[0], $alias) && !empty($this->model) && $this->relationSearch) { //修复关联模型下时间无法搜索的BUG $relation = Loader::parseName($tableArr[0], 1, false); $alias[$this->model->$relation()->getTable()] = $tableArr[0]; } $where[] = [$k, str_replace('RANGE', 'BETWEEN', $sym) . ' TIME', $arr]; break; case 'NULL': case 'IS NULL': case 'NOT NULL': case 'IS NOT NULL': $where[] = [$k, strtolower(str_replace('IS ', '', $sym))]; break; default: break; } $index++; } if (!empty($this->model)) { $this->model->alias($alias); } $model = $this->model; $where = function ($query) use ($where, $alias, $bind, &$model) { if (!empty($model)) { $model->alias($alias); $model->bind($bind); } foreach ($where as $k => $v) { if (is_array($v)) { call_user_func_array([$query, 'where'], $v); } else { $query->where($v); } } }; return [$where, $sort, $order, $offset, $limit, $page, $alias, $bind]; } /** * 刷新Token */ protected function token() { $token = $this->request->param('__token__'); //验证Token if (!Validate::make()->check(['__token__' => $token], ['__token__' => 'require|token'])) { $this->error(__('Token verification error'), '', ['__token__' => $this->request->token()]); } //刷新Token $this->request->token(); } } ``` ### 8.去除添加和修改里面的多余页头页尾 修改文件:application/index/view/layout/default.html 在需要去除的地方加上判断 {if !IS_DIALOG},如下图所示,主要是在头部和尾部加判断  其中的IS_DIALOG是因为我们在基类里加了常量,如果不加就会报错 ```php // 定义是否Dialog请求 !defined('IS_DIALOG') && define('IS_DIALOG', input("dialog") ? true : false); ``` 好了,现在所有的功能就完成了,快去试试吧,文字能力有限,有不明白的地方看视频讲解。
0
0
铜牌 · 会员
解锁全部文章
全部课程8折购买
如果在b站充值了专属会员,可联系猫叔直接开通相同时间的此会员
¥
50
/年
立即购买
金牌 · 会员
解锁全部文章
全部课程5折购买
微信一对一答疑
优先解决问题
¥
1999
/年
立即购买