tpext-myadmin框架完整说明

ichynul

说明:

之前发布了插件:https://www.workerman.net/plugin/70

由于插件页面不支发布回复,所以在此另开一个贴,希望感兴趣的朋友下载试用,有问题的可以在此反馈。

其实里面包含好几个东西,插件系统、后台权限、ui生成、配置管理、等,整合为一个插件发布出来,说是个插件,其实更是一个框架。

因为涉及到多个功能,而且是移植版,经过了大量调整,所以发布出来有一些问题,一直在迭代修复。

以下为正文

简介

tpext-myadmin 快速开发框架,内置插件系统、admin权限,插件系统,ui生成(类似laravel-admin)

集成[webman]版仓库:https://github.com/hi-tpext/mywebman

插件仓库:https://github.com/hi-tpext/tpextmyadmin/tree/4.0

QQ群

安装

[php环境] 建议7.37.4
8.x未测试

方式一、使用 composer 全新安装

安装 [webman] 和 [tpextmyadmin]

#取消composer镜像,使用官方源,确定下载的是最新

composer config -g --unset repos.packagist

composer create-project workerman/webman mywebman

cd mywebman

composer require ichynul/tpextmyadmin:^4.1.1

安装完毕,此安装版是最小模式,只包含基本的后台功能,建议开发新项目时使用此方式。


方式二、使用 git 安装演示站

git拉取,依次执行以下命令,mywebman 为新项目目录,可自行调整

git clone https://github.com/hi-tpext/mywebman.git mywebman

cd mywebman

composer update

相关演示代码在https://github.com/hi-tpext/mywebman app/admin/中,数据库脚本由[myadmindata]扩展提供,请下载安装。

安装完毕,此安装版是最和演示站同步的,如果你想自己搭建演示站可用此方式。

注意:此方式的仓库是不带composer依赖vendor目录的,请务必运行composer update安装所有依赖后再访问网站。


配置

  • /config/thinkorm.php中配置数据库,或在网页中配置[见下一步]

webman1.4.x

新版本默认开启控制器后缀:'controller_suffix' => 'Controller',

请关闭它,在config/app.php中修改为:

'controller_suffix' => '',

webman1.5.x

2023-02-16 已适配

