如何使用Element框架配合TP打造自己的后端(不熟悉vue脚手架的可以一起学习下)

15 篇文章 2 订阅
12 篇文章 0 订阅

首先打开thinkphp6.0看云文档,把本地环境搭建好,再安装TP,把伪静态设置好,
1.先安装多应用插件

composer require topthink/think-multi-app

2.然后命令行创建两个应用!!!
命令:php think build admin
第一个应用 admin
第二个应用 api
目录结构如下:

在这里插入图片描述
3.然后在浏览器中输入你绑定的域名 +/admin/index/index 看看是否可以访问?
在这里插入图片描述
OJBK 是可以访问的。
4.在配置数据库 略过
5.创建一个数据表 名字随意
在这里插入图片描述
有这几个字段就足够了,然后手打几个菜单
在这里插入图片描述
pid 为0的就是一级菜单,不为0的就是二级菜单/三级菜单…
6.然后在app目录下创建一个AdminController 类,下面是内容

<?php
declare (strict_types = 1);

namespace app;

use think\App;
use think\exception\HttpResponseException;
use think\exception\ValidateException;
use think\facade\Request;

/**
 * 控制器基础类
 */
abstract class AdminController
{
    /**
     * Request实例
     * @var \think\Request
     */
    protected $request;

    /**
     * 应用实例
     * @var \think\App
     */
    protected $app;


    /**
     * 控制器中间件
     * @var array
     */
    protected $middleware = [];

    /**
     * 构造方法
     * @access public
     * @param  App  $app  应用对象
     */
    public function __construct(App $app)
    {
        $this->app     = $app;
        $this->request = $this->app->request;
    }


}

7.然后再在app/admin/model目录下创建一个模型,这个模型用来查询后台菜单用,内容如下(只查到第二级菜单):

<?php

namespace app\admin\model;


use think\Model;

class AdminMenu extends Model
{
    protected $pk = 'id';
    protected $autoWriteTimestamp = true;
    protected $createTime = 'add_time';

    public function getAddTimeAttr($value)
    {
        return date('Y-m-d H:i:s',$value);
    }

    public function childs()
    {
        return $this->hasMany(AdminMenu::class,'pid','id');
    }

}

8.在app/admin目录下创建一个ViewController.php 类 在这个类里面初始化你的后台菜单,也可以在里面加上页面权限认证等等,内容如下:

<?php
declare (strict_types = 1);

namespace app\admin;

use app\admin\model\AdminMenu;
use app\AdminController;
use think\App;
use think\Exception;
use think\exception\HttpResponseException;
use think\facade\Request;
use think\facade\View;

/**
 * 控制器基础类
 */
abstract class ViewController extends AdminController
{
    protected $menu = [];

    /**
     * 构造方法
     * @access public
     * @param  App  $app  应用对象
     */
    public function __construct(App $app)
    {

        // 控制器初始化
        $this->initialize();
    }

    // 初始化
    protected function initialize()
    {

        $this->menu = AdminMenu::where('pid',0)->with('childs')->select()->toArray();
        View::assign([
            'menu'  => jsonToHtml($this->menu),
            'homeMenu' => jsonToHtml(AdminMenu::where('title','首页')->find()->toArray())
        ]);
    }


    public function success($msg='成功',$data=null, $count = 0,int $wait = 3){
        $result = [
            'code'=> 200,
            'msg' => $msg,
            'data'=> $data,
        ];
        if (!empty($count)){
            $result = [
                'code'=> 200,
                'msg' => $msg,
                'data'=> $data,
                'count'=>$count
            ];
        }
        $response = json($result);
        throw new HttpResponseException($response);
    }

    public function error($msg='失败',$data =null,int $code = 400){
        $result = [
            'code'=> $code,
            'msg' => $msg,
            'debug'=> $data
        ];
        $response = json($result);
        throw new HttpResponseException($response);
    }

}

下面两个函数放进 app/admin/common.php

<?php
// 这是系统自动生成的公共文件


/**
 * json处理
 *
 * @param $str
 * @return string|string[]
 */
function escapeQuotes($str) {
    if ($str && is_string($str)) {
        $str = str_replace("'",  "\u0027", $str);
        $str = str_replace('"',  "\u0022", $str);
    }
    return $str;
}

/**
 * json处理
 *
 * @param $data
 * @return string|string[]
 */
function jsonToHtml($data){
    return escapeQuotes(json_encode($data));
}

9.打开Element文档,找一个你喜欢的后台布局方法然后写好后台主页面的架构
位置 app/admin/view/index/index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <!-- import CSS -->
    <link href="https://cdn.bootcdn.net/ajax/libs/element-ui/2.14.0/theme-chalk/index.min.css" rel="stylesheet">
    <style>
        #app {
            position: fixed;
            top: 0;
            right: 0;
            left: 0;
            bottom: 0;
        }

        .el-container.el-container-box {
            height: 100%;
        }

        .el-container.el-container-body {
            height: 100%;
        }

        .el-aside {
            background-color: #545c64
        }

        .el-main {
            padding-top: 0;
        }

        .el-tab-content-box {
            height: calc(100% - 39px);
        }

        .el-min-content-box {
            width: 100%;
            height: calc(100% - 50px);
            border: none;
        }

        .el-min-content-box .el-tabs__content {
            height: calc(100% - 40px);
        }

        .el-min-content-box .el-tabs__content .el-tab-pane, .el-min-content-box-body {
            width: 100%;
            height: 100%;
            border: none;
        }

        .el-main-header-box {
            text-align: right;
            border-bottom: 1px solid #eee;
            height: 40px;
            line-height: 40px;
        }
    </style>
