Full Code of qincrm/crm for AI

main 8586c15784be cached
100 files
252.7 KB
77.9k tokens
281 symbols
1 requests
Download .txt
Showing preview only (288K chars total). Download the full file or copy to clipboard to get everything.
Repository: qincrm/crm
Branch: main
Commit: 8586c15784be
Files: 100
Total size: 252.7 KB

Directory structure:
gitextract_m3jzydhx/

├── .github/
│   ├── actions/
│   │   └── build-docs/
│   │       ├── Dockerfile
│   │       └── entrypoint.sh
│   └── workflows/
│       ├── codecov.yml
│       ├── docs.yml
│       └── install.yml
├── .gitignore
├── LICENSE.md
├── README.md
├── app/
│   ├── Console/
│   │   ├── Commands/
│   │   │   ├── .gitkeep
│   │   │   ├── Assign.php
│   │   │   ├── Channel.php
│   │   │   └── Mobile.php
│   │   └── Kernel.php
│   ├── Events/
│   │   ├── Event.php
│   │   └── ExampleEvent.php
│   ├── Exceptions/
│   │   └── Handler.php
│   ├── Http/
│   │   ├── Controllers/
│   │   │   ├── AssignController.php
│   │   │   ├── Controller.php
│   │   │   ├── CustomController.php
│   │   │   ├── NoticeController.php
│   │   │   ├── ProductController.php
│   │   │   ├── SystemRoleController.php
│   │   │   ├── SystemTeamController.php
│   │   │   ├── SystemUserController.php
│   │   │   └── UserController.php
│   │   └── Middleware/
│   │       └── AuthMiddleware.php
│   ├── Jobs/
│   │   ├── ExampleJob.php
│   │   └── Job.php
│   ├── Listeners/
│   │   └── ExampleListener.php
│   ├── Models/
│   │   ├── BaseModel.php
│   │   ├── Captcha.php
│   │   ├── Channel.php
│   │   ├── Constants.php
│   │   ├── Customer.php
│   │   ├── CustomerBack.php
│   │   ├── CustomerLog.php
│   │   ├── CustomerRemarkLog.php
│   │   ├── CustomerRuleConfig.php
│   │   ├── Excel/
│   │   │   └── CustomerModel.php
│   │   ├── Notice.php
│   │   ├── Product.php
│   │   ├── SystemDict.php
│   │   ├── SystemFields.php
│   │   ├── SystemLog.php
│   │   ├── SystemRight.php
│   │   ├── SystemRole.php
│   │   ├── SystemRoleRight.php
│   │   ├── SystemSetting.php
│   │   ├── SystemTeam.php
│   │   ├── SystemUser.php
│   │   └── SystemUserRole.php
│   ├── Providers/
│   │   ├── AppServiceProvider.php
│   │   ├── AuthServiceProvider.php
│   │   └── EventServiceProvider.php
│   ├── Services/
│   │   ├── AssignRule/
│   │   │   ├── Rule1.php
│   │   │   ├── Rule10.php
│   │   │   ├── Rule11.php
│   │   │   ├── Rule13.php
│   │   │   ├── Rule2.php
│   │   │   ├── Rule3.php
│   │   │   ├── Rule4.php
│   │   │   ├── Rule5.php
│   │   │   ├── Rule6.php
│   │   │   └── Rule7.php
│   │   ├── AssignService.php
│   │   ├── CustomerEditService.php
│   │   ├── CustomerService.php
│   │   ├── Hook/
│   │   │   └── LoginHook.php
│   │   ├── RightService.php
│   │   ├── SelectService.php
│   │   ├── ToolService.php
│   │   └── UserService.php
│   └── User.php
├── artisan
├── bootstrap/
│   └── app.php
├── composer.json
├── config/
│   ├── database.php
│   ├── logging.php
│   └── session.php
├── database/
│   ├── factories/
│   │   └── ModelFactory.php
│   ├── migrations/
│   │   └── .gitkeep
│   └── seeds/
│       └── DatabaseSeeder.php
├── docs/
│   └── README.md
├── install/
│   ├── crm.sql
│   └── nginx.conf
├── nginx.conf
├── package.json
├── phpunit.xml
├── public/
│   ├── .htaccess
│   ├── index.html
│   ├── index.php
│   └── resource/
│       └── template.xlsx
├── resources/
│   └── views/
│       └── .gitkeep
├── routes/
│   └── web.php
├── storage/
│   ├── app/
│   │   └── .gitignore
│   ├── framework/
│   │   ├── cache/
│   │   │   └── .gitignore
│   │   └── views/
│   │       └── .gitignore
│   └── logs/
│       └── .gitignore
└── tests/
    ├── ExampleTest.php
    └── TestCase.php

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/actions/build-docs/Dockerfile
================================================
FROM phpdoc/phpdoc

LABEL "repository"="https://github.com/qincrm/crm"

LABEL "com.github.actions.name"="Build Docs"
LABEL "com.github.actions.description"="Build Docs with phpDocumentor"
LABEL "com.github.actions.icon"="file-text"
LABEL "com.github.actions.color"="blue"

# don't show errors
RUN echo "display_errors = Off" > $PHP_INI_DIR/conf.d/errors.ini

COPY entrypoint.sh /entrypoint.sh

RUN chmod 755 /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]


================================================
FILE: .github/actions/build-docs/entrypoint.sh
================================================
#!/bin/sh

set -eu

/opt/phpdoc/bin/phpdoc


================================================
FILE: .github/workflows/codecov.yml
================================================
name: codecov

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

permissions:
  contents: read

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - name: Upload coverage reports to Codecov
      uses: codecov/codecov-action@v3

================================================
FILE: .github/workflows/docs.yml
================================================
name: Docs
on:
  push:
    branches:
      - master # disable
permissions: {}
jobs:
  build_and_publish:
    permissions:
      contents: write # to push changes in repo (jamesives/github-pages-deploy-action)

    name: Build and publish Docs
    runs-on: ubuntu-latest
    if: github.repository == 'qincrm/crm'
    steps:
      - name: Checkout sources
        uses: actions/checkout@v3
        with:
          fetch-depth: 1
      - name: Build Docs
        uses: ./.github/actions/build-docs
      - name: Publish Docs to gh-pages
        uses: JamesIves/github-pages-deploy-action@v4
        with:
          branch: gh-pages
          folder: docs
        env:
          BUILD_DIR: docs/
          GH_PAT: ${{ secrets.GH_PAT }}


================================================
FILE: .github/workflows/install.yml
================================================
name: install

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

permissions:
  contents: read

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    
    - name: Setup PHP 7.1.3
      uses: shivammathur/setup-php@v2
      with:
        php-version: '7.1.3'

    - name: Validate composer.json and composer.lock
      run: composer validate --strict

    - name: Cache Composer packages
      id: composer-cache
      uses: actions/cache@v3
      with:
        path: vendor
        key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
        restore-keys: |
          ${{ runner.os }}-php-

    - name: Install dependencies
      run: composer install --prefer-dist --no-progress

    # Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit"
    # Docs: https://getcomposer.org/doc/articles/scripts.md

    # - name: Run test suite
    #   run: composer run-script test


================================================
FILE: .gitignore
================================================
/vendor
/.idea
Homestead.json
Homestead.yaml
.env
.DS_Store


================================================
FILE: LICENSE.md
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
# <img src="https://github.com/qincrm/crm/raw/main/resources/logo.png" width="50px" style="margin-bottom: -12px;"> 司跃CRM [![Code Climate][codeclimate-img-url]][codeclimate-url] [![Github Action](https://github.com/qincrm/crm/workflows/install/badge.svg?f=1)](https://github.com/qincrm/crm/actions/workflows/install.yml) [![Powered by lumen](https://img.shields.io/badge/Powered_by-Lumen-green.svg?style=flat)](https://lumen.laravel.com/) [![Powered by ArcoDesign](https://img.shields.io/badge/Powered_by-ArcoDesign-green.svg?style=flat)](https://github.com/arco-design/arco-design)


[codeclimate-img-url]: https://codeclimate.com/github/qincrm/crm.svg
[codeclimate-url]: https://codeclimate.com/github/qincrm/crm

### 一、CRM系统服务介绍

1、提供适合各行业的CRM系统,支持个性字段定制

2、提升业务精细化运营程度,提高客户转化率,缩短客户成交周期,总体提升中介业绩产能30%以上  

3、源码交付,独立服务器部署,让机构真正意义上拥有自己的CRM系统,把数据掌握在自己手中  

4、系统一次部署,永久使用,不限坐席  

5、灵活API接口配置,支持客户数据直接接入,支持实时撞库排重  

6、支持移动端APP,提高工作效率


### 三、开源版 VS 收费版

||开源版|收费版|
| ------------- | ------------- | ------------- |
|首页|✅|✅|
|客户管理|✅|✅|
|新数据客户管理|✅|✅|
|无效客户管理|✅|✅|
|公共池客户管理|✅|✅|
|运营管理|✅|✅|
|产品管理|✅|✅|
|系统管理|✅|✅|
|任务审批流|❌|✅|
|渠道管理|❌|✅|
|数据报表|❌|✅|
|手机APP(一键外呼)|❌|✅|
|主管点评|❌|✅|
|上门登记二维码|❌|✅|
|前端源码|❌|✅|
|技术支持|❌|✅|

### 四、系统功能概览
 
 ![img1]

[img1]: https://github.com/qincrm/crm/raw/main/resources/1.png 

### 五、系统功能简介

1、登录系统默认进入首页,首页展示当前登录用户名下数据概况,以及部分快捷操作按钮

* 如待办消息提醒、上级点评提醒、在线状态一键切换
 
![img2]

[img2]: https://github.com/qincrm/crm/raw/main/resources/2.png 

2、我的审批,系统支持重要流程系统审批  

* 我发起的审批,支持系统用户查看自己发起的流程,了解审批进度

* 我处理的审批,新审批消息及时提醒、快捷审批

![img3]

[img3]: https://github.com/qincrm/crm/raw/main/resources/3.png 

3、客户管理

* 客户数据销售跟进仅可查看自己名下数据,上级可查看下级名下数据

* 全部客户展示销售顾问名下跟进的所有数据,分配后未跟进的数据,蓝色底色标记置顶优先展示,跟进后的数据不做特殊标记

* 公共池流转出的数据及从其他销售顾问名下流转的数据展示在再分配客户

* 渠道新数据分配,菜单展示数据条数提醒销售顾问及时跟进

* 工作台支持对客户基本信息、资质信息、星级、跟进状态维护;支持对客户进行锁定、标记重要、移入公海、添加待办、维护回款主管点评等操作

![img4]

[img4]: https://github.com/qincrm/crm/raw/main/resources/4.png 

4、新数据公共池&公共池客户

* 渠道新数据无效销售顾问可分配时,数据流入公共池

* 公共池客户为按照系统配置流转规则流入公海的数据

* 公海数据支持批量划转、导入、分配等操作

5、数据管理

* 实时按渠道监控数据星级分布情况,辅助机构调整流量

![img5]

[img5]: https://github.com/qincrm/crm/raw/main/resources/5.png 

6、数据管理—成本、回款、工作日志

* 工作日志按跟进顾问唯独量化销售工作量级,同时监控数据成本及回款情况,辅助机构精细化运营

* 按渠道统计数据的星级、转化情况,辅助机构选择优质渠道,降低获客成本

![img6]

[img6]: https://github.com/qincrm/crm/raw/main/resources/6.png 

7、客户流转规则

* 支持自定义符合机构业务逻辑的客户流转规则,提升客户转化效率

![img7]

[img7]: https://github.com/qincrm/crm/raw/main/resources/7.png 

8、销售顾问跟进数据权限

* 分数据类型设置销售顾问数据上限

![img8]

[img8]: https://github.com/qincrm/crm/raw/main/resources/8.png 

9、渠道管理

* 统一管理系统API数据渠道,撞库渠道,支持增删渠道,快速接入新渠道

![img9]

[img9]: https://github.com/qincrm/crm/raw/main/resources/9.png 

10、产品管理

* 支持维护机构合作产品信息,以及产品要求的信息,辅助销售顾问查看

![img10]

[img10]: https://github.com/qincrm/crm/raw/main/resources/10.png 

11、用户管理

* 用户管理支持对系统用户增、删、改、查;调整用户权限及上下级关系

![img11]

[img11]: https://github.com/qincrm/crm/raw/main/resources/11.png 

12、岗位管理

* 支持按照岗位分配系统权限,系统查看操作权限最小唯独为按钮级别

![img12]

[img12]: https://github.com/qincrm/crm/raw/main/resources/12.png 

13、ip白名单管理

* 非系统白名单ip地址不可登录,有效控制风险

![img13]

[img13]: https://github.com/qincrm/crm/raw/main/resources/13.png

14、 移动APP

![img14]

[img14]: https://github.com/qincrm/crm/raw/main/resources/14.jpg

![img15]

[img15]: https://github.com/qincrm/crm/raw/main/resources/15.jpg