扩展安装

  1. 浏览器输入 [http://localhost:8787/admin] 打开,如果没有事先配置数据库,将会跳转到配置数据库的页面(若不能正常跳,配置数据库后再试)。

  2. 自动安装基础扩展

  3. 手动安装 [tpext.myadmin],确保此扩展优先,以支持其他扩展的后台菜单创建

    默认账号:admintpextadmin

    安装成功后自动创建id为1的超级管理员,并处于登录状态。

  4. 手动安装其余装扩展

登录后台

  • 安装完所有扩展后,浏览器再次输入[http://localhost:8787/admin]打开,进入后台主页。

一些问题

运行目录

传统的php-fpm一般是以 public 作为启动目录,为保持兼容,建议进入 public 目录执行启动命令:

[linux]

启动:

cd public
php ../start.php start

[windows]

启动:

cd public
php ..\windows.php

或修改把 windows.bat 移入 public 目录并修改内容:

CHCP 65001
php ..\windows.php
pause

启动:

cd public
.\windows.bat

extend 扩展

extend扩展基于composer.josn配置

初次安装会检测,如果未注册/extend/目录将自动修改composer.json文件(命令行会提示:注册扩展目录:extend/成功,composer.json文件已修改),但修改后仍然需你下次运行composer相关命名才后生效。

"autoload": {
    /**其他**/
    "psr-0": {
         "": "extend/"
     }
}

如果下载extend类型插件不能识别,提示:

执行出错:
未匹配到扩展

是因为/extend/目录未注册,里面的php文件无法识别其命名空间。
暂时解决办法,检查composer.json文件有无psr-0 extend/,然后运行composer u,之后使extend生效,重启程序。


文档

https://gxzrnxb27j.k.topthink.com/@tpext-docs/about.html

Thinkphp版:

https://github.com/hi-tpext/myadmin

演示

网址

  1. [tp6.1] http://gaosu.shenzhuo.vip:50469/admin

  2. [webman] http://gaosu.shenzhuo.vip:50468/admin

账号

admin

tpextadmin

实例

<?php

namespace app\admin\controller;

use app\common\logic\MemberLogic;
use app\common\model;
use think\Controller;
use tpext\builder\traits\HasBuilder;

/**
 * Undocumented class
 * @title 会员管理
 */
class Member extends Controller
{
    use HasBuilder;

    /**
     * Undocumented variable
     *
     * @var model\Member
     */
    protected $dataModel;

    protected function initialize()
    {
        $this->dataModel = new model\Member;
        $this->pageTitle = '会员管理';
        $this->enableField = 'status';
        $this->pagesize = 8;

        /* 作为下拉选择数据源 相关设置 */
        //显示
        $this->selectTextField = '{id}#{nickname}({mobile})';
        //like查询字段,$this->dataModel->where('username|nickname|mobile', 'like', $kwd);
        $this->selectSearch = 'username|nickname|mobile';
    }

    protected function filterWhere()
    {
        $searchData = request()->get();
        $where = [];
        if (!empty($searchData['id'])) {
            $where[] = ['id', 'eq', $searchData['id']];
        }
        if (!empty($searchData['username'])) {
            $where[] = ['username', 'like', '%' . $searchData['username'] . '%'];
        }
        if (!empty($searchData['nickname'])) {
            $where[] = ['nickname', 'like', '%' . $searchData['nickname'] . '%'];
        }
        if (!empty($searchData['mobile'])) {
            $where[] = ['mobile', 'like', '%' . $searchData['mobile'] . '%'];
        }
        if (isset($searchData['status']) && $searchData['status'] != '') {
            $where[] = ['status', 'eq', $searchData['status']];
        }
        if (isset($searchData['level']) && $searchData['level'] != '') {
            $where[] = ['level', 'eq', $searchData['level']];
        }
        if (!empty($searchData['province'])) {
            $where[] = ['province', 'eq', $searchData['province']];
            if (!empty($searchData['city'])) {
                $where[] = ['city', 'eq', $searchData['city']];
                if (!empty($searchData['area'])) {
                    $where[] = ['area', 'eq', $searchData['area']];
                }
            }
        }
        return $where;
    }

    /**
     * 构建搜索
     *
     * @return void
     */
    protected function builSearch()
    {
        $search = $this->search;

        $search->text('id', '会员id')->maxlength(20);
        $search->text('username', '账号')->maxlength(20);
        $search->text('nickname', '昵称')->maxlength(20);
        $search->text('mobile', '手机号')->maxlength(20);
        $search->select('level', '等级')->optionsData(model\MemberLevel::order('level')->select(), 'name', 'level')->afterOptions([0 => '普通会员']);
        $search->select('status', '状态')->options([0 => '禁用', 1 => '正常']);
        $search->select('province', '省份')->dataUrl(url('api/areacity/province'), 'ext_name')->withNext(
            $search->select('city', '城市')->dataUrl(url('api/areacity/city'), 'ext_name')->withNext(
                $search->select('area', '地区')->dataUrl(url('api/areacity/area'), 'ext_name')
            )
        );
    }

    /**
     * 构建表格
     *
     * @return void
     */
    protected function buildTable(&$data = [])
    {
        $table = $this->table;

        $table->show('id', 'ID');
        $table->image('avatar', '头像')->thumbSize(50, 50)->default('/static/images/touxiang.png');
        $table->show('username', '账号');
        $table->text('nickname', '昵称')->autoPost()->getWrapper()->addStyle('width:130px');
        $table->show('mobile', '手机号')->getWrapper()->addStyle('width:100px');
        $table->match('gender', '性别')->options([1 => '男', 2 => '女', 0 => '未知'])->getWrapper()->addStyle('width:50px');
        $table->show('age', '性别');
        $table->show('level_name', '等级');
        $table->show('money', model\MemberAccount::$types['money']);
        $table->show('points', model\MemberAccount::$types['points']);
        $table->show('pca', '省市区');
        $table->switchBtn('status', '状态')->default(1)->autoPost()->getWrapper()->addStyle('width:60px');
        $table->show('last_login_time', '最近登录')->getWrapper()->addStyle('width:150px');
        $table->show('create_time', '注册时间')->getWrapper()->addStyle('width:150px');

        $table->sortable('id,sort,money,points,commission,re_comm,shares,last_login_time');

        $table->getToolbar()
            ->btnAdd()
            ->btnEnableAndDisable('启用', '禁用')
            ->btnRefresh();

        $table->getActionbar()
            ->btnEdit()
            ->btnView()
            ->btnLink('account', url('/admin/memberaccount/add', ['member_id' => '__data.pk__']), '', 'btn-success', 'mdi-square-inc-cash');
    }

    /**
     * 构建表单
     *
     * @param boolean $isEdit
     * @param array $data
     */
    protected function builForm($isEdit, &$data = [])
    {
        $form = $this->form;

        $form->tab('基本信息');
        $form->image('avatar', '头像')->thumbSize(50, 50);
        $form->text('username', '账号')->required()->maxlength(20);
        $form->text('nickname', '昵称')->required()->maxlength(20);
        $form->text('mobile', '手机号')->maxlength(11);
        $form->text('email', '邮件')->maxlength(60);
        $form->number('age', '年龄')->max(100)->min(1)->default(18);
        $form->radio('gender', '性别')->options([0 => '未知', 1 => '男', 2 => '女'])->default(0);

        $form->tab('其他信息');
        $form->textarea('remark', '备注')->maxlength(255);
        $form->switchBtn('status', '状态')->default(1);

        if ($isEdit) {
            $form->show('last_login_time', '最近登录时间');
            $form->show('create_time', '注册时间');
            $form->show('update_time', '修改时间');
        }
    }

    /**
     * 保存数据
     *
     * @param integer $id
     * @return void
     */
    private function save($id = 0)
    {
        $data = request()->only([
            'avatar',
            'username',
            'nickname',
            'mobile',
            'email',
            'gender',
            'age',
            'status',
            'remark',
        ], 'post');

        $result = $this->validate($data, [
            'username|账号' => 'require',
            'nickname|昵称' => 'require',
            'mobile|手机号' => 'mobile',
            'age|年龄' => 'number',
        ]);

        if (true !== $result) {
            $this->error($result);
        }

        return $this->doSave($data, $id);
    }
}

效果展示








License

Apache2

2912 6 3
6个评论

moco

$table->getToolbar()
->btnAdd($url = url('add',['module'=>request()->get('module',1)]), $label = '添加' $class = 'btn-primary', $icon = 'mdi-plus', $attr = ''); add链接添加变量数据不起作用,永远是1

  • 暂无评论
fengshengchang

针对商品展示的前台页面有吗?怎么进入?

  • ichynul 2022-07-23

    商城没有pc端,现在一般都是app之类的,用api接口获取数据。

Saas-Maike

作者怎么联系 我安装了 怎么和演示的不一样

  • ichynul 2022-11-01

    后台界面风格可以安装扩展改变的

  • Saas-Maike 2022-11-01

    404怎么解决

  • Saas-Maike 2022-11-01

    生产菜单 404

  • ichynul 2022-11-02

    你说的是生成代码吧,菜单是要手动添加的。
    是生成代码这个功能404,还是生成出来的页面404?
    最好发个截图(在下面新回复,就可以上传图片),是哪个页面,或发一下页面url。

  • Saas-Maike 2022-11-02

    有其他的联系方式吧

  • Saas-Maike 2022-11-02

    老是很不顺利

  • ichynul 2022-11-02

    qq群:171696777
    或扫文章里的二维码进群

owenzhang

哇,不错,改天试下,谢谢分享

  • owenzhang 2022-11-01

    但好卷啊,我还是希望,我就写接口和服务,后台页面什么的都是前端来做,前后端分离啊,后端就做后端的事情

  • ichynul 2022-11-01

    顺带把前端的事情做了而已。
    可能比只写接口麻烦一些,单比前端+后端的工作量减少了。你只是把工作量分个另外一个人了,总的工作量并没减少。
    前端页面也不好写,只不过把html换成了vue之类。另外向其他的通过后端json配置生成的界面,其实也不比我这个简单。

skyhack

感谢分享,mark下!

  • 暂无评论
W

点赞收藏加关注,大佬666

  • 暂无评论

ichynul

1820
积分
0
获赞数
0
粉丝数
2022-03-04 加入
🔝