fastadmin 实现标签的多选研究---基于fa的test案例,已经CMS中的标签写法

官方文档

动态下拉组件
https://doc.fastadmin.net/doc/178.html

首先生成控制器和菜单看下fa_test的多选效果

多选效果如下



使用多选的两种方式(chekbox是最简单的,那中多选就不算了)

1.input里使用多选(官网中,以分类id的多选为例,因为ui的逼格比较高,所以我使用这个。)
view

<div class="form-group">
        <label class="control-label col-xs-12 col-sm-2">{:__('Category_ids')}:</label>
        <div class="col-xs-12 col-sm-8">
            <input id="c-category_ids" data-rule="required" data-source="category/selectpage" data-params='{"custom[type]":"test"}' data-multiple="true" class="form-control selectpage" name="row[category_ids]" type="text" value="">
        </div>
    </div>

2.select里使用多选(官网中,以状态的多选为例子)
view

  <div class="form-group">
        <label class="control-label col-xs-12 col-sm-2">{:__('Flag')}:</label>
        <div class="col-xs-12 col-sm-8">
                        
            <select  id="c-flag" data-rule="required" class="form-control selectpicker" multiple="" name="row[flag][]">
                {foreach name="flagList" item="vo"}
                    <option value="{$key}" {in name="key" value=""}selected{/in}>{$vo}</option>
                {/foreach}
            </select>

        </div>
    </div>

具体的方式,大家,看相关的test控制器和js,以及模型

控制器中直接引入一个方法

  /**
     * Selectpage搜索
     *
     * @internal
     */
    public function selectpage()
    {
        return parent::selectpage();
    }
}

如何,让多选项是树状效果呢?

注释掉父类的方法,重写自己的方法,最后不需要重写
直接在input里增加一个参数

1.data-params='{"isTree":1}'
同时,可以使用
2.data-params='{"custom[type]":"test"}',来限制返回的字段
   /**
     * Selectpage搜索
     *
     * @internal
     */
    public function selectpage()
    {
        // return parent::selectpage();
        // 注释掉继承的,下面是重写的

         //  获取标签列表,渲染成右侧的树形,记得引入use fast/tree 这个命名空间
        $wenzhang_tags_right=collection(db::name("cms_exams_tags")->select())->toArray();
        $tree = Tree::instance();
        $tree->init($wenzhang_tags_right, 'parent');
        $this->tagsListRight = $tree->getTreeList($tree->getTreeArray(0), 'text');
        
         //对请求进行判断,并返回json数据,
        if ($this->request->isAjax()) {
           
            //构造父类select列表选项数据
           
            $list = $this->tagsListRight;
          
            $list = array_values($list);
          
        //   下面这个,是设置pid的,不设置,就会成undefine,前端的展开隐藏,靠这个pid
            foreach ($list as $k => &$v) {
                $v['pid'] = $v['parent'];
             
            }
            $total = count($list);
            $result = array("total" => $total, "rows" => $list);

            return json($result);
        }
        
    }
    

接下来,就是多个tag如何存储的问题,以及如何读取的问题了

1.存储,要操作tag表
参考官方的tags.php控制器
并研究官方的selectpage函数代码

protected function selectpage()
    {
        //设置过滤方法
        $this->request->filter(['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 = 99999;
        }
        $order = [];
        foreach ($orderby as $k => $v) {
            $order[$v[0]] = $v[1];
        }
        $field = $field ? $field : 'name';

        //如果有primaryvalue,说明当前是初始化传值
        if ($primaryvalue !== null) {
            $where = [$primarykey => ['in', $primaryvalue]];
            $pagesize = 99999;
        } else {
            $where = function ($query) use ($word, $andor, $field, $searchfield, $custom) {
                $logic = $andor == 'AND' ? '&' : '|';
                $searchfield = is_array($searchfield) ? implode($logic, $searchfield) : $searchfield;
                foreach ($word as $k => $v) {
                    $query->where(str_replace(',', $logic, $searchfield), "like", "%{$v}%");
                }
                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);
                        }
                    }
                }
            };
        }
        $adminIds = $this->getDataLimitAdminIds();
        if (is_array($adminIds)) {
            $this->model->where($this->dataLimitField, 'in', $adminIds);
        }
        $list = [];
        $total = $this->model->where($where)->count();
        if ($total > 0) {
            if (is_array($adminIds)) {
                $this->model->where($this->dataLimitField, 'in', $adminIds);
            }
            $datalist = $this->model->where($where)
                ->order($order)
                ->page($page, $pagesize)
                ->field($this->selectpageFields)
                ->select();
            foreach ($datalist as $index => $item) {
                unset($item['password'], $item['salt']);
                $list[] = [
                    $primarykey => isset($item[$primarykey]) ? $item[$primarykey] : '',
                    $field      => isset($item[$field]) ? $item[$field] : '',
                    'pid'       => isset($item['pid']) ? $item['pid'] : 0
                ];
            }
            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('&nbsp;', ' ', $item);
                    }
                    unset($item);
                }
            }
        }
        //这里一定要返回有list这个字段,total是可选的,如果total<=list的数量,则会隐藏分页按钮
        return json(['list' => $list, 'total' => $total]);
    }