[下载地址](https://github.com/qincrm/crm/releases/download/1.0.0/app-release-v1.0.apk)

### 六、部署说明

* Nginx 1.22.0
* MySQL 5.7.39
* PHP-7.4.30

前端代码: https://github.com/qincrm/crm/releases/tag/1.0.1

NGINX配置: https://github.com/qincrm/crm/blob/main/install/nginx.conf

数据库文件:  https://github.com/qincrm/crm/blob/main/install/crm.sql


### 七、联系我们

1、联系方式:iflooor(同微信)

2、详细问题请微信/电话咨询,可开通相关测试账号,可对系统进行功能演示说明


================================================
FILE: app/Console/Commands/.gitkeep
================================================


================================================
FILE: app/Console/Commands/Assign.php
================================================
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Models\CustomerRuleConfig;

class Assign extends Command
{
    protected $signature = 'assign';
    protected $description = '客户分配策略';

    /**
     * 执行控制台命令
     */
    public function handle() {
        echo date('Y-m-d H:i:s') . ' start.......'.PHP_EOL;
        // 取到所有分配规则
        $model = new CustomerRuleConfig();
        $rules = $model->get();
        foreach ($rules as $rule) {
            $rulename = $rule->name;
            $config = json_decode($rule->config, true);
            $status = $rule->status;
            if ($status == 0) {
                echo $rulename . ':配置关闭' . PHP_EOL;
                continue;
            }
            $ruleClass = '\App\Services\AssignRule\Rule'.$rule->id;
            if (!class_exists($ruleClass)) {
                echo $rulename . ':找不到规则处理器' . PHP_EOL;
                continue;
            }
            echo $rulename . ': 执行开始 ---> ';
            $ruleStrategy = new $ruleClass;
            $result = $ruleStrategy->handle($config);
            if ($result['status'] != 1) {
                echo '异常, '.$result['error'].PHP_EOL;
            } else {
                echo '执行结束'.PHP_EOL;
            }
        }
        echo date('Y-m-d H:i:s') . ' end.......' . PHP_EOL;
    }
}


================================================
FILE: app/Console/Commands/Channel.php
================================================
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Services\CustomerService;

class Channel extends Command
{
    protected $signature = 'channel {--name=}';
    protected $description = '拉取渠道数据';

    /**
     ** 执行控制台命令
     **/
    public function handle() {
        $channelName  = $this->option('name');
        $className = 'App\Services\Channel\\'.ucfirst($channelName).'Channel';
        $channel = new $className();
        $data = $channel->getData();
        $customService = app(CustomerService::class);
        foreach ($data as $item) {
            $customService->addChannelCustomer($item);
        }
    }


}


================================================
FILE: app/Console/Commands/Mobile.php
================================================
<?php

namespace App\Console\Commands;

use App\Models\Customer;
use Illuminate\Console\Command;

class Mobile extends Command
{
    protected $signature = 'mobile';
    protected $description = '手机号重复判断策略';

    /**
     * 给系统里的客户,手机号相同的打标记,表示客户第几次出现
     */
    public function handle() {
        // 获取上次判断到的id
        $id = intval(@file_get_contents("/www/wwwlogs/mobilelog.txt"));
        // 取到所有规则
        $model = new Customer();
        $mobiles = $model->select('id', 'mobile')->where('id', '>', $id)->orderby('id')->get();
        foreach ($mobiles as $mobile) {
            $id = $mobile->id;
            $x = $model->select('anum')->where('id', '<', $mobile->id)->where('mobile', $mobile->mobile)->orderby('id' ,'desc')->take(1)->get()->toArray();
            if ($x && $x[0]) {
                if ($x[0]['anum'] == 0) {
                    $num = $x[0]['anum'] + 2;
                } else {
                    $num = $x[0]['anum'] + 1;
                }
                $model->where('id', $id)->update(['anum' => $num]);
            }
        }
        file_put_contents("/www/wwwlogs/mobilelog.txt", $id);
    }
}


================================================
FILE: app/Console/Kernel.php
================================================
<?php

namespace App\Console;

use Illuminate\Console\Scheduling\Schedule;
use Laravel\Lumen\Console\Kernel as ConsoleKernel;

class Kernel extends ConsoleKernel
{
    /**
     * The Artisan commands provided by your application.
     *
     * @var array
     */
    protected $commands = [
        //
        Commands\Assign::class,
        Commands\Channel::class,
        Commands\Mobile::class,
        Commands\Websocket::class,
    ];

    /**
     * Define the application's command schedule.
     *
     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule)
    {
        //
    }
}


================================================
FILE: app/Events/Event.php
================================================
<?php

namespace App\Events;

use Illuminate\Queue\SerializesModels;

abstract class Event
{
    use SerializesModels;
}


================================================
FILE: app/Events/ExampleEvent.php
================================================
<?php

namespace App\Events;

class ExampleEvent extends Event
{
    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }
}


================================================
FILE: app/Exceptions/Handler.php
================================================
<?php

namespace App\Exceptions;

use Exception;
use Illuminate\Validation\ValidationException;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Laravel\Lumen\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\HttpException;

class Handler extends ExceptionHandler
{
    /**
     * A list of the exception types that should not be reported.
     *
     * @var array
     */
    protected $dontReport = [
        AuthorizationException::class,
        HttpException::class,
        ModelNotFoundException::class,
        ValidationException::class,
    ];

    /**
     * Report or log an exception.
     *
     * This is a great spot to send exceptions to Sentry, Bugsnag, etc.
     *
     * @param  \Exception  $exception
     * @return void
     */
    public function report(Exception $exception)
    {
        parent::report($exception);
    }

    /**
     * Render an exception into an HTTP response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Exception  $exception
     * @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse
     */
    public function render($request, Exception $exception)
    {
        return parent::render($request, $exception);
    }
}


================================================
FILE: app/Http/Controllers/AssignController.php
================================================
<?php

namespace App\Http\Controllers;

use App\Models\CustomerRuleConfig;
use App\Models\SystemDict;
use App\Models\SystemLog;
use App\Models\SystemUser;
use App\Services\AssignService;
use App\Services\SelectService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class AssignController extends Controller
{
    /**
     * 数据分配权限修改
     */
    public function edit(Request $request) {
        $userId = $request->session()->get('user_id');
        $params = $request->all();
        $data = [];
        // 加工下前端数据
        foreach ($params['config']['types'] as $type) {
            $data[$type] = strval($params['config'][$type."Limit"]);
        }
        // 保存权限
        $model = new SystemUser();
        $model = $model->find($params['id']);
        DB::beginTransaction();
        $oldAssignRight = $model->assign_rights;
        $model->assign_rights = json_encode($data);
        $flag = $model->save();
        if ($flag && $oldAssignRight != $model->assign_rights) {
            $logmodel = new SystemLog();
            $logmodel->saveLog($logmodel::TYPE_ASSIGN, $params['id'], $oldAssignRight, $model->assign_rights, $userId, strval($params['config']['remark']));
        }
        DB::commit();
        return $this->apiReturn(static::OK, $data);
    }

    /**
     * 查看数据分配权限修改日志
     */
    public function log(Request $request) {
        $params = $request->all();
        $logmodel = new SystemLog();
        $list = $logmodel->getLogListById($logmodel::TYPE_ASSIGN, $params['id'], $params);
        $service  = app(AssignService::class);
        $data['total'] = $logmodel->getLogCountById($logmodel::TYPE_ASSIGN, $params['id'], $params);
        $model = new SystemUser();
        $allUser = collect($model->getAllUserWithDel())->mapWithKeys(function ($item){
            return [$item['id'] => $item['name']];
        });
        foreach ($list as $key => $item) {
            $item['before'] = $service->genText($item['before']);
            $item['after'] = $service->genText($item['after']);
            $item['user'] = $allUser[$item['user_id']];
            $list[$key] = $item;
        }
        $data['list'] = $list;
        return $this->apiReturn(static::OK, $data);
    }

    /**
     * 数据分配权限修改日志
     */
    public function config(Request $request) {
        $logmodel = new CustomerRuleConfig();
        $dictModel = new SystemDict();
        $list = $logmodel->where('is_del', 0)->orderby('myorder')->get();
        foreach ($list as $key => $item) {
            $config = json_decode($item['config'], true);
            $item['config'] = $config;
            $list[$key] = $item;
        }
        $data['list'] = $list;
        $followStatus = $dictModel->getListByType($dictModel::TYPE_FOLLOW); 
        $starStatus = $dictModel->getListByType($dictModel::TYPE_STAR); 
        $data['followStatus'] = app(SelectService::class)->genSelectByKV($followStatus); // 城市
        $data['starStatus'] = app(SelectService::class)->genSelectByKV($starStatus); // 城市
        return $this->apiReturn(static::OK, $data);
    }

    /**
     * 修改流转规则
     */
    public function editrule (Request $request) {
        $model = new CustomerRuleConfig();
        $params = $request->all();
        $rules = $params['rule'];
        foreach ($rules as $rule) {
            $model->where('id', $rule['id'])->update(['status' => $rule['status'], 'config' => json_encode($rule['config'])]);
        }
        return $this->apiReturn(static::OK, '修改成功');

    }

    /**
     * 修改流转规则状态,开启或关闭
     */
    public function setstatus(Request $request) {
        $model = new CustomerRuleConfig();
        $params = $request->all();
        $model = $model->find($params['id']);
        if (empty($model)) {
            return $this->apiReturn(static::ERROR, [], '操作失败');
        }
        $model->status = $params['status'];
        $model->save();
        return $this->apiReturn(static::OK, '修改成功');

    }
}


================================================
FILE: app/Http/Controllers/Controller.php
================================================
<?php

namespace App\Http\Controllers;

use Laravel\Lumen\Routing\Controller as BaseController;

class Controller extends BaseController
{

    const OK = 20000;
    const ERROR = 50000;
    const APP_OK = 0;

    protected function apiReturn($code = 20000, $data = [], $msg = '', $httpCode = 200) {
        return  response()->json([
            'code' => $code,
            'data' => $data,
            'msg' => $msg
        ], $httpCode);
    }

}


================================================
FILE: app/Http/Controllers/CustomController.php
================================================
<?php

namespace App\Http\Controllers;

use App\Models\Constants;
use App\Models\Customer;
use App\Models\CustomerBack;
use App\Models\CustomerLog;
use App\Models\CustomerRemarkLog;
use App\Models\Excel\CustomerModel;
use App\Models\Notice;
use App\Models\SystemDict;
use App\Models\SystemTeam;
use App\Models\SystemUser;
use App\Services\CustomerEditService;
use App\Services\CustomerService;
use App\Services\RightService;
use App\Services\ToolService;
use App\Services\SelectService;
use App\Services\UserService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Maatwebsite\Excel\Facades\Excel;

class CustomController extends Controller
{
    /**
     * 客户列表
     */
    public function list(Request $request)
    {
        $userId = $request->session()->get('user_id');
        $data = [];
        $dictModel = new SystemDict();
        $userModel = new SystemUser();
        $customModel = new Customer();
        $customerRemarkLog = new CustomerRemarkLog();
        
        $teammodel = new SystemTeam();
        $allTeamListSelect = $teammodel->getAllTeam();
        $followTeamArray = collect($allTeamListSelect)->mapWithKeys(function ($item) {
            return [$item['id'] => $item['name']];
        })->toArray();
        // 获取客户维度的码表
        $customGourpDict = $dictModel->getListByGroup($dictModel::GROUP_CUSTOM); 
        $data['cityList'] = app(SelectService::class)->genSelectByKV($customGourpDict[$dictModel::TYPE_CITY]); // 城市
        $data['followStatusList'] = app(SelectService::class)->genSelectByKV($customGourpDict[$dictModel::TYPE_FOLLOW]); // 跟进状态
        $data['starList'] = app(SelectService::class)->genSelectByKV($customGourpDict[$dictModel::TYPE_STAR]); // 星级
        $data['userFromList'] = app(SelectService::class)->genSelectByKV($customGourpDict[$dictModel::TYPE_USER_FROM]); // 用户来源
        $data['sourceList'] = app(SelectService::class)->genSelectByKV($customGourpDict[$dictModel::TYPE_SOURCE]); // 渠道来源
        $data['zizhiList'] = app(SelectService::class)->genSelectByKV($customGourpDict[$dictModel::TYPE_QUALIFICATION]); // 资质说明
        $data['teamList'] = app(SelectService::class)->genSelectByKV($followTeamArray); // 转成前端的select

        // 筛选项
        $params = $request->all();
        $export = $params['export'];
        $data['master'] = 0;
        $followUserArray = app(RightService::class)->getCustomViews($userId);
        if ($followUserArray == 'all') {
            $followUserList = $userModel->getAllUser();
            $followUserArray = collect($followUserList)->mapWithKeys(function ($item) {
                return [$item['id'] => $item['name']];
            })->toArray();
            $data['master'] = 1;
        } else {
            $params['users'] = array_keys($followUserArray);
        }
        $data['followUserList'] = app(SelectService::class)->genSelectByKV($followUserArray); // 转成前端的select


        // 加工显示项目
        $list = $customModel->getLists($params);
        $customIds = [];
        foreach ($list as $key => $item) {
            $customIds[] = $item['id'];
            $item['notFollowTime'] = app(CustomerService::class)->getNotFollowTime($item);
            $item['apply_time'] = empty($item['apply_time']) ? '-' : date('Y-m-d H:i:s', $item['apply_time']);
            $item['follow_time'] = empty($item['follow_time']) ? '-' : date('Y-m-d H:i:s', $item['follow_time']);
            $item['assign_time'] = empty($item['assign_time']) ? '-' : date('Y-m-d H:i:s', $item['assign_time']);
            $item['zizhi'] = app(CustomerService::class)->genZizhi($item);
            if ($item['star'] == -1) {
                $item['starcolor'] = 'lime';
            } else {
                $item['starcolor'] = Constants::TAG_COLOR[$item['star']] ?? '';
            }
            $item['star'] = $customGourpDict[$dictModel::TYPE_STAR][$item['star']] ?? '';
            $item['fstatuscolor'] = Constants::TAG_COLOR[$item['follow_status']];
            $item['follow_status'] = $customGourpDict[$dictModel::TYPE_FOLLOW][$item['follow_status']] ?? '-';
            $item['user_from'] = $customGourpDict[$dictModel::TYPE_USER_FROM][$item['user_from']];
            $item['source_id'] = $item['source'];
            $item['source'] = $customGourpDict[$dictModel::TYPE_SOURCE][$item['source']];
            $item['follow_user'] = $followUserArray[$item['follow_user_id']];
            $item['age']  = empty($item['age']) ? '' : $item['age'];
            $item['amount']  = $item['amount'] == 0 ? '' : intval($item['amount']);
            $item['city'] = $customGourpDict[$dictModel::TYPE_CITY][$item['city']] ?? '-';
            $remarks = $customerRemarkLog->getLogListByCustomerId($item['id'], $export ? 100 : 3);
            $item['remark'] = implode($export ? "\n":"<br/>", collect($remarks)->map(function($item) use ($followUserArray, $export) {
                return $item->remark . ($export ? "[".$item->create_time.":".$followUserArray[$item['user_id']]."]" : "");
            })->toArray());
            $list[$key] = $item;
        }
        $data['list'] = $list;
        $data['customIds'] = base64_encode(implode('-', $customIds));
        $data['total'] = $customModel->getCount($params);
        if ($export == 1) {
            app(ToolService::class)->csv(
                "我的客户",
                [
                    "id" => "id",
                    "name" => "姓名",
                    "mobile" => "手机号",
                    "star" => "星级",
                    "source" => "渠道",
                    "follow_status" => "跟进状态",
                    "remark" => "跟进备注"  ,
                    "follow_time" => "最新跟进时间" ,
                ],
                $list
            );
        }
        return $this->apiReturn(static::OK, $data);
    }


    /**
     * 获取用户信息
     */
    public function info(Request $request)
    {
        $userId = $request->session()->get('user_id');
        $color = ['', 'green', 'blue', 'purple', 'pinkpurple', 'red'];
        $params = $request->all();

        $dictModel = new SystemDict();
        $customModel = new Customer();

        // 获取客户维度的码表
        $customGourpDict = $dictModel->getListByGroup($dictModel::GROUP_CUSTOM); 
        $data['cityList'] = app(SelectService::class)->genSelectByKV($customGourpDict[$dictModel::TYPE_CITY]); // 城市
        $data['followStatusList'] = app(SelectService::class)->genSelectByKV($customGourpDict[$dictModel::TYPE_FOLLOW]); // 跟进状态
        $data['starList'] = app(SelectService::class)->genSelectByKV($customGourpDict[$dictModel::TYPE_STAR]); // 星级
        $data['userFromList'] = app(SelectService::class)->genSelectByKV($customGourpDict[$dictModel::TYPE_USER_FROM]); // 用户来源
        $data['sourceList'] = app(SelectService::class)->genSelectByKV($customGourpDict[$dictModel::TYPE_SOURCE]); // 渠道来源
        $data['zizhiList'] = app(SelectService::class)->genSelectByKV($customGourpDict[$dictModel::TYPE_QUALIFICATION]); // 资质说明
        $data['workList'] = app(SelectService::class)->genSelectByKV($customGourpDict[$dictModel::TYPE_WORK]); // 工作类型
        $data['noticesList'] = app(SelectService::class)->genSelectByKV($customGourpDict[$dictModel::TYPE_NOTICE]); // 通知类型
        $logList = [];

        if (isset($params['id']) && !empty($params['id'])) {
            $model = $customModel->find($params['id']);
            $followUserArray = app(RightService::class)->getCustomViews($userId);
            // 防止越权
            if (!in_array($model->follow_user_id, array_keys($followUserArray))) {
                return $this->apiReturn(static::ERROR, [], '无客户权限');
            }
            ToolService::unsetEmptyField($model, ['sex', 'age', 'marry', 'work', 'live_area', 'household_area', 'income', 'amount', 'follow_status', 'star', 'city']);
            unset($model['remark']);

            // 客户操作日志大杂烩
            $logmodel = new CustomerLog();
            $logList = $logmodel->getLogListByCustomerId($params['id'], 100);
            foreach ($logList as $key => $log) {
                $log->color = $color[($log->type % 5) + 1];
                $log->type = $logmodel::TYPE_MAPPING[$log->type]." (".$log->username.")";
                $log->day = $log->create_time;
                $logList[$key] = $log;
            }
        } else {
            $model = new Customer();
        }
        $data['customInfo'] = $model;
        $data['logList'] = $logList;

        return $this->apiReturn(static::OK, $data);
    }


    /**
     * 修改用户信息
     */
    public function edit(Request $request)
    {
        $params = $request->all();

        unset($params['notices']);
        unset($params['update_time']);

        $operUserId = $request->session()->get('user_id');

        $service = app(CustomerEditService::class);

        DB::beginTransaction();

        if (isset($params['id'])) {
            $result = $service->edit($params, $operUserId);
        } else {
            $result = $service->add($params, $operUserId);
        }

        if ($result['status'] == 1) {
            DB::commit();
        } else {
            DB::rollBack();
            return $this->apiReturn(static::ERROR, [], $result['error']);
        }

        return $this->apiReturn(static::OK, [], "操作成功");
    }


    /**
     * 客户分配
     */
    public function assign(Request $request)
    {
        $params = $request->all();
        $operUserId = $request->session()->get('user_id');

        $followUserId = $params['followUserId'];
        $customIds = $params['customIds'];

        $customService = app(CustomerService::class);

        foreach ($customIds as $customId) {
            if (!$customService->canAssign($customId)) {
                $model = new Customer();
                $custom = $model->find($customId);
                return $this->apiReturn(static::ERROR, [], $custom['name']."(".$customId.")正在跟进中,暂时无法分配");
            }
            $flag = $customService->assign($customId, $followUserId, $operUserId);
            if (!$flag) {
                return $this->apiReturn(static::ERROR, [], "部分客户分配失败,请刷新重试");
            }
        }

        return $this->apiReturn(static::OK);
    }

    /**
     * 客户认领
     */
    public function get(Request $request)
    {
        $params = $request->all();
        $operUserId = $request->session()->get('user_id');
        $customId = $params['id'];

        $customService = app(CustomerService::class);
        $userService = app(UserService::class);

        $leftCount = $userService->getGetLeftTime($operUserId);
        if ($leftCount <= 0) {
            return $this->apiReturn(static::ERROR, [], "客户认领失败,超过今日认领上限");
        }
        if (!$customService->canAssign($customId)) {
            $model = new Customer();
            $custom = $model->find($customId);
            return $this->apiReturn(static::ERROR, [], $custom['name']."(".$customId.")正在跟进中,暂时无法分配");
        }

        $flag = $customService->get($customId, $operUserId, $operUserId);
        if (!$flag) {
            return $this->apiReturn(static::ERROR, [], "客户认领失败,请刷新重试");
        }

        return $this->apiReturn(static::OK);
    }


    /**
     * 分配记录LIST
     */
    public function assignlist(Request $request)
    {

        $params = $request->all();
        $userModel = new SystemUser();
        $logModel = new CustomerLog();

        $followUserList = $userModel->getAllUserWithDel();
        $followUserArray = ($followUserList)->mapWithKeys(function ($item) {
            return [$item['id'] => $item['name']];
        })->toArray();

        $list = $logModel->getLogListByCustomerIdAndType($params['customId'], $logModel::TYPE_ASSIGN, $params);
        foreach ($list as $key => $item) {
            $item['old_user'] = $followUserArray[$item['before']];
            $item['new_user'] = $followUserArray[$item['after']];
            $item['oper_user'] = $followUserArray[$item['user_id']];
            $item['type'] = CustomerService::ASSIGN_TYPE_MAPPING[$item['remark']];
            $list[$key] = $item;
        }
        $data['list'] = $list;
        $data['total'] = $logModel->getCountByCustomerIdAndType($params['customId'], $logModel::TYPE_ASSIGN);
        return $this->apiReturn(static::OK, $data);
    }



    /**
     * 跟进记录LIST
     */
    public function followlist(Request $request)
    {

        $params = $request->all();
        $dict = new SystemDict();
        $userModel = new SystemUser();
        $logModel = new CustomerLog();

        $followUserList = $userModel->getAllUserWithDel();
        $followUserArray = collect($followUserList)->mapWithKeys(function ($item) {
            return [$item['id'] => $item['name']];
        })->toArray();

        $customGourpDict = $dict->getListByGroup($dict::GROUP_CUSTOM); // 获取城市信息配置

        $list = $logModel->getLogListByCustomerIdAndType($params['customId'], $logModel::TYPE_FOLLOW, $params);
        foreach ($list as $key => $item) {
            $item['old_status'] = $customGourpDict[$dict::TYPE_FOLLOW][$item['before']];
            $item['new_status'] = $customGourpDict[$dict::TYPE_FOLLOW][$item['after']];
            $item['oper_user'] = $followUserArray[$item['user_id']];
            $list[$key] = $item;
        }
        $data['list'] = $list;
        $data['total'] = $logModel->getCountByCustomerIdAndType($params['customId'], $logModel::TYPE_FOLLOW);
        return $this->apiReturn(static::OK, $data);
    }



    /**
     * 星级变化记录
     */
    public function starlist(Request $request)
    {

        $params = $request->all();
        $dict = new SystemDict();
        $userModel = new SystemUser();
        $logModel = new CustomerLog();

        $followUserList = $userModel->getAllUserWithDel();
        $followUserArray = collect($followUserList)->mapWithKeys(function ($item) {
            return [$item['id'] => $item['name']];
        })->toArray();
        $customGourpDict = $dict->getListByGroup($dict::GROUP_CUSTOM); // 获取城市信息配置

        $list = $logModel->getLogListByCustomerIdAndType($params['customId'], $logModel::TYPE_STAR, $params);
        foreach ($list as $key => $item) {
            $item['old_value'] = $customGourpDict[$dict::TYPE_STAR][$item['before']];
            $item['new_value'] = $customGourpDict[$dict::TYPE_STAR][$item['after']];
            $item['oper_user'] = $followUserArray[$item['user_id']];
            $list[$key] = $item;
        }
        $data['list'] = $list;
        $data['total'] = $logModel->getCountByCustomerIdAndType($params['customId'], $logModel::TYPE_STAR);
        return $this->apiReturn(static::OK, $data);
    }



    /**
     * 锁定
     */
    public function lock(Request $request) {
        $userId = $request->session()->get('user_id');
        $params = $request->all();
        DB::beginTransaction();
        $model = Customer::find($params['id']);
        $model->lock = $params['lock'];
        $model->save();
        $logmodel = new CustomerLog();
        $logmodel->saveLog($model->lock == 1 ? $logmodel::TYPE_LOCK: $logmodel::TYPE_UNLOCK, $params['id'], '', '', $userId, '');
        DB::commit();
        return $this->apiReturn(static::OK);
    }

    /**
     * 移入公海 
     */
    public function giveup(Request $request) {
        $userId = $request->session()->get('user_id');
        $params = $request->all();
        $customService = app(CustomerService::class);
        $customService->giveup($params['id'], $userId, '移入公海');
        return $this->apiReturn(static::OK);
    }


    /**
     * 批量移入公海 
     */
    public function batchgiveup(Request $request) {
        $userId = $request->session()->get('user_id');
        $params = $request->all();
        $customIds = $params['customIds'];
        DB::beginTransaction();
        foreach ($customIds as $customId) {
            $customService = app(CustomerService::class);
            $customService->giveup($customId, $userId, '移入公海');
        }
        DB::commit();
        return $this->apiReturn(static::OK);
    }


    /**
     * 批量领取
     */
    public function batchget(Request $request) {
        $userId = $request->session()->get('user_id');
        $params = $request->all();
        $customIds = $params['customIds'];
        $customService = app(CustomerService::class);
        $userService = app(UserService::class);
        $leftCount = $userService->getGetLeftTime($userId);
        if ($leftCount < count($customIds)) {
            return $this->apiReturn(static::ERROR, [], "认领失败,超过今日认领上限,今日剩余".$leftCount."认领名额");
        }
        DB::beginTransaction();
        foreach ($customIds as $customId) {
            if (!$customService->canAssign($customId)) {
                $model = new Customer();
                $custom = $model->find($customId);
                return $this->apiReturn(static::ERROR, [], $custom['name']."(".$customId.")正在跟进中,暂时无法分配");
            }
            $customService->get($customId, $userId, $userId);
        }
        DB::commit();
        return $this->apiReturn(static::OK);
    }

    /**
     * 设为重要
     */
    public function important(Request $request) {
        $userId = $request->session()->get('user_id');
        $params = $request->all();
        DB::beginTransaction();
        $model = Customer::find($params['id']);
        $model->important = $params['important'];
        $model->save();
        $logmodel = new CustomerLog();
        $logmodel->saveLog($model->important == 1 ? $logmodel::TYPE_IMPORTANT : $logmodel::TYPE_NOT_IMPORTANT, $params['id'], '', '', $userId, '');
        DB::commit();
        return $this->apiReturn(static::OK);
    }

    /**
     * 设为无效
     */
    public function lahei(Request $request) {
        $userId = $request->session()->get('user_id');
        $params = $request->all();
        $model = Customer::find($params['id']);
        $model->status = $params['status'];
        $model->save();
        $logmodel = new CustomerLog();
        $logmodel->saveLog($model->status == 1 ? $logmodel::TYPE_NOT_UNVALID : $logmodel::TYPE_UNVALID, $params['id'], '', '', $userId, '');
        return $this->apiReturn(static::OK);
    }

    /**
     * 批量导入用户
     */
    public function upload(Request $request) {
        $files = ($request->file());
        $fileName = array_keys($files)[0];
        if (!in_array($fileName, ['CustomerPool', 'CustomerNewpool'])) {
            return $this->apiReturn(static::ERROR, [], "入口异常,请刷新重试");
        }
        try {
            $data = Excel::toArray(new CustomerModel, $request->file($fileName))[0];
        } catch (\Exception $e) {
            return $this->apiReturn(static::ERROR, [], "文件格式异常请重试");
        }
        array_shift($data);
        if (empty($data)) {
            return $this->apiReturn(static::ERROR, [], "客户信息为空");
        }
        $service = app(\App\Services\CustomerService::class);
        $error = [];
        $customs = [];
        $dict = new SystemDict();
        $customGourpDict = $dict->getListByGroup($dict::GROUP_CUSTOM); // 获取城市信息配置
        $index = 1;
        $mobiles = [];
        $times = 0;
        $success = 0;
        foreach ($data as $row) {
            $customCheck = $service->genCustomByExcelRow($row, $customGourpDict);
            if ($customCheck['status'] == 1) {
                if ($fileName == 'CustomerNewpool') {
                    $customCheck['custom']['user_from'] = 1;
                } else if ($fileName == 'CustomerPool') {
                    $customCheck['custom']['user_from'] = 2;
                }
                $customCheck['custom']['mobile_md5'] = md5($customCheck['custom']['mobile']);
                $customCheck['custom']['source'] = intval(Constants::EXPORT_CHANNEL);
                if (in_array($customCheck['custom']['mobile'], $mobiles) || count(Customer::where('mobile', $customCheck['custom']['mobile'])->get()) > 0) {
                    $times++;
                } else {
                    $success++;
                    $customs[] = $customCheck['custom'];
                }
            } else {
                $error[] = "第".$index."行:".implode(PHP_EOL, $customCheck['error']);
            }
            $index++;
        }
        if (empty($error)) {
            (new Customer())->insert($customs);
            return $this->apiReturn(static::OK, [], '导入成功'.$success.'个客户, 重复'.$times.'个');
        } else {
            return $this->apiReturn(static::ERROR, [], implode(PHP_EOL, $error));
        }
        
    }

    /**
     * 待办事项列表
     */
    public function getNoticeList (Request $request) {
        $params = $request->all();
        $userId = $request->session()->get('user_id');
        $customId = $params['id'];
        $notice = new Notice();
        $list = $notice->getListByUserIdAndCustomer($customId, $userId, 3);
        $color = ['', 'green', 'blue', 'purple', 'pinkpurple', 'red'];
        $dict = new SystemDict();
        $customGourpDict = $dict->getListByGroup($dict::GROUP_CUSTOM); // 获取城市信息配置
        foreach ($list as $key => $item) {
            $item['color'] = $color[$item['type']];
            $item['type'] = $customGourpDict[$dict::TYPE_NOTICE][$item['type']];
            $item['day'] = date('Y-m-d H:i:s', $item['date']);
            $list[$key] = $item;
        }
        return $this->apiReturn(static::OK, ['list'=>$list]);
    }

    /**
     * 增加代办事项
     */
    public function addNotices(Request $request) {
        $userId = $request->session()->get('user_id');
        $params = $request->all();
        $customId = $params['id'];
        $notices = $params['notices'];
        DB::beginTransaction();
        foreach ($notices as $notice) {
            if (empty($notice['date'])) {
                DB::rollBack();
                return $this->apiReturn(static::ERROR, [], "请选择日期");
            }
            if (empty($notice['remark'])) {
                DB::rollBack();
                return $this->apiReturn(static::ERROR, [], "请输入备注");
            }
            $noticeModel = new Notice();
            $noticeModel->date = strtotime($notice['date']);
            $noticeModel->custom_id = $customId;
            $noticeModel->follow_user_id = $userId;
            $noticeModel->type = $notice['type'];
            $noticeModel->remark = $notice['remark'];
            $flag = $noticeModel->save();
            if (!$flag) {
                DB::rollBack();
                return $this->apiReturn(static::ERROR, [], "日程写入失败");
            }
        }
        DB::commit();
        return $this->apiReturn(static::OK);

    }
    
    /**
     * 添加点评
     */
    public function addDianping(Request $request) {
        $params = $request->all();
        $customId = $params['id'];
        $userId = $request->session()->get('user_id');
        $logmodel = new CustomerLog();
        $logmodel->saveLog($logmodel::TYPE_DIANPING, $params['id'], '', '', $userId, $params['remark']);
        $custom = Customer::find($customId);
        $noticeModel = new Notice();
        $noticeModel->date = time();
        $noticeModel->custom_id = $customId;
        $noticeModel->follow_user_id = $custom['follow_user_id'];
        $noticeModel->type = 5;
        $noticeModel->remark = $params['remark'];
        $noticeModel->save();
        DB::commit();
        return $this->apiReturn(static::OK);
    }

    /**
     * 添加回款
     */
    public function addBack(Request $request) {
        $params = $request->all();
        $userId = $request->session()->get('user_id');
        $customId = $params['id'];
        $model = Customer::find($params['id']);
        $backmodel = new CustomerBack();
        if ($errorMsg = ToolService::checkParams($params, [
            'date' => '放款时间',
            'amount' => '放款金额',
            'agency_fee' => '点位',
            'realmoney' => '实际创收',
        ])) {
            return $this->apiReturn(static::ERROR, [], $errorMsg);
        }
        $backmodel->custom_id = $params['id'];
        $backmodel->date = strtotime($params['date']);
        $backmodel->amount = $params['amount'];
        $backmodel->fee = $params['agency_fee'];
        $backmodel->real_amount = $params['realmoney'];
        $backmodel->remark = $params['remark'];
        $backmodel->cost = $params['cost'];
        $backmodel->quanzheng = $params['quanzheng'];
        $backmodel->apply_date = intval($model->apply_time);
        $backmodel->apply_amount = floatval($model->amount);
        $backmodel->follow_user_id = intval($model->follow_user_id);
        $backmodel->oper_user_id = $userId;
        $backmodel->hetong = $params['hetong'];
        $backmodel->product_id= intval($params['product_id']);
        $backmodel->status = 1;
        $backmodel->save();
        $logModel = new CustomerLog();
        $logModel->saveLog($logModel::TYPE_BACK, $params['id'], '', '', $userId, "金额:".$params['amount']);
        return $this->apiReturn(static::OK);

    }


    /**
     * 编辑回款
     */
    public function editBack(Request $request) {
        $params = $request->all();
        $userId = $request->session()->get('user_id');
        $backmodel = new CustomerBack();
        $backmodel = $backmodel->find($params['id']);
        if (empty($params['id']) || empty($backmodel)) {
            return $this->apiReturn(static::ERROR, [], "参数错误,请刷新重试");
        }
        if ($errorMsg = ToolService::checkParams($params, [
            'date' => '放款时间',
            'amount' => '放款金额',
            'agency_fee' => '点位',
            'realmoney' => '实际创收',
        ])) {
            return $this->apiReturn(static::ERROR, [], $errorMsg);
        }
        $backmodel->date = strtotime($params['date']);
        $backmodel->amount = $params['amount'];
        $backmodel->fee = $params['agency_fee'];
        $backmodel->real_amount = $params['realmoney'];
        $backmodel->remark = $params['remark'];
        $backmodel->cost = $params['cost'];
        $backmodel->hetong = $params['hetong'];
        $backmodel->product_id= intval($params['product_id']);
        $backmodel->save();
        return $this->apiReturn(static::OK);

    }

    /**
     * 编辑回款
     */
    public function delBack(Request $request) {
        $params = $request->all();
        $backmodel = new CustomerBack();
        $backmodel = $backmodel->find(intval($params['id']));
        $backmodel->delete();
        return $this->apiReturn(static::OK);

    }
    /**
     * 回款列表
     */
    public function backlist(Request $request)
    {

        $params = $request->all();
        $dict = new SystemDict();
        $userModel = new SystemUser();
        $model = new CustomerBack();

        $followUserList = $userModel->getAllUserWithDel();
        $followUserArray = collect($followUserList)->mapWithKeys(function ($item) {
            return [$item['id'] => $item['name']];
        })->toArray();
        $customGourpDict = $dict->getListByGroup($dict::GROUP_CUSTOM); // 获取城市信息配置

        $list = $model->getLists($params);
        foreach ($list as $key => $item) {
            $item['apply_amount'] = $item['apply_amount'] ? $item['apply_amount'] : '';
            $item['fee'] = $item['fee'] . '%';
            $item['apply_date'] = $item['apply_date'] ? date('Y-m-d H:i:s', $item['apply_date']) : '';
            $item['date'] = $item['date'] ? date('Y-m-d H:i:s', $item['date']) : '';
            $item['new_value'] = $customGourpDict[$dict::TYPE_STAR][$item['after']];
            $item['oper_user'] = $followUserArray[$item['oper_user_id']];
            $list[$key] = $item;
        }
        $data['list'] = $list;
        $data['total'] = $model->getCount($params);
        return $this->apiReturn(static::OK, $data);
    }
    

    /**
     * 认领后未跟进
     */
    public function follownum(Request $request)
    {
        $userId = $request->session()->get('user_id');
        $data = ['custom_num'=>0, 'approve_num'=>0];
        if ($userId > 0) {
            $model = new Customer();
            $data['custom_num'] =  $model->getWaitForFollow($userId);
        }
        return $this->apiReturn(static::OK, $data);
    }



     /**
     * 统计数据 
     */
    public function data(Request $request)
    {
        $userId = $request->session()->get('user_id');
        $userModel = new SystemUser();
        $customModel = new Customer();
        $data = [];
        
        // 筛选项
        $params = $request->all();
        $data['master'] = 0;
        $followUserArray = app(RightService::class)->getCustomViews($userId);
        if ($followUserArray == 'all') {
            $followUserList = $userModel->getAllUser();
            $followUserArray = collect($followUserList)->mapWithKeys(function ($item) {
                return [$item['id'] => $item['name']];
            })->toArray();
            $data['master'] = 1;
        } else {
            $params['users'] = array_keys($followUserArray);
        }
        $data['followUserList'] = app(SelectService::class)->genSelectByKV($followUserArray); // 转成前端的select

        $data['num1'] = $customModel->getCount(array_merge($params, ['notFollow'=>1]));
        $data['num2'] = $customModel->getCount(array_merge($params, ['notFollow'=>3, 'star'=>6]));
        $data['num3'] = $customModel->getCount(array_merge($params, ['notFollow'=>5, 'star'=>6]));
        $data['num4'] = $customModel->getCount(array_merge($params, ['notFollow'=>7, 'star'=>6]));
        $data['num5'] = $customModel->getCount(array_merge($params, ['notFollow'=>1, 'star'=>6]));
        return $this->apiReturn(static::OK, $data);
    }
}


================================================
FILE: app/Http/Controllers/NoticeController.php
================================================
<?php

namespace App\Http\Controllers;

use App\Models\Customer;
use App\Models\Notice;
use App\Models\SystemDict;
use Illuminate\Http\Request;
use App\Services\RightService;

class NoticeController extends Controller
{
    /**
     * 获取通知信息
     */
    public function unreadlist(Request $request)
    {
        $userId = $request->session()->get('user_id');
        $noticeModel = new Notice();
        $dict = new SystemDict();
        $list = $noticeModel->getUnRead($userId);
        $customGourpDict = $dict->getListByGroup($dict::GROUP_CUSTOM); // 获取城市信息配置
        $returnData = [];
        foreach ($list as $item) {
            $custom = Customer::find($item['custom_id']);
            $returnData[] = [
                'id' => $item['id'],
                'type' => 'notice',
                'title' => $customGourpDict[$dict::TYPE_NOTICE][$item['type']]."(".$custom['name'].")",
                'ntype' => $item['type'],
                'content' => $item['remark'],
                'custom_id' => $item['custom_id'],
                'time' => date('Y-m-d H:i:s', $item['date']),
            ];
        }
        return $this->apiReturn(static::OK, $returnData);
    }

    /**
     * 获取通知信息
     */
    public function list(Request $request)
    {
        $params = $request->all();
        $userId = $request->session()->get('user_id');
        $params['userId'] = $userId;
        $noticeModel = new Notice();
        $dict = new SystemDict();
        $list = $noticeModel->getLists($params);
        $customGourpDict = $dict->getListByGroup($dict::GROUP_CUSTOM); // 获取城市信息配置
        $returnData = [];
        foreach ($list as $key => $item) {
            $custom = Customer::find($item->custom_id);
            $item['name'] = $custom->name;
            $item['type'] = $customGourpDict[$dict::TYPE_NOTICE][$item->type];
            $item['time'] = date('Y-m-d H:i:s', $item->date);
            $item['can_read'] = $item->date > time() ? false : true;
            $list[$key] = $item;
        }
        $returnData['list'] = $list;
        $returnData['total'] = $noticeModel->getCount($params);
        return $this->apiReturn(static::OK, $returnData);
    }

    /**
     * 读信息
     */
    public function read(Request $request)
    {
        $noticeModel = new Notice();
        $noticeModel->read($request->get('ids'));
        return $this->apiReturn(static::OK);
    }
}


================================================
FILE: app/Http/Controllers/ProductController.php
================================================
<?php

namespace App\Http\Controllers;

use App\Models\Product;
use App\Models\SystemUser;
use App\Services\SelectService;
use Illuminate\Http\Request;

class ProductController extends Controller
{
    /**
     * 用户列表
     */
    public function list(Request $request) {
        $model = new Product();
        $list = $model->getLists($request->all());
        $data['total'] = $model->getCount($request->all());
        foreach ($list as $key=>$item) {
            if ($item['amount1'] == 0) {$item['amount1'] = '?';}
            if ($item['amount2'] == 0) {$item['amount2'] = '?';}
            $item['amount'] = $item['amount1'] . ' - '. $item['amount2'];
        }
        $data['list'] = $list;
        return $this->apiReturn(static::OK, $data);
    }

    /**
     * 新增或编辑用户
     */
    public function edit(Request $request) {
        $params = $request->all();
        $model = new Product();
        if (isset($params['id'])) {
            $model = $model->find($params['id']);
        }
        if ($params['amount1']&& $params['amount2'] && $params['amount1'] > $params['amount2']) {
            return $this->apiReturn(static::ERROR, [], '最大额度必须大于最小额度');
        }
        $model->name = $params['name'];
        $model->bank= $params['bank'];
        $model->remark= $params['remark'];
        $model->amount1 = floatval($params['amount1']);
        $model->amount2 = floatval($params['amount2']);
        $model->save();
        return $this->apiReturn(static::OK);
    }

    /**
     * 获取用户信息
     */
    public function info(Request $request) {
        $params = $request->all();
        $model = new Product();
        $allUserListSelect = $model->getAllBank();
        if (isset($params['id'])) {
            $model = $model->find($params['id']);
            if ($model['amount'] == 0) {$model['amount'] = '';}
            if ($model['amount1'] == 0) {$model['amount1'] = '';}
            if ($model['amount2'] == 0) {$model['amount2'] = '';}
        }
        $allUserListSelect = app(SelectService::class)->genSelectByK($allUserListSelect, 'bank'); // 转成前端的select
        return $this->apiReturn(static::OK, ['teamInfo'=>$model, 'allUserListSelect' => $allUserListSelect]);
    }


    /**
     * 新增或编辑用户
     */
    public function del(Request $request) {
        $params = $request->all();
        $model = new Product();
        $usermodel = new SystemUser();
        if (empty($params['id'])) {
            return $this->apiReturn(static::OK);
        }
        $usercount = $usermodel->getUserCountByProductid($params['id']);
        if ($usercount > 0) {
            return $this->apiReturn(static::ERROR, [], '该团队下还有用户,无法删除!');
        }
        $model = $model->find($params['id']);
        $model->status = 0;
        $model->save();
        return $this->apiReturn(static::OK);
    }
}


================================================
FILE: app/Http/Controllers/SystemRoleController.php
================================================
<?php

namespace App\Http\Controllers;

use App\Models\SystemFields;
use App\Models\SystemRight;
use App\Models\SystemRole;
use App\Models\SystemRoleRight;
use App\Models\SystemUser;
use App\Models\SystemUserRole;
use App\Services\RightService;
use App\Services\SelectService;
use App\Services\ToolService;
use Illuminate\Http\Request;

class SystemRoleController extends Controller
{
    /**
     * 角色列表
     */
    public function list(Request $request) {
        $model = new SystemRole();
        $data['list'] = $model->getLists($request->all());
        $data['total'] = $model->getCount($request->all());
        return $this->apiReturn(static::OK, $data);
    }

    /**
     * 新增或编辑用户
     */
    public function edit(Request $request) {
        $params = $request->all();
        $model = new SystemRole();
        $rightModel = new SystemRight();
        $rolerightModel = new SystemRoleRight();
        if (isset($params['id'])) {
            $model = $model->find($params['id']);
        }
        $model->name = $params['name'];
        $model->views = $params['views'] ? $params['views'] : 1;
        $model->fields = implode(",", array_merge((array)$params['fields1'] , (array)$params['fields2'] , (array)$params['fields3']));
        $model->save();
        // 处理权限
        // 获取当当前的权限
        $rights = $rightModel->getRightByRoleId($model->id);
        $oldRights = [];
        foreach ($rights as $right) {
            $oldRights[] = $right->id;
        }
        // 获取新的权限
        $newRights = array_merge((array)$params['rights'], (array)$params['halfrights']);
        // 该新增的权限,改移除的权限
        $delRights = array_diff($oldRights, $newRights);
        $addRights = array_diff($newRights, $oldRights);
        // 删除权限
        $rolerightModel->deleteRights($model->id, $delRights);
        $rolerightModel->addRights($model->id, $addRights);
        return $this->apiReturn(static::OK);
    }

    /**
     * 锁定角色
     */
    public function lock(Request $request) {
        $params = $request->all();
        $model = SystemRole::find($params['id']);
        $model->status = $params['status'];
        $model->save();
        return $this->apiReturn(static::OK);
    }

    /**
     * 获取用户信息
     */
    public function info(Request $request) {
        $params = $request->all();
        $model = new SystemRole();
        $rightModel = new SystemRight();
        $fieldsModel = new SystemFields();
        $selectFieldList = $fieldsModel->getSelect();
        $service = app(RightService::class);
        $selectRightList = $service->getRightTree();
        if (isset($params['id']) && $params['id']) {
            $model = $model->find($params['id']);
            $fields = explode(',', $model['fields']);
            $model['fields1'] = array_values(array_intersect($fields, array_keys($selectFieldList[1]))); 
            $model['fields2'] = array_values(array_intersect($fields, array_keys($selectFieldList[2]))); 
            $model['fields3'] = array_values(array_intersect($fields, array_keys($selectFieldList[3]))); 
            ($selectRightList['leafs'][] = 31);
            $rights = app(ToolService::class)->objColumn($rightModel->getRightByRoleId($params['id']), 'id');
            $model['rights']= array_values(array_intersect($rights, $selectRightList['leafs']));
            $model['halfrights']= array_values(array_diff($rights, $selectRightList['leafs']));
        }
        return $this->apiReturn(static::OK, [
            'roleInfo'=>$model, 
            'selectFieldList1' => app(SelectService::class)->genSelectByKV($selectFieldList[1]), // 转成前端的select
            'selectFieldList2' => app(SelectService::class)->genSelectByKV($selectFieldList[2]), // 转成前端的select
            'selectFieldList3' => app(SelectService::class)->genSelectByKV($selectFieldList[3]), // 转成前端的select
            'selectRightList'=>$selectRightList['tree']
        ]);
    }

    /**
     * 删除用户
     */
    public function delete(Request $request) {
        $params = $request->all();
        $model = new SystemUserRole();
        $count = $model->where('role_id', $params['id'])->count();
        if ($count > 0) {
            return $this->apiReturn(static::ERROR, [], '该账号还有'.$count.'个用户,请转移后再删除');
        }
        $model = SystemRole::find($params['id']);
        $model->is_delete = 1;
        $model->save();
        return $this->apiReturn(static::OK);
    }
}


================================================
FILE: app/Http/Controllers/SystemTeamController.php
================================================
<?php

namespace App\Http\Controllers;

use App\Models\SystemTeam;
use App\Models\SystemUser;
use App\Services\SelectService;
use Illuminate\Http\Request;

class SystemTeamController extends Controller
{
    /**
     * 用户列表
     */
    public function list(Request $request) {
        $model = new SystemTeam();
        $list = $model->getLists($request->all());
        $usermodel = new SystemUser();
        $allUserListSelect = $usermodel->getAllUserWithDel();
        $allUserListSelect = app(SelectService::class)->genKv($allUserListSelect, 'id', 'name'); // 转成前端的select
        $data['total'] = $model->getCount($request->all());
        foreach ($list as $key => $item) {
            $item['manager'] = $allUserListSelect[$item['manager_id']];
            $item['usercount'] = $usermodel->getUserCountByTeamid($item['id']);
            $list[$key] = $item;
        }
        $data['list'] = $list;
        return $this->apiReturn(static::OK, $data);
    }

    /**
     * 新增或编辑用户
     */
    public function edit(Request $request) {
        $params = $request->all();
        $model = new SystemTeam();
        if (isset($params['id'])) {
            $model = $model->find($params['id']);
        }
        $model->name = $params['name'];
        $model->manager_id = $params['manager_id'];
        $model->save();
        return $this->apiReturn(static::OK);
    }

    /**
     * 获取用户信息
     */
    public function info(Request $request) {
        $params = $request->all();
        $model = new SystemTeam();
        if (isset($params['id'])) {
            $model = $model->find($params['id']);
            $model['manager_id'] = empty($model['manager_id']) ? "" : intval($model['manager_id']);
        }
        $usermodel = new SystemUser();
        $allUserListSelect = $usermodel->getAllUser();
        $allUserListSelect = app(SelectService::class)->genSelect($allUserListSelect, 'id', 'name'); // 转成前端的select
        return $this->apiReturn(static::OK, ['teamInfo'=>$model, 'allUserListSelect' => $allUserListSelect]);
    }


    /**
     * 新增或编辑用户
     */
    public function del(Request $request) {
        $params = $request->all();
        $model = new SystemTeam();
        $usermodel = new SystemUser();
        if (empty($params['id'])) {
            return $this->apiReturn(static::OK);
        }
        $usercount = $usermodel->getUserCountByTeamid($params['id']);
        if ($usercount > 0) {
            return $this->apiReturn(static::ERROR, [], '该团队下还有用户,无法删除!');
        }
        $model = $model->find($params['id']);
        $model->status = 0;
        $model->save();
        return $this->apiReturn(static::OK);
    }
}


================================================
FILE: app/Http/Controllers/SystemUserController.php
================================================
<?php

namespace App\Http\Controllers;

use App\Models\Customer;
use App\Models\SystemSetting;
use App\Models\SystemRole;
use App\Models\SystemTeam;
use App\Models\SystemUser;
use App\Models\SystemUserRole;
use App\Services\AssignService;
use App\Services\SelectService;
use App\Services\ToolService;
use App\Services\UserService;
use Illuminate\Http\Request;

class SystemUserController extends Controller
{
    /**
     * 用户列表
     */
    public function list(Request $request) {
        $model = new SystemUser();
        $teammodel = new SystemTeam();
        $list = $model->getLists($request->all());
        $data['total'] = $model->getCount($request->all());
        $allTeamListSelect = $teammodel->getAllTeam();
        $data['allTeamListSelect'] = app(SelectService::class)->genSelect($allTeamListSelect, 'id', 'name'); // 转成前端的select
        foreach ($list as $key => $item) {
            $item['assign_text'] = app(AssignService::class)->genText($item['assign_rights']);
            $list[$key] = $item;
        }
        $data['list'] = $list;
        return $this->apiReturn(static::OK, $data);
    }

    /**
     * 新增或编辑用户
     */
    public function edit(Request $request) {
        $params = $request->all();
        $model = new SystemUser();
        $query = $model->where('mobile', $params['mobile'])->where('id', '!=', $params['id']);
        if (isset($params['id'])) {
            $query = $query->where('is_del', 0);
            $model = $model->find($params['id']);
        } else {
            $defultPwd= "crm123456";
            $model->password_salt = rand(100000, 999999);
            $model->password = md5($defultPwd. $model->password_salt);
        }
        if (count($query->get()) > 0) {
            return $this->apiReturn(static::ERROR, [], '手机号已存在');
        }
        $model->name = $params['name'];
        $model->mobile = $params['mobile'];
        $model->parent_id = intval($params['parent_id']);
        $model->team_id= intval($params['team_id']);
        $model->save();
        return $this->apiReturn(static::OK);
    }

    /**
     * 锁定用户
     */
    public function lock(Request $request) {
        $params = $request->all();
        $model = SystemUser::find($params['id']);
        $model->status = $params['status'];
        $model->save();
        return $this->apiReturn(static::OK);
    }

    /**
     * 锁定用户
     */
    public function resetpwd(Request $request) {
        $params = $request->all();
        $defultPwd= "crm123456";
        $model = SystemUser::find($params['id']);
        $model->password_salt = rand(100000, 999999);
        $model->password = md5($defultPwd. $model->password_salt);
        $model->save();
        return $this->apiReturn(static::OK);
    }


    /**
     * 删除用户
     */
    public function delete(Request $request) {
        $params = $request->all();
        $customModel = new Customer();
        $count = $customModel->where('follow_user_id', $params['id'])->count();
        if ($count > 0) {
            return $this->apiReturn(static::ERROR, [], '该账号还有'.$count.'个跟进中的客户,请转移后再删除');
        }
        $model = SystemUser::find($params['id']);
        $model->is_del = 1;
        $model->save();
        return $this->apiReturn(static::OK);
    }
    /**
     * 获取用户信息
     */
    public function info(Request $request) {
        $userId = $request->session()->get('user_id');
        $params = $request->all();
        $model = new SystemUser();
        $teammodel = new SystemTeam();
        $allUserListSelect = $model->getAllUser($params['id']);
        $allUserListSelect = app(SelectService::class)->genSelect($allUserListSelect, 'id', 'name'); // 转成前端的select
        $allTeamListSelect = $teammodel->getAllTeam();
        $allTeamListSelect = app(SelectService::class)->genSelect($allTeamListSelect, 'id', 'name'); // 转成前端的select
        if (isset($params['id'])) {
            $model = $model->find($params['id']);
            $roleModel = new SystemRole();
            $roles = $roleModel->getRoleByUserId($params['id']);
            $model['roles'] = app(ToolService::class)->objColumn($roles, 'id');
            if (empty($model['team_id'])) {unset($model['team_id']);}
            if (empty($model['parent_id'])) {unset($model['parent_id']);}
        }
        $model['password'] = '';
        $roleModel = new SystemRole();
        $allRole = $roleModel->getRoleSelect();
        $allUser = $model->getAllUser()->toArray();
        $allUserId = array_column($allUser, 'id');
        return $this->apiReturn(static::OK, ['userInfo'=>$model, 'allUserListSelect'=>$allUserListSelect, 'roleList'=>$allRole, 'allTeamListSelect'=>$allTeamListSelect,
            'userTree' => app(UserService::class)->getUserTree(),
            'allUserId' => $allUserId
        ]);
    }

    /**
     * 获取用户角色信息
     */
    public function role(Request $request) {
        $params = $request->all();
        $userId = $params['id'];
        $roleModel = new SystemRole();
        $userroleModel = new SystemUserRole();
        $roles = $roleModel->getRoleByUserId($userId);
        $oldRoleIds = app(ToolService::class)->objColumn($roles, 'id');
        $newRoleIds = $params['roles'];
        // 该新增的权限,改移除的权限
        $delRoleIds = array_diff($oldRoleIds, $newRoleIds);
        $addRoleIds = array_diff($newRoleIds, $oldRoleIds);
        // 删除权限
        $userroleModel->delRoles($userId, $delRoleIds);
        $userroleModel->addRoles($userId, $addRoleIds);
        return $this->apiReturn(static::OK);
    }

    /**
     * 锁定用户
     */
    public function online(Request $request) {
        $userId = $request->session()->get('user_id');
        $params = $request->all();
        $model = SystemUser::find($userId);
        $model->online = $params['online'] ? 1 : 0;
        $model->save();
        return $this->apiReturn(static::OK, [], '操作成功');
    }


    /**
     * 系统设置
     */
    public function setting(Request $request) {
        $userId = $request->session()->get('user_id');
        $params = $request->all();
        $model = SystemSetting::find(1);
        if ($request->isMethod('get')) {
            $roleModel = new SystemRole();
            $allRole = $roleModel->getRoleSelect();
            $roles = explode(",", $model->role_id);
            foreach ($roles as $key=>$r) {
                $roles[$key] = intval($r);
            }
            return $this->apiReturn(static::OK, [
                'setting'=>['ip'=>$model['ip'], 'time'=> [$model->stime.':00', $model->etime.":00"], 'role_id'=>$roles],
                'roles' => $allRole
            ], '操作成功');
        } else {
            $model->ip = $params['ip'];
            $model->stime = $params['time'][0];
            $model->etime = $params['time'][1];
            $model->role_id = implode(",", $params['role_id']);
            $model->save();
            return $this->apiReturn(static::OK, [], '操作成功');
        }
    }
}

================================================
FILE: app/Http/Controllers/UserController.php
================================================
<?php

namespace App\Http\Controllers;

use App\Models\Captcha;
use App\Models\Customer;
use App\Models\CustomerBack;
use App\Models\Notice;
use App\Models\SystemDict;
use App\Models\SystemRight;
use App\Models\SystemTeam;
use App\Models\SystemUser;
use App\Services\Hook\LoginHook;
use App\Services\RightService;
use Illuminate\Http\Request;

class UserController extends Controller
{
    /**
     * 登录
     */
    public function login(Request $request)
    {
        $params = $request->all();
        $userName = $params['username'];
        $password = $params['password'];
        $captcha = $params['captcha'];
        if ($captcha != $request->session()->get('captcha')) {
            return $this->apiReturn(static::ERROR, [], '验证码不正确');
        }
        if (empty($userName) || empty($password)) {
            return $this->apiReturn(static::ERROR, [], "账号或密码错误");
        }
        $user = SystemUser::where('mobile', $userName)->where('status', 1)->where('is_del', 0)->first();
        if (empty($user)) {
            return $this->apiReturn(static::ERROR, [], "账号或密码错误");
        } else if ($user->password != md5($password . $user->password_salt)) {
            return $this->apiReturn(static::ERROR, [], "账号或密码错误");
        }
        if (!LoginHook::canLogin($user->id, $request)){
            return $this->apiReturn(static::ERROR, [], "非法IP, 请联系管理员");
        }
        $page = LoginHook::getPage($user->id);
        $request->session()->put('user_id', $user->id);
        return $this->apiReturn(static::OK, ["token" => 12345, 'page' => $page]);
    }


    /**
     * 退出
     */
    public function logout(Request $request)
    {
        $request->flush();
        return $this->apiReturn(static::OK);
    }

    /**
     * 用户基本信息
     */
    public function info(Request $request)
    {
        $teamModel = new SystemTeam();
        $userModel = new SystemUser();
        $noticeModel = new Notice();

        $userId = $request->session()->get('user_id');
        $userArray = $userModel->getAllUserMap();
        $teamArray = $teamModel->getAllTeamMap();

        $user = SystemUser::where('id', $userId)->first();
        $data = [
            "name" => $user->name,
            "mobile" => $user->mobile,
            "department" => $teamArray[$user->team_id],
            "leader" => $userArray[$user->parent_id],
            "avatar" => '/resource/av.png',
            "online" => $user->online == 1 ? true : false,
            'noticeCount' => $noticeModel->getUnReadCount($userId),
        ];
        return $this->apiReturn(static::OK, $data);
    }

    /**
     * 用户菜单
     */
    public function menu(Request $request)
    {
        $userId = $request->session()->get('user_id');
        $service = app(\App\Services\RightService::class);
        $realMenus = ($service->getRightTree($userId)['tree']);
        // 给一些通过的功能默认加上权限
        $realMenus = array_merge($realMenus, $service->getDefaultRight());
        return $this->apiReturn(static::OK, $realMenus);
    }

    /**
     * 登录
     */
    public function resetpassword(Request $request)
    {
        $params = $request->all();
        $userId = $request->session()->get('user_id');
        $oldpassword = $params['oldpassword'];
        $newpassword = $params['newpassword'];
        $user = SystemUser::find($userId);
        if (empty($user)) {
            return $this->apiReturn(static::ERROR, [], "操作异常,请刷新重试");
        } else if ($user->password != md5($oldpassword . $user->password_salt)) {
            return $this->apiReturn(static::ERROR, [], "旧密码输入错误");
        }
        $user->password = md5($newpassword . $user->password_salt);
        $user->save();
        return $this->apiReturn(static::OK);
    }

    /**
     * 首页
     */
    public function dashboard(Request $request)
    {
        $dict = new SystemDict();
        $customGourpDict = $dict->getListByType($dict::TYPE_NOTICE); // 获取城市信息配置
        $color = ['', 'green', 'blue', 'purple', 'pinkpurple', 'red'];
        $userId = $request->session()->get('user_id');
        $model = new Notice();
        $noticeList = $model->getListByUserId($userId, 10);
        foreach ($noticeList as $key => $notice) {
            $custom = Customer::find($notice->custom_id);
            $notice->color = $color[$notice->type];
            $notice->type = $customGourpDict[$notice->type];
            $notice->day = date('Y-m-d H:i:s', $notice->date);
            $notice->remark = $notice->remark . " (客户姓名:" .$custom['name'] . ")";
            $noticeList[$key] = $notice;
        }
        $users = [];
        $followUserArray = app(RightService::class)->getCustomViews($userId);
        if ($followUserArray != 'all') {
            $users = array_keys($followUserArray);
        }
        $customModel = new Customer();
        $backModel = new CustomerBack();
        $paihangbang = $backModel->getPaihangbang();
        $paihangbang2 = $backModel->getPaihangbang2();
        $chartData = [];
        foreach ($paihangbang2 as $item) {
            $chartData [] = [
                'value' => [$item->cnt],
                'name' => $item->name
            ];
        }
        $index = 1;
        $rightModel = new SystemRight();
        $rights = $rightModel->getRightByUserId($userId);
        $rights = array_column($rights, 'router');
        foreach ($paihangbang as $key=>$item) {
            $item->index = $index;
            $paihangbang[$key] = $item;
            if (!in_array('YejiAmount', $rights)) {
                $item->amount = '';
            }
            if (!in_array('YejiRealAmount', $rights)) {
                $item->real_amount = '';
            }
            $index ++;
        }
        return $this->apiReturn(static::OK, [
            'customer' => $customModel->getMyCount(['users' => $users]),
            'important' => $customModel->getMyCount(['users' => $users, 'important' => 1]),
            'newcustomer' => $customModel->getMyCount(['users' => $users, 'new' => 1]),
            'innercustomer' => $customModel->getMyCount(['users' => $users, 'inner' => 1]),
            'followcustomer' => $customModel->getMyCount(['users' => $users, 'follow_status' => 1]),
            'paihangbang' => $paihangbang,
            'chartData' => $chartData,
            'yeji_list' => [],
            'order_list' => [],
            'notice_list' => $noticeList
        ]);
    }

    /**
     * 验证码
     */
    public function captcha(Request $request) {
        $c = new Captcha();
        $c->create($request);
    }

    /**
     * donoting
     */
    public function donothing(Request $request) {
    }

}


================================================
FILE: app/Http/Middleware/AuthMiddleware.php
================================================
<?php

namespace App\Http\Middleware;

use App\Models\SystemRight;
use App\Models\SystemSetting;
use App\Models\SystemUserRole;
use Closure;
use Illuminate\Support\Facades\Log;

class AuthMiddleware
{

    private $whiteList = ['custom/data', 'user/menu', 'user/online', 'user/info', 'user/resetpassword', 'message/unreadlist', 'message/list', 'message/read', 'user/dashboard', 'custom/getnoticelist','custom/call'];

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $userId = $request->session()->get('user_id', 0);

        if (empty($userId)) {
            echo json_encode(['code'=>50008, 'msg'=>'登录过期,请重新登录']);
            exit;
        }

        $url = str_replace("/api/", "", $request->getPathInfo());
        Log::info("IN1666510036 行为记录: " . $userId . " : " . $url . " : " . $request->ip());

        if (!in_array($url, $this->whiteList)) {
            $right = new SystemRight();
            $menus  = $right->getRightByUserId($userId);
            $hasAuth = false;
            foreach ($menus as $menu) {
                if ($menu->url == $url ) {
                    $hasAuth = true;
                    break;
                }
            }

            if (!$hasAuth) {
                echo json_encode(['code'=>50000, "msg"=>"无操作权限"]);
                exit;
            }
        }

        $model = new SystemUserRole();
        $roles = $model->getRoleByUserId($userId);
        $rolesIds = array_column($roles, 'role_id');

        $setting = SystemSetting::find(1);
        if ($setting['ip']) {
            $ip = explode(",", $setting['ip']) ;
            if (!in_array($request->ip(), $ip) && !in_array(1, $rolesIds)) {
                echo json_encode(['code'=>50008, 'msg' => '非法IP, 请联系管理员']);
                exit;
            }
        }
        

        return $next($request);
    }
}


