首先打开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也好,只是个人不喜欢用。