archives模型init中的更新tags的代码

  self::afterWrite(function ($row) use ($config) {
            if (isset($row['channel_id'])) {
                //在更新成功后刷新副表、TAGS表数据、栏目表
                $channel = Channel::get($row->channel_id);
                if ($channel) {
                    $model = Modelx::get($channel['model_id']);
                    if ($model && isset($row['content'])) {
                        $values = array_intersect_key($row->getData(), array_flip($model->fields));
                        $values['id'] = $row['id'];
                        $values['content'] = $row['content'];
                        db($model['table'])->insert($values, true);
                    }
                }
            }
            if (isset($row['tags'])) {
                $tags = array_filter(explode(',', $row['tags']));
                if ($tags) {
                    $tagslist = Tags::where('name', 'in', $tags)->select();
                    foreach ($tagslist as $k => $v) {
                        $archives = explode(',', $v['archives']);
                        if (!in_array($row['id'], $archives)) {
                            $archives[] = $row['id'];
                            $v->archives = implode(',', $archives);
                            $v->nums++;
                            $v->save();
                        }
                        $tags = array_udiff($tags, [$v['name']], 'strcasecmp');
                    }
                    $list = [];
                    foreach ($tags as $k => $v) {
                        $list[] = ['name' => $v, 'archives' => $row['id'], 'nums' => 1];
                    }
                    if ($list) {
                        (new Tags())->saveAll($list);
                    }
                }
            }
            $changedData = $row->getChangedData();
            if (isset($changedData['status']) && $changedData['status'] == 'normal') {
                //增加积分
                User::score($config['score']['postarchives'], $row['user_id'], '发布文章');
                //推送到熊掌号和百度站长
                if ($config['baidupush']) {
                    $urls = [$row->fullurl];
                    \think\Hook::listen("baidupush", $urls);
                }
            }
            if ($config['searchtype'] == 'xunsearch') {
                //更新全文搜索
                FulltextSearch::update($row->id);
            }
        });

这里我抄袭tags表的更新方法,修改自己的examstags表的tag数据

 // 新增tag分组,不能新增,只能选择,所以,不需要对比,直接插入新的tags
            
              if (isset($row['tags_ids'])) {
                $mytags = array_filter(explode(',', $row['tags_ids']));
                if ($mytags) {
                    // 获取数据表里的tags数据
                    $mytagslist = Examstags::where('id', 'in', $mytags)->select();
                    foreach ($mytagslist as $k => $v) {
                        $archives = explode(',', $v['archive_id']);
                    // 如果当前的id,不在数据表的archives,那么就新增一下
                        if (!in_array($row['id'], $archives)) {
                            $archives[] = $row['id'];
                            $v->archive_id = implode(',', $archives);
                            // 忘记设置nums了,这里也去掉
                            // $v->nums++;
                            $v->save();
                        }
                    // 再看看,有没有新增标签,因为我们展示不支持新增,所以,暂时不用这个
                    //   $tags = array_udiff($tags, [$v['name']], 'strcasecmp');
                    }
                    // $list = [];
                    // foreach ($tags as $k => $v) {
                    //     $list[] = ['name' => $v, 'archives' => $row['id'], 'nums' => 1];
                    // }
                    // if ($list) {
                    //     (new Tags())->saveAll($list);
                    // }
                }
            }

2.读取,也要操作tag表,并且,view视图里,如何写,也是个问题

//在新增页面,新增树状结构的tag下拉选项
 <div class="form-group">
                                <label class="control-label col-xs-12 col-sm-3">{:__('标签(多选)')}:</label>
                                <div class="col-xs-12 col-sm-8">
//默认的字段为name,可以显示出中文,如果字段不是name,那么使用data-field="xxx",来显示tag的中文
                                    <input id="c-tags_ids" data-rule="required" data-source="cms/examstags/selectpage" data-field="text"  data-multiple="true" class="form-control selectpage" name="row[tags_ids]" type="text" value="">
                                </div>
                            </div>

 //在编辑页面获取当前的,多选的tag
 <div class="form-group">
        <label class="control-label col-xs-12 col-sm-2">{:__('tags_ids')}:</label>
        <div class="col-xs-12 col-sm-8">
//默认的字段为name,可以显示出中文,如果字段不是name,那么使用data-field="xxx",来显示tag的中文
            <input id="c-tags_ids" data-rule="required" data-source="cms/examstags/selectpage" data-field="text" data-multiple="true" class="form-control selectpage" name="row[tags_ids]" type="text" value="{$row.tags_ids|htmlentities}">
        </div>
    </div>
默认情况下,是显示所有的tag,id。但是编辑页面,要显示当前的tags,id
对主键值进行判断。为什么要进行这样的判断呢?
 if ($istree&& !$primaryvalue) {
            
                $list = $this->tagsListRight;
                $list = array_values($list);
                  
                //   下面这个,是设置pid的,不设置,就会成undefine,前端的展开隐藏,靠这个pid
                    foreach ($list as $k => &$v) {
                        $v['pid'] = $v['parent'];
                    }
              
              
                if (!$ishtml) {
                    foreach ($list as &$item) {
                        $item = str_replace('&nbsp;', ' ', $item);
                    }
                    unset($item);
                }
            }

3.如何搜索
4.如何批量录入

posted @ 2020-06-09 04:00  风意不止  阅读(1070)  评论(0编辑  收藏  举报