================================================
FILE: app/Jobs/ExampleJob.php
================================================
<?php

namespace App\Jobs;

class ExampleJob extends Job
{
    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        //
    }
}


================================================
FILE: app/Jobs/Job.php
================================================
<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

abstract class Job implements ShouldQueue
{
    /*
    |--------------------------------------------------------------------------
    | Queueable Jobs
    |--------------------------------------------------------------------------
    |
    | This job base class provides a central location to place any logic that
    | is shared across all of your jobs. The trait included with the class
    | provides access to the "queueOn" and "delay" queue helper methods.
    |
    */

    use InteractsWithQueue, Queueable, SerializesModels;
}


================================================
FILE: app/Listeners/ExampleListener.php
================================================
<?php

namespace App\Listeners;

use App\Events\ExampleEvent;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

class ExampleListener
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param  ExampleEvent  $event
     * @return void
     */
    public function handle(ExampleEvent $event)
    {
        //
    }
}


================================================
FILE: app/Models/BaseModel.php
================================================
<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;

class BaseModel extends Model
{

}


================================================
FILE: app/Models/Captcha.php
================================================
<?php

namespace App\Models;

use Yii;

class Captcha {

    /**
     * 验证码
     * 
     */ 
    public function create($request) {

        $image = imagecreatetruecolor(100, 23);    //1>设置验证码图片大小的函数
        $bgcolor = imagecolorallocate($image,255,255,255); //#ffffff
        imagefill($image, 0, 0, $bgcolor);
        $captcha_code = "";
        for($i=0;$i<4;$i++){
          //设置字体大小
          $fontsize = 6;
          //设置字体颜色,随机颜色
          $fontcolor = imagecolorallocate($image, rand(0,120),rand(0,120), rand(0,120));      //0-120深颜色
          //设置数字
          $fontcontent = rand(0,9);
          //10>.=连续定义变量
          $captcha_code .= $fontcontent;
          //设置坐标
          $x = ($i*100/4)+rand(5,10);
          $y = rand(5,10);

          imagestring($image,$fontsize,$x,$y,$fontcontent,$fontcolor);
        }
        $request->session()->put('captcha', $captcha_code);
        //10>存到session
        //8>增加干扰元素,设置雪花点
        for($i=0;$i<200;$i++){
          //设置点的颜色,50-200颜色比数字浅,不干扰阅读
          $pointcolor = imagecolorallocate($image,rand(50,200), rand(50,200), rand(50,200));
          //imagesetpixel — 画一个单一像素
          imagesetpixel($image, rand(1,99), rand(1,29), $pointcolor);
        }
        //9>增加干扰元素,设置横线
        for($i=0;$i<4;$i++){
          //设置线的颜色
          $linecolor = imagecolorallocate($image,rand(80,220), rand(80,220),rand(80,220));
          //设置线,两点一线
          imageline($image,rand(1,99), rand(1,29),rand(1,99), rand(1,29),$linecolor);
        }

        //2>设置头部,image/png
        header('Content-Type: image/png');
        //3>imagepng() 建立png图形函数
        imagepng($image);
        //4>imagedestroy() 结束图形函数 销毁$image
        imagedestroy($image);
    }

}


================================================
FILE: app/Models/Channel.php
================================================
<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;

class Channel extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'channel';
    public $timestamps = false;
    protected $guarded = [];

}


================================================
FILE: app/Models/Constants.php
================================================
<?php
 
namespace App\Models;
 
/**
 * 定义一些公用的常量
 * 
 */
class Constants
{

    // 标签颜色配置
    const TAG_COLOR = ['', 'green', 'blue', 'purple', 'pinkpurple', 'red', 'green', 'blue', 'purple', 'pinkpurple', 'red', 'green', 'blue', 'purple', 'pinkpurple', 'red', 'green', 'blue', 'purple', 'pinkpurple', 'red', 'green', 'blue', 'purple', 'pinkpurple', 'red', 'green', 'blue', 'purple', 'pinkpurple', 'red'];

    const EXPORT_CHANNEL = 4;
}


================================================
FILE: app/Models/Customer.php
================================================
<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;

