同福

使用TFPHP开发一整套TFUMS项目的标签模块的增、删、改、查功能【20210702】

介绍

介绍

福哥今天要把TFPHP框架开发的标准CRUD功能的方法整理一遍,我们以TFUMS系统为基础,给TFUMS项目增加一个标签功能,就是可以给用户打标签的功能。

福哥会把标签模块的增、删、改查功能的开发方法逐个讲解给大家听~~

结构

模型

WEB-APP/Model/tag.inc.php

控制器

WEB-APP/Controller/admin/tag.inc.php
WEB-APP/Controller/api/admin/tag.inc.php
WEB-APP/Controller/api/admin/tag/.mapping.inc.php
WEB-APP/Controller/api/resource/tag.inc.php
WEB-APP/Controller/api/resource/tag/.mapping.inc.php

视图

WEB-APP/View/Template/admin/tag.html

js/pages/admin/tag.js

添加(Create)

错误码

1012001 - 错误请求
1012002 - 标签名称已经存在
1012003 - 保存失败
1012004 - 添加失败

模型

WEB-APP/Model/tag.inc.php

public function add(int $userID, string $title):int {
    // check duplicate
    $tagInfo = $this->getByTable("tagByName", array(tag::T_TYPE, $title));
    if($tagInfo != null){

        return 1;
    }

    // add
    $ret = $this->insert("tag", array(
        'cTypeId'=>tag::T_TYPE,
        'cName'=>$title,
        'cUserId'=>$userID,
        'createDT'=>date("Y-m-d H:i:s"),
        'updateDT'=>date("Y-m-d H:i:s"),
        'cStat'=>tag::T_STATE_NORMAL,
    ));
    if(!$ret){

        return 2;
    }

    return 0;
}

控制器

WEB-APP/Controller/api/admin/tag.inc.php

private function doAdd(){
    $req = $this->tfphp->getRequest();
    $post = $req->post;
    $tag = new tag($this->tfphp);
    $title = $post->get("title");

    try{
        // request test
        if($title == ""){

            $this->tfphp->getResponse()->responseJSON_CM(200, 1012001, "错误请求");
        }
        
        // add tag
        $ret = $tag->add($this->login->getLoginStatus()->mId,
            $title);
        switch ($ret){
            case 1:
                $this->tfphp->getResponse()->responseJSON_CM(200, 1012002, "标签名称已经存在");
                break;
            case 2:
                $this->tfphp->getResponse()->responseJSON_CM(200, 1012003, "保存失败");
                break;
        }
        $tagId = $tag->getLastAddId();
    }
    catch(\Exception $e){
        TFLog::getDefault($this->tfphp)->error($e->getMessage());

        $this->tfphp->getResponse()->responseJSON_CM(200, 1012004, "添加失败");
    }

    // output
    $this->tfphp->getResponse()->responseJSON_CM(200, 0, "OK", array(
        'tagid'=>$tagId,
    ));
}

视图

HTML

<!-- add form -->
<div class="dlg-box dlg-add-form">
    <form class="form add-form">
        <div class="dlg-header">
            <div class="dlg-tool-box">
                <i class="btn-close">X</i>
            </div>
            <div class="dlg-title">
                新建标签
            </div>
        </div>
        <div class="dlg-content">
            <div class="form-group">
                <label>标签名称</label>
                <input class="form-control" type="text" name="title" />
            </div>
        </div>
        <div class="dlg-footer">
            <button class="btn btn-primary btn-sm">提交</button>
        </div>
    </form>
</div>

JS

_startAddForm: function() {
    var ex=this;
    var formOpts;

    formOpts = {
        url: this.baseUri + "api/admin/tag/_add",
        method: "post",
        validations: [
            {type:"empty", name:"title", msg:"请填写标签名称"}
        ],
        onSuccess: function (d) {
            if(d.errcode == 0){
                ex._dlg_add_form.close();
                ex._list.refresh(null, true);
            }
            else{
                $('form.add-form').tips({
                    text:d.errmsg
                });
            }
        },
        onError: function (d) {
            $('form.add-form').tips({
                text:"服务器响应错误"
            });
        },
        onValidationError: function (form, name, msg) {
            $('form.add-form').tips({
                text:msg
            });
            $('form.add-form').find('[name="'+ name +'"]').focus();
        }
    };
    this._add_form = $('form.add-form').form(formOpts);
},

修改(Update)

错误码

1012011 - 错误请求
1012012 - 标签不存在
1012013 - 标签名称已经存在
1012014 - 保存失败
1012015 - 编辑失败

模型

WEB-APP/Model/tag.inc.php

