Browse Source

框架搭建

刘忠健 2 years ago
commit
9ad2251ff7
65 changed files with 2443 additions and 0 deletions
  1. 1 0
      api/.example.env
  2. 5 0
      api/.gitignore
  3. 42 0
      api/.travis.yml
  4. 32 0
      api/LICENSE.txt
  5. 56 0
      api/README.md
  6. 1 0
      api/app/.htaccess
  7. 22 0
      api/app/AppService.php
  8. 94 0
      api/app/BaseController.php
  9. 58 0
      api/app/ExceptionHandle.php
  10. 8 0
      api/app/Request.php
  11. 11 0
      api/app/api/ErrorCode.php
  12. 16 0
      api/app/api/common.php
  13. 174 0
      api/app/api/controller/Base.php
  14. 16 0
      api/app/api/controller/BaseAuthorized.php
  15. 85 0
      api/app/api/controller/Index.php
  16. 137 0
      api/app/api/controller/Record.php
  17. 39 0
      api/app/api/controller/User.php
  18. 5 0
      api/app/api/event.php
  19. 5 0
      api/app/api/middleware.php
  20. 212 0
      api/app/common.php
  21. 52 0
      api/app/common/ErrorCode.php
  22. 2 0
      api/app/common/common.php
  23. 5 0
      api/app/common/event.php
  24. 5 0
      api/app/common/middleware.php
  25. 119 0
      api/app/common/model/Base.php
  26. 35 0
      api/app/common/model/Record.php
  27. 10 0
      api/app/common/model/Type.php
  28. 135 0
      api/app/common/model/User.php
  29. 135 0
      api/app/common/util/Rsa.php
  30. 59 0
      api/app/common/util/SingleObjectClass.php
  31. 130 0
      api/app/common/util/Util.php
  32. 17 0
      api/app/controller/Index.php
  33. 17 0
      api/app/event.php
  34. 12 0
      api/app/middleware.php
  35. 65 0
      api/app/middleware/AllowCrossDomain.php
  36. 9 0
      api/app/provider.php
  37. 9 0
      api/app/service.php
  38. 49 0
      api/composer.json
  39. 32 0
      api/config/app.php
  40. 29 0
      api/config/cache.php
  41. 10 0
      api/config/common.php
  42. 9 0
      api/config/console.php
  43. 20 0
      api/config/cookie.php
  44. 63 0
      api/config/database.php
  45. 24 0
      api/config/filesystem.php
  46. 27 0
      api/config/lang.php
  47. 45 0
      api/config/log.php
  48. 8 0
      api/config/middleware.php
  49. 45 0
      api/config/route.php
  50. 19 0
      api/config/session.php
  51. 10 0
      api/config/trace.php
  52. 25 0
      api/config/view.php
  53. 2 0
      api/extend/.gitignore
  54. 8 0
      api/public/.htaccess
  55. BIN
      api/public/favicon.ico
  56. 24 0
      api/public/index.php
  57. 2 0
      api/public/robots.txt
  58. 19 0
      api/public/router.php
  59. 2 0
      api/public/static/.gitignore
  60. 17 0
      api/route/app.php
  61. 2 0
      api/runtime/.gitignore
  62. 10 0
      api/think
  63. 100 0
      api/time_manager.sql
  64. 1 0
      api/view/README.md
  65. 6 0
      api/说明.md

+ 1 - 0
api/.example.env

@@ -0,0 +1 @@
+APP_DEBUG = true

[APP]
DEFAULT_TIMEZONE = Asia/Shanghai

[DATABASE]
TYPE = mysql
HOSTNAME = 127.0.0.1
DATABASE = time_manager
USERNAME = root
PASSWORD = root
HOSTPORT = 3306
CHARSET = utf8mb4
DEBUG = true

[LANG]
default_lang = zh-cn

+ 5 - 0
api/.gitignore

@@ -0,0 +1,5 @@
+/.idea
+/.vscode
+/vendor
+*.log
+.env

File diff suppressed because it is too large
+ 42 - 0
api/.travis.yml


+ 32 - 0
api/LICENSE.txt

@@ -0,0 +1,32 @@
+
+ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
+版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn)
+All rights reserved。
+ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
+
+Apache Licence是著名的非盈利开源组织Apache采用的协议。
+该协议和BSD类似,鼓励代码共享和尊重原作者的著作权,
+允许代码修改,再作为开源或商业软件发布。需要满足
+的条件: 
+1. 需要给代码的用户一份Apache Licence ;
+2. 如果你修改了代码,需要在被修改的文件中说明;
+3. 在延伸的代码中(修改和有源代码衍生的代码中)需要
+带有原来代码中的协议,商标,专利声明和其他原来作者规
+定需要包含的说明;
+4. 如果再发布的产品中包含一个Notice文件,则在Notice文
+件中需要带有本协议内容。你可以在Notice中增加自己的
+许可,但不可以表现为对Apache Licence构成更改。 
+具体的协议参考:http://www.apache.org/licenses/LICENSE-2.0
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.

+ 56 - 0
api/README.md