class Customer extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'customer';

    protected $guarded = [];

    public $timestamps = false;


    private function _createWhere($params) {
        $query = $this->when(isset($params['name']) && $params['name'] !== "", function ($query) use ($params) {
            return $query->where('name', 'like', '%'.$params['name'].'%');
        })->when(isset($params['mobile']) && $params['mobile'] !== "", function ($query) use ($params) {
            return $query->where('mobile',  $params['mobile']);
        })->when(isset($params['city']) && $params['city'] !== "", function ($query) use ($params) {
            return $query->where('city',  $params['city']);
        })->when(isset($params['followUserId']) && $params['followUserId'] !== "", function ($query) use ($params) {
            return $query->where('follow_user_id',  $params['followUserId']);
        })->when(isset($params['followStatus']) && $params['followStatus'] !== "", function($query) use ($params) {
            return $query->where('follow_status',  $params['followStatus']);
        })->when(isset($params['star']) && $params['star'] !== "", function($query) use ($params) {
            if ($params['star'] == 6) {
                return $query->where('star', '>=', '2');
            } else if ($params['star'] == 7) {
                return $query->where('star', '>=', '3');
            } else if ($params['star'] == 8) {
                return $query->where('star', '>=', '4');
            } else {
                return $query->where('star',  $params['star']);
            }
        })->when($params['custom_ids'], function($query) use ($params) {
            return $query->whereIn('id', $params['custom_ids']);
        })->when(isset($params['userFrom']) && $params['userFrom'] !== "", function($query) use ($params) {
            return $query->where('user_from',  $params['userFrom']);
        })->when(isset($params['source']) && $params['source'] !== "", function($query) use ($params) {
            return $query->where('source',  $params['source']);
        })->when(isset($params['channel']) && $params['channel'] !== "", function($query) use ($params) {
            return $query->where('source',  $params['channel']);
        })->when(isset($params['zizhi']) && is_array($params['zizhi']) && in_array(1, $params['zizhi']), function($query) use ($params) {
            return $query->where('house', "!=", 1);
        })->when(isset($params['zizhi'])  && is_array($params['zizhi']) && in_array(2, $params['zizhi']), function($query) use ($params) {
            return $query->where('car',  "!=", 1);
        })->when(isset($params['zizhi'])  && is_array($params['zizhi']) && in_array(3, $params['zizhi']), function($query) use ($params) {
            return $query->where('policy',  "!=", 1);
        })->when(isset($params['zizhi'])  && is_array($params['zizhi']) && in_array(4, $params['zizhi']), function($query) use ($params) {
            return $query->where('insurance',   "!=",1);
        })->when(isset($params['zizhi'])  && is_array($params['zizhi']) && in_array(5, $params['zizhi']), function($query) use ($params) {
            return $query->where('funds',   "!=",1);
        })->when(isset($params['zizhi'])  && is_array($params['zizhi']) && in_array(6, $params['zizhi']), function($query) use ($params) {
            return $query->where('credit', 1);
        })->when(isset($params['notFollow']) && $params['notFollow']!= '', function($query) use ($params) {
            return $query->where('follow_user_id',  '>', 0)
                        ->where('assign_time', '<', time() - ($params['notFollow'] * 24 *3600))
                        ->where('follow_time', '<', time() - ($params['notFollow'] * 24 *3600));
        })->when(isset($params['createTime']) && !empty($params['createTime']) && is_array($params['createTime']), function($query) use ($params ) {
            $query = $query->where('apply_time',  '>', strtotime($params['createTime'][0]));
            return $query->where('apply_time',  '<', strtotime($params['createTime'][1]));
        })->when(isset($params['followTime']) && !empty($params['followTime']) && is_array($params['followTime']), function($query) use ($params ) {
            $query = $query->where('follow_time',  '>', strtotime($params['followTime'][0]));
            return $query->where('follow_time',  '<', strtotime($params['followTime'][1]));
        })->when($params['type'] == 'CustomerList', function($query) use ($params) {
            return $query->where('follow_user_id', '>' , 0);
        })->when($params['type'] == 'CustomerImportList', function($query) use ($params) {
            $query = $query->where('follow_user_id', '>' , 0);
            return $query->where('important',  1);
        })->when($params['team_id'], function($query) use ($params) {
            $teamModel = new SystemUser();
            $userIds = $teamModel->getUserByTeamid($params['team_id'])->map(function($item) {return $item['id'];});
            return $query->whereIn('follow_user_id', $userIds);
        })->when($params['type'] == 'CustomerNewList', function($query) use ($params) {
            $query = $query->where('follow_user_id', '>' , 0);
            $query = $query->where('important',  0);
            return $query->where('user_from',  1);
        })->when($params['type'] == 'CustomerInnerList', function($query) use ($params) {
            $query = $query->where('follow_user_id', '>' , 0);
            $query = $query->where('important',  0);
            return $query->where('user_from', '!=', 1);
        })->when(isset($params['users']) && in_array($params['type'], ['CustomerImportList', 'CustomerInnerList', 'CustomerNewList', 'CustomerList']), function($query) use ($params) {
            if ($params['users']) {
                return $query->whereIn('follow_user_id',  $params['users']);
            } else {
                return $query->where('follow_user_id', 99999999);
            }
        })->when($params['type'] == 'CustomerNewpool', function($query) use ($params) {
            $query = $query->where('follow_user_id',  0);
            return $query->where('user_from',  1);
        })->when($params['type'] == 'CustomerPool', function($query) use ($params) {
            $query = $query->where('follow_user_id',  0);
            return $query->where('user_from', '!=', 1);
        })->when($params['timeType'] == 1, function($query) use ($params) {
            return $query->where('create_time', '>', date('Y-m-d 00:00:00'));
        })->when($params['timeType'] == 2, function($query) use ($params) {
            return $query->where('create_time', '>', date('Y-m-d 00:00:00', strtotime("-1 day")));
        })->when($params['timeType'] == 3, function($query) use ($params) {
            return $query->where('create_time', '>', date('Y-m-d 00:00:00', strtotime("-2 day")));
        })->when($params['timeType'] == 4, function($query) use ($params) {
            $time = time();
            $monday = date('Y-m-d 00:00:00', ($time - ((date('w',$time) == 0 ? 7 : date('w',$time)) - 1) * 24 * 3600));
            return $query->where('create_time', '>', $monday);
        })->when($params['timeType'] == 5, function($query) use ($params) {
            return $query->where('create_time', '>', date("Y-m-01 00:00:00"));
        })->when($params['timeType'] == 6, function($query) use ($params) {
            $query = $query->where('create_time', '>', $params['times'][0]. ' 00:00:00');
            return $query->where('create_time', '<', $params['times'][1]. ' 00:00:00');
        });
        if ($params['type'] == 'CustomerUnvalid') {
            $query = $query->where('status',  0);
        } else {
            $query = $query->where('status',  1);
        }
        return $query;
    }

    public function getLists($params) {
        $offset = ($params['current'] - 1) * $params['pageSize'];
        $list = $this->_createWhere($params)->select('*', DB::raw('
            (CASE WHEN follow_time > assign_time THEN 1 ELSE 0 END) as is_follow,
            (CASE WHEN follow_time > assign_time THEN id ELSE assign_time END) as order_field 
        '))->orderByRaw("is_follow , order_field desc")->skip($offset)->take($params['pageSize'])->get()->toArray();
        return $list;
    }

    public function getCount($params) {
        return $this->_createWhere($params)->count();
    }

    public function _createChannelWhere($params) {
        $query = $this->when($params['users'], function ($query) use ($params) {
            return $query->whereIn('follow_user_id', $params['users']);
        })->when($params['user_id'], function ($query) use ($params) {
            return $query->where('follow_user_id', $params['user_id']);
        })->when($params['team_id'], function ($query) use ($params) {
            $teamModel = new SystemUser();
            $userIds = $teamModel->getUserByTeamid($params['team_id'])->map(function($item) {return $item['id'];});
            return $query->whereIn('follow_user_id', $userIds);
        })->when($params['source'], function ($query) use ($params) {
            return $query->where('source',  $params['source']);
        })->when($params['timeType'] == 1, function ($query) use ($params) {
            return $query->where('create_time', '>', date('Y-m-d 00:00:00'));
        })->when($params['timeType'] == 2, function ($query) use ($params) {
            $query = $query->where('create_time', '>', date('Y-m-d 00:00:00', strtotime("-1 day")));
            return $query->where('create_time', '<', date('Y-m-d 00:00:00'));
        })->when($params['timeType'] == 3, function ($query) use ($params) {
            return $query->where('create_time', '>', date('Y-m-d 00:00:00', strtotime("-2 day")));
        })->when($params['timeType'] == 4, function ($query) use ($params) {
            $time = time();
            $monday = date('Y-m-d 00:00:00', ($time - ((date('w',$time) == 0 ? 7 : date('w',$time)) - 1) * 24 * 3600));
            return $query->where('create_time', '>', $monday);
        })->when($params['timeType'] == 5, function ($query) use ($params) {
            return $query->where('create_time', '>', date("Y-m-01 00:00:00"));
        })->when($params['timeType'] == 6, function ($query) use ($params) {
            $query = $query->where('create_time', '>', $params['times'][0]. ' 00:00:00');
            return $query->where('create_time', '<', $params['times'][1]. ' 23:59:59');
        });
        return $query;
    }
    public function getListsGroupByChannel($params) {
        return $this->_createChannelWhere($params)->select('source', 'star', DB::raw('count(*) as cnt'))->groupBy('source', 'star')->get();
    }
    public function getListsGroupByChannel2($params) {
        $list = $this->_createChannelWhere($params)->select('source', DB::raw('CASE follow_status WHEN 0 THEN 0 ELSE 1 END as follow_status1'), DB::raw('count(*) as cnt'))
                ->groupBy('source', 'follow_status1')->get();
        return $list;
    }

    public function getMyCount($params) {
        $query = $this->when($params['users'], function ($query) use ($params) {
            return $query->whereIn('follow_user_id', $params['users']);
        })->when($params['important'], function ($query) use ($params) {
            return $query->where('important', $params['important']);
        })->when($params['today'], function ($query) use ($params) {
            return $query->where('assign_time', '>', strtotime(date('Y-m-d')));
        })->when(isset($params['follow_status']) && $params['follow_status'] !== "", function ($query) use ($params) {
            return $query->where('follow_status',  $params['follow_status']);
        })->when($params['new'], function ($query) use ($params) {
            $query = $query->where('follow_user_id', '>' , 0);
            $query = $query->where('important',  0);
            return $query->where('user_from', 1);
        })->when($params['inner'], function ($query) use ($params) {
            $query = $query->where('follow_user_id', '>' , 0);
            $query = $query->where('important',  0);
            return $query->where('user_from', '!=', 1);
        });
        return $query->count();
    }
    public function getCustomerByChannelId($channel, $channelId) {
        return $this->where('source', $channel)->get();
    }
 

    public function getWaitForFollow($userId) {
        $sql = "select count(*) as cnt from customer where follow_user_id = ? and assign_time > follow_time and status = 1 and user_from = 1 and important = 0 and status = 1";
        return intval(app('db')->select($sql, [$userId])[0]->cnt);
    }
 
}


================================================
FILE: app/Models/CustomerBack.php
================================================
<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;

class CustomerBack extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'customer_backs';

    protected $guarded = [];

    public $timestamps = false;

    private function _createWhere($params) {
        $query = $this->leftJoin('customer', 'customer_backs.custom_id', '=', 'customer.id')->where('customer_backs.status', 1);
        if (isset($params['customId']) && !empty($params['customId'])) {
            $query = $query->where('customer_backs.custom_id', $params['customId']);
        }
        if (isset($params['name']) && !empty($params['name'])) {
            $query = $query->where('customer.name', $params['name']);
        }
        if (isset($params['mobile']) && !empty($params['mobile'])) {
            $query = $query->where('customer.mobile', $params['mobile']);
        }
        if (isset($params['follow_user_id']) && !empty($params['follow_user_id'])) {
            $query = $query->where('customer_backs.follow_user_id', $params['follow_user_id']);
        }
        if (isset($params['team_id']) && !empty($params['team_id'])) {
            $teamModel = new SystemUser();
            $userIds = $teamModel->getUserByTeamid($params['team_id'])->map(function($item) {return $item['id'];});
            $query = $query->whereIn('customer_backs.follow_user_id', $userIds);
        }
        if (isset($params['applyTime']) && !empty($params['applyTime']) && is_array($params['applyTime']) ) {
            $query = $query->where('apply_date',  '>', strtotime($params['applyTime'][0]));
            $query = $query->where('apply_date',  '<', strtotime($params['applyTime'][1]));
        }
        if (isset($params['backTime']) && !empty($params['backTime']) && is_array($params['backTime']) ) {
            $query = $query->where('date',  '>', strtotime($params['backTime'][0]));
            $query = $query->where('date',  '<', strtotime($params['backTime'][1]));
        }
        return $query;
    }

    public function getLists($params) {
        $offset = ($params['current'] - 1) * $params['pageSize'];
        $list = $this->_createWhere($params)->select("customer_backs.*", "customer.name", "customer.source", "customer.user_from")->orderBy("customer_backs.id", "desc")->skip($offset)->take($params['pageSize'])->get();
        return $list;
    }

    public function getCount($params) {
        return $this->_createWhere($params)->count();
    }

    /**
     * 排行榜
     */
    public function getPaihangbang() {
        $sql = "SELECT a.follow_user_id,sum(a.amount) as amount,sum(a.real_amount) real_amount, b.name user_name, c.name team_name FROM `customer_backs` a,
            system_user b left join system_team c on b.team_id = c.id  
            where a.follow_user_id = b.id and a.status = 1 and a.create_time > '".date("Y-m-01")."' group by a.follow_user_id order by real_amount desc limit 10";
        return app('db')->select($sql);
    }


    /**
     * 排行榜
     */
    public function getPaihangbang2() {
        $sql = "SELECT a.product_id, b.name, count(*) as cnt FROM `customer_backs` a,
            product b   
            where a.product_id = b.id and a.status = 1 and a.create_time > '".date("Y-m-01")."' group by a.product_id";
        return app('db')->select($sql);
    }
}


================================================
FILE: app/Models/CustomerLog.php
================================================
<?php
 
namespace App\Models;

use App\Services\CustomerService;
use Illuminate\Database\Eloquent\Model;

class CustomerLog extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'customer_log';

    protected $guarded = [];

    public $timestamps = false;

    const TYPE_IN = 1; // 录入客户 
    const TYPE_IMPORTANT = 2; // 设置为重要
    const TYPE_NOT_IMPORTANT = 3; // 设置为非重要
    const TYPE_LOCK = 4; // 设置为锁定
    const TYPE_UNLOCK = 5; // 设置为解锁
    const TYPE_GIVEUP = 6; // 移入公海
    const TYPE_ASSIGN = 7; // 分配
    const TYPE_FOLLOW = 8; // 跟进
    const TYPE_STAR   = 9; // 星级变化
    const TYPE_BACK = 10; // 星级变化
    const TYPE_GET  = 11; // 星级变化
    const TYPE_UNVALID = 12; //
    const TYPE_NOT_UNVALID = 13; //
    const TYPE_EDIT = 14; //
    const TYPE_ASSIGN_NEW = 15; // 新数据分配
    const TYPE_INTRO = 16; // 转介绍
    const TYPE_DIANPING = 17; //
    const TYPE_CALL = 18; //

    const TYPE_MAPPING = [
        self::TYPE_IN => '录入客户',
        self::TYPE_IMPORTANT => '设置重要客户',
        self::TYPE_NOT_IMPORTANT => '取消重要客户',
        self::TYPE_LOCK => '锁定客户',
        self::TYPE_UNLOCK => '解锁客户',
        self::TYPE_GIVEUP =>  '移入公海',
        self::TYPE_ASSIGN => '客户重分配',
        self::TYPE_ASSIGN_NEW => '新数据分配',
        self::TYPE_FOLLOW => '跟进',
        self::TYPE_STAR   => '星级变化',
        self::TYPE_BACK => '回款成功',
        self::TYPE_GET  => '客户认领',
        self::TYPE_EDIT => '客户资料修改',
        self::TYPE_UNVALID=> '设为无效',
        self::TYPE_NOT_UNVALID=> '设为有效',
        self::TYPE_INTRO => '转介绍',
        self::TYPE_DIANPING => '主管点评',
        self::TYPE_CALL => '拨打电话',
    ];


    public function saveLog($type, $id, $before, $after, $userId = 0, $remark = '') {
        $this->type = $type;
        $this->customer_id = $id;
        $this->before = $before;
        $this->after = $after;
        $this->remark = $remark;
        $this->user_id = $userId;
        return $this->save();
    }


    public function getLogListByCustomerId($customerId, $limit) {
        $dictModel = new SystemDict();
        $userModel = new SystemUser();
        $followUserArray = $userModel->getAllUserWithDelMap();
        $dict = $dictModel->getListByGroup($dictModel::GROUP_CUSTOM);
        $list = $this->where('customer_id', $customerId)->whereRaw('type not in ('.static::TYPE_CALL.')')->orderBy("id", "desc")->take($limit)->get();
        foreach ($list as $key => $item) {
            switch($item['type']) {
                case static::TYPE_STAR:
                    $item['remark'] .= "(".$dict[$dictModel::TYPE_STAR][$item['before']]."->".$dict[$dictModel::TYPE_STAR][$item['after']].")";
                    break;
                case static::TYPE_FOLLOW:
                    $item['remark'] .= "(".$dict[$dictModel::TYPE_FOLLOW][$item['before']]."->".$dict[$dictModel::TYPE_FOLLOW][$item['after']].")";
                    break;
                case static::TYPE_ASSIGN:
                    $item['remark'] = CustomerService::ASSIGN_TYPE_MAPPING[$item['remark']] . "(".$followUserArray[$item['before']]."->".$followUserArray[$item['after']].")";
                    break;
                case static::TYPE_ASSIGN_NEW:
                    $item['remark'] = CustomerService::ASSIGN_TYPE_MAPPING[$item['remark']] . "(".$followUserArray[$item['before']]."->".$followUserArray[$item['after']].")";
                    break;
                case static::TYPE_GET:
                    $item['remark'] = CustomerService::ASSIGN_TYPE_MAPPING[$item['remark']] . "(".$followUserArray[$item['before']]."->".$followUserArray[$item['after']].")";
                    break;
                case static::TYPE_INTRO:
                    $item['remark'] = $item['remark'];
                    break;
                case static::TYPE_FOLLOW:
                    $custom = Customer::find($item['before']);
                    $item['remark'] = '转介绍('.$item['before'].'-'.$custom['name'].')';
                    break;
            }
            $item['username'] = $item['user_id'] ? $followUserArray[$item['user_id']] : '系统';
            $list[$key] = $item;
        }
        return $list;
    }


    public function getLogListByCustomerIdAndType($customerId, $type, $params) {
        $offset = ($params['current'] - 1) * $params['pageSize'];
        $list = $this->where('customer_id', $customerId)->where('type', $type)->orderBy("id", "desc")->skip($offset)->take($params['pageSize'])->get();
        return $list;
    }

    public function getCountByCustomerIdAndType($customerId, $type) {
        return $this->where('customer_id', $customerId)->where('type', $type)->count();
    }

    public function getCountByUserIdAndTime($userId, $type, $startTime, $endTime) {
        $sql = "SELECT  count(distinct customer_id) as cnt, max(id) as id FROM customer_log where type = ? 
            and `after` = ? and create_time >= ? and create_time < ?";
        return app('db')->select($sql, [$type, $userId, $startTime, $endTime]);
    }
    public function getLogListByUserIdAndType($userId, $type, $offset, $pageSize) {
        $list = $this->where('user_id', $userId)->where('type', $type)->orderBy("id", "desc")->skip($offset)->take($pageSize)->get();
        return $list;
    }
}


================================================
FILE: app/Models/CustomerRemarkLog.php
================================================
<?php
 
namespace App\Models;

use App\Services\CustomerService;
use Illuminate\Database\Eloquent\Model;

class CustomerRemarkLog extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'customer_remark_log';

    protected $guarded = [];

    public $timestamps = false;

    public function saveLog($id, $remark, $userId) {
        $this->customer_id = $id;
        $this->remark = $remark;
        $this->user_id = $userId;
        return $this->save();
    }


    public function getLogListByCustomerId($customerId, $limit) {
        $list = $this->where('customer_id', $customerId)->orderBy("id", "desc")->take($limit)->get();
        return $list;
    }

}


================================================
FILE: app/Models/CustomerRuleConfig.php
================================================
<?php
 
namespace App\Models;

use App\Services\CustomerService;
use Illuminate\Database\Eloquent\Model;

class CustomerRuleConfig extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'customer_rule_config';

    protected $guarded = [];
    public $timestamps = false;

}


================================================
FILE: app/Models/Excel/CustomerModel.php
================================================
<?php
namespace App\Models\Excel;

use App\Models\Customer;
use Illuminate\Validation\Rule;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithValidation;

class CustomerModel implements ToModel
{
    public function model(array $rows)
    {
        return null;
    }

}

================================================
FILE: app/Models/Notice.php
================================================
<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;

class Notice extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'notice';

    protected $guarded = [];

    public $timestamps = false;

    public function getUnRead($userId) {
        $data1 = $this->where('follow_user_id', $userId)->where('type', '!=', 5)->where('date', '<', time() + 24 * 3600)->where('date', '>', time())->where('is_read', 0)->take(10)->get()->toArray();
        $data2 = $this->where('follow_user_id', $userId)->where('type', 5)->where('is_read', 0)->take(10)->get()->toArray();
        return array_merge($data1, $data2);
    }

    public function read($ids) {
        $this->wherein('id', $ids)->update(['is_read' => 1]);
        return true;
    }

    public function getUnReadCount($userId) {
        $num1 = $this->where('follow_user_id', $userId)->where('type', '!=', 5)->where('date', '<', time() + 24 * 3600)->where('date', '>', time())->where('is_read', 0)->count();
        $num2 = $this->where('follow_user_id', $userId)->where('type', 5)->where('is_read', 0)->count();
        return $num1 + $num2;
    }


    private function _createWhere($params) {
        $query = $this;
        if (isset($params['userId']) && !empty($params['userId'])) {
            $query = $query->where('follow_user_id', $params['userId']);
        }
        if (isset($params['name']) && !empty($params['name'])) {
            $customer = Customer::where('name', $params['name'])->get()->toArray()[0];
            if ($customer && $customer['id']) {
                $query = $query->where('custom_id', $customer['id']);
            } else {
                $query = $query->where('custom_id', 999999999999);
            }
        }
        if (isset($params['time']) && !empty($params['time']) && is_array($params['time']) ) {
            $query = $query->where('date',  '>', strtotime($params['time'][0]));
            $query = $query->where('date',  '<', strtotime($params['time'][1]));
        }
        return $query;
    }

    public function getLists($params) {
        $offset = ($params['current'] - 1) * $params['pageSize'];
        $list = $this->_createWhere($params)->orderBy("id", "desc")->skip($offset)->take($params['pageSize'])->get();
        return $list;
    }

    public function getCount($params = []) {
        return $this->_createWhere($params)->count();
    }


    public function getListByUserId($userId, $limit) {
        $list = $this->where('follow_user_id', $userId)->orderBy("date", "desc")->take($limit)->get();
        return $list;
    }

    public function getListByUserIdAndCustomer($customId, $userId, $limit) {
        $list = $this->where('follow_user_id', $userId)->where('custom_id', $customId)->where('date', '>', time())->orderBy("date", "desc")->take($limit)->get();
        return $list;
    }
}


================================================
FILE: app/Models/Product.php
================================================
<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'product';

    public $timestamps = false;

    public function getAllProduct() {
        return $this->where('status', 1)->get();
    }

    public function getAllBank() {
        return $this->select('bank')->groupBy('bank')->get();
    }

    private function _createWhere($params) {
        $query = $this->where('status', 1);
        if (isset($params['name']) && $params['name'] !== "") {
            $query = $query->where(['name' => $params['name']]);
        }
        if (isset($params['status']) && $params['status'] !== "") {
            $query = $query->where(['status' => $params['status']]);
        }
        return $query;
    }

    public function getLists($params) {
        $offset = ($params['current'] - 1) * $params['pageSize'];
        $list = $this->_createWhere($params)->orderBy("id", "desc")->skip($offset)->take($params['pageSize'])->get();
        return $list;
    }
    public function getCount($params) {
        return $this->_createWhere($params)->count();
    }
}


================================================
FILE: app/Models/SystemDict.php
================================================
<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;

class SystemDict extends Model
{

    const TYPE_CITY = 1;   // 城市
    const TYPE_WORK = 2;   // 工作类型
    const TYPE_FOLLOW = 3; // 跟进类型
    const TYPE_STAR = 4; // 星级类型
    const TYPE_USER_FROM = 5; // 用户来源
    const TYPE_SOURCE = 6; // 渠道来源
    const TYPE_QUALIFICATION = 7; // 资质
    const TYPE_NOTICE = 8; // 日程

    const GROUP_CUSTOM = 1; // 客户相关

    protected $table = 'dict';
    protected $guarded = [];

    public $timestamps = false;

    public function getListByType($type) {
        $list = $this->where(['type'=>$type, 'status'=>1])->get();
        $returnData = [];
        foreach ($list as $item) {
            $returnData[$item['tid']] = $item['name'];
        }
        return $returnData;
    }

    public function getListByGroup($group) {
        $list = $this->where(['groups'=>$group, 'status'=>1])->get();
        $returnData = [];
        foreach ($list as $item) {
            $returnData[$item['type']][$item['tid']] = $item['name'];
        }
        return $returnData;
    }


}


================================================
FILE: app/Models/SystemFields.php
================================================
<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;

class SystemFields extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'system_field';

    public $timestamps = false;

    public function getSelect() {
        $list = $this->get();
        $returnData = [ ];
        foreach ($list as $item) {
            $returnData[$item['type']][$item['name']] =$item['name_cn'] ;
        }
        return $returnData;
    }
}


================================================
FILE: app/Models/SystemLog.php
================================================
<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;

class SystemLog extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'system_log';

    protected $guarded = [];

    public $timestamps = false;

    const TYPE_ASSIGN = 1; // 分配权限修改
    const TYPE_EDIT   = 2; // 基本资料修改


    public function saveLog($type, $id, $before, $after, $userId = 0, $remark = '') {
        $this->type = $type;
        $this->obj_id = $id;
        $this->before = $before;
        $this->after = $after;
        $this->remark = $remark;
        $this->user_id = $userId;
        $this->save();
    }


    public function getLogListById($type, $id, $params) {
        $offset = ($params['current'] - 1) * $params['pageSize'];
        $list = $this->where('type', $type)->where('obj_id', $id)->orderBy("id", "desc")->skip($offset)->take($params['pageSize'])->get();
        return $list;
    }
    public function getLogCountById($type, $id, $params) {
        return $this->where('type', $type)->where('obj_id', $id)->count();
    }

}


================================================
FILE: app/Models/SystemRight.php
================================================
<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;
 
class SystemRight extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'system_right';

    public function getRightByUserId($userId) {
        $sql = "SELECT a.* FROM `system_right` a, system_role_right b, system_role c, system_user_role d , system_user e
        where a.id =b.right_id and b.role_id = c.id and c.id = d.role_id and d.user_id = e.id and e.status = 1 and is_del = 0 and c.status = 1 and d.user_id = ? and c.status = 1 and a.status = 1 group by a.id order by a.parent_id, a.orders desc";
        return app('db')->select($sql, [$userId]);
    }

    public function getRightByRoleId($roleId) {
        $sql = "SELECT a.* FROM `system_right` a, system_role_right b where a.id =b.right_id and a.status = 1 and b.role_id = ? group by a.id ";
        return app('db')->select($sql, [$roleId]);
    }


    public function getAllRight() {
        $sql = "SELECT a.* FROM `system_right` a where a.status = 1 order by a.parent_id, a.orders desc";
        return app('db')->select($sql);
    }


}


================================================
FILE: app/Models/SystemRole.php
================================================
<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;

class SystemRole extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'system_role';

    public static $statusMapping = [
        1 => '有效',
        0 => '无效',
    ];
    public $timestamps = false;


    public function getRoleByUserId($userId) {
        $sql = "SELECT c.* FROM system_role c, system_user_role d 
        where c.id = d.role_id and c.status = 1 and d.user_id = ? and c.status = 1 group by c.id";
        return app('db')->select($sql, [$userId]);
    }


    public function getUserByRoleId($roleId) {
        $sql = "SELECT c.* FROM system_user c, system_user_role d 
        where c.id = d.user_id and c.status = 1 and d.role_id = ? group by c.id";
        return app('db')->select($sql, [$roleId]);
    }

    public function getRoleSelect() {
        $list = $this->where('is_delete', 0)->where('status', 1)->get();
        $returnData = [ ];
        foreach ($list as $item) {
            $returnData[] = [
                'label' => $item['name'],
                'value' => $item['id'],
            ];
        }
        return $returnData;
    }



    private function _createWhere($params) {
        $query = $this;
        $query = $query->where(['is_delete' => 0]);
        if (isset($params['name']) && $params['name'] !== "") {
            $query = $query->where(['name' => $params['name']]);
        }
        if (isset($params['status']) && $params['status'] !== "") {
            $query = $query->where(['status' => $params['status']]);
        }
        return $query;
    }
    public function getLists($params) {
        $offset = ($params['current'] - 1) * $params['pageSize'];
        $list = $this->_createWhere($params)->orderBy("id", "desc")->skip($offset)->take($params['pageSize'])->get();
        foreach ($list as $key => $item) {
            $item['statusname'] = static::$statusMapping[$item['status']];
            $list[$key] = $item;
        }
        return $list;
    }
    public function getCount($params) {
        return $this->_createWhere($params)->count();
    }
}

================================================
FILE: app/Models/SystemRoleRight.php
================================================
<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;
 
