PHPackages                             tiderjian/qscmf - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Admin Panels](/categories/admin)
4. /
5. tiderjian/qscmf

ActiveCmf[Admin Panels](/categories/admin)

tiderjian/qscmf
===============

qscmf

v15.0.1(1mo ago)98911[2 PRs](https://github.com/quansitech/qs_cmf/pulls)MITPHP

Since Jun 5Pushed 1mo ago3 watchersCompare

[ Source](https://github.com/quansitech/qs_cmf)[ Packagist](https://packagist.org/packages/tiderjian/qscmf)[ RSS](/packages/tiderjian-qscmf/feed)WikiDiscussions master Synced 2d ago

READMEChangelogDependencies (21)Versions (111)Used By (0)

qscmf
=====

[](#qscmf)

[![lincense](https://camo.githubusercontent.com/942e017bf0672002dd32a857c95d66f28c5900ab541838c6c664442516309c8a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e7376673f7374796c653d666c61742d737175617265)](https://camo.githubusercontent.com/942e017bf0672002dd32a857c95d66f28c5900ab541838c6c664442516309c8a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e7376673f7374796c653d666c61742d737175617265)[![LICENSE](https://camo.githubusercontent.com/be80b8cb211ceb2263744e99fdb161a40124901906fd7c7f47d6361760dd7e8b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d416e74692532303939362d626c75652e737667)](https://github.com/996icu/996.ICU/blob/master/LICENSE)[![Pull request welcome](https://camo.githubusercontent.com/25f2db1404306d6dc01b1ac6e8c70f5f397ea8043dd9584d8dc4bc31b8bfea59/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f70722d77656c636f6d652d677265656e2e7376673f7374796c653d666c61742d737175617265)](https://camo.githubusercontent.com/25f2db1404306d6dc01b1ac6e8c70f5f397ea8043dd9584d8dc4bc31b8bfea59/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f70722d77656c636f6d652d677265656e2e7376673f7374796c653d666c61742d737175617265)

介绍
--

[](#介绍)

快速搭建信息管理类系统的框架。基于tp3.2开发,在其基础上添加了许多功能特性。tp3.2已经停止更新，该框架源码也对核心源码做了部分改动。

特性
--

[](#特性)

- 支持composer依赖管理
- 支持phpunit及laravel dusk自动化测试
- 集成laravel数据库管理工具及依赖注入容器
- 支持ListBuilder、FormBuilder后台管理界面模块化开发
- 插件系统
- 简单易用，可自定义的配置管理
- 消息队列系统
- 集成Elasticsearch、可自定义索引重建自制，实现数据库记录与搜索引擎索引同步变动

截图
--

[](#截图)

[![](https://user-images.githubusercontent.com/1665649/55472251-36458e80-563e-11e9-87c0-10c386d5bd78.png)](https://user-images.githubusercontent.com/1665649/55472251-36458e80-563e-11e9-87c0-10c386d5bd78.png)

安装
--

[](#安装)

第一种安装方法

```
git clone https://github.com/tiderjian/qs_cmf.git

```

代码拉取完成后，执行composer安装

```
composer install

```

第二种安装方法，composer create project

```
composer create-project tiderjian/qscmf qscmf
```

完成第一种或者第二种安装后

1. 复制.env.example并重命名为.env，配置数据库参数
2. 执行migrate数据库迁移命令。

```
php artisan migrate

```

将web服务器搭起来后，后台登录地址 协议://域名:端口/admin， 账号:admin 密码:Qs123!@#

维护模式
----

[](#维护模式)

在.env将 APP\_MAINTENANCE 设成true，系统进入维护状态，所有请求都只会提示系统维护中。如需要在维护模式下执行升级脚本，可传递"maintenance"给第三个参数

```
php index.php Qscmf/UpgradeFix/v300FixSchedule/queue/default maintenance
```

Elasticsearch
-------------

[](#elasticsearch)

框架为集成Elasticsearch提供了方便的方法, 假设使用者已经具备elasticsearch使用的相关知识。

1. 添加 "elasticsearch/elasticsearch": "~6.0" 到composer.json文件，执行composer update 命令安装扩展包。
2. 安装elasticsearch, 具体安装方法自行查找，推荐使用laradock作为开发环境，直接集成了elasticsearch的docker安装环境。
3. 安装ik插件，安装查找elasticsearch官方文档。
4. 在.env下添加 ELASTICSEARCH\_HOSTS值，设置为elasticsearch的启动ip和端口，如laradock的默认设置为10.0.75.1:9200，需要配置一组地址，可用“,”隔开。
5. 设置需要使用elastic的model和字段

    以ChapterModel添加title和summary到全文索引为例

    ```
    // ChapterModel类必须继承接口
    class ChapterModel  extends \Gy_Library\GyListModel implements \Qscmf\Lib\Elasticsearch\ElasticsearchModelContract{

       // ElasticsearchHelper已经实现了一些帮助函数
       use \Qscmf\Lib\Elasticsearch\ElasticsearchHelper;

       // 初始化全文索引时需要指定该Model要添加的索引记录
       public function elasticsearchIndexList()
       {
            // 如这里chapter表与course表关联，只有当course及chapter状态都为可用，且非描述类chapter(pid = 0为描述类chapter)才会添加全文索引
           return $this->alias('ch')->join('__COURSE__ c ON c.id=ch.course_id and c.status = ' . DBCont::NORMAL_STATUS)->where(['ch.status' => DBCont::NORMAL_STATUS, 'ch.pid' => ['neq', 0]])->field('ch.*')->select();
       }

       // chapter进行增删查改时同时会更新索引内容，该方法是指定什么状态的记录才会进行索引更改
       // 返回false为无需索引的记录，true则会进行索引更新
       public function isElasticsearchIndex($ent){
           if($ent['status'] != DBCont::NORMAL_STATUS || $ent['pid'] == 0){
               return false;
           }

           $course_ent = D('Course')->find($ent['course_id']);
           if($course_ent['status'] == DBCont::NORMAL_STATUS){
               return true;
           }
           else{
               return false;
           }
       }

       // 程序会自动生成索引的配置参数，此处是定义生成参数的规则
       // 以:开头的字母表示该处会自动替换成相应字段的实际值
       // {}表示里面的字符会与替换后的:字段值进行连接，如:id{_chapter}, id实际值为 12，则该处会替换成 12_chapter
       // | 表示可以将字段的实际值传递给指定的函数进行处理，转换成想要的值。如，description字段是富文本内容，我们将html标签进行索引，可以在model方法里自定义一个叫deleteHtmlTag的方法进行处理，当然也可以定义为全局函数，程序会先查找全局是否存在该函数，如果没有再去对象里查找有无该方法
      // index和type的值在建立初始化全文索引时指定，具体查看全文索引初始化说明
       public function elasticsearchAddDataParams()
       {
           return [
               'index' => 'global_search',
               'type' => 'content',
               'id' => ':id{_chapter}',
               'body' => [
                   'title' => ':title',
                   'desc' => ':description|html_entity_decode'
               ]
           ];
       }
    }
    ```
6. 初始化全文索引

    打开Home/Controller/ElasticController.class.php文件, 修改index方法里的$params变量，根据你的需要来设置
7. 执行索引初始化，程序会自动检索数据库全部数据表，为需要添加索引的表和字段进行索引添加操作。

    ```
    //进入app目录，下面有个makeIndex.php文件
    php makeIndex.php

    ```
8. 可通过在config文件设置 "ELASTIC\_ALLOW\_EXCEPTION" 来禁止抛出异常，即使搜索引擎关闭，也不会影响原来的业务操作。
9. 更新操作的索引重建仅会在索引字段发生变化时才会触发。

Controller
----------

[](#controller)

[传送门](https://github.com/quansitech/qs_cmf/blob/master/docs/Controller.md)

Model
-----

[](#model)

[传送门](https://github.com/quansitech/qs_cmf/blob/master/docs/Model.md)

数据库迁移
-----

[](#数据库迁移)

扩展了laravel的迁移功能, 可在执行迁移前后插入一些操作。

```
class CreateTestTable extends Migration
{

    public function beforeCmmUp()
    {
        echo "执行前置命令" . PHP_EOL;
    }

    public function beforeCmmDown()
    {
        echo "执行前置回滚命令" . PHP_EOL;
    }

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('test', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('test');
    }

    public function afterCmmUp()
    {
        echo "执行后置命令" . PHP_EOL;
    }

    public function afterCmmDown()
    {
        echo "执行后置回滚命令" . PHP_EOL;
    }
}
```

运用场景：

迁移文件是为了方便我们对数据库结构进行变更管理。那么是所有的数据库变更都会放到迁移文件处理吗？当然不是，像一些跟业务逻辑有关的数据处理就不应该放到迁移文件，否则这部分代码跟 业务数据捆绑，很容易导致执行迁移时出错。而只有那些跟业务数据无关，用于构造系统数据存储结构的变更操作才应该放到迁移中。但一个业务系统维护久了，难免必须处理一些数据后才能正常 执行数据库结构变更，例如唯一索引的创建往往就需要我们清理掉一些重复的业务数据。这时就有了不能放在迁移里的业务数据维护脚本的管理需求。

依托上面的场景，就有了在迁移文件中加入了前后置的操作点的构思。默认情况下，只要设置了前后置操作点，执行迁移时就会自动执行一遍，回滚类同。

那么如果只是想执行迁移而不执行前后置操作怎么办呢（例如执行自动测试脚本前，我们会自动构建系统的数据库）。只需在命令后面加入 --no-cmd即可

下面是支持加入--no-cmd操作的命令

```
php artisan migrate --no-cmd

php artisan migrate:rollback --no-cmd

php artisan migrate:fresh --no-cmd

php artisan migrate:refresh --no-cmd

php artisan migrate:reset --no-cmd
```

- CmmProcess 该类是为了方便在迁移中调用tp的脚本

    > 用法：
    >
    > ```
    > $process = new \Larafortp\CmmMigrate\CmmProcess();
    > //timeout为程序的超时退出时间，默认60秒
    > $process->setTimeOut(100)->callTp('/var/www/move/www/index.php', '/home/index/test');
    > ```
- ConfigGenerator 迁移中处理系统配置的工具类

    addGroup($name) //添加配置分组

    deleteGroup($name) //删除配置分组

    updateGroup($config\_name, $group\_name) //将配置转移到指定分组

    以下为新增配置项的操作函数

    > $name 配置名
    >
    > $title 配置标题
    >
    > $value 配置值
    >
    > $remark 配置说明
    >
    > $group 配置分组
    >
    > $sort 排序

    addNum($name, $title, $value, $remark = '', $group = 1, $sort = 0) //新增数字类型配置值

    addText($name, $title, $value, $remark = '', $group = 1, $sort = 0) //新增字符类型配置值

    addArray($name, $title, $value, $remark = '', $group = 1, $sort = 0) //新增数组类型配置值

    addPicture($name, $title, $value, $remark = '', $group = 1, $sort = 0) //新增图片类型配置值

    addUeditor($name, $title, $value, $remark = '', $group = 1, $sort = 0) //新增富文本类型配置值

    addSelect($name, $title, $value, $options, $remark = '', $group = 1, $sort = 0) //新增下拉选择配置值 $options 是下拉配置数组

    add($name, $type, $title, $group, $extra, $remark, $value, $sort) //新增配置方法，未预设的第三方组件可使用该函数

    delete($name) //删除配置

后台JS
----

[](#后台js)

[传送门](https://github.com/quansitech/qs_cmf/blob/master/docs/BackendJs.md)

ListBuilder
-----------

[](#listbuilder)

[传送门](https://github.com/quansitech/qs_cmf/blob/master/docs/ListBuilder.md)

FormBuilder
-----------

[](#formbuilder)

[传送门](https://github.com/quansitech/qs_cmf/blob/master/docs/FormBuilder.md)

CompareBuilder
--------------

[](#comparebuilder)

[传送门](https://github.com/quansitech/qs_cmf/blob/master/docs/CompareBuilder.md)

Builder
-------

[](#builder)

[传送门](https://github.com/quansitech/qs_cmf/blob/master/docs/Builder.md)

Cache
-----

[](#cache)

[传送门](https://github.com/quansitech/qs_cmf/blob/master/docs/Cache.md)

upload Api
----------

[](#upload-api)

[传送门](https://github.com/quansitech/qs_cmf/blob/master/docs/Upload.md)

前台js错误收集
--------

[](#前台js错误收集)

#### 用法

[](#用法)

在前端head中引入log.js后调用frontLog方法

```

      frontLog({
        url:'/api/jsLog/index'
      });

```

权限功能
----

[](#权限功能)

[传送门](https://github.com/quansitech/qs_cmf/blob/master/docs/Auth.md)

微信登录
----

[](#微信登录)

为解决第三方平台网站应用的PC扫码后openid不可操作问题，统一对PC端微信扫码以及微信端登录进行封装。

- 从[微信公众平台](https://mp.weixin.qq.com/)中获取公众号的app\_id和app\_secret，并进行相关配置，放入.env文件

    ```
    # 微信公众号
    WX_APPID=
    WX_APPSECRET=
    ```
- PC扫码页面，在需要显示二维码的地方加入iframe

    ```

    ```

    PS:

1. 构造iframe的src时，可通过goto\_url参数来指定PC端扫码后跳转的地址，默认为首页
2. 构造iframe的src时，可通过mobile\_goto\_url参数来指定微信端扫码后跳转的地址，默认为首页

- 微信端获取登录信息

    ```
      $wx_info=Qscmf\Lib\WeixinLogin::getInstance()->getInfoForMobile();
    ```
- 运行/扫码后可用`session('wx_info')`获取微信登录信息
- 若'wx\_info'的session值已设置，可通过设置config.php中的'WX\_INFO\_SESSION\_KEY'来改变

### 场景模拟

[](#场景模拟)

一、 PC端实现扫码登录/注册

- 扫码页面（扫码后需要跳转到'/home/index/wxLogin'）

    ```

    ```
- 登录/注册业务处理（对应上一步的"/home/index/wxLogin"）

    ```
    $wx_info=json_decode(session('wx_info'),true);
    // 若用户表为member表
    $member=D('Member')->where(['openid'=>$wx_info['id']])->find();
    if ($member){
      //登录
      session('mid',$member['id']);
    }else{
      //注册
      $ent=[
          'openid'=>$wx_info['id'],
          'nickname'=>$wx_info['nickname']
      ];
      $r=D('Member')->createAdd($ent);
      if ($r===false){
          E(D('Member')->getError());
      }
      session('mid',$r);
    }
    redirect(U('home/user/index'));
    ```

二、 微信端实现授权登录/注册

1. 授权页面 （授权后需要跳转到'/home/index/wxLogin'）

    ```
     $wx_info=Qscmf\Lib\WeixinLogin::getInstance()->getInfoForMobile();
     if ($wx_info){
         redirect(U('/home/index/wxLogin'));
     }
    ```
2. 登录/注册业务处理（对应上一步的"/home/index/wxLogin"）

    ```
    // 与PC端扫码后登录/注册业务处理一致
    ```

全局函数
----

[](#全局函数)

[传送门](https://github.com/quansitech/qs_cmf/blob/master/docs/Helper.md)

js组件
----

[](#js组件)

### selectAddr

[](#selectaddr)

```
select框的地址选择器

参数
addressLevel: array 省/市/县的select框默认值，默认为：['选择省','选择市','选择区']
level: int 1|2|3 地址的等级：省/市/区，默认为：3
url: array 分别获取地址的接口url，默认为：['/api/area/getProvince.html','/api/area/getCityByProvince.html','/api/area/getDistrictByCity.html']
onSelected: function (val,changeEle){}  每个select框选择地址后执行自定义function，val： 隐藏域的值 changeEle： 触发事件的select
```

代码示例

```

    jQuery(document).ready(function() {
        $('#hidden_position').selectAddr({
            addressLevel: ['省','市','区'],
            level: 3,
            onSelected: function (val,changeEle){
                log(val);
            }
        });

        function log(str) {
            console.log(str+"-111");
        }
    });

```

常量
--

[](#常量)

DOMAIN 域名，可通过env去改写，默认采用$\_SERVER\["HTTP\_HOST"\]

ROOT 指定子目录，默认为空, 可通过env改写，如子路径 ROOT=/move

SITE\_URL 包含子目录的网站根地址

HTTP\_PROTOCOL 返回http或者https协议字符串, 可通过env指定

REQUEST\_URI 获取方向代理前的REQUEST\_URI值

扩展
--

[](#扩展)

[传送门](https://github.com/quansitech/qs_cmf/blob/master/docs/Extends.md)

```
部分扩展包会将组件的js/css注入 dashboard_layout 头部

默认只注入路径 T('Admin@default/common/dashboard_layout')
如果项目使用自定义的 layout ，可以通过 QS_INJECT_LAYOUT_PATH 配置需要注入的 layout 路径

```

```
// config.php文件加入以下配置
// 只需要配置自定义的 layout 路径
'QS_INJECT_LAYOUT_PATH' => [
    T('Admin@default/common/letter/layout')
]
```

消息队列
----

[](#消息队列)

[传送门](https://github.com/quansitech/qs_cmf/blob/master/docs/Resque.md)

测试
--

[](#测试)

[传送门](/docs/Testing.md)

#### 压缩前端js代码

[](#压缩前端js代码)

压缩办法很多，这里提供一种配置简单的方式，[传送门](https://gist.github.com/gaearon/42a2ffa41b8319948f9be4076286e1f3)

### HEIC格式图片转JPG格式

[](#heic格式图片转jpg格式)

```
为解决部分组件暂不支持展示heic格式图片，将其转换为jpg

上传到阿里云oss的图片已处理

```

- 使用

    - 复制数据迁移文件*2022\_07\_18\_014941\_alter\_file\_pic\_add\_mime\_type.php*，qs\_file\_pic添加字段 mime\_type
- 扩展包需自行注册并实现heic\_to\_jpg行为

    - 定义行为 ```
          class HeicToJpgBehavior{

          public function run(&$params)
          {
              // $params为qs_file_pic的一条数据
              // 具体逻辑
              $params['url'] = 'your new url';
          }

          }
        ```
    - 注册行为 ```
        \Think\Hook::add('heic_to_jpg', 'xxx\\HeicToJpgBehavior');
        ```

### TRACE\_ERROR

[](#trace_error)

env增加了TRACE\_ERROR配置，如果希望在debug关闭的模式下能收集到错误的报错位置，可以设置为true。这样就无需开启debug模式，也能收集到错误的报错位置。减少日志负担。

### 后台使用react构建页面

[](#后台使用react构建页面)

[传送门](https://github.com/quansitech/qs_cmf/blob/master/react-admin/README.md)

### 静态资源配置CDN

[](#静态资源配置cdn)

[传送门](./doc/InjectCdn.md)

文档
--

[](#文档)

由于工作量大，文档会逐步补全。

lincense
--------

[](#lincense)

[MIT License](https://github.com/tiderjian/lara-for-tp/blob/master/LICENSE.MIT) AND [996ICU License](https://github.com/tiderjian/lara-for-tp/blob/master/LICENSE.996ICU)

###  Health Score

55

—

FairBetter than 98% of packages

Maintenance94

Actively maintained with recent releases

Popularity19

Limited adoption so far

Community20

Small or concentrated contributor base

Maturity76

Established project with proven stability

 Bus Factor1

Top contributor holds 76.4% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~23 days

Recently: every ~61 days

Total

106

Last Release

30d ago

Major Versions

v12.4.1 → v13.0.12023-12-06

v12.4.2 → v13.1.02024-01-31

v12.x-dev → v13.3.02024-10-08

v13.3.0 → v14.0.02024-11-15

14.x-dev → v15.0.02026-04-09

### Community

Maintainers

![](https://www.gravatar.com/avatar/15a0610fee78753bdad92fd45c3506455c0fd45ae51924797b1841d260495a3f?d=identicon)[tiderjian](/maintainers/tiderjian)

---

Top Contributors

[![Xhiny](https://avatars.githubusercontent.com/u/35066497?v=4)](https://github.com/Xhiny "Xhiny (480 commits)")[![tiderjian](https://avatars.githubusercontent.com/u/1665649?v=4)](https://github.com/tiderjian "tiderjian (81 commits)")[![lailixiaoheihong1](https://avatars.githubusercontent.com/u/77043859?v=4)](https://github.com/lailixiaoheihong1 "lailixiaoheihong1 (24 commits)")[![qq958691165](https://avatars.githubusercontent.com/u/13673962?v=4)](https://github.com/qq958691165 "qq958691165 (18 commits)")[![viki719632](https://avatars.githubusercontent.com/u/20202439?v=4)](https://github.com/viki719632 "viki719632 (11 commits)")[![hardykay](https://avatars.githubusercontent.com/u/42793107?v=4)](https://github.com/hardykay "hardykay (7 commits)")[![1041729157](https://avatars.githubusercontent.com/u/35829078?v=4)](https://github.com/1041729157 "1041729157 (3 commits)")[![qian-xiang](https://avatars.githubusercontent.com/u/37764940?v=4)](https://github.com/qian-xiang "qian-xiang (2 commits)")[![minnielove](https://avatars.githubusercontent.com/u/52516935?v=4)](https://github.com/minnielove "minnielove (2 commits)")

---

Tags

gridformadminthinkphp

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/tiderjian-qscmf/health.svg)

```
[![Health](https://phpackages.com/badges/tiderjian-qscmf/health.svg)](https://phpackages.com/packages/tiderjian-qscmf)
```

###  Alternatives

[encore/laravel-admin

laravel admin

11.2k3.1M444](/packages/encore-laravel-admin)[dcat/laravel-admin

dcat admin

4.0k519.0k168](/packages/dcat-laravel-admin)[open-admin-org/open-admin

open-admin. Open-source Laravel Admin panel. No pro or paid package, free &amp; open. Based on laravel-admin, with special thanks to z-song

28464.9k22](/packages/open-admin-org-open-admin)[printnow/laravel-admin

Dcat admin 永久分叉版 / 支持 Laravel 12, PHP 版本限制 &gt;= 8.1（支持 PHP 8.4）

432.0k](/packages/printnow-laravel-admin)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