public function mod(int $userID, int $tagID, string $title):int {
    // check exist
    $tagInfo = $this->getByTable("tag", array(tag::T_TYPE, $tagID));
    if($tagInfo == null){

        return 1;
    }

    // check duplicate
    $tagInfo = $this->getByTable("tagByName", array(tag::T_TYPE, $title));
    if($tagInfo != null
        && $tagInfo['cId'] != $tagID){

        return 2;
    }

    // mod
    $ret = $this->update("tag", array(
        'cTypeId'=>tag::T_TYPE,
        'cId'=>$tagID,
        'cName'=>$title,
        'updateDT'=>date("Y-m-d H:i:s"),
    ));
    if(!$ret){

        return 3;
    }

    return 0;
}

控制器

WEB-APP/Controller/api/admin/tag/.mapping.inc.php

private function doMod(){
    $req = $this->tfphp->getRequest();
    $post = $req->post;
    $pathVars = $req->server->get("PATH_VARIABLE");
    $tag = new tag($this->tfphp);
    $tagId = $pathVars['tag'];
    $title = $post->get("title");

    try{
        if(!($tagId > 0)) {
            $this->tfphp->getResponse()->responseJSON_CM(200, 1012011, "错误请求");
        }

        // request test
        if($title == ""){

            $this->tfphp->getResponse()->responseJSON_CM(200, 1012011, "错误请求");
        }

        // modify
        $ret = $tag->mod($this->login->getLoginStatus()->mId,
            $tagId, $title);
        switch ($ret){
            case 1:
                $this->tfphp->getResponse()->responseJSON_CM(200, 1012012, "标签不存在");
                break;
            case 2:
                $this->tfphp->getResponse()->responseJSON_CM(200, 1012013, "标签名称已经存在");
                break;
            case 3:
                $this->tfphp->getResponse()->responseJSON_CM(200, 1012014, "保存失败");
                break;
        }
    }
    catch(\Exception $e){
        TFLog::getDefault($this->tfphp)->error($e->getMessage());

        $this->tfphp->getResponse()->responseJSON_CM(200, 1012015, "编辑失败");
    }

    // output
    $this->tfphp->getResponse()->responseJSON_CM(200, 0, "OK", array(
        'tagid'=>$tagId,
    ));
}

视图

HTML

<!-- modify form -->
<div class="dlg-box dlg-mod-form">
    <form class="form mod-form">
        <div class="dlg-header">
            <div class="dlg-tool-box">
                <i class="btn-close">X</i>
            </div>
            <div class="dlg-title">
                修改标签
            </div>
        </div>
        <div class="dlg-content">
            <div class="form-group">
                <label>标签名称</label>
                <input class="form-control" type="text" name="title" />
            </div>
        </div>
        <div class="dlg-footer">
            <button class="btn btn-primary btn-sm">保存</button>
        </div>
    </form>
</div>

JS

_startModForm: function(id) {
    var ex=this;
    var formOpts;

    formOpts = {
        url: this.baseUri + "api/admin/tag/" + id + "/_mod",
        method: "post",
        validations: [
            {type:"empty", name:"title", msg:"请填写标签名称"}
        ],
        dataUrl: this.baseUri + "api/resource/tag/" + id + "/_detail",
        dataMethod: "post",
        dataMapRules: [
            {name:"title", dataKey:"cName"}
        ],
        onSuccess: function (d) {
            if(d.errcode == 0){
                ex._dlg_mod_form.close();
                ex._list.refresh(null, true);
            }
            else{
                $('form.mod-form').tips({
                    text:d.errmsg
                });
            }
        },
        onError: function (d) {
            $('form.mod-form').tips({
                text:"服务器响应错误"
            });
        },
        onValidationError: function (form, name, msg) {
            $('form.mod-form').tips({
                text:msg
            });
            $('form.mod-form').find('[name="'+ name +'"]').focus();
        }
    };
    this._mod_form = $('form.mod-form').form(formOpts);
},

删除(Delete)

错误码

1012021 - 错误请求
1012022 - 标签不存在
1012023 - 保存失败
1012024 - 删除失败

模型

WEB-APP/Model/tag.inc.php

public function del(int $userID, int $tagID):int {
    // check exist
    $tagInfo = $this->getByTable("tag", array(tag::T_TYPE, $tagID));
    if($tagInfo == null){

        return 1;
    }

    // mod
    $ret = $this->update("tag", array(
        'cTypeId'=>tag::T_TYPE,
        'cId'=>$tagID,
        'cStat'=>tag::T_STATE_LOCKED,
        'updateDT'=>date("Y-m-d H:i:s"),
    ));
    if(!$ret){

        return 2;
    }

    return 0;
}