class SystemRoleRight extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'system_role_right';

    public function deleteRights($roleId, $rightIds) {
        if (empty($rightIds)){
            return true;
        }
        return $this->where('role_id', $roleId)->wherein('right_id', $rightIds)->delete();
    }



    public function addRights($roleId, $rightIds){
        if (empty($rightIds)){
            return true;
        }
        $rights = [];
        foreach ($rightIds as $rightId) {
            $rights[] = [
                'role_id'=>$roleId,
                'right_id'=>$rightId
            ];
        }
        return $this->insert($rights);
    }
}


================================================
FILE: app/Models/SystemSetting.php
================================================
<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;
 
class SystemSetting extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'system_setting';

    protected $guarded = [];

    public $timestamps = false;

}


================================================
FILE: app/Models/SystemTeam.php
================================================
<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;

class SystemTeam extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'system_team';

    public $timestamps = false;

    /**
     * 获取所有团队
     */
    public function getAllTeam() {
        return $this->where('status', 1)->get();
    }

    /**
     * 获取所有团队转成KV
     */
    public function getAllTeamMap() {
        $list = $this->getAllTeam();
        return collect($list)->mapWithKeys(function ($item) {
            return [$item['id'] => $item['name']];
        })->toArray();
    }

    /**
     * 通用查询
     */
    private function _createWhere($params) {
        $query = $this->where('status', 1);
        if (isset($params['name']) && $params['name'] !== "") {
            $query = $query->where(['name' => $params['name']]);
        }
        if (isset($params['status']) && $params['status'] !== "") {
            $query = $query->where(['status' => $params['status']]);
        }
        return $query;
    }

    /**
     * 通用查询
     */
    public function getLists($params) {
        $offset = ($params['current'] - 1) * $params['pageSize'];
        $list = $this->_createWhere($params)->orderBy("id", "desc")->skip($offset)->take($params['pageSize'])->get();
        return $list;
    }

    /**
     * 通用查询
     */
    public function getCount($params) {
        return $this->_createWhere($params)->count();
    }
}


================================================
FILE: app/Models/SystemUser.php
================================================
<?php
 
namespace App\Models;

use App\Services\ToolService;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Config;
use PHPUnit\Framework\SkippedTest;

class SystemUser extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'system_user';

    public $timestamps = false;

    public static $statusMapping = [
        1 => '有效',
        0 => '无效',
    ];

    private function _createWhere($params) {
        $query = $this;
        $query = $query->where(['is_del' => 0]);
        if (isset($params['name']) && $params['name'] !== "") {
            $query = $query->where(['name' => $params['name']]);
        }
        if (isset($params['team_id']) && $params['team_id'] !== "") {
            $query = $query->where(['team_id' => $params['team_id']]);
        }
        if (isset($params['status']) && $params['status'] !== "") {
            $query = $query->where(['status' => $params['status']]);
        }
        if (isset($params['online']) && $params['online'] !== "") {
            $query = $query->where(['online' => $params['online']]);
        }
        if (isset($params['mobile']) && $params['mobile'] !== "") {
            $query = $query->where(['mobile' => $params['mobile']]);
        }
        return $query;
    }
    public function getLists($params) {
        $roleModel = new SystemRole();
        $teamModel = new SystemTeam();
        $teams = $teamModel->getAllTeam();
        $teams = collect($teams)->mapWithKeys(function($item){return [$item['id']=>$item['name']];});
        $offset = ($params['current'] - 1) * $params['pageSize'];
        $list = $this->_createWhere($params)->orderBy("id", "desc")->skip($offset)->take($params['pageSize'])->get();
        foreach ($list as $key => $item) {
            $roles = $roleModel->getRoleByUserId($item['id']);
            $item['roles'] = implode(",", app(ToolService::class)->objColumn($roles, 'name'));
            $item['team'] = $teams[$item->team_id];
            $item['statusname'] = static::$statusMapping[$item['status']];
            unset($item['password']);
            $list[$key] = $item;
        }
        return $list;
    }
    public function getCount($params) {
        return $this->_createWhere($params)->count();
    }

    public function getAllUserWithDel($userId = 0) {
        return $this->where('id', '!=', $userId)->get();
    }

    public function getAllUserWithDelMap($userId = 0) {
        $userList = $this->getAllUserWithDel($userId);
        return collect($userList)->mapWithKeys(function ($item) {
            return [$item['id'] => $item['name']];
        })->toArray();
    }

    public function getAllUserTeamWithDelMap($userId = 0) {
        $userList = $this->getAllUserWithDel($userId);
        return collect($userList)->mapWithKeys(function ($item) {
            return [$item['id'] => $item['team_id']];
        })->toArray();
    }

    public function getAllUser($userId = 0) {
        return $this->where('status', 1)->where('is_del', 0)->where('id', '!=', $userId)->get();
    }

    public function getAllUserMap($userId = 0) {
        $userList = $this->getAllUser($userId);
        return collect($userList)->mapWithKeys(function ($item) {
            return [$item['id'] => $item['name']];
        })->toArray();
    }

    public function getAllUserByParentId($parentId = 0) {
        return $this->where('status', 1)->where('is_del', 0)->where('parent_id', '=', $parentId)->get();
    }

    public function getUserCountByTeamid($teamId) {
        return $this->where('team_id', $teamId)->where('is_del', 0)->count();
    }

    public function getUserByTeamid($teamId) {
        return $this->where('team_id', $teamId)->where('is_del', 0)->get();
    }
}

================================================
FILE: app/Models/SystemUserRole.php
================================================
<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;

class SystemUserRole extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'system_user_role';

    public $timestamps = false;

    public function getRoleByUserId($userId) {
        return $this->where('user_id', $userId)->get()->toArray();
    }

    public function delRoles($userId, $roleIds){
        if (empty($roleIds)){
            return true;
        }
        return $this->where('user_id', $userId)->where('role_id', $roleIds)->delete();
    }

    public function addRoles($userId, $roleIds){
        if (empty($roleIds)){
            return true;
        }
        $roles = [];
        foreach ($roleIds as $roleId) {
            $roles[] = [
                'role_id'=>$roleId,
                'user_id'=>$userId
            ];
        }
        return $this->insert($roles);
    }
}

================================================
FILE: app/Providers/AppServiceProvider.php
================================================
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Services\RightService;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
        $this->app->singleton(RightService::class, function ($app) {
            return new RightService();
        });
    }

    public function boot() {
        error_reporting(E_ALL ^ E_NOTICE);//
    }
}


================================================
FILE: app/Providers/AuthServiceProvider.php
================================================
<?php

namespace App\Providers;

use App\User;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Boot the authentication services for the application.
     *
     * @return void
     */
    public function boot()
    {
        // Here you may define how you wish users to be authenticated for your Lumen
        // application. The callback which receives the incoming request instance
        // should return either a User instance or null. You're free to obtain
        // the User instance via an API token or any other method necessary.

        $this->app['auth']->viaRequest('api', function ($request) {
            if ($request->input('api_token')) {
                return User::where('api_token', $request->input('api_token'))->first();
            }
        });
    }
}


================================================
FILE: app/Providers/EventServiceProvider.php
================================================
<?php

namespace App\Providers;

use Laravel\Lumen\Providers\EventServiceProvider as ServiceProvider;

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen = [
        'App\Events\ExampleEvent' => [
            'App\Listeners\ExampleListener',
        ],
    ];
}


================================================
FILE: app/Services/AssignRule/Rule1.php
================================================
<?php

namespace App\Services\AssignRule;

use App\Models\Customer;
use App\Services\CustomerService;
use App\Services\UserService;

/**
 * 客户分配相关的service
 */
class Rule1
{
    public function handle($config) {
        echo PHP_EOL;
        // 获取今天还有分配名额的用户
        $customService = app(CustomerService::class);
        $userService = app(UserService::class);
        $users = $userService->getAllAssignUser();
        echo "RULE1: 新数据分配的所有用户" . json_encode($users).PHP_EOL;
        // 获取所有新数据公共池用户
        $model = new Customer();
        $customers = $model->where('user_from', 1)->where('follow_user_id', 0)->get();
        echo "RULE1: 一共" . count($customers) . "待分配用户" .PHP_EOL;
        foreach ($customers as $customer) {
            if (empty($users)) {
                continue;
            }
            foreach ($users as $userId => $leftCount) {
                $userIdStr = $userId;
                $userId = intval($userId);
                if ($leftCount <= 0) {
                    continue;
                }
                echo "RULE1: 分配" . $customer->id . ' --> ' . $userId .PHP_EOL;
                $flag = $customService->assign($customer->id, $userId, 0, CustomerService::ASSIGN_TYPE_NEW);
                $users[$userIdStr] = $leftCount - 1;
                break;
            }
            // 把第一位的用户排到最后一位用作轮训
            $key = array_keys($users);
            $users[$key[0]] = array_shift($users);
        }
        return ['status'=>1];
    }
}


================================================
FILE: app/Services/AssignRule/Rule10.php
================================================
<?php

namespace App\Services\AssignRule;

use App\Services\CustomerService;

/**
 * 客户分配相关的service
 */
class Rule10
{
    public function handle($config) {
        // 获取今天分配最少的用户
        return ['status'=>1];
    }
}


================================================
FILE: app/Services/AssignRule/Rule11.php
================================================
<?php

namespace App\Services\AssignRule;

use App\Models\Customer;
use App\Models\CustomerLog;
use App\Services\CustomerService;
use Illuminate\Support\Facades\DB;

/**
 * 客户分配相关的service
 */
class Rule11
{
    public function handle($config) {
        // 获取今天分配最少的用户
        echo "RULE11: 配置" . json_encode($config).PHP_EOL;
        if (empty($config['day'])) {
            echo "RULE11: 配置异常" .PHP_EOL;
            return ['status'=>0];
        }
        $time = date('Y-m-d H:i:s', time() - $config['day'] * 3600 * 24);
        $sql = "SELECT a.id FROM `customer` a , customer_log b where a.id = b.customer_id and `lock` = 1 and b.type = 4  group by a.id HAVING max(b.create_time) < ?"; // 星级为0且分配时间超过2天
        echo $time;
        $data = app('db')->select($sql, [$time]);
        var_dump($data);
        foreach ($data as $item) {
            echo "RULE11: 锁定超过".$config['day']."天,流入公共池, id: ".$item->id.PHP_EOL;
            DB::beginTransaction();
            $model = Customer::find($item->id);
            $model->lock = 0;
            $model->save();
            $logmodel = new CustomerLog();
            $logmodel->saveLog($logmodel::TYPE_UNLOCK, $item->id, '', '', 0, '锁定超过'.$config['day'].'天');
            DB::commit();
        }
        return ['status'=>1];
    }
}


================================================
FILE: app/Services/AssignRule/Rule13.php
================================================
<?php

namespace App\Services\AssignRule;
use App\Services\CustomerService;


/**
 * 客户分配相关的service
 */
class Rule13
{
    public function handle($config) {
        echo "RULE13: 配置" . json_encode($config).PHP_EOL;
        if (empty($config['hour'])) {
            echo "RULE13: 配置异常".PHP_EOL;
            return ['status'=>0];
        }
        $customService = app(CustomerService::class);
        $time = time() - $config['hour'] * 3600 * 24;
        $sql = "select * from customer where follow_user_id > 0 and assign_time < ? and follow_time < ? and user_from != 1  and follow_time < assign_time";
        $data = app('db')->select($sql, [$time, $time]);
        foreach ($data as $item) {
            echo "RULE13: 超过".$config['hour']."天没有跟进,流入公共池, id: ".$item->id.PHP_EOL;
            $customService->giveup($item->id, 0, '再分配客户超过'.$config['hour'].'天没有跟进,流入公共池');
        }
        return ['status'=>1];
    }
}


================================================
FILE: app/Services/AssignRule/Rule2.php
================================================
<?php

namespace App\Services\AssignRule;
use App\Services\CustomerService;


/**
 * 客户分配相关的service
 */
class Rule2
{
    public function handle($config) {
        echo "RULE2: 配置" . json_encode($config).PHP_EOL;
        if (empty($config['hour'])) {
            echo "RULE2: 配置异常".PHP_EOL;
            return ['status'=>0];
        }
        $customService = app(CustomerService::class);
        $time = time() - $config['hour'] * 3600;
        $sql = "select * from customer where follow_user_id > 0 and assign_time < ? and follow_time < ?  and follow_time < assign_time  and user_from = 1"; 
        $data = app('db')->select($sql, [$time, $time]);
        foreach ($data as $item) {
            echo "RULE2: 超过".$config['hour']."小时没有跟进,流入公共池, id: ".$item->id.PHP_EOL;
            $customService->giveup($item->id, 0, '新客户超过'.$config['hour'].'小时没有跟进,流入公共池');
        }
        return ['status'=>1];
    }
}


================================================
FILE: app/Services/AssignRule/Rule3.php
================================================
<?php

namespace App\Services\AssignRule;

use App\Services\CustomerService;

/**
 * 客户分配相关的service
 */
class Rule3
{
    public function handle($config) {
        // 获取今天分配最少的用户
        echo "RULE3: 配置" . json_encode($config).PHP_EOL;
        if (empty($config['type']) || empty($config['values']) || empty($config['day'])) {
            echo "RULE3: 配置异常" .PHP_EOL;
            return ['status'=>0];
        }
        $customService = app(CustomerService::class);
        $time = time() - $config['day'] * 3600 * 24;
        $field = $config['type'] == 1 ? 'follow_status' : 'star';
        $sql = "select * from customer where ".$field." in (".implode(",", $config['values']).") and follow_user_id > 0 and assign_time < ? and follow_time < ?"; // 星级为0且分配时间超过2天
        $data = app('db')->select($sql, [$time, $time]);
        foreach ($data as $item) {
            echo "RULE3: 超过".$config['day']."天没有跟进,流入公共池, id: ".$item->id.PHP_EOL;
            $customService->giveup($item->id, 0, '超过'.$config['day'].'天没有跟进,流入公共池');
        }
        return ['status'=>1];
    }
}


================================================
FILE: app/Services/AssignRule/Rule4.php
================================================
<?php

namespace App\Services\AssignRule;

use App\Services\CustomerService;

/**
 * 客户分配相关的service
 */
class Rule4
{
    public function handle($config) {
        // 获取今天分配最少的用户
        if (empty($config['type']) || empty($config['values']) || empty($config['day'])) {
            return ['status'=>0];
        }
        $customService = app(CustomerService::class);
        $time = time() - $config['day'] * 3600 * 24;
        $field = $config['type'] == 1 ? 'follow_status' : 'star';
        $sql = "select * from customer where ".$field." in (".implode(",", $config['values']).") and follow_user_id > 0 and assign_time < ? and follow_time < ?"; // 星级为0且分配时间超过2天
        $data = app('db')->select($sql, [$time, $time]);
        foreach ($data as $item) {
            $customService->giveup($item->id, 0, '超过'.$config['day'].'天没有跟进,流入公共池');
        }
        return ['status'=>1];
    }
}


================================================
FILE: app/Services/AssignRule/Rule5.php
================================================
<?php

namespace App\Services\AssignRule;

use App\Services\CustomerService;

/**
 * 客户分配相关的service
 */
class Rule5
{
    public function handle($config) {
        // 获取今天分配最少的用户
        echo "RULE5: 配置" . json_encode($config).PHP_EOL;
        if (empty($config['type']) || empty($config['values']) || empty($config['day'])) {
            echo "RULE5: 配置异常" .PHP_EOL;
            return ['status'=>0];
        }
        $customService = app(CustomerService::class);
        $time = time() - $config['day'] * 3600 * 24;
        $field = $config['type'] == 1 ? 'follow_status' : 'star';
        $sql = "select * from customer where ".$field." in (".implode(",", $config['values']).") and follow_user_id > 0 and assign_time < ? and follow_time < ?"; // 星级为0且分配时间超过2天
        $data = app('db')->select($sql, [$time, $time]);
        foreach ($data as $item) {
            echo "RULE5: 超过".$config['day']."天没有跟进,流入公共池, id: ".$item->id.PHP_EOL;
            $customService->giveup($item->id, 0, '超过'.$config['day'].'天没有跟进,流入公共池');
        }
        return ['status'=>1];
    }
}


================================================
FILE: app/Services/AssignRule/Rule6.php
================================================
<?php

namespace App\Services\AssignRule;

use App\Services\CustomerService;

/**
 * 客户分配相关的service
 */
class Rule6
{
    public function handle($config) {
        // 获取今天分配最少的用户
        echo "RULE6: 配置" . json_encode($config).PHP_EOL;
        if (empty($config['type']) || empty($config['values']) || empty($config['day'])) {
            echo "RULE6: 配置异常" .PHP_EOL;
            return ['status'=>0];
        }
        $customService = app(CustomerService::class);
        $time = time() - $config['day'] * 3600 * 24;
        $field = $config['type'] == 1 ? 'follow_status' : 'star';
        $sql = "select * from customer where ".$field." in (".implode(",", $config['values']).") and follow_user_id > 0 and assign_time < ? and follow_time < ?"; // 星级为0且分配时间超过2天
        $data = app('db')->select($sql, [$time, $time]);
        foreach ($data as $item) {
            echo "RULE6: 超过".$config['day']."天没有跟进,流入公共池, id: ".$item->id.PHP_EOL;
            $customService->giveup($item->id, 0, '超过'.$config['day'].'天没有跟进,流入公共池');
        }
        return ['status'=>1];
    }
}


================================================
FILE: app/Services/AssignRule/Rule7.php
================================================
<?php

namespace App\Services\AssignRule;

use App\Services\CustomerService;

/**
 * 客户分配相关的service
 */
class Rule7
{
    public function handle($config) {
        // 获取今天分配最少的用户
        echo "RULE7: 配置" . json_encode($config).PHP_EOL;
        if (empty($config['type']) || empty($config['values']) || empty($config['day'])) {
            echo "RULE7: 配置异常" .PHP_EOL;
            return ['status'=>0];
        }
        $customService = app(CustomerService::class);
        $time = time() - $config['day'] * 3600 * 24;
        $field = $config['type'] == 1 ? 'follow_status' : 'star';
        $sql = "select * from customer where ".$field." in (".implode(",", $config['values']).") and follow_user_id > 0 and assign_time < ? and follow_time < ?"; // 星级为0且分配时间超过2天
        $data = app('db')->select($sql, [$time, $time]);
        foreach ($data as $item) {
            echo "RULE7: 超过".$config['day']."天没有跟进,流入公共池, id: ".$item->id.PHP_EOL;
            $customService->giveup($item->id, 0, '超过'.$config['day'].'天没有跟进,流入公共池');
        }
        return ['status'=>1];
    }
}


================================================
FILE: app/Services/AssignService.php
================================================
<?php

namespace App\Services;


/**
 * 客户分配相关的service
 */
class AssignService
{

    const TYPE_MAPPING = [
        "public" => "公共池领取数据",
        "inner"  => "内部流转分配数据",
        "new"    => "新数据分配"
    ];

    /**
     * 通过json生成文案 
     * 
     */
    public function genText($json) {
        $data = json_decode($json, true);
        $returnText = "";
        if (empty($data)) {
            return "";
        }
        foreach ($data  as $key => $value) {
            $returnText .= static::TYPE_MAPPING[$key] . "(每日上限:".$value."); ";
        }
        return $returnText;
    }

}


================================================
FILE: app/Services/CustomerEditService.php
================================================
<?php

namespace App\Services;

use App\Models\Customer;
use App\Models\CustomerAssign;
use App\Models\CustomerLog;
use App\Models\CustomerRemarkLog;
use App\Models\SystemDict;
use App\Models\SystemFields;
use App\Models\SystemLog;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Symfony\Component\VarDumper\Cloner\Cursor;

class CustomerEditService
{

    public function edit($params, $operUserId) {
        $result = ['status'=>1, 'error'=>''];
        $customModel = new Customer();
        $service = app(CustomerService::class);

        $customId = $params['id'];
        $customModel = $customModel->find($params['id']);
        $oldInfo = clone ($customModel);
        $params['mobile_md5'] = md5($params['mobile']);
        $flag = $customModel->update($params);

        if (!$flag) {
            $result = ['status'=>0, 'error'=>"基本信息保存失败"];
        }
        $diff = $service->diff($oldInfo, $customModel);
        if ($diff['star']) {
            $logModel = new CustomerLog();
            $flag = $logModel->saveLog($logModel::TYPE_STAR, $params['id'], $diff['star']['old'], $diff['star']['new'], $operUserId, $customModel->remark);
            if (!$flag) {
                $result = ['status'=>0, 'error'=>"星级变化保存失败"];
            }
        }
        if ($diff['follow_status']) {
            $logModel = new CustomerLog();
            $flag = $logModel->saveLog($logModel::TYPE_FOLLOW, $params['id'], $diff['follow_status']['old'], $diff['follow_status']['new'], $operUserId, $customModel->remark);
            if (!$flag) {
                $result = ['status'=>0, 'error'=>"跟进变化保存失败"];
            }
            $customModel->follow_time = time();
            $customModel->save();
            if (!$flag) {
                $result = ['status'=>0, 'error'=>"跟进时间保存失败"];
            }
        } else if (!empty($params['remark'])) {
            $logModel = new CustomerLog();
            $flag = $logModel->saveLog($logModel::TYPE_FOLLOW, $params['id'], intval($params['follow_status']), intval($params['follow_status']), $operUserId, $params['remark']);
            if (!$flag) {
                $result = ['status'=>0, 'error'=>"跟进变化保存失败"];
            }
            $customModel->follow_time = time();
            $customModel->save();
            if (!$flag) {
                $result = ['status'=>0, 'error'=>"跟进时间保存失败"];
            }
        }
        unset($diff['star']);
        unset($diff['follow_status']);
        if (count($diff) > 0) {
            $logModel = new CustomerLog();
            $flag = $logModel->saveLog($logModel::TYPE_EDIT, $params['id'], '', '', $operUserId, '');
            $logmodel = new SystemLog();
            $logmodel->saveLog($logmodel::TYPE_EDIT, $params['id'], json_encode($diff), '', $operUserId, strval($params['config']['remark']));
        }
        if ($params['remark']) {
            $customerRemarkLogModel = new CustomerRemarkLog();
            $customerRemarkLogModel->saveLog($customId, $params['remark'], $operUserId);
        }
        return $result;
    }

    public function add($params, $operUserId) {
        $customModel = new Customer();

        $result = ['status'=>1, 'error'=>''];
        $params['add_user_id'] = $operUserId;
        $params['apply_time'] = time();
        $params['assign_time'] = time();
        // 转介绍
        $params['user_from'] = empty($params['introid']) ? CustomerService::ASSIGN_TYPE_SELF : CustomerService::ASSIGN_TYPE_INTRO;
        $params['follow_user_id'] = $operUserId;
        $params['mobile_md5'] = md5($params['mobile']);
        if ($params['follow_status']) {
            $params['follow_time'] = time();
        }
        $custom = $customModel->create($params);
        if (!$custom->id) {
            $result = ['status'=>0, 'error'=>"客户录入失败"];
        }
        $logModel = new CustomerLog();
        if ($params['introid']) {
            $flag = $logModel->saveLog($logModel::TYPE_INTRO, $custom->id, $params['introid'], '', $operUserId, "转介绍");
            $flag = $logModel->saveLog($logModel::TYPE_INTRO, $params['introid'], $custom->id, '', $operUserId, "转介绍");
        } else {
            $flag = $logModel->saveLog($logModel::TYPE_IN, $custom->id, '', '', $operUserId, "手动录入");
        }
        if (!$flag) {
            $result = ['status'=>0, 'error'=>"客户录入失败"];
        }
        if ($params['star']) {
            $logModel = new CustomerLog();
            $flag = $logModel->saveLog($logModel::TYPE_STAR, $custom->id, 0, $params['star'], $operUserId, strval($params['remark']));
            if (!$flag) {
                $result = ['status'=>0, 'error'=>"星级变化保存失败"];
            }
        }
        if ($params['follow_status']) {
            $logModel = new CustomerLog();
            $flag = $logModel->saveLog($logModel::TYPE_FOLLOW, $custom->id, 0, $params['follow_status'], $operUserId, strval($params['remark']));
            if (!$flag) {
                $result = ['status'=>0, 'error'=>"跟进变化保存失败"];
            }
        }
            
        $customId = $custom->id;

        if ($params['remark']) {
            $customerRemarkLogModel = new CustomerRemarkLog();
            $customerRemarkLogModel->saveLog($customId, $params['remark'], $operUserId);
        }

        return $result;
    }
}

================================================
FILE: app/Services/CustomerService.php
================================================
<?php

namespace App\Services;

