wugg 2 jaren geleden
commit
4bde0aabd7
100 gewijzigde bestanden met toevoegingen van 8352 en 0 verwijderingen
  1. 1 0
      .gitignore
  2. 1236 0
      CHANGELOG.md
  3. 32 0
      LICENSE.txt
  4. 133 0
      README.md
  5. 1 0
      application/.htaccess
  6. 21 0
      application/Admin/command/Test.php
  7. 275 0
      application/Admin/common.php
  8. 5 0
      application/Admin/config.php
  9. 381 0
      application/Admin/controller/Account.php
  10. 35 0
      application/Admin/controller/Base.php
  11. 17 0
      application/Admin/controller/Expire.php
  12. 10 0
      application/Admin/controller/Index.php
  13. 80 0
      application/Admin/controller/Login.php
  14. 397 0
      application/Admin/controller/Menu.php
  15. 196 0
      application/Admin/controller/Order.php
  16. 219 0
      application/Admin/controller/Stock.php
  17. 270 0
      application/Admin/controller/Stock2.php
  18. 133 0
      application/Admin/controller/System.php
  19. 30 0
      application/Admin/controller/Upload.php
  20. 50 0
      application/Admin/controller/User.php
  21. 53 0
      application/Admin/controller/Version.php
  22. 9 0
      application/Admin/model/User.php
  23. 51 0
      application/Home/common.php
  24. 5 0
      application/Home/config.php
  25. 227 0
      application/Home/controller/Addr.php
  26. 57 0
      application/Home/controller/Base.php
  27. 12 0
      application/Home/controller/Index.php
  28. 124 0
      application/Home/controller/Login.php
  29. 260 0
      application/Home/controller/Order.php
  30. 28 0
      application/Home/controller/User.php
  31. 41 0
      application/Home/controller/Vdlist.php
  32. 9 0
      application/Home/model/User.php
  33. 14 0
      application/command.php
  34. 96 0
      application/common.php
  35. 243 0
      application/config.php
  36. 55 0
      application/database.php
  37. 84 0
      application/route.php
  38. 28 0
      application/tags.php
  39. 29 0
      build.php
  40. 37 0
      composer.json
  41. 206 0
      composer.lock
  42. 2 0
      extend/.gitignore
  43. 0 0
      public/.htaccess
  44. BIN
      public/favicon.ico
  45. 19 0
      public/index.php
  46. 4 0
      public/nginx.htaccess
  47. 2 0
      public/robots.txt
  48. 20 0
      public/router.php
  49. BIN
      public/upload/20210924/334e6a9e80bf543144695263397c8d4b.jpg
  50. BIN
      public/upload/20210924/b0e425e8396f4100ee4c7bccec1b8c02.jpg
  51. BIN
      public/upload/20211021/229b0fcb6a7354ed9198a8a923532c78.png
  52. BIN
      public/upload/20211021/321a256afc2765f0879dbac95533ae63.png
  53. BIN
      public/upload/20211021/9c2d89d4f0bff60434e4222ff4cc3ae1.png
  54. BIN
      public/upload/20211021/ccd60e0bdecb6231c67eb42ed98ecf27.png
  55. BIN
      public/upload/20211021/f0efc0aea59b8b5289e58a422bb458be.png
  56. BIN
      public/upload/20211021/f5224fe1aa65e1fa5194dae21d91a05d.png
  57. BIN
      public/upload/20211115/4167c72de4b4190efef76a5459bcde16.jpg
  58. BIN
      public/upload/20211117/02dda17daeca31abc84342f212a2f107.jpg
  59. BIN
      public/upload/20211117/0a371d939ea9c11725c1dd8e7eddccd8.jpg
  60. BIN
      public/upload/20211117/0a52bbd6d23a55f64550f98ab981a022.jpg
  61. BIN
      public/upload/20211117/0e33954161a26198af81c8966dc0ffc0.jpg
  62. BIN
      public/upload/20211117/1c9a3be4b1b4b4d597d3c4916893cd29.jpg
  63. BIN
      public/upload/20211117/293e261ee9f0a344300a5f47012f1f6c.jpg
  64. BIN
      public/upload/20211117/2b23345356af9dac20d27515d568c446.jpg
  65. BIN
      public/upload/20211117/3b76ea39af9b4541327f277f8640f664.jpg
  66. BIN
      public/upload/20211117/517209a7d49dc3444422b961444ff06b.jpg
  67. BIN
      public/upload/20211117/59e365bbdff192d6203cc486fdfeffb6.jpg
  68. BIN
      public/upload/20211117/5b207dd1547b802113cfc99bd9ae4be6.jpg
  69. BIN
      public/upload/20211117/695d3042fd9da1229e4fb0e48d2c7e51.jpg
  70. BIN
      public/upload/20211117/88de72f3b8663349583df64414e27445.jpg
  71. BIN
      public/upload/20211117/89638faa808c1cc075db7470d71cc355.jpg
  72. BIN
      public/upload/20211117/97b89c692e260f1131eb28c852044f86.jpg
  73. BIN
      public/upload/20211117/b00a3732f0e1aab6065e5e1efc2b7f5f.jpg
  74. BIN
      public/upload/20211117/b7b15212eec251a510ae7ba030ba8a23.jpg
  75. BIN
      public/upload/20211117/b96a6a441cf25d1812a35a5b558f38e0.jpg
  76. BIN
      public/upload/20211117/cc01842ecc0cc51009a2c0602d074125.jpg
  77. BIN
      public/upload/20211117/ce3c6500c332dc3306db536e01e5fdc6.jpg
  78. BIN
      public/upload/20211117/e24545b4fe387c8582c8a08a16526b6e.jpg
  79. BIN
      public/upload/20211117/e9fe42067e2755dd69a371950669801d.jpg
  80. BIN
      public/upload/20211117/ed720d1978bab890ddc4800107de7ed2.jpg
  81. BIN
      public/upload/20211117/f1cfb4d65ba08f85fc7f76d2164f1374.jpg
  82. BIN
      public/upload/20211117/f453e4dfecec6c06a2f09d79ae693b8b.jpg
  83. BIN
      public/upload/20211126/426337790046a7c05ee6d662a030432f.png
  84. 17 0
      think
  85. 1 0
      thinkphp/.htaccess
  86. 47 0
      thinkphp/.travis.yml
  87. 119 0
      thinkphp/CONTRIBUTING.md
  88. 32 0
      thinkphp/LICENSE.txt
  89. 114 0
      thinkphp/README.md
  90. 65 0
      thinkphp/base.php
  91. 12 0
      thinkphp/codecov.yml
  92. 35 0
      thinkphp/composer.json
  93. 20 0
      thinkphp/console.php
  94. 298 0
      thinkphp/convention.php
  95. 589 0
      thinkphp/helper.php
  96. 136 0
      thinkphp/lang/zh-cn.php
  97. 681 0
      thinkphp/library/think/App.php
  98. 235 0
      thinkphp/library/think/Build.php
  99. 247 0
      thinkphp/library/think/Cache.php
  100. 467 0
      thinkphp/library/think/Collection.php

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+

+ 1236 - 0
CHANGELOG.md