控制器

WEB-APP/Controller/api/admin/tag/.mapping.inc.php

private function doDel(){
    $pathVars = $this->tfphp->getRequest()->server->get("PATH_VARIABLE");
    $tag = new tag($this->tfphp);
    $tagId = $pathVars['tag'];

    try{
        if(!($tagId > 0)) {
            $this->tfphp->getResponse()->responseJSON_CM(200, 1012021, "错误请求");
        }

        // delete
        $ret = $tag->del($this->login->getLoginStatus()->mId,
            $tagId);
        switch ($ret){
            case 1:
                $this->tfphp->getResponse()->responseJSON_CM(200, 1012022, "标签不存在");
                break;
            case 2:
                $this->tfphp->getResponse()->responseJSON_CM(200, 1012023, "保存失败");
                break;
        }
    }
    catch(\Exception $e){
        TFLog::getDefault($this->tfphp)->error($e->getMessage());

        $this->tfphp->getResponse()->responseJSON_CM(200, 1012024, "删除失败");
    }

    // output
    $this->tfphp->getResponse()->responseJSON_CM(200, 0, "OK", array(
        'tagid'=>$tagId,
    ));
}

视图

HTML

<!-- delete form -->
<div class="dlg-box dlg-del-form">
    <form class="form del-form">
        <div class="dlg-header">
            <div class="dlg-tool-box">
                <i class="btn-close">X</i>
            </div>
            <div class="dlg-title">
                删除标签
            </div>
        </div>
        <div class="dlg-content">
            <div class="form-group">
                <label>标签名称</label>
                <span class="form-text" name="title"></span>
            </div>
        </div>
        <div class="dlg-footer">
            <button class="btn btn-primary btn-sm">删除</button>
        </div>
    </form>
</div>

JS

_startDelForm: function(id) {
    var ex=this;
    var formOpts;

    formOpts = {
        url: this.baseUri + "api/admin/tag/" + id + "/_del",
        method: "post",
        dataUrl: this.baseUri + "api/resource/tag/" + id + "/_detail",
        dataMethod: "post",
        onSuccess: function (d) {
            if(d.errcode == 0){
                ex._dlg_del_form.close();
                ex._list.refresh(null, true);
            }
            else{
                $('form.del-form').tips({
                    text:d.errmsg
                });
            }
        },
        onError: function (d) {
            $('form.del-form').tips({
                text:"服务器响应错误"
            });
        },
        onDataSuccess: function (d) {
            $('form.del-form').find('[name="title"]').text(d.cName);
        },
        onValidationError: function (form, name, msg) {
            $('form.del-form').tips({
                text:msg
            });
            $('form.del-form').find('[name="'+ name +'"]').focus();
        }
    };
    this._mod_form = $('form.del-form').form(formOpts);
},

查询(Retreive)

模型

WEB-APP/Model/tag.inc.php

public function loadTags(int $parentID, string $keyword, int $pageSize, int $pageNum, array $states=null):array {
    $tfdo = $this->tfphp->getDatabase()->getTFDO();

    $sql = "SELECT a.cId, a.cName FROM tfart_categories a
        WHERE a.cPId = @int
            AND a.cStat = @int";
    if($keyword != ""){
        $sql .= " AND a.cName LIKE '%". str_replace("'", "\'", $keyword). "%'";
    }
    $sql .= " ORDER BY a.cId DESC";
    $params = array($parentID, tag::T_STATE_NORMAL);
    $total = $tfdo->fetchTotal($sql, $params);
    $page = new TFDataPage($this->tfphp, $total, $pageSize, $pageNum);
    $page->makeTeamlinkRange(6);
    $pageArr = $page->toArray();
    $datas = $tfdo->fetchPart($sql, $pageArr['seekBegin'], $pageArr['fetchNums'], $params);

    if(is_array($datas)){
        foreach($datas as $k => $data){

        }
    }

    return array(
        'page'=>$pageArr,
        'data'=>$datas,
    );
}

控制器

WEB-APP/Controller/api/admin/tag.inc.php

private function doList(){
    $req = $this->tfphp->getRequest();
    $tag = new tag($this->tfphp);
    $keyword = $req->post->get("keyword");

    $datas = $tag->loadTags(intval($req->get->get("pid")),
        strval($keyword),
        10,
        intval($req->get->get("pn")));

    // output
    $this->tfphp->getResponse()->responseJSON(200, $datas);
}

视图

HTML