use App\Models\Customer;
use App\Models\CustomerAssign;
use App\Models\CustomerLog;
use App\Models\SystemDict;
use App\Models\SystemFields;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class CustomerService
{

    const ASSIGN_TYPE_PUBLIC = 1; // 公共池
    const ASSIGN_TYPE_INSIDE = 2; // 内部流转
    const ASSIGN_TYPE_NEW = 3; // 新数据分配
    const ASSIGN_TYPE_SELF = 4; // 录入
    const ASSIGN_TYPE_FOLLOW = 5; // 公共池认领
    const ASSIGN_TYPE_INTRO = 6; // 转介绍

    const ASSIGN_TYPE_MAPPING = [
        self::ASSIGN_TYPE_PUBLIC => '公共池分配',
        self::ASSIGN_TYPE_INSIDE => '再分配',
        self::ASSIGN_TYPE_NEW => '新数据分配',
        self::ASSIGN_TYPE_SELF => '自主录入',
        self::ASSIGN_TYPE_FOLLOW => '公共池认领',
        self::ASSIGN_TYPE_INTRO => '转介绍',
    ];

    const HOUSE_MAPPING = [
        1=>'无房',
        2=>'本地房',
        3=>'外地房',
    ];

    const CAR_MAPPING = [
        2=>'有车',
        1=>'无车',
    ];

    const POLICY_MAPPING = [
        2=>'有保单',
        1=>'无保单',
    ];

    const WAGE_MAPPING = [
        2=>'有打卡工资',
        1=>'无打卡工资',
    ];

    const FUNDS_MAPPING = [
        2=>'有公积金',
        1=>'无公积金',
    ];

    const INSURANCE_MAPPING = [
        2=>'有社保',
        1=>'无社保',
    ];

    const CREDIT_MAPPING = [
        1=>'无逾期',
        2=>'有逾期',
    ];

    /**
     * 两个客户的diff
     */
    public function diff($cust1, $cust2) {
        $diff = [];
        $fieldModel = new SystemFields();
        $fields = $fieldModel->all()->map(function($item) {
            return $item['name'];
        })->toArray();
        foreach ($fields as $field) {
            if ($cust1->$field != $cust2->$field) {
                $diff[$field] = [
                    'old' => $cust1->$field,
                    'new' => $cust2->$field
                ];
            }
        }
        return ($diff);
    }

    public function canAssign($customId) {
        $customModel = new Customer();
        $custom = $customModel->find($customId);
        $data = $customModel->where('mobile', $custom['mobile'])->where('follow_user_id', '>', 0)->where('id', '!=', $customId)->get()->toArray();
        if ($data) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 客户分配
     */
    public function assign($customId, $followUserId, $operUserId = 0, $assignType = 0) {
        DB::beginTransaction();
        $customModel = new Customer();
        $custom = $customModel->lockForUpdate()->find($customId);
        $oldFollowUserId = $custom->follow_user_id;
        if (empty($custom) || $oldFollowUserId == $followUserId || ($oldFollowUserId != 0 && $assignType == CustomerService::ASSIGN_TYPE_NEW)) {
            // 新用户已经分配了退出
            DB::rollBack();
            return true;
        }

        if ($assignType == 0) {
            if ($custom->follow_user_id == 0) {
                $assignType = static::ASSIGN_TYPE_PUBLIC;
            } else {
                $assignType = static::ASSIGN_TYPE_INSIDE;
            }
        }

        if ($custom->first_follow_user_id == 0) {
            $custom->first_follow_user_id = $followUserId;
        }

        $result = true;
        $custom->follow_user_id = $followUserId;
        $custom->assign_time = time();
        $custom->status = 1;
        // 之前有跟进人变成内部流转
        if ($oldFollowUserId != 0) {
            $custom->user_from = 2;
        }
        $flag = $custom->save();
        if (!$flag) {
            $result = false;
        }

        $logModel = new CustomerLog();
        $logType =  $assignType == static::ASSIGN_TYPE_NEW ? $logModel::TYPE_ASSIGN_NEW : $logModel::TYPE_ASSIGN;
        $flag = $logModel->saveLog($logType, $customId, $oldFollowUserId, $followUserId, $operUserId, $assignType);
        if (!$flag) {
            $result = false;
        }

        if ($result) {
            DB::commit();
        } else {
            DB::rollBack();
        }
        return true;
    }

    /**
     * 客户认领
     */
    public function get($customId, $followUserId, $operUserId = 0, $assignType = 0) {
        $customModel = new Customer();
        $custom = $customModel->find($customId);
        $oldFollowUserId = $custom->follow_user_id;
        if (empty($custom) || $oldFollowUserId == $followUserId) {
            return true;
        }

        if ($custom->follow_user_id != 0) {
            return false;
        }

        DB::beginTransaction();
        $result = true;

        if ($custom->first_follow_user_id == 0) {
            $custom->first_follow_user_id = $followUserId;
        }

        $custom->follow_user_id = $followUserId;
        $custom->assign_time = time();
        $custom->user_from = self::ASSIGN_TYPE_FOLLOW;
        $flag = $custom->save();
        if (!$flag) {
            $result = false;
        }

        $logModel = new CustomerLog();
        $flag = $logModel->saveLog($logModel::TYPE_GET, $customId, $oldFollowUserId, $followUserId, $operUserId, $assignType);
        if (!$flag) {
            $result = false;
        }

        if ($result) {
            DB::commit();
        } else {
            DB::rollBack();
        }
        return true;
    }

    /**
     * 移入公海 
     */
    public function giveup($customId, $userId = 0, $remark = "") {
        $model = Customer::find($customId);
        if ($model->follow_user_id == 0) {
            return true;
        }
        $oldFollowUserId = $model->follow_user_id;
        $model->follow_user_id = 0;
        $model->user_from = 2;
        DB::beginTransaction();
        $model->save();
        $logmodel = new CustomerLog();
        $logmodel->saveLog($logmodel::TYPE_GIVEUP, $customId, $oldFollowUserId, $model->follow_user_id, $userId, $remark);
        DB::commit();
        return true;
    }
    /**
     * 资质信息文案装换
     */
    public function genZizhi($custom) {
        $zizhis = [];
        if ($custom['house'] && $custom['house'] != 1 && static::HOUSE_MAPPING[$custom['house']]) {
            $zizhis[] = static::HOUSE_MAPPING[$custom['house']];
        }
        if ($custom['car'] && $custom['car'] != 1 && static::CAR_MAPPING[$custom['car']]) {
            $zizhis[] = static::CAR_MAPPING[$custom['car']];
        }
        if ($custom['policy'] && $custom['policy'] != 1 && static::POLICY_MAPPING[$custom['policy']]) {
            $zizhis[] = static::POLICY_MAPPING[$custom['policy']];
        }
        if ($custom['wage'] && $custom['wage'] != 1 && static::WAGE_MAPPING[$custom['wage']]) {
            $zizhis[] = static::WAGE_MAPPING[$custom['wage']];
        }
        if ($custom['funds'] && $custom['funds'] != 1 && static::FUNDS_MAPPING[$custom['funds']]) {
            $zizhis[] = static::FUNDS_MAPPING[$custom['funds']];
        }
        if ($custom['insurance'] && $custom['insurance'] != 1 && static::INSURANCE_MAPPING[$custom['insurance']]) {
            $zizhis[] = static::INSURANCE_MAPPING[$custom['insurance']];
        }
        if ($custom['credit'] && $custom['credit'] == 1 && static::CREDIT_MAPPING[$custom['credit']]) {
            $zizhis[] = static::CREDIT_MAPPING[$custom['credit']];
        }
        return implode("/", $zizhis);
    }

    /**
     * 多少天没有跟进
     */
    public function getNotFollowTime($custom) {
        $lastTime = max(intval($custom['assign_time']), intval($custom['follow_time']));
        if ($lastTime < 1) {
            return '';
        }
        $cha = time() - $lastTime;
        $data = intval($cha / ( 24 * 3600));
        $hour = intval(($cha % ( 24 * 3600)) / 3600);
        return $data. '天'.$hour .'小时';
    }

    /**
     * 解析excel
     */
    public function genCustomByExcelRow($row, $dict) {
        $returnData = [
            'status' => 0,
            'error' => [],
            'custom' => []
        ];
        if (!$row[0]) {
            $returnData['error'][] = '姓名不能为空';
        }
        $returnData['custom']['name'] = $row[0];
        if (!$row[1]) {
            $returnData['error'][] = '手机号不能为空';
        }
        if (!empty($row[1]) && !preg_match("/^1[3456789]\d{9}$/", $row[1])) {
            $returnData['error'][] = '手机号格式不正确';
        }
        $returnData['custom']['mobile'] = $row[1];
        $returnData['custom']['age'] = intval($row[2]);
        $row[3] = trim($row[3]);
        $row[6] = trim($row[6]);
        $row[7] = trim($row[7]);
        $row[8] = trim($row[8]);
        $row[9] = trim($row[9]);
        $row[10] = trim($row[10]);
        $row[11] = trim($row[11]);
        $row[12] = trim($row[12]);
        if (!empty($row[3]) && empty(array_flip($dict[SystemDict::TYPE_CITY])[$row[3]])) {
            $returnData['error'][] = '找不到对应的城市';
        }
        $returnData['city'] = intval(array_flip($dict[SystemDict::TYPE_CITY])[$row[3]]);
        $returnData['custom']['amount'] = floatval($row[4]);
        if (empty($row['5'])) {
            $applyTime = time();
        } else {
            $applyTime = strtotime($row['5']);
        }
        if (!$applyTime)  {
            $returnData['error'][] = '申请时间格式不对';
        }
        $returnData['custom']['apply_time'] = $applyTime;
        if (!empty($row[6]) && empty(array_flip(static::HOUSE_MAPPING)[$row[6]])) {
            $returnData['error'][] = '找不到对应的房产信息类型';
        }
        $returnData['custom']['house'] = intval(array_flip(static::HOUSE_MAPPING)[$row[6]]);

        if (!empty($row[7]) && empty(array_flip(static::CAR_MAPPING)[$row[7]])) {
            $returnData['error'][] = '找不到对应的车辆信息类型';
        }
        $returnData['custom']['car'] = intval(array_flip(static::CAR_MAPPING)[$row[7]]);

        if (!empty($row[8]) && empty(array_flip(static::POLICY_MAPPING)[$row[8]])) {
            $returnData['error'][] = '找不到对应的保单信息类型';
        }
        $returnData['custom']['policy'] = intval(array_flip(static::POLICY_MAPPING)[$row[8]]);
        if (!empty($row[9]) && empty(array_flip(static::WAGE_MAPPING)[$row[9]])) {
            $returnData['error'][] = '找不到对应的打卡工资信息类型';
        }
        $returnData['custom']['wage'] = intval(array_flip(static::WAGE_MAPPING)[$row[9]]);

        if (!empty($row[10]) && empty(array_flip(static::FUNDS_MAPPING)[$row[10]])) {
            $returnData['error'][] = '找不到对应的公积金信息类型';
        }
        $returnData['custom']['funds'] = intval(array_flip(static::FUNDS_MAPPING)[$row[10]]);

        if (!empty($row[11]) && empty(array_flip(static::INSURANCE_MAPPING)[$row[11]])) {
            $returnData['error'][] = '找不到对应的社保信息类型';
        }
        $returnData['custom']['insurance'] = intval(array_flip(static::INSURANCE_MAPPING)[$row[11]]);

        if (!empty($row[12]) && empty(array_flip(static::CREDIT_MAPPING)[$row[12]])) {
            $returnData['error'][] = '找不到对应的信用情况信息类型';
        }
        $returnData['custom']['credit'] = intval(array_flip(static::CREDIT_MAPPING)[$row[12]]);
        if (empty($returnData['error'])) {
            $returnData['status'] = 1;
        }

        return $returnData;
    }

    /**
     * 新增渠道过来的用户
     */
    public function addChannelCustomer($custom) {
        $id = 0;
        $hasInfo = Customer::where('source', $custom['source'])->where('channel_id', $custom['channel_id'])->get()->toArray();
        // 判断客户已经存在
        if (empty($hasInfo)) {
            $customService = app(CustomerService::class);
            $userService = app(UserService::class);
            $item['mobile_md5'] = md5($custom['mobile']);
            // 写客户信息表
            $id = (new Customer())->insertGetId($item);
            $users = $userService->getAllAssignUser();
            // 遍历所有可以对接客户的销售
            foreach ($users as $userId => $leftCount) {
                $userId = intval($userId);
                // 销售今天没有名额了
                if ($leftCount <= 0) {
                    continue;
                }
                Log::info("addChannelCustomer 分配" . $id . " --> " . $userId);
                $customService->assign($id, $userId, 0, CustomerService::ASSIGN_TYPE_NEW);
                break;
            }
        }
        return $id;
    }
}


================================================
FILE: app/Services/Hook/LoginHook.php
================================================
<?php

namespace App\Services\Hook;

use App\Models\SystemSetting;
use App\Models\SystemUserRole;

/**
 * 登录hook 
 */
class LoginHook
{
    /**
     * 判断用户是否可以登录
     */
    public static function canLogin($userId, $request) {
        $model = new SystemUserRole();
        $roles = $model->getRoleByUserId($userId);
        $rolesIds = array_column($roles, 'role_id');
        $setting = SystemSetting::find(1);
        if ($setting['ip']) {
            $ip = explode(",", $setting['ip']) ;
            if (!in_array($request->ip(), $ip) && !in_array(1, $rolesIds)) {
                return false;
            }
        }
        return true;
    }
    
    /**
     * 获取用户第一个能打开的页面
     */
    public static function getPage($userId) {
        $service = app(\App\Services\RightService::class);
        $realMenus = ($service->getRightTree($userId)['tree']);
        foreach ($realMenus as $menu) {
            return $menu['path'];
        }
        return '';
    }
}

================================================
FILE: app/Services/RightService.php
================================================
<?php

namespace App\Services;

use App\Models\SystemRight;
use App\Models\SystemRole;
use App\Models\SystemUser;

class RightService
{
    /**
     * 获取权限树
     * 
     * @param userId 信贷员id
     */
    public function getRightTree($userId = 0)
    {
        $rightModel = new SystemRight();
        if ($userId > 0) {
            $rights = $rightModel->getRightByUserId($userId);
        } else {
            $rights = $rightModel->getAllRight();
        }
        $notParentRights = [];
        $realRights = [];
        foreach ($rights as $right) {
            $item = [
                'id' => $right->id,
                'title' => $right->name_cn,
                'value' => $right->name_cn,
                'key'  => $right->id,
                'path' => $right->router,
                'name' => $right->router,
                'parent_id' => $right->parent_id,
                'meta' => [
                    'locale' => $right->name,
                    'icon' => $right->icon,
                    'hideInMenu' => $right->hide_in_menu ? true : false,
                    'requiresAuth' => true
                ]
            ];
            if ($right->parent_id > 0) {
                if (isset($realRights[$right->parent_id]) && $realRights[$right->parent_id]) {
                    // 有上级才能有下级权限
                    $realRights[$right->parent_id]['children'][$right->id] = $item;
                } else {
                    $notParentRights[$right->parent_id][] = $item;
                }
            } else {
                $realRights[$right->id] = $item;
            }
        }
        $returnRights = [];
        $leafs = [];
        foreach ($realRights as $id => $levelOneRights) {
            if (!empty($levelOneRights['children'])) {
                $tempRights = [];
                foreach ($levelOneRights['children'] as $subid => $levelTwoRights) {
                    if (!empty($notParentRights[$subid])) {
                        $levelTwoRights['children'] = $notParentRights[$subid];
                        foreach ($levelTwoRights['children'] as $levelThreeRights) {
                            $leafs[] = $levelThreeRights['id'];
                        }
                    } else {
                        $leafs[] = $subid;
                    }
                    $tempRights[] = $levelTwoRights;
                }
                $levelOneRights['children'] = $tempRights;
            } else {
                $leafs[] = $id;
            }
            $returnRights[] = $levelOneRights;
        }
        return [
            'tree' => $returnRights,
            'leafs' => $leafs
        ];
    }

    /**
     * 默认默认开放的权限
     */
    public function getDefaultRight()
    {
        return [
            [
                'key'  => 9999,
                'path' => 'Usersetting',
                'name' => 'Usersetting',
                'parent_id' => 0,
                'meta' => [
                    'locale' => 'menu.nothing',
                    'hideInMenu' =>  true,
                    'requiresAuth' => true
                ]
            ],
            [
                'key'  => 9998,
                'path' => 'NoticeList',
                'name' => 'NoticeList',
                'parent_id' => 0,
                'meta' => [
                    'locale' => 'menu.nothing',
                    'hideInMenu' =>  true,
                    'requiresAuth' => true
                ]
            ],
            [
                'key'  => 9997,
                'path' => 'Working',
                'name' => 'Working',
                'parent_id' => 0,
                'meta' => [
                    'locale' => 'menu.nothing',
                    'icon' => "",
                    'hideInMenu' =>  true,
                    'requiresAuth' => true
                ]
            ]
        ];
    }

    /**
     * 获取某个账号的可见客户权限
     */
    public function getCustomViews($userId) {
        // 如果有角色是可以查看所有客户权限,直接返回all
        $model = new SystemRole();
        $userModel = new SystemUser();
        $roles = $model->getRoleByUserId($userId);
        foreach ($roles as $role) {
            if ($role->views == 1) {
                return  $userModel->getAllUserMap();
            }
        }
        // 如果只能查看下级权限,递归查询下级
        $allUserId = [];
        $this->getSubUserids($userId, $allUserId);
        $user = $userModel->find($userId);
        $allUserId[$userId] = $user->name;
        return $allUserId;
    }

    /**
     * 获取下一级的用户
     */
    public function getSubUserids($userId, &$nowSubUserids = [], $time = 0) {
        if ($time > 20 ) {
            return [];
        }
        $model = new SystemUser();
        $subIds = $model->getAllUserByParentId($userId)->mapWithKeys(
            function($item) {
                return [$item->id => $item->name];
            }
        )->toArray();
        $time++;
        foreach ($subIds as $subId => $name) {
            if (in_array($subId, $nowSubUserids)) {
                continue;
            }
            $nowSubUserids[$subId] = $name;
            $this->getSubUserids($subId, $nowSubUserids, $time);
        }
    }

}


================================================
FILE: app/Services/SelectService.php
================================================
<?php

namespace App\Services;


class SelectService
{
    /**
     * 构造前端的select 
     * 
     */
    public function genKv($data, $key, $value) {
        $returnData = [];
        foreach ($data as $item) {
            $returnData[$item[$key]] = $item[$value];
        }
        return $returnData;
    }

    /**
     * 构造前端的select 
     * 
     */
    public function genSelect($data, $value, $label) {
        $returnData = [];
        foreach ($data as $item) {
            $returnData[] = [
                'value' => $item[$value],
                'label' => $item[$label],
            ];
        }
        return $returnData;
    }

    /**
     * 构造前端的select 
     * 
     */
    public function genSelectByKV($data) {
        $returnData = [];
        foreach ($data as $key=>$value) {
            $returnData[] = [
                'value' => $key,
                'label' => $value,
            ];
        }
        return $returnData;
    }

    /**
     * 构造前端的select 
     * 
     */
    public function genSelectByVK($data) {
        $returnData = [];
        foreach ($data as $key=>$value) {
            $returnData[] = [
                'value' => $value,
                'label' => $key,
            ];
        }
        return $returnData;
    }


    /**
     * 构造前端的select 
     * 
     */
    public function genSelectByK($data, $k) {
        $returnData = [];
        foreach ($data as $value) {
            $returnData[] = [
                'value' => $value[$k],
                'label' => $value[$k],
            ];
        }
        return $returnData;
    }
}


================================================
FILE: app/Services/ToolService.php
================================================
<?php

namespace App\Services;


class ToolService
{
    /**
     * 构造前端的select 
     * 
     */
    public function objColumn($data, $key, $justkey = true) {
        $returnData = [];
        foreach ($data as $item) {
            if ($justkey) {
                $returnData[] = $item->$key;
            } else {
                $returnData[$item->$key] = $item;
            }
        }
        return $returnData;
    }

    /**
     * 简化sql
     */
    public static function checkParams($params, $notNull = []) {
        foreach ($notNull as $key => $value) {
            if (empty($params[$key])) {
                return "请输入".$value;
            }
        }
        return '';
    }

    /**
     * 简化sql
     */
    public static function ifQueryEq($query, $params, $field, $sqlfield = '') {
        $sqlfield = $sqlfield == '' ? $field : $sqlfield;
        if (isset($params[$field]) && $params[$field] !== "") {
            $query = $query->where($sqlfield, $params[$field]);
        }
        return $query;
    }

    /**
     * 清理空字段
     */
    public static function unsetEmptyField($model, $fields = []) {
        foreach ($fields as $field) {
            if (empty($model[$field])) unset($model[$field]);
        }
        return $model;
    }

    /**
     * 导出csv
     */
    public function csv($downname, $header, $data) {
        $tempfile = "/tmp/".time().".csv";
        $fp = fopen($tempfile, 'w+');//生成CSV文件
        $row = [];
        foreach($header as $k => $v) {
            $row[] = iconv("UTF-8", "GB2312//IGNORE", $v);
        }
        fputcsv($fp, $row);//生成报表头,
        foreach ($data as $item) {
            $row = [];
            foreach (array_keys($header) as $key) {
                $row[] = iconv("UTF-8", "GB2312//IGNORE", strval($item[$key]));
            }
            fputcsv($fp, $row);
        }
        fclose($fp);//关闭操作文件
        header("Content-Type: text/csv;charset=utf-8"); 
        header("Content-Disposition: attachment; filename=".$downname.'-'.date('Ymd').".csv"); 
        header('Cache-Control:must-revalidate,post-check=0,pre-check=0'); 
        header('Expires:0'); 
        header('Pragma:public');
        ob_start();//对输出数据进行压缩,可减少用户下载时候的等待时间
        echo file_get_contents($tempfile);
        ob_end_flush();//结束压缩
        exit;
    }
}

================================================
FILE: app/Services/UserService.php
================================================
<?php

namespace App\Services;

use App\Models\CustomerLog;
use App\Models\SystemUser;


class UserService
{
    /**
     * 获取有新数据分配权限的所有用户和剩余的分配次数
     */
    public function getAllAssignUser() {
        $model = new SystemUser();
        $logmodel = new CustomerLog();
        $users = $model->where('status', 1)->where('is_del', 0)->where('online', 1)->get();
        $retUser = [];
        $sort1 = [];
        $sort2 = [];
        foreach ($users as $user) {
            $config = json_decode($user['assign_rights'], true);
            if ($config["new"] > 0) {
                $count = $logmodel->getCountByUserIdAndTime($user['id'], CustomerLog::TYPE_ASSIGN_NEW, date('Y-m-d 00:00:00'), date('Y-m-d 00:00:00', strtotime('+1 day')))[0];
                $leftCount = $config["new"] - $count->cnt;
                $sort1[] = intval($count->id);
                $sort2[] = $leftCount;
                $retUser[$user['id'].'-UID'] = $leftCount; 
            }
        }
        array_multisort($sort1, SORT_ASC, $sort2, SORT_DESC, $retUser);
        return $retUser;
    }

    /**
     * 获取有认领剩余次数
     */
    public function getGetLeftTime($userId) {
        $model = new SystemUser();
        $logmodel = new CustomerLog();
        $user = $model->find($userId);
        $config = json_decode($user['assign_rights'], true);
        $leftCount = 0;
        if ($config["public"] > 0) {
            $count = $logmodel->getCountByUserIdAndTime($user['id'], CustomerLog::TYPE_GET, date('Y-m-d 00:00:00'), date('Y-m-d 00:00:00', strtotime('+1 day')))[0];
            $leftCount = $config["public"] - $count->cnt;
        }
        return $leftCount;
    }

       /**
     * 获取权限树
     * 
     * @param userId 信贷员id
     */
    public function getUserTree($userId = 0, $userIds = [])
    {
        $model = new SystemUser();
        $users = $model->getAllUserByParentId($userId);
        $list = [];
        foreach ($users as $user) {
            if (in_array($user->id, $userIds)) {
                continue;
            }
            $userIds[] = $user->id;
            $item = [
                'title' => $user->name,
                'key'  => $user->id,
            ];
            $children = $this->getUserTree($user->id, $userIds);
            if ($children) {
                $item['children'] = $children;
            }
            $list[] = $item;
        }
        return $list;
    }
}


================================================
FILE: app/User.php
================================================
<?php

namespace App;

use Illuminate\Auth\Authenticatable;
use Laravel\Lumen\Auth\Authorizable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;

class User extends Model implements AuthenticatableContract, AuthorizableContract
{
    use Authenticatable, Authorizable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email',
    ];

    /**
     * The attributes excluded from the model's JSON form.
     *
     * @var array
     */
    protected $hidden = [
        'password',
    ];
}


================================================
FILE: artisan
================================================
#!/usr/bin/env php
<?php

use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Output\ConsoleOutput;

/*
|--------------------------------------------------------------------------
| Create The Application
|--------------------------------------------------------------------------
|
| First we need to get an application instance. This creates an instance
| of the application / container and bootstraps the application so it
| is ready to receive HTTP / Console requests from the environment.
|
*/

$app = require __DIR__.'/bootstrap/app.php';

/*
|--------------------------------------------------------------------------
| Run The Artisan Application
|--------------------------------------------------------------------------
|
| When we run the console application, the current CLI command will be
| executed in this console and the response sent back to a terminal
| or another output device for the developers. Here goes nothing!
|
*/

$kernel = $app->make(
    'Illuminate\Contracts\Console\Kernel'
);

exit($kernel->handle(new ArgvInput, new ConsoleOutput));


================================================
FILE: bootstrap/app.php
================================================
<?php

require_once __DIR__.'/../vendor/autoload.php';

(new Laravel\Lumen\Bootstrap\LoadEnvironmentVariables(
    dirname(__DIR__)
))->bootstrap();

/*
|--------------------------------------------------------------------------
| Create The Application
|--------------------------------------------------------------------------
|
| Here we will load the environment and create the application instance
| that serves as the central piece of this framework. We'll use this
| application as an "IoC" container and router for this framework.
|
*/

$app = new Laravel\Lumen\Application(
    dirname(__DIR__)
);

$app->withFacades();

$app->withEloquent();

/*
|--------------------------------------------------------------------------
| Register Container Bindings
|--------------------------------------------------------------------------
|
| Now we will register a few bindings in the service container. We will
| register the exception handler and the console kernel. You may add
| your own bindings here if you like or you can make another file.
|
*/

$app->singleton(
    Illuminate\Contracts\Debug\ExceptionHandler::class,
    App\Exceptions\Handler::class
);

$app->singleton(
    Illuminate\Contracts\Console\Kernel::class,
    App\Console\Kernel::class
);

$app->singleton(Illuminate\Session\SessionManager::class, function () use ($app) {
    return $app->loadComponent('session', Illuminate\Session\SessionServiceProvider::class, 'session');
});

$app->singleton('session.store', function () use ($app) {
    return $app->loadComponent('session', Illuminate\Session\SessionServiceProvider::class, 'session.store');
});
/*
|--------------------------------------------------------------------------
| Register Middleware
|--------------------------------------------------------------------------
|
| Next, we will register the middleware with the application. These can
| be global middleware that run before and after each request into a
| route or middleware that'll be assigned to some specific routes.
|
*/

 $app->middleware([
    Illuminate\Session\Middleware\StartSession::class,
 ]);

$app->routeMiddleware([
     'auth' => App\Http\Middleware\AuthMiddleware::class,
]);


$app->alias('Excel', Maatwebsite\Excel\Facades\Excel::class);

/*
|--------------------------------------------------------------------------
| Register Service Providers
|--------------------------------------------------------------------------
|
| Here we will register all of the application's service providers which
| are used to bind services into the container. Service providers are
| totally optional, so you are not required to uncomment this line.
|
*/

$app->register(App\Providers\AppServiceProvider::class);
$app->register(Maatwebsite\Excel\ExcelServiceProvider::class);
// $app->register(App\Providers\AuthServiceProvider::class);
// $app->register(App\Providers\EventServiceProvider::class);

/*
|--------------------------------------------------------------------------
| Load The Application Routes
|--------------------------------------------------------------------------
|
| Next we will include the routes file so that they can all be added to
| the application. This will provide all of the URLs the application
| can respond to, as well as the controllers that may handle them.
|
*/

$app->router->group([
    'namespace' => 'App\Http\Controllers',
], function ($router) {
    require __DIR__.'/../routes/web.php';
});

return $app;


================================================
FILE: composer.json
================================================
{
    "name": "laravel/lumen",
    "description": "The Laravel Lumen Framework.",
    "keywords": ["framework", "laravel", "lumen"],
    "license": "MIT",
    "type": "project",
    "require": {
        "php": ">=7.1.3",
        "guzzlehttp/guzzle": "^6.5",
        "illuminate/session": "^5.8",
        "laravel/lumen-framework": "5.8.*",
        "league/flysystem": "^1.0",
        "maatwebsite/excel": "^3.0",
        "workerman/workerman": "^4.1"
    },
    "require-dev": {
        "fzaninotto/faker": "^1.4",
        "phpunit/phpunit": "^7.0",
        "mockery/mockery": "^1.0"
    },
    "autoload": {
        "classmap": [
            "database/seeds",
            "database/factories"
        ],
        "psr-4": {
            "App\\": "app/"
        }
    },
    "autoload-dev": {
        "classmap": [
            "tests/"
        ]
    },
    "scripts": {
        "post-root-package-install": [
            "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
        ]
    },
    "config": {
        "preferred-install": "dist",
        "sort-packages": true,
        "optimize-autoloader": true
    },
    "minimum-stability": "dev",
    "prefer-stable": true
}


================================================
FILE: config/database.php
================================================
<?php
return [
    'default' => 'mysql',
    'connections' => [
        'mysql' => [
            'driver' => 'mysql',
            'host' => '127.0.0.1',
            'port' => '3306',
            'database' => 'crm',
            'username' => 'crm',
            'password' => '123456',
            'charset' => 'utf8mb4',
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => false,
            'engine' => null,
        ],
    ]
];

================================================
FILE: config/logging.php
================================================
<?php

use Monolog\Handler\NullHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\SyslogUdpHandler;