@@ -0,0 +1,1236 @@
+## 2019-1-11 V5.0.24
+
+本次更新包含了一个安全更新,建议更新
+
+- 改进关联的save方法
+- 改进模型数据验证
+- Collection增加values方法
+- 改进unique验证方法
+- 改进Request类的method方法
+
+## 2018-12-9 V5.0.23
+
+本次版本更新主要涉及一个安全更新,推荐尽快更新到最新版本。
+
+* Query支持调用模型的查询范围
+* 聚合查询字段支持`DISTINCT`
+* 改进闭包验证的参数
+* 多对多关联支持指定中间表数据名称
+* after/before验证支持指定字段验证
+* 改进多对多关联
+* 改进验证类
+* 增加`afterWith`和`beforeWith`验证规则 用于比较日期字段
+* 完善规则提示
+* 改进断线重连
+* 修正软删除的`destroy`方法
+* 修复模型的`save`方法当`data`变量为空 数据不验证
+* 模型增加`replace`方法
+* MorphOne 增加 make 方法创建关联对象实例
+* 改进`count`方法返回值类型
+* 改进聚合查询方法的正则判断
+* 改进`sqlsrv`驱动
+* 完善关联的`save`方法
+* 修正控制器名获取
+
+
+## 2018-10-22 V5.0.22
+
+该版本主要增加了JSON日志格式的支持,并且包含了一个安全更新。
+
+* 调试模式下关闭路由解析缓存
+* 改进Log类支持`json`日志格式
+* 改进聚合查询的安全性
+* 改进`count`查询的返回值类型
+
+## 2018-9-7 V5.0.21
+
+该版本主要做了一些已知问题的修正,改进了对Swoole的支持,以及增加路由解析缓存功能。
+
+* 增加路由解析缓存功能
+* 改进url生成的端口问题
+* 改进缓存驱动
+* 改进value方法的缓存处理
+* 修正Builder类的insertAll方法
+* 改进对Swoole的支持(使用参考:[xavier-swoole](https://github.com/xavieryang007/xavier-swoole))
+
+## 2018-5-11 V5.0.20
+
+该版本为修正版本,修正了一些已知的问题。
+
+* `join`方法的条件支持传入`Expression`对象
+* 改进驱动的`parseKey`方法
+* 改进Request类的`host`方法
+* 使用`exp`表达式更新数据的异常提示
+* 修正查询
+* 改进多对多关联的中间表模型更新
+
+## 2018-4-25 V5.0.19
+
+该版本属于改进版本,主要改进了composer自动加载及内置模板引擎的一处可能的安全隐患。
+
+* 改进composer自动加载
+* 改进模板引擎一处安全隐患
+* 改进`comment`方法解析
+* 改进分布式写入数据后及时读取的问题
+* 改进url操作方法的自动转换
+* 改进分页类魔术方法的返回值
+* SQL日志增加主从标记
+
+## 2018-4-14 V5.0.18
+
+该版本主要修正上一个发布的一些BUG,并且改进了`exp`表达式查询/写入的严谨性。
+
+* 修正`field`方法`*`兼容问题;
+* 修正`inc/dec`方法;
+* 修正`setInc/setDec`方法;
+* 改进`insertAll`方法;
+* 改进`parseTime`方法;
+* 改进`exp`表达式查询/写入的严谨性;
+
+## 2018-4-12 V5.0.17
+
+该版本主要是一些修正和改进,并且包含了一个安全更新。
+
+* 改进Response类`create`方法
+* 改进`inc/dec`查询
+* 默认模板渲染规则支持直接使用操作方法名
+* 改进视图驱动
+* 改进Request类ip方法 支持代理设置
+* 修正request类的`create`方法
+* 闭包查询使用`cache(true)`抛出异常
+* 改进composer自动加载文件
+* 增加`Expression`类及相关方法
+
+## 2018-3-26 V5.0.16
+
+该版本主要做了一些修正和改进,由于包含了一个安全更新,是一个推荐更新的版本。
+
+* 改进Url生成
+* 改进composer自动加载性能
+* 改进一对一查询
+* 改进查询缓存
+* 改进field方法
+* 优化Template类
+* 修正分页参数
+* 改进默认模板的自动识别
+* 改进Query类查询
+* Collection类改进
+* 改进模型类`readTransform`方法对序列化类型的处理
+* 改进trace显示
+* 文件日志支持自动清理
+* 改进断线重连的判断
+* 改进验证方法
+* 修正Query类view方法的数组表名定义
+* 改进参数绑定
+* 改进文件缓存的并发删除
+* 改进`inc/dec/exp`更新的安全性
+* 增加控制台配置
+
+## 2018-1-31 V5.0.15
+
+该版本主要进行了一些修正和完善
+
+* 改进View类
+* 改进chunk方法
+* 改进模板引擎的表达式语法
+* 改进自关联查询多级调用问题
+* 关联定义增加`selfRelation`方法用于设置是否自关联
+* 改进file类型的缓存`inc`和`dec`方法不改变缓存有效期
+* 改进软删除 支持设置`deleteTime`属性关闭
+* 改进`union`查询
+* 改进查询缓存
+* 优化File缓存自动生成空目录的问题
+* 改进日志写入并发问题
+* 修正`MorphTo`关联
+* 改进`join`自关联查询
+* 改进`case`标签解析
+* 改进Url类对`url_convert`配置的支持
+
+
+## 2018-1-1 V5.0.14
+
+V5.0.14版本主对复合主键进行了更多支持,改进了PHP7的兼容性,并且对数据库的一些问题做了改进。
+
+主要更新如下:
+
+* 改进Validate类的unique验证
+* Validate类增加checkRule方法用于静态验证多个规则
+* 改进多对多关联的save方法
+* 改进多对多的pivot对象
+* 修正setDec方法的延迟写入
+* max和min方法增加第二个参数用于设置是否强制转换数字
+* 改进View类
+* 改进join关联自身的问题
+* 改进union查询
+* 改进Url类
+* 改进同名路由不同请求的注册
+* 改进Builder类parseData对空数组的判断
+* 改进模板替换
+* 调整BelongsTo的hasWhere方法
+* 改进模板的编译缓存命名规则 增加布局模板的标识
+* 改进insertall方法
+* 改进chunk方法支持复合主键
+* 改进Error类的一个兼容问题
+* 改进model类的save方法的复合主键包含自增的情况
+* save方法改进复合主键的支持
+* 改进mysql的insertAll方法
+* 改进redis长连接多编号库的情况
+
+## 2017-12-12 V5.0.13
+
+`V5.0.13`主要是对模型和日志方面做了一些改进
+
+### [数据库和模型]
+
+* 改进Model类`save`方法对`oracle`的支持
+* 改进中间表模型的实例化
+* 改进`Pivot`类
+* 模型`saveall`方法支持配合`isUpdate`方法
+* 模型类增加`force`方法设置是否强制更新所有数据
+* 关联自动删除增加一对多关联删除支持
+* 改进`hasWhere`查询的数据重复问题
+* 改进一对多`with`关联查询的`field`支持
+* 模型`saveall`方法支持返回数据集 读取`resultSetType`属性
+* 改进废弃字段判断
+* 模型的`hasWhere`方法增加`fields`参数
+* 改进断线重连异常捕获机制
+* 修正Query类的`inc`和`dec`方法的Mysql关键词问题
+* 修正数据集对象的BUG
+
+### [其它]
+
+* 增加`app_dispatch`钩子位置
+* cookie类`httponly`参数默认改为false
+* File日志驱动增加`single`参数配置是否记录单个文件日志
+* 单个日志文件支持大小设置
+* 改进日志记录的ip地址
+* Redis缓存驱动改用`serialize`序列化替代json序列化
+* 改进异常捕获
+* 改进上传文件验证
+* 修正redis驱动
+* 改进File缓存的`clear`方法
+* 代码格式化规范
+* 改进一处PHP7.2的兼容问题
+* 调试模式下不读取字段缓存文件
+* `default_filter`支持在模块中配置生效
+
+## 2017-11-06 V5.0.12
+
+5.0.12是一个修正版本,包含了上个版本发布以来的一些修正和完善,主要包括:
+
+* 上传类和验证类的多语言支持;
+* 模型增加排除和废弃字段支持;
+* 改进insertAll方法的分批处理;
+* 改进对枚举类型的参数绑定支持;
+* 修正社区反馈的问题;
+
+
+### [数据库和模型]
+
+* 改进Connection类的getRealSql方法
+* 改进append方法支持一对一关联的bind设置
+* 改进whereTime查询
+* 改进model类的`destroy`方法
+* 修正softdelete
+* 修正`chunk`方法对时间字段的支持
+* Collection类增加`push`方法
+* 改进alias方法 
+* 修正模型类的`append`处理
+* 改进`appendRelationAttr`方法
+* 改进HasManyThrough关联
+* 改进MorphTo关联
+* 模型增加废除字段`disuse`定义
+* 增加排除字段方法`except`
+* 修正`has`方法 
+* 改进参数绑定类型对枚举类型的支持
+* 改进`insertAll`方法的分批处理
+
+
+### [其它]
+
+* 改进Loader类`controller`和`validate`方法支持多层
+* 验证提示信息支持多语言
+* File类错误信息支持多语言 
+* 模板渲染异常处理
+* 修正rest控制器
+* 改进trace驱动
+* 改进Cache类的`remember`方法 
+* 改进`url_common_param`的情况下urlencode的问题
+* 改进Url类
+* 改进`exception_handle`配置参数对闭包的支持 
+* 执行路由缓存命令前检测RUNTIME_PATH是否存在 
+* 调整部分`CacheDriver::dec`在为空的时候递减的行为
+* 优化移动端的显示
+* 改进对JSON-Handle插件的支持
+* 改进redis的`get`方法
+* 改进Request类的`host`方法
+
+
+## 2017-09-08 V5.0.11
+
+5.0.11是一个安全及修正版本,包含了上个版本发布以来的一些修正和完善,更新了几处可能的安全问题,主要包括:
+
+* 完善缓存驱动;
+* 改进数据库查询;
+* 改进URL生成类;
+* 缓存有效期支持指定过期时间;
+
+### [数据库和模型]
+
+* 改进数据库驱动类
+* 改进`group`方法的字段关键字冲突
+* 修正聚合查询返回null的问题
+* 改进Db类的强制重连
+* 改进关联的属性绑定
+* 修正事务的断线重连
+* 修正对象的条件查询
+* Db类增加`clear`方法
+* 改进数组查询条件中的`null`查询
+* 改进Query类的`chunk`方法支持排序设置
+* 改进HasOne和HasMany关联的`has`方法
+* 改进软删除的关联删除
+* 改进一个字段多次查询条件
+
+### [其它]
+
+* 缓存有效期支持指定过期时间(`DateTime`);
+* 改进Url生成对端口号的支持
+* 改进`RouteNotFound`异常提示
+* 改进路由分组的全局完整路由匹配
+* 修正部分验证规则的错误提示问题
+* 支持数据集和模型的XML响应输出
+* 改进模板的三元运算标签
+* 改进控制器不存在的错误提示
+* input助手函数支持`route`变量获取
+* 支持在配置文件中读取额外配置参数
+* 完善分页类
+* 修复Trait命名空间重复问题
+* 修正Request类的env方法
+* 优先使用Cookie中的多语言设置
+* 获取缓存标签的时候过滤无效的缓存标识
+* 修正路由批量注册的一个BUG
+* `exception_handle`配置参数支持使用闭包定义`render`处理
+* 请求缓存支持缓存标签设置
+* 缓存类`remember`方法增加并发锁定机制
+* 改进上传类对`swf`的支持
+* 改进Session类的`prefix`方法
+
+## 2017-07-04 V5.0.10
+
+5.0.10是一个修正版本,并包含了一个安全更新,推荐更新,主要包含:
+
+* 数据库和模型的多处改进
+* 添加新的行为监听
+* 路由支持Response设置
+* 改进调试模式下数据库敏感信息暴露
+
+### [数据库和模型]
+
+* 修正join其他表时生成的delete语句错误
+* 修正远程一对多
+* insertall支持replace
+* 修正多对多默认的中间表获取
+* 改进更新后的模型`update_time`数据更新
+* model类增加`removeRelation`方法
+* 模型类增加`setInc`和`setDec`方法
+* 模型类增加`autoWriteTimestamp`方法动态设置时间字段写入
+* 改进驱动类方法的断线重连判断
+* 改进多对多的数据更新
+* 改进BelongsToMany关联查询
+* 修正Query类的value和column方法
+* 改进in查询的去重问题
+* 修正模型类的scope方法传值问题
+* 调整模型的save方法`before_update`检查位置
+* 修改器和获取器方法支持第三个关联数据参数
+
+### [其它]
+
+* 默认关闭调试模式
+* 修复配置extra目录临时文件的错误加载
+* 添加log存储完成行为监听 `log_write_done`
+* 改进Build类生成公共文件的目录判断
+* 增加`response_send`行为监听 
+* 路由增加response参数用于绑定response处理行为
+* 改进redirect的参数传入
+* 改进环境变量的布尔值读取
+* 改进Url类的域名传入
+* 修正命令行文件生成
+* 改进命令行下面的URL生成
+* 添加`app_host`参数设置默认的URL根地址
+* 改进`Request`类`isSsl`方法判断支持CDN
+* 增加`record_trace`配置参数用于日志记录trace信息
+
+## 2017-05-20 V5.0.9
+
+5.0.9是一个修正版本,推荐更新,主要更新包含:
+
+### [数据库和模型]
+
+* 修正关联自动写入
+* 修正模型数据变化判断对为空数据的支持
+* 修正Query类的useSoftDelete方法返回值
+* 修正一对一嵌套关联数组定义的问题
+* 修正使用了手动参数绑定的时候的缓存BUG
+* 改进数据库类的一处不能嵌套查询的缺陷
+* 改进数据库断线重连判断
+* 改进模型的appendRelationAttr方法
+* 改进模型类destroy方法传入空数组的时候不进行任何删除操作
+* 改进一对多关联数据的输出
+* 改进模型的save方法对allowField方法的支持
+* 改进分页类的toarray方法 增加总页数
+* 比较运算增加闭包子查询支持
+* db助手函数默认不再强制重新连接
+* 改进belongsToMany的查询字段指定
+* 分页类增加each方法
+
+### [其它]
+
+* 修正路由分组的路由规则大小写识别问题
+* 修正命令行的日志切割生成
+* 修复URL生成时路由规则中的参数没有进行 urlencode
+* 改进Request类的filter过滤机制 支持正则
+* 改进Response类支持手动设置contentType
+* 修正异常模板中助手函数未定义错误
+
+## 2017-04-28 V5.0.8
+
+### 主要调整
+
+* 改进关联模型
+* 改进日志记录
+* 增加多态一对一关联
+* 修正社区反馈的一些BUG
+
+### [ 请求和路由 ]
+
+* 修正Request类`cookie`方法对前缀的支持
+* 改进全局请求缓存的缓存标识
+* 改进Request类`param`方法
+* 修正别名路由
+
+### [ 模型和数据库 ]
+
+* 改进模型数据的更新检查
+* 改进Query类的`column`方法
+* 改进软删除条件在使用闭包查询情况下多次生成的问题
+* belongsToMany增加数据同步方法
+* 查询范围支持静态调用
+* 增加多态一对一(MorphOne)关联
+* 改进BelongsTo关联
+* 改进多态关联支持关联数据添加和注销
+* 改进多对多关联,支持中间表模型自定义 并且定义的时候不需要使用完整表名
+* 改进浮点数类型转换避免出现逗号
+* 调整关联模型的save方法返回值
+* 模型类的get方法第一个参数必须 如果传入null则返回null
+* model的save方法改进如果数据没有更新不执行
+* Query增加`useSoftDelete`方法可以单独设置软删除条件
+* 重载BelongsToMany的`selectOrFail`和`findOrFail`方法
+* 重载BelongsToMany的`select` 、`find`和 `paginate`方法
+* 增加模型和`Pivot`对象的`parent`属性
+* 多对多关联支持设置中间表模型
+* 改进Query类的`view`方法中字段的关键字问题
+* 主从数据库的时候开启事务始终操作主库
+
+### [ 其它 ]
+
+* 改进Cookie类的`get`方法支持获取全部
+* `schema`指令增加`config`参数,支持传入数据库连接配置
+* 改进cache类的`store`方法为当次有效
+* 修正cache助手函数对`option`传参的支持
+* 修复`optimize:autoload`命令在`EXTEND_PATH`目录不存在的情况下,类库映射生成错误问题
+* 支持自定义的根命名空间也可以生成类库映射缓存
+* 验证字段比较支持对比其他字段
+* 修复`Session::prefix('xxx');`设置当前作用域BUG
+* 改进`optimize::schema`指令
+* 修复`clear`指令无法删除多级目录下文件的问题
+* 改进默认语言读取和自动侦测
+* 改进日志记录格式 并且命令行下面日志改为实时写入
+* 修正模板标签默认值某些情况无效bug
+* 改进Url生成对完整域名的支持
+* 改进`Clear`指令不删除`.gitignore` 文件
+* 修复Memcache缓存驱动的`inc`方法
+
+### 调整
+
+* 如果自定义了应用的命名空间的话,原来的`app_namespace`配置参数改为`APP_NAMESPACE`常量在入口文件中定义
+* 多对多关联的中间表名称不需要添加表前缀
+* 模型的scope方法之后只能使用数据库查询方法而不能使用模型的方法
+
+## 2017-02-24 V5.0.7
+
+### 主要调整
+
+本次更新主要为BUG修正和改进,主要改进如下:
+
+* 改进全局请求缓存对子域名的支持;
+* 改进数据缓存自动更新机制;
+* 关联统计支持指定统计属性名;
+* 模型嵌套关联支持数组方式;
+* HasOne关联支持`has`和`hasWhere`方法;
+* 路由的`ext`和`deny_ext`参数允许设置为空(表示不允许任何后缀或者必须使用后缀访问);
+
+### 修正如下
+
+* 修正 IN / NOT IN 型查询条件为空导致的 sql 语法错误
+* 修正分页类的`toArray`方法对简洁模式的支持
+* 修正Model类`delete`方法对多主键的处理
+* 修正软删除对`Mongodb`的支持
+* 修正`Connection`类一处可能的错误
+* 改进Query类的find方法的缓存机制
+* 修正BelongsTo关联
+* 修正JOIN方式一对一关联预载入闭包查询
+* 修正Query类的`insert`方法一处可能存在的警告错误
+* 修正Model类一处Collection的`use`冲突
+* 修正Model类`hasWhere`方法
+* 修正URl生成对`ext`参数的支持
+* 文件缓存`clear`方法会删除空目录
+* 修正Route类的`parseUrlPath`方法一处问题
+
+### 调整如下
+
+* 默认关闭session的安全参数`secure`,此选项仅能在HTTPS下设置开启
+
+## 2017-02-07 V5.0.6
+
+### 主要调整:
+
+本次更新主要为BUG修正及优化(可无缝升级):
+
+* 数据库支持断线重连机制;
+* 改进查询事件的回调参数;
+* 改进数据自动缓存机制;
+* 增加时间字段自动格式转换设置;
+* `MongoDb`和`Oracle`扩展更新至最新核心框架;
+
+### [数据库和模型]
+
+* 修正hasMany关联的`has`方法
+* 去除一些数据库惯例配置 避免使用数据库扩展的时候影响
+* 改进多对多的`attach`方法的返回值
+* 增加Mysql的断线重连机制和开关
+* 改进Query类的`find`方法数据缓存机制
+* 改进Query类查询事件的回调参数
+* 改进Query类的自动缓存更新
+* Model类增加`readonly`方法
+* 改进Model类的`has`和`hasWhere`方法
+* 改进模型类的`get`和`all`方法 第二个参数为true或者数字表示缓存参数
+* 修复闭包查询条件为空导致的 sql 语法错误
+* 改进Query类的`setBuilder`方法 避免因自定义连接器类后找不到生成器类
+* 删除Connection类废弃属性`resultSetType`
+* 优化Connection类`close`方法
+* 修正Connection类的`bindParam`方法对存储过程的支持
+* 数据库配置参数`datetime_format` 设置为`false`表示关闭时间字段自动转换输出
+* 改进软删除的数据库兼容性问题 支持`Mongodb`
+
+### [其它]
+
+* 改进Url类生成 `root`为`/`的情况
+* redirect助手函数和controller类的redirect方法增加with参数
+* 全局请求缓存添加排除规则 添加request_cache_except配置参数
+* Cache类store方法参数允许为空 表示获取当前缓存驱动句柄
+* 改进Validate类的ip验证规则
+
+## 2017-01-23 V5.0.5
+### 主要调整:
+
+本次更新主要改进了数据访问层和模型关联:
+
+* 增加快捷查询及设置方法;
+* 增加关联统计功能;
+* 增加关联查询延迟预载入功能;
+* 增加关联一对一自动写入和删除;
+* 改进存储过程查询;
+* 改进关联数据输出;
+* 优化查询性能;
+* 模型时间字段自动格式化输出;
+
+### [请求和路由]
+
+* 改进路由定义的后缀检测
+* Route类的`rest`方法支持覆盖定义
+* 改进Request类的`put`和`post`方法对`json`格式参数的接收
+* Request类增加`contentType`方法
+* 改进Route类`setRule`方法 
+* 改进Request类的`create`方法
+* 改进路由到控制器类的方法对默认渲染模板的影响
+* 修正Url类`build`方法定义路由别名后的BUG
+
+### [数据库和模型]
+
+* 增加关联统计功能
+* 增加一对一关联自动写入功能
+* 修正聚合模型的`delete`方法
+* 改进Model类的`useGlobalScope`方法
+* Model类的日期类型支持设置为类名
+* Query类增加`data`/`inc`/`dec`/`exp`方法用于快捷设置数据 `insert`和`update`方法参数可以为空 读取`data`设置数据
+* 优化Connection的查询性能
+* 修正Builder类的`parseOrder`方法
+* 修正BelongsToMany类的`attach`方法
+* BelongsToMany类的`attach`方法改进 支持批量写入
+* 改进BelongsToMany类的`saveall`方法 增加第三个参数 用于指定额外参数是否一致
+* Query类的`order`方法支持多次调用合并
+* 改进`count`方法对`group`查询的支持
+* 增加时间戳自动写入的判断
+* 改进Model类`writeTransform`方法
+* 改进Model的时间戳字段写入和读取
+* 写入数据为对象的时候检测是否有`__toString`方法
+* 改进Mysql驱动的`getFields`方法
+* 改进自动时间字段的输出
+* `like`查询条件支持数组
+* 自动时间字段的获取自动使用时间格式化
+* 改进单个字段多次Or查询情况的查询
+* 修正`null`查询的条件合并
+* 改进Query类`paginate`方法第一个参数可以使用数组参数
+* 改进数据集对象的返回,由Query类的select方法进行数据集转换,原生查询不再支持返回数据集对象
+* 增加`whereNull`、`whereIn`等一系列快捷查询方法
+* `fetchPdo`方法调整
+* 改进对存储过程调用的支持 改进`getRealSql`的调用机制 改进数据表字段使用中划线的参数绑定支持
+* 数据库配置参数增加`result_type` 用于设置数据返回类型 方法参数名称调整
+* 改进Query类的`whereTime`方法支持更多的时间日期表达式(默认查询条件为大于指定时间表达式)
+* 取消`min`/`max`/`sum`/`avg`方法的参数默认值
+* Query类增加`getPdo`方法用于返回`PDOStatement`对象
+* 改进`today`的日期表达式查询
+* 改进关联属性的获取
+* 改进关联定义中包含查询条件后重复执行的问题
+* 改进参数绑定支持中文字段自动绑定
+* 改进Builder类的`insertall`方法 增加对null和对象数据的处理
+* 改进参数绑定类型 支持`bit`类型自动绑定
+* Connection类`model`方法更改为`getQuery`
+* 优化Connection类`__call`方法
+* 修正聚合模型
+* 一对一关联预载入默认改为IN查询方式
+* 增加`collection`助手函数用于数据集转换
+* 增加`load_relation`助手函数用于数组的延迟预载入
+* 改进Model类的`has`方法第二个参数支持使用数组和闭包,无需再使用`hasWhere`
+* `relation`方法支持嵌套关联查询
+* 增加`think\model\Collection`作为模型的数据集查询集合对象
+* 取消关联定义的`alias`参数(仅`morphTo`保留)
+* Model类的`delete`方法,支持没有主键的情况
+* Model类的`allowField`方法支持逗号分割的字符串
+* 改进写入数据的自动参数绑定的参数名混淆问题
+* 关联预载入查询的属性名默认使用小写+下划线命名
+* Query类的`with`和`relation`方法支持多次调用
+* Collection类增加`hidden`、`visible`和`append`方法
+* 修正软删除的强制删除方法
+
+### [其它]
+
+* `unique`验证规则支持指定完整模型类 并且默认会优先检测模型类是否存在 不存在则检测数据表
+* 改进`Loader`类的`model`、`controller` 和 `validate`方法 支持直接传入类名实例化
+* `Session`类增加安全选项`httponly`和`secure`
+* 可以允许自定义`Output`的driver,以适应命令行模式下调用其它命令行指令 
+* 改进`loader`类`action`的参数污染问题
+* Validate类的`confirm`验证改为恒等判断
+* 改进`Validate`类的错误信息处理
+* 修正`Validate`类的布尔值规则验证
+* 改进`cookie`助手函数对前缀的支持
+* 文件缓存默认开启子目录缓存避免文件过多导致性能问题
+
+### [调整]
+* Connection类`model`方法更改为`getQuery`
+* 原生查询不再支持返回数据集对象
+* 分页查询返回类型变成`think\Paginator`(用法不变)
+* 模型的时间日期字段会自动进行格式化输出,不需要进行额外处理。
+* Session类添加了`secure`和`httponly`参数,并且默认是true
+
+## 2016-12-20 V5.0.4
+### 主要调整:
+
+* 关联模型重构并增加多态一对多关联;
+* 数据库支持一个字段多次调用不同查询条件;
+* 增加数据库CURD事件支持;
+* 路由到类和控制器的方法支持传入额外参数;
+* 支持全局模板变量赋值;
+* 模型支持独立设置查询数据集对象;
+* 日志针对命令行及调试做出改进;
+* 改进Hook类的行为方法调用
+
+### [请求和路由]
+* 请求缓存支持模块单独开启
+* Request类`post`方法支持获取`json`方式的请求数据
+* 路由到类的方法和控制器方法 支持传入额外参数,用于方法的参数
+* 改进控制器自动搜索的目录规范
+* 改进请求缓存
+* 改进自动参数绑定
+* 修正路由的请求缓存设置
+* 改进Route类name方法
+
+### [数据库和模型]
+* 增加数据库查询(CURD)事件
+* 改进多表更新的字段不存在问题
+* 改进Model类的`useGlobalScope`方法
+* 修正子查询作为表名查询的问题
+* Model类增加`resultSetType`属性 用于指定模型查询的数据集对象(默认为空返回数组) 
+* Model类增加`toCollection`方法(自动调用)
+* 关联模型架构调整
+* 改进预载入`with`方法的参数支持小写和下划线定义
+* 修正关联多对多一处错误
+* 改进关联多对多的查询
+* 关联模型支持多态一对多关联
+* 预载入关联查询支持关联对象属性绑定到当前模型
+* 支持追加关联对象的属性到当前模型数据
+* 一对一关联预载入支持JOIN和IN两种方式(默认为JOIN)
+* 改进多对多查询
+* 改进模型更新的数据变化比较规则
+* 查询支持一个字段多次查询条件
+* 改进sql日志的sql语句
+* 修正`join`自身表的别名覆盖问题
+* 模型类的`connection`属性和数据库默认配置合并
+* 改进`in`和`between`查询条件的自动参数绑定
+* 改进Query类对数据集对象以及关联字段排序的支持
+* 增加模型的快捷事件方法
+* 改进Query类的`getTableInfo`方法缓存读取
+* model类的`saveAll`方法支持调用`allowField`方法进行字段过滤
+* 修正关联查询的时候 `whereTime`方法的bug
+* 改进Query类的聚合查询
+* table方法支持字符串方式的子查询
+* 修正`count` `avg`方法使用`fetchsql`无法正确返回sql的问题
+
+### [其它]
+* 改进命令行下的日志记录
+* 部署模式下简化日志记录
+* 增加debug日志类型 仅限调试模式记录
+* 改进Template类`parseTemplateFile`方法
+* 改进Validate类的`getRuleMsg`方法
+* 控制器的`error`方法在AJAX请求默认返回url为空
+* Validate类架构方法增加`field`参数 用于设置验证字段的描述
+* 改进App类`invokeMethod`方法对架构函数依赖注入的支持
+* 增加RedirectResponse的`restore`方法返回值
+* View类增加`share`静态方法 用于静态赋值模板变量
+* 验证类增加`hasScene`方法判断是否存在某个场景的验证配置
+* 修正redis和session驱动的`destroy`方法返回值
+* 空操作方法的参数传入去掉操作方法后缀
+* 在控制器中调用request和view增加类型提示
+* 改进`input`助手函数支持多维数据获取
+* Cache类增加`pull`和`remember`方法
+* 改进验证类的`confirm`验证规则 支持自动规则识别
+* 改进验证类的错误信息定义
+* 增加Validate类自定义验证错误信息的替换规则
+* Cookie类增加`forever`方法用于永久保存
+* 模板渲染支持从视图根目录读取模板
+* 改进Hook类的exec方法
+
+### [调整]
+* Db类查询不再支持设置自定义数据集对象
+* 废除Query类的`fetchClass`方法
+* 控制器的`error`方法在AJAX请求默认返回的url为空
+* 关联方法定义不支持使用小写下划线,必须使用驼峰法
+* 行为类的方法必须使用驼峰法命名
+
+## 2016-11-11 V5.0.3
+### 主要调整:
+* 请求缓存增强;
+* 路由增强;
+* 数据库和模型完善;
+* 支持反射的异常捕获;
+* File类改进;
+* 修正社区反馈的一些BUG;
+
+### [ 请求和路由 ]
+
+* 资源路由自动注册的路由规则的时候会记录当前使用的资源标识;
+* 增强请求缓存功能和规则定义,支持全局自动缓存
+* 修正控制器自动搜索的大小写问题
+* 修正路由绑定到命名空间后 类的自动定位
+* 改进Route类的parseRule方法 路由地址中的变量替换不自动去除路由变量
+* 改进控制器自动搜索
+* Route类增加setOption和getOption方法 用于记录当前路由执行过程中的参数信息
+* 优化路由分组方法
+* 改进分组路由的url生成
+
+### [ 数据库和模型 ]
+
+* 一对一关联查询方法支持定义`field`方法
+* 聚合模型支持设置`field`属性
+* 改进Query类的`alias`方法
+* 改进Query类`join`和`view`方法的table参数
+* 改进Query类`where`方法
+* 改进Query类的`paginate`方法,支持`order`方法
+* 改进Query类的`min`和`max`方法支持日期类型
+* 修正软删除`withTrashed`方法
+* 优化Connection类的`getRealSql`方法生成的sql
+
+### [ 其它 ]
+* 增加request_cache和request_cache_expire配置参数用于配置全局请求缓存;
+* 修正input助手函数的数组过滤
+* cache助手函数支持清空操作
+* 改进Config类load方法 一级配置名称强制转为小写
+* 修正Url多次生成的问题
+* File类修正某些环境下面无法识别上传文件的问题
+* 改进App类的空操作方法调用
+* 域名部署URL生成不依赖 url_domain_deploy 配置参数
+* 修正Url类域名部署的问题
+* 视图文件目录支持集中式存放 不放入模块目录
+* cache助手函数支持 remember方法
+* Request类的input方法或者input助手函数的`filter`参数支持传入null 表示不过滤
+
+## 2016-10-24 V5.0.2
+### 主要调整:
+
+* 数据库和模型完善;
+* 路由功能完善;
+* 增加`yaml`配置格式支持;
+* 依赖注入完善;
+* Session类完善;
+* Cookie类完善;
+* Validate类完善;
+* 支持反射类的异常捕获;
+* 修正社区反馈BUG;
+
+### [ 请求和路由 ]
+* 依赖注入的类如果定义了`invoke`方法则自动调用
+* Request类的`header`方法增加自定义header支持
+* Request类禁止直接实例化调用
+* 改进Request类ip方法
+* 路由变量规则支持闭包定义
+* 路由参数增加`ajax`和`pjax`判断
+* 别名路由增加允许和排除操作
+* 改进路由域名绑定后的url生成
+* 路由生成改进对路由到类的支持
+* 路由生成支持`url_param_type`配置参数
+* 路由生成支持别名路由
+* Route重定向规则支持更多` schema`
+* 别名路由支持定义单独方法的请求类型
+* 改进路由分组的url生成
+* 路由规则的组合变量支持可选分隔符定义
+* 改进路由合并参数的获取
+* 路由规则支持单独设置url分隔符,路由参数为 `param_depr`
+* 自动搜索控制器支持自定义访问控制器层的情况
+* 改进路由标识不区分大小写
+* 改进路由地址是否定义过路由规则的检测
+
+### [ 数据库和模型 ]
+* 改进Query类的join方法
+* 改进Query类分页方法的参数绑定
+* 修正软删除方法
+* 修正Query类parseOrder方法一处错误
+* 修正sqlsrv驱动parseOrder方法
+* 修正Query类setInc和setDec方法
+* 改进Model类的save方法支持非自增主键的处理
+* 整型字段的参数绑定如果为空写入默认值0
+* 改进Model类has和hasWhere方法
+* 改进Query类的value方法缓存判断
+* 改进Query类join方法对子查询支持
+* 改进Query类的table方法和alias方法用法
+* 关联预载入支持`hasOne`自关联
+* 改进Builder类的parseKey方法
+* 改进Builder类的join/alias/table方法的解析
+* 改进全局查询范围
+* 改进Query类的聚合查询方法的返回值
+* 改进关联属性的读取
+* 改进聚合模型主键和关联键相同的情况
+* 改进模型在开启`class_suffix`参数情况下的name属性的识别
+
+### [ 其它 ]
+* Cache类增加`remember`方法 用于当获取的缓存不存在的时候自动写入
+* Session类增加`flash`方法用于设置下一次请求有效的值 
+* Session类增加`flush`方法用于清空当前请求有效的值 
+* Session类增加`push`方法用于更新数组数据
+* 增加yaml配置格式支持
+* 改进App类的反射异常无法捕获问题
+* 修正session助手函数的清空操作
+* 改进验证类的`image`方法
+* 改进验证类的`activeUrl`方法 
+* 改进自定义验证规则的使用
+* 改进控制器自动搜索后的控制器名获取
+* 修正import方法加载extend目录类库
+* 修正json_encode时 "Failed calling XXX::jsonSerialize()" 的异常
+* 改进Loader类model和validate方法的单例问题
+* 改进方法执行的日志记录
+* 改进模板引擎的Think变量解析
+* 改进Lang类`load`方法
+* 验证错误信息支持多语言读取
+* 改进ROOT_PATH常量
+* 改进语言包加载
+* 改进模板session和cookie变量获取,自动判断前缀
+* 缓存驱动统一增加handler方法用于获取操作对象的句柄(某些缓存类型可能为null)
+* File类增加`__call`方法用于兼容5.0版本的`md5`和 `sha1`方法
+* 改进文件缓存驱动的`clear`方法
+* Lang类增加`setLangCookieExpire`方法设置多语言cookie过期时间
+* 增加`route_complete_match`配置参数
+
+### [ 调整 ]
+下列模型属性和方法由原来的静态(static)定义改为动态定义:
+* 聚合模型的`relationModel`属性
+* Model类的`useGlobalScope `属性
+* 全局查询范围方法`base`改为动态方法
+* 软删除属性 `deleteTime`属性
+
+
+## 2016-9-28 V5.0.1
+### 主要调整:
+* [依赖注入](215849)完善;
+* [扩展配置](118027)文件位置调整;
+* 新增数据表[字段缓存命令](211524);
+* 支持设置当前的查询对象;
+* 支持[请求和路由缓存](215850);
+
+### [ 请求和路由 ]
+* 改进Controller类的`success`和`error`方法的跳转地址识别 支持更多Scheme
+* 操作方法和架构方法支持任何对象自动注入
+* Requesst类增加`getInput`方法 用于获取` php://input`值
+* 路由到方法的时候 支持架构方法注入请求对象
+* 改进Route类路由到类的判断
+* Request增加`cache`方法,支持请求缓存
+* 绑定到模块后 路由依然优先检查
+* 路由增加请求缓存参数
+* 修正路由组合变量的可选变量的BUG
+
+### [ 数据库 ]
+* 修正`pgsql`数据库驱动的数据表字段信息读取
+* 改进Query类的`view`方法 第二个参数默认值更改为true 获取全部的字段
+* 数据库配置信息增加`query`参数用于配置查询对象名称
+* 型类增加`query`属性用于配置模型需要的查询对象名称
+* 改进数据表字段缓存读取
+* 改进数据表字段缓存生成 模型为抽象类或者 没有继承Model类 不生成字段缓存
+* 改进模型的字段缓存 虚拟模型不生成字段缓存
+* 改进数据表字段缓存生成 支持读取模块的模型生成
+* 改进聚合模型的`save`方法 主键写入
+* 模型类的field属性定义简化 取消`Query`类的`allowField`和`setFieldType`方法及相关属性
+* 改进数据表字段缓存生成 支持生成多个数据库的
+* 更新数据库驱动类 改进`getTables`方法
+* 增加` optimize:schema` 命令 用于生成数据表字段信息缓存
+* 修正一个查询条件多个条件的时候的参数绑定BUG
+* 分页查询方法`paginate`第二个参数传入数字表示总记录数
+* 修正mysql的`JSON`字段查询
+* 改进Query类的getOptions方法 当name参数不存在的时候返回null
+
+### [ 模型和关联 ]
+* 模型类的field属性不需要添加字段类型定义
+* 改进Model类 添加`getDb`静态方法获取db查询对象
+* 改进聚合模型`save`方法返回值
+* 改进Relation类`save`方法
+* 修正关联模型 多对多`save`方法一处问题
+* 改进Model类的save方法 修正不按主键查询的更新问题
+* 时间字段获取器获取的时候为NULL则不做转换
+
+### [ 其它 ]
+
+* 改进配置缓存生成 支持扩展配置
+* 取消`extra_config_list`配置参数 扩展配置文件直接放到 `extra`目录下面即可自动加载(数据库配置文件位置不变)
+* cache助手函数支持判断缓存是否有效
+* 修正 模板引擎驱动类的`config`方法
+* 修复在配置Model属性field=true情况下,通过`__call`调用db()引发的BUG
+* 改进模板引擎驱动的config方法 支持获取配置参数值
+* 改进redirct的url地址解析
+* 删除`File`类的`md5`和`sha1`方法 改为`hash`方法 支持更多的散列值类型生成
+* 增加`response_end`行为标签
+* 改进默认语言的加载
+
+## 2016-9-15 V5.0
+
+### [ 请求和路由 ]
+
+* Request对象支持动态绑定属性
+* 定义了路由规则的URL原地址禁止访问
+* 改进路由规则存储结构
+* 路由分组功能增强,支持嵌套和虚拟分组
+* 路由URL高效反解
+* 改进Request对象param方法获取优先级
+* 路由增加name方法设置和获取路由标识
+* 增加MISS和AUTO路由规则
+* Route类增加auto方法 支持注册一个自动解析URL的路由
+* 路由规则支持模型绑定
+* 路由变量统一使用param方法获取
+* 路由规则标识功能和自动标识
+* 增加生成路由缓存指令 optimize:route
+* Request对象增加route方法单独获取路由变量
+* Request对象的param get post put request delete server cookie env方法的第一个参数传入false 则表示获取原始数据 不进行过滤
+* 改进自动路由标识生成 支持不同的路由规则 指向同一个路由标识,改进Url自动生成对路由标识的支持
+* 改进Request类 filter属性的初始化
+* 改进Request类的isAjax和isPjax方法
+* Request类增加token方法
+* 路由配置文件支持多个 使用 route_config_file 配置参数配置
+* 域名绑定支持https检测
+* 改进域名绑定 支持同时绑定模块和其他 支持绑定到数组定义的路由规则,取消域名绑定到分组
+* 路由规则增加PATCH请求类型支持
+* 增加route_complete_match配置参数设置全局路由规则定义是否采用完整匹配 可以由路由规则的参数complete_match 进行覆盖
+* 改进路由的 后缀参数识别 优先于系统的伪静态后缀参数
+* Url类增加root方法用于指定当前root地址(不含域名)
+* 改进Url生成对可选参数的支持
+
+### [ 数据库 ]
+
+* 查询条件自动参数绑定
+* 改进分页方法支持参数绑定
+* Query类的cache方法增加缓存标签参数
+* Query类的update和delete方法支持调用cache方法 会自动清除指定key的缓存 配合查询方法的cache方法一起使用 
+* 改进Query类的延迟写入方法
+* Query类的column和value方法支持fetchsql
+* 改进日期查询方法
+* 改进存储过程方法exec的支持
+* 改进Connection类的getLastInsID方法获取
+* 记录数据库的连接日志(连接时间和DSN)
+* 改进Query类的select方法的返回结果集判断  
+* Connection类增加getNumRows方法
+* 数据库事务方法取消返回值
+* 改进Query类的chunk方法对主键的获取
+* 改进当数据库驱动类型使用完整命名空间的时候 Query类的builder方法的问题
+
+### [ 模型 ]
+
+* 增加软删除功能
+* 关联模型和预载入改进
+* 关联预载入查询闭包支持更多的连贯操作
+* 完善savell方法支持更新和验证
+* 关联定义统一返回Relation类
+* Model类的has和hasWhere方法对join类型的支持
+* Model类的data方法 批量赋值数据的时候 清空原始数据
+* Model类的get方法第三个参数传入true的时候会自动更新缓存
+* Model类增加只读字段支持
+* Model类增加useGlobalScope方法设置是否启用全局查询范围
+* Model类的base方法改为静态定义 全局多次调用有效
+* Model类支持设定主键、字段信息和字段类型,不依赖自动获取,提高性能
+* Model类的data方法 支持修改器
+* 改进Relation类对非数字类型主键的支持
+* 改进Relation类的一对多删除
+* 修正Relation类的一对多关联预载入查询
+
+### [ 日志和缓存 ]
+
+* 支持日志类型分离存储
+* 日志允许设置记录级别
+* 增加缓存标签功能
+* 缓存类增加pull方法用于获取并删除
+* cache助手函数增加tag参数
+* 简化日志信息,隐藏数据库密码
+* 增加cache/session redis驱动的库选择逻辑;
+* memcached驱动的配置参数支持option参数
+* 调试模式下面 日志记录增加页面的header和param参数记录
+* memcached缓存驱动增加连接账号密码参数
+* 缓存支持设置complex类型 支持配置多种缓存并用store切换
+* 缓存类增加tag方法 用于缓存标签设置 clear方法支持清除某个缓存标签的数据
+* File类型日志驱动支持设置单独文件记录不同的日志级别
+* 改进文件缓存和日志的存储文件名命名规范
+* 缓存类增加inc和dec方法 针对数值型数据提供自增和自减操作
+* Cache类增加has方法 get方法支持默认值
+
+### [ 其它 ]
+
+* 视图类支持设置模板引擎参数
+* 增加表单令牌生成和验证
+* 增加中文验证规则
+* 增加image和文件相关验证规则
+* 重定向Response对象支持with方法隐含传参
+* 改进Session类自动初始化
+* session类增加pull方法用于获取并删除
+* 增加Env类用于获取环境变量
+* Request类get/post/put等更改赋值后param方法依然有效
+* 改进Jump跳转地址支持Url::build 解析
+* 优化Hook类
+* 应用调试模式和页面trace支持环境变量设置
+* config助手函数支持 config('?name') 用法
+* 支持使用BIND_MODULE常量的方式绑定模块
+* 入口文件自动绑定模块功能
+* 改进验证异常类的错误信息和模板输出,支持批量验证的错误信息抛出
+* 完善console 增加output一些常用的方法
+* 增加token助手函数 用于在页面快速显示令牌
+* 增加halt方法用于变量调试并中断输出
+* 改进Validate类的number验证规则 和 integer区分开
+* optimize:autoload增加对extend扩展目录的扫描
+* 改进Validate类的boolean验证规则 支持表单数据
+* 改进cookie助手函数支持 判断是否存在某个cookie值
+* 改进abort助手函数 支持抛出HttpResponseException异常
+* 改进File类增加对上传错误的处理
+* 改进File类move方法的返回对象增加上传表单信息,增加获取文件散列值的方法
+* 改进File类的move方法的返回对象改为返回File对象实例
+* 增加clear和optimize:config 指令
+* 改进File类和Validate类的图像文件类型验证
+* 控制器的操作方法支持注入Request之外的对象实例
+* Request类 param(true) 支持获取带文件的数据
+* input助手函数第一个参数增加默认值
+* Validate类增加image验证规则 并改进max min length支持多种数据类型
+* json输出时数据编码失败后抛出异常
+
+### [ 调整 ]
+* 废除路由映射(静态路由)定义
+* 取消url_deny_suffix配置 改由路由的deny_ext参数设置
+* 模型save方法返回值改为影响的记录数,取消getId参数
+* Request对象controller方法返回驼峰控制器名
+* 控制器前置操作方法不存在则抛出异常
+* Loader类db方法增加name标识参数
+* db助手函数增加第三个参数用于指定连接标识
+* Sqlsrv驱动默认不对数据表字段进行小写转换
+* 移除sae驱动 改为扩展包
+* Oracle驱动移出核心包
+* Firebird驱动移出核心包
+* 取消别名定义文件alias.php
+* 配置参数读取的时候取消环境变量判断 需要读取环境变量的时候使用Env类
+* 环境变量定义文件更改为 .env 由原来的PHP数组改为ini格式定义(支持数组方式)
+* 状态配置和扩展配置的加载顺序调整 便于状态配置文件中可以更改扩展配置的参数
+* 取消域名绑定到路由分组功能
+* 控制器类的success和error方法url参数支持传入空字符串,则不做任何处理
+* 控制器的error success result redirect方法均不需要使用return
+* 创建目录的权限修改为0644
+
+
+## 2016-7-1 RC4版本
+### [ 底层架构 ]
+* 增加Request类 并支持自动注入
+* 统一Composer的自动加载机制
+* 增加Response类的子类扩展
+* 增加File类用于上传和文件操作
+* 取消模式扩展 SAE支持降权
+* 优化框架入口文件
+* 改进异常机制
+* App类输入/输出调整
+* 单元测试的完美支持
+* 增加新的控制台指令
+* 取消系统路径之外的大部分常量定义
+* 类库映射文件由命令行动态生成 包含应用类库
+
+### [ 数据库 ]
+
+* 增加分表规则方法
+* 增加日期和时间表达式查询方法
+* 增加分页查询方法
+* 增加视图查询方法
+* 默认保持数据表字段大小写
+* 数据缓存自动更新机制
+* 完善事务嵌套支持
+* 改进存储过程数据读取
+* 支持设置数据库查询数据集返回类型
+
+### [ 模型 ]
+* 增加Merge扩展模型
+* 模型支持动态查询
+* 增加更多的类型自动转换支持
+* 增加全局查询范围
+* toJson/toArray支持隐藏和增加属性输出
+* 增加远程一对多关联
+
+### [ 其它 ]
+* 日志存储结构调整
+* Trace调试功能从日志类独立并增强
+* 原Input类功能并入Request类
+* 类库映射文件采用命令行生成 包含应用类库
+* 验证类的check方法data数据取消引用传参
+* 路由增加MISS路由规则
+* 路由增加路由别名功能
+
+## 2016-4-23 RC3版本
+### [ 底层架构 ]
+* 框架核心仓库和应用仓库分离 便于composer独立更新
+* 数据库类重构,拆分为Connection(连接器)/Query(查询器)/Builder(SQL生成器)
+* 模型类重构,更加对象化
+
+### [ 数据库 ]
+
+* 新的查询语法
+* 闭包查询和闭包事务
+* Query对象查询
+* 数据分批处理
+* 数据库SQL执行监听
+
+### [ 模型 ]
+* 对象化操作
+* 支持静态调用(查询)
+* 支持读取器/修改器
+* 时间戳字段
+* 对象/数组访问
+* JSON序列化
+* 事件触发
+* 命名范围
+* 类型自动转换
+* 数据验证和完成
+* 关联查询/写入
+* 关联预载入
+
+### [ 其它更新 ]
+* 路由类增加快速路由支持
+* 验证Validate类重构
+* Build类增加快速创建模块的方法
+* Url生成类改进
+* Validate类改进
+* View类及模板引擎驱动设计改进
+* 取消模板引擎的模板主题设计
+* 修正社区反馈的一些问题
+* 助手函数重新命名
+* `router.php`文件位置移动
+
+## 2016-3-11 RC2版本
+
+* 重新设计的自动验证和自动完成机制(原有自动验证和完成支持采用traits\model\Auto兼容);
+* 验证类Validate独立设计;
+* 自动生成功能交给Console完成;
+* 对数据表字段大小写的处理;
+* 改进Controller类(取消traits\contorller\View);
+* 改进Input类;
+* 改进Url类;
+* 改进Cookie类;
+* 优化Loader类;
+* 优化Route类;
+* 优化Template类;
+* Session类自动初始化;
+* 增加traits\model\Bulk模型扩展用于大批量数据写入和更新;
+* 缓存类和日志类增加Test驱动;
+* 对异常机制和错误处理的改进;
+* 增加URL控制器和操作是否自动转换开关;
+* 支持类名后缀设置;
+* 取消操作绑定到类的功能;
+* 取消use_db_switch参数设计;
+
+## 2016-1-30 RC1版本
+### [ 底层架构 ]
+
+*   真正的惰性加载
+*   核心类库组件化
+*   框架引导文件
+*   完善的类库自动加载(支持Composer)
+*   采用Traits扩展
+*   API友好(输出、异常和调试)
+*   文件命名规范调整
+
+### [ 调试和异常 ]
+
+*   专为API开发而设计的输出、调试和异常处理
+*   日志类支持本地文件/SAE/页面Trace/SocketLog输出,可以实现远程浏览器插件调试
+*   内置trace方法直接远程调试
+*   异常预警通知驱动设计
+*   数据库SQL性能分析支持
+
+### [ 路由 ]
+
+*   动态注册路由
+*   自定义路由检测方法
+*   路由分组功能
+*   规则路由中的变量支持采用正则规则定义(包括全局和局部)
+*   闭包路由
+*   支持路由到多层控制器
+
+### [ 控制器 ]
+
+*   控制器类无需继承controller类
+*   灵活的多层控制器支持
+*   可以Traits引入高级控制器功能
+*   rest/yar/rpc/hprose/jsonrpc控制器扩展
+*   前置操作方法支持排除和指定操作
+
+
+### [ 模型 ]
+
+*   简化的核心模型
+*   Traits引入高级模型/视图模型/关联模型
+*   主从分布时候主数据库读操作支持
+*   改进的join方法和order方法
+
+### [ 视图 ]
+
+*   视图解析驱动设计(模板引擎)
+*   所有方法不再直接输出而是返回交由系统统一输出处理
+*   动态切换模板主题设计
+*   动态切换模板引擎设计
+
+### [ 数据库 ]
+
+*   完全基于PDO实现
+*   简化的数据库驱动设计
+*   SQL性能监控(需要开启数据库调试模式)
+*   PDO参数绑定改进
+
+### [ 其他方面 ]
+
+*   目录和MVC文件自动生成支持
+*   I函数默认添加变量修饰符为/s
+*   一个行为类里面支持为多个标签位定义不同的方法
+*   更多的社交扩展类库

+ 32 - 0
LICENSE.txt

@@ -0,0 +1,32 @@
+
+ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
+版权所有Copyright © 2006-2017 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.

+ 133 - 0
README.md

@@ -0,0 +1,133 @@
+ThinkPHP 5.0
+===============
+
+[![Total Downloads](https://poser.pugx.org/topthink/think/downloads)](https://packagist.org/packages/topthink/think)
+[![Latest Stable Version](https://poser.pugx.org/topthink/think/v/stable)](https://packagist.org/packages/topthink/think)
+[![Latest Unstable Version](https://poser.pugx.org/topthink/think/v/unstable)](https://packagist.org/packages/topthink/think)
+[![License](https://poser.pugx.org/topthink/think/license)](https://packagist.org/packages/topthink/think)
+
+ThinkPHP5在保持快速开发和大道至简的核心理念不变的同时,PHP版本要求提升到5.4,对已有的CBD模式做了更深的强化,优化核心,减少依赖,基于全新的架构思想和命名空间实现,是ThinkPHP突破原有框架思路的颠覆之作,其主要特性包括:
+
+ + 基于命名空间和众多PHP新特性
+ + 核心功能组件化
+ + 强化路由功能
+ + 更灵活的控制器
+ + 重构的模型和数据库类
+ + 配置文件可分离
+ + 重写的自动验证和完成
+ + 简化扩展机制
+ + API支持完善
+ + 改进的Log类
+ + 命令行访问支持
+ + REST支持
+ + 引导文件支持
+ + 方便的自动生成定义
+ + 真正惰性加载
+ + 分布式环境支持
+ + 更多的社交类库
+
+> ThinkPHP5的运行环境要求PHP5.4以上。
+
+详细开发文档参考 [ThinkPHP5完全开发手册](http://www.kancloud.cn/manual/thinkphp5)
+
+## 目录结构
+
+初始的目录结构如下:
+
+~~~
+www  WEB部署目录(或者子目录)
+├─application           应用目录
+│  ├─common             公共模块目录(可以更改)
+│  ├─module_name        模块目录
+│  │  ├─config.php      模块配置文件
+│  │  ├─common.php      模块函数文件
+│  │  ├─controller      控制器目录
+│  │  ├─model           模型目录
+│  │  ├─view            视图目录
+│  │  └─ ...            更多类库目录
+│  │
+│  ├─command.php        命令行工具配置文件
+│  ├─common.php         公共函数文件
+│  ├─config.php         公共配置文件
+│  ├─route.php          路由配置文件
+│  ├─tags.php           应用行为扩展定义文件
+│  └─database.php       数据库配置文件
+│
+├─public                WEB目录(对外访问目录)
+│  ├─index.php          入口文件
+│  ├─router.php         快速测试文件
+│  └─.htaccess          用于apache的重写
+│
+├─thinkphp              框架系统目录
+│  ├─lang               语言文件目录
+│  ├─library            框架类库目录
+│  │  ├─think           Think类库包目录
+│  │  └─traits          系统Trait目录
+│  │
+│  ├─tpl                系统模板目录
+│  ├─base.php           基础定义文件
+│  ├─console.php        控制台入口文件
+│  ├─convention.php     框架惯例配置文件
+│  ├─helper.php         助手函数文件
+│  ├─phpunit.xml        phpunit配置文件
+│  └─start.php          框架入口文件
+│
+├─extend                扩展类库目录
+├─runtime               应用的运行时目录(可写,可定制)
+├─vendor                第三方类库目录(Composer依赖库)
+├─build.php             自动生成定义文件(参考)
+├─composer.json         composer 定义文件
+├─LICENSE.txt           授权说明文件
+├─README.md             README 文件
+├─think                 命令行入口文件
+~~~
+
+> router.php用于php自带webserver支持,可用于快速测试
+> 切换到public目录后,启动命令:php -S localhost:8888  router.php
+> 上面的目录结构和名称是可以改变的,这取决于你的入口文件和配置参数。
+
+## 命名规范
+
+`ThinkPHP5`遵循PSR-2命名规范和PSR-4自动加载规范,并且注意如下规范:
+
+### 目录和文件
+
+*   目录不强制规范,驼峰和小写+下划线模式均支持;
+*   类库、函数文件统一以`.php`为后缀;
+*   类的文件名均以命名空间定义,并且命名空间的路径和类库文件所在路径一致;
+*   类名和类文件名保持一致,统一采用驼峰法命名(首字母大写);
+
+### 函数和类、属性命名
+
+*   类的命名采用驼峰法,并且首字母大写,例如 `User`、`UserType`,默认不需要添加后缀,例如`UserController`应该直接命名为`User`;
+*   函数的命名使用小写字母和下划线(小写字母开头)的方式,例如 `get_client_ip`;
+*   方法的命名使用驼峰法,并且首字母小写,例如 `getUserName`;
+*   属性的命名使用驼峰法,并且首字母小写,例如 `tableName`、`instance`;
+*   以双下划线“__”打头的函数或方法作为魔法方法,例如 `__call` 和 `__autoload`;
+
+### 常量和配置
+
+*   常量以大写字母和下划线命名,例如 `APP_PATH`和 `THINK_PATH`;
+*   配置参数以小写字母和下划线命名,例如 `url_route_on` 和`url_convert`;
+
+### 数据表和字段
+
+*   数据表和字段采用小写加下划线方式命名,并注意字段名不要以下划线开头,例如 `think_user` 表和 `user_name`字段,不建议使用驼峰和中文作为数据表字段命名。
+
+## 参与开发
+
+请参阅 [ThinkPHP5 核心框架包](https://github.com/top-think/framework)。
+
+## 版权信息
+
+ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
+
+本项目包含的第三方源码和二进制文件之版权信息另行标注。
+
+版权所有Copyright © 2006-2018 by ThinkPHP (http://thinkphp.cn)
+
+All rights reserved。
+
+ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
+
+更多细节参阅 [LICENSE.txt](LICENSE.txt)

+ 1 - 0
application/.htaccess

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

+ 21 - 0
application/Admin/command/Test.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace app\admin\command;
+use think\console\Command;
+use think\console\Input;
+use think\console\Output;
+use think\Db;
+class Test extends Command
+{
+    protected function configure()
+    {
+        $this->setName('test')->setDescription('Here is the remark ');
+    }
+
+    protected function execute(Input $input, Output $output)
+    {
+        $acocunt =Db::name('Account')->where("is_del=0 and status>=1 and expiretime<='".date("Y-m-d H:i:s")."'")->select();
+        var_dump($acocunt);
+        $output->writeln("AccountExpire:");
+    }
+}

+ 275 - 0
application/Admin/common.php

@@ -0,0 +1,275 @@
+<?php
+use think\Db;
+use think\File;
+
+/**
+ * @param $account
+ * @return string
+ * @throws \think\db\exception\DataNotFoundException
+ * @throws \think\db\exception\DbException
+ * @throws \think\db\exception\ModelNotFoundException
+ * @throws \think\exception\DbException
+ */
+function makeToken($account){
+    $now=time();
+    $str = $account['username'].$account['salt'].$now;
+    $token = base64_encode($str);
+    $has = Db::name("admin_token")->where(["adminid"=>$account['id']])->find();
+    if($has){
+        Db::name("admin_token")->where(["adminid"=>$account['id']])->update(["token"=>$token,"expiretime"=>date("Y-m-d H:i:s",$now+1800)]);
+    }else{
+        Db::name("admin_token")->insert(["token"=>$token,"expiretime"=>date("Y-m-d H:i:s",$now+1800),"addtime"=>date("Y-m-d H:i:s"),
+            "adminid"=>$account['id']]);
+    }
+    return $token;
+}
+
+/**
+ * @param $token
+ */
+function verifyToken($token){
+    $has = Db::name("admin_token")->where(["token"=>$token])->find();
+    if(!$has){
+        return ["code"=>101,"msg"=>"token不存在"];
+    }
+    if(strtotime($has['expiretime'])<=time()){
+        return ["code"=>102,"msg"=>"token已失效"];
+    }
+    $account = Db::name("admin")->where(["id"=>$has['adminid'],"is_del"=>0])->find();
+    if(!$account){
+        return ["code"=>103,"msg"=>"未找到账户"];
+    }
+    if($account['status']!=1){
+        return ["code"=>104,"msg"=>"账户已禁用"];
+    }
+    $token_str = base64_decode($token);
+
+    $account_str= substr($token_str,0,-10);
+    if($account_str==$account['username'].$account['salt']){
+        Db::name("admin_token")->where(["token"=>$token])->update(["expiretime"=>date("Y-m-d H:i:s",time()+1800)]);
+        return ["code"=>0,"msg"=>"账户有效"];
+    }else{
+        return ["code"=>105,"msg"=>"账户token无效"];
+    }
+}
+
+/**
+ * @param $username
+ * @return bool   账户正则匹配
+ */
+function checkAccount($username){
+    $match ='/^(1745)([\d]{6})$/';
+    return preg_match($match,$username)?true:false;
+}
+
+/**
+ * @param $pawd
+ * @return bool   账户正则匹配
+ */
+function checkPasswd($pawd){
+    $match ='/^([a-zA-z]{2})([\d]{4})$/';
+    return preg_match($match,$pawd)?true:false;
+}
+function UploadImg($files){
+    $savename = [];
+
+    $files= !is_array($files) ? [$files] : $files;
+   // var_dump($files);
+    try{
+       foreach($files as $file){
+        $info= $file->validate(['size'=>10240000,'ext'=>'jpg,jpeg,png,bmp,gif'])->move(ROOT_PATH .'public' .DS .'upload');
+            if($info){
+                $temp = ['url'=>'upload/'. $info->getSaveName()];
+                $savename[]=$temp;
+
+            }else{
+                return "";
+
+            }
+        }
+
+        return $savename;
+    }catch (\think\exception\ValidateException $e) {
+
+        return $e->getMessage();
+    }
+
+}
+
+function QueuePush($data,$queue="createOrderJob"){
+    //当前任务将由哪个类来负责处理
+    $jobHandlerClassName = 'app\admin\JobInv';
+    //业务数据 对象需要手动转序列化
+    $jobQueueName = $queue;
+    $isPushed = Queue::push($jobHandlerClassName, $data,$jobQueueName);
+    if( $isPushed !== false ){
+        Log::write("{$jobQueueName} 任务失败:{$data['id']}");
+    }
+}
+
+function checkRole($roleid,$menu){
+    $roleinfo = \think\facade\Db::name("role_action")->where([['role_id',"=",$roleid],["status","=",1]])->find();
+    if($roleinfo['private_data']!=""){
+
+        $private = explode(",",$roleinfo['private_data']);
+        if(in_array($menu,$private)){
+            return true;
+        }
+    }
+    return false;
+}
+
+function excelSave($fileName = '', $headArr = [], $data = [])
+{
+    $objPHPExcel = new PHPExcel();
+    $objPHPExcel->getProperties();
+    $keyA = 0; // 设置表头
+    foreach ($headArr as $v) {
+        $colum = PHPExcel_Cell::stringFromColumnIndex($keyA);
+        $objPHPExcel->setActiveSheetIndex(0)->setCellValue($colum . '1', $v);
+        $keyA += 1;
+    }
+
+    $column = 2;
+    $objActSheet = $objPHPExcel->getActiveSheet();
+
+    foreach ($data as $key => $rows) { // 行写入
+        $span = 0;
+        foreach ($rows as $keyName => $value) { // 列写入
+            //判断数据是否有数组,如果有数组,转换成字符串
+
+            if(is_array($value)){
+                $value = implode("、", $value);
+            }
+            $objActSheet->setCellValue(PHPExcel_Cell::stringFromColumnIndex($span) . $column, $value);
+            $span++;
+        }
+        $column++;
+    }
+    //  var_dump($objActSheet->getActiveCell());
+    $file = $fileName. ".xls";
+    //$fileName .= "_" . date("Y_m_d", Request()->instance()->time()) . ".xls";
+    //$fileName = iconv("utf-8", "gb2312", $fileName); // 重命名表
+    $dir =ROOT_PATH. 'public/storage/report/'.date("YmdHis")."/";
+    if(!is_dir($dir)){
+        mkdir($dir,0777,true);
+    }
+    $objPHPExcel->setActiveSheetIndex(0); // 设置活动单指数到第一个表,所以Excel打开这是第一个表
+    $objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
+    $objWriter->save($dir . $file); // 文件通过浏览器下载
+    $url = $dir . $file;
+    if(!file_exists($url)){
+        echo "文件生成失败";
+    }
+    $saveDir = ROOT_PATH."public/storage/zip/";
+    if(!is_dir( $saveDir)){
+        mkdir($saveDir,0777,true);
+    }
+    $datetime = date("Y-m-d H:i:s");
+    $file_dir = $saveDir.$datetime.".zip";
+    # 5.1 文件打包,提示:使用本类,linux需开启zlib,windows需取消php_zip.dll前的注释
+    $zip = new \ZipArchive ();
+    # 5.2 文件不存在则生成一个新的文件 用CREATE打开文件会追加内容至zip
+    if ($zip->open($file_dir, \ZipArchive::OVERWRITE) !== true && $zip->open($file_dir, \ZipArchive::CREATE) !==
+        true) echo '无法打开文件或者文件创建失败';
+
+    # 5.3 批量写入压缩包
+    $zip->addEmptyDir($fileName);
+    // @$zip->addFile($v['file_path'], 'resume'.DIRECTORY_SEPARATOR.basename($headername));
+    @$zip->addFile($url,$fileName.DIRECTORY_SEPARATOR.basename($url));
+    # 5.4 关闭压缩包写入
+    $zip->close();
+    @deldir($dir);
+    # 6. 检查文件是否存在,并输出文件
+    if (! file_exists ( $file_dir ))  echo '简历文件不存在';
+
+    ob_clean();
+    flush();
+    header("Cache-Control: max-age=0");
+    header("Content-Description: File Transfer");
+    header('Content-disposition: attachment; filename=' . basename($file_dir)); # 处理文件名
+    header("Content-Type: application/octet-stream");                           # 流文件输出
+    header("Content-Transfer-Encoding: binary");                                # 告诉浏览器,这是二进制文件
+    header('Content-Length: ' . filesize($file_dir));                           # 告诉浏览器,文件大小
+    readfile($file_dir);                                                        # 输出文件
+    @ unlink($file_dir);
+    exit();
+}
+function deldir($path){
+    //如果是目录则继续
+    if(is_dir($path)){
+        //扫描一个文件夹内的所有文件夹和文件并返回数组
+        $p = scandir($path);
+        //如果 $p 中有两个以上的元素则说明当前 $path 不为空
+        if(count($p)>2){
+            foreach($p as $val){
+                //排除目录中的.和..
+                if($val !="." && $val !=".."){
+                    //如果是目录则递归子目录,继续操作
+                    if(is_dir($path.$val)){
+                        //子目录中操作删除文件夹和文件
+                        deldir($path.$val.'/');
+                    }else{
+                        //如果是文件直接删除
+                        unlink($path.$val);
+                    }
+                }
+            }
+        }
+    }
+    //删除目录
+    return rmdir($path);
+}
+
+function excelExport($fileName = '', $headArr = [], $data = [])
+{
+    $objPHPExcel = new PHPExcel();
+    $objPHPExcel->getProperties();
+    $keyA = 0; // 设置表头
+    foreach ($headArr as $v) {
+        $colum = PHPExcel_Cell::stringFromColumnIndex($keyA);
+        $objPHPExcel->setActiveSheetIndex(0)->setCellValue($colum . '1', $v);
+        $keyA += 1;
+    }
+
+    $column = 2;
+    $objActSheet = $objPHPExcel->getActiveSheet();
+
+    foreach ($data as $key => $rows) { // 行写入
+        $span = 0;
+        foreach ($rows as $keyName => $value) { // 列写入
+            //判断数据是否有数组,如果有数组,转换成字符串
+
+            if(is_array($value)){
+                $value = implode("、", $value);
+            }
+            $objActSheet->setCellValue(PHPExcel_Cell::stringFromColumnIndex($span) . $column, $value);
+            $span++;
+        }
+        $column++;
+    }
+    //  var_dump($objActSheet->getActiveCell());
+    $fileName .= "_" . date("Y_m_d", time()) . ".xls";
+    //$fileName .= "_" . date("Y_m_d", Request()->instance()->time()) . ".xls";
+    //$fileName = iconv("utf-8", "gb2312", $fileName); // 重命名表
+
+    $objPHPExcel->setActiveSheetIndex(0); // 设置活动单指数到第一个表,所以Excel打开这是第一个表
+    // Redirect output to a client’s web browser (Excel2007)
+    header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
+    header('Content-Disposition: attachment;filename="'.$fileName.'"');
+    header('Cache-Control: max-age=0');
+// If you're serving to IE 9, then the following may be needed
+    header('Cache-Control: max-age=1');
+
+// If you're serving to IE over SSL, then the following may be needed
+    header ('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
+    header ('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); // always modified
+    header ('Cache-Control: cache, must-revalidate'); // HTTP/1.1
+    header ('Pragma: public'); // HTTP/1.0
+
+    // header("Content-Type: application/octet-stream");                           # 流文件输出
+    //  header("Content-Transfer-Encoding: binary");                                # 告诉浏览器,这是二进制文件
+    $objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
+    $objWriter->save('php://output'); // 文件通过浏览器下载
+    exit();
+}

+ 5 - 0
application/Admin/config.php

@@ -0,0 +1,5 @@
+<?php
+//配置文件
+return [
+
+];

+ 381 - 0
application/Admin/controller/Account.php

@@ -0,0 +1,381 @@
+<?php
+/**
+ * 用户账户管理
+ */
+
+namespace app\Admin\controller;
+
+use think\Db;
+
+class Account extends Base
+{
+
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @param status
+     * @param username
+     * @param mobile
+     * @param nickname
+     * @param page
+     * @param size
+     */
+    public function List()
+    {
+        $page = isset($this->post['page']) && $this->post['page'] != "" ? intval($this->post['page']) : 1;
+        $size = isset($this->post['size']) && $this->post['size'] != "" ? intval($this->post['size']) : 10;
+        $status = isset($this->post['status']) && $this->post['status'] !== "" ? intval($this->post['status']) : "";
+        $where = ['a.is_del'=>0];
+        if ($status !== "") {
+            $where['a.status'] = $status;
+        }
+        $username = isset($this->post['username']) && $this->post['username'] !== "" ? trim($this->post['username']) : "";
+        if ($username != "") {
+            $where['username'] = ["like", "%{$username}%"];
+        }
+        $nickname = isset($this->post['nickname']) && $this->post['nickname'] !== "" ? trim($this->post['nickname']) : "";
+        if ($nickname != "") {
+            $where['nickname'] = ["like" => "%{$nickname}%"];
+        }
+        $mobile = isset($this->post['mobile']) && $this->post['mobile'] !== "" ? trim($this->post['mobile']) : "";
+        if ($mobile != "") {
+            $where['c.mobile'] = ["like" => "%{$mobile}%"];
+        }
+        $count = Db::name("account")->alias('a')
+            ->join("fc_rela_account b", "a.id = b.accountid", "left")
+            ->join("fc_account_info c", "b.account_info= c.id", "left")
+            ->where($where)->count();
+        $total = ceil($count / $size);
+        $page = $page >= $total ? $total : $page;
+
+        $list = Db::name("account")->alias('a')->where($where)->page($page, $size)
+            ->join("fc_rela_account b", "a.id = b.accountid", "left")
+            ->join("fc_account_info c", "b.account_info= c.id", "left")
+            ->field("`a`.`id` AS `id`,
+	                      `a`.`username` AS `username`,
+	                      `a`.`password` AS `password`,
+	                      `a`.`salt` AS `salt`,
+	                      `a`.`status` AS `status`,
+                          `a`.`is_del` AS `is_del`,
+                          `a`.`starttime` AS `starttime`,
+                          `a`.`expiretime` AS `expiretime`,
+                          `a`.`activetime` AS `activetime`,
+                          `a`.`addtime` AS `addtime`,
+                           `c`.`nickname` AS `nickname`,
+                           `c`.`avatar` AS `avatar`,
+                           `c`.`mobile` AS `mobile`,
+                           `c`.`remark` AS `remark`,
+                           `c`.`sex` AS `sex`")
+            ->order("a.id desc")->select();
+        $i = [];
+        foreach ($list as $vus) {
+            $vi = Db::name('rela_video')->join('fc_video a', 'a.id=fc_rela_video.video_id', 'left')->field('a.video_sn,a.video_name,a.video_url,a.video_img')->where(['accountid' => $vus['id'], 'a.is_del' => 0,])->select();
+            if (empty($vi)) {
+                $vi = [];
+            }
+            $vus['info'] = $vi;
+            $i[] = $vus;
+        }
+        return app_show(0, "获取成功", ["list" => $i, "count" => $count]);
+    }
+
+    /**
+     * @param username
+     * @param password
+     * @param starttime
+     * @param expiretime
+     * @param nickname
+     * @param remark
+     * @param video
+     */
+    public function Create()
+    {
+        $username = isset($this->post['username']) && $this->post['username'] !== "" ? trim($this->post['username']) : "";
+        if ($username == "") {
+            return error_show(1004, "参数username 不能为空");
+        }
+        if (!checkAccount($username)) {
+            return error_show(1004, "账户格式不正确");
+        }
+        $isT = Db::name("account")->where(["is_del" => 0, "username" => $username])->find();
+        if ($isT) {
+            return error_show(1004, "账户名已存在");
+        }
+        $pasword = isset($this->post['password']) && $this->post['password'] !== "" ? trim($this->post['password']) : "";
+        if ($pasword == "") {
+            return error_show(1004, "参数password 不能为空");
+        }
+        if (!checkPasswd($pasword)) {
+            return error_show(1004, "密码格式不正确");
+        }
+        $starttime = isset($this->post['starttime']) && $this->post['starttime'] !== "" ? $this->post['starttime'] : "";
+        if ($starttime == "") {
+            return error_show(1004, "参数starttime 不能为空");
+        }
+        $expiretime = isset($this->post['expiretime']) && $this->post['expiretime'] !== "" ? $this->post['expiretime'] : "";
+        if ($expiretime == "") {
+            return error_show(1004, "参数expiretime 不能为空");
+        }
+        $nickname = isset($this->post['nickname']) && $this->post['nickname'] !== "" ? trim($this->post['nickname']) : "";
+//        if($nickname==""){
+//            return error_show(1004,"参数nickname 不能为空");
+//        }
+        $mobile = isset($this->post['mobile']) && $this->post['mobile'] !== "" ? trim($this->post['mobile']) : "";
+//        if($mobile==""){
+//            return error_show(1004,"参数mobile 不能为空");
+//        }
+        $remark = isset($this->post['remark']) && $this->post['remark'] !== "" ? trim($this->post['remark']) : "";
+        $video = isset($this->post['video']) && $this->post['video'] !== "" ? $this->post['video'] : "";
+        if ($video == "") {
+            return error_show(1004, "参数video 不能为空");
+        }
+        Db::startTrans();
+        try {
+            $salt = makeSalt();
+            $pas = sha1($pasword . $salt);
+            $data = [
+                "username" => $username,
+                "password" => $pas,
+                "pwd" => $pasword,
+                "salt" => $salt,
+                "status" => 0,
+                "is_del" => 0,
+                "starttime" => $starttime,
+                "expiretime" => $expiretime,
+                "addtime" => date("Y-m-d H:i:s"),
+                "updatetime" => date("Y-m-d H:i:s")
+            ];
+            $acccount = Db::name("account")->insert($data, false, true);
+            if ($acccount > 0) {
+                $user = [
+                    "nickname" => $nickname,
+                    "mobile" => $mobile,
+                    "avatar" => "",
+                    "remark" => $remark,
+                    "sex" => "",
+                    "addtime" => date("Y-m-d H:i:s"),
+                    "updatetime" => date("Y-m-d H:i:s")
+                ];
+                $info = Db::name("account_info")->insert($user, false, true);
+                if ($info > 0) {
+                    $rela = ["accountid" => $acccount, "account_info" => $info];
+                    $rela_acc = Db::name("rela_account")->insert($rela);
+
+                    // $rele = [["video_id"=>$video,"accountid"=>$video,"addtime"=>$video]];
+                    $l = [];
+                    foreach ($video as $value) {
+
+                        $temp = ["video_id" => $value, "accountid" => $acccount, "addtime" => date("Y-m-d H:i:s")];
+                        $l[] = $temp;
+                    }
+
+                    $rele_a = Db::name("rela_video")->insertAll($l);
+                    if ($rele_a == false) {
+                        Db::rollback();
+                        return error_show(1002, "绑定失败");
+                    } else {
+                        write_log("视频绑定成功", $this->userinfo, "account", "add");
+                    }
+                    if ($rela_acc) {
+                        write_log("账户{$username}新建成功", $this->userinfo, "account", "add");
+                        Db::commit();
+                        return app_show(0, "账户新建成功");
+                    }
+
+                }
+            }
+            Db::rollback();
+            return error_show(1005, "账户新建失败");
+        } catch (\Exception $e) {
+            Db::rollback();
+            return error_show(1003, $e->getMessage());
+        }
+    }
+
+    /**@param id 账户id
+     * @return \think\response\Json|void
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function Read()
+    {
+        $id = isset($this->post['id']) && $this->post["id"] != "" ? intval($this->post['id']) : "";
+        if ($id == "") {
+            return error_show(1004, "参数id 不能为空");
+        }
+        $info = Db::name("account")->alias('a')->where(["a.id" => $id,'a.is_del'=>0])
+            ->join("fc_rela_account b", "a.id = b.accountid", "left")
+            ->join("fc_account_info c", "b.account_info= c.id", "left")
+            ->field("`a`.`id` AS `id`,
+	                      `a`.`username` AS `username`,
+	                      `a`.`password` AS `password`,
+	                      `a`.`salt` AS `salt`,
+	                      `a`.`status` AS `status`,
+                          `a`.`is_del` AS `is_del`,
+                          `a`.`starttime` AS `starttime`,
+                          `a`.`expiretime` AS `expiretime`,
+                          `a`.`activetime` AS `activetime`,
+                          `a`.`addtime` AS `addtime`,
+                           `c`.`nickname` AS `nickname`,
+                           `c`.`avatar` AS `avatar`,
+                           `c`.`mobile` AS `mobile`,
+                           `c`.`remark` AS `remark`,
+                           `c`.`sex` AS `sex`")
+            ->find();
+        if (empty($info)) {
+            return error_show(1005, "未找到数据");
+        }
+        if ($info["is_del"] == 1) {
+            return error_show(1005, "账户已被删除");
+        }
+        $info['status_n'] = $info['status'] == 0 ? "未激活" : $info['status'] == 1 ? "已激活" : "已失效";
+
+        $vi = Db::name('rela_video')->join('fc_video a', 'a.id=fc_rela_video.video_id', 'left')
+            ->field('a.video_sn,a.video_name,a.video_url,a.video_img,fc_rela_video.video_id,a.status')
+            ->where(['accountid' => $id, 'a.is_del' => 0, 'fc_rela_video.is_del' => 0])->select();
+        //var_dump(Db::name('rela_video')->getLastSql());
+        $info['info'] = $vi;
+        return app_show(0, "获取成功", $info);
+
+    }
+
+    /**
+     * @param id
+     * @param username
+     * @param password
+     * @param starttime
+     * @param expiretime
+     * @param nickname
+     * @param remark
+     * @param video
+     */
+    public function Save()
+    {
+        $id = isset($this->post['id']) && $this->post['id'] != "" ? intval($this->post['id']) : "";
+        if ($id == "") {
+            return error_show(1004, "参数id 不能为空");
+        }
+        $info = Db::name("account")->where(["is_del" => 0, "id" => $id])->find();
+        if (empty($info)) {
+            return error_show(1004, "未找到数据");
+        }
+        $username = isset($this->post['username']) && $this->post['username'] !== "" ? trim($this->post['username']) : "";
+        if ($username != "") {
+            $isT = Db::name("account")->where(["is_del" => 0, "username" => $username, "id" => ["<>", $id]])->find();
+            if ($isT) {
+                return error_show(1004, "账户名已存在");
+            }
+            $info['username'] = $username;
+        }
+//
+//       $pasword = isset($this->post['password']) && $this->post['password'] !== "" ? trim($this->post['password']) : "";
+//        if ($pasword != "" && $info['password'] != sha1($pasword.$info['salt'])) {
+//            $salt = makeSalt();
+//            $info['password'] = sha1($pasword . $salt);
+//            $info['pwd'] = $pasword;
+//        }
+        $starttime = isset($this->post['starttime']) && $this->post['starttime'] !== "" ? $this->post['starttime'] : "";
+        if ($starttime != "") {
+            $info['starttime'] = $starttime;
+        }
+        $expiretime = isset($this->post['expiretime']) && $this->post['expiretime'] !== "" ? $this->post['expiretime'] : "";
+        if ($expiretime != "") {
+            $expire = strtotime($expiretime);
+            if ($expire > time()) {
+                $info['status'] = $info['activetime'] == "" ? 0 : 1;
+            } else {
+                $info['status'] = 2;
+            }
+            $info['expiretime'] = $expiretime;
+        }
+        $info['updatetime'] = date("Y-m-d H:i:s");
+        $rela = Db::name("account_info")->alias("a")->Join("fc_rela_account b", "b.account_info=a.id", "left")->where(["b.accountid" => $id])->field("a.*")->find();
+        $nickname = isset($this->post['nickname']) && $this->post['nickname'] !== "" ? trim($this->post['nickname']) : "";
+        $rela['nickname'] = $nickname;
+        $mobile = isset($this->post['mobile']) && $this->post['mobile'] !== "" ? trim($this->post['mobile']) : "";
+        if ($mobile != "") {
+            $rela['mobile'] = $mobile;
+        }
+
+        $rela['remark'] = isset($this->post['remark']) && $this->post['remark'] !== "" ? trim($this->post['remark']) : "";
+        $video = isset($this->post['video']) && $this->post['video'] !== "" ? $this->post['video'] : "";
+        if ($video == "") {
+            return error_show(1004, "参数video 不能为空");
+        }
+        $rela['updatetime'] = date("Y-m-d H:i:s");
+
+        Db::startTrans();
+        try {
+            $acccount = Db::name("account")->update($info);
+            if ($acccount) {
+                $infoacc = Db::name("account_info")->update($rela);
+                $del = Db::name('rela_video')->where(["is_del" => 0, "accountid" => $id])->select();
+                if ($del == true) {
+                    $dl = Db::name('rela_video')->where(["is_del" => 0, "accountid" => $id])->update(["addtime" => date("Y-m-d H:i:s"), "is_del" => 1]);
+                }
+                $k = [];
+                $vb = Db::name('video')->where(['status' => 0, 'id' => ["in", $video]])->select();
+                if (!empty($vb)) {
+                    return error_show(1004, "存在已禁用的视频");
+                }
+                foreach ($video as $valu) {
+                    $temp = ["video_id" => $valu, "accountid" => $id, "addtime" => date("Y-m-d H:i:s")];
+                    $k[] = $temp;
+                }
+                $rele_a = Db::name("rela_video")->insertAll($k);
+                if ($rele_a == false) {
+                    Db::rollback();
+                    return error_show(1002, "绑定失败");
+                } else {
+                    write_log("视频绑定成功", $this->userinfo, "account", "edit");
+                }
+
+                if ($infoacc) {
+                    write_log("账户{$username}新建成功", $this->userinfo, "account", "edit");
+                    Db::commit();
+                    return app_show(0, "账户编辑成功");
+                } else {
+                    Db::rollback();
+                    return error_show(1005, "账户编辑失败");
+                }
+            }
+            Db::rollback();
+            return error_show(1005, "账户编辑失败");
+        } catch (\Exception $e) {
+            Db::rollback();
+            return error_show(1003, $e->getMessage());
+        }
+    }
+    public  function  checkPwd(){
+       $id=  isset($this->post['id']) && $this->post['id'] !== "" ? intval($this->post['id']) : "";
+       if($id===''){
+           return error_show(1004, "参数id 不能为空");
+       }
+        $info = Db::name("account")->where(["is_del" => 0, "id" => $id])->find();
+        if (empty($info)) {
+            return error_show(1004, "未找到数据");
+        }
+       $pasword = isset($this->post['password']) && $this->post['password'] !== "" ? trim($this->post['password']) : "";
+        if($pasword===''){
+            return error_show(1004, "参数password 不能为空");
+        }
+        if ($info['pwd']==$pasword) {
+            return error_show(1004, "新密码不能与原密码相同");
+        }
+//        if (!checkPasswd($pasword)) {
+//            return error_show(1004, "密码格式不正确");
+//        }
+            $salt = makeSalt();
+            $info['password'] = sha1($pasword . $salt);
+            $info['pwd'] = $pasword;
+            $info['salt'] = $salt;
+            $info['updatetime'] = date("Y-m-d H:i:s");
+        $acc= Db::name("account")->update($info);
+        return $acc ?app_show(0,"账户密码修改成功"): error_show(1005, "账户密码修改失败");
+    }
+}

+ 35 - 0
application/Admin/controller/Base.php

@@ -0,0 +1,35 @@
+<?php
+namespace app\Admin\controller;
+use think\Db;
+class Base
+{
+    public $post="";
+    public $userinfo="";
+    public function __construct()
+    {
+
+        if(request()->isOptions()){
+            echo '';
+            die();
+        }
+        $post=request()->post();
+        $token = isset($post['token']) && $post['token']!=""?$post['token']:"";
+        if($token==""){
+            return error_show(104,"参数token 不能为空");
+        }
+        $verify = verifyToken($token);
+        if($verify['code']!=0){
+            return error_show($verify['code'],$verify['msg']);
+        }
+        $tokeninfo = Db::name("admin_token")->where(["token"=>$token])->find();
+        if(!isset($tokeninfo['adminid'])){
+            return error_show(1004,"未找到账户id");
+        }
+        $userinfo = Db::name("admin")->where(["id"=>$tokeninfo['adminid']])->find();
+        if(empty($userinfo)){
+            return error_show(1004,"未找到账户数据");
+        }
+        $this->userinfo=$userinfo;
+        $this->post=$post;
+    }
+}

+ 17 - 0
application/Admin/controller/Expire.php

@@ -0,0 +1,17 @@
+<?php
+
+
+namespace app\Admin\controller;
+use think\Db;
+
+class Expire
+{
+    public function update(){
+        $acocunt =Db::name('Account')->where("is_del=0 and status>=1 and expiretime<='".date("Y-m-d H:i:s")."'")->select();
+        foreach ($acocunt as $value){
+            Db::name("Account")->where($value)->update(['status'=>2,"updatetime"=>date("Y-m-d H:i:s")]);
+        }
+
+    }
+
+}

+ 10 - 0
application/Admin/controller/Index.php

@@ -0,0 +1,10 @@
+<?php
+namespace app\Admin\controller;
+
+class Index
+{
+    public function index()
+    {
+        return '<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} a{color:#2E5CD5;cursor: pointer;text-decoration: none} a:hover{text-decoration:underline; } body{ background: #fff; font-family: "Century Gothic","Microsoft yahei"; color: #333;font-size:18px;} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.6em; font-size: 42px }</style><div style="padding: 24px 48px;"> <h1>:)</h1><p> ThinkPHP V5<br/><span style="font-size:30px">十年磨一剑 - 为API开发设计的高性能框架</span></p><span style="font-size:22px;">[ V5.0 版本由 <a href="http://www.qiniu.com" target="qiniu">七牛云</a> 独家赞助发布 ]</span></div><script type="text/javascript" src="http://tajs.qq.com/stats?sId=9347272" charset="UTF-8"></script><script type="text/javascript" src="http://ad.topthink.com/Public/static/client.js"></script><thinkad id="ad_bd568ce7058a1091"></thinkad>';
+    }
+}

+ 80 - 0
application/Admin/controller/Login.php

@@ -0,0 +1,80 @@
+<?php
+/**
+ * @2021-7-10
+**/
+namespace app\Admin\controller;
+use think\Db;
+use app\Admin\model\User;
+class Login
+{
+
+    /**
+     * @method post
+     * @param username 账户名
+     * @param password  密码
+     *
+     */
+    public function __construct(){
+        if(request()->isOptions()){
+            echo '';
+            die();
+        }
+    }
+    public function index(){
+         $post=request()->post();
+         $username = isset($post['username'])&&$post['username']!="" ? trim($post['username']) :"";
+         if($username==""){
+             return error_show(1004,"参数username 不能为空");
+         }
+         $password = isset($post['password'])&&$post['password']!="" ? trim($post['password']):"";
+        if($password==""){
+            return error_show(1004,"参数password 不能为空");
+        }
+
+        $account = Db::name("admin")->where(["is_del"=>0,"username"=>$username])->find();
+
+        if(empty($account)){
+            return error_show(1005,"账户未找到");
+        }
+       if($account['status']==0){
+           return error_show(1005,"账户已禁用");
+       }
+       $pass = sha1($password.$account['salt']);
+           if($pass!=$account['password']){
+               return error_show(1006,"账户密码错误");
+           }
+        $token = makeToken($account);
+        $userinfo = ["username"=>$account['username'],"nickname"=>$account['nickname'],"mobile"=>$account['mobile'],"role_id"=>$account['role_id']];
+        $userinfo['token'] = $token;
+        write_log("账户{$account['username']}登录系统","","login","",0);
+        return app_show(0,"登录成功",$userinfo);
+     }
+
+    /**
+     * @param Token
+     * 退出登录
+     */
+     public function logout(){
+         $post=request()->post();
+         $token =  isset($post['token'])&&$post['token']!="" ? trim($post['token']) :"";
+         if($token==""){
+             return error_show(101,"参数token 不能为空");
+         }
+         $verify = verifyToken($token);
+         if($verify['code']!=0){
+             return error_show($verify['code'],$verify['msg']);
+         }
+         $info = Db::name("admin_token")->where(["token"=>$token])->update(['token'=>""]);
+        if($info){
+            return app_show(0,"退出成功");
+        }else{
+            return error_show(1004,"退出失败");
+        }
+     }
+
+     public function LastVersion(){
+         $version = Db::name("version")->order("addtime desc")->find();
+         return app_show(0,"获取成功",$version);
+     }
+
+}

+ 397 - 0
application/Admin/controller/Menu.php

@@ -0,0 +1,397 @@
+<?php
+
+
+namespace app\Admin\controller;
+use think\Db;
+
+class Menu extends Base
+{
+
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     *获取用户菜单
+     */
+    public function MenuList(){
+//        if($this->userinfo['role_id']==0){
+//            return app_show(0,"获取成功",[]);
+//        }
+//        $action = Db::name("role")->where(["id"=>$this->userinfo['role_id'],"status"=>1])->find();
+//        if(empty($action)){
+//            return error_show(1004,"未找到角色权限");
+//        }
+        $data= Db::name("menu_action")->where(['status'=>1,"cstatus"=>1,"is_show"=>1])->order("weight desc,id asc,cweight desc,cid asc")->select();
+        $list=[];
+        $act=[];
+        foreach ($data as $value){
+            $list[$value["id"]]['menu_name']=$value['menu_name'];
+            $list[$value["id"]]['menu_img']=$value['menu_img'];
+            $list[$value["id"]]['menu_route']=$value['menu_route'];
+            $list[$value["id"]]['status']=$value['status'];
+            $temp = [];
+            $temp['menu_name']=$value['cname'];
+            $temp['menu_img']=$value['cmenu_img'];
+            $temp['menu_route']=$value['cmenu_route'];
+            $temp['menu_url']=$value['cmenu_url'];
+            $temp['menu_url']=$value['cmenu_url'];
+            $temp['status']=$value['cstatus'];
+            $temp['is_private']=$value['cprivate'];
+            $list[$value["id"]]['child'][$value['cid']]=$temp;
+            $act[$value['id']][$value['cid']][]=$value['acode'];
+            $list[$value["id"]]['child'][$value['cid']]['action']= $act[$value['id']][$value['cid']];
+
+        }
+        array_walk($list,function (&$value){
+            $value['child']= array_values($value['child']);
+        });
+        return app_show(0,"获取成功",array_values($list));
+     }
+
+    /**
+     *获取所有菜单列表
+     */
+     public function MenuAll(){
+         $data = Db::name("admin_menu")->where(['pid'=>0,"is_show"=>1])->order("weight desc,id asc")->select();
+         $list=[];
+         foreach ($data as $key=>$value){
+             $temp=[];
+             $temp =  Db::name("admin_menu")->where(['pid'=>$value['id'],"is_show"=>1])->order("weight desc,id asc")
+                 ->select();
+             $value['child']=$temp;
+             $list[]=$value;
+         }
+         return app_show(0,"获取成功",$list);
+     }
+
+     public function ActionMenu(){
+         $pageid = isset($this->post['id']) ? intval($this->post['id']) : "";
+         if($pageid==""){
+             return error_show(1001,'页面id不能为空');
+         }
+         $menu = Db::name("admin_menu")->where(["id"=>$pageid])->find();
+         if(empty($menu)){
+             return error_show(1003,'页面数据未找到');
+         }
+         if($menu['is_show']==0){
+             return error_show(1003,'页面数据已删除');
+         }
+         $condition = ['menuid'=>$pageid,];
+         $data=Db::name('action')->alias("a")->Join("fc_action_list l","a.action_code=l.action_code","left")->field
+         ("a.*,action_name")->where($condition)->select();
+         return app_show(0,"获取成功",$data);
+     }
+
+    /**
+     *
+     */
+    public function ActionSave(){
+
+        $actid = isset($this->post['id']) ? intval($this->post['id']) : "";
+        if($actid==""){
+            return error_show(1001,'功能id不能为空');
+        }
+        $menuid = isset($this->post['menuid']) ? intval($this->post['menuid']) : "";
+        if($menuid==""){
+            return error_show(1001,'页面menuid不能为空');
+        }
+        $menu = Db::name("admin_menu")->where(["id"=>$menuid])->find();
+        if(empty($menu)){
+            return error_show(1003,'页面数据未找到');
+        }
+        if($menu['is_show']==0){
+            return error_show(1003,'页面数据已删除');
+        }
+        $code = isset($this->post['action_code']) ? trim($this->post['action_code']) : "";
+        $status = isset($this->post['status']) ? intval($this->post['status']) : 1;
+        if($code==""){
+            return error_show(1002,'功能code不能为空');
+        }
+        $action_info = Db::name("action_list")->where(["action_code"=>$code])->find();
+        if(empty($action_info)){
+            return error_show(1003,'功能数据未找到');
+        }
+        if($action_info['is_show']==0){
+            return error_show(1003,'功能数据已删除');
+        }
+        $istrue =Db::name("action")->where(['menuid'=>$menuid,"action_code"=>$code])->find();
+        if($istrue && $istrue['id']!=$actid){
+            return error_show(1005,'此功能已存在');
+        }
+        try{
+            $data = ['action_code'=>$code,'status'=>$status,"updatetime"=>date("Y-m-d H:i:s")];
+            $result=Db::name("action")->where(["id"=>$actid])->update($data);
+            if($result){
+                write_log("菜单{$menu['menu_name']}功能{$action_info['action_name']}编辑成功",$this->userinfo,"orderaction",
+                    "edit","0");
+                return app_show(0,"更新成功");
+            }else{
+                return error_show(1004,"更新失败");
+            }
+
+        }catch (\Exception $e){
+            return error_show(1003,$e->getMessage());
+        }
+    }
+
+    /**
+     * 功能状态修改
+     */
+    public function ActionStatus(){
+        $actid = isset($this->post['id']) ? intval($this->post['id']) : "";
+        if($actid==""){
+            return error_show(1001,'页面功id不能为空');
+        }
+        $action =Db::name("action")->where(["id"=>$actid])->find();
+        if(empty($action)){
+            return error_show(1001,'页面功能未找到数据');
+        }
+        $action_info = Db::name("action_list")->where(["action_code"=>$action['action_code']])->find();
+        if(empty($action_info)){
+            return error_show(1003,'功能数据未找到');
+        }
+        if($action_info['is_show']==0){
+            return error_show(1003,'功能数据已删除');
+        }
+        $menu = Db::name("admin_menu")->where(["id"=>$action['menuid']])->find();
+        if(empty($menu)){
+            return error_show(1003,'页面数据未找到');
+        }
+        if($menu['is_show']==0){
+            return error_show(1003,'页面数据已删除');
+        }
+        $status = isset($this->post['status']) ? intval($this->post['status']) : 1;
+        try{
+            $data = ['status'=>$status,"updatetime"=>date("Y-m-d H:i:s")];
+            $result=Db::name("action")->where(["id"=>$actid])->update($data);
+            $msg= $status==1?"启用":"禁用";
+            if($result){
+                write_log("菜单{$menu['menu_name']}功能{$action_info['action_name']}{$msg}成功",$this->userinfo,
+                    "orderaction","status","0");
+                return app_show(0,"更新成功");
+            }else{
+                return error_show(1004,"更新失败");
+            }
+        }catch (\Exception $e){
+            return error_show(1003,$e->getMessage());
+        }
+    }
+
+    public function ActionDel(){
+        $actid = isset($this->post['id']) ? intval($this->post['id']) : "";
+        if($actid==""){
+            return error_show(1001,'页面功id不能为空');
+        }
+        $action =Db::name("action")->where(["id"=>$actid])->find();
+        if(empty($action)){
+            return error_show(1001,'页面功能未找到数据');
+        }
+        $action_info = Db::name("action_list")->where(["action_code"=>$action['action_code']])->find();
+        if(empty($action_info)){
+            return error_show(1003,'功能数据未找到');
+        }
+        if($action_info['is_show']==0){
+            return error_show(1003,'功能数据已删除');
+        }
+        $menu = Db::name("admin_menu")->where(["id"=>$action['menuid']])->find();
+        if(empty($menu)){
+            return error_show(1003,'页面数据未找到');
+        }
+        if($menu['is_show']==0){
+            return error_show(1003,'页面数据已删除');
+        }
+        $result=Db::name("action")->where(["id"=>$actid])->delete();
+        if($result){
+            write_log("菜单{$menu['menu_name']}功能{$action_info['action_name']}删除成功",$this->userinfo,"orderaction",
+                "del","0");
+            return app_show(0,"更新成功");
+        }else{
+            return error_show(1004,"更新失败");
+        }
+    }
+
+    /**
+     * @return \think\response\Json|void
+     * @throws \think\exception\DbException
+     */
+    public function ActionAdd(){
+        $pageid = isset($this->post['menuid']) ? intval($this->post['menuid']) : "";
+        if($pageid==""){
+            return error_show(1001,'页面id不能为空');
+        }
+        $code = isset($this->post['action_code']) ? trim($this->post['action_code']) : "";
+
+        $status = isset($this->post['status']) ? intval($this->post['status']) : 1;
+        if($code==""){
+            return error_show(1002,'功能code不能为空');
+        }
+        $action_info = Db::name("action_list")->where(["action_code"=>$code])->find();
+        if(empty($action_info)){
+            return error_show(1003,'功能数据未找到');
+        }
+        if($action_info['is_show']==0){
+            return error_show(1003,'功能数据已删除');
+        }
+        $menu = Db::name("admin_menu")->where(["id"=>$pageid])->find();
+        if(empty($menu)){
+            return error_show(1003,'页面数据未找到');
+        }
+        if($menu['is_show']==0){
+            return error_show(1003,'页面数据已删除');
+        }
+        try{
+            $where = ['menuid'=>$pageid,'action_code'=>$code];
+            $true =Db::name("action")->where($where)->find();
+            $data = ['menuid'=>$pageid,'action_code'=>$code,'status'=>$status,"updatetime"=>date("Y-m-d H:i:s"),"addtime"=>date("Y-m-d H:i:s")];
+            if($true){
+                return error_show(1003,'此功能已存在');
+            }else{
+                Db::name("action")->insert($data);
+                write_log("菜单{$menu['menu_name']}功能{$action_info['action_name']}新建成功",$this->userinfo,"orderaction",
+                    "add","0");
+                return app_show(0,"添加成功");
+            }
+        }catch (\Exception $e){
+            return error_show(1005,$e->getMessage());
+        }
+    }
+
+    public function MenuAdd(){
+
+        $name = isset($this->post['menu_name']) ?trim($this->post['menu_name']) :"";
+        if($name==""){
+            return error_show(1002,"菜单名称不能为空");
+        }
+        $url = isset($this->post['menu_url']) ?trim($this->post['menu_url']) :"";
+        $route = isset($this->post['menu_route']) ?trim($this->post['menu_route']) :"";
+        $code = isset($this->post['menu_code']) ?trim($this->post['menu_code']) :"";
+        $img = isset($this->post['menu_img']) ?trim($this->post['menu_img']) :"";
+        $pid = isset($this->post['pid']) ?intval($this->post['pid']) :0;
+        $private = isset($this->post['private']) ?intval($this->post['private']) :0;
+        $weight = isset($this->post['weight']) ?floatval($this->post['weight']) :1;
+        if($pid!=0 && $route==""){
+            return error_show(1002,"子级菜单路由不能为空");
+        }
+        $data=[
+            "menu_name"=>$name,
+            "menu_url"=>$url,
+            "menu_route"=>$route,
+            "menu_code"=>$code,
+            "menu_img"=>$img,
+            "pid"=>$pid,
+            "weight"=>$weight,
+            "is_show"=>1,
+            "is_private"=>$private,
+            "status"=>1,
+            "addtime"=>date("Y-m-d H:i:s"),
+            "updatetime"=>date("Y-m-d H:i:s"),
+        ];
+
+        $result = Db::name("admin_menu")->insert($data);
+        if($result){
+            write_log("菜单{$data['menu_name']}新建成功",$this->userinfo,"order","add","0");
+            return app_show(0,"添加成功");
+        }else{
+            return error_show(1003,"添加失败");
+        }
+    }
+
+    /**
+     * @return \think\response\Json|void
+     * @throws \think\Exception
+     */
+    public function MenuEdit(){
+
+        $id = isset($this->post['id']) ?intval($this->post['id']) :"";
+        if($id!=""){
+            $menu = Db::name("admin_menu")->where(["id"=>$id])->find();
+            if($menu==false){
+                return error_show(1003,"菜单不信息不存在");
+            }
+        }
+        $name = isset($this->post['name']) ?trim($this->post['name']) :"";
+        if($name==""){
+            return error_show(1002,"菜单名称不能为空");
+        }
+        $url = isset($this->post['url']) ?trim($this->post['url']) :"";
+        $route = isset($this->post['route']) ?trim($this->post['route']) :"";
+        $code = isset($this->post['menu_code']) ?trim($this->post['menu_code']) :"";
+        $img = isset($this->post['img']) ?trim($this->post['img']) :"";
+        $pid = isset($this->post['pid']) ?intval($this->post['pid']) :0;
+        $weight = isset($this->post['weight']) ?floatval($this->post['weight']) :1;
+        $is_show = isset($this->post['is_show']) ? intval($this->post['is_show']) : 0;
+        $private = isset($this->post['private']) ?intval($this->post['private']) :(isset($menu['is_private']) ?
+            $menu['is_private'] : 0);
+        if($pid!=0 && $route==""){
+            return error_show(1002,"子级菜单路由不能为空");
+        }
+        $data=[
+            "menu_name"=>$name,
+            "menu_url"=>$url,
+            "menu_route"=>$route,
+            "menu_code"=>$code,
+            "menu_img"=>$img,
+            "pid"=>$pid,
+            'is_show'=>$is_show,
+            "is_private"=>$private,
+            'status'=>1,
+            "weight"=>$weight,
+            "updatetime"=>date("Y-m-d H:i:s")
+        ];
+        if($id!=""){
+            $result = Db::name("admin_menu")->where(["id"=>$id])->update($data);
+            $msh ="编辑";
+        }else{
+            $result = Db::name("admin_menu")->insert($data); $msh ="新建";
+        }
+        if($result){
+            write_log("菜单{$data['menu_name']}{$msh}成功",$this->userinfo,"order",$id==""?"add":"edit","0");
+            return app_show(0,"{$msh}成功");
+        }else{
+            return error_show(1003,"{$msh}失败");
+        }
+    }
+    public function MenuDel(){
+
+        $id = isset($this->post['id']) ?intval($this->post['id']) :"";
+        $menu =  Db::name("admin_menu")->where(["id"=>$id])->find();
+        if($menu==false){
+            return error_show(1003,"菜单不信息不存在");
+        }
+        $menu['is_show']=0;
+        $menu['status']=0;
+        $menu['updatetime']=date("Y-m-d H:i:s");
+        $result =  Db::name("admin_menu")->update($menu);
+        if($result){
+            write_log("菜单{$menu['menu_name']}删除成功",$this->userinfo,"order","del","0");
+            return app_show(0,"删除成功");
+        }else{
+            return error_show(1003,"删除失败");
+        }
+    }
+
+    public function MenuStatus(){
+
+        $id = isset($this->post['id']) ?intval($this->post['id']) :"";
+        $menu = Db::name("admin_menu")->where(["id"=>$id])->find();
+        if($menu==false){
+            return error_show(1003,"菜单信息不存在");
+        }
+        $statu = isset($this->post['status'])&&$this->post['status']!="" ? intval($this->post['status']) :"";
+        if($statu===""){
+            return error_show(1003,"菜单状态不能为空");
+        }
+        $menu['status']=$statu;
+        $menu['updatetime']=date("Y-m-d H:i:s");
+        $result = Db::name("admin_menu")->update($menu);
+        $msg=$statu==1?"启用":"禁用";
+        if($result){
+            write_log("菜单{$menu['menu_name']}{$msg}成功",$this->userinfo,"order","status","0");
+            return app_show(0,"状态更新成功");
+        }else{
+            return error_show(1003,"状态更新失败");
+        }
+    }
+}

+ 196 - 0
application/Admin/controller/Order.php

@@ -0,0 +1,196 @@
+<?php
+
+
+namespace app\Admin\controller;
+use think\Db;
+
+
+class Order extends Base
+{
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    public function list()
+    {
+        $page = isset($this->post['page']) && $this->post['page'] != "" ? intval($this->post['page']) : 1;
+        $size = isset($this->post['size']) && $this->post['size'] != "" ? intval($this->post['size']) : 10;
+        $status = isset($this->post['status']) && $this->post['status'] !== "" ? intval($this->post['status']) : "";
+        $where = ["a.is_del"=>0];
+        if ($status !== "") {
+            $where['a.status'] = $status;
+        }
+        $username = isset($this->post['username']) && $this->post['username'] !== "" ? trim($this->post['username']) : "";
+        if ($username != "") {
+            $where['e.username'] = ["like", "%{$username}%"];
+        }
+        $nickname = isset($this->post['nickname']) && $this->post['nickname'] !== "" ? trim($this->post['nickname']) : "";
+        if ($nickname != "") {
+            $where['g.nickname'] = ["like", "%{$nickname}%"];
+        }
+        $mobile = isset($this->post['mobile']) && $this->post['mobile'] !== "" ? trim($this->post['mobile']) : "";
+        if ($mobile != "") {
+            $where['g.mobile'] = ["like", "%{$mobile}%"];
+        }
+        $order_low = isset($this->post['order_low']) && $this->post['order_low'] !== "" ? $this->post['order_low'] : "";
+        if ($order_low != "") {
+            $order_low = date("Y-m-d H:i:s", strtotime($order_low . " 00:00:00"));
+        } else {
+            $order_low = "1970-01-01 00:00:00";
+        }
+        $order_up = isset($this->post['order_up']) && $this->post['order_up'] !== "" ? $this->post['order_up'] : "";
+        if ($order_up != "") {
+            $order_up = date("Y-m-d H:i:s", strtotime($order_up . " 23:59:59"));
+        } else {
+            $order_up = date("Y-m-d H:i:s");
+        }
+        $where['a.order_time'] = ["between", [$order_low, $order_up]];
+        $count = Db::name("order a")->join("fc_order_post b", "a.order_sn=b.order_sn", "left")
+            ->join("fc_addr c", "b.addrid = c.id", "left")
+            ->join("fc_account e", "a.accountid = e.id", "left")
+            ->join("fc_rela_account f", "a.accountid = f.accountid", "left")
+            ->join("fc_account_info g", "f.account_info =g.id", "left")->where($where)->count();
+        $total = ceil($count / $size);
+        $page = $page >= $total ? $total : $page;
+
+        $list = Db::name("order a")->where($where)->page($page, $size)->join("fc_order_post b", "a.order_sn=b.order_sn", "left")
+            ->join("fc_addr c", "b.addrid = c.id", "left")
+            ->join("fc_account e", "a.accountid = e.id", "left")
+            ->join("fc_rela_account f", "a.accountid = f.accountid", "left")
+            ->join("fc_account_info g", "f.account_info =g.id", "left")
+            ->field("`a`.`id` AS `id`,
+	`a`.`order_sn` AS `order_sn`,
+	`a`.`accountid` AS `accountid`,
+	`a`.`order_num` AS `order_num`,
+	`a`.`status` AS `status`,
+	`a`.`is_del` AS `is_del`,
+	`a`.`delivery_time` AS `delivery_time`,
+	`a`.`order_time` AS `order_time`,
+	`b`.`addrid` AS `addrid`,
+	`b`.`order_num` AS `border_num`,
+	`b`.`post_code` AS `post_code`,
+	`b`.`post_name` AS `post_name`,
+	`b`.`status` AS `bstatus`,
+	`c`.`addr` AS `addr`,
+	`c`.`provice` AS `provice`,
+	`c`.`city` AS `city`,
+	`c`.`provice_name` AS `provice_name`,
+	`c`.`city_name` AS `city_name`,
+	`c`.`area` AS `area`,
+	`c`.`area_name` AS `area_name`,
+	`c`.`contector` AS `contector`,
+	`c`.`mobile` AS `contector_mobile`,
+	`e`.`username` AS `username`,
+	`g`.`nickname` AS `nickname`,
+	`g`.`mobile` AS `mobile`,
+	`a`.`unit_weight` AS `unit_weight`,
+	`a`.`unit` AS `unit`
+	")
+            ->order("order_time desc")
+            ->select();
+
+       // var_dump(Db::name("order a")->getLastSql());
+        return app_show(0, "获取成功", ["list" => $list, "count" => $count]);
+    }
+
+    /**
+     * @param ordersn
+     * @param post_code
+     * @param post_company
+     */
+    public function OrderDelivery()
+    {
+        $ordersn = isset($this->post['ordersn']) && $this->post['ordersn'] != "" ? trim($this->post['ordersn']) : "";
+        if ($ordersn == "") {
+            return error_show(1004, "参数ordersn 不能为空");
+        }
+        $orderinfo = Db::name("order")->where(["order_sn" => $ordersn])->find();
+        if (empty($orderinfo)) {
+            return error_show(1005, "订单不存在");
+        }
+        if ($orderinfo['is_del'] == 1) {
+            return error_show(1005, "订单已删除");
+        }
+        if ($orderinfo['status'] != 1) {
+            return error_show(1005, "订单状态有误");
+        }
+        $orderpost = Db::name("order_post")->where(["order_sn" => $ordersn, "is_del" => 0])->find();
+        if (empty($orderpost)) {
+            return error_show(1005, "订单地址信息不存在");
+        }
+        $post_code = isset($this->post['post_code']) && $this->post['post_code'] != "" ? trim($this->post['post_code']) : "";
+        if ($post_code == "") {
+            return error_show(1004, "参数post_code 不能为空");
+        }
+        $post_company = isset($this->post['post_company']) && $this->post['post_company'] != "" ? trim($this->post['post_company']) : "";
+        if ($post_company == "") {
+            return error_show(1004, "参数post_company 不能为空");
+        }
+        $orderpost['post_code'] = $post_code;
+        $orderpost['post_name'] = $post_company;
+        $orderpost['updatetime'] = date("Y-m-d H:i:s");
+        Db::startTrans();
+        try {
+            $psot = Db::name("order_post")->update($orderpost);
+            if ($psot) {
+                $orderinfo['status'] = 2;
+                $orderinfo['delivery_time'] = date("Y-m-d H:i:s");
+                $order = Db::name("order")->update($orderinfo);
+                if ($order) {
+                    write_log("订单{$ordersn}发货", $this->userinfo, "order", "edit", "0");
+                    Db::commit();
+                    return app_show(0, "订单物流信息新建成功");
+                }
+            }
+            Db::rollback();
+            return error_show(1004, "物流信息新建失败");
+        } catch (\Exception $e) {
+            Db::rollback();
+            return error_show(1004, $e->getMessage());
+        }
+    }
+
+    public function uploud()
+    {
+        $sql = "SELECT
+	a.order_sn  '订单编号',
+	a.order_num '订单数量',
+	a.unit '单位',
+	a.order_time '下单时间',
+	concat(a.unit_weight,'kg')'单位重量(kg)',
+    concat(a.order_num*a.unit_weight,'kg') '总重量(kg)',
+	if(a.status=1,'待发货',if(a.status=2,'已发货','')) '发货状态',
+	a.delivery_time '发货时间',
+	b.post_code '快递编号',
+	b.post_name '快递公司',
+	k.username '账户名',
+	c.addr '收货地址',
+	c.provice_name '省级名称',
+	c.city_name '市级名称',
+	c.area_name '县区名称',
+	c.contector '收货人',
+	c.mobile '收货电话',
+	v.nickname '用户名',
+	v.mobile AS '用户电话'
+FROM
+	fc_order a
+	LEFT JOIN fc_order_post b ON b.order_sn = a.order_sn
+	LEFT JOIN fc_addr c ON c.id = b.addrid
+	LEFT JOIN fc_account k ON k.id = a.accountid
+	LEFT JOIN fc_rela_account n ON n.accountid = a.accountid
+	LEFT JOIN fc_account_info v ON v.id = n.account_info 
+    where a.status=1 and a.is_del=0
+    ";
+        $list = Db::query($sql);
+        if(empty($list)){
+            $list=[["未找到数据"=>""]];
+        }
+        $header = array_keys($list[0]);
+        array_walk($list, function (&$v) {
+            $v = array_values($v);
+        });
+        excelExport(date("Y-m-d")."未发货订单", $header, $list);
+    }
+
+}

+ 219 - 0
application/Admin/controller/Stock.php

@@ -0,0 +1,219 @@
+<?php
+
+
+namespace app\Admin\controller;
+use think\Db;
+
+class Stock extends Base
+{
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+    * @param status
+    * @param username
+    * @param nickname
+    * @param mobile
+    * @param stock_low
+    * @param stock_up
+     */
+    public  function StockList(){
+        $page = isset($this->post['page'])&&$this->post['page']!="" ? intval($this->post['page']) : 1;
+        $size = isset($this->post['size'])&&$this->post['size']!="" ? intval($this->post['size']) :10;
+        $status = isset($this->post['status'])&&$this->post['status']!=="" ? intval($this->post['status']) :"";
+        $where=['a.is_del'=>0,'d.is_del'=>0];
+        if($status!==""){
+            $where['a.status'] = $status;
+        }
+        $username =  isset($this->post['username'])&&$this->post['username']!=="" ? trim($this->post['username']) :"";
+        if($username!=""){
+            $where['a.username'] = ["like","%{$username}%"];
+        }
+        $nickname =  isset($this->post['nickname'])&&$this->post['nickname']!=="" ? trim($this->post['nickname']) :"";
+        if($nickname!=""){
+            $where['v.nickname'] = ["like","%{$nickname}%"];
+        }
+        $mobile =  isset($this->post['mobile'])&&$this->post['mobile']!=="" ? trim($this->post['mobile']) :"";
+        if($mobile!=""){
+            $where['v.mobile'] = ["like","%{$mobile}%"];
+        }
+        $stock_low =  isset($this->post['stock_low'])&&$this->post['stock_low']!=="" ? intval($this->post['stock_low'])
+            :"";
+       // $wherestock="1=1";
+        if($stock_low!=""){
+            $where['stock_balance'] = [">=",$stock_low];
+           // $wherestock .=" and stock_balance>={$stock_low}";
+        }
+        $stock_up =  isset($this->post['stock_up'])&&$this->post['stock_up']!=="" ? intval($this->post['stock_up']) :"";
+        if($stock_up!=""){
+           $where['stock_balance'] = ["<=",$stock_up];
+            //$wherestock .=" and stock_balance<={$stock_up}";
+        }
+        $count= Db::name("account")->alias('a')
+            ->join("fc_rela_account b","a.id = b.accountid","left")
+            ->join("fc_account_info v","b.account_info = v.id","left")
+            ->join("fc_account_stock d","a.id = d.accountid","left")
+            ->where($where)->count();
+        $total = ceil($count/$size);
+        $page = $page>=$total? $total:$page;
+        $list = Db::name("account")->alias('a')->where($where)->page($page,$size)
+            ->join("fc_rela_account b","a.id = b.accountid","left")
+            ->join("fc_account_info v","b.account_info = v.id","left")
+            ->join("fc_account_stock d","a.id = d.accountid","left")
+            ->field("`a`.`id` AS `id`,
+                        `a`.`username` AS `username`,
+                        `a`.`status` AS `status`,
+                        `a`.`starttime` AS `starttime`,
+                        `a`.`expiretime` AS `expiretime`,
+                        `a`.`activetime` AS `activetime`,
+                        `a`.`addtime` AS `addtime`,
+                        `v`.`nickname` AS `nickname`,
+                        `v`.`avatar` AS `avatar`,
+                        `v`.`mobile` AS `mobile`,
+                        `v`.`remark` AS `remark`,
+                        ifnull( `d`.`stock_total`, 0 ) AS `stock_total`,
+                        ifnull( `d`.`stock_used`, 0 ) AS `stock_used`,
+                        ifnull( `d`.`stock_balance`, 0 ) AS `stock_balance`,
+                        ifnull( `d`.`stock_delivery`, 0 ) AS `stock_delivery`,
+                        ifnull( `d`.`updatetime`, '' ) AS `stock_update` ")
+            ->order("d.updatetime desc")->select();
+        return app_show(0,"获取成功",["list"=>$list,"count"=>$count]);
+    }
+
+    /**
+     * @param id
+     * @param stock
+     * @param type
+     */
+    public function Save(){
+        $id = isset($this->post['id'])&&$this->post['id']!=""? intval($this->post["id"]) :"";
+        if($id==""){
+            return error_show(1004,"参数id 不能为空");
+        }
+        $account = Db::name("account")->where(["is_del"=>0,"id"=>$id])->find();
+        if(empty($account)){
+            return error_show(1005,"账户信息不存在");
+        }
+        $stock = isset($this->post['stock'])&&$this->post['stock']!==""? $this->post["stock"] :"";
+        if($stock==""){
+            return error_show(1005,"参数stock 不能为空或0");
+        }
+        $type = isset($this->post['type'])&&$this->post['type']!=""?intval($this->post['type']) :"";
+        if($type===""){
+            return error_show(1005,"参数type 不能为空");
+        }
+        if(!in_array($type,[1,2])){
+            return error_show(1005,"参数type 值无效");
+        }
+        $stockinfo = Db::name("account_stock")->where(["accountid"=>$id,"is_del"=>0])->find();
+        Db::startTrans();
+        try {
+            $msg = $type==1?"增加库存":"减少库存";
+            $log=[
+                "accountid"=>$id,
+                "run_stock"=>$stock,
+                "type"=>$type,
+                "after_stock"=>isset($stockinfo['stock_balance']) ? $stockinfo['stock_balance']+$stock:$stock,
+                "before_stock"=>isset($stockinfo['stock_balance']) ? $stockinfo['stock_balance']:0,
+                "action_uid"=>$this->userinfo['id'],
+                "action_name"=>$this->userinfo['nickname'],
+                "addtime"=>date("Y-m-d H:i:s")
+            ];
+            $stocklog= Db::name("stock_log")->insert($log);
+            if($stocklog){
+             if($stockinfo){
+                if($type==1){
+                    $stockinfo['stock_total']+=$stock;
+                    $stockinfo['stock_balance']+=$stock;
+                }else{
+                    if($stockinfo['stock_balance']<$stock){
+                        Db::rollback();
+                        return error_show(1005,"剩余库存不足");
+                    }
+                    $stockinfo['stock_total']-=$stock;
+                    $stockinfo['stock_balance']-=$stock;
+                }
+                $stockinfo['updatetime']=date("Y-m-d H:i:s");
+                $accstock = Db::name("account_stock")->update($stockinfo);
+             }else{
+                 if($type==1){
+                   $data = [
+                       "accountid"=>$id,
+                       "stock_total"=>$stock,
+                       "stock_balance"=>$stock,
+                       "stock_used"=>0,
+                       "stock_delivery"=>0,
+                       "status"=>1,
+                       "is_del"=>0,
+                       "updatetime"=>date("Y-m-d H:i:s"),
+                       "addtime"=>date("Y-m-d H:i:s")
+                   ];
+                     $accstock = Db::name("account_stock")->insert($data);
+                 }else{
+                     Db::rollback();
+                     return error_show(1005,"账户剩余库存不足");
+                 }
+             }
+             if($accstock){
+                 write_log("账户{$account['username']}{$msg}:{$stock}",$this->userinfo,"stock","edit","0");
+                 Db::commit();
+                 return app_show(0,"{$msg}成功");
+             }
+            }
+            Db::rollback();
+            return error_show(1005,"{$msg}失败");
+        }catch (\Exception $e){
+            Db::rollback();
+            return error_show(1004,$e->getMessage());
+        }
+    }
+
+    /**
+    * @param id
+    * @param page
+    * @param size
+     */
+
+    public function StockLog(){
+        $id = isset($this->post['id'])&&$this->post['id']!=""? intval($this->post["id"]) :"";
+        if($id==""){
+            return error_show(1004,"参数id 不能为空");
+        }
+        $account = Db::name("account")->alias('a')->where(["a.is_del"=>0,"a.id"=>$id])
+            ->join("fc_rela_account b", "a.id = b.accountid", "left")
+            ->join("fc_account_info c", "b.account_info= c.id", "left")
+            ->field("`a`.`id` AS `id`,
+	                      `a`.`username` AS `username`,
+	                      `a`.`password` AS `password`,
+	                      `a`.`salt` AS `salt`,
+	                      `a`.`status` AS `status`,
+                          `a`.`is_del` AS `is_del`,
+                          `a`.`starttime` AS `starttime`,
+                          `a`.`expiretime` AS `expiretime`,
+                          `a`.`activetime` AS `activetime`,
+                          `a`.`addtime` AS `addtime`,
+                           `c`.`nickname` AS `nickname`,
+                           `c`.`avatar` AS `avatar`,
+                           `c`.`mobile` AS `mobile`,
+                           `c`.`remark` AS `remark`,
+                           `c`.`sex` AS `sex`")
+            ->find();
+        if(empty($account)){
+            return error_show(1005,"账户信息不存在");
+        }
+        $page = isset($this->post['page'])&&$this->post['page']!="" ? intval($this->post['page']) : 1;
+        $size = isset($this->post['size'])&&$this->post['size']!="" ? intval($this->post['size']) :10;
+        $count = Db::name("stock_log")->where(["accountid"=>$id])->count();
+        $total = ceil($count/$size);
+        $page = $page>=$total? $total:$page;
+        $list = Db::name("stock_log")->where(["accountid"=>$id])->page($page,$size)->order("addtime desc")->select();
+        foreach ($list as $key=>$value){
+            $list[$key]['username']=$account['username'];
+            $list[$key]['nickname']=$account['nickname'];
+        }
+        return app_show(0,"获取成功",['list'=>$list,"count"=>$count]);
+    }
+
+}

+ 270 - 0
application/Admin/controller/Stock2.php

@@ -0,0 +1,270 @@
+<?php
+
+namespace app\Admin\controller;
+
+use think\Db;
+class Stock2 extends Base
+
+{
+//    public $post="";
+//    public $userinfo="";
+   public function __construct()
+   {
+      parent:: __construct();
+//       $post=request()->post();
+//       $this->post=$post;
+    }
+
+    public function video()
+    {
+        $page = isset($this->post['page']) && $this->post['page'] != "" ? intval($this->post['page']) : 1;
+        $size = isset($this->post['size']) && $this->post['size'] != "" ? intval($this->post['size']) : 10;
+        $status = isset($this->post['status']) && $this->post['status'] !== "" ? intval($this->post['status']) : "";
+
+        $where = ['is_del'=>0];
+        if ($status != "") {
+            $where ['status'] = $status;
+        }
+        $video_sn = isset($this->post['video_sn']) && $this->post['video_sn'] !== "" ? trim($this->post['video_sn']) : "";
+        if ($video_sn !== "") {
+            $where['video_sn'] = ["like", "%{$video_sn}%"];
+        }
+        $video_name = isset($this->post['video_name']) && $this->post['video_name'] !== "" ? trim($this->post['video_name']) : "";
+        if ($video_name) {
+            $where['video_name'] = ["like", "%{$video_name}%"];
+        }
+        $video_url = isset($this->post['video_url']) && $this->post['video_url'] !== "" ? trim($this->post['video_url']) : "";
+        if ($video_url) {
+            $where['video_url'] = ["like", "%{$video_url}%"];
+        }
+        $video_img = isset($this->post['video_img']) && $this->post['video_img'] !== "" ? trim($this->post['video_img']) : "";
+        if ($video_img) {
+            $where['video_img'] = ["like", "%{$video_img}%"];
+        }
+        $count = Db::name("video")->where($where)->count();
+        $total = ceil($count / $size);
+        $page = $page >= $total ? $total : $page;
+        $video = Db::name("video")->where($where)->page($page, $size)->order("addtime desc")->select();
+        return app_show(0, "获取成功", ["video" => $video, "count" => $count]);
+    }
+
+    public function Create()
+    {
+        /**
+
+         * @param video_name
+         * @param video_url
+         * @param video_img
+         * @param remark
+         */
+
+        $video_sn = makeNo("FC");
+        //var_dump($this->post);
+        $video_name = isset($this->post['video_name']) && $this->post['video_name'] !== "" ? trim($this->post['video_name']) : "";
+      // var_dump($video_name);
+        if ($video_name == "") {
+            return error_show(1004, "参数video_name  不能为空");
+        }
+
+        $isN = Db::name("video")->where(["is_del" => 0, "video_name" => $video_name])->find();
+        //var_dump(Db::name("video")->getLastSql());
+        if (!empty($isN)) {
+            return error_show(1004, "视频名称已存在");
+        }
+        $video_url = isset($this->post['video_url']) && $this->post['video_url'] !== "" ? trim($this->post['video_url']) : "";
+       // var_dump( $video_url);
+        if ($video_url == "") {
+
+            return error_show(1004, "参数video_url  视频地址不能为空");
+        }
+
+        $video_img = isset($this->post['video_img']) && $this->post['video_img'] !== "" ? trim($this->post['video_img']) :"";
+        //var_dump($video_img);
+        if ($video_img == "") {
+            return error_show(1004, "参数video_img 视频图片不能为空");
+        }
+        $remark = isset($this->post['remark']) && $this->post['remark'] !== "" ? trim($this->post['remark']) : "";
+        $data = [
+            "video_sn" => $video_sn,
+            "video_name"=>$video_name,
+            "video_url"=>$video_url,
+            "video_img"=>$video_img,
+            "remark"=>$remark,
+            "is_del" => 0,
+            "status" => 1,
+            "addtime" => date("Y-m-d H:i:s"),
+            "updatetime" => date("Y-m-d H:i:s"),
+        ];
+        Db::startTrans();
+        try{
+            $video = Db::name("video")->insert($data, false, true);
+            //var_dump( Db::name("video")->getLastSql());
+            if ($video) {
+                write_log("视频{$video}新建成功", $this->userinfo, "account", "add");
+                Db::commit();
+                return app_show(0, "视频新建成功");
+            }
+
+            Db::rollback();
+            return error_show(1005, "视频新建失败");
+        }catch (\Exception $e){
+            Db::rollback();
+            return error_show(1003,$e->getMessage());
+        }
+
+
+
+}
+    public function Read(){
+        $id=isset($this->post['id'])&&$this->post["id"]!="" ? intval($this->post['id']):"";
+        if($id==""){
+            return error_show(1004,"参数id 不能为空");
+        }
+        $video_sn = db::name("video")->where(["id"=>$id,"is_del"=>0])->find();
+        if(empty($video_sn)){
+            return error_show(1005,"未找到视频编号");
+        }
+        if($video_sn["is_del"]==1) {
+            return error_show(1005, "视频编号已删除");
+        }
+        $video_sn['status_n'] = $video_sn['status']==0? "禁用视频": $video_sn['status']==1? "启用视频":"禁用视频";
+
+        return app_show(0,"成功获取",$video_sn);
+
+    }
+    /**
+     * @param video_sn
+     * @param video_name
+     * @param video_url
+     * @param video_img
+     * @param remark
+
+
+     */
+    public function change(){
+        $id = isset($this->post['id'])? intval($this->post['id']) : "";
+       // var_dump($this->post,$id);
+
+        if($id==""){
+
+            return error_show(1001,'参数ID 不能为空');
+        }
+        $act = Db::name("video")->where(["id"=>$id,"is_del"=>0])->find();
+        if(empty($act)){
+            return error_show(1001,"未找到视频");
+        }
+
+        if($act['is_del']==1){
+            return error_show(1003,'视频编号已删除');
+        }
+      $status = isset($this->post['status']) ? intval($this->post['status']) : "";
+        if($status===""){
+            return error_show(1004,"参数不能为空");
+        }
+        if(!in_array($status,[0,1])){
+            return error_show(1004,"参数status无效值");
+        }
+
+        try{
+            $data = ['status'=>$status,"updatetime"=>date("Y-m-d H:i:s")];
+            $result = Db::name("video")->where(["id"=>$id])->update($data);
+            $msg = $status ==1?"启用":"禁用";
+            //var_dump(Db::name("video")->getLastSql());
+
+
+            if($result){
+                write_log("视频{$act['video_name']}功能{$act['video_name']}{$msg}成功",$this->userinfo,"status","0");
+                return app_show(0,"更新成功");
+            }else{
+                return error_show(1004,"更新失败");
+            }
+        }catch (\Exception $e){
+            return error_show(1003,$e->getMessage());
+        }
+
+
+    }
+
+    /**
+     * @param video_sn
+     * @param video_name
+     * @param video_url
+     * @param video_img
+
+     */
+
+    public function Edit(){
+        $id = isset($this->post['id'])&&$this->post['id']!== "" ?trim($this->post['id']):"";
+        if($id==""){
+            return error_show(1005,"参数id不能为空");
+        }
+        $in = Db::name("video")->where(["id"=>$id,"is_del"=>0])->find();
+        //var_dump($in);
+        if(empty($in)){
+            return error_show(1004,"视频不存在");
+        }
+        $weight = isset($this->post['weight'])&&$this->post['weight']!==""?$this->post['weight']:$in["weight"];
+
+
+        $video_name = isset($this->post['video_name']) ? trim($this->post['video_name']) : "";
+        if($video_name==""){
+            return error_show(1004,"视频名称不能为空");
+        }
+        $video_url = isset($this->post['video_url']) ? trim($this->post['video_url']) : "";
+        if($video_name==""){
+            return error_show(1004,"视频地址不能为空");
+        }
+        $video_img = isset($this->post['video_img']) ? trim($this->post['video_img']) : "";
+        if($video_img==""){
+            return error_show(1004,"视频图片不能为空");
+        }
+        $remark = isset($this->post['remark']) && $this->post['remark'] !== "" ? trim($this->post['remark']) : "";
+        Db::startTrans();
+        try{
+            $data=[
+                "id"=>$id,
+                "video_name"=>$video_name,
+                "video_url"=>$video_url,
+                "video_img"=>$video_img,
+                "updatetime"=>date("Y-m-d H:i:s"),
+                "weight"=>$weight,
+                "remark"=>$remark
+           ];
+
+            $video_name= Db::name("video")->update($data);
+           // var_dump(Db::name("video")->getLastSql());
+            if($video_name){
+                Db::commit();
+                return app_show(0,"视频内容编辑成功");
+            }
+            Db::rollback();
+            return error_show(1008,"视频内容修改失败");
+        }catch (\Exception $e){
+            Db::rollback();
+            return error_show(1008,$e->getMessage());
+        }
+
+    }
+    public function Delete(){
+        $id = isset($this->post['id'])&&$this->post['id']!==""? intval($this->post['id']):"";
+
+        if($id==""){
+            return error_show(1005,"参数id不能为空");
+        }
+        $list = Db::name("video")->where(["id"=>$id,"is_del"=>0])->find();
+        if(empty($list)){
+            return error_show(1004,"未找到数据");
+        }
+
+        $del = Db::name("video")->where(["id"=>$id])->update(["is_del"=>1,"updatetime"=>date("Y-m-d H:i:s")]);
+       // var_dump( Db::name("video")->getLastSql());
+        if($del){
+            return app_show(0,"视频数据修改成功");
+        }
+        return error_show(1005,"视频数修改失败");
+    }
+
+
+
+
+}

+ 133 - 0
application/Admin/controller/System.php

@@ -0,0 +1,133 @@
+<?php
+
+
+namespace app\Admin\controller;
+
+use think\Db;
+
+
+class System extends Base
+{
+    protected $role = ["0" => '系统', "1" => "超级管理员", "2" => "运营", "3" => "用户","4"=>'库管','5'=>"管理员"];
+    protected $menu = [];
+    protected $action = [];
+
+    public function __construct()
+    {
+        parent::__construct();
+        $this->menu = [
+            "login" => ["label" => "后台登录模块", "action" => []],
+            "homelogin" => ["label" => "用户登录模块", "action" => []],
+            "menu" => ["label" => "菜单管理模块", "action" => [
+//                ['value'=>"add","label"=>'新建'],
+//                ['value'=>"edit","label"=>'编辑'],
+//                ['value'=>"status","label"=>'状态'],
+//                ['value'=>"del","label"=>'删除'],
+                ]],
+            "menuaction" => ["label" => "菜单功能模块", "action" => [
+//                ['value'=>"add","label"=>'新建'],
+//                ['value'=>"edit","label"=>'编辑'],
+//                ['value'=>"status","label"=>'状态'],
+//                ['value'=>"del","label"=>'删除']
+            ]
+            ],
+            "order" => ["label" => "订单管理模块", "action" => [
+//                ['value'=>"edit","label"=>'编辑'],
+//                ['value'=>"status","label"=>'状态']
+            ]],
+            "stock" => ["label" => "库存管理模块", "action" => [
+//                ['value'=>"add","label"=>'新建'],
+//                ['value'=>"edit","label"=>'编辑']
+            ]],
+            "account" => ["label" => "用户管理模块", "action" => [
+//                ['value'=>"add","label"=>'新建'],
+//                ['value'=>"edit","label"=>'编辑'],
+//                ['value'=>"status","label"=>'状态'],
+//                ['value'=>"del","label"=>'删除']
+            ]],
+            "version" => ["label" => "版本管理模块", "action" => [
+//                ['value'=>"add","label"=>'新建'],
+//                ['value'=>"edit","label"=>'编辑']
+            ]
+        ]];
+        $this->action = [
+            "add" => "新建",
+            "edit" => "编辑",
+            "status" => "状态",
+            "del" => "删除"
+        ];
+    }
+
+    public function list()
+    {
+        $page = isset($this->post['page']) && $this->post['page'] != "" ? intval($this->post['page']) : 1;
+        $size = isset($this->post['size']) && $this->post['size'] != "" ? intval($this->post['size']) : 10;
+        $where = [];
+        $role = isset($this->post['role']) && $this->post['role'] != "" ? $this->post['role'] : "";
+        if ($role != "") {
+            if($role==2){
+                $where['role'] = ['in',[2,4,5]];
+            }else{
+                $where['role'] = $role;
+            }
+
+        }
+        $lowtime = isset($this->post['lowtime']) && $this->post['lowtime'] != "" ? $this->post['lowtime'] : "";
+        if ($lowtime != "") {
+            $where['addtime'] = [">=", $lowtime];
+        }
+        $uptime = isset($this->post['uptime']) && $this->post['uptime'] != "" ? $this->post['uptime'] : "";
+        if ($uptime != "") {
+            $where['addtime'] = ["<=", $uptime];
+        }
+        $username = isset($this->post['username']) && $this->post['username'] != "" ? $this->post['username'] : "";
+        if ($username != "") {
+            $where['username'] = ["like", "%{$username}%"];
+        }
+        $moudel = isset($this->post['moudel']) && $this->post['moudel'] != "" ? $this->post['moudel'] : "";
+        if ($moudel != "") {
+            $where['module|action'] =$moudel;
+        }
+        $count = Db::name("system_log")->where($where)->count();
+        $total = ceil($count / $size);
+        $page = $page >= $total ? $total : $page;
+        $list = Db::name("system_log")->where($where)->page($page, $size)->order("addtime desc")->select();
+        foreach ($list as $key => $value) {
+            $list[$key]['module'] = key_exists($value['module'], $this->menu) ?
+                $this->menu[$value['module']]['label'] :
+                $value['module'];
+            $list[$key]['action'] = key_exists($value['action'], $this->action) ? $this->action[$value['action']] : $value['action'];
+            $list[$key]['role'] = key_exists($value['role'], $this->role) ? $this->role[$value['role']] : $value['role'];
+        }
+        return app_show(0, "获取成功", ["list" => $list, "count" => $count]);
+    }
+
+    public function GetMenu()
+    {
+        $data = [];
+        foreach ($this->menu as $key => $value) {
+            $temp = [];
+            $temp["label"] = $value['label'];
+            $temp["value"] = $key;
+            $temp["children"] = $value['action'];
+            $data[] = $temp;
+        }
+        return app_show(0, "获取成功", $data);
+    }
+
+    public function GetAction()
+    {
+        $data = [];
+        $moudel=isset($this->post['moudel'])&&$this->post['moudel']!="" ?  trim($this->post['moudel']):"";
+        if($moudel!=""){
+            $this->action = key_exists($moudel, $this->menu) ? $this->menu[$moudel]['action'] :[];
+        }
+        foreach ($this->action as $key => $value) {
+            $temp = [];
+            $temp["value"] = $value;
+            $temp["lable"] = $key;
+            $data[] = $temp;
+        }
+        return app_show(0, "获取成功", $data);
+    }
+}

+ 30 - 0
application/Admin/controller/Upload.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace app\Admin\controller;
+
+class Upload
+{
+
+    public $post="";
+    public $userinfo="";
+    public function __construct()
+    {
+
+        $post=request()->post();
+        $this->post=$post;
+
+    }
+    public function index(){
+        $files = request()->file('img');
+        $list="";
+        if($files!=""){
+            $list=UploadImg($files);
+        }
+        //var_dump($list);
+        if(is_array($list)&&!empty($list)){
+            return app_show(0,"上传成功",$list);
+        }else{
+            return error_show(1004,"上传失败");
+        }
+    }
+}

+ 50 - 0
application/Admin/controller/User.php

@@ -0,0 +1,50 @@
+<?php
+
+
+namespace app\Admin\controller;
+use think\Db;
+
+class User extends Base
+{
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+
+    /**
+     *
+     */
+    public function ResetInfo(){
+       $pasword = isset($this->post['password']) && $this->post['password']!="" ? $this->post['password'] :"";
+       $data=[];
+       if($pasword!=""){
+        $data['salt']=makeSalt();
+        $data['password']=sha1($pasword.$data['salt']);
+       }
+       $nickname = isset($this->post['nickname'])&& $this->post['nickname']!="" ? trim($this->post['nickname']):"";
+       if($nickname!=""){
+           $data['nickname']=$nickname;
+       }
+        $mobile = isset($this->post['mobile'])&& $this->post['mobile']!="" ? trim($this->post['mobile']):"";
+        if($mobile!=""){
+            $data['mobile']=$mobile;
+        }
+        $data['updatetime'] = date("Y-m-d H:i:s");
+        $result=Db::name('admin')->where(['id'=>$this->userinfo['id']])->update($data);
+
+        $msg =isset($data['password'])? "修改密码为:{$pasword}":"";
+        $msg .=isset($data['nickname'])? "修改昵称为:{$nickname}":"";
+        $msg .=isset($data['mobile'])? "修改手机号为:{$mobile}":"";
+      if($result){
+            write_log("管理员{$this->userinfo['nickname']}修改个人信息成功{$msg}",$this->userinfo,"user","edit");
+            return app_show(0,"信息修改成功");
+        }else{
+            return error_show(1003,"信息修改失败");
+        }
+    }
+    //获取用户信息
+    public function UserInfo(){
+        return app_show(0,"获取成功",$this->userinfo);
+    }
+}

+ 53 - 0
application/Admin/controller/Version.php

@@ -0,0 +1,53 @@
+<?php
+
+
+namespace app\Admin\controller;
+use think\Db;
+
+class Version extends Base
+{
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    public function list(){
+        $page = isset($this->post['page'])&&$this->post['page']!="" ? intval($this->post['page']) : 1;
+        $size = isset($this->post['size'])&&$this->post['size']!="" ? intval($this->post['size']) :10;
+        $count= Db::name("version")->count();
+        $total = ceil($count/$size);
+        $page = $page>=$total? $total:$page;
+        $list = Db::name("version")->page($page,$size)->order("addtime desc")->select();
+        return app_show(0,"获取成功",["list"=>$list,"count"=>$count]);
+    }
+
+    public function create(){
+        $title = isset($this->post['title'])&&$this->post['title']!="" ? $this->post['title']:"";
+        if($title==""){
+            return error_show(1004,"参数title 不能为空");
+        }
+        $content = isset($this->post['content'])&&$this->post['content']!="" ? $this->post['content']:"";
+        if($content==""){
+            return error_show(1004,"参数content 不能为空");
+        }
+        $version = isset($this->post['version'])&&$this->post['version']!="" ? $this->post['version']:"";
+        if($version==""){
+            return error_show(1004,"参数version 不能为空");
+        }
+        $data=[
+            "title"=>$title,
+            "content"=>$content,
+            "version"=>$version,
+            "addtime"=>date("Y-m-d H:i:s")
+        ];
+
+        $inert= Db::name("version")->insert($data);
+        if($inert){
+            write_log("版本{$version}新建成功",$this->userinfo,"version","add");
+            return app_show(0,"版本信息新建成功");
+        }else{
+            return app_show(0,"版本信息新建失败");
+        }
+    }
+
+}

+ 9 - 0
application/Admin/model/User.php

@@ -0,0 +1,9 @@
+<?php
+namespace app\Admin\model;
+
+use think\Model;
+
+class User extends Model
+{
+
+}

+ 51 - 0
application/Home/common.php

@@ -0,0 +1,51 @@
+<?php
+use think\Db;
+/**
+ * @param $account
+ * @return string
+ * @throws \think\db\exception\DataNotFoundException
+ * @throws \think\db\exception\DbException
+ * @throws \think\db\exception\ModelNotFoundException
+ * @throws \think\exception\DbException
+ */
+function makeToken($account){
+    $now=time();
+    $str = $account['username'].$account['salt'].$now;
+    $token = base64_encode($str);
+    $has = Db::name("account_token")->where(["accountid"=>$account['id']])->find();
+    if($has){
+        Db::name("account_token")->where(["accountid"=>$account['id']])->update(["token"=>$token,"expiretime"=>date("Y-m-d H:i:s",$now+1800)]);
+    }else{
+        Db::name("account_token")->insert(["token"=>$token,"expiretime"=>date("Y-m-d H:i:s",$now+1800),
+            "accountid"=>$account['id']]);
+    }
+    return $token;
+}
+
+/**
+ * @param $token
+ */
+function verifyToken($token){
+    $has = Db::name("account_token")->where(["token"=>$token])->find();
+    if(!$has){
+        return ["code"=>101,"msg"=>"token不存在"];
+    }
+    if(strtotime($has['expiretime'])<=time()){
+        return ["code"=>102,"msg"=>"token已失效"];
+    }
+    $account = Db::name("account")->where(["id"=>$has['accountid'],"is_del"=>0])->find();
+    if(!$account){
+        return ["code"=>103,"msg"=>"未找到账户"];
+    }
+    if(strtotime($account['expiretime'])<=time()){
+        return ["code"=>104,"msg"=>"账户已失效"];
+    }
+    $token_str = base64_decode($token);
+    $account_str= substr($token_str,0,-10);
+    if($account_str==$account['username'].$account['salt']){
+        Db::name("account_token")->where(["token"=>$token])->update(["expiretime"=>date("Y-m-d H:i:s",time()+1800)]);
+        return ["code"=>0,"msg"=>"账户有效"];
+    }else{
+        return ["code"=>105,"msg"=>"账户token无效"];
+    }
+}

+ 5 - 0
application/Home/config.php

@@ -0,0 +1,5 @@
+<?php
+//配置文件
+return [
+
+];

+ 227 - 0
application/Home/controller/Addr.php

@@ -0,0 +1,227 @@
+<?php
+
+
+namespace app\Home\controller;
+use think\Db;
+
+class Addr extends Base
+{
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @param id 地址id
+     */
+    public function Info(){
+        $addrid = isset($this->post['id'])&&$this->post['id']!==""?$this->post['id']:"";
+        if($addrid==""){
+            return error_show(1005,"参数id 不能为空");
+        }
+        $list = Db::name("rela_addr")->alias('a')->join("addr b","a.addrid=b.id","left")->where(["
+        a.accountid"=>$this->userinfo['id'],"b.is_del"=>0,"b.id"=>$addrid])->field("b.id,b.provice,b.provice_name,b.city,
+        b.city_name,b.area,b.area_name,b.addr,b.contector,b.mobile,b.addtime")->find();
+        if(empty($list)){
+            return error_show(1004,"未找到数据");
+        }
+        return app_show(0,"获取数据成功",$list);
+    }
+
+    /**
+     * @param
+     */
+    public function list(){
+        $page = isset($this->post['page'])&&$this->post['page']!="" ? intval($this->post['page']):1;
+        $size = isset($this->post['size'])&&$this->post['size']!="" ? intval($this->post['size']):10;
+        $count= Db::name("rela_addr")->alias('a')->join("addr b","a.addrid=b.id","left")->where(["
+        a.accountid"=>$this->userinfo['id'],"b.is_del"=>0])->count();
+        $total = ceil($count/$size);
+        $page=$page>$total ? $total:$page;
+        $list = Db::name("rela_addr")->alias('a')->join("addr b","a.addrid=b.id","left")->where(["
+        a.accountid"=>$this->userinfo['id'],"b.is_del"=>0])->page($page,$size)->field("b.id,b.provice,b.provice_name,b.city,
+        b.city_name,b.area,b.area_name,b.addr,b.contector,b.mobile,b.addtime")->select();
+        return  app_show(0,"获取成功", ["list"=>$list,"count"=>$count]);
+    }
+
+    /**
+     * @param contector
+     * @param mobile
+     * @param provice
+     * @param city
+     * @param area
+     */
+    public function Add(){
+        $contector = isset($this->post['contector'])&&$this->post['contector']!=""? trim($this->post['contector']):"";
+
+        if($contector==""){
+            return error_show(1004,"参数contector 不能为空");
+        }
+        $mobile = isset($this->post['mobile'])&&$this->post['mobile']!="" ? trim($this->post['mobile']):"";
+        if($mobile==""){
+            return error_show(1005,"参数mobile 不能为空");
+        }
+        $province =  isset($this->post['provice'])&&$this->post['provice']!=""? trim($this->post['provice']):"";
+        $city =  isset($this->post['city'])&&$this->post['city']!=""? trim($this->post['city']):"";
+        $area =  isset($this->post['area'])&&$this->post['area']!=""? trim($this->post['area']):"";
+        if($province==""){
+            return error_show(1005,"参数provice 不能为空");
+        }
+        if($city==""){
+            return error_show(1005,"参数city 不能为空");
+        }
+        if($area==""){
+            return error_show(1005,"参数area 不能为空");
+        }
+        $province_info = Db::name("province")->where(['province_code'=>$province])->find();
+        if(empty($province_info)){
+            return error_show(1005,"省级数据未找到");
+        }
+       $cityinfo = Db::name("city")->where(['province_code'=>$province,"city_code"=>$city])->find();
+        if(empty($cityinfo)){
+            return error_show(1005,"市级数据未找到");
+        }
+        $areainfo = Db::name("area")->where(['area_code'=>$area,"city_code"=>$city])->find();
+        if(empty($areainfo)){
+            return error_show(1005,"区县级数据未找到");
+        }
+        $addr = isset($this->post['addr'])&&$this->post['addr']!=""?$this->post['addr']:"";
+        if($addr==""){
+            return error_show(1005,"参数addr 不能为空");
+        }
+        Db::startTrans();
+        try{
+            $data=[
+                "addr"=>$addr,
+                "provice"=>$province,
+                "provice_name"=>$province_info['name'],
+                "city"=>$city,
+                "city_name"=>$cityinfo['name'],
+                "area"=>$area,
+                "area_name"=>$areainfo['name'],
+                "contector"=>$contector,
+                "mobile"=>$mobile,
+                'status'=>1,
+                "is_del"=>0,
+                "addtime"=>date("Y-m-d H:i:s"),
+                "updatetime"=>date("Y-m-d H:i:s")
+            ];
+            $addrid =Db::name("addr")->insert($data,false,true);
+            if($addrid>0){
+                $rela = Db::name("rela_addr")->insert(['accountid'=>$this->userinfo['id'],"addrid"=>$addrid]);
+                if($rela){
+                    Db::commit();
+                    return app_show(0,"地址新建成功");
+                }
+            }
+            Db::rollback();
+            return error_show(1008,"地址新建失败");
+        }catch (\Exception $e){
+            Db::rollback();
+            return error_show(1008,$e->getMessage());
+        }
+    }
+    /**
+     * @param contector
+     * @param mobile
+     * @param provice
+     * @param city
+     * @param area
+     * @param id
+     */
+    public function Edit(){
+        $addrid = isset($this->post['id'])&&$this->post['id']!==""?$this->post['id']:"";
+        if($addrid==""){
+            return error_show(1005,"参数id 不能为空");
+        }
+        $list = Db::name("rela_addr")->alias('a')->join("addr b","a.addrid=b.id","left")->where(["
+        a.accountid"=>$this->userinfo['id'],"b.is_del"=>0,"b.id"=>$addrid])->field("b.id,b.provice,b.provice_name,b.city,
+        b.city_name,b.area,b.area_name,b.addr,b.contector,b.mobile,b.addtime")->find();
+        if(empty($list)){
+            return error_show(1004,"未找到数据");
+        }
+        $contector = isset($this->post['contector'])&&$this->post['contector']!=""? trim($this->post['contector']):"";
+        if($contector==""){
+            return error_show(1004,"参数contector 不能为空");
+        }
+        $mobile = isset($this->post['mobile'])&&$this->post['mobile']!="" ? trim($this->post['mobile']):"";
+        if($mobile==""){
+            return error_show(1005,"参数mobile 不能为空");
+        }
+        $province =  isset($this->post['provice'])&&$this->post['provice']!=""? trim($this->post['provice']):"";
+        $city =  isset($this->post['city'])&&$this->post['city']!=""? trim($this->post['city']):"";
+        $area =  isset($this->post['area'])&&$this->post['area']!=""? trim($this->post['area']):"";
+        if($province==""){
+            return error_show(1005,"参数provice 不能为空");
+        }
+        if($city==""){
+            return error_show(1005,"参数city 不能为空");
+        }
+        if($area==""){
+            return error_show(1005,"参数area 不能为空");
+        }
+        $province_info = Db::name("province")->where(['province_code'=>$province])->find();
+        if(empty($province_info)){
+            return error_show(1005,"省级数据未找到");
+        }
+        $cityinfo = Db::name("city")->where(['province_code'=>$province,"city_code"=>$city])->find();
+        if(empty($cityinfo)){
+            return error_show(1005,"市级数据未找到");
+        }
+        $areainfo = Db::name("area")->where(['area_code'=>$area,"city_code"=>$city])->find();
+        if(empty($areainfo)){
+            return error_show(1005,"区县级数据未找到");
+        }
+        $addr = isset($this->post['addr'])&&$this->post['addr']!=""?$this->post['addr']:"";
+        if($addr==""){
+            return error_show(1005,"参数addr 不能为空");
+        }
+        Db::startTrans();
+        try{
+            $data=[
+                "id"=>$addrid,
+                "addr"=>$addr,
+                "provice"=>$province,
+                "provice_name"=>$province_info['name'],
+                "city"=>$city,
+                "city_name"=>$cityinfo['name'],
+                "area"=>$area,
+                "area_name"=>$areainfo['name'],
+                "contector"=>$contector,
+                "mobile"=>$mobile,
+                "updatetime"=>date("Y-m-d H:i:s")
+            ];
+            $addrup =Db::name("addr")->update($data);
+            if($addrup){
+                    Db::commit();
+                    return app_show(0,"地址修改成功");
+            }
+            Db::rollback();
+            return error_show(1008,"地址修改失败");
+        }catch (\Exception $e){
+            Db::rollback();
+            return error_show(1008,$e->getMessage());
+        }
+    }
+
+    /**
+     * @param id 地址id
+     */
+    public function Delete(){
+        $addrid = isset($this->post['id'])&&$this->post['id']!==""?$this->post['id']:"";
+        if($addrid==""){
+            return error_show(1005,"参数id 不能为空");
+        }
+        $list = Db::name("rela_addr")->alias('a')->join("addr b","a.addrid=b.id","left")->where(["
+        a.accountid"=>$this->userinfo['id'],"b.is_del"=>0,"b.id"=>$addrid])->field("b.id,b.provice,b.provice_name,b.city,
+        b.city_name,b.area,b.area_name,b.addr,b.contector,b.mobile,b.addtime")->find();
+        if(empty($list)){
+            return error_show(1004,"未找到数据");
+        }
+        $del= Db::name("addr")->where(['id'=>$addrid])->update(["is_del"=>1,"updatetime"=>date("Y-m-d H:i:s")]);
+        if($del){
+            return app_show(0,"地址删除成功");
+        }
+        return error_show(1005,"地址删除失败");
+    }
+}

+ 57 - 0
application/Home/controller/Base.php

@@ -0,0 +1,57 @@
+<?php
+
+
+namespace app\Home\controller;
+use think\Db;
+
+
+class Base
+{
+    public $post="";
+    public $userinfo="";
+    public function __construct()
+    {
+        if(request()->isOptions()){
+            echo '';
+            die();
+        }
+        $this->post=request()->post();
+        $token = isset($this->post['token'])&&$this->post['token']!="" ? trim($this->post['token']):"";
+        if($token==""){
+            return error_show(102,"token不能为空");
+        }
+        $verify = verifyToken($token);
+        if($verify['code']!=0){
+            return error_show($verify['code'],$verify['msg']);
+        }
+        $tokeninfo = Db::name("account_token")->where(["token"=>$token])->find();
+        if(!isset($tokeninfo['accountid'])){
+            return error_show(1004,"未找到账户id");
+        }
+
+        $userinfo = Db::name("account")->alias('a')->where(["a.id"=>$tokeninfo['accountid'],'a.is_del'=>0])
+            ->join("fc_rela_account b", "a.id = b.accountid", "left")
+            ->join("fc_account_info c", "b.account_info= c.id", "left")
+            ->field("`a`.`id` AS `id`,
+	                      `a`.`username` AS `username`,
+	                      `a`.`password` AS `password`,
+	                      `a`.`salt` AS `salt`,
+	                      `a`.`status` AS `status`,
+                          `a`.`is_del` AS `is_del`,
+                          `a`.`starttime` AS `starttime`,
+                          `a`.`expiretime` AS `expiretime`,
+                          `a`.`activetime` AS `activetime`,
+                          `a`.`addtime` AS `addtime`,
+                           `c`.`nickname` AS `nickname`,
+                           `c`.`avatar` AS `avatar`,
+                           `c`.`mobile` AS `mobile`,
+                           `c`.`remark` AS `remark`,
+                           `c`.`sex` AS `sex`")
+            ->find();
+        if(empty($userinfo)){
+            return error_show(1004,"未找到账户数据");
+        }
+        $this->userinfo=$userinfo;
+    }
+
+}

+ 12 - 0
application/Home/controller/Index.php

@@ -0,0 +1,12 @@
+<?php
+namespace app\Home\controller;
+
+use think\Db;
+
+class Index
+{
+    public function index()
+    {
+
+        }
+}

+ 124 - 0
application/Home/controller/Login.php

@@ -0,0 +1,124 @@
+<?php
+
+
+namespace app\Home\controller;
+use think\Db;
+class Login
+{
+    /**
+     * @method post
+     * @param username 账户名
+     * @param password  密码
+     *
+     */
+    public function __construct(){
+        if(request()->isOptions()){
+            echo '';
+            die();
+        }
+    }
+    public function index(){
+        $post=request()->post();
+        $username = isset($post['username'])&&$post['username']!="" ? trim($post['username']) :"";
+        if($username==""){
+            return error_show(1004,"参数username 不能为空");
+        }
+        $password = isset($post['password'])&&$post['password']!="" ? trim($post['password']):"";
+        if($password==""){
+            return error_show(1004,"参数username 不能为空");
+        }
+        $account = Db::name("account")->where(["is_del"=>0,"username"=>$username])->find();
+
+        if(empty($account)){
+            return error_show(1005,"卡号不正确");
+        }
+        $pass = sha1($password.$account['salt']);
+        if($pass!=$account['password']){
+            return error_show(1006,"账户密码错误");
+        }
+        if($account['status']==2){
+            return error_show(1005,"卡号已过有效期");
+        }
+        $now =time();
+        $expire = strtotime($account['expiretime']);
+        $start = strtotime($account['starttime']);
+        if($now<$start){
+            return error_show(1005,"账户未到生效期");
+        }
+        if($now>$expire){
+            return error_show(1005,"账户已过有效期");
+        }
+        if($account['status']==0){
+            $account['status']=1;
+            $account['activetime']=date("Y-m-d H:i:s");
+            $account['updatetime']=date("Y-m-d H:i:s");
+            Db::name("account")->update($account);
+        }
+        $token = makeToken($account);
+        $userinfo = Db::name("account_info")->alias("a")->join("fc_rela_account b","b.account_info=a.id")->where(["b.accountid"=>$account['id']])->field("a.*")->find();
+        $userinfo['token'] = $token;
+        write_log("账户{$account['username']}登录系统","","homelogin","",1);
+        return app_show(0,"登录成功",$userinfo);
+    }
+
+    public function  logout(){
+        $post=request()->post();
+        $token =  isset($post['token'])&&$post['token']!="" ? trim($post['token']) :"";
+        if($token==""){
+            return error_show(101,"参数token 不能为空");
+        }
+        $verify = verifyToken($token);
+        if($verify['code']!=0){
+            return error_show($verify['code'],$verify['msg']);
+        }
+        $info = Db::name("account_token")->where(["token"=>$token])->update(['token'=>""]);
+        if($info){
+            return app_show(0,"退出成功");
+        }else{
+            return error_show(1004,"退出失败");
+        }
+    }
+
+    public function passwd(){
+        $post=request()->post();
+        $username = isset($post['username']) && $post['username'] !== "" ? $post['username'] : "";
+       // var_dump($post);
+        if($username==""){
+            return error_show(1004, "参数username不能为空");
+        }
+        $info = Db::name("account")->where(["is_del" => 0, "username" =>$username ])->find();
+        if (empty($info)) {
+            return error_show(1004, "未找到数据");
+        }
+        $pas = isset($post['pas']) && $post['pas'] !== "" ? trim($post['pas']) : "";
+      //  var_dump($pas);
+        if($pas==""){
+            return error_show(1002,"参数pas不能为空");
+        }
+//        var_dump(sha1($pas.$info['salt']));
+//        var_dump($info['password']);
+        if(sha1($pas.$info['salt'])!==$info['password']){
+            return error_show(1004, "原密码填写不正确");
+        }
+
+        $pasword = isset($post['pasword']) && $post['pasword'] !== "" ? trim($post['pasword']) : "";
+       // var_dump($pasword);
+        if($pasword===""){
+            return error_show(1004, "参数password 不能为空");
+        }
+        if ($pas==$pasword) {
+            return error_show(1004, "新密码不能与原密码相同");
+        }
+//        if (!checkPasswd($pasword)) {
+//            return error_show(1004, "密码格式不正确");
+//        }
+        $salt=makeSalt();
+        $info['salt']=$salt;
+        $info['password']=sha1($pasword . $salt);
+        $info['pwd']=$pasword;
+        $info['updatetime']=date("Y-m-d H:i:s");
+
+        $item = Db::name('account')->where(['username'=>$username,'is_del'=>0])->update($info);
+        return $item ?app_show(0,"账户密码修改成功"): error_show(1005, "账户密码修改失败");
+    }
+}

+ 260 - 0
application/Home/controller/Order.php

@@ -0,0 +1,260 @@
+<?php
+
+
+namespace app\Home\controller;
+use think\Db;
+
+class Order extends Base
+{
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * @param status 0/1/2
+     * @param page
+     * @param size
+     */
+    public function list(){
+        $page = isset($this->post['page'])&&$this->post['page']!="" ? intval($this->post['page']):1;
+        $size = isset($this->post['size'])&&$this->post['size']!="" ? intval($this->post['size']):10;
+        $status = isset($this->post['status'])&&$this->post['status']!="" ? intval($this->post['status']):0;
+        $where=["a.is_del"=>0,"a.accountid"=>$this->userinfo['id']];
+        if($status!=0 && in_array($status,[1,2])){
+            $where['a.status']=$status;
+        }
+        $count =Db::name("order a")->where($where)->count();
+        $total = ceil($count/$size);
+        $page = $page>$total?$total:$page;
+        $list = Db::name("order a")->where($where)->page($page,$size)
+            ->join("fc_order_post b","a.`order_sn` = `b`.`order_sn`","left")
+            ->join("fc_addr c","`b`.`addrid` = `c`.`id`","left")
+            ->join("fc_account e","a.`accountid` = `e`.`id`","left")
+            ->join("fc_rela_account f","a.`accountid` = `f`.`accountid`","left")
+            ->join("fc_account_info g","`f`.`account_info` = `g`.`id`","left")
+            ->field("a.id AS id,
+	a.`order_sn` AS `order_sn`,
+	a.`accountid` AS `accountid`,
+	a.`order_num` AS `order_num`,
+	a.`status` AS `status`,
+	a.`is_del` AS `is_del`,
+	a.`delivery_time` AS `delivery_time`,
+	a.`order_time` AS `order_time`,
+	`b`.`addrid` AS `addrid`,
+	`b`.`order_num` AS `border_num`,
+	`b`.`post_code` AS `post_code`,
+	`b`.`post_name` AS `post_name`,
+	`b`.`status` AS `bstatus`,
+	`c`.`addr` AS `addr`,
+	`c`.`provice` AS `provice`,
+	`c`.`city` AS `city`,
+	`c`.`provice_name` AS `provice_name`,
+	`c`.`city_name` AS `city_name`,
+	`c`.`area` AS `area`,
+	`c`.`area_name` AS `area_name`,
+	`c`.`contector` AS `contector`,
+	`c`.`mobile` AS `contector_mobile`,
+	`e`.`username` AS `username`,
+	`g`.`nickname` AS `nickname`,
+	`g`.`mobile` AS `mobile`,
+	a.`unit_weight` AS `unit_weight`,
+	a.`unit` AS `unit`")->select();
+        return app_show(0,"获取成功",["list"=>$list,"count"=>$count]);
+    }
+
+    /**
+     * @param id 订单id
+     */
+
+    public function info(){
+        $id = isset($this->post['id'])&&$this->post['id']!="" ? intval($this->post['id']):"";
+        if($id==""){
+            return error_show(1004,"参数id 不能为空");
+        }
+
+        $order = Db::name("order")->alias('a')->where(["a.is_del"=>0,"a.accountid"=>$this->userinfo['id'],"a.id"=>$id])
+
+            ->join("fc_order_post b","a.order_sn =b.order_sn","left")
+            ->join("fc_addr c","b.addrid= c.id","left")
+            ->join("fc_account e","a.accountid= e.id","left")
+            ->join("fc_rela_account f","a.accountid = f.accountid","left")
+            ->join("fc_account_info g","f.account_info = g.id","left")
+            ->field("`a`.`id` AS `id`,
+                        `a`.`order_sn` AS `order_sn`,
+                        `a`.`accountid` AS `accountid`,
+                        `a`.`order_num` AS `order_num`,
+                        `a`.`status` AS `status`,
+                        `a`.`is_del` AS `is_del`,
+                        `a`.`delivery_time` AS `delivery_time`,
+                        `a`.`order_time` AS `order_time`,
+                        `b`.`addrid` AS `addrid`,
+                        `b`.`order_num` AS `border_num`,
+                        `b`.`post_code` AS `post_code`,
+                        `b`.`post_name` AS `post_name`,
+                        `b`.`status` AS `bstatus`,
+                        `c`.`addr` AS `addr`,
+                        `c`.`provice` AS `provice`,
+                        `c`.`city` AS `city`,
+                        `c`.`provice_name` AS `provice_name`,
+                        `c`.`city_name` AS `city_name`,
+                        `c`.`area` AS `area`,
+                        `c`.`area_name` AS `area_name`,
+                        `c`.`contector` AS `contector`,
+                        `c`.`mobile` AS `contector_mobile`,
+                        `e`.`username` AS `username`,
+                        `g`.`nickname` AS `nickname`,
+                        `g`.`mobile` AS `mobile`,
+                        `a`.`unit_weight` AS `unit_weight`,
+                        `a`.`unit` AS `unit` ")
+            ->find();
+        //var_dump($order);
+        if(empty($order)){
+            return error_show(1005,"未找到订单数据");
+        }
+        return app_show(0,"获取成功",$order);
+    }
+
+    /**
+     * @param  num
+     * @param  addrid
+     */
+    public function ist(){
+      $ist = Db::name('unit')->where(["is_del" => 0,"status"=>1])->field("id,name,weight")->select();
+      return app_show(0,"获取成功",["list"=>$ist]);
+    }
+    public function add(){
+        $num = isset($this->post['num'])&&$this->post['num']!="" ? intval($this->post['num']):"";
+        if($num==""){
+            return error_show(1004,"参数num 不能为空或0");
+        }
+        $id = isset($this->post['unit_id'])&&$this->post['unit_id']!=""? intval($this->post['unit_id']): "";
+        if($id==""){
+            return error_show(1004,"unit_id不能为空");
+        }
+        $kg= Db::name('unit')->where(["is_del" => 0,"id"=>$id,"status"=>1])->field("id,name,weight,limit_num")->find();
+       // var_dump(Db::name('unit')->where(["is_del" => 0,"id"=>$id,"status"=>1])->getLastSql());
+        if(empty($kg)){
+            return error_show(1004,"单位不能为空");
+        }
+        $count=$num*$kg['weight'];
+        if($count==""){
+            return error_show(1004,"购买数量不能为空");
+        }
+        if($kg['limit_num']>0){
+            $zl = Db::name('order_log')->where(["unit_id"=>$id,"accountid"=>$this->userinfo['id']])->sum('num');
+          // var_dump(Db::name('order_log')->getLastSql());
+
+            if($zl+$num>$kg['limit_num']){
+                $jf = $kg['limit_num']>=$zl ?$kg['limit_num']-$zl :0;
+                return error_show(1004,"购买数量超过限额,可购数量{$jf}{$kg['name']}");
+            }
+
+        }
+
+        $addrid = isset($this->post['addrid'])&&$this->post['addrid']!="" ? intval($this->post['addrid']):"";
+        if($addrid==""){
+            return error_show(1004,"参数addrid 不能为空");
+        }
+        $stock = Db::name("account_stock")->where(['is_del'=>0,"accountid"=>$this->userinfo['id']])->find();
+        if(empty($stock) || $stock['stock_balance']<$count){
+            return error_show(1004,"库存数量不足");
+        }
+        $addr =Db::name("rela_addr")->alias('a')->join("addr b","a.addrid=b.id","left")->where(["a.accountid"=>$this->userinfo['id'],
+            "b.is_del"=>0,"b.id"=>$addrid])->field("b.id,b.provice,b.provice_name,b.city,b.city_name,b.area,b.area_name,b.addr,b.contector,b.mobile,b.addtime")->find();
+        if(empty($addr)){
+            return error_show(1004,"地址数据未找到");
+        }
+        Db::startTrans();
+        try{
+            $ordersn =makeNo("FC");
+            $data=[
+                "order_sn"=>$ordersn,
+                "accountid"=>$this->userinfo['id'],
+                "order_num"=>$num,
+                "unit"=>$kg['name'],
+                "unit_weight"=>$kg['weight'],
+                "is_del"=>0,
+                "status"=>1,
+                "addtime"=>date("Y-m-d H:i:s"),
+                "updatetime"=>date("Y-m-d H:i:s"),
+                "order_time"=>date("Y-m-d H:i:s"),
+            ];
+            $ordercreate= Db::name("order")->insert($data,false,true);
+            if($ordercreate>0){
+                $post =[
+                    "order_sn"=>$ordersn,
+                    "addrid"=>$addrid,
+                    "order_num"=>$num,
+                    'post_code'=>"",
+                    'post_name'=>"",
+                    "status"=>1,
+                    "is_del"=>0,
+                    "addtime"=>date("Y-m-d H:i:s"),
+                    "updatetime"=>date("Y-m-d H:i:s")
+                ];
+                $orderpost=Db::name("order_post")->insert($post);
+                if($orderpost){
+                   $updatestock= Db::name("account_stock")->where($stock)->update
+                    (['stock_balance'=>$stock['stock_balance']-$count,
+                        "stock_delivery"=>$stock['stock_delivery']+$count,"updatetime"=>date("Y-m-d H:i:s")]);
+                   if($updatestock){
+                       $log=[
+                           "accountid"=>$this->userinfo['id'],
+                           "run_stock"=>$count,
+                           "type"=>3,
+                           "after_stock"=>$stock['stock_balance']-$count,
+                           "before_stock"=>$stock['stock_balance'],
+                           "action_uid"=>$this->userinfo['id'],
+                           "action_name"=>$this->userinfo['nickname'],
+                           "addtime"=>date("Y-m-d H:i:s"),
+
+                       ];
+                       $stocklog =Db::name("stock_log")->insert($log);
+                       $log=[
+                           "accountid"=>$this->userinfo['id'],
+                           "addtime"=>date("Y-m-d H:i:s"),
+                            "unit"=>$kg['name'],
+                           "unit_weight"=>$kg['weight'],
+                           "num"=>$num,
+                           "total_weight"=>$num*$kg['weight'],
+                           "unit_id"=>$kg['id']
+                       ];
+                       $st =Db::name("order_log")->insert($log);
+                       if($stocklog && $st){
+                           Db::commit();
+                           return app_show(0,"下单成功",['orderid'=>$ordercreate]);
+                       }
+                   }
+                }
+            }
+            Db::rollback();
+            return error_show(1006,"下单失败");
+        }catch (\Exception $e){
+            Db::rollback();
+            return error_show(1005,$e->getMessage());
+        }
+    }
+
+    public function Stock(){
+        $stock = Db::name("account_stock")->where(["accountid"=>$this->userinfo['id'],'is_del'=>0])->find();
+        $data=[];
+        $data['stock'] = isset($stock['stock_balance']) ? $stock['stock_balance']:0;
+        $unit = Db::name('unit')->where(['is_del'=>0,'status'=>1])->field("id,name,weight,limit_num")->select();
+        $limit=[];
+        foreach ($unit as $value){
+            $zl =0;
+            $num = intval($data['stock']/$value['weight']);
+            if($value['limit_num']>0){
+                $zl = Db::name('order_log')->where(["unit_id"=>$value['id'],"accountid"=>$this->userinfo['id']])->sum('num');
+                $value['limit_num']>$zl?$value['limit_num'] -= $zl:$value['limit_num']=0;
+                $value['limit_num'] = $value['limit_num']>$num  ? $num : $value['limit_num'];
+            }else{
+                $value['limit_num'] = $num ;
+            }
+            $limit[]=$value;
+        }
+        $data['limit']=$limit;
+        return app_show(0,"获取成功",$data);
+    }
+}

+ 28 - 0
application/Home/controller/User.php

@@ -0,0 +1,28 @@
+<?php
+
+
+namespace app\Home\controller;
+use think\Db;
+
+class User extends Base
+{
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    public function Info(){
+        return app_show(0,"获取成功",$this->userinfo);
+    }
+
+    /**
+     * @param 地址列表
+     */
+    public function AddrList(){
+        $list = Db::name("rela_addr")->alias('a')->join("addr as b","a.addrid=b.id","left")->where(["a
+        .accountid"=>$this->userinfo['id'],"b.is_del"=>0])->select();
+        return  app_show(0,"获取成功", $list);
+    }
+
+
+}

+ 41 - 0
application/Home/controller/Vdlist.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace app\Home\controller;
+
+use think\Db;
+class Vdlist extends Base
+{
+//    public $post="";
+//    public $userinfo="";
+    public function __construct()
+    {
+         parent:: __construct();
+//        $post=request()->post();
+//        $this->post=$post;
+    }
+    public function obtainlist(){
+        $page = isset($this->post['page'])&&$this->post['page']!="" ? intval($this->post['page']):1;
+        $size = isset($this->post['size'])&&$this->post['size']!="" ? intval($this->post['size']):10;
+        $where = ["b.is_del"=>0,'a.accountid'=>$this->userinfo['id'],"a.is_del"=>0,"b.status"=>1,"a.status"=>1];
+        $count = Db::name("rela_video")->alias('a')->join("video b","a.video_id=b.id","left")->where($where)->count();
+        //var_dump(Db::name("rela_video")->getLastSql());
+        $total = ceil($count/$size);
+        $page = $page>$total?$total:$page;
+        //var_dump(Db::name("rela_video")->getLastSql());
+        $list = Db::name("rela_video")->alias('a')->join("video b","a.video_id=b.id","left")->where($where)->page($page,$size)->field("b.id,b.video_sn,b.video_name,b.video_url,b.video_img,b.remark")->select();
+        return app_show(0,"视频列表获取成功",["list"=>$list,"count"=>$count]);
+
+    }
+    public function preview(){
+        $id = isset($this->post['id'])&&$this->post['id']!="" ? intval($this->post['id']):"";
+
+        $where = ['b.id'=>$id,'a.accountid'=>$this->userinfo['id'],'b.is_del'=>0,'b.status'=>1,'a.is_del'=>0,'a.status'=>1];
+
+        $look = Db::name("rela_video")->alias('a')->join("video b","a.video_id=b.id","left")->where($where)->field("b.id,b.video_sn,b.video_name,b.video_url,b.video_img,b.remark")->find();
+       // var_dump(Db::name("rela_video")->getLastSql());
+        if($look==false){
+            return error_show(1002,"预览失败");
+        }else
+            return app_show(0,"预览成功",$look);
+    }
+}

+ 9 - 0
application/Home/model/User.php

@@ -0,0 +1,9 @@
+<?php
+namespace app\Home\model;
+
+use think\Model;
+
+class User extends Model
+{
+
+}

+ 14 - 0
application/command.php

@@ -0,0 +1,14 @@
+<?php
+// +----------------------------------------------------------------------
+// | ThinkPHP [ WE CAN DO IT JUST THINK ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+// +----------------------------------------------------------------------
+// | Author: yunwuxin <448901948@qq.com>
+// +----------------------------------------------------------------------
+
+return [
+    "app\admin\command\Test"
+];

+ 96 - 0
application/common.php

@@ -0,0 +1,96 @@
+<?php
+// +----------------------------------------------------------------------
+// | ThinkPHP [ WE CAN DO IT JUST THINK ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+// +----------------------------------------------------------------------
+// | Author: 流年 <liu21st@gmail.com>
+// +----------------------------------------------------------------------
+use think\Db;
+// 应用公共文件
+
+function makeSalt(){
+    $str =rand(100000,999999);
+    return $str;
+}
+
+/**
+ * @param $file
+ * @return string
+ */
+function uplaod_avatar($file){
+    // 移动到框架应用根目录/public/uploads/ 目录下
+    $info = $file->validate(['size'=>15678,'ext'=>'jpg,png,gif'])->move(ROOT_PATH . 'public' . DS . 'uploads/avatar');
+    if($info){
+          return $info->getSaveName();
+        }else{
+          return "";
+    }
+}
+
+/**
+ * 日志记录
+ * @param $log
+ * @param $id
+ */
+function write_log($log,$userinfo,$module="",$action="",$role=0){
+
+    $data=[
+        "action_id"=>isset($userinfo['id'])? $userinfo['id']:"",
+        "msg"=>$log,
+        "addtime"=>date("y-m-d H:i:s"),
+        "action_name"=>isset($userinfo['nickname'])? $userinfo['nickname']:"sys",
+        "module"=>$module,
+        "action"=>$action,
+        "username"=>isset($userinfo['username'])? $userinfo['username']:"sys",
+        "role"=>$role==0?(isset($userinfo['role_id'])&&$userinfo['role_id']!=0?$userinfo['role_id']:0):3,
+    ];
+    Db::name("system_log")->insert($data);
+}
+
+/**
+ * @param $code
+ * @param $msg
+ */
+function error_show($code,$msg=""){
+    $data = [
+        "code"=>$code,
+        "msg"=>$msg
+    ];
+
+    echo  json_encode($data);
+die();
+}
+
+/**
+ * @param $code
+ * @param string $msg
+ * @param array $list
+ */
+function app_show($code,$msg="",$list=[]){
+    $data = [
+        "code"=>$code,
+        "msg"=>$msg,
+        "data"=>$list
+    ];
+    echo  json_encode($data);
+die();
+}
+function makeNo($str){
+
+    $date=date("mdHis");
+    $year = date("Y")-2000;
+    $msec=randomkeys(4);
+    return $str.$msec.$year.$date;
+}
+function randomkeys($length) {
+    $returnStr='';
+    $pattern = '1234567890abcdefghijklmnopqrstuvwxyz';//ABCDEFGHIJKLOMNOPQRSTUVWXYZ
+
+    for($i = 0; $i < $length; $i ++) {
+        $returnStr .= $pattern[mt_rand ( 0, strlen($pattern)-1 )]; //生成php随机数
+    }
+    return $returnStr;
+}

+ 243 - 0
application/config.php

@@ -0,0 +1,243 @@
+<?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>
+// +----------------------------------------------------------------------
+
+return [
+    // +----------------------------------------------------------------------
+    // | 应用设置
+    // +----------------------------------------------------------------------
+
+    // 应用调试模式
+    'app_debug'              => false,
+    // 应用Trace
+    'app_trace'              => false,
+    // 应用模式状态
+    'app_status'             => '',
+    // 是否支持多模块
+    'app_multi_module'       => true,
+    // 入口自动绑定模块
+    'auto_bind_module'       => false,
+    // 注册的根命名空间
+    'root_namespace'         => [],
+    // 扩展函数文件
+    'extra_file_list'        => [THINK_PATH . 'helper' . EXT],
+    // 默认输出类型
+    'default_return_type'    => 'html',
+    // 默认AJAX 数据返回格式,可选json xml ...
+    'default_ajax_return'    => 'json',
+    // 默认JSONP格式返回的处理方法
+    'default_jsonp_handler'  => 'jsonpReturn',
+    // 默认JSONP处理方法
+    'var_jsonp_handler'      => 'callback',
+    // 默认时区
+    'default_timezone'       => 'PRC',
+    // 是否开启多语言
+    'lang_switch_on'         => false,
+    // 默认全局过滤方法 用逗号分隔多个
+    'default_filter'         => '',
+    // 默认语言
+    'default_lang'           => 'zh-cn',
+    // 应用类库后缀
+    'class_suffix'           => false,
+    // 控制器类后缀
+    'controller_suffix'      => false,
+
+    // +----------------------------------------------------------------------
+    // | 模块设置
+    // +----------------------------------------------------------------------
+
+    // 默认模块名
+    'default_module'         => 'Home',
+    // 禁止访问模块
+    'deny_module_list'       => ['common'],
+    // 默认控制器名
+    'default_controller'     => 'Index',
+    // 默认操作名
+    'default_action'         => 'index',
+    // 默认验证器
+    'default_validate'       => '',
+    // 默认的空控制器名
+    'empty_controller'       => 'Error',
+    // 操作方法后缀
+    'action_suffix'          => '',
+    // 自动搜索控制器
+    'controller_auto_search' => false,
+
+    // +----------------------------------------------------------------------
+    // | URL设置
+    // +----------------------------------------------------------------------
+
+    // PATHINFO变量名 用于兼容模式
+    'var_pathinfo'           => 's',
+    // 兼容PATH_INFO获取
+    'pathinfo_fetch'         => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'],
+    // pathinfo分隔符
+    'pathinfo_depr'          => '/',
+    // URL伪静态后缀
+    'url_html_suffix'        => 'html',
+    // URL普通方式参数 用于自动生成
+    'url_common_param'       => false,
+    // URL参数方式 0 按名称成对解析 1 按顺序解析
+    'url_param_type'         => 0,
+    // 是否开启路由
+    'url_route_on'           => true,
+    // 路由使用完整匹配
+    'route_complete_match'   => false,
+    // 路由配置文件(支持配置多个)
+    'route_config_file'      => ['route'],
+    // 是否开启路由解析缓存
+    'route_check_cache'      => false,
+    // 是否强制使用路由
+    'url_route_must'         => false,
+    // 域名部署
+    'url_domain_deploy'      => false,
+    // 域名根,如thinkphp.cn
+    'url_domain_root'        => '',
+    // 是否自动转换URL中的控制器和操作名
+    'url_convert'            => true,
+    // 默认的访问控制器层
+    'url_controller_layer'   => 'controller',
+    // 表单请求类型伪装变量
+    'var_method'             => '_method',
+    // 表单ajax伪装变量
+    'var_ajax'               => '_ajax',
+    // 表单pjax伪装变量
+    'var_pjax'               => '_pjax',
+    // 是否开启请求缓存 true自动缓存 支持设置请求缓存规则
+    'request_cache'          => false,
+    // 请求缓存有效期
+    'request_cache_expire'   => null,
+    // 全局请求缓存排除规则
+    'request_cache_except'   => [],
+
+    // +----------------------------------------------------------------------
+    // | 模板设置
+    // +----------------------------------------------------------------------
+
+    'template'               => [
+        // 模板引擎类型 支持 php think 支持扩展
+        'type'         => 'Think',
+        // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写
+        'auto_rule'    => 1,
+        // 模板路径
+        'view_path'    => '',
+        // 模板后缀
+        'view_suffix'  => 'html',
+        // 模板文件名分隔符
+        'view_depr'    => DS,
+        // 模板引擎普通标签开始标记
+        'tpl_begin'    => '{',
+        // 模板引擎普通标签结束标记
+        'tpl_end'      => '}',
+        // 标签库标签开始标记
+        'taglib_begin' => '{',
+        // 标签库标签结束标记
+        'taglib_end'   => '}',
+    ],
+
+    // 视图输出字符串内容替换
+    'view_replace_str'       => [],
+    // 默认跳转页面对应的模板文件
+    'dispatch_success_tmpl'  => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl',
+    'dispatch_error_tmpl'    => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl',
+
+    // +----------------------------------------------------------------------
+    // | 异常及错误设置
+    // +----------------------------------------------------------------------
+
+    // 异常页面的模板文件
+    'exception_tmpl'         => THINK_PATH . 'tpl' . DS . 'think_exception.tpl',
+
+    // 错误显示信息,非调试模式有效
+    'error_message'          => '页面错误!请稍后再试~',
+    // 显示错误信息
+    'show_error_msg'         => false,
+    // 异常处理handle类 留空使用 \think\exception\Handle
+    'exception_handle'       => '',
+
+    // +----------------------------------------------------------------------
+    // | 日志设置
+    // +----------------------------------------------------------------------
+
+    'log'                    => [
+        // 日志记录方式,内置 file socket 支持扩展
+        'type'  => 'File',
+        // 日志保存目录
+        'path'  => LOG_PATH,
+        // 日志记录级别
+        'level' => [],
+    ],
+
+    // +----------------------------------------------------------------------
+    // | Trace设置 开启 app_trace 后 有效
+    // +----------------------------------------------------------------------
+    'trace'                  => [
+        // 内置Html Console 支持扩展
+        'type' => 'Html',
+    ],
+
+    // +----------------------------------------------------------------------
+    // | 缓存设置
+    // +----------------------------------------------------------------------
+
+    'cache'                  => [
+        // 驱动方式
+        'type'   => 'File',
+        // 缓存保存目录
+        'path'   => CACHE_PATH,
+        // 缓存前缀
+        'prefix' => '',
+        // 缓存有效期 0表示永久缓存
+        'expire' => 0,
+    ],
+
+    // +----------------------------------------------------------------------
+    // | 会话设置
+    // +----------------------------------------------------------------------
+
+    'session'                => [
+        'id'             => '',
+        // SESSION_ID的提交变量,解决flash上传跨域
+        'var_session_id' => '',
+        // SESSION 前缀
+        'prefix'         => 'think',
+        // 驱动方式 支持redis memcache memcached
+        'type'           => '',
+        // 是否自动开启 SESSION
+        'auto_start'     => true,
+    ],
+
+    // +----------------------------------------------------------------------
+    // | Cookie设置
+    // +----------------------------------------------------------------------
+    'cookie'                 => [
+        // cookie 名称前缀
+        'prefix'    => '',
+        // cookie 保存时间
+        'expire'    => 0,
+        // cookie 保存路径
+        'path'      => '/',
+        // cookie 有效域名
+        'domain'    => '',
+        //  cookie 启用安全传输
+        'secure'    => false,
+        // httponly设置
+        'httponly'  => '',
+        // 是否使用 setcookie
+        'setcookie' => true,
+    ],
+
+    //分页配置
+    'paginate'               => [
+        'type'      => 'bootstrap',
+        'var_page'  => 'page',
+        'list_rows' => 15,
+    ],
+];

+ 55 - 0
application/database.php

@@ -0,0 +1,55 @@
+<?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>
+// +----------------------------------------------------------------------
+
+return [
+    // 数据库类型
+    'type'            => 'mysql',
+    // 服务器地址
+    'hostname'        => '123.60.220.71',
+    // 数据库名
+    'database'        => 'fivechang',
+    // 用户名
+    'username'        => 'fivechang',
+    // 密码
+    'password'        => 'fivechang123',
+    // 端口
+    'hostport'        => '3306',
+    // 连接dsn
+    'dsn'             => '',
+    // 数据库连接参数
+    'params'          => [],
+    // 数据库编码默认采用utf8
+    'charset'         => 'utf8',
+    // 数据库表前缀
+    'prefix'          => 'fc_',
+    // 数据库调试模式
+    'debug'           => true,
+    // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
+    'deploy'          => 0,
+    // 数据库读写是否分离 主从式有效
+    'rw_separate'     => false,
+    // 读写分离后 主服务器数量
+    'master_num'      => 1,
+    // 指定从服务器序号
+    'slave_no'        => '',
+    // 自动读取主库数据
+    'read_master'     => false,
+    // 是否严格检查字段是否存在
+    'fields_strict'   => true,
+    // 数据集返回类型
+    'resultset_type'  => 'array',
+    // 自动写入时间戳字段
+    'auto_timestamp'  => false,
+    // 时间字段取出后的默认时间格式
+    'datetime_format' => 'Y-m-d H:i:s',
+    // 是否需要进行SQL性能分析
+    'sql_explain'     => false,
+];

+ 84 - 0
application/route.php

@@ -0,0 +1,84 @@
+<?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\Route;
+// 注册路由到index模块的News控制器的read操作
+
+Route::rule('admin/login',
+    'Admin/Login/index');
+Route::rule('admin/logout','Admin/Login/logout');
+Route::rule('admin/version','Admin/Login/LastVersion');
+
+Route::rule('admin/menulist', 'Admin/Menu/MenuList');
+Route::rule('admin/menuadd', 'Admin/Menu/MenuAdd');
+Route::rule('admin/menusave', 'Admin/Menu/MenuEdit');
+Route::rule('admin/menudel', 'Admin/Menu/MenuDel');
+Route::rule('admin/menustatus', 'Admin/Menu/MenuStatus');
+Route::rule('admin/menuaction', 'Admin/Menu/ActionMenu');
+Route::rule('admin/menuactionsave', 'Admin/Menu/ActionSave');
+Route::rule('admin/menuactionstatus', 'Admin/Menu/ActionStatus');
+Route::rule('admin/menuactiondel', 'Admin/Menu/ActionDel');
+Route::rule('admin/menuactionadd', 'Admin/Menu/ActionAdd');
+Route::rule('admin/menuall', 'Admin/Menu/MenuAll');
+
+Route::rule('admin/reset','Admin/User/ResetInfo');
+Route::rule('admin/userinfo','Admin/User/UserInfo');
+
+Route::rule('admin/accountinfo','Admin/Account/Read');
+Route::rule('admin/accountlist','Admin/Account/List');
+Route::rule('admin/accountadd','Admin/Account/Create');
+Route::rule('admin/accountsave','Admin/Account/Save');
+Route::rule('admin/checkpwd','Admin/Account/checkPwd');
+
+Route::rule('admin/orderlist','Admin/Order/list');
+Route::rule('admin/orderdelivery','Admin/Order/OrderDelivery');
+Route::rule('admin/orderupload','Admin/Order/uploud');
+
+Route::rule('admin/stocklist','Admin/Stock/StockList');
+Route::rule('admin/stocksave','Admin/Stock/Save');
+Route::rule('admin/stocklog','Admin/Stock/StockLog');
+
+Route::rule('admin/versionlist','Admin/Version/list');
+Route::rule('admin/versionadd','Admin/Version/create');
+
+Route::rule('admin/systemlist','Admin/System/list');
+Route::rule('admin/getmoudel','Admin/System/GetMenu');
+Route::rule('admin/getaction','Admin/System/GetAction');
+Route::rule('admin/Video','Admin/Stock2/Video');
+Route::rule('admin/Create','Admin/Stock2/Create');
+Route::rule('admin/Delete','Admin/Stock2/Delete');
+Route::rule('admin/Read','Admin/Stock2/Read');
+Route::rule("admin/Change","Admin/Stock2/Change");
+Route::rule("admin/Edit","Admin/Stock2/Edit");
+Route::rule('admin/upload',"Admin/Upload/Index");
+
+Route::rule('admin/expire','Admin/Expire/update');
+
+Route::rule("home/login","Home/Login/index");
+
+Route::rule("home/userinfo","Home/User/info");
+Route::rule('home/password','Home/Login/passwd');
+
+Route::rule("home/addrlist","Home/Addr/list");
+Route::rule("home/addrinfo","Home/Addr/Info");
+Route::rule("home/addradd","Home/Addr/Add");
+Route::rule("home/addredit","Home/Addr/Edit");
+Route::rule("home/addrdel","Home/Addr/Delete");
+
+Route::rule("home/orderlist","Home/Order/list");
+Route::rule("home/unitist","Home/Order/Ist");
+Route::rule("home/orderinfo","Home/Order/info");
+Route::rule("home/orderadd","Home/Order/add");
+Route::rule("home/orderstock","Home/Order/Stock");
+Route::rule("home/obtainlist","Home/Vdlist/Obtainlist");
+Route::rule("home/preview","Home/Vdlist/Preview");
+
+

+ 28 - 0
application/tags.php

@@ -0,0 +1,28 @@
+<?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>
+// +----------------------------------------------------------------------
+
+// 应用行为扩展定义文件
+return [
+    // 应用初始化
+    'app_init'     => [],
+    // 应用开始
+    'app_begin'    => [],
+    // 模块初始化
+    'module_init'  => [],
+    // 操作开始执行
+    'action_begin' => [],
+    // 视图内容过滤
+    'view_filter'  => [],
+    // 日志写入
+    'log_write'    => [],
+    // 应用结束
+    'app_end'      => [],
+];

+ 29 - 0
build.php

@@ -0,0 +1,29 @@
+<?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>
+// +----------------------------------------------------------------------
+
+return [
+    // 生成应用公共文件
+    '__file__' => ['common.php', 'config.php', 'database.php'],
+
+    'Home'     => [
+        '__file__'   => ['common.php'],
+        '__dir__'    => ['behavior', 'controller', 'model'],
+        'controller' => ['Index'],
+        'model'      => ['User'],
+    ],
+    'Admin'     => [
+        '__file__'   => ['common.php'],
+        '__dir__'    => ['behavior', 'controller', 'model'],
+        'controller' => ['Index'],
+        'model'      => ['User'],
+    ],
+    // 其他更多的模块定义
+];

+ 37 - 0
composer.json

@@ -0,0 +1,37 @@
+{
+    "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"
+        }
+    ],
+    "require": {
+        "php": ">=5.4.0",
+        "topthink/framework": "5.0.*",
+        "phpoffice/phpexcel": "^1.8"
+    },
+    "autoload": {
+        "psr-4": {
+            "app\\": "application"
+        }
+    },
+    "extra": {
+        "think-path": "thinkphp"
+    },
+    "config": {
+        "preferred-install": "dist",
+        "allow-plugins": {
+            "topthink/think-installer": true
+        }
+    }
+}

+ 206 - 0
composer.lock

@@ -0,0 +1,206 @@
+{
+    "_readme": [
+        "This file locks the dependencies of your project to a known state",
+        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+        "This file is @generated automatically"
+    ],
+    "content-hash": "638eddbd80e05c03658dbc79fd48239b",
+    "packages": [
+        {
+            "name": "phpoffice/phpexcel",
+            "version": "1.8.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/PHPOffice/PHPExcel.git",
+                "reference": "1441011fb7ecdd8cc689878f54f8b58a6805f870"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/PHPOffice/PHPExcel/zipball/1441011fb7ecdd8cc689878f54f8b58a6805f870",
+                "reference": "1441011fb7ecdd8cc689878f54f8b58a6805f870",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "ext-mbstring": "*",
+                "ext-xml": "*",
+                "ext-xmlwriter": "*",
+                "php": "^5.2|^7.0"
+            },
+            "require-dev": {
+                "squizlabs/php_codesniffer": "2.*"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "PHPExcel": "Classes/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "LGPL-2.1"
+            ],
+            "authors": [
+                {
+                    "name": "Maarten Balliauw",
+                    "homepage": "http://blog.maartenballiauw.be"
+                },
+                {
+                    "name": "Erik Tilt"
+                },
+                {
+                    "name": "Franck Lefevre",
+                    "homepage": "http://rootslabs.net"
+                },
+                {
+                    "name": "Mark Baker",
+                    "homepage": "http://markbakeruk.net"
+                }
+            ],
+            "description": "PHPExcel - OpenXML - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine",
+            "homepage": "https://github.com/PHPOffice/PHPExcel",
+            "keywords": [
+                "OpenXML",
+                "excel",
+                "php",
+                "spreadsheet",
+                "xls",
+                "xlsx"
+            ],
+            "support": {
+                "issues": "https://github.com/PHPOffice/PHPExcel/issues",
+                "source": "https://github.com/PHPOffice/PHPExcel/tree/master"
+            },
+            "abandoned": "phpoffice/phpspreadsheet",
+            "time": "2018-11-22T23:07:24+00:00"
+        },
+        {
+            "name": "topthink/framework",
+            "version": "v5.0.24",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/top-think/framework.git",
+                "reference": "c255c22b2f5fa30f320ecf6c1d29f7740eb3e8be"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/top-think/framework/zipball/c255c22b2f5fa30f320ecf6c1d29f7740eb3e8be",
+                "reference": "c255c22b2f5fa30f320ecf6c1d29f7740eb3e8be",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "php": ">=5.4.0",
+                "topthink/think-installer": "~1.0"
+            },
+            "require-dev": {
+                "johnkary/phpunit-speedtrap": "^1.0",
+                "mikey179/vfsstream": "~1.6",
+                "phpdocumentor/reflection-docblock": "^2.0",
+                "phploc/phploc": "2.*",
+                "phpunit/phpunit": "4.8.*",
+                "sebastian/phpcpd": "2.*"
+            },
+            "type": "think-framework",
+            "autoload": {
+                "psr-4": {
+                    "think\\": "library/think"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache-2.0"
+            ],
+            "authors": [
+                {
+                    "name": "liu21st",
+                    "email": "liu21st@gmail.com"
+                }
+            ],
+            "description": "the new thinkphp framework",
+            "homepage": "http://thinkphp.cn/",
+            "keywords": [
+                "framework",
+                "orm",
+                "thinkphp"
+            ],
+            "support": {
+                "issues": "https://github.com/top-think/framework/issues",
+                "source": "https://github.com/top-think/framework/tree/master"
+            },
+            "time": "2019-01-11T08:04:58+00:00"
+        },
+        {
+            "name": "topthink/think-installer",
+            "version": "v1.0.14",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/top-think/think-installer.git",
+                "reference": "eae1740ac264a55c06134b6685dfb9f837d004d1"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/top-think/think-installer/zipball/eae1740ac264a55c06134b6685dfb9f837d004d1",
+                "reference": "eae1740ac264a55c06134b6685dfb9f837d004d1",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "composer-plugin-api": "^1.0||^2.0"
+            },
+            "require-dev": {
+                "composer/composer": "^1.0||^2.0"
+            },
+            "type": "composer-plugin",
+            "extra": {
+                "class": "think\\composer\\Plugin"
+            },
+            "autoload": {
+                "psr-4": {
+                    "think\\composer\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache-2.0"
+            ],
+            "authors": [
+                {
+                    "name": "yunwuxin",
+                    "email": "448901948@qq.com"
+                }
+            ],
+            "support": {
+                "issues": "https://github.com/top-think/think-installer/issues",
+                "source": "https://github.com/top-think/think-installer/tree/v1.0.14"
+            },
+            "time": "2021-03-25T08:34:02+00:00"
+        }
+    ],
+    "packages-dev": [],
+    "aliases": [],
+    "minimum-stability": "stable",
+    "stability-flags": [],
+    "prefer-stable": false,
+    "prefer-lowest": false,
+    "platform": {
+        "php": ">=5.4.0"
+    },
+    "platform-dev": [],
+    "plugin-api-version": "2.2.0"
+}

+ 2 - 0
extend/.gitignore

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

+ 0 - 0
public/.htaccess


BIN
public/favicon.ico


+ 19 - 0
public/index.php

@@ -0,0 +1,19 @@
+<?php
+// +----------------------------------------------------------------------
+// | ThinkPHP [ WE CAN DO IT JUST THINK ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+// +----------------------------------------------------------------------
+// | Author: liu21st <liu21st@gmail.com>
+// +----------------------------------------------------------------------
+
+// [ 应用入口文件 ]
+header('Access-Control-Allow-Origin:*');
+header('Access-Control-Allow-Methods:POST,GET,OPTIONS,DELETE');
+header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization");
+// 定义应用目录
+define('APP_PATH', __DIR__ . '/../application/');
+// 加载框架引导文件
+require __DIR__ . '/../thinkphp/start.php';

+ 4 - 0
public/nginx.htaccess

@@ -0,0 +1,4 @@
+if (!-e $request_filename) {
+   rewrite  ^/(.*)$  /index.php/$1  last;
+   break;
+}

+ 2 - 0
public/robots.txt

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

+ 20 - 0
public/router.php

@@ -0,0 +1,20 @@
+<?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>
+// +----------------------------------------------------------------------
+// $Id$
+
+if (is_file($_SERVER["DOCUMENT_ROOT"] . $_SERVER["SCRIPT_NAME"])) {
+    return false;
+} else {
+    if (!isset($_SERVER['PATH_INFO'])) {
+        $_SERVER['PATH_INFO'] = $_SERVER['REQUEST_URI'];
+    }
+    require __DIR__ . "/index.php";
+}

BIN
public/upload/20210924/334e6a9e80bf543144695263397c8d4b.jpg


BIN
public/upload/20210924/b0e425e8396f4100ee4c7bccec1b8c02.jpg


BIN
public/upload/20211021/229b0fcb6a7354ed9198a8a923532c78.png


BIN
public/upload/20211021/321a256afc2765f0879dbac95533ae63.png


BIN
public/upload/20211021/9c2d89d4f0bff60434e4222ff4cc3ae1.png


BIN
public/upload/20211021/ccd60e0bdecb6231c67eb42ed98ecf27.png


BIN
public/upload/20211021/f0efc0aea59b8b5289e58a422bb458be.png


BIN
public/upload/20211021/f5224fe1aa65e1fa5194dae21d91a05d.png


BIN
public/upload/20211115/4167c72de4b4190efef76a5459bcde16.jpg


BIN
public/upload/20211117/02dda17daeca31abc84342f212a2f107.jpg


BIN
public/upload/20211117/0a371d939ea9c11725c1dd8e7eddccd8.jpg


BIN
public/upload/20211117/0a52bbd6d23a55f64550f98ab981a022.jpg


BIN
public/upload/20211117/0e33954161a26198af81c8966dc0ffc0.jpg


BIN
public/upload/20211117/1c9a3be4b1b4b4d597d3c4916893cd29.jpg


BIN
public/upload/20211117/293e261ee9f0a344300a5f47012f1f6c.jpg


BIN
public/upload/20211117/2b23345356af9dac20d27515d568c446.jpg


BIN
public/upload/20211117/3b76ea39af9b4541327f277f8640f664.jpg


BIN
public/upload/20211117/517209a7d49dc3444422b961444ff06b.jpg


BIN
public/upload/20211117/59e365bbdff192d6203cc486fdfeffb6.jpg


BIN
public/upload/20211117/5b207dd1547b802113cfc99bd9ae4be6.jpg


BIN
public/upload/20211117/695d3042fd9da1229e4fb0e48d2c7e51.jpg


BIN
public/upload/20211117/88de72f3b8663349583df64414e27445.jpg


BIN
public/upload/20211117/89638faa808c1cc075db7470d71cc355.jpg


BIN
public/upload/20211117/97b89c692e260f1131eb28c852044f86.jpg


BIN
public/upload/20211117/b00a3732f0e1aab6065e5e1efc2b7f5f.jpg


BIN
public/upload/20211117/b7b15212eec251a510ae7ba030ba8a23.jpg


BIN
public/upload/20211117/b96a6a441cf25d1812a35a5b558f38e0.jpg


BIN
public/upload/20211117/cc01842ecc0cc51009a2c0602d074125.jpg


BIN
public/upload/20211117/ce3c6500c332dc3306db536e01e5fdc6.jpg


BIN
public/upload/20211117/e24545b4fe387c8582c8a08a16526b6e.jpg


BIN
public/upload/20211117/e9fe42067e2755dd69a371950669801d.jpg


BIN
public/upload/20211117/ed720d1978bab890ddc4800107de7ed2.jpg


BIN
public/upload/20211117/f1cfb4d65ba08f85fc7f76d2164f1374.jpg


BIN
public/upload/20211117/f453e4dfecec6c06a2f09d79ae693b8b.jpg


BIN
public/upload/20211126/426337790046a7c05ee6d662a030432f.png


+ 17 - 0
think

@@ -0,0 +1,17 @@
+#!/usr/bin/env php
+<?php
+// +----------------------------------------------------------------------
+// | ThinkPHP [ WE CAN DO IT JUST THINK ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+// +----------------------------------------------------------------------
+// | Author: yunwuxin <448901948@qq.com>
+// +----------------------------------------------------------------------
+
+// 定义项目路径
+define('APP_PATH', __DIR__ . '/application/');
+
+// 加载框架引导文件
+require __DIR__.'/thinkphp/console.php';

+ 1 - 0
thinkphp/.htaccess

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

+ 47 - 0
thinkphp/.travis.yml

@@ -0,0 +1,47 @@
+sudo: false
+
+language: php
+
+services:
+  - memcached
+  - mongodb
+  - mysql
+  - postgresql
+  - redis-server
+
+matrix:
+  fast_finish: true
+  include:
+    - php: 5.4
+    - php: 5.5
+    - php: 5.6
+    - php: 7.0
+    - php: hhvm
+  allow_failures:
+    - php: hhvm
+
+cache:
+  directories:
+    - $HOME/.composer/cache
+
+before_install:
+  - composer self-update
+  - mysql -e "create database IF NOT EXISTS test;" -uroot
+  - psql -c 'DROP DATABASE IF EXISTS test;' -U postgres
+  - psql -c 'create database test;' -U postgres
+
+install:
+  - ./tests/script/install.sh
+
+script:
+  ## LINT
+  - find . -path ./vendor -prune -o -type f -name \*.php -exec php -l {} \;
+  ## PHP Copy/Paste Detector
+  - vendor/bin/phpcpd --verbose --exclude vendor ./ || true
+  ## PHPLOC
+  - vendor/bin/phploc --exclude vendor ./
+  ## PHPUNIT
+  - vendor/bin/phpunit --coverage-clover=coverage.xml --configuration=phpunit.xml
+
+after_success:
+  - bash <(curl -s https://codecov.io/bash)

+ 119 - 0
thinkphp/CONTRIBUTING.md

@@ -0,0 +1,119 @@
+如何贡献我的源代码
+===
+
+此文档介绍了 ThinkPHP 团队的组成以及运转机制,您提交的代码将给 ThinkPHP 项目带来什么好处,以及如何才能加入我们的行列。
+
+## 通过 Github 贡献代码
+
+ThinkPHP 目前使用 Git 来控制程序版本,如果你想为 ThinkPHP 贡献源代码,请先大致了解 Git 的使用方法。我们目前把项目托管在 GitHub 上,任何 GitHub 用户都可以向我们贡献代码。
+
+参与的方式很简单,`fork`一份 ThinkPHP 的代码到你的仓库中,修改后提交,并向我们发起`pull request`申请,我们会及时对代码进行审查并处理你的申请。审查通过后,你的代码将被`merge`进我们的仓库中,这样你就会自动出现在贡献者名单里了,非常方便。
+
+我们希望你贡献的代码符合:
+
+* ThinkPHP 的编码规范
+* 适当的注释,能让其他人读懂
+* 遵循 Apache2 开源协议
+
+**如果想要了解更多细节或有任何疑问,请继续阅读下面的内容**
+
+### 注意事项
+
+* 本项目代码格式化标准选用 [**PSR-2**](http://www.kancloud.cn/thinkphp/php-fig-psr/3141);
+* 类名和类文件名遵循 [**PSR-4**](http://www.kancloud.cn/thinkphp/php-fig-psr/3144);
+* 对于 Issues 的处理,请使用诸如 `fix #xxx(Issue ID)` 的 commit title 直接关闭 issue。
+* 系统会自动在 PHP 5.4 5.5 5.6 7.0 和 HHVM 上测试修改,其中 HHVM 下的测试容许报错,请确保你的修改符合 PHP 5.4 ~ 5.6 和 PHP 7.0 的语法规范;
+* 管理员不会合并造成 CI faild 的修改,若出现 CI faild 请检查自己的源代码或修改相应的[单元测试文件](tests);
+
+## GitHub Issue
+
+GitHub 提供了 Issue 功能,该功能可以用于:
+
+* 提出 bug
+* 提出功能改进
+* 反馈使用体验
+
+该功能不应该用于:
+
+ * 提出修改意见(涉及代码署名和修订追溯问题)
+ * 不友善的言论
+
+## 快速修改
+
+**GitHub 提供了快速编辑文件的功能**
+
+1. 登录 GitHub 帐号;
+2. 浏览项目文件,找到要进行修改的文件;
+3. 点击右上角铅笔图标进行修改;
+4. 填写 `Commit changes` 相关内容(Title 必填);
+5. 提交修改,等待 CI 验证和管理员合并。
+
+**若您需要一次提交大量修改,请继续阅读下面的内容**
+
+## 完整流程
+
+1. `fork`本项目;
+2. 克隆(`clone`)你 `fork` 的项目到本地;
+3. 新建分支(`branch`)并检出(`checkout`)新分支;
+4. 添加本项目到你的本地 git 仓库作为上游(`upstream`);
+5. 进行修改,若你的修改包含方法或函数的增减,请记得修改[单元测试文件](tests);
+6. 变基(衍合 `rebase`)你的分支到上游 master 分支;
+7. `push` 你的本地仓库到 GitHub;
+8. 提交 `pull request`;
+9. 等待 CI 验证(若不通过则重复 5~7,不需要重新提交 `pull request`,GitHub 会自动更新你的 `pull request`);
+10. 等待管理员处理,并及时 `rebase` 你的分支到上游 master 分支(若上游 master 分支有修改)。
+
+*若有必要,可以 `git push -f` 强行推送 rebase 后的分支到自己的 `fork`*
+
+*绝对不可以使用 `git push -f` 强行推送修改到上游*
+
+### 注意事项
+
+* 若对上述流程有任何不清楚的地方,请查阅 GIT 教程,如 [这个](http://backlogtool.com/git-guide/cn/);
+* 对于代码**不同方面**的修改,请在自己 `fork` 的项目中**创建不同的分支**(原因参见`完整流程`第9条备注部分);
+* 变基及交互式变基操作参见 [Git 交互式变基](http://pakchoi.me/2015/03/17/git-interactive-rebase/)
+
+## 推荐资源
+
+### 开发环境
+
+* XAMPP for Windows 5.5.x
+* WampServer (for Windows)
+* upupw Apache PHP5.4 ( for Windows)
+
+或自行安装
+
+- Apache / Nginx
+- PHP 5.4 ~ 5.6
+- MySQL / MariaDB
+
+*Windows 用户推荐添加 PHP bin 目录到 PATH,方便使用 composer*
+
+*Linux 用户自行配置环境, Mac 用户推荐使用内置 Apache 配合 Homebrew 安装 PHP 和 MariaDB*
+
+### 编辑器
+
+Sublime Text 3 + phpfmt 插件
+
+phpfmt 插件参数
+
+```json
+{
+	"autocomplete": true,
+	"enable_auto_align": true,
+	"format_on_save": true,
+	"indent_with_space": true,
+	"psr1_naming": false,
+	"psr2": true,
+	"version": 4
+}
+```
+
+或其他 编辑器 / IDE 配合 PSR2 自动格式化工具
+
+### Git GUI
+
+* SourceTree
+* GitHub Desktop
+
+或其他 Git 图形界面客户端

+ 32 - 0
thinkphp/LICENSE.txt

@@ -0,0 +1,32 @@
+
+ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
+版权所有Copyright © 2006-2017 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.

+ 114 - 0
thinkphp/README.md

@@ -0,0 +1,114 @@
+ThinkPHP 5.0
+===============
+
+[![StyleCI](https://styleci.io/repos/48530411/shield?style=flat&branch=master)](https://styleci.io/repos/48530411)
+[![Build Status](https://travis-ci.org/top-think/framework.svg?branch=master)](https://travis-ci.org/top-think/framework)
+[![codecov.io](http://codecov.io/github/top-think/framework/coverage.svg?branch=master)](http://codecov.io/github/github/top-think/framework?branch=master)
+[![Total Downloads](https://poser.pugx.org/topthink/framework/downloads)](https://packagist.org/packages/topthink/framework)
+[![Latest Stable Version](https://poser.pugx.org/topthink/framework/v/stable)](https://packagist.org/packages/topthink/framework)
+[![Latest Unstable Version](https://poser.pugx.org/topthink/framework/v/unstable)](https://packagist.org/packages/topthink/framework)
+[![License](https://poser.pugx.org/topthink/framework/license)](https://packagist.org/packages/topthink/framework)
+
+ThinkPHP5在保持快速开发和大道至简的核心理念不变的同时,PHP版本要求提升到5.4,优化核心,减少依赖,基于全新的架构思想和命名空间实现,是ThinkPHP突破原有框架思路的颠覆之作,其主要特性包括:
+
+ + 基于命名空间和众多PHP新特性
+ + 核心功能组件化
+ + 强化路由功能
+ + 更灵活的控制器
+ + 重构的模型和数据库类
+ + 配置文件可分离
+ + 重写的自动验证和完成
+ + 简化扩展机制
+ + API支持完善
+ + 改进的Log类
+ + 命令行访问支持
+ + REST支持
+ + 引导文件支持
+ + 方便的自动生成定义
+ + 真正惰性加载
+ + 分布式环境支持
+ + 支持Composer
+ + 支持MongoDb
+
+> ThinkPHP5的运行环境要求PHP5.4以上。
+
+详细开发文档参考 [ThinkPHP5完全开发手册](http://www.kancloud.cn/manual/thinkphp5) 以及[ThinkPHP5入门系列教程](http://www.kancloud.cn/special/thinkphp5_quickstart)
+
+## 目录结构
+
+初始的目录结构如下:
+
+~~~
+www  WEB部署目录(或者子目录)
+├─application           应用目录
+│  ├─common             公共模块目录(可以更改)
+│  ├─module_name        模块目录
+│  │  ├─config.php      模块配置文件
+│  │  ├─common.php      模块函数文件
+│  │  ├─controller      控制器目录
+│  │  ├─model           模型目录
+│  │  ├─view            视图目录
+│  │  └─ ...            更多类库目录
+│  │
+│  ├─command.php        命令行工具配置文件
+│  ├─common.php         公共函数文件
+│  ├─config.php         公共配置文件
+│  ├─route.php          路由配置文件
+│  ├─tags.php           应用行为扩展定义文件
+│  └─database.php       数据库配置文件
+│
+├─public                WEB目录(对外访问目录)
+│  ├─index.php          入口文件
+│  ├─router.php         快速测试文件
+│  └─.htaccess          用于apache的重写
+│
+├─thinkphp              框架系统目录
+│  ├─lang               语言文件目录
+│  ├─library            框架类库目录
+│  │  ├─think           Think类库包目录
+│  │  └─traits          系统Trait目录
+│  │
+│  ├─tpl                系统模板目录
+│  ├─base.php           基础定义文件
+│  ├─console.php        控制台入口文件
+│  ├─convention.php     框架惯例配置文件
+│  ├─helper.php         助手函数文件
+│  ├─phpunit.xml        phpunit配置文件
+│  └─start.php          框架入口文件
+│
+├─extend                扩展类库目录
+├─runtime               应用的运行时目录(可写,可定制)
+├─vendor                第三方类库目录(Composer依赖库)
+├─build.php             自动生成定义文件(参考)
+├─composer.json         composer 定义文件
+├─LICENSE.txt           授权说明文件
+├─README.md             README 文件
+├─think                 命令行入口文件
+~~~
+
+> router.php用于php自带webserver支持,可用于快速测试
+> 切换到public目录后,启动命令:php -S localhost:8888  router.php
+> 上面的目录结构和名称是可以改变的,这取决于你的入口文件和配置参数。
+
+## 命名规范
+
+ThinkPHP5的命名规范遵循`PSR-2`规范以及`PSR-4`自动加载规范。
+
+## 参与开发
+注册并登录 Github 帐号, fork 本项目并进行改动。
+
+更多细节参阅 [CONTRIBUTING.md](CONTRIBUTING.md)
+
+## 版权信息
+
+ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
+
+本项目包含的第三方源码和二进制文件之版权信息另行标注。
+
+版权所有Copyright © 2006-2018 by ThinkPHP (http://thinkphp.cn)
+
+All rights reserved。
+
+ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
+
+更多细节参阅 [LICENSE.txt](LICENSE.txt)

+ 65 - 0
thinkphp/base.php

@@ -0,0 +1,65 @@
+<?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>
+// +----------------------------------------------------------------------
+
+define('THINK_VERSION', '5.0.24');
+define('THINK_START_TIME', microtime(true));
+define('THINK_START_MEM', memory_get_usage());
+define('EXT', '.php');
+define('DS', DIRECTORY_SEPARATOR);
+defined('THINK_PATH') or define('THINK_PATH', __DIR__ . DS);
+define('LIB_PATH', THINK_PATH . 'library' . DS);
+define('CORE_PATH', LIB_PATH . 'think' . DS);
+define('TRAIT_PATH', LIB_PATH . 'traits' . DS);
+defined('APP_PATH') or define('APP_PATH', dirname($_SERVER['SCRIPT_FILENAME']) . DS);
+defined('ROOT_PATH') or define('ROOT_PATH', dirname(realpath(APP_PATH)) . DS);
+defined('EXTEND_PATH') or define('EXTEND_PATH', ROOT_PATH . 'extend' . DS);
+defined('VENDOR_PATH') or define('VENDOR_PATH', ROOT_PATH . 'vendor' . DS);
+defined('RUNTIME_PATH') or define('RUNTIME_PATH', ROOT_PATH . 'runtime' . DS);
+defined('LOG_PATH') or define('LOG_PATH', RUNTIME_PATH . 'log' . DS);
+defined('CACHE_PATH') or define('CACHE_PATH', RUNTIME_PATH . 'cache' . DS);
+defined('TEMP_PATH') or define('TEMP_PATH', RUNTIME_PATH . 'temp' . DS);
+defined('CONF_PATH') or define('CONF_PATH', APP_PATH); // 配置文件目录
+defined('CONF_EXT') or define('CONF_EXT', EXT); // 配置文件后缀
+defined('ENV_PREFIX') or define('ENV_PREFIX', 'PHP_'); // 环境变量的配置前缀
+
+// 环境常量
+define('IS_CLI', PHP_SAPI == 'cli' ? true : false);
+define('IS_WIN', strpos(PHP_OS, 'WIN') !== false);
+
+// 载入Loader类
+require CORE_PATH . 'Loader.php';
+
+// 加载环境变量配置文件
+if (is_file(ROOT_PATH . '.env')) {
+    $env = parse_ini_file(ROOT_PATH . '.env', true);
+
+    foreach ($env as $key => $val) {
+        $name = ENV_PREFIX . strtoupper($key);
+
+        if (is_array($val)) {
+            foreach ($val as $k => $v) {
+                $item = $name . '_' . strtoupper($k);
+                putenv("$item=$v");
+            }
+        } else {
+            putenv("$name=$val");
+        }
+    }
+}
+
+// 注册自动加载
+\think\Loader::register();
+
+// 注册错误和异常处理机制
+\think\Error::register();
+
+// 加载惯例配置文件
+\think\Config::set(include THINK_PATH . 'convention' . EXT);

+ 12 - 0
thinkphp/codecov.yml

@@ -0,0 +1,12 @@
+comment:
+  layout: header, changes, diff
+coverage:
+  ignore:
+  - base.php
+  - helper.php
+  - convention.php
+  - lang/zh-cn.php
+  - start.php
+  - console.php
+  status:
+    patch: false

+ 35 - 0
thinkphp/composer.json

@@ -0,0 +1,35 @@
+{
+    "name": "topthink/framework",
+    "description": "the new thinkphp framework",
+    "type": "think-framework",
+    "keywords": [
+        "framework",
+        "thinkphp",
+        "ORM"
+    ],
+    "homepage": "http://thinkphp.cn/",
+    "license": "Apache-2.0",
+    "authors": [
+        {
+            "name": "liu21st",
+            "email": "liu21st@gmail.com"
+        }
+    ],
+    "require": {
+        "php": ">=5.4.0",
+        "topthink/think-installer": "~1.0"
+    },
+    "require-dev": {
+        "phpunit/phpunit": "4.8.*",
+        "johnkary/phpunit-speedtrap": "^1.0",
+        "mikey179/vfsStream": "~1.6",
+        "phploc/phploc": "2.*",
+        "sebastian/phpcpd": "2.*",
+        "phpdocumentor/reflection-docblock": "^2.0"
+    },
+    "autoload": {
+        "psr-4": {
+            "think\\": "library/think"
+        }
+    }
+}

+ 20 - 0
thinkphp/console.php

@@ -0,0 +1,20 @@
+<?php
+// +----------------------------------------------------------------------
+// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2006-2017 http://thinkphp.cn All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+// +----------------------------------------------------------------------
+// | Author: yunwuxin <448901948@qq.com>
+// +----------------------------------------------------------------------
+
+namespace think;
+
+// ThinkPHP 引导文件
+// 加载基础文件
+require __DIR__ . '/base.php';
+
+// 执行应用
+App::initCommon();
+Console::init();

+ 298 - 0
thinkphp/convention.php

@@ -0,0 +1,298 @@
+<?php
+
+return [
+    // +----------------------------------------------------------------------
+    // | 应用设置
+    // +----------------------------------------------------------------------
+    // 默认Host地址
+    'app_host'               => '',
+    // 应用调试模式
+    'app_debug'              => false,
+    // 应用Trace
+    'app_trace'              => false,
+    // 应用模式状态
+    'app_status'             => '',
+    // 是否支持多模块
+    'app_multi_module'       => true,
+    // 入口自动绑定模块
+    'auto_bind_module'       => false,
+    // 注册的根命名空间
+    'root_namespace'         => [],
+    // 扩展函数文件
+    'extra_file_list'        => [THINK_PATH . 'helper' . EXT],
+    // 默认输出类型
+    'default_return_type'    => 'html',
+    // 默认AJAX 数据返回格式,可选json xml ...
+    'default_ajax_return'    => 'json',
+    // 默认JSONP格式返回的处理方法
+    'default_jsonp_handler'  => 'jsonpReturn',
+    // 默认JSONP处理方法
+    'var_jsonp_handler'      => 'callback',
+    // 默认时区
+    'default_timezone'       => 'PRC',
+    // 是否开启多语言
+    'lang_switch_on'         => false,
+    // 默认全局过滤方法 用逗号分隔多个
+    'default_filter'         => '',
+    // 默认语言
+    'default_lang'           => 'zh-cn',
+    // 应用类库后缀
+    'class_suffix'           => false,
+    // 控制器类后缀
+    'controller_suffix'      => false,
+
+    // +----------------------------------------------------------------------
+    // | 模块设置
+    // +----------------------------------------------------------------------
+
+    // 默认模块名
+    'default_module'         => 'index',
+    // 禁止访问模块
+    'deny_module_list'       => ['common'],
+    // 默认控制器名
+    'default_controller'     => 'Index',
+    // 默认操作名
+    'default_action'         => 'index',
+    // 默认验证器
+    'default_validate'       => '',
+    // 默认的空控制器名
+    'empty_controller'       => 'Error',
+    // 操作方法前缀
+    'use_action_prefix'      => false,
+    // 操作方法后缀
+    'action_suffix'          => '',
+    // 自动搜索控制器
+    'controller_auto_search' => false,
+
+    // +----------------------------------------------------------------------
+    // | URL设置
+    // +----------------------------------------------------------------------
+
+    // PATHINFO变量名 用于兼容模式
+    'var_pathinfo'           => 's',
+    // 兼容PATH_INFO获取
+    'pathinfo_fetch'         => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'],
+    // pathinfo分隔符
+    'pathinfo_depr'          => '/',
+    // HTTPS代理标识
+    'https_agent_name'       => '',
+    // URL伪静态后缀
+    'url_html_suffix'        => 'html',
+    // URL普通方式参数 用于自动生成
+    'url_common_param'       => false,
+    // URL参数方式 0 按名称成对解析 1 按顺序解析
+    'url_param_type'         => 0,
+    // 是否开启路由
+    'url_route_on'           => true,
+    // 路由配置文件(支持配置多个)
+    'route_config_file'      => ['route'],
+    // 路由使用完整匹配
+    'route_complete_match'   => false,
+    // 是否强制使用路由
+    'url_route_must'         => false,
+    // 域名部署
+    'url_domain_deploy'      => false,
+    // 域名根,如thinkphp.cn
+    'url_domain_root'        => '',
+    // 是否自动转换URL中的控制器和操作名
+    'url_convert'            => true,
+    // 默认的访问控制器层
+    'url_controller_layer'   => 'controller',
+    // 表单请求类型伪装变量
+    'var_method'             => '_method',
+    // 表单ajax伪装变量
+    'var_ajax'               => '_ajax',
+    // 表单pjax伪装变量
+    'var_pjax'               => '_pjax',
+    // 是否开启请求缓存 true自动缓存 支持设置请求缓存规则
+    'request_cache'          => false,
+    // 请求缓存有效期
+    'request_cache_expire'   => null,
+    // 全局请求缓存排除规则
+    'request_cache_except'   => [],
+
+    // +----------------------------------------------------------------------
+    // | 模板设置
+    // +----------------------------------------------------------------------
+
+    'template'               => [
+        // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写
+        'auto_rule'    => 1,
+        // 模板引擎类型 支持 php think 支持扩展
+        'type'         => 'Think',
+        // 视图基础目录,配置目录为所有模块的视图起始目录
+        'view_base'    => '',
+        // 当前模板的视图目录 留空为自动获取
+        'view_path'    => '',
+        // 模板后缀
+        'view_suffix'  => 'html',
+        // 模板文件名分隔符
+        'view_depr'    => DS,
+        // 模板引擎普通标签开始标记
+        'tpl_begin'    => '{',
+        // 模板引擎普通标签结束标记
+        'tpl_end'      => '}',
+        // 标签库标签开始标记
+        'taglib_begin' => '{',
+        // 标签库标签结束标记
+        'taglib_end'   => '}',
+    ],
+
+    // 视图输出字符串内容替换
+    'view_replace_str'       => [],
+    // 默认跳转页面对应的模板文件
+    'dispatch_success_tmpl'  => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl',
+    'dispatch_error_tmpl'    => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl',
+
+    // +----------------------------------------------------------------------
+    // | 异常及错误设置
+    // +----------------------------------------------------------------------
+
+    // 异常页面的模板文件
+    'exception_tmpl'         => THINK_PATH . 'tpl' . DS . 'think_exception.tpl',
+
+    // 错误显示信息,非调试模式有效
+    'error_message'          => '页面错误!请稍后再试~',
+    // 显示错误信息
+    'show_error_msg'         => false,
+    // 异常处理handle类 留空使用 \think\exception\Handle
+    'exception_handle'       => '',
+    // 是否记录trace信息到日志
+    'record_trace'           => false,
+
+    // +----------------------------------------------------------------------
+    // | 日志设置
+    // +----------------------------------------------------------------------
+
+    'log'                    => [
+        // 日志记录方式,内置 file socket 支持扩展
+        'type'  => 'File',
+        // 日志保存目录
+        'path'  => LOG_PATH,
+        // 日志记录级别
+        'level' => [],
+    ],
+
+    // +----------------------------------------------------------------------
+    // | Trace设置 开启 app_trace 后 有效
+    // +----------------------------------------------------------------------
+    'trace'                  => [
+        // 内置Html Console 支持扩展
+        'type' => 'Html',
+    ],
+
+    // +----------------------------------------------------------------------
+    // | 缓存设置
+    // +----------------------------------------------------------------------
+
+    'cache'                  => [
+        // 驱动方式
+        'type'   => 'File',
+        // 缓存保存目录
+        'path'   => CACHE_PATH,
+        // 缓存前缀
+        'prefix' => '',
+        // 缓存有效期 0表示永久缓存
+        'expire' => 0,
+    ],
+
+    // +----------------------------------------------------------------------
+    // | 会话设置
+    // +----------------------------------------------------------------------
+
+    'session'                => [
+        'id'             => '',
+        // SESSION_ID的提交变量,解决flash上传跨域
+        'var_session_id' => '',
+        // SESSION 前缀
+        'prefix'         => 'think',
+        // 驱动方式 支持redis memcache memcached
+        'type'           => '',
+        // 是否自动开启 SESSION
+        'auto_start'     => true,
+        'httponly'       => true,
+        'secure'         => false,
+    ],
+
+    // +----------------------------------------------------------------------
+    // | Cookie设置
+    // +----------------------------------------------------------------------
+    'cookie'                 => [
+        // cookie 名称前缀
+        'prefix'    => '',
+        // cookie 保存时间
+        'expire'    => 0,
+        // cookie 保存路径
+        'path'      => '/',
+        // cookie 有效域名
+        'domain'    => '',
+        //  cookie 启用安全传输
+        'secure'    => false,
+        // httponly设置
+        'httponly'  => '',
+        // 是否使用 setcookie
+        'setcookie' => true,
+    ],
+
+    // +----------------------------------------------------------------------
+    // | 数据库设置
+    // +----------------------------------------------------------------------
+
+    'database'               => [
+        // 数据库类型
+        'type'            => 'mysql',
+        // 数据库连接DSN配置
+        'dsn'             => '',
+        // 服务器地址
+        'hostname'        => '127.0.0.1',
+        // 数据库名
+        'database'        => '',
+        // 数据库用户名
+        'username'        => 'root',
+        // 数据库密码
+        'password'        => '',
+        // 数据库连接端口
+        'hostport'        => '',
+        // 数据库连接参数
+        'params'          => [],
+        // 数据库编码默认采用utf8
+        'charset'         => 'utf8',
+        // 数据库表前缀
+        'prefix'          => '',
+        // 数据库调试模式
+        'debug'           => false,
+        // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
+        'deploy'          => 0,
+        // 数据库读写是否分离 主从式有效
+        'rw_separate'     => false,
+        // 读写分离后 主服务器数量
+        'master_num'      => 1,
+        // 指定从服务器序号
+        'slave_no'        => '',
+        // 是否严格检查字段是否存在
+        'fields_strict'   => true,
+        // 数据集返回类型
+        'resultset_type'  => 'array',
+        // 自动写入时间戳字段
+        'auto_timestamp'  => false,
+        // 时间字段取出后的默认时间格式
+        'datetime_format' => 'Y-m-d H:i:s',
+        // 是否需要进行SQL性能分析
+        'sql_explain'     => false,
+    ],
+
+    //分页配置
+    'paginate'               => [
+        'type'      => 'bootstrap',
+        'var_page'  => 'page',
+        'list_rows' => 15,
+    ],
+
+    //控制台配置
+    'console'                => [
+        'name'    => 'Think Console',
+        'version' => '0.1',
+        'user'    => null,
+    ],
+
+];

+ 589 - 0
thinkphp/helper.php

@@ -0,0 +1,589 @@
+<?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>
+// +----------------------------------------------------------------------
+
+//------------------------
+// ThinkPHP 助手函数
+//-------------------------
+
+use think\Cache;
+use think\Config;
+use think\Cookie;
+use think\Db;
+use think\Debug;
+use think\exception\HttpException;
+use think\exception\HttpResponseException;
+use think\Lang;
+use think\Loader;
+use think\Log;
+use think\Model;
+use think\Request;
+use think\Response;
+use think\Session;
+use think\Url;
+use think\View;
+
+if (!function_exists('load_trait')) {
+    /**
+     * 快速导入Traits PHP5.5以上无需调用
+     * @param string    $class trait库
+     * @param string    $ext 类库后缀
+     * @return boolean
+     */
+    function load_trait($class, $ext = EXT)
+    {
+        return Loader::import($class, TRAIT_PATH, $ext);
+    }
+}
+
+if (!function_exists('exception')) {
+    /**
+     * 抛出异常处理
+     *
+     * @param string    $msg  异常消息
+     * @param integer   $code 异常代码 默认为0
+     * @param string    $exception 异常类
+     *
+     * @throws Exception
+     */
+    function exception($msg, $code = 0, $exception = '')
+    {
+        $e = $exception ?: '\think\Exception';
+        throw new $e($msg, $code);
+    }
+}
+
+if (!function_exists('debug')) {
+    /**
+     * 记录时间(微秒)和内存使用情况
+     * @param string            $start 开始标签
+     * @param string            $end 结束标签
+     * @param integer|string    $dec 小数位 如果是m 表示统计内存占用
+     * @return mixed
+     */
+    function debug($start, $end = '', $dec = 6)
+    {
+        if ('' == $end) {
+            Debug::remark($start);
+        } else {
+            return 'm' == $dec ? Debug::getRangeMem($start, $end) : Debug::getRangeTime($start, $end, $dec);
+        }
+    }
+}
+
+if (!function_exists('lang')) {
+    /**
+     * 获取语言变量值
+     * @param string    $name 语言变量名
+     * @param array     $vars 动态变量值
+     * @param string    $lang 语言
+     * @return mixed
+     */
+    function lang($name, $vars = [], $lang = '')
+    {
+        return Lang::get($name, $vars, $lang);
+    }
+}
+
+if (!function_exists('config')) {
+    /**
+     * 获取和设置配置参数
+     * @param string|array  $name 参数名
+     * @param mixed         $value 参数值
+     * @param string        $range 作用域
+     * @return mixed
+     */
+    function config($name = '', $value = null, $range = '')
+    {
+        if (is_null($value) && is_string($name)) {
+            return 0 === strpos($name, '?') ? Config::has(substr($name, 1), $range) : Config::get($name, $range);
+        } else {
+            return Config::set($name, $value, $range);
+        }
+    }
+}
+
+if (!function_exists('input')) {
+    /**
+     * 获取输入数据 支持默认值和过滤
+     * @param string    $key 获取的变量名
+     * @param mixed     $default 默认值
+     * @param string    $filter 过滤方法
+     * @return mixed
+     */
+    function input($key = '', $default = null, $filter = '')
+    {
+        if (0 === strpos($key, '?')) {
+            $key = substr($key, 1);
+            $has = true;
+        }
+        if ($pos = strpos($key, '.')) {
+            // 指定参数来源
+            list($method, $key) = explode('.', $key, 2);
+            if (!in_array($method, ['get', 'post', 'put', 'patch', 'delete', 'route', 'param', 'request', 'session', 'cookie', 'server', 'env', 'path', 'file'])) {
+                $key    = $method . '.' . $key;
+                $method = 'param';
+            }
+        } else {
+            // 默认为自动判断
+            $method = 'param';
+        }
+        if (isset($has)) {
+            return request()->has($key, $method, $default);
+        } else {
+            return request()->$method($key, $default, $filter);
+        }
+    }
+}
+
+if (!function_exists('widget')) {
+    /**
+     * 渲染输出Widget
+     * @param string    $name Widget名称
+     * @param array     $data 传入的参数
+     * @return mixed
+     */
+    function widget($name, $data = [])
+    {
+        return Loader::action($name, $data, 'widget');
+    }
+}
+
+if (!function_exists('model')) {
+    /**
+     * 实例化Model
+     * @param string    $name Model名称
+     * @param string    $layer 业务层名称
+     * @param bool      $appendSuffix 是否添加类名后缀
+     * @return \think\Model
+     */
+    function model($name = '', $layer = 'model', $appendSuffix = false)
+    {
+        return Loader::model($name, $layer, $appendSuffix);
+    }
+}
+
+if (!function_exists('validate')) {
+    /**
+     * 实例化验证器
+     * @param string    $name 验证器名称
+     * @param string    $layer 业务层名称
+     * @param bool      $appendSuffix 是否添加类名后缀
+     * @return \think\Validate
+     */
+    function validate($name = '', $layer = 'validate', $appendSuffix = false)
+    {
+        return Loader::validate($name, $layer, $appendSuffix);
+    }
+}
+
+if (!function_exists('db')) {
+    /**
+     * 实例化数据库类
+     * @param string        $name 操作的数据表名称(不含前缀)
+     * @param array|string  $config 数据库配置参数
+     * @param bool          $force 是否强制重新连接
+     * @return \think\db\Query
+     */
+    function db($name = '', $config = [], $force = false)
+    {
+        return Db::connect($config, $force)->name($name);
+    }
+}
+
+if (!function_exists('controller')) {
+    /**
+     * 实例化控制器 格式:[模块/]控制器
+     * @param string    $name 资源地址
+     * @param string    $layer 控制层名称
+     * @param bool      $appendSuffix 是否添加类名后缀
+     * @return \think\Controller
+     */
+    function controller($name, $layer = 'controller', $appendSuffix = false)
+    {
+        return Loader::controller($name, $layer, $appendSuffix);
+    }
+}
+
+if (!function_exists('action')) {
+    /**
+     * 调用模块的操作方法 参数格式 [模块/控制器/]操作
+     * @param string        $url 调用地址
+     * @param string|array  $vars 调用参数 支持字符串和数组
+     * @param string        $layer 要调用的控制层名称
+     * @param bool          $appendSuffix 是否添加类名后缀
+     * @return mixed
+     */
+    function action($url, $vars = [], $layer = 'controller', $appendSuffix = false)
+    {
+        return Loader::action($url, $vars, $layer, $appendSuffix);
+    }
+}
+
+if (!function_exists('import')) {
+    /**
+     * 导入所需的类库 同java的Import 本函数有缓存功能
+     * @param string    $class 类库命名空间字符串
+     * @param string    $baseUrl 起始路径
+     * @param string    $ext 导入的文件扩展名
+     * @return boolean
+     */
+    function import($class, $baseUrl = '', $ext = EXT)
+    {
+        return Loader::import($class, $baseUrl, $ext);
+    }
+}
+
+if (!function_exists('vendor')) {
+    /**
+     * 快速导入第三方框架类库 所有第三方框架的类库文件统一放到 系统的Vendor目录下面
+     * @param string    $class 类库
+     * @param string    $ext 类库后缀
+     * @return boolean
+     */
+    function vendor($class, $ext = EXT)
+    {
+        return Loader::import($class, VENDOR_PATH, $ext);
+    }
+}
+
+if (!function_exists('dump')) {
+    /**
+     * 浏览器友好的变量输出
+     * @param mixed     $var 变量
+     * @param boolean   $echo 是否输出 默认为true 如果为false 则返回输出字符串
+     * @param string    $label 标签 默认为空
+     * @return void|string
+     */
+    function dump($var, $echo = true, $label = null)
+    {
+        return Debug::dump($var, $echo, $label);
+    }
+}
+
+if (!function_exists('url')) {
+    /**
+     * Url生成
+     * @param string        $url 路由地址
+     * @param string|array  $vars 变量
+     * @param bool|string   $suffix 生成的URL后缀
+     * @param bool|string   $domain 域名
+     * @return string
+     */
+    function url($url = '', $vars = '', $suffix = true, $domain = false)
+    {
+        return Url::build($url, $vars, $suffix, $domain);
+    }
+}
+
+if (!function_exists('session')) {
+    /**
+     * Session管理
+     * @param string|array  $name session名称,如果为数组表示进行session设置
+     * @param mixed         $value session值
+     * @param string        $prefix 前缀
+     * @return mixed
+     */
+    function session($name, $value = '', $prefix = null)
+    {
+        if (is_array($name)) {
+            // 初始化
+            Session::init($name);
+        } elseif (is_null($name)) {
+            // 清除
+            Session::clear('' === $value ? null : $value);
+        } elseif ('' === $value) {
+            // 判断或获取
+            return 0 === strpos($name, '?') ? Session::has(substr($name, 1), $prefix) : Session::get($name, $prefix);
+        } elseif (is_null($value)) {
+            // 删除
+            return Session::delete($name, $prefix);
+        } else {
+            // 设置
+            return Session::set($name, $value, $prefix);
+        }
+    }
+}
+
+if (!function_exists('cookie')) {
+    /**
+     * Cookie管理
+     * @param string|array  $name cookie名称,如果为数组表示进行cookie设置
+     * @param mixed         $value cookie值
+     * @param mixed         $option 参数
+     * @return mixed
+     */
+    function cookie($name, $value = '', $option = null)
+    {
+        if (is_array($name)) {
+            // 初始化
+            Cookie::init($name);
+        } elseif (is_null($name)) {
+            // 清除
+            Cookie::clear($value);
+        } elseif ('' === $value) {
+            // 获取
+            return 0 === strpos($name, '?') ? Cookie::has(substr($name, 1), $option) : Cookie::get($name, $option);
+        } elseif (is_null($value)) {
+            // 删除
+            return Cookie::delete($name);
+        } else {
+            // 设置
+            return Cookie::set($name, $value, $option);
+        }
+    }
+}
+
+if (!function_exists('cache')) {
+    /**
+     * 缓存管理
+     * @param mixed     $name 缓存名称,如果为数组表示进行缓存设置
+     * @param mixed     $value 缓存值
+     * @param mixed     $options 缓存参数
+     * @param string    $tag 缓存标签
+     * @return mixed
+     */
+    function cache($name, $value = '', $options = null, $tag = null)
+    {
+        if (is_array($options)) {
+            // 缓存操作的同时初始化
+            $cache = Cache::connect($options);
+        } elseif (is_array($name)) {
+            // 缓存初始化
+            return Cache::connect($name);
+        } else {
+            $cache = Cache::init();
+        }
+
+        if (is_null($name)) {
+            return $cache->clear($value);
+        } elseif ('' === $value) {
+            // 获取缓存
+            return 0 === strpos($name, '?') ? $cache->has(substr($name, 1)) : $cache->get($name);
+        } elseif (is_null($value)) {
+            // 删除缓存
+            return $cache->rm($name);
+        } elseif (0 === strpos($name, '?') && '' !== $value) {
+            $expire = is_numeric($options) ? $options : null;
+            return $cache->remember(substr($name, 1), $value, $expire);
+        } else {
+            // 缓存数据
+            if (is_array($options)) {
+                $expire = isset($options['expire']) ? $options['expire'] : null; //修复查询缓存无法设置过期时间
+            } else {
+                $expire = is_numeric($options) ? $options : null; //默认快捷缓存设置过期时间
+            }
+            if (is_null($tag)) {
+                return $cache->set($name, $value, $expire);
+            } else {
+                return $cache->tag($tag)->set($name, $value, $expire);
+            }
+        }
+    }
+}
+
+if (!function_exists('trace')) {
+    /**
+     * 记录日志信息
+     * @param mixed     $log log信息 支持字符串和数组
+     * @param string    $level 日志级别
+     * @return void|array
+     */
+    function trace($log = '[think]', $level = 'log')
+    {
+        if ('[think]' === $log) {
+            return Log::getLog();
+        } else {
+            Log::record($log, $level);
+        }
+    }
+}
+
+if (!function_exists('request')) {
+    /**
+     * 获取当前Request对象实例
+     * @return Request
+     */
+    function request()
+    {
+        return Request::instance();
+    }
+}
+
+if (!function_exists('response')) {
+    /**
+     * 创建普通 Response 对象实例
+     * @param mixed      $data   输出数据
+     * @param int|string $code   状态码
+     * @param array      $header 头信息
+     * @param string     $type
+     * @return Response
+     */
+    function response($data = [], $code = 200, $header = [], $type = 'html')
+    {
+        return Response::create($data, $type, $code, $header);
+    }
+}
+
+if (!function_exists('view')) {
+    /**
+     * 渲染模板输出
+     * @param string    $template 模板文件
+     * @param array     $vars 模板变量
+     * @param array     $replace 模板替换
+     * @param integer   $code 状态码
+     * @return \think\response\View
+     */
+    function view($template = '', $vars = [], $replace = [], $code = 200)
+    {
+        return Response::create($template, 'view', $code)->replace($replace)->assign($vars);
+    }
+}
+
+if (!function_exists('json')) {
+    /**
+     * 获取\think\response\Json对象实例
+     * @param mixed   $data 返回的数据
+     * @param integer $code 状态码
+     * @param array   $header 头部
+     * @param array   $options 参数
+     * @return \think\response\Json
+     */
+    function json($data = [], $code = 200, $header = [], $options = [])
+    {
+        return Response::create($data, 'json', $code, $header, $options);
+    }
+}
+
+if (!function_exists('jsonp')) {
+    /**
+     * 获取\think\response\Jsonp对象实例
+     * @param mixed   $data    返回的数据
+     * @param integer $code    状态码
+     * @param array   $header 头部
+     * @param array   $options 参数
+     * @return \think\response\Jsonp
+     */
+    function jsonp($data = [], $code = 200, $header = [], $options = [])
+    {
+        return Response::create($data, 'jsonp', $code, $header, $options);
+    }
+}
+
+if (!function_exists('xml')) {
+    /**
+     * 获取\think\response\Xml对象实例
+     * @param mixed   $data    返回的数据
+     * @param integer $code    状态码
+     * @param array   $header  头部
+     * @param array   $options 参数
+     * @return \think\response\Xml
+     */
+    function xml($data = [], $code = 200, $header = [], $options = [])
+    {
+        return Response::create($data, 'xml', $code, $header, $options);
+    }
+}
+
+if (!function_exists('redirect')) {
+    /**
+     * 获取\think\response\Redirect对象实例
+     * @param mixed         $url 重定向地址 支持Url::build方法的地址
+     * @param array|integer $params 额外参数
+     * @param integer       $code 状态码
+     * @param array         $with 隐式传参
+     * @return \think\response\Redirect
+     */
+    function redirect($url = [], $params = [], $code = 302, $with = [])
+    {
+        if (is_integer($params)) {
+            $code   = $params;
+            $params = [];
+        }
+        return Response::create($url, 'redirect', $code)->params($params)->with($with);
+    }
+}
+
+if (!function_exists('abort')) {
+    /**
+     * 抛出HTTP异常
+     * @param integer|Response      $code 状态码 或者 Response对象实例
+     * @param string                $message 错误信息
+     * @param array                 $header 参数
+     */
+    function abort($code, $message = null, $header = [])
+    {
+        if ($code instanceof Response) {
+            throw new HttpResponseException($code);
+        } else {
+            throw new HttpException($code, $message, null, $header);
+        }
+    }
+}
+
+if (!function_exists('halt')) {
+    /**
+     * 调试变量并且中断输出
+     * @param mixed      $var 调试变量或者信息
+     */
+    function halt($var)
+    {
+        dump($var);
+        throw new HttpResponseException(new Response);
+    }
+}
+
+if (!function_exists('token')) {
+    /**
+     * 生成表单令牌
+     * @param string $name 令牌名称
+     * @param mixed  $type 令牌生成方法
+     * @return string
+     */
+    function token($name = '__token__', $type = 'md5')
+    {
+        $token = Request::instance()->token($name, $type);
+        return '<input type="hidden" name="' . $name . '" value="' . $token . '" />';
+    }
+}
+
+if (!function_exists('load_relation')) {
+    /**
+     * 延迟预载入关联查询
+     * @param mixed $resultSet 数据集
+     * @param mixed $relation 关联
+     * @return array
+     */
+    function load_relation($resultSet, $relation)
+    {
+        $item = current($resultSet);
+        if ($item instanceof Model) {
+            $item->eagerlyResultSet($resultSet, $relation);
+        }
+        return $resultSet;
+    }
+}
+
+if (!function_exists('collection')) {
+    /**
+     * 数组转换为数据集对象
+     * @param array $resultSet 数据集数组
+     * @return \think\model\Collection|\think\Collection
+     */
+    function collection($resultSet)
+    {
+        $item = current($resultSet);
+        if ($item instanceof Model) {
+            return \think\model\Collection::make($resultSet);
+        } else {
+            return \think\Collection::make($resultSet);
+        }
+    }
+}

+ 136 - 0
thinkphp/lang/zh-cn.php

@@ -0,0 +1,136 @@
+<?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>
+// +----------------------------------------------------------------------
+
+// 核心中文语言包
+return [
+    // 系统错误提示
+    'Undefined variable'                                        => '未定义变量',
+    'Undefined index'                                           => '未定义数组索引',
+    'Undefined offset'                                          => '未定义数组下标',
+    'Parse error'                                               => '语法解析错误',
+    'Type error'                                                => '类型错误',
+    'Fatal error'                                               => '致命错误',
+    'syntax error'                                              => '语法错误',
+
+    // 框架核心错误提示
+    'dispatch type not support'                                 => '不支持的调度类型',
+    'method param miss'                                         => '方法参数错误',
+    'method not exists'                                         => '方法不存在',
+    'module not exists'                                         => '模块不存在',
+    'controller not exists'                                     => '控制器不存在',
+    'class not exists'                                          => '类不存在',
+    'property not exists'                                       => '类的属性不存在',
+    'template not exists'                                       => '模板文件不存在',
+    'illegal controller name'                                   => '非法的控制器名称',
+    'illegal action name'                                       => '非法的操作名称',
+    'url suffix deny'                                           => '禁止的URL后缀访问',
+    'Route Not Found'                                           => '当前访问路由未定义',
+    'Undefined db type'                                         => '未定义数据库类型',
+    'variable type error'                                       => '变量类型错误',
+    'PSR-4 error'                                               => 'PSR-4 规范错误',
+    'not support total'                                         => '简洁模式下不能获取数据总数',
+    'not support last'                                          => '简洁模式下不能获取最后一页',
+    'error session handler'                                     => '错误的SESSION处理器类',
+    'not allow php tag'                                         => '模板不允许使用PHP语法',
+    'not support'                                               => '不支持',
+    'redisd master'                                             => 'Redisd 主服务器错误',
+    'redisd slave'                                              => 'Redisd 从服务器错误',
+    'must run at sae'                                           => '必须在SAE运行',
+    'memcache init error'                                       => '未开通Memcache服务,请在SAE管理平台初始化Memcache服务',
+    'KVDB init error'                                           => '没有初始化KVDB,请在SAE管理平台初始化KVDB服务',
+    'fields not exists'                                         => '数据表字段不存在',
+    'where express error'                                       => '查询表达式错误',
+    'not support data'                                          => '不支持的数据表达式',
+    'no data to update'                                         => '没有任何数据需要更新',
+    'miss data to insert'                                       => '缺少需要写入的数据',
+    'miss complex primary data'                                 => '缺少复合主键数据',
+    'miss update condition'                                     => '缺少更新条件',
+    'model data Not Found'                                      => '模型数据不存在',
+    'table data not Found'                                      => '表数据不存在',
+    'delete without condition'                                  => '没有条件不会执行删除操作',
+    'miss relation data'                                        => '缺少关联表数据',
+    'tag attr must'                                             => '模板标签属性必须',
+    'tag error'                                                 => '模板标签错误',
+    'cache write error'                                         => '缓存写入失败',
+    'sae mc write error'                                        => 'SAE mc 写入错误',
+    'route name not exists'                                     => '路由标识不存在(或参数不够)',
+    'invalid request'                                           => '非法请求',
+    'bind attr has exists'                                      => '模型的属性已经存在',
+    'relation data not exists'                                  => '关联数据不存在',
+    'relation not support'                                      => '关联不支持',
+    'chunk not support order'                                   => 'Chunk不支持调用order方法',
+    'closure not support cache(true)'                           => '使用闭包查询不支持cache(true),请指定缓存Key',
+
+    // 上传错误信息
+    'unknown upload error'                                      => '未知上传错误!',
+    'file write error'                                          => '文件写入失败!',
+    'upload temp dir not found'                                 => '找不到临时文件夹!',
+    'no file to uploaded'                                       => '没有文件被上传!',
+    'only the portion of file is uploaded'                      => '文件只有部分被上传!',
+    'upload File size exceeds the maximum value'                => '上传文件大小超过了最大值!',
+    'upload write error'                                        => '文件上传保存错误!',
+    'has the same filename: {:filename}'                        => '存在同名文件:{:filename}',
+    'upload illegal files'                                      => '非法上传文件',
+    'illegal image files'                                       => '非法图片文件',
+    'extensions to upload is not allowed'                       => '上传文件后缀不允许',
+    'mimetype to upload is not allowed'                         => '上传文件MIME类型不允许!',
+    'filesize not match'                                        => '上传文件大小不符!',
+    'directory {:path} creation failed'                         => '目录 {:path} 创建失败!',
+
+    // Validate Error Message
+    ':attribute require'                                        => ':attribute不能为空',
+    ':attribute must be numeric'                                => ':attribute必须是数字',
+    ':attribute must be integer'                                => ':attribute必须是整数',
+    ':attribute must be float'                                  => ':attribute必须是浮点数',
+    ':attribute must be bool'                                   => ':attribute必须是布尔值',
+    ':attribute not a valid email address'                      => ':attribute格式不符',
+    ':attribute not a valid mobile'                             => ':attribute格式不符',
+    ':attribute must be a array'                                => ':attribute必须是数组',
+    ':attribute must be yes,on or 1'                            => ':attribute必须是yes、on或者1',
+    ':attribute not a valid datetime'                           => ':attribute不是一个有效的日期或时间格式',
+    ':attribute not a valid file'                               => ':attribute不是有效的上传文件',
+    ':attribute not a valid image'                              => ':attribute不是有效的图像文件',
+    ':attribute must be alpha'                                  => ':attribute只能是字母',
+    ':attribute must be alpha-numeric'                          => ':attribute只能是字母和数字',
+    ':attribute must be alpha-numeric, dash, underscore'        => ':attribute只能是字母、数字和下划线_及破折号-',
+    ':attribute not a valid domain or ip'                       => ':attribute不是有效的域名或者IP',
+    ':attribute must be chinese'                                => ':attribute只能是汉字',
+    ':attribute must be chinese or alpha'                       => ':attribute只能是汉字、字母',
+    ':attribute must be chinese,alpha-numeric'                  => ':attribute只能是汉字、字母和数字',
+    ':attribute must be chinese,alpha-numeric,underscore, dash' => ':attribute只能是汉字、字母、数字和下划线_及破折号-',
+    ':attribute not a valid url'                                => ':attribute不是有效的URL地址',
+    ':attribute not a valid ip'                                 => ':attribute不是有效的IP地址',
+    ':attribute must be dateFormat of :rule'                    => ':attribute必须使用日期格式 :rule',
+    ':attribute must be in :rule'                               => ':attribute必须在 :rule 范围内',
+    ':attribute be notin :rule'                                 => ':attribute不能在 :rule 范围内',
+    ':attribute must between :1 - :2'                           => ':attribute只能在 :1 - :2 之间',
+    ':attribute not between :1 - :2'                            => ':attribute不能在 :1 - :2 之间',
+    'size of :attribute must be :rule'                          => ':attribute长度不符合要求 :rule',
+    'max size of :attribute must be :rule'                      => ':attribute长度不能超过 :rule',
+    'min size of :attribute must be :rule'                      => ':attribute长度不能小于 :rule',
+    ':attribute cannot be less than :rule'                      => ':attribute日期不能小于 :rule',
+    ':attribute cannot exceed :rule'                            => ':attribute日期不能超过 :rule',
+    ':attribute not within :rule'                               => '不在有效期内 :rule',
+    'access IP is not allowed'                                  => '不允许的IP访问',
+    'access IP denied'                                          => '禁止的IP访问',
+    ':attribute out of accord with :2'                          => ':attribute和确认字段:2不一致',
+    ':attribute cannot be same with :2'                         => ':attribute和比较字段:2不能相同',
+    ':attribute must greater than or equal :rule'               => ':attribute必须大于等于 :rule',
+    ':attribute must greater than :rule'                        => ':attribute必须大于 :rule',
+    ':attribute must less than or equal :rule'                  => ':attribute必须小于等于 :rule',
+    ':attribute must less than :rule'                           => ':attribute必须小于 :rule',
+    ':attribute must equal :rule'                               => ':attribute必须等于 :rule',
+    ':attribute has exists'                                     => ':attribute已存在',
+    ':attribute not conform to the rules'                       => ':attribute不符合指定规则',
+    'invalid Request method'                                    => '无效的请求类型',
+    'invalid token'                                             => '令牌数据无效',
+    'not conform to the rules'                                  => '规则错误',
+];

+ 681 - 0
thinkphp/library/think/App.php

@@ -0,0 +1,681 @@
+<?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>
+// +----------------------------------------------------------------------
+
+namespace think;
+
+use think\exception\ClassNotFoundException;
+use think\exception\HttpException;
+use think\exception\HttpResponseException;
+use think\exception\RouteNotFoundException;
+
+/**
+ * App 应用管理
+ * @author liu21st <liu21st@gmail.com>
+ */
+class App
+{
+    /**
+     * @var bool 是否初始化过
+     */
+    protected static $init = false;
+
+    /**
+     * @var string 当前模块路径
+     */
+    public static $modulePath;
+
+    /**
+     * @var bool 应用调试模式
+     */
+    public static $debug = true;
+
+    /**
+     * @var string 应用类库命名空间
+     */
+    public static $namespace = 'app';
+
+    /**
+     * @var bool 应用类库后缀
+     */
+    public static $suffix = false;
+
+    /**
+     * @var bool 应用路由检测
+     */
+    protected static $routeCheck;
+
+    /**
+     * @var bool 严格路由检测
+     */
+    protected static $routeMust;
+
+    /**
+     * @var array 请求调度分发
+     */
+    protected static $dispatch;
+
+    /**
+     * @var array 额外加载文件
+     */
+    protected static $file = [];
+
+    /**
+     * 执行应用程序
+     * @access public
+     * @param  Request $request 请求对象
+     * @return Response
+     * @throws Exception
+     */
+    public static function run(Request $request = null)
+    {
+        $request = is_null($request) ? Request::instance() : $request;
+
+        try {
+            $config = self::initCommon();
+
+            // 模块/控制器绑定
+            if (defined('BIND_MODULE')) {
+                BIND_MODULE && Route::bind(BIND_MODULE);
+            } elseif ($config['auto_bind_module']) {
+                // 入口自动绑定
+                $name = pathinfo($request->baseFile(), PATHINFO_FILENAME);
+                if ($name && 'index' != $name && is_dir(APP_PATH . $name)) {
+                    Route::bind($name);
+                }
+            }
+
+            $request->filter($config['default_filter']);
+
+            // 默认语言
+            Lang::range($config['default_lang']);
+            // 开启多语言机制 检测当前语言
+            $config['lang_switch_on'] && Lang::detect();
+            $request->langset(Lang::range());
+
+            // 加载系统语言包
+            Lang::load([
+                THINK_PATH . 'lang' . DS . $request->langset() . EXT,
+                APP_PATH . 'lang' . DS . $request->langset() . EXT,
+            ]);
+
+            // 监听 app_dispatch
+            Hook::listen('app_dispatch', self::$dispatch);
+            // 获取应用调度信息
+            $dispatch = self::$dispatch;
+
+            // 未设置调度信息则进行 URL 路由检测
+            if (empty($dispatch)) {
+                $dispatch = self::routeCheck($request, $config);
+            }
+
+            // 记录当前调度信息
+            $request->dispatch($dispatch);
+
+            // 记录路由和请求信息
+            if (self::$debug) {
+                Log::record('[ ROUTE ] ' . var_export($dispatch, true), 'info');
+                Log::record('[ HEADER ] ' . var_export($request->header(), true), 'info');
+                Log::record('[ PARAM ] ' . var_export($request->param(), true), 'info');
+            }
+
+            // 监听 app_begin
+            Hook::listen('app_begin', $dispatch);
+
+            // 请求缓存检查
+            $request->cache(
+                $config['request_cache'],
+                $config['request_cache_expire'],
+                $config['request_cache_except']
+            );
+
+            $data = self::exec($dispatch, $config);
+        } catch (HttpResponseException $exception) {
+            $data = $exception->getResponse();
+        }
+
+        // 清空类的实例化
+        Loader::clearInstance();
+
+        // 输出数据到客户端
+        if ($data instanceof Response) {
+            $response = $data;
+        } elseif (!is_null($data)) {
+            // 默认自动识别响应输出类型
+            $type = $request->isAjax() ?
+            Config::get('default_ajax_return') :
+            Config::get('default_return_type');
+
+            $response = Response::create($data, $type);
+        } else {
+            $response = Response::create();
+        }
+
+        // 监听 app_end
+        Hook::listen('app_end', $response);
+
+        return $response;
+    }
+
+    /**
+     * 初始化应用,并返回配置信息
+     * @access public
+     * @return array
+     */
+    public static function initCommon()
+    {
+        if (empty(self::$init)) {
+            if (defined('APP_NAMESPACE')) {
+                self::$namespace = APP_NAMESPACE;
+            }
+
+            Loader::addNamespace(self::$namespace, APP_PATH);
+
+            // 初始化应用
+            $config       = self::init();
+            self::$suffix = $config['class_suffix'];
+
+            // 应用调试模式
+            self::$debug = Env::get('app_debug', Config::get('app_debug'));
+
+            if (!self::$debug) {
+                ini_set('display_errors', 'Off');
+            } elseif (!IS_CLI) {
+                // 重新申请一块比较大的 buffer
+                if (ob_get_level() > 0) {
+                    $output = ob_get_clean();
+                }
+
+                ob_start();
+
+                if (!empty($output)) {
+                    echo $output;
+                }
+
+            }
+
+            if (!empty($config['root_namespace'])) {
+                Loader::addNamespace($config['root_namespace']);
+            }
+
+            // 加载额外文件
+            if (!empty($config['extra_file_list'])) {
+                foreach ($config['extra_file_list'] as $file) {
+                    $file = strpos($file, '.') ? $file : APP_PATH . $file . EXT;
+                    if (is_file($file) && !isset(self::$file[$file])) {
+                        include $file;
+                        self::$file[$file] = true;
+                    }
+                }
+            }
+
+            // 设置系统时区
+            date_default_timezone_set($config['default_timezone']);
+
+            // 监听 app_init
+            Hook::listen('app_init');
+
+            self::$init = true;
+        }
+
+        return Config::get();
+    }
+
+    /**
+     * 初始化应用或模块
+     * @access public
+     * @param string $module 模块名
+     * @return array
+     */
+    private static function init($module = '')
+    {
+        // 定位模块目录
+        $module = $module ? $module . DS : '';
+
+        // 加载初始化文件
+        if (is_file(APP_PATH . $module . 'init' . EXT)) {
+            include APP_PATH . $module . 'init' . EXT;
+        } elseif (is_file(RUNTIME_PATH . $module . 'init' . EXT)) {
+            include RUNTIME_PATH . $module . 'init' . EXT;
+        } else {
+            // 加载模块配置
+            $config = Config::load(CONF_PATH . $module . 'config' . CONF_EXT);
+
+            // 读取数据库配置文件
+            $filename = CONF_PATH . $module . 'database' . CONF_EXT;
+            Config::load($filename, 'database');
+
+            // 读取扩展配置文件
+            if (is_dir(CONF_PATH . $module . 'extra')) {
+                $dir   = CONF_PATH . $module . 'extra';
+                $files = scandir($dir);
+                foreach ($files as $file) {
+                    if ('.' . pathinfo($file, PATHINFO_EXTENSION) === CONF_EXT) {
+                        $filename = $dir . DS . $file;
+                        Config::load($filename, pathinfo($file, PATHINFO_FILENAME));
+                    }
+                }
+            }
+
+            // 加载应用状态配置
+            if ($config['app_status']) {
+                Config::load(CONF_PATH . $module . $config['app_status'] . CONF_EXT);
+            }
+
+            // 加载行为扩展文件
+            if (is_file(CONF_PATH . $module . 'tags' . EXT)) {
+                Hook::import(include CONF_PATH . $module . 'tags' . EXT);
+            }
+
+            // 加载公共文件
+            $path = APP_PATH . $module;
+            if (is_file($path . 'common' . EXT)) {
+                include $path . 'common' . EXT;
+            }
+
+            // 加载当前模块语言包
+            if ($module) {
+                Lang::load($path . 'lang' . DS . Request::instance()->langset() . EXT);
+            }
+        }
+
+        return Config::get();
+    }
+
+    /**
+     * 设置当前请求的调度信息
+     * @access public
+     * @param array|string  $dispatch 调度信息
+     * @param string        $type     调度类型
+     * @return void
+     */
+    public static function dispatch($dispatch, $type = 'module')
+    {
+        self::$dispatch = ['type' => $type, $type => $dispatch];
+    }
+
+    /**
+     * 执行函数或者闭包方法 支持参数调用
+     * @access public
+     * @param string|array|\Closure $function 函数或者闭包
+     * @param array                 $vars     变量
+     * @return mixed
+     */
+    public static function invokeFunction($function, $vars = [])
+    {
+        $reflect = new \ReflectionFunction($function);
+        $args    = self::bindParams($reflect, $vars);
+
+        // 记录执行信息
+        self::$debug && Log::record('[ RUN ] ' . $reflect->__toString(), 'info');
+
+        return $reflect->invokeArgs($args);
+    }
+
+    /**
+     * 调用反射执行类的方法 支持参数绑定
+     * @access public
+     * @param string|array $method 方法
+     * @param array        $vars   变量
+     * @return mixed
+     */
+    public static function invokeMethod($method, $vars = [])
+    {
+        if (is_array($method)) {
+            $class   = is_object($method[0]) ? $method[0] : self::invokeClass($method[0]);
+            $reflect = new \ReflectionMethod($class, $method[1]);
+        } else {
+            // 静态方法
+            $reflect = new \ReflectionMethod($method);
+        }
+
+        $args = self::bindParams($reflect, $vars);
+
+        self::$debug && Log::record('[ RUN ] ' . $reflect->class . '->' . $reflect->name . '[ ' . $reflect->getFileName() . ' ]', 'info');
+
+        return $reflect->invokeArgs(isset($class) ? $class : null, $args);
+    }
+
+    /**
+     * 调用反射执行类的实例化 支持依赖注入
+     * @access public
+     * @param string $class 类名
+     * @param array  $vars  变量
+     * @return mixed
+     */
+    public static function invokeClass($class, $vars = [])
+    {
+        $reflect     = new \ReflectionClass($class);
+        $constructor = $reflect->getConstructor();
+        $args        = $constructor ? self::bindParams($constructor, $vars) : [];
+
+        return $reflect->newInstanceArgs($args);
+    }
+
+    /**
+     * 绑定参数
+     * @access private
+     * @param \ReflectionMethod|\ReflectionFunction $reflect 反射类
+     * @param array                                 $vars    变量
+     * @return array
+     */
+    private static function bindParams($reflect, $vars = [])
+    {
+        // 自动获取请求变量
+        if (empty($vars)) {
+            $vars = Config::get('url_param_type') ?
+            Request::instance()->route() :
+            Request::instance()->param();
+        }
+
+        $args = [];
+        if ($reflect->getNumberOfParameters() > 0) {
+            // 判断数组类型 数字数组时按顺序绑定参数
+            reset($vars);
+            $type = key($vars) === 0 ? 1 : 0;
+
+            foreach ($reflect->getParameters() as $param) {
+                $args[] = self::getParamValue($param, $vars, $type);
+            }
+        }
+
+        return $args;
+    }
+
+    /**
+     * 获取参数值
+     * @access private
+     * @param \ReflectionParameter  $param 参数
+     * @param array                 $vars  变量
+     * @param string                $type  类别
+     * @return array
+     */
+    private static function getParamValue($param, &$vars, $type)
+    {
+        $name  = $param->getName();
+        $class = $param->getClass();
+
+        if ($class) {
+            $className = $class->getName();
+            $bind      = Request::instance()->$name;
+
+            if ($bind instanceof $className) {
+                $result = $bind;
+            } else {
+                if (method_exists($className, 'invoke')) {
+                    $method = new \ReflectionMethod($className, 'invoke');
+
+                    if ($method->isPublic() && $method->isStatic()) {
+                        return $className::invoke(Request::instance());
+                    }
+                }
+
+                $result = method_exists($className, 'instance') ?
+                $className::instance() :
+                new $className;
+            }
+        } elseif (1 == $type && !empty($vars)) {
+            $result = array_shift($vars);
+        } elseif (0 == $type && isset($vars[$name])) {
+            $result = $vars[$name];
+        } elseif ($param->isDefaultValueAvailable()) {
+            $result = $param->getDefaultValue();
+        } else {
+            throw new \InvalidArgumentException('method param miss:' . $name);
+        }
+
+        return $result;
+    }
+
+    /**
+     * 执行调用分发
+     * @access protected
+     * @param array $dispatch 调用信息
+     * @param array $config   配置信息
+     * @return Response|mixed
+     * @throws \InvalidArgumentException
+     */
+    protected static function exec($dispatch, $config)
+    {
+        switch ($dispatch['type']) {
+            case 'redirect': // 重定向跳转
+                $data = Response::create($dispatch['url'], 'redirect')
+                    ->code($dispatch['status']);
+                break;
+            case 'module': // 模块/控制器/操作
+                $data = self::module(
+                    $dispatch['module'],
+                    $config,
+                    isset($dispatch['convert']) ? $dispatch['convert'] : null
+                );
+                break;
+            case 'controller': // 执行控制器操作
+                $vars = array_merge(Request::instance()->param(), $dispatch['var']);
+                $data = Loader::action(
+                    $dispatch['controller'],
+                    $vars,
+                    $config['url_controller_layer'],
+                    $config['controller_suffix']
+                );
+                break;
+            case 'method': // 回调方法
+                $vars = array_merge(Request::instance()->param(), $dispatch['var']);
+                $data = self::invokeMethod($dispatch['method'], $vars);
+                break;
+            case 'function': // 闭包
+                $data = self::invokeFunction($dispatch['function']);
+                break;
+            case 'response': // Response 实例
+                $data = $dispatch['response'];
+                break;
+            default:
+                throw new \InvalidArgumentException('dispatch type not support');
+        }
+
+        return $data;
+    }
+
+    /**
+     * 执行模块
+     * @access public
+     * @param array $result  模块/控制器/操作
+     * @param array $config  配置参数
+     * @param bool  $convert 是否自动转换控制器和操作名
+     * @return mixed
+     * @throws HttpException
+     */
+    public static function module($result, $config, $convert = null)
+    {
+        if (is_string($result)) {
+            $result = explode('/', $result);
+        }
+
+        $request = Request::instance();
+
+        if ($config['app_multi_module']) {
+            // 多模块部署
+            if($convert){ //增加模块的大小写是否自动转换的功能
+                $module    = strip_tags(strtolower($result[0] ?: $config['default_module']));
+            }else{
+                $module    = strip_tags($result[0] ?: $config['default_module']);
+            }
+            $bind      = Route::getBind('module');
+            $available = false;
+
+            if ($bind) {
+                // 绑定模块
+                list($bindModule) = explode('/', $bind);
+
+                if (empty($result[0])) {
+                    $module    = $bindModule;
+                    $available = true;
+                } elseif ($module == $bindModule) {
+                    $available = true;
+                }
+            } elseif (!in_array($module, $config['deny_module_list']) && is_dir(APP_PATH . $module)) {
+                $available = true;
+            }
+
+            // 模块初始化
+            if ($module && $available) {
+                // 初始化模块
+                $request->module($module);
+                $config = self::init($module);
+
+                // 模块请求缓存检查
+                $request->cache(
+                    $config['request_cache'],
+                    $config['request_cache_expire'],
+                    $config['request_cache_except']
+                );
+            } else {
+                throw new HttpException(404, 'module not exists:' . $module);
+            }
+        } else {
+            // 单一模块部署
+            $module = '';
+            $request->module($module);
+        }
+
+        // 设置默认过滤机制
+        $request->filter($config['default_filter']);
+
+        // 当前模块路径
+        App::$modulePath = APP_PATH . ($module ? $module . DS : '');
+
+        // 是否自动转换控制器和操作名
+        $convert = is_bool($convert) ? $convert : $config['url_convert'];
+
+        // 获取控制器名
+        $controller = strip_tags($result[1] ?: $config['default_controller']);
+
+        if (!preg_match('/^[A-Za-z](\w|\.)*$/', $controller)) {
+            throw new HttpException(404, 'controller not exists:' . $controller);
+        }
+
+        $controller = $convert ? strtolower($controller) : $controller;
+
+        // 获取操作名
+        $actionName = strip_tags($result[2] ?: $config['default_action']);
+        if (!empty($config['action_convert'])) {
+            $actionName = Loader::parseName($actionName, 1);
+        } else {
+            $actionName = $convert ? strtolower($actionName) : $actionName;
+        }
+
+        // 设置当前请求的控制器、操作
+        $request->controller(Loader::parseName($controller, 1))->action($actionName);
+
+        // 监听module_init
+        Hook::listen('module_init', $request);
+
+        try {
+            $instance = Loader::controller(
+                $controller,
+                $config['url_controller_layer'],
+                $config['controller_suffix'],
+                $config['empty_controller']
+            );
+        } catch (ClassNotFoundException $e) {
+            throw new HttpException(404, 'controller not exists:' . $e->getClass());
+        }
+
+        // 获取当前操作名
+        $action = $actionName . $config['action_suffix'];
+
+        $vars = [];
+        if (is_callable([$instance, $action])) {
+            // 执行操作方法
+            $call = [$instance, $action];
+            // 严格获取当前操作方法名
+            $reflect    = new \ReflectionMethod($instance, $action);
+            $methodName = $reflect->getName();
+            $suffix     = $config['action_suffix'];
+            $actionName = $suffix ? substr($methodName, 0, -strlen($suffix)) : $methodName;
+            $request->action($actionName);
+
+        } elseif (is_callable([$instance, '_empty'])) {
+            // 空操作
+            $call = [$instance, '_empty'];
+            $vars = [$actionName];
+        } else {
+            // 操作不存在
+            throw new HttpException(404, 'method not exists:' . get_class($instance) . '->' . $action . '()');
+        }
+
+        Hook::listen('action_begin', $call);
+
+        return self::invokeMethod($call, $vars);
+    }
+
+    /**
+     * URL路由检测(根据PATH_INFO)
+     * @access public
+     * @param  \think\Request $request 请求实例
+     * @param  array          $config  配置信息
+     * @return array
+     * @throws \think\Exception
+     */
+    public static function routeCheck($request, array $config)
+    {
+        $path   = $request->path();
+        $depr   = $config['pathinfo_depr'];
+        $result = false;
+
+        // 路由检测
+        $check = !is_null(self::$routeCheck) ? self::$routeCheck : $config['url_route_on'];
+        if ($check) {
+            // 开启路由
+            if (is_file(RUNTIME_PATH . 'route.php')) {
+                // 读取路由缓存
+                $rules = include RUNTIME_PATH . 'route.php';
+                is_array($rules) && Route::rules($rules);
+            } else {
+                $files = $config['route_config_file'];
+                foreach ($files as $file) {
+                    if (is_file(CONF_PATH . $file . CONF_EXT)) {
+                        // 导入路由配置
+                        $rules = include CONF_PATH . $file . CONF_EXT;
+                        is_array($rules) && Route::import($rules);
+                    }
+                }
+            }
+
+            // 路由检测(根据路由定义返回不同的URL调度)
+            $result = Route::check($request, $path, $depr, $config['url_domain_deploy']);
+            $must   = !is_null(self::$routeMust) ? self::$routeMust : $config['url_route_must'];
+
+            if ($must && false === $result) {
+                // 路由无效
+                throw new RouteNotFoundException();
+            }
+        }
+
+        // 路由无效 解析模块/控制器/操作/参数... 支持控制器自动搜索
+        if (false === $result) {
+            $result = Route::parseUrl($path, $depr, $config['controller_auto_search']);
+        }
+
+        return $result;
+    }
+
+    /**
+     * 设置应用的路由检测机制
+     * @access public
+     * @param  bool $route 是否需要检测路由
+     * @param  bool $must  是否强制检测路由
+     * @return void
+     */
+    public static function route($route, $must = false)
+    {
+        self::$routeCheck = $route;
+        self::$routeMust  = $must;
+    }
+}

+ 235 - 0
thinkphp/library/think/Build.php

@@ -0,0 +1,235 @@
+<?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>
+// +----------------------------------------------------------------------
+
+namespace think;
+
+class Build
+{
+    /**
+     * 根据传入的 build 资料创建目录和文件
+     * @access public
+     * @param  array  $build     build 列表
+     * @param  string $namespace 应用类库命名空间
+     * @param  bool   $suffix    类库后缀
+     * @return void
+     * @throws Exception
+     */
+    public static function run(array $build = [], $namespace = 'app', $suffix = false)
+    {
+        // 锁定
+        $lock = APP_PATH . 'build.lock';
+
+        // 如果锁定文件不可写(不存在)则进行处理,否则表示已经有程序在处理了
+        if (!is_writable($lock)) {
+            if (!touch($lock)) {
+                throw new Exception(
+                    '应用目录[' . APP_PATH . ']不可写,目录无法自动生成!<BR>请手动生成项目目录~',
+                    10006
+                );
+            }
+
+            foreach ($build as $module => $list) {
+                if ('__dir__' == $module) {
+                    // 创建目录列表
+                    self::buildDir($list);
+                } elseif ('__file__' == $module) {
+                    // 创建文件列表
+                    self::buildFile($list);
+                } else {
+                    // 创建模块
+                    self::module($module, $list, $namespace, $suffix);
+                }
+            }
+
+            // 解除锁定
+            unlink($lock);
+        }
+    }
+
+    /**
+     * 创建目录
+     * @access protected
+     * @param  array $list 目录列表
+     * @return void
+     */
+    protected static function buildDir($list)
+    {
+        foreach ($list as $dir) {
+            // 目录不存在则创建目录
+            !is_dir(APP_PATH . $dir) && mkdir(APP_PATH . $dir, 0755, true);
+        }
+    }
+
+    /**
+     * 创建文件
+     * @access protected
+     * @param  array $list 文件列表
+     * @return void
+     */
+    protected static function buildFile($list)
+    {
+        foreach ($list as $file) {
+            // 先创建目录
+            if (!is_dir(APP_PATH . dirname($file))) {
+                mkdir(APP_PATH . dirname($file), 0755, true);
+            }
+
+            // 再创建文件
+            if (!is_file(APP_PATH . $file)) {
+                file_put_contents(
+                    APP_PATH . $file,
+                    'php' == pathinfo($file, PATHINFO_EXTENSION) ? "<?php\n" : ''
+                );
+            }
+        }
+    }
+
+    /**
+     * 创建模块
+     * @access public
+     * @param  string $module    模块名
+     * @param  array  $list      build 列表
+     * @param  string $namespace 应用类库命名空间
+     * @param  bool   $suffix    类库后缀
+     * @return void
+     */
+    public static function module($module = '', $list = [], $namespace = 'app', $suffix = false)
+    {
+        $module = $module ?: '';
+
+        // 创建模块目录
+        !is_dir(APP_PATH . $module) && mkdir(APP_PATH . $module);
+
+        // 如果不是 runtime 目录则需要创建配置文件和公共文件、创建模块的默认页面
+        if (basename(RUNTIME_PATH) != $module) {
+            self::buildCommon($module);
+            self::buildHello($module, $namespace, $suffix);
+        }
+
+        // 未指定文件和目录,则创建默认的模块目录和文件
+        if (empty($list)) {
+            $list = [
+                '__file__' => ['config.php', 'common.php'],
+                '__dir__'  => ['controller', 'model', 'view'],
+            ];
+        }
+
+        // 创建子目录和文件
+        foreach ($list as $path => $file) {
+            $modulePath = APP_PATH . $module . DS;
+
+            if ('__dir__' == $path) {
+                // 生成子目录
+                foreach ($file as $dir) {
+                    self::checkDirBuild($modulePath . $dir);
+                }
+            } elseif ('__file__' == $path) {
+                // 生成(空白)文件
+                foreach ($file as $name) {
+                    if (!is_file($modulePath . $name)) {
+                        file_put_contents(
+                            $modulePath . $name,
+                            'php' == pathinfo($name, PATHINFO_EXTENSION) ? "<?php\n" : ''
+                        );
+                    }
+                }
+            } else {
+                // 生成相关 MVC 文件
+                foreach ($file as $val) {
+                    $val      = trim($val);
+                    $filename = $modulePath . $path . DS . $val . ($suffix ? ucfirst($path) : '') . EXT;
+                    $space    = $namespace . '\\' . ($module ? $module . '\\' : '') . $path;
+                    $class    = $val . ($suffix ? ucfirst($path) : '');
+
+                    switch ($path) {
+                        case 'controller': // 控制器
+                            $content = "<?php\nnamespace {$space};\n\nclass {$class}\n{\n\n}";
+                            break;
+                        case 'model': // 模型
+                            $content = "<?php\nnamespace {$space};\n\nuse think\Model;\n\nclass {$class} extends Model\n{\n\n}";
+                            break;
+                        case 'view': // 视图
+                            $filename = $modulePath . $path . DS . $val . '.html';
+                            self::checkDirBuild(dirname($filename));
+                            $content = '';
+                            break;
+                        default:
+                            // 其他文件
+                            $content = "<?php\nnamespace {$space};\n\nclass {$class}\n{\n\n}";
+                    }
+
+                    if (!is_file($filename)) {
+                        file_put_contents($filename, $content);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 创建模块的欢迎页面
+     * @access protected
+     * @param  string $module    模块名
+     * @param  string $namespace 应用类库命名空间
+     * @param  bool   $suffix    类库后缀
+     * @return void
+     */
+    protected static function buildHello($module, $namespace, $suffix = false)
+    {
+        $filename = APP_PATH . ($module ? $module . DS : '') .
+            'controller' . DS . 'Index' .
+            ($suffix ? 'Controller' : '') . EXT;
+
+        if (!is_file($filename)) {
+            $module = $module ? $module . '\\' : '';
+            $suffix = $suffix ? 'Controller' : '';
+            $content = str_replace(
+                ['{$app}', '{$module}', '{layer}', '{$suffix}'],
+                [$namespace, $module, 'controller', $suffix],
+                file_get_contents(THINK_PATH . 'tpl' . DS . 'default_index.tpl')
+            );
+
+            self::checkDirBuild(dirname($filename));
+            file_put_contents($filename, $content);
+        }
+    }
+
+    /**
+     * 创建模块的公共文件
+     * @access protected
+     * @param  string $module 模块名
+     * @return void
+     */
+    protected static function buildCommon($module)
+    {
+        $config = CONF_PATH . ($module ? $module . DS : '') . 'config.php';
+
+        self::checkDirBuild(dirname($config));
+
+        if (!is_file($config)) {
+            file_put_contents($config, "<?php\n//配置文件\nreturn [\n\n];");
+        }
+
+        $common = APP_PATH . ($module ? $module . DS : '') . 'common.php';
+        if (!is_file($common)) file_put_contents($common, "<?php\n");
+    }
+
+    /**
+     * 创建目录
+     * @access protected
+     * @param  string $dirname 目录名称
+     * @return void
+     */
+    protected static function checkDirBuild($dirname)
+    {
+        !is_dir($dirname) && mkdir($dirname, 0755, true);
+    }
+}

+ 247 - 0
thinkphp/library/think/Cache.php

@@ -0,0 +1,247 @@
+<?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>
+// +----------------------------------------------------------------------
+
+namespace think;
+
+use think\cache\Driver;
+
+class Cache
+{
+    /**
+     * @var array 缓存的实例
+     */
+    public static $instance = [];
+
+    /**
+     * @var int 缓存读取次数
+     */
+    public static $readTimes = 0;
+
+    /**
+     * @var int 缓存写入次数
+     */
+    public static $writeTimes = 0;
+
+    /**
+     * @var object 操作句柄
+     */
+    public static $handler;
+
+    /**
+     * 连接缓存驱动
+     * @access public
+     * @param  array       $options 配置数组
+     * @param  bool|string $name    缓存连接标识 true 强制重新连接
+     * @return Driver
+     */
+    public static function connect(array $options = [], $name = false)
+    {
+        $type = !empty($options['type']) ? $options['type'] : 'File';
+
+        if (false === $name) {
+            $name = md5(serialize($options));
+        }
+
+        if (true === $name || !isset(self::$instance[$name])) {
+            $class = false === strpos($type, '\\') ?
+            '\\think\\cache\\driver\\' . ucwords($type) :
+            $type;
+
+            // 记录初始化信息
+            App::$debug && Log::record('[ CACHE ] INIT ' . $type, 'info');
+
+            if (true === $name) {
+                return new $class($options);
+            }
+
+            self::$instance[$name] = new $class($options);
+        }
+
+        return self::$instance[$name];
+    }
+
+    /**
+     * 自动初始化缓存
+     * @access public
+     * @param  array $options 配置数组
+     * @return Driver
+     */
+    public static function init(array $options = [])
+    {
+        if (is_null(self::$handler)) {
+            if (empty($options) && 'complex' == Config::get('cache.type')) {
+                $default = Config::get('cache.default');
+                // 获取默认缓存配置,并连接
+                $options = Config::get('cache.' . $default['type']) ?: $default;
+            } elseif (empty($options)) {
+                $options = Config::get('cache');
+            }
+
+            self::$handler = self::connect($options);
+        }
+
+        return self::$handler;
+    }
+
+    /**
+     * 切换缓存类型 需要配置 cache.type 为 complex
+     * @access public
+     * @param  string $name 缓存标识
+     * @return Driver
+     */
+    public static function store($name = '')
+    {
+        if ('' !== $name && 'complex' == Config::get('cache.type')) {
+            return self::connect(Config::get('cache.' . $name), strtolower($name));
+        }
+
+        return self::init();
+    }
+
+    /**
+     * 判断缓存是否存在
+     * @access public
+     * @param  string $name 缓存变量名
+     * @return bool
+     */
+    public static function has($name)
+    {
+        self::$readTimes++;
+
+        return self::init()->has($name);
+    }
+
+    /**
+     * 读取缓存
+     * @access public
+     * @param  string $name    缓存标识
+     * @param  mixed  $default 默认值
+     * @return mixed
+     */
+    public static function get($name, $default = false)
+    {
+        self::$readTimes++;
+
+        return self::init()->get($name, $default);
+    }
+
+    /**
+     * 写入缓存
+     * @access public
+     * @param  string   $name   缓存标识
+     * @param  mixed    $value  存储数据
+     * @param  int|null $expire 有效时间 0为永久
+     * @return boolean
+     */
+    public static function set($name, $value, $expire = null)
+    {
+        self::$writeTimes++;
+
+        return self::init()->set($name, $value, $expire);
+    }
+
+    /**
+     * 自增缓存(针对数值缓存)
+     * @access public
+     * @param  string $name 缓存变量名
+     * @param  int    $step 步长
+     * @return false|int
+     */
+    public static function inc($name, $step = 1)
+    {
+        self::$writeTimes++;
+
+        return self::init()->inc($name, $step);
+    }
+
+    /**
+     * 自减缓存(针对数值缓存)
+     * @access public
+     * @param  string $name 缓存变量名
+     * @param  int    $step 步长
+     * @return false|int
+     */
+    public static function dec($name, $step = 1)
+    {
+        self::$writeTimes++;
+
+        return self::init()->dec($name, $step);
+    }
+
+    /**
+     * 删除缓存
+     * @access public
+     * @param  string $name 缓存标识
+     * @return boolean
+     */
+    public static function rm($name)
+    {
+        self::$writeTimes++;
+
+        return self::init()->rm($name);
+    }
+
+    /**
+     * 清除缓存
+     * @access public
+     * @param  string $tag 标签名
+     * @return boolean
+     */
+    public static function clear($tag = null)
+    {
+        self::$writeTimes++;
+
+        return self::init()->clear($tag);
+    }
+
+    /**
+     * 读取缓存并删除
+     * @access public
+     * @param  string $name 缓存变量名
+     * @return mixed
+     */
+    public static function pull($name)
+    {
+        self::$readTimes++;
+        self::$writeTimes++;
+
+        return self::init()->pull($name);
+    }
+
+    /**
+     * 如果不存在则写入缓存
+     * @access public
+     * @param  string $name   缓存变量名
+     * @param  mixed  $value  存储数据
+     * @param  int    $expire 有效时间 0为永久
+     * @return mixed
+     */
+    public static function remember($name, $value, $expire = null)
+    {
+        self::$readTimes++;
+
+        return self::init()->remember($name, $value, $expire);
+    }
+
+    /**
+     * 缓存标签
+     * @access public
+     * @param  string       $name    标签名
+     * @param  string|array $keys    缓存标识
+     * @param  bool         $overlay 是否覆盖
+     * @return Driver
+     */
+    public static function tag($name, $keys = null, $overlay = false)
+    {
+        return self::init()->tag($name, $keys, $overlay);
+    }
+
+}

+ 467 - 0
thinkphp/library/think/Collection.php

@@ -0,0 +1,467 @@
+<?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: zhangyajun <448901948@qq.com>
+// +----------------------------------------------------------------------
+
+namespace think;
+
+use ArrayAccess;
+use ArrayIterator;
+use Countable;
+use IteratorAggregate;
+use JsonSerializable;
+
+class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable
+{
+    /**
+     * @var array 数据
+     */
+    protected $items = [];
+
+    /**
+     * Collection constructor.
+     * @access public
+     * @param  array $items 数据
+     */
+    public function __construct($items = [])
+    {
+        $this->items = $this->convertToArray($items);
+    }
+
+    /**
+     * 创建 Collection 实例
+     * @access public
+     * @param  array $items 数据
+     * @return static
+     */
+    public static function make($items = [])
+    {
+        return new static($items);
+    }
+
+    /**
+     * 判断数据是否为空
+     * @access public
+     * @return bool
+     */
+    public function isEmpty()
+    {
+        return empty($this->items);
+    }
+
+    /**
+     * 将数据转成数组
+     * @access public
+     * @return array
+     */
+    public function toArray()
+    {
+        return array_map(function ($value) {
+            return ($value instanceof Model || $value instanceof self) ?
+                $value->toArray() :
+                $value;
+        }, $this->items);
+    }
+
+    /**
+     * 获取全部的数据
+     * @access public
+     * @return array
+     */
+    public function all()
+    {
+        return $this->items;
+    }
+
+    /**
+     * 交换数组中的键和值
+     * @access public
+     * @return static
+     */
+    public function flip()
+    {
+        return new static(array_flip($this->items));
+    }
+
+    /**
+     * 返回数组中所有的键名组成的新 Collection 实例
+     * @access public
+     * @return static
+     */
+    public function keys()
+    {
+        return new static(array_keys($this->items));
+    }
+
+    /**
+     * 返回数组中所有的值组成的新 Collection 实例
+     * @access public
+     * @return static
+     */
+    public function values()
+    {
+        return new static(array_values($this->items));
+    }
+
+    /**
+     * 合并数组并返回一个新的 Collection 实例
+     * @access public
+     * @param  mixed $items 新的数据
+     * @return static
+     */
+    public function merge($items)
+    {
+        return new static(array_merge($this->items, $this->convertToArray($items)));
+    }
+
+    /**
+     * 比较数组,返回差集生成的新 Collection 实例
+     * @access public
+     * @param  mixed $items 做比较的数据
+     * @return static
+     */
+    public function diff($items)
+    {
+        return new static(array_diff($this->items, $this->convertToArray($items)));
+    }
+
+    /**
+     * 比较数组,返回交集组成的 Collection 新实例
+     * @access public
+     * @param  mixed $items 比较数据
+     * @return static
+     */
+    public function intersect($items)
+    {
+        return new static(array_intersect($this->items, $this->convertToArray($items)));
+    }
+
+    /**
+     * 返回并删除数据中的的最后一个元素(出栈)
+     * @access public
+     * @return mixed
+     */
+    public function pop()
+    {
+        return array_pop($this->items);
+    }
+
+    /**
+     * 返回并删除数据中首个元素
+     * @access public
+     * @return mixed
+     */
+    public function shift()
+    {
+        return array_shift($this->items);
+    }
+
+    /**
+     * 在数组开头插入一个元素
+     * @access public
+     * @param mixed $value 值
+     * @param mixed $key   键名
+     * @return void
+     */
+    public function unshift($value, $key = null)
+    {
+        if (is_null($key)) {
+            array_unshift($this->items, $value);
+        } else {
+            $this->items = [$key => $value] + $this->items;
+        }
+    }
+
+    /**
+     * 在数组结尾插入一个元素
+     * @access public
+     * @param  mixed $value 值
+     * @param  mixed $key   键名
+     * @return void
+     */
+    public function push($value, $key = null)
+    {
+        if (is_null($key)) {
+            $this->items[] = $value;
+        } else {
+            $this->items[$key] = $value;
+        }
+    }
+
+    /**
+     * 通过使用用户自定义函数,以字符串返回数组
+     * @access public
+     * @param  callable $callback 回调函数
+     * @param  mixed    $initial  初始值
+     * @return mixed
+     */
+    public function reduce(callable $callback, $initial = null)
+    {
+        return array_reduce($this->items, $callback, $initial);
+    }
+
+    /**
+     * 以相反的顺序创建一个新的 Collection 实例
+     * @access public
+     * @return static
+     */
+    public function reverse()
+    {
+        return new static(array_reverse($this->items));
+    }
+
+    /**
+     * 把数据分割为新的数组块
+     * @access public
+     * @param  int  $size         分隔长度
+     * @param  bool $preserveKeys 是否保持原数据索引
+     * @return static
+     */
+    public function chunk($size, $preserveKeys = false)
+    {
+        $chunks = [];
+
+        foreach (array_chunk($this->items, $size, $preserveKeys) as $chunk) {
+            $chunks[] = new static($chunk);
+        }
+
+        return new static($chunks);
+    }
+
+    /**
+     * 给数据中的每个元素执行回调
+     * @access public
+     * @param  callable $callback 回调函数
+     * @return $this
+     */
+    public function each(callable $callback)
+    {
+        foreach ($this->items as $key => $item) {
+            $result = $callback($item, $key);
+
+            if (false === $result) {
+                break;
+            }
+
+            if (!is_object($item)) {
+                $this->items[$key] = $result;
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * 用回调函数过滤数据中的元素
+     * @access public
+     * @param callable|null $callback 回调函数
+     * @return static
+     */
+    public function filter(callable $callback = null)
+    {
+        return new static(array_filter($this->items, $callback ?: null));
+    }
+
+    /**
+     * 返回数据中指定的一列
+     * @access public
+     * @param mixed $columnKey 键名
+     * @param null  $indexKey  作为索引值的列
+     * @return array
+     */
+    public function column($columnKey, $indexKey = null)
+    {
+        if (function_exists('array_column')) {
+            return array_column($this->items, $columnKey, $indexKey);
+        }
+
+        $result = [];
+        foreach ($this->items as $row) {
+            $key    = $value = null;
+            $keySet = $valueSet = false;
+
+            if (null !== $indexKey && array_key_exists($indexKey, $row)) {
+                $key    = (string) $row[$indexKey];
+                $keySet = true;
+            }
+
+            if (null === $columnKey) {
+                $valueSet = true;
+                $value    = $row;
+            } elseif (is_array($row) && array_key_exists($columnKey, $row)) {
+                $valueSet = true;
+                $value    = $row[$columnKey];
+            }
+
+            if ($valueSet) {
+                if ($keySet) {
+                    $result[$key] = $value;
+                } else {
+                    $result[] = $value;
+                }
+            }
+        }
+
+        return $result;
+    }
+
+    /**
+     * 对数据排序,并返回排序后的数据组成的新 Collection 实例
+     * @access public
+     * @param  callable|null $callback 回调函数
+     * @return static
+     */
+    public function sort(callable $callback = null)
+    {
+        $items    = $this->items;
+        $callback = $callback ?: function ($a, $b) {
+            return $a == $b ? 0 : (($a < $b) ? -1 : 1);
+        };
+
+        uasort($items, $callback);
+        return new static($items);
+    }
+
+    /**
+     * 将数据打乱后组成新的 Collection 实例
+     * @access public
+     * @return static
+     */
+    public function shuffle()
+    {
+        $items = $this->items;
+
+        shuffle($items);
+        return new static($items);
+    }
+
+    /**
+     * 截取数据并返回新的 Collection 实例
+     * @access public
+     * @param  int  $offset       起始位置
+     * @param  int  $length       截取长度
+     * @param  bool $preserveKeys 是否保持原先的键名
+     * @return static
+     */
+    public function slice($offset, $length = null, $preserveKeys = false)
+    {
+        return new static(array_slice($this->items, $offset, $length, $preserveKeys));
+    }
+
+    /**
+     * 指定的键是否存在
+     * @access public
+     * @param  mixed $offset 键名
+     * @return bool
+     */
+    public function offsetExists($offset)
+    {
+        return array_key_exists($offset, $this->items);
+    }
+
+    /**
+     * 获取指定键对应的值
+     * @access public
+     * @param  mixed $offset 键名
+     * @return mixed
+     */
+    public function offsetGet($offset)
+    {
+        return $this->items[$offset];
+    }
+
+    /**
+     * 设置键值
+     * @access public
+     * @param  mixed $offset 键名
+     * @param  mixed $value  值
+     * @return void
+     */
+    public function offsetSet($offset, $value)
+    {
+        if (is_null($offset)) {
+            $this->items[] = $value;
+        } else {
+            $this->items[$offset] = $value;
+        }
+    }
+
+    /**
+     * 删除指定键值
+     * @access public
+     * @param  mixed $offset 键名
+     * @return void
+     */
+    public function offsetUnset($offset)
+    {
+        unset($this->items[$offset]);
+    }
+
+    /**
+     * 统计数据的个数
+     * @access public
+     * @return int
+     */
+    public function count()
+    {
+        return count($this->items);
+    }
+
+    /**
+     * 获取数据的迭代器
+     * @access public
+     * @return ArrayIterator
+     */
+    public function getIterator()
+    {
+        return new ArrayIterator($this->items);
+    }
+
+    /**
+     * 将数据反序列化成数组
+     * @access public
+     * @return array
+     */
+    public function jsonSerialize()
+    {
+        return $this->toArray();
+    }
+
+    /**
+     * 转换当前数据集为 JSON 字符串
+     * @access public
+     * @param  integer $options json 参数
+     * @return string
+     */
+    public function toJson($options = JSON_UNESCAPED_UNICODE)
+    {
+        return json_encode($this->toArray(), $options);
+    }
+
+    /**
+     * 将数据转换成字符串
+     * @access public
+     * @return string
+     */
+    public function __toString()
+    {
+        return $this->toJson();
+    }
+
+    /**
+     * 将数据转换成数组
+     * @access protected
+     * @param  mixed $items 数据
+     * @return array
+     */
+    protected function convertToArray($items)
+    {
+        return $items instanceof self ? $items->all() : (array) $items;
+    }
+}

Some files were not shown because too many files changed in this diff