<div class="row">
    <div class="col-12">
        <div class="tag-search">
            <form class="search-form form-horizontal">
                <div class="row">
                    <div class="col-12">
                        <div class="float-left">

                        </div>
                        <div class="float-right">
                            <div class="form-inline">
                                <span><label>关键词</label></span>
                                <span><input class="form-control" type="text" name="keyword" /></span>
                                <span><button class="btn btn-primary btn-sm form-control">搜索</button></span>
                                <span><button class="btn btn-fun btn-sm form-control add-btn">新建标签</button></span>
                            </div>
                        </div>
                    </div>
                </div>
            </form>
        </div>
    </div>
    <div class="col-12">
        <div class="tag-list">
            <table class="table">
                <thead>
                <tr>
                    <th>ID</th>
                    <th>标签</th>
                    <th>&nbsp;</th>
                </tr>
                </thead>
                <tbody>

                </tbody>
            </table>

            <ul class="pagination">
                <li><a>第一页</a></li>
                <li><a>前一页</a></li>
                <li class="active"><a>1</a></li>
                <li><a>2</a></li>
                <li><a>3</a></li>
                <li><a>4</a></li>
                <li><a>5</a></li>
                <li><a>6</a></li>
                <li><a>后一页</a></li>
                <li><a>最后页</a></li>
            </ul>
        </div>
    </div>
</div>

JS

_startTable: function (_pn) {
    var ex = this;
    var tableOpts;

    tableOpts = {
        dataUrl: this.baseUri + "api/admin/tag/_list?pn={pn}",
        dataMethod: "post",
        dataRenderType: "classic",
        pn: _pn,
        attachRowEvent: function (obj, id) {
            var item = obj.find('tr[dataid="' + id + '"]'), dataid = id;

            item.find('.btn-mod').click(function () {
                // modify
                ex._openModForm(dataid);
            });
            item.find('.btn-del').click(function () {
                // delete
                ex._openDelForm(dataid);
            });
        },
        onRenderTable: function (data, table) {
            var obj = table.find(".table").find("tbody");

            obj.find("tr").remove();
        },
        onRenderRow: function (row, table) {
            var obj = table.find(".table").find("tbody"), extraBtns, extraClass;

            extraBtns = '';
            extraClass = '';
            obj.append('<tr dataid="' + row.cId + '">' +
                '       <td>' + row.cId + '</td>' +
                '       <td><a href="">' + row.cName + '</a></td>' +
                '       <td class="btns">' +
                '           <span class="btn btn-white btn-sm btn-mod">编辑</span>' +
                '           <span class="btn btn-white btn-sm btn-del">删除</span>' +
                '       </td>' +
                '</tr>');

            this.attachRowEvent(obj, row.cId);
        },
        onRenderPage: function (page, table) {
            var obj = table.find(".pagination"), html = "";

            obj.html("");
            if (page.pageNum > 1) {
                obj.append('<li><a page-num="1">第一页</a></li>');
                obj.append('<li><a page-num="' + (page.pageNum - 1) + '">前一页</a></li>');
            }
            if (page.pageTeamlinkRange) {
                for (var p = page.pageTeamlinkRange.low; p <= page.pageTeamlinkRange.high; p++) {
                    obj.append('<li><a page-num="' + p + '">' + p + '</a></li>');
                }
                obj.find('[page-num="' + page.pageNum + '"]').parent().addClass("active");
            }
            if (page.pageNum < page.pageTotal) {
                obj.append('<li><a page-num="' + (page.pageNum + 1) + '">后一页</a></li>');
                obj.append('<li><a page-num="' + page.pageTotal + '">最后页</a></li>');
            }
        },
        onError: function (d) {

        }
    };
    this._list = $('.tag-list').table(tableOpts);
},

_startSearchForm: function() {
    var ex=this;
    var formOpts;

    formOpts = {
        method: "post",
        onSuccess: function (d) {
            if(d.page && d.data){

            }
            else{
                $('form.search').tips({
                    text:d.errmsg
                });
            }
        },
        onError: function (d) {
            $('form.search').tips({
                text:"服务器响应错误"
            });
        },
        onValidationError: function (form, name, msg) {
            $('form.search').tips({
                text:msg
            });
            $('form.search').find('[name="'+ name +'"]').focus();
        }
    };
    formOpts.table = this._list;
    this._search_form = $('form.search-form').form(formOpts);
},

效果

列表

home/topic/2021/0703/21/85c807cd221431ccf7ba70b121e94bde.png

表单

home/topic/2021/0703/21/41d427791b87e2db23309ce0dd2cbcbf.png

总结

今天福哥教给了童鞋们使用TFPHP框架开发一套完整的增、删、改、查(CRUD)功能的方法,福哥以同福网的标签管理功能为例,给出了全套的代码,包括前后端,大家可以参考!