return [

    /*
    |--------------------------------------------------------------------------
    | Default Log Channel
    |--------------------------------------------------------------------------
    |
    | This option defines the default log channel that gets used when writing
    | messages to the logs. The name specified in this option should match
    | one of the channels defined in the "channels" configuration array.
    |
    */

    'default' => env('LOG_CHANNEL', 'stack'),

    /*
    |--------------------------------------------------------------------------
    | Deprecations Log Channel
    |--------------------------------------------------------------------------
    |
    | This option controls the log channel that should be used to log warnings
    | regarding deprecated PHP and library features. This allows you to get
    | your application ready for upcoming major versions of dependencies.
    |
    */

    'deprecations' => [
        'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'),
        'trace' => false,
    ],

    /*
    |--------------------------------------------------------------------------
    | Log Channels
    |--------------------------------------------------------------------------
    |
    | Here you may configure the log channels for your application. Out of
    | the box, Laravel uses the Monolog PHP logging library. This gives
    | you a variety of powerful log handlers / formatters to utilize.
    |
    | Available Drivers: "single", "daily", "slack", "syslog",
    |                    "errorlog", "monolog",
    |                    "custom", "stack"
    |
    */

    'channels' => [
        'stack' => [
            'driver' => 'stack',
            'channels' => ['daily'],
            'ignore_exceptions' => false,
        ],

        'single' => [
            'driver' => 'single',
            'path' => storage_path('logs/laravel.log'),
            'level' => env('LOG_LEVEL', 'debug'),
        ],

        'daily' => [
            'driver' => 'daily',
            'path' => '/www/wwwlogs/crmapp/app.log',
            'level' => env('LOG_LEVEL', 'debug'),
            'days' => 14,
        ],

        'slack' => [
            'driver' => 'slack',
            'url' => env('LOG_SLACK_WEBHOOK_URL'),
            'username' => 'Laravel Log',
            'emoji' => ':boom:',
            'level' => env('LOG_LEVEL', 'critical'),
        ],

        'papertrail' => [
            'driver' => 'monolog',
            'level' => env('LOG_LEVEL', 'debug'),
            'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class),
            'handler_with' => [
                'host' => env('PAPERTRAIL_URL'),
                'port' => env('PAPERTRAIL_PORT'),
                'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'),
            ],
        ],

        'stderr' => [
            'driver' => 'monolog',
            'level' => env('LOG_LEVEL', 'debug'),
            'handler' => StreamHandler::class,
            'formatter' => env('LOG_STDERR_FORMATTER'),
            'with' => [
                'stream' => 'php://stderr',
            ],
        ],

        'syslog' => [
            'driver' => 'syslog',
            'level' => env('LOG_LEVEL', 'debug'),
        ],

        'errorlog' => [
            'driver' => 'errorlog',
            'level' => env('LOG_LEVEL', 'debug'),
        ],

        'null' => [
            'driver' => 'monolog',
            'handler' => NullHandler::class,
        ],

        'emergency' => [
            'path' => storage_path('logs/laravel.log'),
        ],
    ],

];

================================================
FILE: config/session.php
================================================
<?php