</head>
<body>
<div id="app">
    <el-container class="el-container-box">
        <el-container class="el-container-body">
            <el-aside class="el-aside" width="200px">
                <el-menu
                        :default-active="active"
                        class="el-menu-vertical-demo"
                        @select="handleOpen"
                        :unique-opened="true"
                        background-color="#545c64"
                        text-color="#fff"
                        active-text-color="#ffd04b">
                    <div v-for="(item, index) in menu">
                        <el-submenu v-if="item.childs.length > 0" :index="index" >
                            <template slot="title">
                                <i class="el-icon-location"></i>
                                <span>{{item.title}}</span>
                            </template>
                            <el-menu-item v-for="(items, indexs) in item.childs" :index="`${index}-${indexs}`">
                                {{items.title}}
                            </el-menu-item>
                        </el-submenu>
                        <el-menu-item v-else :index="index">
                            <i class="el-icon-location"></i>
                            <span>{{item.title}}</span>
                        </el-menu-item>
                    </div>

                </el-menu>
            </el-aside>
            <el-container>
                <el-main>
                    <header class="el-main-header-box">
                        <el-dropdown>
                          <span class="el-dropdown-link">
                            用户<i class="el-icon-arrow-down el-icon--right"></i>
                          </span>
                            <el-dropdown-menu slot="dropdown">
                                <el-dropdown-item>更新缓存</el-dropdown-item>
                                <el-dropdown-item>退出登陆</el-dropdown-item>
                            </el-dropdown-menu>
                        </el-dropdown>
                    </header>
                    <el-tabs  size="mini" type="border-card" class="el-min-content-box" v-model="tabActive" @tab-click="tabClick" closable @tab-remove="removeTab">
                        <el-tab-pane
                                :key="item.id"
                                v-for="(item, index) in editableTabs"
                                :label="item.title"
                                :name="item.id"
                        >
                            <iframe v-if="tabActive === item.id" :src="`/${item.path}.html`" class="el-min-content-box-body"></iframe>
                        </el-tab-pane>
                    </el-tabs>
                </el-main>
            </el-container>
        </el-container>
    </el-container>
</div>
</body>
<!-- import Vue before Element -->
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
<!-- import JavaScript -->
<script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.14.0/index.min.js"></script>
<script>
    const menu = JSON.parse('{$menu}')
    console.log(menu)
    const homeMenu = JSON.parse('{$homeMenu}')
    new Vue({
        el: '#app',
        data: function () {
            return {
                menu: menu,
                tabActive: 0,
                editableTabs: [],
                height: {height: 0},
                active: '0-0'
            }
        },
        methods: {
            handleOpen(key, keyPath) {
                console.log(key, keyPath)
                if ((key+'').indexOf('-') > -1){
                    let arr = key.split('-')
                    var item = this.menu[Number(arr[0])].childs[Number(arr[1])]

                } else  {
                    var item = this.menu[key]
                }
                item['name'] = item.title
                item['index'] = key
                let times = 0
                this.editableTabs.forEach((i, index) => {
                    if (i.id === item.id){

                    } else {
                        times += 1
                    }
                })
                if (times === this.editableTabs.length){
                    this.editableTabs.push(item)
                }
                this.tabActive = item.id
                this.saveMenu()
            },
            tabClick(data) {
                this.editableTabs.forEach((item,index)=> {
                    if (data.name === item.id){
                        console.log(item.index)
                        this.active = item.index
                        this.saveMenu()
                    }
                })
            },
            removeTab(targetName) {
                let tabs = this.editableTabs;
                let activeName = this.tabActive;
                if (activeName === targetName) {
                    tabs.forEach((tab, index) => {
                        if (tab.id === targetName) {
                            let nextTab = tabs[index + 1] || tabs[index - 1];
                            if (nextTab) {
                                activeName = nextTab.id;
                                this.active = nextTab.index
                            }
                        }
                    });
                }
                this.tabActive = activeName;
                this.editableTabs = tabs.filter(tab => tab.id !== targetName);

                this.saveMenu()
                if (tabs.length === 1) {
                    setTimeout(()=> {
                        homeMenu['index'] = '0'
                        homeMenu['name'] = homeMenu.title
                        this.editableTabs.push(homeMenu)
                        this.tabActive = homeMenu.id
                        this.active = '0'
                        this.saveMenu()
                    },600)
                }

            },
            saveMenu() {
                let data = {
                    tabActive: this.tabActive,
                    editableTabs: this.editableTabs,
                    active: this.active
                }
                window.sessionStorage.setItem('menu',JSON.stringify(data))
            },
            getMenu() {
                let data = window.sessionStorage.getItem('menu')
                console.log(data)
                if (data !== null) {
                    data = JSON.parse(data)
                    this.editableTabs = data.editableTabs
                    this.tabActive = data.tabActive
                    this.active = data.active
                }
            }
        },
        mounted() {
            let that = this
            this.getMenu()
        }
    })
</script>
</html>

10.然后到了写功能页面了,,,看菜单数据表的字段path(这个由你决定)然后去创建对应的控制器及方法,然后写好模板。下面举个例子:
文件位置:app/admin/sys/setting.html
对应数据表:
在这里插入图片描述
内容:直接从element首页的文档抄过来的.
在这里插入图片描述
element这段代码目测是用的国外的cdn 所以加载时间短
在这里插入图片描述
在这里插入图片描述
自己写了一个测试用的,下图:
在这里插入图片描述
11.其实还可以用更好的方式,就是把页面写成vue的组件,保存在JS当中,然后在切换菜单栏的时候,就载入那段js即可,这样在用Dialog 对话框的时候体验比较好。

其实layui也好,只是个人不喜欢用。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值