@@ -0,0 +1,56 @@
+ThinkPHP 6.0
+===============
+
+> 运行环境要求PHP7.1+,兼容PHP8.0。
+
+[官方应用服务市场](https://market.topthink.com) | [`ThinkAPI`——官方统一API服务](https://docs.topthink.com/think-api)
+
+ThinkPHPV6.0版本由[亿速云](https://www.yisu.com/)独家赞助发布。
+
+## 主要新特性
+
+* 采用`PHP7`强类型(严格模式)
+* 支持更多的`PSR`规范
+* 原生多应用支持
+* 更强大和易用的查询
+* 全新的事件系统
+* 模型事件和数据库事件统一纳入事件系统
+* 模板引擎分离出核心
+* 内部功能中间件化
+* SESSION/Cookie机制改进
+* 对Swoole以及协程支持改进
+* 对IDE更加友好
+* 统一和精简大量用法
+
+## 安装
+
+~~~
+composer create-project topthink/think tp 6.0.*
+~~~
+
+如果需要更新框架使用
+~~~
+composer update topthink/framework
+~~~
+
+## 文档
+
+[完全开发手册](https://www.kancloud.cn/manual/thinkphp6_0/content)
+
+## 参与开发
+
+请参阅 [ThinkPHP 核心框架包](https://github.com/top-think/framework)。
+
+## 版权信息
+
+ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
+
+本项目包含的第三方源码和二进制文件之版权信息另行标注。
+
+版权所有Copyright © 2006-2020 by ThinkPHP (http://thinkphp.cn)
+
+All rights reserved。
+
+ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
+
+更多细节参阅 [LICENSE.txt](LICENSE.txt)

+ 1 - 0
api/app/.htaccess

@@ -0,0 +1 @@
+deny from all

+ 22 - 0
api/app/AppService.php

@@ -0,0 +1,22 @@
+<?php
+declare (strict_types = 1);
+
+namespace app;
+
+use think\Service;
+
+/**
+ * 应用服务类
+ */
+class AppService extends Service
+{
+    public function register()
+    {
+        // 服务注册
+    }
+
+    public function boot()
+    {
+        // 服务启动
+    }
+}

+ 94 - 0
api/app/BaseController.php

@@ -0,0 +1,94 @@
+<?php
+declare (strict_types = 1);
+
+namespace app;
+
+use think\App;
+use think\exception\ValidateException;
+use think\Validate;
+
+/**
+ * 控制器基础类
+ */
+abstract class BaseController
+{
+    /**
+     * Request实例
+     * @var \think\Request
+     */
+    protected $request;
+
+    /**
+     * 应用实例
+     * @var \think\App
+     */
+    protected $app;
+
+    /**
+     * 是否批量验证
+     * @var bool
+     */
+    protected $batchValidate = false;
+
+    /**
+     * 控制器中间件
+     * @var array
+     */
+    protected $middleware = [];
+
+    /**
+     * 构造方法
+     * @access public
+     * @param  App  $app  应用对象
+     */
+    public function __construct(App $app)
+    {
+        $this->app     = $app;
+        $this->request = $this->app->request;
+
+        // 控制器初始化
+        $this->initialize();
+    }
+
+    // 初始化
+    protected function initialize()
+    {}
+
+    /**
+     * 验证数据
+     * @access protected
+     * @param  array        $data     数据
+     * @param  string|array $validate 验证器名或者验证规则数组
+     * @param  array        $message  提示信息
+     * @param  bool         $batch    是否批量验证
+     * @return array|string|true
+     * @throws ValidateException
+     */
+    protected function validate(array $data, $validate, array $message = [], bool $batch = false)
+    {
+        if (is_array($validate)) {
+            $v = new Validate();
+            $v->rule($validate);
+        } else {
+            if (strpos($validate, '.')) {
+                // 支持场景
+                [$validate, $scene] = explode('.', $validate);
+            }
+            $class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
+            $v     = new $class();
+            if (!empty($scene)) {
+                $v->scene($scene);
+            }
+        }
+
+        $v->message($message);
+
+        // 是否批量验证
+        if ($batch || $this->batchValidate) {
+            $v->batch(true);
+        }
+
+        return $v->failException(true)->check($data);
+    }
+
+}

+ 58 - 0
api/app/ExceptionHandle.php

@@ -0,0 +1,58 @@
+<?php
+namespace app;
+
+use think\db\exception\DataNotFoundException;
+use think\db\exception\ModelNotFoundException;
+use think\exception\Handle;
+use think\exception\HttpException;
+use think\exception\HttpResponseException;
+use think\exception\ValidateException;
+use think\Response;
+use Throwable;
+
+/**
+ * 应用异常处理类
+ */
+class ExceptionHandle extends Handle
+{
+    /**
+     * 不需要记录信息(日志)的异常类列表
+     * @var array
+     */
+    protected $ignoreReport = [
+        HttpException::class,
+        HttpResponseException::class,
+        ModelNotFoundException::class,
+        DataNotFoundException::class,
+        ValidateException::class,
+    ];
+
+    /**
+     * 记录异常信息(包括日志或者其它方式记录)
+     *
+     * @access public
+     * @param  Throwable $exception
+     * @return void
+     */
+    public function report(Throwable $exception): void
+    {
+        // 使用内置的方式记录异常日志
+        parent::report($exception);
+    }
+
+    /**
+     * Render an exception into an HTTP response.
+     *
+     * @access public
+     * @param \think\Request   $request
+     * @param Throwable $e
+     * @return Response
+     */
+    public function render($request, Throwable $e): Response
+    {
+        // 添加自定义异常处理机制
+
+        // 其他错误交给系统处理
+        return parent::render($request, $e);
+    }
+}

+ 8 - 0
api/app/Request.php

@@ -0,0 +1,8 @@
+<?php
+namespace app;
+
+// 应用请求对象类
+class Request extends \think\Request
+{
+
+}

+ 11 - 0
api/app/api/ErrorCode.php

@@ -0,0 +1,11 @@
+<?php
+
+
+namespace app\api;
+
+
+class ErrorCode extends \app\common\ErrorCode
+{
+
+
+}

+ 16 - 0
api/app/api/common.php

@@ -0,0 +1,16 @@
+<?php
+if (!function_exists('arrayToDic')) {
+    /**
+     * 数组转键值对数组
+     * @param $array
+     */
+    function arrayToDic($array,$keyName="value",$valueName="label"){
+        $dic=[];
+        foreach ($array as $key=>$value){
+            $item[$keyName]=$key;
+            $item[$valueName]=$value;
+            $dic[]=$item;
+        }
+        return $dic;
+    }
+}

+ 174 - 0
api/app/api/controller/Base.php

@@ -0,0 +1,174 @@
+<?php
+
+
+namespace app\api\controller;
+
+
+use app\api\ErrorCode;
+use app\api\model\User;
+use app\BaseController;
+use app\common\model\Place;
+use think\exception\HttpResponseException;
+use think\exception\ValidateException;
+use think\facade\Log;
+use think\Response;
+
+class Base
+{
+
+    protected $checkTokenOpen = false;//是否校验token
+    public $user;//用户
+
+
+    public function __construct()
+    {
+        Log::record("---------------------------", "info");
+        Log::record($_SERVER['REQUEST_METHOD'] . '  ' . getUrl(), 'info');
+        Log::record('REFERER  ' . (array_key_exists('HTTP_REFERER', $_SERVER) ? $_SERVER['HTTP_REFERER'] : ""), 'info');
+        Log::record('GET  ' . json_encode($_GET, JSON_UNESCAPED_UNICODE), 'info');
+        Log::record('POST  ' . json_encode($_POST, JSON_UNESCAPED_UNICODE), 'info');
+        Log::record('cookie  ' . json_encode($_COOKIE, JSON_UNESCAPED_UNICODE), 'info');
+        Log::record('input  ' . json_encode(input('param.'), JSON_UNESCAPED_UNICODE), 'info');
+        $this->checkApiSign();
+
+        if ($this->checkTokenOpen) {
+            $this->checkToken();
+        }
+    }
+
+
+    /**
+     * 获取token
+     * @return array|mixed|string|null
+     */
+    protected function getToken()
+    {
+        $token = null;
+        if (!$token) {
+            //from header
+            $token = request()->header("token");
+        }
+        if (!$token) {
+            //from url
+            $token = input("token");
+        }
+        return $token;
+    }
+
+    /**
+     * 检测token
+     * token规则
+     * token由base64编码,解码后分为密文、主键、过期时间(时间戳)三部分,用竖线|隔开
+     */
+    public function checkToken()
+    {
+        $token = $this->getToken();
+        if (!$token) {
+            $this->error(ErrorCode::getError(ErrorCode::CODE_TOKEN_NONE), ErrorCode::CODE_TOKEN_NONE);
+        }
+        $tokerReal = base64_decode($token);
+        $tokenArr = explode("|", $tokerReal);//拆分token
+
+        if (count($tokenArr) != 3) {
+            $this->error(ErrorCode::getError(ErrorCode::CODE_TOKEN_FORMAT_ERR), ErrorCode::CODE_TOKEN_FORMAT_ERR);
+        }
+        //判断token有没有超时
+        if (time() > $tokenArr[2]) {
+            $this->error(ErrorCode::getError(ErrorCode::CODE_TOKEN_EXPIRE), ErrorCode::CODE_TOKEN_EXPIRE);
+        }
+        //以下部分根据自己的业务实现
+
+        //$field = "id,login_name,valid,last_login_time,login_count,token";
+        $user = \app\common\model\User::where("token", "=", $token)->find();//找到token
+        if (!$user) {
+            $this->error(ErrorCode::getError(ErrorCode::CODE_TOKEN_ERR), ErrorCode::CODE_TOKEN_ERR);
+        }
+        $this->user = $user;
+
+    }
+
+    /**
+     * 返回成功信息
+     * @param $data
+     * @param string $msg
+     */
+    public function success($data, $msg = "")
+    {
+
+        $res = returnFormat(0, $msg, $data);
+
+        Log::record("response:" . mb_substr(json_encode($res, JSON_UNESCAPED_UNICODE), 0, 1000) . ",code:0", "debug");
+        throw new HttpResponseException(Response::create($res, "json"));
+    }
+
+    /**
+     * 简易错误提示
+     * @param $code
+     */
+    public function errorSimple($code)
+    {
+        $this->error(ErrorCode::getError($code), $code);
+    }
+
+    /**
+     * 返回失败信息
+     * @param $msg
+     * @param int $code
+     * @param array $data
+     */
+    public function error($msg, $code = 999, $data = [])
+    {
+        $res = returnFormat($code, $msg, $data);
+        Log::record("response:" . mb_substr(json_encode($res, JSON_UNESCAPED_UNICODE), 0, 1000) . ",code:" . $code, "debug");
+        throw new HttpResponseException(Response::create($res, "json"));
+    }
+
+    /**
+     * 自动校验
+     * @param $class
+     * @param $param
+     */
+    public function autoValid($class, $param)
+    {
+        try {
+            validate($class)->check($param);
+        } catch (ValidateException $e) {
+            // 验证失败 输出错误信息
+            $this->error($e->getError());
+        }
+    }
+
+    /**
+     * 检查签名
+     */
+    public function checkApiSign()
+    {
+
+        $timestampLimit = 20;
+        $param = request()->param();
+
+        $this->autoValid([
+            "_timestamp" => "require",
+            "_sign" => "require",
+        ], $param);
+        if (!($param["_timestamp"] >= time() - $timestampLimit * 60 && $param["_timestamp"] <= time() + $timestampLimit * 60)) {
+            $this->error("时间戳不合法,请刷新");
+        }
+        $sign = $param["_sign"];
+        unset($param["_sign"]);
+        ksort($param);
+
+        $param['_timestamp'] = $param['_timestamp'];
+        $secret = config("common.api_sign_secret");
+        $signStr = stripslashes(json_encode($param, JSON_UNESCAPED_UNICODE) . $secret);
+
+        $sign2 = md5($signStr);
+
+        if ($sign !== $sign2) {
+            Log::record("签名错误:sign: $sign sign2: $sign2", "debug");
+            Log::record("sign2 签名key:".$secret,"debug");
+            Log::record("sign2 签名字符串:".$signStr,"debug");
+            $this->error("签名错误。" . $signStr);
+        }
+    }
+}

+ 16 - 0
api/app/api/controller/BaseAuthorized.php

@@ -0,0 +1,16 @@
+<?php
+
+
+namespace app\api\controller;
+
+
+/**
+ * 需要登录 的基类
+ * Class AuthBase
+ * @package app\api\controller
+ */
+class BaseAuthorized extends Base
+{
+    protected $checkTokenOpen = true;
+
+}

+ 85 - 0
api/app/api/controller/Index.php

@@ -0,0 +1,85 @@
+<?php
+declare (strict_types=1);
+
+namespace app\api\controller;
+
+use think\facade\Db;
+
+class Index extends Base
+{
+    public function index()
+    {
+        return '您好!这是一个[api]示例应用';
+    }
+
+    /**
+     * 注册
+     */
+    public function reg()
+    {
+        $param = request()->param();
+        $rules = [
+            "login_name" => "require|length:2,25",
+            'password' => 'require|length:6,25',
+            'repassword' => 'require|confirm:password',
+        ];
+        $this->autoValid($rules, $param);
+
+
+        // 启动事务,用事务实现注册
+        $res = $this->regTrans($param);
+        if ($res["code"] != 0) {
+            $this->error($res['msg'], $res["code"]);
+        }
+        $this->success($res['data']);
+    }
+
+    /**
+     * 注册事务
+     */
+    private function regTrans($param)
+    {
+        Db::startTrans();
+        try {
+            $res = \app\common\model\User::regUser($param["login_name"], $param["password"]);
+            if ($res["code"] != 0) {
+                // 回滚事务
+                Db::rollback();
+                return $res;
+            }
+            $res = \app\common\model\User::login($param["login_name"], $param["password"]);
+            if ($res["code"] != 0) {
+                // 回滚事务c
+                Db::rollback();
+                return $res;
+            }
+            Db::commit();
+        } catch (\Exception $e) {
+            // 回滚事务
+            Db::rollback();
+            return returnFormat(9999, (string)$e);
+        }
+
+
+        return $res;
+    }
+
+    /**
+     * 登录
+     */
+    public function login()
+    {
+        $param = request()->param();
+        $rules = [
+            "login_name" => "require|length:2,25",
+            'password' => 'require|length:6,25',
+        ];
+        $this->autoValid($rules, $param);
+        $res = \app\common\model\User::login($param["login_name"], $param["password"]);
+        if ($res["code"] != 0) {
+            $this->error($res['msg'], $res["code"]);
+        }
+        $this->success($res['data']);
+    }
+
+}

+ 137 - 0
api/app/api/controller/Record.php

@@ -0,0 +1,137 @@
+<?php
+
+
+namespace app\api\controller;
+
+
+use app\common\ErrorCode;
+use app\common\model\Type;
+
+class Record extends BaseAuthorized
+{
+    public function typeList()
+    {
+        $typeList = Type::where("valid", "=", "1")->select();
+        $this->success($typeList);
+    }
+
+    public function add()
+    {
+        ///^(20|21|22|23|[0-1]\d):[0-5]\d:[0-5]\d$/;
+        $param = request()->param();
+        $rules = [
+            "record_date" => "require|date",
+            "record_begin" => "require",
+            "record_end" => "require",
+            "type_id" => "require|number",
+            "remark" => "require|max:25",
+        ];
+        $this->autoValid($rules, $param);
+        $record = new \app\common\model\Record([
+            "record_date" => $param["record_date"],
+            "record_begin" => $param["record_begin"],
+            "record_end" => $param["record_end"],
+            "type_id" => $param["type_id"],
+            "remark" => $param["remark"],
+            "user_id" => $this->user->id,
+        ]);
+        $record->record_long = $record->computeRecordLong();
+        $res = $record->save();
+        if ($res === false) {
+            //数据库读写失败
+            $this->error(ErrorCode::getError(ErrorCode::CODE_DB_ERROR), ErrorCode::CODE_DB_ERROR);
+
+        }
+        $this->success(ErrorCode::CODE_SUCC);
+
+    }
+
+    public function detail(){
+        $param = request()->param();
+        $rules = [
+            "id" => "require|number",
+
+        ];
+        $this->autoValid($rules, $param);
+        $record = \app\common\model\Record::find($param["id"]);
+        $record->type;
+        if (!$record) {
+            $this->error("记录未找到", ErrorCode::CODE_RECORD_NOT_FOUND);
+        }
+        $this->success($record);
+    }
+
+    public function edit()
+    {
+        $param = request()->param();
+        $rules = [
+            "id" => "require|number",
+            "record_date" => "require|date",
+            "record_begin" => "require",
+            "record_end" => "require",
+            "type_id" => "require|number",
+            "remark" => "require|max:25",
+        ];
+        $this->autoValid($rules, $param);
+        $record = \app\common\model\Record::find($param["id"]);
+        if (!$record) {
+            $this->error("记录未找到", ErrorCode::CODE_RECORD_NOT_FOUND);
+        }
+        $record->record_date = $param["record_date"];
+        $record->record_begin = $param["record_begin"];
+        $record->record_end = $param["record_end"];
+        $record->type_id = $param["type_id"];
+        $record->remark = $param["remark"];
+        $record->record_long = $record->computeRecordLong();
+        $res = $record->save();
+        if ($res === false) {
+            //数据库读写失败
+            $this->error(ErrorCode::getError(ErrorCode::CODE_DB_ERROR), ErrorCode::CODE_DB_ERROR);
+
+        }
+        $this->success(ErrorCode::CODE_SUCC);
+    }
+
+    public function delete()
+    {
+        $param = request()->param();
+        $rules = [
+            "id" => "require|number",
+        ];
+        $this->autoValid($rules, $param);
+        $res = \app\common\model\Record::where("id", "=", $param["id"])->delete();
+        if ($res === false) {
+            //数据库读写失败
+            $this->error(ErrorCode::getError(ErrorCode::CODE_DB_ERROR), ErrorCode::CODE_DB_ERROR);
+
+        }
+        $this->success(ErrorCode::CODE_SUCC);
+    }
+
+    public function index()
+    {
+        $param = request()->param();
+        $rules = [
+            "date" => "require|date"
+        ];
+        $this->autoValid($rules, $param);
+        //找当月
+        $dateStamp = strtotime($param["date"]);//当天的时间戳
+        $beginDay = date("Y-m-1", $dateStamp);//月头
+        $endDay = date("Y-m-" . date("t", $dateStamp), $dateStamp);
+        //找日期列表
+        $whereDateList[] = ["record_date", "between", [$beginDay, $endDay]];
+
+        $dateList = \app\common\model\Record::where($whereDateList)->field("record_date")->group("record_date")->order("record_date  asc")->select();
+        $dateArr = [];
+        foreach ($dateList as $key => $value) {
+            $dateArr[] = $value["record_date"];
+        }
+        //找当天
+        $recordList = \app\common\model\Record::with(["type"])->where("record_date", "=", date("Y-m-d", $dateStamp))->order("record_begin asc,id asc")->select();
+        $this->success([
+            "dateArr" => $dateArr,
+            "recordList" => $recordList
+        ]);
+    }
+}

+ 39 - 0
api/app/api/controller/User.php

@@ -0,0 +1,39 @@
+<?php
+
+
+namespace app\api\controller;
+
+
+use think\facade\Db;
+
+class User extends BaseAuthorized
+{
+    public function changePassword()
+    {
+        $param = request()->param();
+        $rules = [
+            "orgPassword" => "require|length:2,25",
+            'password' => 'require|length:6,25',
+            'repassword' => 'require|confirm:password',
+        ];
+        $this->autoValid($rules, $param);
+        $res = $this->user->changePassword($param["orgPassword"], $param["password"]);
+        if ($res["code"] != 0) {
+            $this->error($res['msg'], $res["code"]);
+        }
+        $this->success("");
+    }
+
+    /**
+     * 退出登录
+     */
+    public function loginOut(){
+        $res=$this->user->loginOut();
+        if ($res["code"] != 0) {
+            $this->error($res['msg'], $res["code"]);
+        }
+        $this->success("","退出成功");
+    }
+
+
+}

+ 5 - 0
api/app/api/event.php

@@ -0,0 +1,5 @@
+<?php
+// 这是系统自动生成的event定义文件
+return [
+
+];

+ 5 - 0
api/app/api/middleware.php

@@ -0,0 +1,5 @@
+<?php
+// 这是系统自动生成的middleware定义文件
+return [
+
+];

+ 212 - 0
api/app/common.php

@@ -0,0 +1,212 @@
+<?php
+// 应用公共文件
+
+
+
+
+if (!function_exists('returnFormat')) {
+    /**
+     * 格式化输出返回值
+     * @param int $code
+     * @param string $msg
+     * @param array $data
+     * @return mixed
+     */
+    function returnFormat($code=0,$msg="",$data=[]){
+        $res['code']=$code;
+        $res['data']=$data;
+        $res['msg']=$msg;
+        return $res;
+    }
+}
+
+
+
+
+
+if (!function_exists('each_item')) {
+    function each_item(&$array)
+    {
+        $res = array();
+        $key = key($array);
+        if ($key !== null) {
+            next($array);
+            $res[1] = $res['value'] = $array[$key];
+            $res[0] = $res['key'] = $key;
+        } else {
+            $res = false;
+        }
+        return $res;
+    }
+}
+
+if (!function_exists('getVirRootDir')) {
+    /**
+     * 获取虚拟目录路径
+     * @return bool|string
+     */
+    function getVirRootDir()
+    {
+        $url = $_SERVER['SCRIPT_NAME'];
+        $url = substr($url, 0, strripos($url, "/"));
+        return $url;
+    }
+}
+
+
+if (!function_exists('getNow')) {
+    /**
+     * 获取当时时间
+     * @param string $fmt 格式化
+     * @return false|string
+     */
+    function getNow($fmt = "Y-m-d H:i:s")
+    {
+        return date($fmt);
+    }
+}
+
+if (!function_exists('getUrl')) {
+    /**
+     * 获取当前的访问路径
+     * @return [type] [description]
+     */
+    function getUrl()
+    {
+        $sys_protocal = isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == '443' ? 'https://' : 'http://';
+        $php_self = $_SERVER['PHP_SELF'] ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
+        $path_info = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '';
+        $relate_url = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : $php_self . (isset($_SERVER['QUERY_STRING']) ? '?' . $_SERVER['QUERY_STRING'] : $path_info);
+        return $sys_protocal . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '') . $relate_url;
+    }
+}
+
+if(!function_exists('number2chinese')){
+
+    function number2chinese($num)
+    {
+        $arr = array('零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖');
+        $cny = array('', '拾', '佰', '仟', '', '萬', '亿', '兆');
+        //小数部分
+        $retval = '';
+        if (strpos($num, '.') !== false) {
+            list($num, $dec) = explode('.', $num);
+            $retval .= $arr[$dec[0]] . '角' . $arr[$dec[1]] . '分';
+        }
+        //整数部分
+        $str = $num != '0' ? strrev($num) : '';
+        $out = array();
+        for ($i = 0; $i < strlen($str); $i++) {
+            $out[$i] = $arr[$str[$i]];
+            $out[$i] .= $str[$i] != '0' ? $cny[$i % 4] : '';
+            if ($i > 1 && $str[$i] + $str[$i - 1] == 0) {
+                $out[$i] = '';
+            }
+            if ($i % 4 == 0) {
+                $out[$i] .= $cny[4 + floor($i / 4)];
+            }
+            //echo $out[$i].'<br>';
+        }
+        $retval = implode('', array_reverse($out)) . '元' . $retval;
+        return $retval;
+    }
+}
+
+
+if (!function_exists('toUnderScore')) {
+    /**
+     * 驼峰命名转下划线命名
+     * 思路:
+     * 小写和大写紧挨一起的地方,加上分隔符,然后全部转小写
+     * @param $camelCaps
+     * @param string $separator
+     * @return string
+     * @author web
+     */
+    function toUnderScore($camelCaps, $separator = '_')
+    {
+        return strtolower(preg_replace('/([a-z])([A-Z])/', "$1" . $separator . "$2", $camelCaps));
+    }
+}
+
+
+if (!function_exists('convertUTF8')) {
+    /**
+     * 解决中文乱码的问题
+     * @param $str
+     * @return string
+     */
+    function convertUTF8($str)
+    {
+        if (empty($str)) return '';
+        return iconv('utf-8', 'gb2312', $str);
+    }
+}
+if (!function_exists('isIdCardNo')) {
+    /**
+     * 判断是否为合法的身份证号码
+     * @param $mobile
+     * @return int
+     */
+    function isIdCardNo($vStr)
+    {
+        $vCity = array(
+            '11', '12', '13', '14', '15', '21', '22',
+            '23', '31', '32', '33', '34', '35', '36',
+            '37', '41', '42', '43', '44', '45', '46',
+            '50', '51', '52', '53', '54', '61', '62',
+            '63', '64', '65', '71', '81', '82', '91'
+        );
+
+        if (!preg_match('/^([\d]{17}[xX\d]|[\d]{15})$/', $vStr)) return false;
+        if (!in_array(substr($vStr, 0, 2), $vCity)) return false;
+        $vStr = preg_replace('/[xX]$/i', 'a', $vStr);
+        $vLength = strlen($vStr);
+        if ($vLength == 18) {
+            $vBirthday = substr($vStr, 6, 4) . '-' . substr($vStr, 10, 2) . '-' . substr($vStr, 12, 2);
+        } else {
+            $vBirthday = '19' . substr($vStr, 6, 2) . '-' . substr($vStr, 8, 2) . '-' . substr($vStr, 10, 2);
+            return false;//不考虑一代身份证了
+        }
+        if (date('Y-m-d', strtotime($vBirthday)) != $vBirthday) return false;
+        if ($vLength == 18) {
+            $vSum = 0;
+            for ($i = 17; $i >= 0; $i--) {
+                $vSubStr = substr($vStr, 17 - $i, 1);
+                $vSum += (pow(2, $i) % 11) * (($vSubStr == 'a') ? 10 : intval($vSubStr, 11));
+            }
+            if ($vSum % 11 != 1) return false;
+        }
+        return true;
+    }
+}
+if (!function_exists('cleanEnter')) {
+    /**
+     * 清除回车换行和前后空格
+     * @param $str
+     * @return array|string|string[]
+     */
+    function cleanEnter($str)
+    {
+        $str = trim($str);
+        $str = str_replace("\n", "", $str);
+        $str = str_replace("\r", "", $str);
+        return $str;
+    }
+}
+
+if (!function_exists('randNum')) {
+    /**
+     * 获取数字随机数
+     * @param $length 数字长度
+     * @return int
+     */
+    function randNum($length = 8)
+    {
+        $min = pow(10, $length-1) + 1;
+        $max = pow(10, $length ) - 1;
+        $rand = rand($min, $max);
+//        echo "length: $length, min: $min ,max: $max ,rand: $rand \r\n <br/>";
+        return $rand;
+    }
+}

+ 52 - 0
api/app/common/ErrorCode.php

@@ -0,0 +1,52 @@
+<?php
+
+
+namespace app\common;
+
+
+class ErrorCode
+{
+    const CODE_SUCC = "0";//成功代码
+    const CODE_DB_ERROR = "9005";//数据库写入失败
+    const CODE_RECORD_NOT_FOUND = "9404";//记录未找到或已被删除0
+    const CODE_TOKEN_ERR = "12";
+    const CODE_TOKEN_EXPIRE = "11";
+    const CODE_TOKEN_FORMAT_ERR = "14";
+    const CODE_TOKEN_NONE = "13";
+
+    /**
+     * 返回错误代内容
+     * @param $code
+     * @return mixed
+     */
+    public static function getError($code)
+    {
+        $errArr = self::getErrorArr();
+        if (!key_exists($code, $errArr)) {
+            return "未知错误";
+        }
+        return $errArr[$code];
+    }
+
+    /**
+     * 获取错误码数组
+     * @return array
+     */
+    protected static function getErrorArr()
+    {
+        return [
+            self::CODE_SUCC => "成功",
+            //100以内,需要重新登录
+            self::CODE_TOKEN_EXPIRE => "token过期",
+            self::CODE_TOKEN_ERR => "token不正确或已失效",
+            self::CODE_TOKEN_NONE => "缺少token",
+            self::CODE_TOKEN_FORMAT_ERR => "token格式不正确",
+            "9001" => "缺少签名",
+            "9002" => "签名不正确",
+            "9004" => "请求已过期",
+            self::CODE_DB_ERROR => "数据写入失败,请稍后再试",
+            self::CODE_RECORD_NOT_FOUND => "记录未找到或已被删除",
+            "9999" => "系统错误",
+        ];
+    }
+}

+ 2 - 0
api/app/common/common.php

@@ -0,0 +1,2 @@
+<?php
+// 这是系统自动生成的公共文件

+ 5 - 0
api/app/common/event.php

@@ -0,0 +1,5 @@
+<?php
+// 这是系统自动生成的event定义文件
+return [
+
+];

+ 5 - 0
api/app/common/middleware.php

@@ -0,0 +1,5 @@
+<?php
+// 这是系统自动生成的middleware定义文件
+return [
+
+];

+ 119 - 0
api/app/common/model/Base.php

@@ -0,0 +1,119 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: dengjq
+ * Date: 2019/1/24
+ * Time: 14:59
+ */
+
+namespace app\common\model;
+
+
+use think\Model;
+
+abstract class Base extends Model
+{
+    protected $keywordColumn = "name";
+
+
+    public function getList()
+    {
+        $where = [];
+        $keyword = input("keyword");
+        if (empty($keyword)) {
+            $keyword = input("searchData.keyword");
+        }
+        if ($keyword) {
+            $where[] = array($this->keywordColumn, "like", "%" . $keyword . "%");
+        }
+        $order_by = input("order_by", $this->getPk() . " desc");
+        $page_size = input("page_size", 10);
+        $list = $this->where($where)->order($order_by)->paginate($page_size);
+        return returnFormat(0, '查询成功', $list);
+    }
+
+    public function add()
+    {
+        $param = input('param.');
+        $param['update_time'] = $param['create_time'] = getNow();
+        $res = self::insert($param);
+        if ($res === false) {
+            return returnFormat(999, '服务器错误,新增失败');
+        }
+        return returnFormat(0, '添加成功');
+    }
+
+    public function detail()
+    {
+        $id = input("id");
+        if (!$id) {
+            return returnFormat(999, '缺少参数');
+        }
+        $where['id'] = $id;
+        $model = $this->where($where)->find();
+        if (!$model) {
+            return returnFormat(999, '未找到记录');
+        }
+        return returnFormat(0, '', $model->toArray());
+    }
+
+    public function del()
+    {
+        $id = input("id");
+        $where[$this->getPk()] = $id;
+
+        $model = $this->where($where)->find();
+        if (empty($model)) {
+            return returnFormat(999, '未找到记录');
+        }
+
+        $res = $model->delete();
+        if ($res === false) {
+            return returnFormat(999, '服务器错误');
+        }
+        return returnFormat(0, '删除成功');
+    }
+
+    public function edit()
+    {
+        $id = input("id");
+        if (!$id) {
+            return returnFormat(999, '缺少参数');
+        }
+        $where[$this->getPk()] = $id;
+        $model = $this->where($where)->find();
+        if (!$model) {
+            return returnFormat(999, '未找到记录');
+        }
+        $param = input("param.");
+        $param[$this->getPk()] = $id;
+        $res = self::update($param);
+        if ($res === false) {
+            return returnFormat(999, '服务器错误');
+        }
+        return returnFormat(0, '修改成功');
+    }
+
+    public function appendMerge($arr)
+    {
+        $arr = (array)$arr;
+        $this->append = array_merge($this->append, $arr);
+    }
+
+
+    /**
+     * 构造标准输出
+     * @param $code
+     * @param string $msg
+     * @return array
+     */
+    public static function standardOutput($code, $msg = "", $data = [])
+    {
+        $res = [
+            "code" => $code,
+            "msg" => $msg,
+            "data" => $data
+        ];
+        return $res;
+    }
+}

+ 35 - 0
api/app/common/model/Record.php

@@ -0,0 +1,35 @@
+<?php
+
+
+namespace app\common\model;
+
+
+class Record extends Base
+{
+
+    /**
+     * 计算时长
+     * @return int
+     */
+    public function computeRecordLong(){
+        $begin=strtotime(date("Y-m-d ").$this->record_begin);
+        $end=strtotime(date("Y-m-d ").$this->record_end);
+        return intval(($end-$begin)/60);
+    }
+
+    /**
+     * 关联类型
+     * @return \think\model\relation\HasOne
+     */
+    public function type(){
+        return $this->hasOne(Type::class,"id","type_id");
+    }
+
+    /**
+     * 关联用户
+     */
+    public function user(){
+        return $this->hasOne(User::class,"id","user_id");
+    }
+
+}

+ 10 - 0
api/app/common/model/Type.php

@@ -0,0 +1,10 @@
+<?php
+
+
+namespace app\common\model;
+
+
+class Type extends Base
+{
+
+}

+ 135 - 0
api/app/common/model/User.php

@@ -0,0 +1,135 @@
+<?php
+
+
+namespace app\common\model;
+
+
+use app\common\ErrorCode;
+
+class User extends Base
+{
+    public static $fieldStr = "id,login_name,salt,valid,last_login_time,login_count,token";
+
+    /**
+     * 检测用户是否存在
+     * @param $login_name
+     * @return array
+     */
+    public static function checkRegUser($login_name)
+    {
+        //检测账号是否被注册
+        $where['login_name'] = $login_name;
+        $exist = self::where($where)->find();
+        if ($exist) {
+            //用户存在
+            return self::standardOutput(9999, "用户已存在");
+        }
+        return self::standardOutput(ErrorCode::CODE_SUCC);
+    }
+
+    /**
+     * 用户注册
+     * @param $login_name
+     * @param $password
+     * @return array
+     */
+    public static function regUser($login_name, $password)
+    {
+        //注册用户
+        $res = self::checkRegUser($login_name);
+        if ($res["code"] != 0) {
+            return $res;
+        }
+        //创建用户
+        $salt = randNum(4);//生成随机盐
+        $user = new User([
+            "login_name" => $login_name,
+            "salt" => $salt,
+            "password" => md5($salt . $password),
+            "ext1" => $salt . $password
+        ]);
+        $res = $user->save();
+
+        if ($res === false) {
+            return self::standardOutput(ErrorCode::CODE_DB_ERROR, ErrorCode::getError(ErrorCode::CODE_DB_ERROR));
+        }
+        return self::standardOutput(ErrorCode::CODE_SUCC);
+    }
+
+    /**
+     * 用户登录
+     * @param $login_name
+     * @param $password
+     */
+    public static function login($login_name, $password)
+    {
+        $whereUser = [];
+        $whereUser["login_name"] = $login_name;
+        $user = self::where($whereUser)->find();
+        if (!$user) {
+            return self::standardOutput(9999, "用户不存在");
+        }
+        $passwordMd5 = md5($user->salt . $password);
+        if ($passwordMd5 != $user->password) {
+            return self::standardOutput(9999, "用户密码不正确");
+        }
+        //更新用户登录 信息
+        $user->last_login_time = getNow();
+        $user->login_count = $user->login_count + 1;
+        $user->token = $user->getToken();
+        $user->hidden(["salt","password"]);
+        $res = $user->save();
+        if ($res === false) {
+            //数据库读写失败
+            return self::standardOutput(ErrorCode::CODE_DB_ERROR, ErrorCode::getError(ErrorCode::CODE_DB_ERROR));
+        }
+        return self::standardOutput(ErrorCode::CODE_SUCC, "登录成功", $user);
+    }
+
+    /**
+     * 获取token
+     * @return string
+     */
+    public function getToken()
+    {
+        $expireDays = 7;//过期时间,单位天
+        //token:  md5([用户名][当前时间])|[用户id]|[过期时间]
+        $token = base64_encode(md5($this->login_name . getNow()) . "|" . $this->id . "|" . (time() + 86400 * $expireDays));
+        return $token;
+    }
+
+    /**
+     * 修改密码
+     */
+    public function changePassword($orgPassword, $newPassword)
+    {
+        //校验旧密码
+        $passwordMd5 = md5($this->salt . $orgPassword);
+        if ($passwordMd5 != $this->password) {
+            $str=$this->salt . $orgPassword."---".$passwordMd5."---".$this->password;
+            return self::standardOutput(9999, "原密码不正确".$str);
+        }
+        $this->password = md5($this->salt . $newPassword);
+        $res = $this->save();
+        if ($res === false) {
+            //数据库读写失败
+            return self::standardOutput(ErrorCode::CODE_DB_ERROR, ErrorCode::getError(ErrorCode::CODE_DB_ERROR));
+        }
+        return self::standardOutput(ErrorCode::CODE_SUCC);
+    }
+
+    /**
+     * 退出登录
+     */
+    public function loginOut()
+    {
+        $this->token = "";
+        $res = $this->save();
+        if ($res === false) {
+            //数据库读写失败
+            return self::standardOutput(ErrorCode::CODE_DB_ERROR, ErrorCode::getError(ErrorCode::CODE_DB_ERROR));
+        }
+        return self::standardOutput(ErrorCode::CODE_SUCC);
+    }
+
+}

+ 135 - 0
api/app/common/util/Rsa.php

@@ -0,0 +1,135 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: yckj_lzj
+ * Date: 2019-10-22
+ * Time: 19:27
+ */
+
+namespace app\common\util;
+
+
+class Rsa extends SingleObjectClass
+{
+    protected $priKeyStr;
+    protected $pubKeyStr;
+
+    public  function setPriPubKey($pubKey,$priKey){
+        $this->priKeyStr=$priKey;
+        $this->pubKeyStr=$pubKey;
+//        $this->$pubKeyStr=$pubKey;
+    }
+
+    public function setPriKey($priKey){
+        $this->priKeyStr=$priKey;
+    }
+
+    public function setPubKey($pubKey){
+        $this->pubKeyStr=$pubKey;
+    }
+
+    private  function getPriKeyStr()
+    {
+        return "-----BEGIN PRIVATE KEY-----\n".$this->priKeyStr."\n-----END PRIVATE KEY-----";
+    }
+
+    public  function getPubKeyStr(){
+        return "-----BEGIN PUBLIC KEY-----\n".$this->pubKeyStr."\n-----END PUBLIC KEY-----";
+    }
+
+
+    /**
+     * 获取公钥     *
+     * @return bool|resource
+     */
+    private  function getPublicKey()
+    {
+
+
+        $content = $this->getPubKeyStr();
+
+        return openssl_pkey_get_public($content);
+    }
+
+    /**
+     * 获取私钥
+     * @return bool|resource
+     */
+    private  function getPrivateKey()
+    {
+
+        $content = $this->getPriKeyStr();
+//        echo $content;
+        return openssl_pkey_get_private($content);
+    }
+
+
+    /**
+     * 私钥加密
+     * @param $signString
+     * @return string
+     */
+    public  function priSign($signString){
+        $privKeyId = $this->getPrivateKey();
+        $signature = '';
+        openssl_sign($signString, $signature, $privKeyId);
+        openssl_free_key($privKeyId);
+        return base64_encode($signature);
+
+    }
+
+
+    /**
+     * 私钥加密
+     * @param string $data
+     * @return null|string
+     */
+    public  function privEncrypt($data = '')
+    {
+
+        if (!is_string($data)) {
+            return null;
+        }
+        return openssl_private_encrypt($data, $encrypted, $this->getPrivateKey()) ? base64_encode($encrypted) : null;
+    }
+
+    /**
+     * 公钥加密
+     * @param string $data
+     * @return null|string
+     */
+    public  function publicEncrypt($data = '')
+    {
+        if (!is_string($data)) {
+            return null;
+        }
+        var_dump($this->getPublicKey());
+        return openssl_public_encrypt($data, $encrypted, $this->getPublicKey()) ? base64_encode($encrypted) : null;
+    }
+
+    /**
+     * 私钥解密
+     * @param string $encrypted
+     * @return null
+     */
+    public  function privDecrypt($encrypted = '')
+    {
+        if (!is_string($encrypted)) {
+            return null;
+        }
+        return (openssl_private_decrypt(base64_decode($encrypted), $decrypted, $this->getPrivateKey())) ? $decrypted : null;
+    }
+
+    /**
+     * 公钥解密
+     * @param string $encrypted
+     * @return null
+     */
+    public  function publicDecrypt($encrypted = '')
+    {
+        if (!is_string($encrypted)) {
+            return null;
+        }
+        return (openssl_public_decrypt(base64_decode($encrypted), $decrypted, $this->getPublicKey())) ? $decrypted : null;
+    }
+}

+ 59 - 0
api/app/common/util/SingleObjectClass.php

@@ -0,0 +1,59 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: yckj_lzj
+ * Date: 2019-08-21
+ * Time: 16:38
+ */
+
+namespace app\common\util;
+
+
+use think\Log;
+
+class SingleObjectClass
+{
+    protected $openLog=true;
+    //输出结果
+    protected function writeln($info, $type = "debug")
+    {
+        if ($this->openLog) {
+            Log::write(print_r($info, true), $type);
+        }
+    }
+
+    /**
+     * 返回内容
+     * @param $code
+     * @param $data
+     */
+    protected function getResult($code, $data = null)
+    {
+        $result['code'] = $code;
+        $result['msg'] = ActQuestionErrCode::$errInfo[$code];
+        if ($data) {
+            $result['data'] = $data;
+        }
+        return $result;
+    }
+
+    /**
+     * 类实例化(单例模式)
+     */
+    public static function instance()
+    {
+        static $_instance = array();
+
+        $classFullName = get_called_class();
+        if (!isset($_instance[$classFullName])) {
+            // $_instance[$classFullName] = new $classFullName();
+            // 1、先前这样写的话,PhpStrom 代码提示功能失效;
+            // 2、并且中间变量不能是 数组,如 不能用 return $_instance[$classFullName] 形式返回实例对象,否则 PhpStrom 代码提示功能失效;
+            $instance = $_instance[$classFullName] = new static();
+            return $instance;
+        }
+
+        return $_instance[$classFullName];
+    }
+
+}

+ 130 - 0
api/app/common/util/Util.php

@@ -0,0 +1,130 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: yckj-yf7
+ * Date: 2021/9/24
+ * Time: 17:25
+ */
+
+namespace app\common\util;
+
+/**
+ * 工具类
+ * @package app\common\util
+ */
+class Util
+{
+    /**
+     * 获取一定配置下的父子级的数据集合
+     * @param $list 一维的数据集合
+     * @param array $option 配置
+     *              field 判断子级的字段名,默认为id
+     *              parent_field 判断父级的字段名,默认为pid
+     *              children 写入返回值的字段名,默认为children
+     *              default 默认搜索开始的数值,默认为0
+     * @return array|mixed
+     */
+    public static function getChildrenList($list, $option = []){
+        $field = isset($option['field'])?$option['field']:'id';
+        $parent_field = isset($option['parent_field'])?$option['parent_field']:'pid';
+        $children_name = isset($option['children'])?$option['children']:'children';
+        $default = isset($option['default'])?$option['default']:0;
+
+        //按父级生成索引数组
+        $index_data = [];
+        foreach ($list as $item){
+            $index_data[$item[$parent_field]][] = $item;
+        }
+        unset($item);
+
+        return self::setChildren($index_data,$default,$field,$children_name);
+    }
+
+    /**
+     * 写入子集
+     * @param $index_data 索引数组
+     * @param $pid 父级数值
+     * @param $field 关联字段名
+     * @param $children_name 写入的子集字段名
+     * @return array|mixed
+     */
+    private static function setChildren($index_data, $pid, $field, $children_name){
+        if (isset($index_data[$pid])){
+            $list = $index_data[$pid];
+            foreach ($list as &$item){
+                $children = self::setChildren($index_data,$item[$field],$field, $children_name);
+                if (count($children)>0){
+                    $item[$children_name] = $children;
+                }
+            }
+            return $list;
+        }else{
+            return [];
+        }
+    }
+
+    /**
+     * 获取两个日期之间的日期数组
+     * @param $start_time
+     * @param $end_time
+     * @return mixed
+     */
+    public static function getPeriodDate($start_time,$end_time){
+        $start_time = strtotime($start_time);
+        $end_time = strtotime($end_time);
+        $i = 0;
+        $arr = [];
+        while ($start_time <= $end_time){
+            $arr[$i] = date('Y-m-d',$start_time);
+            $start_time = strtotime('+1 day',$start_time);
+            $i++;
+        }
+
+        return $arr;
+    }
+
+    /**
+     * 根据数字转换成excel的字母
+     * @param $num
+     * @return string
+     */
+    public static function numToExcelLetter($num)
+    {
+        //由于大写字母只有26个,所以基数为26
+        $base = 26;
+        $result = '';
+        while ($num > 0 ) {
+            $mod = (int)($num % $base);
+            $num = (int)($num / $base);
+
+            if($mod == 0){
+                $num -= 1;
+                $temp = self::numToLetter($base) . $result;
+            } elseif ($num == 0) {
+                $temp = self::numToLetter($mod) . $result;
+            } else {
+                $temp = self::numToLetter($mod) . $result;
+            }
+            $result = $temp;
+        }
+
+        return $result;
+    }
+
+    /**
+     * 数字转字母
+     * @param $num
+     * @return string
+     */
+    public static function numToLetter($num)
+    {
+        if ($num == 0) {
+            return '';
+        }
+
+        $num = (int)$num - 1;
+        //获取A的ascii码
+        $ordA = ord('A');
+        return chr($ordA + $num);
+    }
+}

File diff suppressed because it is too large
+ 17 - 0
api/app/controller/Index.php


+ 17 - 0
api/app/event.php

@@ -0,0 +1,17 @@
+<?php
+// 事件定义文件
+return [
+    'bind'      => [
+    ],
+
+    'listen'    => [
+        'AppInit'  => [],
+        'HttpRun'  => [],
+        'HttpEnd'  => [],
+        'LogLevel' => [],
+        'LogWrite' => [],
+    ],
+
+    'subscribe' => [
+    ],
+];

+ 12 - 0
api/app/middleware.php

@@ -0,0 +1,12 @@
+<?php
+// 全局中间件定义文件
+return [
+    // 全局请求缓存
+    // \think\middleware\CheckRequestCache::class,
+    // 多语言加载
+    // \think\middleware\LoadLangPack::class,
+    // Session初始化
+    // \think\middleware\SessionInit::class
+    //跨域请求
+    app\middleware\AllowCrossDomain::class
+];

+ 65 - 0
api/app/middleware/AllowCrossDomain.php

@@ -0,0 +1,65 @@
+<?php
+
+declare (strict_types=1);
+
+namespace app\middleware;
+
+use Closure;
+use think\Config;
+use think\Request;
+use think\Response;
+
+/**
+ * 跨域中间件
+ * Class AllowCrossDomain
+ * @package app\middleware
+ */
+class AllowCrossDomain
+{
+
+    protected $cookieDomain;
+
+    // header头配置
+    protected $header = [
+        "Access-Control-Allow-Origin" => "*",//注意修改这里填写你的前端的域名
+        'Access-Control-Allow-Credentials' => 'true',
+        'Access-Control-Max-Age' => 1800,
+        'Access-Control-Allow-Methods' => 'GET, POST, PATCH, PUT, DELETE, OPTIONS',
+        'Access-Control-Allow-Headers' => 'Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With,content-type,ignore,token',//如果有新增header字段,在这里添加
+    ];
+
+
+    /**
+     * AllowCrossDomain constructor.
+     * @param Config $config
+     */
+    public function __construct(Config $config)
+    {
+        $this->cookieDomain = $config->get('cookie.domain', '');
+    }
+
+    /**
+     * 允许跨域请求
+     * @access public
+     * @param Request $request
+     * @param Closure $next
+     * @param array $header
+     * @return Response
+     */
+    public function handle($request, Closure $next, ?array $header = [])
+    {
+        $header = !empty($header) ? array_merge($this->header, $header) : $this->header;
+
+        if (!isset($header['Access-Control-Allow-Origin'])) {
+            $origin = $request->header('origin');
+
+            if ($origin && ('' == $this->cookieDomain || strpos($origin, $this->cookieDomain))) {
+                $header['Access-Control-Allow-Origin'] = $origin;
+            } else {
+                $header['Access-Control-Allow-Origin'] = '*';
+            }
+        }
+
+        return $next($request)->header($header);
+    }
+}

+ 9 - 0
api/app/provider.php

@@ -0,0 +1,9 @@
+<?php
+use app\ExceptionHandle;
+use app\Request;
+
+// 容器Provider定义文件
+return [
+    'think\Request'          => Request::class,
+    'think\exception\Handle' => ExceptionHandle::class,
+];

+ 9 - 0
api/app/service.php

@@ -0,0 +1,9 @@
+<?php
+
+use app\AppService;
+
+// 系统服务定义文件
+// 服务在完成全局初始化之后执行
+return [
+    AppService::class,
+];

+ 49 - 0
api/composer.json

@@ -0,0 +1,49 @@
+{
+    "name": "topthink/think",
+    "description": "the new thinkphp framework",
+    "type": "project",
+    "keywords": [
+        "framework",
+        "thinkphp",
+        "ORM"
+    ],
+    "homepage": "http://thinkphp.cn/",
+    "license": "Apache-2.0",
+    "authors": [
+        {
+            "name": "liu21st",
+            "email": "liu21st@gmail.com"
+        },
+        {
+            "name": "yunwuxin",
+            "email": "448901948@qq.com"
+        }        
+    ],
+    "require": {
+        "php": ">=7.1.0",
+        "topthink/framework": "^6.0.0",
+        "topthink/think-orm": "^2.0",
+        "topthink/think-multi-app": "^1.0"
+    },
+    "require-dev": {
+        "symfony/var-dumper": "^4.2",
+        "topthink/think-trace":"^1.0"
+    },
+    "autoload": {
+        "psr-4": {
+            "app\\": "app"
+        },
+        "psr-0": {
+            "": "extend/"
+        }
+    },
+    "config": {
+        "preferred-install": "dist"
+    },
+    "scripts": {
+        "post-autoload-dump": [
+            "@php think service:discover",
+            "@php think vendor:publish"
+        ]
+    }
+}

+ 32 - 0
api/config/app.php

@@ -0,0 +1,32 @@
+<?php
+// +----------------------------------------------------------------------
+// | 应用设置
+// +----------------------------------------------------------------------
+
+return [
+    // 应用地址
+    'app_host'         => env('app.host', ''),
+    // 应用的命名空间
+    'app_namespace'    => '',
+    // 是否启用路由
+    'with_route'       => true,
+    // 默认应用
+    'default_app'      => 'index',
+    // 默认时区
+    'default_timezone' => 'Asia/Shanghai',
+
+    // 应用映射(自动多应用模式有效)
+    'app_map'          => [],
+    // 域名绑定(自动多应用模式有效)
+    'domain_bind'      => [],
+    // 禁止URL访问的应用列表(自动多应用模式有效)
+    'deny_app_list'    => [],
+
+    // 异常页面的模板文件
+    'exception_tmpl'   => app()->getThinkPath() . 'tpl/think_exception.tpl',
+
+    // 错误显示信息,非调试模式有效
+    'error_message'    => '页面错误!请稍后再试~',
+    // 显示错误信息
+    'show_error_msg'   => false,
+];

+ 29 - 0
api/config/cache.php

@@ -0,0 +1,29 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | 缓存设置
+// +----------------------------------------------------------------------
+
+return [
+    // 默认缓存驱动
+    'default' => env('cache.driver', 'file'),
+
+    // 缓存连接方式配置
+    'stores'  => [
+        'file' => [
+            // 驱动方式
+            'type'       => 'File',
+            // 缓存保存目录
+            'path'       => '',
+            // 缓存前缀
+            'prefix'     => '',
+            // 缓存有效期 0表示永久缓存
+            'expire'     => 0,
+            // 缓存标签前缀
+            'tag_prefix' => 'tag:',
+            // 序列化机制 例如 ['serialize', 'unserialize']
+            'serialize'  => [],
+        ],
+        // 更多的缓存连接
+    ],
+];

+ 10 - 0
api/config/common.php

@@ -0,0 +1,10 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: Wang
+ * Date: 2020-09-07
+ * Time: 14:39
+ */
+return [
+    "api_sign_secret"=>md5("api_sign_secret"),//接口签名秘钥
+];

+ 9 - 0
api/config/console.php

@@ -0,0 +1,9 @@
+<?php
+// +----------------------------------------------------------------------
+// | 控制台配置
+// +----------------------------------------------------------------------
+return [
+    // 指令定义
+    'commands' => [
+    ],
+];

+ 20 - 0
api/config/cookie.php

@@ -0,0 +1,20 @@
+<?php
+// +----------------------------------------------------------------------
+// | Cookie设置
+// +----------------------------------------------------------------------
+return [
+    // cookie 保存时间
+    'expire'    => 0,
+    // cookie 保存路径
+    'path'      => '/',
+    // cookie 有效域名
+    'domain'    => '',
+    //  cookie 启用安全传输
+    'secure'    => false,
+    // httponly设置
+    'httponly'  => false,
+    // 是否使用 setcookie
+    'setcookie' => true,
+    // samesite 设置,支持 'strict' 'lax'
+    'samesite'  => '',
+];

+ 63 - 0
api/config/database.php

@@ -0,0 +1,63 @@
+<?php
+
+return [
+    // 默认使用的数据库连接配置
+    'default'         => env('database.driver', 'mysql'),
+
+    // 自定义时间查询规则
+    'time_query_rule' => [],
+
+    // 自动写入时间戳字段
+    // true为自动识别类型 false关闭
+    // 字符串则明确指定时间字段类型 支持 int timestamp datetime date
+    'auto_timestamp'  => true,
+
+    // 时间字段取出后的默认时间格式
+    'datetime_format' => 'Y-m-d H:i:s',
+
+    // 时间字段配置 配置格式:create_time,update_time
+    'datetime_field'  => '',
+
+    // 数据库连接配置信息
+    'connections'     => [
+        'mysql' => [
+            // 数据库类型
+            'type'            => env('database.type', 'mysql'),
+            // 服务器地址
+            'hostname'        => env('database.hostname', '127.0.0.1'),
+            // 数据库名
+            'database'        => env('database.database', ''),
+            // 用户名
+            'username'        => env('database.username', 'root'),
+            // 密码
+            'password'        => env('database.password', ''),
+            // 端口
+            'hostport'        => env('database.hostport', '3306'),
+            // 数据库连接参数
+            'params'          => [],
+            // 数据库编码默认采用utf8
+            'charset'         => env('database.charset', 'utf8'),
+            // 数据库表前缀
+            'prefix'          => env('database.prefix', ''),
+
+            // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
+            'deploy'          => 0,
+            // 数据库读写是否分离 主从式有效
+            'rw_separate'     => false,
+            // 读写分离后 主服务器数量
+            'master_num'      => 1,
+            // 指定从服务器序号
+            'slave_no'        => '',
+            // 是否严格检查字段是否存在
+            'fields_strict'   => true,
+            // 是否需要断线重连
+            'break_reconnect' => false,
+            // 监听SQL
+            'trigger_sql'     => env('app_debug', true),
+            // 开启字段缓存
+            'fields_cache'    => false,
+        ],
+
+        // 更多的数据库配置信息
+    ],
+];

+ 24 - 0
api/config/filesystem.php

@@ -0,0 +1,24 @@
+<?php
+
+return [
+    // 默认磁盘
+    'default' => env('filesystem.driver', 'local'),
+    // 磁盘列表
+    'disks'   => [
+        'local'  => [
+            'type' => 'local',
+            'root' => app()->getRuntimePath() . 'storage',
+        ],
+        'public' => [
+            // 磁盘类型
+            'type'       => 'local',
+            // 磁盘路径
+            'root'       => app()->getRootPath() . 'public/storage',
+            // 磁盘路径对应的外部URL路径
+            'url'        => '/storage',
+            // 可见性
+            'visibility' => 'public',
+        ],
+        // 更多的磁盘配置信息
+    ],
+];

+ 27 - 0
api/config/lang.php

@@ -0,0 +1,27 @@
+<?php
+// +----------------------------------------------------------------------
+// | 多语言设置
+// +----------------------------------------------------------------------
+
+return [
+    // 默认语言
+    'default_lang'    => env('lang.default_lang', 'zh-cn'),
+    // 允许的语言列表
+    'allow_lang_list' => [],
+    // 多语言自动侦测变量名
+    'detect_var'      => 'lang',
+    // 是否使用Cookie记录
+    'use_cookie'      => true,
+    // 多语言cookie变量
+    'cookie_var'      => 'think_lang',
+    // 多语言header变量
+    'header_var'      => 'think-lang',
+    // 扩展语言包
+    'extend_list'     => [],
+    // Accept-Language转义为对应语言包名称
+    'accept_language' => [
+        'zh-hans-cn' => 'zh-cn',
+    ],
+    // 是否支持语言分组
+    'allow_group'     => false,
+];

+ 45 - 0
api/config/log.php

@@ -0,0 +1,45 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | 日志设置
+// +----------------------------------------------------------------------
+return [
+    // 默认日志记录通道
+    'default'      => env('log.channel', 'file'),
+    // 日志记录级别
+    'level'        => [],
+    // 日志类型记录的通道 ['error'=>'email',...]
+    'type_channel' => [],
+    // 关闭全局日志写入
+    'close'        => false,
+    // 全局日志处理 支持闭包
+    'processor'    => null,
+
+    // 日志通道列表
+    'channels'     => [
+        'file' => [
+            // 日志记录方式
+            'type'           => 'File',
+            // 日志保存目录
+            'path'           => '',
+            // 单文件日志写入
+            'single'         => false,
+            // 独立日志级别
+            'apart_level'    => [],
+            // 最大日志文件数量
+            'max_files'      => 0,
+            // 使用JSON格式记录
+            'json'           => false,
+            // 日志处理
+            'processor'      => null,
+            // 关闭通道日志写入
+            'close'          => false,
+            // 日志输出格式化
+            'format'         => '[%s][%s] %s',
+            // 是否实时写入
+            'realtime_write' => false,
+        ],
+        // 其它日志通道配置
+    ],
+
+];

+ 8 - 0
api/config/middleware.php

@@ -0,0 +1,8 @@
+<?php
+// 中间件配置
+return [
+    // 别名或分组
+    'alias'    => [],
+    // 优先级设置,此数组中的中间件会按照数组中的顺序优先执行
+    'priority' => [],
+];

+ 45 - 0
api/config/route.php

@@ -0,0 +1,45 @@
+<?php
+// +----------------------------------------------------------------------
+// | 路由设置
+// +----------------------------------------------------------------------
+
+return [
+    // pathinfo分隔符
+    'pathinfo_depr'         => '/',
+    // URL伪静态后缀
+    'url_html_suffix'       => 'html',
+    // URL普通方式参数 用于自动生成
+    'url_common_param'      => true,
+    // 是否开启路由延迟解析
+    'url_lazy_route'        => false,
+    // 是否强制使用路由
+    'url_route_must'        => false,
+    // 合并路由规则
+    'route_rule_merge'      => false,
+    // 路由是否完全匹配
+    'route_complete_match'  => false,
+    // 访问控制器层名称
+    'controller_layer'      => 'controller',
+    // 空控制器名
+    'empty_controller'      => 'Error',
+    // 是否使用控制器后缀
+    'controller_suffix'     => false,
+    // 默认的路由变量规则
+    'default_route_pattern' => '[\w\.]+',
+    // 是否开启请求缓存 true自动缓存 支持设置请求缓存规则
+    'request_cache_key'     => false,
+    // 请求缓存有效期
+    'request_cache_expire'  => null,
+    // 全局请求缓存排除规则
+    'request_cache_except'  => [],
+    // 默认控制器名
+    'default_controller'    => 'Index',
+    // 默认操作名
+    'default_action'        => 'index',
+    // 操作方法后缀
+    'action_suffix'         => '',
+    // 默认JSONP格式返回的处理方法
+    'default_jsonp_handler' => 'jsonpReturn',
+    // 默认JSONP处理方法
+    'var_jsonp_handler'     => 'callback',
+];

+ 19 - 0
api/config/session.php

@@ -0,0 +1,19 @@
+<?php
+// +----------------------------------------------------------------------
+// | 会话设置
+// +----------------------------------------------------------------------
+
+return [
+    // session name
+    'name'           => 'PHPSESSID',
+    // SESSION_ID的提交变量,解决flash上传跨域
+    'var_session_id' => '',
+    // 驱动方式 支持file cache
+    'type'           => 'file',
+    // 存储连接标识 当type使用cache的时候有效
+    'store'          => null,
+    // 过期时间
+    'expire'         => 1440,
+    // 前缀
+    'prefix'         => '',
+];

+ 10 - 0
api/config/trace.php

@@ -0,0 +1,10 @@
+<?php
+// +----------------------------------------------------------------------
+// | Trace设置 开启调试模式后有效
+// +----------------------------------------------------------------------
+return [
+    // 内置Html和Console两种方式 支持扩展
+    'type'    => 'Html',
+    // 读取的日志通道名
+    'channel' => '',
+];

+ 25 - 0
api/config/view.php

@@ -0,0 +1,25 @@
+<?php
+// +----------------------------------------------------------------------
+// | 模板设置
+// +----------------------------------------------------------------------
+
+return [
+    // 模板引擎类型使用Think
+    'type'          => 'Think',
+    // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 3 保持操作方法
+    'auto_rule'     => 1,
+    // 模板目录名
+    'view_dir_name' => 'view',
+    // 模板后缀
+    'view_suffix'   => 'html',
+    // 模板文件名分隔符
+    'view_depr'     => DIRECTORY_SEPARATOR,
+    // 模板引擎普通标签开始标记
+    'tpl_begin'     => '{',
+    // 模板引擎普通标签结束标记
+    'tpl_end'       => '}',
+    // 标签库标签开始标记
+    'taglib_begin'  => '{',
+    // 标签库标签结束标记
+    'taglib_end'    => '}',
+];

+ 2 - 0
api/extend/.gitignore

@@ -0,0 +1,2 @@
+*
+!.gitignore

+ 8 - 0
api/public/.htaccess

@@ -0,0 +1,8 @@
+<IfModule mod_rewrite.c>
+  Options +FollowSymlinks -Multiviews
+  RewriteEngine On
+
+  RewriteCond %{REQUEST_FILENAME} !-d
+  RewriteCond %{REQUEST_FILENAME} !-f
+  RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
+</IfModule>

BIN
api/public/favicon.ico


+ 24 - 0
api/public/index.php

@@ -0,0 +1,24 @@
+<?php
+// +----------------------------------------------------------------------
+// | ThinkPHP [ WE CAN DO IT JUST THINK ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2006-2019 http://thinkphp.cn All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+// +----------------------------------------------------------------------
+// | Author: liu21st <liu21st@gmail.com>
+// +----------------------------------------------------------------------
+
+// [ 应用入口文件 ]
+namespace think;
+
+require __DIR__ . '/../vendor/autoload.php';
+
+// 执行HTTP应用并响应
+$http = (new App())->http;
+
+$response = $http->run();
+
+$response->send();
+
+$http->end($response);

+ 2 - 0
api/public/robots.txt

@@ -0,0 +1,2 @@
+User-agent: *
+Disallow:

+ 19 - 0
api/public/router.php

@@ -0,0 +1,19 @@
+<?php
+// +----------------------------------------------------------------------
+// | ThinkPHP [ WE CAN DO IT JUST THINK ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+// +----------------------------------------------------------------------
+// | Author: liu21st <liu21st@gmail.com>
+// +----------------------------------------------------------------------
+// $Id$
+
+if (is_file($_SERVER["DOCUMENT_ROOT"] . $_SERVER["SCRIPT_NAME"])) {
+    return false;
+} else {
+    $_SERVER["SCRIPT_FILENAME"] = __DIR__ . '/index.php';
+
+    require __DIR__ . "/index.php";
+}

+ 2 - 0
api/public/static/.gitignore

@@ -0,0 +1,2 @@
+*
+!.gitignore

+ 17 - 0
api/route/app.php

@@ -0,0 +1,17 @@
+<?php
+// +----------------------------------------------------------------------
+// | ThinkPHP [ WE CAN DO IT JUST THINK ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+// +----------------------------------------------------------------------
+// | Author: liu21st <liu21st@gmail.com>
+// +----------------------------------------------------------------------
+use think\facade\Route;
+
+Route::get('think', function () {
+    return 'hello,ThinkPHP6!';
+});
+
+Route::get('hello/:name', 'index/hello');

+ 2 - 0
api/runtime/.gitignore

@@ -0,0 +1,2 @@
+*
+!.gitignore

+ 10 - 0
api/think

@@ -0,0 +1,10 @@
+#!/usr/bin/env php
+<?php
+namespace think;
+
+// 命令行入口文件
+// 加载基础文件
+require __DIR__ . '/vendor/autoload.php';
+
+// 应用初始化
+(new App())->console->run();

+ 100 - 0
api/time_manager.sql

@@ -0,0 +1,100 @@
+/*
+Navicat MySQL Data Transfer
+
+Source Server         : 0localhost
+Source Server Version : 50726
+Source Host           : localhost:3306
+Source Database       : time_manager
+
+Target Server Type    : MYSQL
+Target Server Version : 50726
+File Encoding         : 65001
+
+Date: 2021-11-21 03:32:29
+*/
+
+SET FOREIGN_KEY_CHECKS=0;
+
+-- ----------------------------
+-- Table structure for record
+-- ----------------------------
+DROP TABLE IF EXISTS `record`;
+CREATE TABLE `record` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `user_id` int(11) DEFAULT '0' COMMENT '用户ID',
+  `record_date` date DEFAULT NULL COMMENT '记录日期',
+  `record_begin` varchar(255) DEFAULT '' COMMENT '记录开始时间',
+  `record_end` varchar(255) DEFAULT '' COMMENT '记录结束时间',
+  `record_long` int(11) DEFAULT '0' COMMENT '记录时长,分钟',
+  `type_id` int(11) DEFAULT '0' COMMENT '记录类型',
+  `remark` varchar(255) DEFAULT '' COMMENT '备注',
+  `create_time` datetime DEFAULT NULL COMMENT '添加时间',
+  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+  `ext1` text COMMENT '扩展字段1',
+  `ext2` text COMMENT '扩展字段2',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8mb4 COMMENT='时间记录';
+
+-- ----------------------------
+-- Records of record
+-- ----------------------------
+INSERT INTO `record` VALUES ('4', '7', '2021-11-21', '01:45', '02:45', '60', '1', '55', '2021-11-21 02:45:57', '2021-11-21 02:45:57', null, null);
+INSERT INTO `record` VALUES ('5', '7', '2021-11-21', '01:47', '02:47', '60', '1', '333', '2021-11-21 02:47:54', '2021-11-21 02:47:54', null, null);
+INSERT INTO `record` VALUES ('6', '7', '2021-11-21', '01:48', '02:48', '60', '1', 'eee', '2021-11-21 02:48:25', '2021-11-21 02:48:25', null, null);
+INSERT INTO `record` VALUES ('8', '7', '2021-11-21', '01:53', '02:54', '61', '2', 'ddd', '2021-11-21 02:53:48', '2021-11-21 02:53:48', null, null);
+INSERT INTO `record` VALUES ('9', '7', '2021-11-22', '01:54', '02:54', '60', '1', 'www', '2021-11-21 02:54:51', '2021-11-21 02:54:51', null, null);
+INSERT INTO `record` VALUES ('10', '7', '2021-11-21', '01:43', '02:43', '60', '2', '5666', '2021-11-21 03:02:34', '2021-11-21 03:02:34', null, null);
+INSERT INTO `record` VALUES ('16', '7', '2021-11-21', '01:36', '02:43', '67', '4', '5666', '2021-11-21 03:10:31', '2021-11-21 03:10:31', null, null);
+INSERT INTO `record` VALUES ('18', '7', '2021-11-21', '01:45', '04:45', '180', '1', '55', '2021-11-21 03:19:00', '2021-11-21 03:19:00', null, null);
+INSERT INTO `record` VALUES ('19', '7', '2021-11-21', '00:32', '02:43', '131', '1', '我爱中国', '2021-11-21 03:20:09', '2021-11-21 03:21:39', null, null);
+INSERT INTO `record` VALUES ('20', '7', '2021-11-21', '00:36', '02:43', '127', '3', '我中国', '2021-11-21 03:20:14', '2021-11-21 03:21:48', null, null);
+INSERT INTO `record` VALUES ('21', '7', '2021-11-24', '02:31', '03:31', '60', '1', '我爱学习', '2021-11-21 03:31:50', '2021-11-21 03:31:50', null, null);
+
+-- ----------------------------
+-- Table structure for type
+-- ----------------------------
+DROP TABLE IF EXISTS `type`;
+CREATE TABLE `type` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `name` varchar(255) DEFAULT '' COMMENT '类型名称',
+  `color` varchar(255) DEFAULT '' COMMENT '颜色',
+  `valid` int(11) DEFAULT '1' COMMENT '是否有效,0无效,1有效',
+  `create_time` datetime DEFAULT NULL COMMENT '添加时间',
+  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+  `ext1` text COMMENT '扩展字段1',
+  `ext2` text COMMENT '扩展字段2',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COMMENT='类型表';
+
+-- ----------------------------
+-- Records of type
+-- ----------------------------
+INSERT INTO `type` VALUES ('1', '学习', '#2979ff', '1', null, null, null, null);
+INSERT INTO `type` VALUES ('2', '游戏', '#ff9900', '1', null, null, null, null);
+INSERT INTO `type` VALUES ('3', '运动', '#19be6b', '1', null, null, null, null);
+INSERT INTO `type` VALUES ('4', '恋爱', ' #fa3534', '1', null, null, null, null);
+
+-- ----------------------------
+-- Table structure for user
+-- ----------------------------
+DROP TABLE IF EXISTS `user`;
+CREATE TABLE `user` (
+  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
+  `login_name` varchar(255) DEFAULT NULL COMMENT '管理员账号',
+  `password` varchar(255) DEFAULT NULL COMMENT '密码',
+  `salt` varchar(255) CHARACTER SET utf8 DEFAULT '' COMMENT '密码盐,用于和密码明文组合加密',
+  `valid` tinyint(11) DEFAULT '1' COMMENT '是否有效,0:无效,1:有效',
+  `create_time` datetime DEFAULT NULL COMMENT '添加时间',
+  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+  `ext1` text COMMENT '扩展字段1',
+  `ext2` text COMMENT '扩展字段2',
+  `last_login_time` datetime DEFAULT NULL COMMENT '最后一次登录时间',
+  `login_count` int(11) DEFAULT '0' COMMENT '登录次数',
+  `token` varchar(255) DEFAULT '' COMMENT 'token',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
+
+-- ----------------------------
+-- Records of user
+-- ----------------------------
+INSERT INTO `user` VALUES ('7', '123', 'e3497c5e785263d924514bf6282804b0', '9215', '1', '2021-11-21 02:06:12', '2021-11-21 03:31:20', '9215123456', null, '2021-11-21 03:31:20', '7', 'YTZlNjU3ODMyMGM5MDM5ZDlkYTQ2YTQ3OWNiYWVlYTB8N3wxNjM4MDQxNDgw');

+ 1 - 0
api/view/README.md

@@ -0,0 +1 @@
+如果不使用模板,可以删除该目录

+ 6 - 0
api/说明.md

@@ -0,0 +1,6 @@
+#### app\middleware\AllowCrossDomain
+跨域中间件,如果有新增跨域字段,在此中间件中修改
+
+### app\common\util\SingleObjectClass 
+单例模式基类
+