return [

    /*
    |--------------------------------------------------------------------------
    | Default Session Driver
    |--------------------------------------------------------------------------
    |
    | This option controls the default session "driver" that will be used on
    | requests. By default, we will use the lightweight native driver but
    | you may specify any of the other wonderful drivers provided here.
    |
    | Supported: "file", "cookie", "database", "apc",
    |            "memcached", "redis", "dynamodb", "array"
    |
    */

    'driver' => 'file',

    /*
    |--------------------------------------------------------------------------
    | Session Lifetime
    |--------------------------------------------------------------------------
    |
    | Here you may specify the number of minutes that you wish the session
    | to be allowed to remain idle before it expires. If you want them
    | to immediately expire on the browser closing, set that option.
    |
    */

    'lifetime' => 120,

    'expire_on_close' => false,

    /*
    |--------------------------------------------------------------------------
    | Session Encryption
    |--------------------------------------------------------------------------
    |
    | This option allows you to easily specify that all of your session data
    | should be encrypted before it is stored. All encryption will be run
    | automatically by Laravel and you can use the Session like normal.
    |
    */

    'encrypt' => false,

    /*
    |--------------------------------------------------------------------------
    | Session File Location
    |--------------------------------------------------------------------------
    |
    | When using the native session driver, we need a location where session
    | files may be stored. A default has been set for you but a different
    | location may be specified. This is only needed for file sessions.
    |
    */

    'files' => '/www/wwwroot/session',

    /*
    |--------------------------------------------------------------------------
    | Session Database Connection
    |--------------------------------------------------------------------------
    |
    | When using the "database" or "redis" session drivers, you may specify a
    | connection that should be used to manage these sessions. This should
    | correspond to a connection in your database configuration options.
    |
    */

    'connection' => '',

    /*
    |--------------------------------------------------------------------------
    | Session Database Table
    |-------------------
Download .txt
gitextract_m3jzydhx/

├── .github/
│   ├── actions/
│   │   └── build-docs/
│   │       ├── Dockerfile
│   │       └── entrypoint.sh
│   └── workflows/
│       ├── codecov.yml
│       ├── docs.yml
│       └── install.yml
├── .gitignore
├── LICENSE.md
├── README.md
├── app/
│   ├── Console/
│   │   ├── Commands/
│   │   │   ├── .gitkeep
│   │   │   ├── Assign.php
│   │   │   ├── Channel.php
│   │   │   └── Mobile.php
│   │   └── Kernel.php
│   ├── Events/
│   │   ├── Event.php
│   │   └── ExampleEvent.php
│   ├── Exceptions/
│   │   └── Handler.php
│   ├── Http/
│   │   ├── Controllers/
│   │   │   ├── AssignController.php
│   │   │   ├── Controller.php
│   │   │   ├── CustomController.php
│   │   │   ├── NoticeController.php
│   │   │   ├── ProductController.php
│   │   │   ├── SystemRoleController.php
│   │   │   ├── SystemTeamController.php
│   │   │   ├── SystemUserController.php
│   │   │   └── UserController.php
│   │   └── Middleware/
│   │       └── AuthMiddleware.php
│   ├── Jobs/
│   │   ├── ExampleJob.php
│   │   └── Job.php
│   ├── Listeners/
│   │   └── ExampleListener.php
│   ├── Models/
│   │   ├── BaseModel.php
│   │   ├── Captcha.php
│   │   ├── Channel.php
│   │   ├── Constants.php
│   │   ├── Customer.php
│   │   ├── CustomerBack.php
│   │   ├── CustomerLog.php
│   │   ├── CustomerRemarkLog.php
│   │   ├── CustomerRuleConfig.php
│   │   ├── Excel/
│   │   │   └── CustomerModel.php
│   │   ├── Notice.php
│   │   ├── Product.php
│   │   ├── SystemDict.php
│   │   ├── SystemFields.php
│   │   ├── SystemLog.php
│   │   ├── SystemRight.php
│   │   ├── SystemRole.php
│   │   ├── SystemRoleRight.php
│   │   ├── SystemSetting.php
│   │   ├── SystemTeam.php
│   │   ├── SystemUser.php
│   │   └── SystemUserRole.php
│   ├── Providers/
│   │   ├── AppServiceProvider.php
│   │   ├── AuthServiceProvider.php
│   │   └── EventServiceProvider.php
│   ├── Services/
│   │   ├── AssignRule/
│   │   │   ├── Rule1.php
│   │   │   ├── Rule10.php
│   │   │   ├── Rule11.php
│   │   │   ├── Rule13.php
│   │   │   ├── Rule2.php
│   │   │   ├── Rule3.php
│   │   │   ├── Rule4.php
│   │   │   ├── Rule5.php
│   │   │   ├── Rule6.php
│   │   │   └── Rule7.php
│   │   ├── AssignService.php
│   │   ├── CustomerEditService.php
│   │   ├── CustomerService.php
│   │   ├── Hook/
│   │   │   └── LoginHook.php
│   │   ├── RightService.php
│   │   ├── SelectService.php
│   │   ├── ToolService.php
│   │   └── UserService.php
│   └── User.php
├── artisan
├── bootstrap/
│   └── app.php
├── composer.json
├── config/
│   ├── database.php
│   ├── logging.php
│   └── session.php
├── database/
│   ├── factories/
│   │   └── ModelFactory.php
│   ├── migrations/
│   │   └── .gitkeep
│   └── seeds/
│       └── DatabaseSeeder.php
├── docs/
│   └── README.md
├── install/
│   ├── crm.sql
│   └── nginx.conf
├── nginx.conf
├── package.json
├── phpunit.xml
├── public/
│   ├── .htaccess
│   ├── index.html
│   ├── index.php
│   └── resource/
│       └── template.xlsx
├── resources/
│   └── views/
│       └── .gitkeep
├── routes/
│   └── web.php
├── storage/
│   ├── app/
│   │   └── .gitignore
│   ├── framework/
│   │   ├── cache/
│   │   │   └── .gitignore
│   │   └── views/
│   │       └── .gitignore
│   └── logs/
│       └── .gitignore
└── tests/
    ├── ExampleTest.php
    └── TestCase.php
Download .txt
SYMBOL INDEX (281 symbols across 68 files)

FILE: app/Console/Commands/Assign.php
  class Assign (line 8) | class Assign extends Command
    method handle (line 16) | public function handle() {

FILE: app/Console/Commands/Channel.php
  class Channel (line 8) | class Channel extends Command
    method handle (line 16) | public function handle() {

FILE: app/Console/Commands/Mobile.php
  class Mobile (line 8) | class Mobile extends Command
    method handle (line 16) | public function handle() {

FILE: app/Console/Kernel.php
  class Kernel (line 8) | class Kernel extends ConsoleKernel
    method schedule (line 29) | protected function schedule(Schedule $schedule)

FILE: app/Events/Event.php
  class Event (line 7) | abstract class Event

FILE: app/Events/ExampleEvent.php
  class ExampleEvent (line 5) | class ExampleEvent extends Event
    method __construct (line 12) | public function __construct()

FILE: app/Exceptions/Handler.php
  class Handler (line 12) | class Handler extends ExceptionHandler
    method report (line 34) | public function report(Exception $exception)
    method render (line 46) | public function render($request, Exception $exception)

FILE: app/Http/Controllers/AssignController.php
  class AssignController (line 14) | class AssignController extends Controller
    method edit (line 19) | public function edit(Request $request) {
    method log (line 45) | public function log(Request $request) {
    method config (line 68) | public function config(Request $request) {
    method editrule (line 88) | public function editrule (Request $request) {
    method setstatus (line 102) | public function setstatus(Request $request) {

FILE: app/Http/Controllers/Controller.php
  class Controller (line 7) | class Controller extends BaseController
    method apiReturn (line 14) | protected function apiReturn($code = 20000, $data = [], $msg = '', $ht...

FILE: app/Http/Controllers/CustomController.php
  class CustomController (line 25) | class CustomController extends Controller
    method list (line 30) | public function list(Request $request)
    method info (line 128) | public function info(Request $request)
    method edit (line 181) | public function edit(Request $request)
    method assign (line 214) | public function assign(Request $request)
    method get (line 242) | public function get(Request $request)
    method assignlist (line 273) | public function assignlist(Request $request)
    method followlist (line 303) | public function followlist(Request $request)
    method starlist (line 335) | public function starlist(Request $request)
    method lock (line 366) | public function lock(Request $request) {
    method giveup (line 382) | public function giveup(Request $request) {
    method batchgiveup (line 394) | public function batchgiveup(Request $request) {
    method batchget (line 411) | public function batchget(Request $request) {
    method important (line 437) | public function important(Request $request) {
    method lahei (line 453) | public function lahei(Request $request) {
    method upload (line 467) | public function upload(Request $request) {
    method getNoticeList (line 524) | public function getNoticeList (Request $request) {
    method addNotices (line 545) | public function addNotices(Request $request) {
    method addDianping (line 580) | public function addDianping(Request $request) {
    method addBack (line 601) | public function addBack(Request $request) {
    method editBack (line 641) | public function editBack(Request $request) {
    method delBack (line 673) | public function delBack(Request $request) {
    method backlist (line 684) | public function backlist(Request $request)
    method follownum (line 717) | public function follownum(Request $request)
    method data (line 733) | public function data(Request $request)

FILE: app/Http/Controllers/NoticeController.php
  class NoticeController (line 11) | class NoticeController extends Controller
    method unreadlist (line 16) | public function unreadlist(Request $request)
    method list (line 42) | public function list(Request $request)
    method read (line 68) | public function read(Request $request)

FILE: app/Http/Controllers/ProductController.php
  class ProductController (line 10) | class ProductController extends Controller
    method list (line 15) | public function list(Request $request) {
    method edit (line 31) | public function edit(Request $request) {
    method info (line 52) | public function info(Request $request) {
    method del (line 70) | public function del(Request $request) {

FILE: app/Http/Controllers/SystemRoleController.php
  class SystemRoleController (line 16) | class SystemRoleController extends Controller
    method list (line 21) | public function list(Request $request) {
    method edit (line 31) | public function edit(Request $request) {
    method lock (line 64) | public function lock(Request $request) {
    method info (line 75) | public function info(Request $request) {
    method delete (line 106) | public function delete(Request $request) {

FILE: app/Http/Controllers/SystemTeamController.php
  class SystemTeamController (line 10) | class SystemTeamController extends Controller
    method list (line 15) | public function list(Request $request) {
    method edit (line 34) | public function edit(Request $request) {
    method info (line 49) | public function info(Request $request) {
    method del (line 66) | public function del(Request $request) {

FILE: app/Http/Controllers/SystemUserController.php
  class SystemUserController (line 17) | class SystemUserController extends Controller
    method list (line 22) | public function list(Request $request) {
    method edit (line 40) | public function edit(Request $request) {
    method lock (line 66) | public function lock(Request $request) {
    method resetpwd (line 77) | public function resetpwd(Request $request) {
    method delete (line 91) | public function delete(Request $request) {
    method info (line 106) | public function info(Request $request) {
    method role (line 137) | public function role(Request $request) {
    method online (line 157) | public function online(Request $request) {
    method setting (line 170) | public function setting(Request $request) {

FILE: app/Http/Controllers/UserController.php
  class UserController (line 17) | class UserController extends Controller
    method login (line 22) | public function login(Request $request)
    method logout (line 52) | public function logout(Request $request)
    method info (line 61) | public function info(Request $request)
    method menu (line 87) | public function menu(Request $request)
    method resetpassword (line 100) | public function resetpassword(Request $request)
    method dashboard (line 120) | public function dashboard(Request $request)
    method captcha (line 184) | public function captcha(Request $request) {
    method donothing (line 192) | public function donothing(Request $request) {

FILE: app/Http/Middleware/AuthMiddleware.php
  class AuthMiddleware (line 11) | class AuthMiddleware
    method handle (line 23) | public function handle($request, Closure $next)

FILE: app/Jobs/ExampleJob.php
  class ExampleJob (line 5) | class ExampleJob extends Job
    method __construct (line 12) | public function __construct()
    method handle (line 22) | public function handle()

FILE: app/Jobs/Job.php
  class Job (line 10) | abstract class Job implements ShouldQueue

FILE: app/Listeners/ExampleListener.php
  class ExampleListener (line 9) | class ExampleListener
    method __construct (line 16) | public function __construct()
    method handle (line 27) | public function handle(ExampleEvent $event)

FILE: app/Models/BaseModel.php
  class BaseModel (line 7) | class BaseModel extends Model

FILE: app/Models/Captcha.php
  class Captcha (line 7) | class Captcha {
    method create (line 13) | public function create($request) {

FILE: app/Models/Channel.php
  class Channel (line 7) | class Channel extends Model

FILE: app/Models/Constants.php
  class Constants (line 9) | class Constants

FILE: app/Models/Customer.php
  class Customer (line 8) | class Customer extends Model
    method _createWhere (line 22) | private function _createWhere($params) {
    method getLists (line 126) | public function getLists($params) {
    method getCount (line 135) | public function getCount($params) {
    method _createChannelWhere (line 139) | public function _createChannelWhere($params) {
    method getListsGroupByChannel (line 169) | public function getListsGroupByChannel($params) {
    method getListsGroupByChannel2 (line 172) | public function getListsGroupByChannel2($params) {
    method getMyCount (line 178) | public function getMyCount($params) {
    method getCustomerByChannelId (line 198) | public function getCustomerByChannelId($channel, $channelId) {
    method getWaitForFollow (line 203) | public function getWaitForFollow($userId) {

FILE: app/Models/CustomerBack.php
  class CustomerBack (line 7) | class CustomerBack extends Model
    method _createWhere (line 20) | private function _createWhere($params) {
    method getLists (line 50) | public function getLists($params) {
    method getCount (line 56) | public function getCount($params) {
    method getPaihangbang (line 63) | public function getPaihangbang() {
    method getPaihangbang2 (line 74) | public function getPaihangbang2() {

FILE: app/Models/CustomerLog.php
  class CustomerLog (line 8) | class CustomerLog extends Model
    method saveLog (line 62) | public function saveLog($type, $id, $before, $after, $userId = 0, $rem...
    method getLogListByCustomerId (line 73) | public function getLogListByCustomerId($customerId, $limit) {
    method getLogListByCustomerIdAndType (line 111) | public function getLogListByCustomerIdAndType($customerId, $type, $par...
    method getCountByCustomerIdAndType (line 117) | public function getCountByCustomerIdAndType($customerId, $type) {
    method getCountByUserIdAndTime (line 121) | public function getCountByUserIdAndTime($userId, $type, $startTime, $e...
    method getLogListByUserIdAndType (line 126) | public function getLogListByUserIdAndType($userId, $type, $offset, $pa...

FILE: app/Models/CustomerRemarkLog.php
  class CustomerRemarkLog (line 8) | class CustomerRemarkLog extends Model
    method saveLog (line 21) | public function saveLog($id, $remark, $userId) {
    method getLogListByCustomerId (line 29) | public function getLogListByCustomerId($customerId, $limit) {

FILE: app/Models/CustomerRuleConfig.php
  class CustomerRuleConfig (line 8) | class CustomerRuleConfig extends Model

FILE: app/Models/Excel/CustomerModel.php
  class CustomerModel (line 9) | class CustomerModel implements ToModel
    method model (line 11) | public function model(array $rows)

FILE: app/Models/Notice.php
  class Notice (line 8) | class Notice extends Model
    method getUnRead (line 21) | public function getUnRead($userId) {
    method read (line 27) | public function read($ids) {
    method getUnReadCount (line 32) | public function getUnReadCount($userId) {
    method _createWhere (line 39) | private function _createWhere($params) {
    method getLists (line 59) | public function getLists($params) {
    method getCount (line 65) | public function getCount($params = []) {
    method getListByUserId (line 70) | public function getListByUserId($userId, $limit) {
    method getListByUserIdAndCustomer (line 75) | public function getListByUserIdAndCustomer($customId, $userId, $limit) {

FILE: app/Models/Product.php
  class Product (line 7) | class Product extends Model
    method getAllProduct (line 18) | public function getAllProduct() {
    method getAllBank (line 22) | public function getAllBank() {
    method _createWhere (line 26) | private function _createWhere($params) {
    method getLists (line 37) | public function getLists($params) {
    method getCount (line 42) | public function getCount($params) {

FILE: app/Models/SystemDict.php
  class SystemDict (line 7) | class SystemDict extends Model
    method getListByType (line 26) | public function getListByType($type) {
    method getListByGroup (line 35) | public function getListByGroup($group) {

FILE: app/Models/SystemFields.php
  class SystemFields (line 7) | class SystemFields extends Model
    method getSelect (line 18) | public function getSelect() {

FILE: app/Models/SystemLog.php
  class SystemLog (line 7) | class SystemLog extends Model
    method saveLog (line 24) | public function saveLog($type, $id, $before, $after, $userId = 0, $rem...
    method getLogListById (line 35) | public function getLogListById($type, $id, $params) {
    method getLogCountById (line 40) | public function getLogCountById($type, $id, $params) {

FILE: app/Models/SystemRight.php
  class SystemRight (line 7) | class SystemRight extends Model
    method getRightByUserId (line 16) | public function getRightByUserId($userId) {
    method getRightByRoleId (line 22) | public function getRightByRoleId($roleId) {
    method getAllRight (line 28) | public function getAllRight() {

FILE: app/Models/SystemRole.php
  class SystemRole (line 7) | class SystemRole extends Model
    method getRoleByUserId (line 23) | public function getRoleByUserId($userId) {
    method getUserByRoleId (line 30) | public function getUserByRoleId($roleId) {
    method getRoleSelect (line 36) | public function getRoleSelect() {
    method _createWhere (line 50) | private function _createWhere($params) {
    method getLists (line 61) | public function getLists($params) {
    method getCount (line 70) | public function getCount($params) {

FILE: app/Models/SystemRoleRight.php
  class SystemRoleRight (line 7) | class SystemRoleRight extends Model
    method deleteRights (line 16) | public function deleteRights($roleId, $rightIds) {
    method addRights (line 25) | public function addRights($roleId, $rightIds){

FILE: app/Models/SystemSetting.php
  class SystemSetting (line 7) | class SystemSetting extends Model

FILE: app/Models/SystemTeam.php
  class SystemTeam (line 7) | class SystemTeam extends Model
    method getAllTeam (line 21) | public function getAllTeam() {
    method getAllTeamMap (line 28) | public function getAllTeamMap() {
    method _createWhere (line 38) | private function _createWhere($params) {
    method getLists (line 52) | public function getLists($params) {
    method getCount (line 61) | public function getCount($params) {

FILE: app/Models/SystemUser.php
  class SystemUser (line 10) | class SystemUser extends Model
    method _createWhere (line 26) | private function _createWhere($params) {
    method getLists (line 46) | public function getLists($params) {
    method getCount (line 63) | public function getCount($params) {
    method getAllUserWithDel (line 67) | public function getAllUserWithDel($userId = 0) {
    method getAllUserWithDelMap (line 71) | public function getAllUserWithDelMap($userId = 0) {
    method getAllUserTeamWithDelMap (line 78) | public function getAllUserTeamWithDelMap($userId = 0) {
    method getAllUser (line 85) | public function getAllUser($userId = 0) {
    method getAllUserMap (line 89) | public function getAllUserMap($userId = 0) {
    method getAllUserByParentId (line 96) | public function getAllUserByParentId($parentId = 0) {
    method getUserCountByTeamid (line 100) | public function getUserCountByTeamid($teamId) {
    method getUserByTeamid (line 104) | public function getUserByTeamid($teamId) {

FILE: app/Models/SystemUserRole.php
  class SystemUserRole (line 7) | class SystemUserRole extends Model
    method getRoleByUserId (line 18) | public function getRoleByUserId($userId) {
    method delRoles (line 22) | public function delRoles($userId, $roleIds){
    method addRoles (line 29) | public function addRoles($userId, $roleIds){

FILE: app/Providers/AppServiceProvider.php
  class AppServiceProvider (line 8) | class AppServiceProvider extends ServiceProvider
    method register (line 15) | public function register()
    method boot (line 23) | public function boot() {

FILE: app/Providers/AuthServiceProvider.php
  class AuthServiceProvider (line 9) | class AuthServiceProvider extends ServiceProvider
    method register (line 16) | public function register()
    method boot (line 26) | public function boot()

FILE: app/Providers/EventServiceProvider.php
  class EventServiceProvider (line 7) | class EventServiceProvider extends ServiceProvider

FILE: app/Services/AssignRule/Rule1.php
  class Rule1 (line 12) | class Rule1
    method handle (line 14) | public function handle($config) {

FILE: app/Services/AssignRule/Rule10.php
  class Rule10 (line 10) | class Rule10
    method handle (line 12) | public function handle($config) {

FILE: app/Services/AssignRule/Rule11.php
  class Rule11 (line 13) | class Rule11
    method handle (line 15) | public function handle($config) {

FILE: app/Services/AssignRule/Rule13.php
  class Rule13 (line 10) | class Rule13
    method handle (line 12) | public function handle($config) {

FILE: app/Services/AssignRule/Rule2.php
  class Rule2 (line 10) | class Rule2
    method handle (line 12) | public function handle($config) {

FILE: app/Services/AssignRule/Rule3.php
  class Rule3 (line 10) | class Rule3
    method handle (line 12) | public function handle($config) {

FILE: app/Services/AssignRule/Rule4.php
  class Rule4 (line 10) | class Rule4
    method handle (line 12) | public function handle($config) {

FILE: app/Services/AssignRule/Rule5.php
  class Rule5 (line 10) | class Rule5
    method handle (line 12) | public function handle($config) {

FILE: app/Services/AssignRule/Rule6.php
  class Rule6 (line 10) | class Rule6
    method handle (line 12) | public function handle($config) {

FILE: app/Services/AssignRule/Rule7.php
  class Rule7 (line 10) | class Rule7
    method handle (line 12) | public function handle($config) {

FILE: app/Services/AssignService.php
  class AssignService (line 9) | class AssignService
    method genText (line 22) | public function genText($json) {

FILE: app/Services/CustomerEditService.php
  class CustomerEditService (line 16) | class CustomerEditService
    method edit (line 19) | public function edit($params, $operUserId) {
    method add (line 79) | public function add($params, $operUserId) {

FILE: app/Services/CustomerService.php
  class CustomerService (line 13) | class CustomerService
    method diff (line 71) | public function diff($cust1, $cust2) {
    method canAssign (line 88) | public function canAssign($customId) {
    method assign (line 102) | public function assign($customId, $followUserId, $operUserId = 0, $ass...
    method get (line 156) | public function get($customId, $followUserId, $operUserId = 0, $assign...
    method giveup (line 200) | public function giveup($customId, $userId = 0, $remark = "") {
    method genZizhi (line 218) | public function genZizhi($custom) {
    method getNotFollowTime (line 247) | public function getNotFollowTime($custom) {
    method genCustomByExcelRow (line 261) | public function genCustomByExcelRow($row, $dict) {
    method addChannelCustomer (line 344) | public function addChannelCustomer($custom) {

FILE: app/Services/Hook/LoginHook.php
  class LoginHook (line 11) | class LoginHook
    method canLogin (line 16) | public static function canLogin($userId, $request) {
    method getPage (line 33) | public static function getPage($userId) {

FILE: app/Services/RightService.php
  class RightService (line 9) | class RightService
    method getRightTree (line 16) | public function getRightTree($userId = 0)
    method getDefaultRight (line 84) | public function getDefaultRight()
    method getCustomViews (line 127) | public function getCustomViews($userId) {
    method getSubUserids (line 148) | public function getSubUserids($userId, &$nowSubUserids = [], $time = 0) {

FILE: app/Services/SelectService.php
  class SelectService (line 6) | class SelectService
    method genKv (line 12) | public function genKv($data, $key, $value) {
    method genSelect (line 24) | public function genSelect($data, $value, $label) {
    method genSelectByKV (line 39) | public function genSelectByKV($data) {
    method genSelectByVK (line 54) | public function genSelectByVK($data) {
    method genSelectByK (line 70) | public function genSelectByK($data, $k) {

FILE: app/Services/ToolService.php
  class ToolService (line 6) | class ToolService
    method objColumn (line 12) | public function objColumn($data, $key, $justkey = true) {
    method checkParams (line 27) | public static function checkParams($params, $notNull = []) {
    method ifQueryEq (line 39) | public static function ifQueryEq($query, $params, $field, $sqlfield = ...
    method unsetEmptyField (line 50) | public static function unsetEmptyField($model, $fields = []) {
    method csv (line 60) | public function csv($downname, $header, $data) {

FILE: app/Services/UserService.php
  class UserService (line 9) | class UserService
    method getAllAssignUser (line 14) | public function getAllAssignUser() {
    method getGetLeftTime (line 38) | public function getGetLeftTime($userId) {
    method getUserTree (line 56) | public function getUserTree($userId = 0, $userIds = [])

FILE: app/User.php
  class User (line 11) | class User extends Model implements AuthenticatableContract, Authorizabl...

FILE: database/seeds/DatabaseSeeder.php
  class DatabaseSeeder (line 5) | class DatabaseSeeder extends Seeder
    method run (line 12) | public function run()

FILE: install/crm.sql
  type `channel` (line 1) | CREATE TABLE `channel` (
  type `customer` (line 15) | CREATE TABLE `customer` (
  type `customer_backs` (line 80) | CREATE TABLE `customer_backs` (
  type `customer_log` (line 102) | CREATE TABLE `customer_log` (
  type `customer_remark_log` (line 116) | CREATE TABLE `customer_remark_log` (
  type `customer_rule_config` (line 127) | CREATE TABLE `customer_rule_config` (
  type `dict` (line 157) | CREATE TABLE `dict` (
  type `product` (line 240) | CREATE TABLE `product` (
  type `system_field` (line 260) | CREATE TABLE `system_field` (
  type `system_log` (line 306) | CREATE TABLE `system_log` (
  type `system_right` (line 324) | CREATE TABLE `system_right` (
  type `system_role` (line 446) | CREATE TABLE `system_role` (
  type `system_role_field` (line 470) | CREATE TABLE `system_role_field` (
  type `system_role_right` (line 484) | CREATE TABLE `system_role_right` (
  type `system_setting` (line 626) | CREATE TABLE `system_setting` (
  type `system_team` (line 650) | CREATE TABLE `system_team` (
  type `system_user` (line 665) | CREATE TABLE `system_user` (
  type `system_user_role` (line 696) | CREATE TABLE `system_user_role` (

FILE: tests/ExampleTest.php
  class ExampleTest (line 6) | class ExampleTest extends TestCase
    method testExample (line 13) | public function testExample()

FILE: tests/TestCase.php
  class TestCase (line 3) | abstract class TestCase extends Laravel\Lumen\Testing\TestCase
    method createApplication (line 10) | public function createApplication()
Condensed preview — 100 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (289K chars).
[
  {
    "path": ".github/actions/build-docs/Dockerfile",
    "chars": 454,
    "preview": "FROM phpdoc/phpdoc\n\nLABEL \"repository\"=\"https://github.com/qincrm/crm\"\n\nLABEL \"com.github.actions.name\"=\"Build Docs\"\nLAB"
  },
  {
    "path": ".github/actions/build-docs/entrypoint.sh",
    "chars": 43,
    "preview": "#!/bin/sh\n\nset -eu\n\n/opt/phpdoc/bin/phpdoc\n"
  },
  {
    "path": ".github/workflows/codecov.yml",
    "chars": 264,
    "preview": "name: codecov\n\non:\n  push:\n    branches: [ \"main\" ]\n  pull_request:\n    branches: [ \"main\" ]\n\npermissions:\n  contents: r"
  },
  {
    "path": ".github/workflows/docs.yml",
    "chars": 732,
    "preview": "name: Docs\non:\n  push:\n    branches:\n      - master # disable\npermissions: {}\njobs:\n  build_and_publish:\n    permissions"
  },
  {
    "path": ".github/workflows/install.yml",
    "chars": 971,
    "preview": "name: install\n\non:\n  push:\n    branches: [ \"main\" ]\n  pull_request:\n    branches: [ \"main\" ]\n\npermissions:\n  contents: r"
  },
  {
    "path": ".gitignore",
    "chars": 66,
    "preview": "/vendor\r\n/.idea\r\nHomestead.json\r\nHomestead.yaml\r\n.env\r\n.DS_Store\r\n"
  },
  {
    "path": "LICENSE.md",
    "chars": 11357,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.md",
    "chars": 3877,
    "preview": "# <img src=\"https://github.com/qincrm/crm/raw/main/resources/logo.png\" width=\"50px\" style=\"margin-bottom: -12px;\"> 司跃CRM"
  },
  {
    "path": "app/Console/Commands/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "app/Console/Commands/Assign.php",
    "chars": 1366,
    "preview": "<?php\r\n\r\nnamespace App\\Console\\Commands;\r\n\r\nuse Illuminate\\Console\\Command;\r\nuse App\\Models\\CustomerRuleConfig;\r\n\r\nclass"
  },
  {
    "path": "app/Console/Commands/Channel.php",
    "chars": 683,
    "preview": "<?php\r\n\r\nnamespace App\\Console\\Commands;\r\n\r\nuse Illuminate\\Console\\Command;\r\nuse App\\Services\\CustomerService;\r\n\r\nclass "
  },
  {
    "path": "app/Console/Commands/Mobile.php",
    "chars": 1129,
    "preview": "<?php\n\nnamespace App\\Console\\Commands;\n\nuse App\\Models\\Customer;\nuse Illuminate\\Console\\Command;\n\nclass Mobile extends C"
  },
  {
    "path": "app/Console/Kernel.php",
    "chars": 711,
    "preview": "<?php\r\n\r\nnamespace App\\Console;\r\n\r\nuse Illuminate\\Console\\Scheduling\\Schedule;\r\nuse Laravel\\Lumen\\Console\\Kernel as Cons"
  },
  {
    "path": "app/Events/Event.php",
    "chars": 131,
    "preview": "<?php\r\n\r\nnamespace App\\Events;\r\n\r\nuse Illuminate\\Queue\\SerializesModels;\r\n\r\nabstract class Event\r\n{\r\n    use SerializesM"
  },
  {
    "path": "app/Events/ExampleEvent.php",
    "chars": 219,
    "preview": "<?php\r\n\r\nnamespace App\\Events;\r\n\r\nclass ExampleEvent extends Event\r\n{\r\n    /**\r\n     * Create a new event instance.\r\n   "
  },
  {
    "path": "app/Exceptions/Handler.php",
    "chars": 1352,
    "preview": "<?php\r\n\r\nnamespace App\\Exceptions;\r\n\r\nuse Exception;\r\nuse Illuminate\\Validation\\ValidationException;\r\nuse Illuminate\\Aut"
  },
  {
    "path": "app/Http/Controllers/AssignController.php",
    "chars": 4057,
    "preview": "<?php\r\n\r\nnamespace App\\Http\\Controllers;\r\n\r\nuse App\\Models\\CustomerRuleConfig;\r\nuse App\\Models\\SystemDict;\r\nuse App\\Mode"
  },
  {
    "path": "app/Http/Controllers/Controller.php",
    "chars": 473,
    "preview": "<?php\r\n\r\nnamespace App\\Http\\Controllers;\r\n\r\nuse Laravel\\Lumen\\Routing\\Controller as BaseController;\r\n\r\nclass Controller "
  },
  {
    "path": "app/Http/Controllers/CustomController.php",
    "chars": 30114,
    "preview": "<?php\r\n\r\nnamespace App\\Http\\Controllers;\r\n\r\nuse App\\Models\\Constants;\r\nuse App\\Models\\Customer;\r\nuse App\\Models\\Customer"
  },
  {
    "path": "app/Http/Controllers/NoticeController.php",
    "chars": 2467,
    "preview": "<?php\r\n\r\nnamespace App\\Http\\Controllers;\r\n\r\nuse App\\Models\\Customer;\r\nuse App\\Models\\Notice;\r\nuse App\\Models\\SystemDict;"
  },
  {
    "path": "app/Http/Controllers/ProductController.php",
    "chars": 2818,
    "preview": "<?php\n\nnamespace App\\Http\\Controllers;\n\nuse App\\Models\\Product;\nuse App\\Models\\SystemUser;\nuse App\\Services\\SelectServic"
  },
  {
    "path": "app/Http/Controllers/SystemRoleController.php",
    "chars": 4513,
    "preview": "<?php\r\n\r\nnamespace App\\Http\\Controllers;\r\n\r\nuse App\\Models\\SystemFields;\r\nuse App\\Models\\SystemRight;\r\nuse App\\Models\\Sy"
  },
  {
    "path": "app/Http/Controllers/SystemTeamController.php",
    "chars": 2739,
    "preview": "<?php\r\n\r\nnamespace App\\Http\\Controllers;\r\n\r\nuse App\\Models\\SystemTeam;\r\nuse App\\Models\\SystemUser;\r\nuse App\\Services\\Sel"
  },
  {
    "path": "app/Http/Controllers/SystemUserController.php",
    "chars": 7100,
    "preview": "<?php\r\n\r\nnamespace App\\Http\\Controllers;\r\n\r\nuse App\\Models\\Customer;\r\nuse App\\Models\\SystemSetting;\r\nuse App\\Models\\Syst"
  },
  {
    "path": "app/Http/Controllers/UserController.php",
    "chars": 6796,
    "preview": "<?php\r\n\r\nnamespace App\\Http\\Controllers;\r\n\r\nuse App\\Models\\Captcha;\r\nuse App\\Models\\Customer;\r\nuse App\\Models\\CustomerBa"
  },
  {
    "path": "app/Http/Middleware/AuthMiddleware.php",
    "chars": 2063,
    "preview": "<?php\r\n\r\nnamespace App\\Http\\Middleware;\r\n\r\nuse App\\Models\\SystemRight;\r\nuse App\\Models\\SystemSetting;\r\nuse App\\Models\\Sy"
  },
  {
    "path": "app/Jobs/ExampleJob.php",
    "chars": 341,
    "preview": "<?php\r\n\r\nnamespace App\\Jobs;\r\n\r\nclass ExampleJob extends Job\r\n{\r\n    /**\r\n     * Create a new job instance.\r\n     *\r\n   "
  },
  {
    "path": "app/Jobs/Job.php",
    "chars": 744,
    "preview": "<?php\r\n\r\nnamespace App\\Jobs;\r\n\r\nuse Illuminate\\Bus\\Queueable;\r\nuse Illuminate\\Queue\\SerializesModels;\r\nuse Illuminate\\Qu"
  },
  {
    "path": "app/Listeners/ExampleListener.php",
    "chars": 515,
    "preview": "<?php\r\n\r\nnamespace App\\Listeners;\r\n\r\nuse App\\Events\\ExampleEvent;\r\nuse Illuminate\\Queue\\InteractsWithQueue;\r\nuse Illumin"
  },
  {
    "path": "app/Models/BaseModel.php",
    "chars": 118,
    "preview": "<?php\r\n \r\nnamespace App\\Models;\r\n \r\nuse Illuminate\\Database\\Eloquent\\Model;\r\n\r\nclass BaseModel extends Model\r\n{\r\n\r\n}\r\n"
  },
  {
    "path": "app/Models/Captcha.php",
    "chars": 1762,
    "preview": "<?php\r\n\r\nnamespace App\\Models;\r\n\r\nuse Yii;\r\n\r\nclass Captcha {\r\n\r\n    /**\r\n     * 验证码\r\n     * \r\n     */ \r\n    public func"
  },
  {
    "path": "app/Models/Channel.php",
    "chars": 305,
    "preview": "<?php\r\n \r\nnamespace App\\Models;\r\n \r\nuse Illuminate\\Database\\Eloquent\\Model;\r\n\r\nclass Channel extends Model\r\n{\r\n    /**\r\n"
  },
  {
    "path": "app/Models/Constants.php",
    "chars": 455,
    "preview": "<?php\r\n \r\nnamespace App\\Models;\r\n \r\n/**\r\n * 定义一些公用的常量\r\n * \r\n */\r\nclass Constants\r\n{\r\n\r\n    // 标签颜色配置\r\n    const TAG_COLO"
  },
  {
    "path": "app/Models/Customer.php",
    "chars": 13052,
    "preview": "<?php\r\n \r\nnamespace App\\Models;\r\n \r\nuse Illuminate\\Database\\Eloquent\\Model;\r\nuse Illuminate\\Support\\Facades\\DB;\r\n\r\nclass"
  },
  {
    "path": "app/Models/CustomerBack.php",
    "chars": 3458,
    "preview": "<?php\r\n \r\nnamespace App\\Models;\r\n \r\nuse Illuminate\\Database\\Eloquent\\Model;\r\n\r\nclass CustomerBack extends Model\r\n{\r\n    "
  },
  {
    "path": "app/Models/CustomerLog.php",
    "chars": 5394,
    "preview": "<?php\r\n \r\nnamespace App\\Models;\r\n\r\nuse App\\Services\\CustomerService;\r\nuse Illuminate\\Database\\Eloquent\\Model;\r\n\r\nclass C"
  },
  {
    "path": "app/Models/CustomerRemarkLog.php",
    "chars": 767,
    "preview": "<?php\r\n \r\nnamespace App\\Models;\r\n\r\nuse App\\Services\\CustomerService;\r\nuse Illuminate\\Database\\Eloquent\\Model;\r\n\r\nclass C"
  },
  {
    "path": "app/Models/CustomerRuleConfig.php",
    "chars": 365,
    "preview": "<?php\r\n \r\nnamespace App\\Models;\r\n\r\nuse App\\Services\\CustomerService;\r\nuse Illuminate\\Database\\Eloquent\\Model;\r\n\r\nclass C"
  },
  {
    "path": "app/Models/Excel/CustomerModel.php",
    "chars": 310,
    "preview": "<?php\r\nnamespace App\\Models\\Excel;\r\n\r\nuse App\\Models\\Customer;\r\nuse Illuminate\\Validation\\Rule;\r\nuse Maatwebsite\\Excel\\C"
  },
  {
    "path": "app/Models/Notice.php",
    "chars": 3022,
    "preview": "<?php\r\n \r\nnamespace App\\Models;\r\n \r\nuse Illuminate\\Database\\Eloquent\\Model;\r\nuse Illuminate\\Support\\Facades\\DB;\r\n\r\nclass"
  },
  {
    "path": "app/Models/Product.php",
    "chars": 1214,
    "preview": "<?php\n \nnamespace App\\Models;\n \nuse Illuminate\\Database\\Eloquent\\Model;\n\nclass Product extends Model\n{\n    /**\n     * Th"
  },
  {
    "path": "app/Models/SystemDict.php",
    "chars": 1131,
    "preview": "<?php\r\n \r\nnamespace App\\Models;\r\n \r\nuse Illuminate\\Database\\Eloquent\\Model;\r\n\r\nclass SystemDict extends Model\r\n{\r\n\r\n    "
  },
  {
    "path": "app/Models/SystemFields.php",
    "chars": 539,
    "preview": "<?php\r\n \r\nnamespace App\\Models;\r\n \r\nuse Illuminate\\Database\\Eloquent\\Model;\r\n\r\nclass SystemFields extends Model\r\n{\r\n    "
  },
  {
    "path": "app/Models/SystemLog.php",
    "chars": 1152,
    "preview": "<?php\r\n \r\nnamespace App\\Models;\r\n \r\nuse Illuminate\\Database\\Eloquent\\Model;\r\n\r\nclass SystemLog extends Model\r\n{\r\n    /**"
  },
  {
    "path": "app/Models/SystemRight.php",
    "chars": 1186,
    "preview": "<?php\r\n \r\nnamespace App\\Models;\r\n \r\nuse Illuminate\\Database\\Eloquent\\Model;\r\n \r\nclass SystemRight extends Model\r\n{\r\n    "
  },
  {
    "path": "app/Models/SystemRole.php",
    "chars": 2242,
    "preview": "<?php\r\n \r\nnamespace App\\Models;\r\n \r\nuse Illuminate\\Database\\Eloquent\\Model;\r\n\r\nclass SystemRole extends Model\r\n{\r\n    /*"
  },
  {
    "path": "app/Models/SystemRoleRight.php",
    "chars": 854,
    "preview": "<?php\r\n \r\nnamespace App\\Models;\r\n \r\nuse Illuminate\\Database\\Eloquent\\Model;\r\n \r\nclass SystemRoleRight extends Model\r\n{\r\n"
  },
  {
    "path": "app/Models/SystemSetting.php",
    "chars": 303,
    "preview": "<?php\n \nnamespace App\\Models;\n \nuse Illuminate\\Database\\Eloquent\\Model;\n \nclass SystemSetting extends Model\n{\n    /**\n  "
  },
  {
    "path": "app/Models/SystemTeam.php",
    "chars": 1545,
    "preview": "<?php\r\n \r\nnamespace App\\Models;\r\n \r\nuse Illuminate\\Database\\Eloquent\\Model;\r\n\r\nclass SystemTeam extends Model\r\n{\r\n    /*"
  },
  {
    "path": "app/Models/SystemUser.php",
    "chars": 3890,
    "preview": "<?php\r\n \r\nnamespace App\\Models;\r\n\r\nuse App\\Services\\ToolService;\r\nuse Illuminate\\Database\\Eloquent\\Model;\r\nuse Illuminat"
  },
  {
    "path": "app/Models/SystemUserRole.php",
    "chars": 984,
    "preview": "<?php\r\n \r\nnamespace App\\Models;\r\n \r\nuse Illuminate\\Database\\Eloquent\\Model;\r\n\r\nclass SystemUserRole extends Model\r\n{\r\n  "
  },
  {
    "path": "app/Providers/AppServiceProvider.php",
    "chars": 524,
    "preview": "<?php\r\n\r\nnamespace App\\Providers;\r\n\r\nuse Illuminate\\Support\\ServiceProvider;\r\nuse App\\Services\\RightService;\r\n\r\nclass Ap"
  },
  {
    "path": "app/Providers/AuthServiceProvider.php",
    "chars": 1055,
    "preview": "<?php\r\n\r\nnamespace App\\Providers;\r\n\r\nuse App\\User;\r\nuse Illuminate\\Support\\Facades\\Gate;\r\nuse Illuminate\\Support\\Service"
  },
  {
    "path": "app/Providers/EventServiceProvider.php",
    "chars": 402,
    "preview": "<?php\r\n\r\nnamespace App\\Providers;\r\n\r\nuse Laravel\\Lumen\\Providers\\EventServiceProvider as ServiceProvider;\r\n\r\nclass Event"
  },
  {
    "path": "app/Services/AssignRule/Rule1.php",
    "chars": 1520,
    "preview": "<?php\r\n\r\nnamespace App\\Services\\AssignRule;\r\n\r\nuse App\\Models\\Customer;\r\nuse App\\Services\\CustomerService;\r\nuse App\\Serv"
  },
  {
    "path": "app/Services/AssignRule/Rule10.php",
    "chars": 218,
    "preview": "<?php\n\nnamespace App\\Services\\AssignRule;\n\nuse App\\Services\\CustomerService;\n\n/**\n * 客户分配相关的service\n */\nclass Rule10\n{\n "
  },
  {
    "path": "app/Services/AssignRule/Rule11.php",
    "chars": 1283,
    "preview": "<?php\n\nnamespace App\\Services\\AssignRule;\n\nuse App\\Models\\Customer;\nuse App\\Models\\CustomerLog;\nuse App\\Services\\Custome"
  },
  {
    "path": "app/Services/AssignRule/Rule13.php",
    "chars": 918,
    "preview": "<?php\n\nnamespace App\\Services\\AssignRule;\nuse App\\Services\\CustomerService;\n\n\n/**\n * 客户分配相关的service\n */\nclass Rule13\n{\n "
  },
  {
    "path": "app/Services/AssignRule/Rule2.php",
    "chars": 938,
    "preview": "<?php\r\n\r\nnamespace App\\Services\\AssignRule;\r\nuse App\\Services\\CustomerService;\r\n\r\n\r\n/**\r\n * 客户分配相关的service\r\n */\r\nclass R"
  },
  {
    "path": "app/Services/AssignRule/Rule3.php",
    "chars": 1102,
    "preview": "<?php\r\n\r\nnamespace App\\Services\\AssignRule;\r\n\r\nuse App\\Services\\CustomerService;\r\n\r\n/**\r\n * 客户分配相关的service\r\n */\r\nclass R"
  },
  {
    "path": "app/Services/AssignRule/Rule4.php",
    "chars": 918,
    "preview": "<?php\r\n\r\nnamespace App\\Services\\AssignRule;\r\n\r\nuse App\\Services\\CustomerService;\r\n\r\n/**\r\n * 客户分配相关的service\r\n */\r\nclass R"
  },
  {
    "path": "app/Services/AssignRule/Rule5.php",
    "chars": 1102,
    "preview": "<?php\r\n\r\nnamespace App\\Services\\AssignRule;\r\n\r\nuse App\\Services\\CustomerService;\r\n\r\n/**\r\n * 客户分配相关的service\r\n */\r\nclass R"
  },
  {
    "path": "app/Services/AssignRule/Rule6.php",
    "chars": 1102,
    "preview": "<?php\r\n\r\nnamespace App\\Services\\AssignRule;\r\n\r\nuse App\\Services\\CustomerService;\r\n\r\n/**\r\n * 客户分配相关的service\r\n */\r\nclass R"
  },
  {
    "path": "app/Services/AssignRule/Rule7.php",
    "chars": 1102,
    "preview": "<?php\r\n\r\nnamespace App\\Services\\AssignRule;\r\n\r\nuse App\\Services\\CustomerService;\r\n\r\n/**\r\n * 客户分配相关的service\r\n */\r\nclass R"
  },
  {
    "path": "app/Services/AssignService.php",
    "chars": 622,
    "preview": "<?php\r\n\r\nnamespace App\\Services;\r\n\r\n\r\n/**\r\n * 客户分配相关的service\r\n */\r\nclass AssignService\r\n{\r\n\r\n    const TYPE_MAPPING = [\r"
  },
  {
    "path": "app/Services/CustomerEditService.php",
    "chars": 5408,
    "preview": "<?php\r\n\r\nnamespace App\\Services;\r\n\r\nuse App\\Models\\Customer;\r\nuse App\\Models\\CustomerAssign;\r\nuse App\\Models\\CustomerLog"
  },
  {
    "path": "app/Services/CustomerService.php",
    "chars": 12370,
    "preview": "<?php\r\n\r\nnamespace App\\Services;\r\n\r\nuse App\\Models\\Customer;\r\nuse App\\Models\\CustomerAssign;\r\nuse App\\Models\\CustomerLog"
  },
  {
    "path": "app/Services/Hook/LoginHook.php",
    "chars": 1011,
    "preview": "<?php\r\n\r\nnamespace App\\Services\\Hook;\r\n\r\nuse App\\Models\\SystemSetting;\r\nuse App\\Models\\SystemUserRole;\r\n\r\n/**\r\n * 登录hook"
  },
  {
    "path": "app/Services/RightService.php",
    "chars": 5312,
    "preview": "<?php\r\n\r\nnamespace App\\Services;\r\n\r\nuse App\\Models\\SystemRight;\r\nuse App\\Models\\SystemRole;\r\nuse App\\Models\\SystemUser;\r"
  },
  {
    "path": "app/Services/SelectService.php",
    "chars": 1670,
    "preview": "<?php\r\n\r\nnamespace App\\Services;\r\n\r\n\r\nclass SelectService\r\n{\r\n    /**\r\n     * 构造前端的select \r\n     * \r\n     */\r\n    public"
  },
  {
    "path": "app/Services/ToolService.php",
    "chars": 2388,
    "preview": "<?php\r\n\r\nnamespace App\\Services;\r\n\r\n\r\nclass ToolService\r\n{\r\n    /**\r\n     * 构造前端的select \r\n     * \r\n     */\r\n    public f"
  },
  {
    "path": "app/Services/UserService.php",
    "chars": 2478,
    "preview": "<?php\r\n\r\nnamespace App\\Services;\r\n\r\nuse App\\Models\\CustomerLog;\r\nuse App\\Models\\SystemUser;\r\n\r\n\r\nclass UserService\r\n{\r\n "
  },
  {
    "path": "app/User.php",
    "chars": 716,
    "preview": "<?php\n\nnamespace App;\n\nuse Illuminate\\Auth\\Authenticatable;\nuse Laravel\\Lumen\\Auth\\Authorizable;\nuse Illuminate\\Database"
  },
  {
    "path": "artisan",
    "chars": 1129,
    "preview": "#!/usr/bin/env php\r\n<?php\r\n\r\nuse Symfony\\Component\\Console\\Input\\ArgvInput;\r\nuse Symfony\\Component\\Console\\Output\\Consol"
  },
  {
    "path": "bootstrap/app.php",
    "chars": 3562,
    "preview": "<?php\r\n\r\nrequire_once __DIR__.'/../vendor/autoload.php';\r\n\r\n(new Laravel\\Lumen\\Bootstrap\\LoadEnvironmentVariables(\r\n    "
  },
  {
    "path": "composer.json",
    "chars": 1237,
    "preview": "{\r\n    \"name\": \"laravel/lumen\",\r\n    \"description\": \"The Laravel Lumen Framework.\",\r\n    \"keywords\": [\"framework\", \"lara"
  },
  {
    "path": "config/database.php",
    "chars": 485,
    "preview": "<?php\r\nreturn [\r\n    'default' => 'mysql',\r\n    'connections' => [\r\n        'mysql' => [\r\n            'driver' => 'mysql"
  },
  {
    "path": "config/logging.php",
    "chars": 3865,
    "preview": "<?php\r\n\r\nuse Monolog\\Handler\\NullHandler;\r\nuse Monolog\\Handler\\StreamHandler;\r\nuse Monolog\\Handler\\SyslogUdpHandler;\r\n\r\n"
  },
  {
    "path": "config/session.php",
    "chars": 6963,
    "preview": "<?php\r\n\r\n\r\nreturn [\r\n\r\n    /*\r\n    |--------------------------------------------------------------------------\r\n    | De"
  },
  {
    "path": "database/factories/ModelFactory.php",
    "chars": 575,
    "preview": "<?php\r\n\r\n/*\r\n|--------------------------------------------------------------------------\r\n| Model Factories\r\n|----------"
  },
  {
    "path": "database/migrations/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "database/seeds/DatabaseSeeder.php",
    "chars": 252,
    "preview": "<?php\r\n\r\nuse Illuminate\\Database\\Seeder;\r\n\r\nclass DatabaseSeeder extends Seeder\r\n{\r\n    /**\r\n     * Run the database see"
  },
  {
    "path": "docs/README.md",
    "chars": 15,
    "preview": "为action自动生成文档创建"
  },
  {
    "path": "install/crm.sql",
    "chars": 49031,
    "preview": "CREATE TABLE `channel` (\n  `id` int(11) UNSIGNED NOT NULL,\n  `name` varchar(200) NOT NULL DEFAULT '' COMMENT '渠道名,与dict "
  },
  {
    "path": "install/nginx.conf",
    "chars": 1691,
    "preview": "server\n{\n    listen 80;\n    server_name #ip#;\n    index index.html index.php;\n    root /www/wwwroot/crm/public;\n    \n   "
  },
  {
    "path": "nginx.conf",
    "chars": 642,
    "preview": "server {\n    listen       80;\n    server_name  139.198.191.172 ;\n    index index.html;\n    root /data/www/crm4/public/;\n"
  },
  {
    "path": "package.json",
    "chars": 2930,
    "preview": "{\n  \"name\": \"arco-design-pro-vue\",\n  \"description\": \"Arco Design Pro for Vue\",\n  \"version\": \"1.0.0\",\n  \"private\": true,\n"
  },
  {
    "path": "phpunit.xml",
    "chars": 904,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<phpunit backupGlobals=\"false\"\r\n         backupStaticAttributes=\"false\"\r\n       "
  },
  {
    "path": "public/.htaccess",
    "chars": 614,
    "preview": "<IfModule mod_rewrite.c>\r\n    <IfModule mod_negotiation.c>\r\n        Options -MultiViews -Indexes\r\n    </IfModule>\r\n\r\n   "
  },
  {
    "path": "public/index.html",
    "chars": 777,
    "preview": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n  <head>\r\n    <meta charset=\"UTF-8\" />\r\n    <link rel=\"shortcut icon\" type=\"image/x-i"
  },
  {
    "path": "public/index.php",
    "chars": 925,
    "preview": "<?php\r\n\r\n/*\r\n|--------------------------------------------------------------------------\r\n| Create The Application\r\n|---"
  },
  {
    "path": "resources/views/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "routes/web.php",
    "chars": 6050,
    "preview": "<?php\r\n\r\n/*\r\n|--------------------------------------------------------------------------\r\n| Application Routes\r\n|-------"
  },
  {
    "path": "storage/app/.gitignore",
    "chars": 16,
    "preview": "*\r\n!.gitignore\r\n"
  },
  {
    "path": "storage/framework/cache/.gitignore",
    "chars": 24,
    "preview": "*\r\n!data/\r\n!.gitignore\r\n"
  },
  {
    "path": "storage/framework/views/.gitignore",
    "chars": 16,
    "preview": "*\r\n!.gitignore\r\n"
  },
  {
    "path": "storage/logs/.gitignore",
    "chars": 16,
    "preview": "*\r\n!.gitignore\r\n"
  },
  {
    "path": "tests/ExampleTest.php",
    "chars": 411,
    "preview": "<?php\r\n\r\nuse Laravel\\Lumen\\Testing\\DatabaseMigrations;\r\nuse Laravel\\Lumen\\Testing\\DatabaseTransactions;\r\n\r\nclass Example"
  },
  {
    "path": "tests/TestCase.php",
    "chars": 293,
    "preview": "<?php\r\n\r\nabstract class TestCase extends Laravel\\Lumen\\Testing\\TestCase\r\n{\r\n    /**\r\n     * Creates the application.\r\n  "
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the qincrm/crm GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 100 files (252.7 KB), approximately 77.9k tokens, and a symbol index with 281 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!