初始化项目

This commit is contained in:
2026-09-01 22:15:50 +08:00
commit b5a26a8848
11217 changed files with 1710987 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
APP_DEBUG = false␍␍[APP]␍DEFAULT_TIMEZONE = Asia/Shanghai␍␍[DATABASE]␍TYPE = mysql␍HOSTNAME = 127.0.0.1␍DATABASE = oil␍USERNAME = user␍PASSWORD = qQ19961012␍HOSTPORT = 3306␍CHARSET = utf8␍DEBUG = true␍␍[CACHE]␍DRIVER = file␍␍[REDIS]␍HOSTNAME = 127.0.0.1␍HOSTPORT = 6379␍PASSWORD =␍SELECT = 0␍␍[LANG]␍default_lang = zh-cn␍
+3
View File
@@ -0,0 +1,3 @@
/.idea
/.vscode
*.log
+42
View File
@@ -0,0 +1,42 @@
sudo: false
language: php
branches:
only:
- stable
cache:
directories:
- $HOME/.composer/cache
before_install:
- composer self-update
install:
- composer install --no-dev --no-interaction --ignore-platform-reqs
- zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Core.zip .
- composer require --update-no-dev --no-interaction "topthink/think-image:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-migration:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-captcha:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-mongo:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-worker:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-helper:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-queue:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-angular:^1.0"
- composer require --dev --update-no-dev --no-interaction "topthink/think-testing:^1.0"
- zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Full.zip .
script:
- php think unit
deploy:
provider: releases
api_key:
secure: TSF6bnl2JYN72UQOORAJYL+CqIryP2gHVKt6grfveQ7d9rleAEoxlq6PWxbvTI4jZ5nrPpUcBUpWIJHNgVcs+bzLFtyh5THaLqm39uCgBbrW7M8rI26L8sBh/6nsdtGgdeQrO/cLu31QoTzbwuz1WfAVoCdCkOSZeXyT/CclH99qV6RYyQYqaD2wpRjrhA5O4fSsEkiPVuk0GaOogFlrQHx+C+lHnf6pa1KxEoN1A0UxxVfGX6K4y5g4WQDO5zT4bLeubkWOXK0G51XSvACDOZVIyLdjApaOFTwamPcD3S1tfvuxRWWvsCD5ljFvb2kSmx5BIBNwN80MzuBmrGIC27XLGOxyMerwKxB6DskNUO9PflKHDPI61DRq0FTy1fv70SFMSiAtUv9aJRT41NQh9iJJ0vC8dl+xcxrWIjU1GG6+l/ZcRqVx9V1VuGQsLKndGhja7SQ+X1slHl76fRq223sMOql7MFCd0vvvxVQ2V39CcFKao/LB1aPH3VhODDEyxwx6aXoTznvC/QPepgWsHOWQzKj9ftsgDbsNiyFlXL4cu8DWUty6rQy8zT2b4O8b1xjcwSUCsy+auEjBamzQkMJFNlZAIUrukL/NbUhQU37TAbwsFyz7X0E/u/VMle/nBCNAzgkMwAUjiHM6FqrKKBRWFbPrSIixjfjkCnrMEPw=
file:
- ThinkPHP_Core.zip
- ThinkPHP_Full.zip
skip_cleanup: true
on:
tags: true
+191
View File
@@ -0,0 +1,191 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, "control" means (i) the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising
permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.
"Object" form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
"submitted" means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.
2. Grant of Copyright License.
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.
3. Grant of Patent License.
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.
4. Redistribution.
You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:
You must give any other recipients of the Work or Derivative Works a copy of
this License; and
You must cause any modified files to carry prominent notices stating that You
changed the files; and
You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source form
of the Work, excluding those notices that do not pertain to any part of the
Derivative Works; and
If the Work includes a "NOTICE" text file as part of its distribution, then any
Derivative Works that You distribute must include a readable copy of the
attribution notices contained within such NOTICE file, excluding those notices
that do not pertain to any part of the Derivative Works, in at least one of the
following places: within a NOTICE text file distributed as part of the
Derivative Works; within the Source form or documentation, if provided along
with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents of
the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works that
You distribute, alongside or as an addendum to the NOTICE text from the Work,
provided that such additional attribution notices cannot be construed as
modifying the License.
You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a whole,
provided Your use, reproduction, and distribution of the Work otherwise complies
with the conditions stated in this License.
5. Submission of Contributions.
Unless You explicitly state otherwise, any Contribution intentionally submitted
for inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the terms of
any separate license agreement you may have executed with Licensor regarding
such Contributions.
6. Trademarks.
This License does not grant permission to use the trade names, trademarks,
service marks, or product names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
7. Disclaimer of Warranty.
Unless required by applicable law or agreed to in writing, Licensor provides the
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
including, without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.
8. Limitation of Liability.
In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as deliberate
and grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License or
out of the use or inability to use the Work (including but not limited to
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has
been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability.
While redistributing the Work or Derivative Works thereof, You may choose to
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
other liability obligations and/or rights consistent with this License. However,
in accepting such obligations, You may act only on Your own behalf and on Your
sole responsibility, not on behalf of any other Contributor, and only if You
agree to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work
To apply the Apache License to your work, attach the following boilerplate
notice, with the fields enclosed by brackets "{}" replaced with your own
identifying information. (Don't include the brackets!) The text should be
enclosed in the appropriate comment syntax for the file format. We also
recommend that a file or class name and description of purpose be included on
the same "printed page" as the copyright notice for easier identification within
third-party archives.
Copyright 2018 萤火科技
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+116
View File
@@ -0,0 +1,116 @@
# 萤火商城V2.0开源版
#### 项目介绍
萤火商城V2.0,是全新推出的一款轻量级、高性能、前后端分离的电商系统,支持微信小程序 + H5+ 公众号 + APP,前后端源码完全开源,看见及所得,完美支持二次开发,可学习可商用,让您快速搭建个性化独立商城。
如果对您有帮助,您可以点右上角 “Star” 收藏一下 ,获取第一时间更新,谢谢!
#### 技术特点
* 前后端完全分离 (互不依赖 开发效率高)
* 采用PHP7.4 (强类型严格模式)
* Thinkphp6.0.5(轻量级PHP开发框架)
* Uni-APP(开发跨平台应用的前端框架)
* Ant Design Vue(企业级中后台产品UI组件库)
* RBAC(基于角色的权限控制管理)
* Composer一键引入三方扩展
* 部署运行的项目体积仅30多MB(真正的轻量化)
* 所有端代码开源 (服务端PHP、后台vue端、uniapp端)
* 简约高效的编码风格 (可能是最适合二开的源码)
* 源码中清晰中文注释 (小白也能看懂的代码)
#### 页面展示
![前端展示](https://images.gitee.com/uploads/images/2021/0316/215102_7bcb0802_2166072.png "前端展示.png")
![后台-首页](https://images.gitee.com/uploads/images/2021/0316/215827_7df5251c_2166072.png "后台-首页.png")
![后台-页面设计](https://images.gitee.com/uploads/images/2021/0316/215839_2d4ebccc_2166072.png "后台-页面设计.png")
![后台-编辑商品](https://images.gitee.com/uploads/images/2021/0316/215848_9d54adff_2166072.png "后台-编辑商品.png")
![后台-订单详情](https://images.gitee.com/uploads/images/2021/0316/215855_8606fce3_2166072.png "后台-订单详情.png")
#### 系统演示
- 商城后台演示:https://shop2.yiovo.com/admin/
- 用户名和密码:admin yinghuo
![前端演示二维码](https://images.gitee.com/uploads/images/2021/0316/104516_3778337e_2166072.png "111.png")
- QQ交流群 806461900
#### 源码下载
1. 主商城端(又称后端、服务端,PHP开发 用于管理后台和提供api接口)
下载地址:https://gitee.com/xany/yoshop2.0
2. 用户端(也叫客户端、前端,uniapp开发 用于生成H5和微信小程序)
下载地址:https://gitee.com/xany/yoshop2.0-uniapp
2. 后台VUE端(指的是商城后台的前端代码,使用vue2编写,分store模块和admin模块)
下载地址:https://gitee.com/xany/yoshop2.0-store
下载地址:https://gitee.com/xany/yoshop2.0-admin
#### 代码风格
* PHP7强类型严格模式
* 严格遵守MVC设计模式 同时具有service层和枚举类enum支持
* 简约整洁的编码风格 绝不冗余一行代码
* 代码注释完整易读性高 尽量保障初级程序员也可读懂 极大提升二开效率
* 不允许直接调用和使用DB类(破坏封装性)
* 不允许使用原生SQL语句 全部使用链式操作(可维护性强)
* 不允许存在复杂SQL查询语句(可维护性强)
* 所有的CURD操作均通过ORM模型类 并封装方法(扩展性强)
* 数据库设计满足第三范式
* 前端JS编码均采用ES6标准
#### 环境要求
- CentOS 7.0+
- Nginx 1.10+
- PHP 7.4
- MySQL 5.6+
#### 如何安装
##### 一、自动安装(推荐)
1. 将后端源码上传至服务器站点,并且将站点运行目录设置为/public
2. 在浏览器中输入站点域名 + /install,例如:https://www.你的域名.com/install
3. 根据页面提示,自动完成安装即可
##### 二、手动安装(不推荐)
1. 将后端源码上传至服务器站点,并且将站点运行目录设置为/public
2. 创建一个数据库,例如:yoshop2_db
3. 导入数据库表结构文件,路径:/public/install/data/install_struct.sql
4. 导入数据库默认数据文件,路径:/public/install/data/install_data.sql
5. 修改数据库连接文件,将数据库用户名密码等信息填写完整,路径/.env
#### 后台地址
- 超管后台:https://www.你的域名.com/admin
- 商户后台:https://www.你的域名.com/store
- 默认的账户密码:admin yinghuo
#### 定时任务
用于自动处理订单状态、优惠券状态、会员等级等
```sh
php think timer start
```
#### 安全&缺陷
如果您碰到安装和使用问题可以查阅[Issue](https://gitee.com/xany/yoshop2.0/issues?state=all),或者将操作流程和截图详细发出来,我们看到后会给出解决方案。
如果有BUG或者安全问题,我们会第一时间修复。
#### 版权须知
1. 允许个人学习研究使用,支持二次开发,允许商业用途(仅限自运营)。
2. 允许商业用途,但仅限自运营,如果商用必须保留版权信息,望自觉遵守。
3. 不允许对程序代码以任何形式任何目的的再发行或出售,否则将追究侵权者法律责任。
本项目包含的第三方源码和二进制文件之版权信息另行标注。
版权所有Copyright © 2017-2023 By 萤火科技 (https://www.yiovo.com) All rights reserved。
+1
View File
@@ -0,0 +1 @@
deny from all
@@ -0,0 +1,218 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\admin\controller;
use cores\BaseController;
use cores\exception\BaseException;
use app\admin\service\admin\User as AdminUserService;
use think\response\Json;
/**
* 超管后台控制器基类
* Class Controller
* @package app\admin\controller
*/
class Controller extends BaseController
{
// 商家登录信息
protected $admin;
// 当前控制器名称
protected $controller = '';
// 当前方法名称
protected $action = '';
// 当前路由uri
protected $routeUri = '';
// 当前路由:分组名称
protected $group = '';
// 登录验证白名单
protected $allowAllAction = [
// 登录页面
'passport/login',
];
// 无需全局layout
protected $notLayoutAction = [];
/**
* 强制验证当前访问的控制器方法method
* 例: [ 'login' => 'POST' ]
* @var array
*/
protected $methodRules = [];
/**
* 后台初始化
* @throws \Exception
*/
public function initialize()
{
// 设置管理员登录信息
$this->setAdminInfo();
// 当前路由信息
$this->getRouteInfo();
// 验证登录
$this->checkLogin();
// 强制验证当前访问的控制器方法method
$this->checkMethodRules();
}
/**
* 设置管理员登录信息
*/
private function setAdminInfo()
{
$this->admin = AdminUserService::getLoginInfo();
}
/**
* 解析当前路由参数 (分组名称、控制器名称、方法名)
*/
protected function getRouteInfo()
{
// 控制器名称
$this->controller = uncamelize($this->request->controller());
// 方法名称
$this->action = $this->request->action();
// 控制器分组 (用于定义所属模块)
$group = strstr($this->controller, '.', true);
$this->group = $group !== false ? $group : $this->controller;
// 当前uri
$this->routeUri = "{$this->controller}/$this->action";
}
/**
* 后台菜单配置
* @return array
*/
private function menus(): array
{
// 获取后台菜单内容 [app/admin/config/menus.php]
$menus = \think\facade\Config::get('menus');
foreach ($menus as $group => &$first) {
$first['active'] = $group === $this->group;
// 遍历:二级菜单
if (isset($first['submenu'])) {
foreach ($first['submenu'] as $secondKey => &$second) {
// 二级菜单所有uri
$secondUris = $second['uris'] ?? [$second['index']];
// 二级菜单:active
!isset($second['active']) && $second['active'] = in_array($this->routeUri, $secondUris);
}
}
}
return $menus;
}
/**
* 验证登录状态
* @return void
* @throws BaseException
*/
private function checkLogin(): void
{
// 验证当前请求是否在白名单
if (in_array($this->routeUri, $this->allowAllAction)) {
return;
}
// 验证登录状态
if (empty($this->admin) || (int)$this->admin['is_login'] !== 1) {
throwError('请先登录后再访问', config('status.not_logged'));
}
}
/**
* 返回封装后的 API 数据到客户端
* @param int|null $status 状态码
* @param string $message
* @param array $data
* @return Json
*/
protected function renderJson(int $status = null, string $message = '', array $data = []): Json
{
return json(compact('status', 'message', 'data'));
}
/**
* 返回操作成功json
* @param array|string $data
* @param string $message
* @return Json
*/
protected function renderSuccess($data = [], string $message = 'success'): Json
{
if (is_string($data)) {
$message = $data;
$data = [];
}
return $this->renderJson(config('status.success'), $message, $data);
}
/**
* 返回操作失败json
* @param string $message
* @param array $data
* @return Json
*/
protected function renderError(string $message = 'error', array $data = []): Json
{
return $this->renderJson(config('status.error'), $message, $data);
}
/**
* 获取post数据 (数组)
* @param $key
* @return mixed
*/
protected function postData($key = null)
{
return $this->request->post(empty($key) ? '' : "{$key}/a");
}
/**
* 获取post数据 (数组)
* @param string $key
* @return mixed
*/
protected function postForm(string $key = 'form')
{
return $this->postData($key);
}
/**
* 强制验证当前访问的控制器方法method
* @throws BaseException
*/
private function checkMethodRules(): void
{
if (!isset($this->methodRules[$this->action])) {
return;
}
$methodRule = $this->methodRules[$this->action];
$currentMethod = $this->request->method();
if (empty($methodRule)) {
return;
}
if (is_array($methodRule) && in_array($currentMethod, $methodRule)) {
return;
}
if (is_string($methodRule) && $methodRule == $currentMethod) {
return;
}
throwError('illegal request method');
}
}
@@ -0,0 +1,60 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\admin\controller;
use app\admin\model\admin\User as UserModel;
/**
* 超管后台认证
* Class Passport
* @package app\store\controller
*/
class Passport extends Controller
{
/**
* 强制验证当前访问的控制器方法method
* @var array
*/
protected $methodRules = [
'login' => 'POST',
];
/**
* 超管后台登录
* @return array|string
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \Exception
*/
public function login()
{
// 超管后台用户登录
$model = new UserModel;
if (($userInfo = $model->login($this->postData())) === false) {
return $this->renderError($model->getError() ?: '登录失败');
}
return $this->renderSuccess([
'userId' => $userInfo['admin_user_id'],
'token' => $model->getToken()
], '登录成功');
}
/**
* 退出登录
*/
public function logout()
{
return $this->renderSuccess('操作成功');
}
}
+97
View File
@@ -0,0 +1,97 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\admin\controller;
use app\admin\model\Store as StoreModel;
/**
* 小程序商城管理
* Class Store
* @package app\admin\controller
*/
class Store extends Controller
{
/**
* 强制验证当前访问的控制器方法method
* @var array
*/
protected $methodRules = [
'index' => 'GET',
'recycle' => 'GET',
'add' => 'POST',
'move' => 'POST',
'delete' => 'POST',
];
/**
* 小程序商城列表
* @return array
* @throws \think\db\exception\DbException
*/
public function index()
{
// 商城列表
$model = new StoreModel;
$list = $model->getList();
return $this->renderSuccess(compact('list'));
}
/**
* 回收站列表
* @return array
* @throws \think\db\exception\DbException
*/
public function recycle()
{
// 商城列表
$model = new StoreModel;
$list = $model->getList(true);
return $this->renderSuccess(compact('list'));
}
/**
* 回收小程序
* @param int $storeId
* @return array
*/
public function recovery(int $storeId)
{
// 小程序详情
$model = StoreModel::detail($storeId);
if (!$model->recycle()) {
return $this->renderError($model->getError() ?: '操作失败');
}
return $this->renderSuccess('操作成功');
}
/**
* 移出回收站
* @param int $storeId
* @return array
*/
public function move(int $storeId)
{
// 小程序详情
$model = StoreModel::detail($storeId);
if (!$model->recycle(false)) {
return $this->renderError($model->getError() ?: '操作失败');
}
return $this->renderSuccess('操作成功');
}
public function add()
{
return $this->renderError('很抱歉,免费版暂不支持多开商城');
}
}
@@ -0,0 +1,60 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\admin\controller\admin;
use app\admin\controller\Controller;
use app\admin\model\admin\User as AdminUserModel;
/**
* 超管后台管理员控制器
* Class User
* @package app\store\controller
*/
class User extends Controller
{
/**
* 强制验证当前访问的控制器方法method
* 例: [ 'login' => 'POST' ]
* @var array
*/
protected $methodRules = [
'detail' => 'GET',
'renew' => 'POST',
];
/**
* 获取当前用户信息
* @return array
*/
public function detail()
{
$userInfo = AdminUserModel::detail($this->admin['user']['admin_user_id']);
return $this->renderSuccess(['userInfo' => $userInfo]);
}
/**
* 更新当前管理员信息
* @return array|string
* @throws \Exception
*/
public function renew()
{
// 获取当前用户信息
$model = AdminUserModel::detail($this->admin['user']['admin_user_id']);
// 更新用户信息
if ($model->renew($this->postForm())) {
return $this->renderSuccess('更新成功');
}
return $this->renderError($model->getError() ?: '更新失败');
}
}
@@ -0,0 +1,40 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\admin\controller\setting;
use app\admin\controller\Controller;
use app\admin\service\Cache as CacheService;
/**
* 清理缓存
* Class Index
* @package app\admin\controller
*/
class Cache extends Controller
{
/**
* 清理缓存
* @return array|string
* @throws \Exception
*/
public function clear()
{
// 清理缓存
$CacheService = new CacheService;
if (!$CacheService->rmCache($this->postForm())) {
return $this->renderError($CacheService->getError() ?: '操作失败');
}
return $this->renderSuccess('操作成功');
}
}
@@ -0,0 +1,264 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\admin\controller\setting;
use think\response\Json;
use app\admin\controller\Controller;
use app\common\library\helper;
/**
* 环境检测
* Class Science
* @package app\admin\controller\setting
*/
class Science extends Controller
{
/**
* 环境检测
* @return Json
*/
public function info(): Json
{
return $this->renderSuccess([
'scienceInfo' => [
'server' => $this->server(), // 服务器信息
'phpinfo' => $this->phpinfo(), // PHP环境要求
'writeable' => $this->writeable(), // 目录权限监测
]
]);
}
/**
* 服务器信息
* @return array
*/
private function server(): array
{
return [
[
'name' => '服务器操作系统',
'key' => 'system',
'value' => PHP_OS,
'status' => PHP_SHLIB_SUFFIX === 'dll' ? 'warning' : 'normal',
'remark' => '建议使用 Linux 系统以提升程序性能'
],
[
'name' => 'Web服务器环境',
'key' => 'webserver',
'value' => $this->request->server('SERVER_SOFTWARE'),
'status' => PHP_SAPI === 'isapi' ? 'warning' : 'normal',
'remark' => '建议使用 Apache 或 Nginx 以提升程序性能'
],
[
'name' => 'PHP版本',
'key' => 'php',
'value' => PHP_VERSION,
'status' => version_compare(PHP_VERSION, '7.4.0') === -1 ? 'danger' : 'normal',
'remark' => 'PHP版本必须为 7.4.0 及以上'
],
[
'name' => 'PHP运行位数',
'key' => 'system',
'value' => (PHP_INT_SIZE === 4 ? '32' : '64') . '位',
'status' => PHP_INT_SIZE === 4 ? 'warning' : 'normal',
'remark' => '建议使用 64位 PHP以提升程序性能'
],
// [
// 'name' => '文件上传功能',
// 'key' => 'file_uploads',
// 'value' => !ini_get('file_uploads') ? '关闭' : '开启',
// 'status' => !ini_get('file_uploads') ? 'danger' : 'normal',
// 'remark' => '文件上传必须开启 file_uploads'
// ],
[
'name' => '文件上传最大值',
'key' => 'upload_max_filesize',
'value' => ini_get('upload_max_filesize'),
'status' => $this->compareBytes(ini_get('upload_max_filesize'), '10m') ? 'danger' : 'normal',
'remark' => '不能小于10MB;请修改php.ini中upload_max_filesize'
],
[
'name' => 'POST数据最大值',
'key' => 'post_max_size',
'value' => ini_get('post_max_size'),
'status' => $this->compareBytes(ini_get('post_max_size'), '12m') ? 'danger' : 'normal',
'remark' => '不能小于12MB;请修改php.ini中post_max_size'
],
[
'name' => '程序运行目录',
'key' => 'root_path',
'value' => str_replace('\\', '/', root_path()),
'status' => 'normal',
'remark' => ''
],
];
}
/**
* PHP环境要求
* @return string[][]
*/
private function phpinfo(): array
{
return [
[
'name' => 'PHP版本',
'key' => 'php_version',
'value' => '7.4.0及以上',
'status' => version_compare(PHP_VERSION, '7.4.0') === -1 ? 'danger' : 'normal',
'remark' => 'PHP版本必须为 7.4.0及以上'
],
[
'name' => 'Mysqlnd',
'key' => 'mysqlnd',
'value' => '支持',
'status' => extension_loaded('mysqlnd') ? 'normal' : 'danger',
'remark' => '您的PHP环境不支持mysqlnd, 系统无法正常运行'
],
// [
// 'name' => 'Redis',
// 'key' => 'redis',
// 'value' => '支持',
// 'status' => extension_loaded('redis') ? 'normal' : 'warning',
// 'remark' => '您的PHP环境不支持redis, 系统无法使用队列服务'
// ],
[
'name' => 'ZIP',
'key' => 'zip',
'value' => '支持',
'status' => extension_loaded('zip') ? 'normal' : 'warning',
'remark' => '您的PHP环境不支持zip, 系统无法使用zip压缩文件'
],
[
'name' => 'CURL',
'key' => 'curl',
'value' => '支持',
'status' => extension_loaded('curl') && function_exists('curl_init') ? 'normal' : 'danger',
'remark' => '您的PHP环境不支持CURL, 系统无法正常运行'
],
[
'name' => 'JSON',
'key' => 'json',
'value' => '支持',
'status' => extension_loaded('json') ? 'normal' : 'danger',
'remark' => '您的PHP环境不支持JSON, 系统无法正常运行'
],
[
'name' => 'Fileinfo',
'key' => 'fileinfo',
'value' => '支持',
'status' => extension_loaded('fileinfo') ? 'normal' : 'danger',
'remark' => '您的PHP环境不支持fileinfo, 系统无法上传文件'
],
[
'name' => 'OpenSSL',
'key' => 'openssl',
'value' => '支持',
'status' => extension_loaded('openssl') ? 'normal' : 'danger',
'remark' => '没有启用OpenSSL, 将无法访问微信平台的接口'
],
[
'name' => 'PDO',
'key' => 'pdo',
'value' => '支持',
'status' => extension_loaded('PDO') && extension_loaded('pdo_mysql') ? 'normal' : 'danger',
'remark' => '您的PHP环境不支持PDO, 系统无法正常运行'
],
[
'name' => 'GD',
'key' => 'gd',
'value' => '支持',
'status' => extension_loaded('gd') ? 'normal' : 'danger',
'remark' => '您的PHP环境不支持GD, 系统无法正常生成图片'
],
[
'name' => 'BCMath',
'key' => 'bcmath',
'value' => '支持',
'status' => extension_loaded('bcmath') ? 'normal' : 'danger',
'remark' => '您的PHP环境不支持BCMath, 系统无法正常运行'
],
[
'name' => 'Mbstring',
'key' => 'mbstring',
'value' => '支持',
'status' => extension_loaded('mbstring') ? 'normal' : 'danger',
'remark' => '您的PHP环境不支持mbstring, 系统无法正常运行'
],
[
'name' => 'SimpleXML',
'key' => 'simplexML',
'value' => '支持',
'status' => extension_loaded('SimpleXML') ? 'normal' : 'danger',
'remark' => '您的PHP环境不支持SimpleXML, 系统无法解析xml 无法使用微信支付'
],
];
}
/**
* 目录权限监测
* @return array[]
*/
private function writeable(): array
{
$paths = [
'data' => realpath(data_path()) . '/',
'uploads' => realpath(web_path()) . '/uploads/',
'downloads' => realpath(web_path()) . '/downloads/',
'temp' => realpath(web_path()) . '/temp/',
];
return [
[
'name' => '系统数据目录',
'key' => 'data',
'value' => str_replace('\\', '/', $paths['data']),
'status' => helper::checkWriteable($paths['data']) ? 'normal' : 'danger',
'remark' => '目录不可写,系统将无法正常写入文件'
],
[
'name' => '文件上传目录',
'key' => 'uploads',
'value' => str_replace('\\', '/', $paths['uploads']),
'status' => helper::checkWriteable($paths['uploads']) ? 'normal' : 'danger',
'remark' => '目录不可写,系统将无法正常上传文件'
],
[
'name' => '文件下载目录',
'key' => 'downloads',
'value' => str_replace('\\', '/', $paths['downloads']),
'status' => helper::checkWriteable($paths['downloads']) ? 'normal' : 'danger',
'remark' => '目录不可写,系统将无法正常上传文件'
],
[
'name' => '临时文件目录',
'key' => 'temp',
'value' => str_replace('\\', '/', $paths['temp']),
'status' => helper::checkWriteable($paths['temp']) ? 'normal' : 'danger',
'remark' => '目录不可写,系统将无法正常写入文件'
],
];
}
/**
* 比较数据大小
* @param string $size1
* @param string $size2
* @return bool
*/
private function compareBytes(string $size1, string $size2): bool
{
$size1 = helper::convertToBytes($size1);
$size2 = helper::convertToBytes($size2);
return $size1 < $size2;
}
}
@@ -0,0 +1,90 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\admin\controller\store;
use app\admin\controller\Controller;
use app\admin\model\store\Api as ApiModel;
/**
* 商家后台API权限控制器
* Class Api
* @package app\store\controller
*/
class Api extends Controller
{
/**
* 权限列表
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$model = new ApiModel;
$list = $model->getList();
return $this->renderSuccess(compact('list'));
}
/**
* 添加权限
* @return array
*/
public function add()
{
// 新增记录
$model = new ApiModel;
if ($model->add($this->postForm())) {
return $this->renderSuccess('添加成功');
}
return $this->renderError($model->getError() ?: '添加失败');
}
/**
* 更新权限
* @param $apiId
* @return array|string
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function edit(int $apiId)
{
// 权限详情
$model = ApiModel::detail($apiId);
// 更新记录
if ($model->edit($this->postForm())) {
return $this->renderSuccess('更新成功');
}
return $this->renderError($model->getError() ?: '更新失败');
}
/**
* 删除权限
* @param $apiId
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function delete(int $apiId)
{
// 权限详情
$model = ApiModel::detail($apiId);
if (!$model->remove()) {
return $this->renderError($model->getError() ?: '删除失败');
}
return $this->renderSuccess('删除成功');
}
}
@@ -0,0 +1,124 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\admin\controller\store;
use app\admin\controller\Controller;
use app\admin\model\store\Menu as MenuModel;
/**
* 商家后台菜单控制器
* Class Menu
* @package app\store\controller
*/
class Menu extends Controller
{
/**
* 菜单列表
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$model = new MenuModel;
$list = $model->getList();
return $this->renderSuccess(compact('list'));
}
/**
* 菜单详情
* @param int $menuId
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function info(int $menuId)
{
// 菜单详情
$model = MenuModel::detail($menuId);
return $this->renderSuccess(['info' => $model]);
}
/**
* 添加菜单
* @return array
*/
public function add()
{
// 新增记录
$model = new MenuModel;
if ($model->add($this->postForm())) {
return $this->renderSuccess('添加成功');
}
return $this->renderError($model->getError() ?: '添加失败');
}
/**
* 更新菜单
* @param $menuId
* @return array|string
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function edit(int $menuId)
{
// 菜单详情
$model = MenuModel::detail($menuId);
// 更新记录
if ($model->edit($this->postForm())) {
return $this->renderSuccess('更新成功');
}
return $this->renderError($model->getError() ?: '更新失败');
}
/**
* 设置菜单绑定的Api
* @param int $menuId
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function setApis(int $menuId)
{
// 菜单详情
$model = MenuModel::detail($menuId);
// 更新记录
if ($model->setApis($this->postForm())) {
return $this->renderSuccess('操作成功');
}
return $this->renderError($model->getError() ?: '操作失败');
}
/**
* 删除菜单
* @param $menuId
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function delete(int $menuId)
{
// 菜单详情
$model = MenuModel::detail($menuId);
if (!$model->remove()) {
return $this->renderError($model->getError() ?: '删除失败');
}
return $this->renderSuccess('删除成功');
}
}
+48
View File
@@ -0,0 +1,48 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\admin\model;
use app\common\model\Store as StoreModel;
/**
* 商家记录表模型
* Class Store
* @package app\admin\model
*/
class Store extends StoreModel
{
/**
* 获取列表数据
* @param bool $isRecycle
* @return \think\Paginator
* @throws \think\db\exception\DbException
*/
public function getList(bool $isRecycle = false): \think\Paginator
{
return $this->where('is_recycle', '=', (int)$isRecycle)
->where('is_delete', '=', 0)
->order(['create_time' => 'desc'])
->paginate(15);
}
/**
* 移入移出回收站
* @param bool $isRecycle
* @return false|int
*/
public function recycle($isRecycle = true)
{
return $this->save(['is_recycle' => (int)$isRecycle]);
}
}
+25
View File
@@ -0,0 +1,25 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\admin\model;
use app\common\model\UploadFile as UploadFileModel;
/**
* 文件库模型
* Class UploadFile
* @package app\admin\model
*/
class UploadFile extends UploadFileModel
{
}
+110
View File
@@ -0,0 +1,110 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\admin\model\admin;
use app\common\model\admin\User as UserModel;
use app\admin\service\admin\User as AdminUserService;
/**
* 超管后台用户模型
* Class User
* @package app\admin\model\admin
*/
class User extends UserModel
{
/**
* 隐藏的字段
* @var array
*/
protected $hidden = [
'password',
];
// 用户登录token
private $token;
/**
* 超管后台用户登录
* @param array $data
* @return array|bool|null|\think\Model
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function login(array $data)
{
// 验证用户名密码是否正确
if (!$user = $this->getUserInfoByLogin($data)) {
$this->error = '登录失败, 用户名或密码错误';
return false;
}
// 记录登录状态, 并记录token
$this->token = AdminUserService::login($user->toArray());
return $user;
}
/**
* 返回生成的token
* @return mixed
*/
public function getToken()
{
return $this->token;
}
/**
* 获取登录的用户信息
* @param $data
* @return array|false|\think\Model
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function getUserInfoByLogin(array $data)
{
// 用户信息
$useInfo = static::withoutGlobalScope()
->where(['user_name' => $data['username']])
->find();
if (empty($useInfo)) return false;
// 验证密码是否正确
if (!password_verify($data['password'], $useInfo['password'])) {
return false;
}
return $useInfo;
}
/**
* 更新当前管理员信息
* @param $data
* @return bool
*/
public function renew(array $data)
{
if ($data['password'] !== $data['password_confirm']) {
$this->error = '确认密码不正确';
return false;
}
// 更新管理员信息
if ($this->save([
'user_name' => $data['user_name'],
'password' => encryption_hash($data['password']),
]) === false) {
return false;
}
// 更新登录信息
AdminUserService::update($this->toArray());
return true;
}
}
+129
View File
@@ -0,0 +1,129 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\admin\model\store;
use app\common\model\store\Api as ApiModel;
/**
* 商家后台API权限模型
* Class Api
* @package app\admin\model\store
*/
class Api extends ApiModel
{
/**
* 获取权限列表
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getList()
{
$all = static::getAll();
return $this->getTreeData($all);
}
/**
* 新增记录
* @param $data
* @return false|int
*/
public function add(array $data)
{
return $this->allowField(['name', 'parent_id', 'url', 'sort'])->save($data);
}
/**
* 更新记录
* @param $data
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function edit($data)
{
// 判断上级角色是否为当前子级
if ($data['parent_id'] > 0) {
// 获取所有上级id集
$parentIds = $this->getTopApiIds($data['parent_id']);
if (in_array($this['api_id'], $parentIds)) {
$this->error = '上级权限不允许设置为当前子权限';
return false;
}
}
return $this->allowField(['name', 'parent_id', 'url', 'sort'])->save($data) !== false;
}
/**
* 删除权限
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @throws \Exception
*/
public function remove()
{
// 判断是否存在下级权限
if (self::detail(['parent_id' => $this['api_id']])) {
$this->error = '当前权限下存在子权限,请先删除';
return false;
}
return $this->delete();
}
/**
* 获取所有上级id集
* @param int $apiId
* @param null $all
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function getTopApiIds(int $apiId, $all = null)
{
static $ids = [];
is_null($all) && $all = $this->getAll();
foreach ($all as $item) {
if ($item['api_id'] == $apiId && $item['parent_id'] > 0) {
$ids[] = $item['parent_id'];
$this->getTopApiIds($item['parent_id'], $all);
}
}
return $ids;
}
/**
* 获取树状列表
* @param array $list
* @param int $parentId
* @return array
*/
private function getTreeData(array &$list, int $parentId = 0)
{
$data = [];
foreach ($list as $key => $item) {
if ($item['parent_id'] == $parentId) {
$children = $this->getTreeData($list, (int)$item['api_id']);
!empty($children) && $item['children'] = $children;
$data[] = $item;
unset($list[$key]);
}
}
return $data;
}
}
+116
View File
@@ -0,0 +1,116 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\admin\model\store;
use app\common\model\store\Menu as MenuModel;
use app\admin\model\store\MenuApi as MenuApiModel;
/**
* 商家后台菜单模型
* Class Menu
* @package app\admin\model\store
*/
class Menu extends MenuModel
{
/**
* 新增记录
* @param $data
* @return false|int
*/
public function add(array $data)
{
return $this->save($data);
}
/**
* 更新记录
* @param array $data
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function edit(array $data)
{
// 判断上级角色是否为当前子级
if (isset($data['parent_id']) && $data['parent_id'] > 0) {
// 获取所有上级id集
$parentIds = $this->getTopMenuIds($data['parent_id']);
if (in_array($this['menu_id'], $parentIds)) {
$this->error = '上级菜单不允许设置为当前子菜单';
return false;
}
}
// 如果模块是操作, 不允许修改上级菜单id
if ($this['module'] == 20 && isset($data['parent_id'])) {
unset($data['parent_id']);
}
return $this->save($data) !== false;
}
/**
* 设置菜单的API权限
* @param array $data
* @return bool|int
*/
public function setApis(array $data)
{
if (!isset($data['apiIds']) || empty($data['apiIds'])) {
$this->error = 'API权限不能为空';
return false;
}
// 根据菜单id批量更新API关联记录
return (new MenuApiModel)->updateByMenuId($this['menu_id'], $data['apiIds']);
}
/**
* 删除菜单
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @throws \Exception
*/
public function remove()
{
// 判断是否存在下级菜单
if (self::detail(['parent_id' => $this['menu_id']])) {
$this->error = '当前菜单下存在子菜单或操作,请先删除';
return false;
}
return $this->delete();
}
/**
* 获取所有上级id集
* @param int $menuId
* @param null $menuList
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function getTopMenuIds(int $menuId, $menuList = null)
{
static $ids = [];
is_null($menuList) && $menuList = $this->getAll();
foreach ($menuList as $item) {
if ($item['menu_id'] == $menuId && $item['parent_id'] > 0) {
$ids[] = $item['parent_id'];
$this->getTopMenuIds($item['parent_id'], $menuList);
}
}
return $ids;
}
}
@@ -0,0 +1,64 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\admin\model\store;
use app\common\model\store\MenuApi as MenuApiModel;
/**
* 商家后台用户角色与菜单权限关系表模型
* Class MenuApi
* @package app\admin\model\store
*/
class MenuApi extends MenuApiModel
{
/**
* 根据菜单id批量更新记录
* @param int $menuId
* @param array $apiIds
* @return int
*/
public function updateByMenuId(int $menuId, array $apiIds)
{
return $this->transaction(function () use ($menuId, $apiIds) {
$this->removeByMenuId($menuId);
return $this->insertByMenuId($menuId, $apiIds);
});
}
/**
* 根据菜单id批量删除记录
* @param int $menuId
* @return bool
* @throws \Exception
*/
private function removeByMenuId(int $menuId)
{
return $this->where('menu_id', '=', $menuId)->delete();
}
/**
* 根据菜单id批量新增记录
* @param int $menuId
* @param array $apiIds
* @return bool
*/
private function insertByMenuId(int $menuId, array $apiIds)
{
$data = [];
foreach ($apiIds as $api) {
$data[] = ['menu_id' => $menuId, 'api_id' => $api];
}
return (bool)$this->addAll($data);
}
}
+60
View File
@@ -0,0 +1,60 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\admin\model\store;
use cores\exception\BaseException;
use app\common\model\store\User as StoreUserModel;
/**
* 商家用户模型
* Class StoreUser
* @package app\admin\model
*/
class User extends StoreUserModel
{
/**
* 商家用户登录
* @param int $storeId
* @throws BaseException
* @throws \think\Exception
*/
public function login(int $storeId)
{
// 获取该商户管理员用户信息
$userInfo = $this->getSuperStoreUser($storeId);
if (empty($userInfo)) {
throwError('超级管理员用户信息不存在');
}
}
/**
* 获取该商户管理员用户信息
* @param int $storeId
* @return static|null
*/
private function getSuperStoreUser(int $storeId)
{
return static::detail(['store_id' => $storeId, 'is_super' => 1], ['wxapp']);
}
/**
* 删除小程序下的商家用户
* @param $storeId
* @return false|int
*/
public static function setDelete(int $storeId)
{
static::update(['is_delete' => '1'], ['store_id' => $storeId]);
return true;
}
}
+94
View File
@@ -0,0 +1,94 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\admin\service;
use app\common\service\BaseService;
use think\facade\Cache as CacheDriver;
/**
* 清理缓存
* Class Cache
*/
class Cache extends BaseService
{
// 缓存驱动句柄
/** @var $CacheDriver \think\Cache */
private $cache;
/**
* 构造方法
* Cache constructor.
*/
public function initialize()
{
// 实例化缓存驱动
$this->cache = CacheDriver::instance();
}
/**
* 删除缓存
* @param $data
* @return bool
*/
public function rmCache($data)
{
// 数据缓存
if (in_array('data', $data['item'])) {
// 强制模式
$isForce = isset($data['isForce']) && $data['isForce'];
// 清除缓存
$isForce ? $this->cache->clear() : $this->cache->tag('cache')->clear();
}
// 临时文件
if (in_array('temp', $data['item'])) {
$paths = [
'temp' => web_path() . 'temp/',
'runtime-image' => runtime_root_path() . 'image/',
'runtime-local' => runtime_root_path() . 'local/',
];
foreach ($paths as $path) {
$this->deleteFolder($path);
}
}
return true;
}
/**
* 递归删除指定目录下所有文件
* @param $path
* @return bool
*/
private function deleteFolder($path)
{
if (!is_dir($path))
return false;
// 扫描一个文件夹内的所有文件夹和文件
foreach (scandir($path) as $val) {
// 排除目录中的.和..
if (!in_array($val, ['.', '..', '.gitignore'])) {
// 如果是目录则递归子目录,继续操作
if (is_dir($path . $val)) {
// 子目录中操作删除文件夹和文件
$this->deleteFolder($path . $val . '/');
// 目录清空后删除空文件夹
rmdir($path . $val . '/');
} else {
// 如果是文件直接删除
unlink($path . $val);
}
}
}
return true;
}
}
+120
View File
@@ -0,0 +1,120 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\admin\service\admin;
use think\facade\Cache;
use app\common\service\BaseService;
/**
* 超管用户服务类
* Class User
*/
class User extends BaseService
{
// 用于生成token的自定义盐
const TOKEN_SALT = '_admin_user_salt_';
/**
* 获取登录的信息
* @return mixed
*/
public static function getLoginInfo()
{
if (($token = self::getToken()) !== false) {
return Cache::get($token);
}
return false;
}
/**
* 记录登录信息
* @param array $userInfo
* @return string
*/
public static function login(array $userInfo)
{
// 生成token
$token = self::makeToken((int)$userInfo['admin_user_id']);
// 记录缓存, 7天
Cache::set($token, [
'user' => [
'admin_user_id' => (int)$userInfo['admin_user_id'],
'user_name' => $userInfo['user_name'],
],
'is_login' => true,
], 86400 * 7);
return $token;
}
/**
* 清空登录状态
* @return bool
*/
public static function logout()
{
Cache::delete(self::getToken());
return true;
}
/**
* 更新登录信息
* @param array $userInfo
* @return mixed
*/
public static function update(array $userInfo)
{
return Cache::set(self::getToken(), [
'user' => [
'admin_user_id' => $userInfo['admin_user_id'],
'user_name' => $userInfo['user_name'],
],
'is_login' => true,
], 86400 * 7);
}
/**
* 生成用户认证的token
* @param int $userId
* @return string
*/
private static function makeToken(int $userId)
{
// 生成一个不会重复的随机字符串
$guid = get_guid_v4();
// 当前时间戳 (精确到毫秒)
$timeStamp = microtime(true);
// 自定义一个盐
$salt = self::TOKEN_SALT;
return md5("{$timeStamp}_{$userId}_{$guid}_{$salt}");
}
/**
* 获取用户认证Token
* @return bool|string
*/
private static function getToken()
{
// 获取请求中的token
$token = request()->header('Access-Token');
// 调试模式下可通过param
if (empty($token) && is_debug()) {
$token = request()->param('Access-Token');
}
// 不存在token报错
if (empty($token)) {
return false;
}
return $token;
}
}
@@ -0,0 +1,25 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\admin\service\store;
use app\common\service\store\User as Basics;
use app\admin\model\store\User as StoreUserModel;
/**
* 超管用户服务类
* Class User
*/
class User extends Basics
{
}
+29
View File
@@ -0,0 +1,29 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
// 应用公共函数库文件
/**
* 获取当前访问的渠道(微信小程序、H5、APP等)
* @return string|null
*/
function getPlatform()
{
static $value = null;
// 从header中获取 channel
empty($value) && $value = request()->header('platform');
// 调试模式下可通过param中获取
if (is_debug() && empty($value)) {
$value = request()->param('platform');
}
return $value;
}
+31
View File
@@ -0,0 +1,31 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
return [
// 验证码图片宽度
'imageW' => 0,
// 验证码图片高度
'imageH' => 0,
// 验证码位数
'length' => 4,
// 是否画混淆曲线
'useCurve' => false,
// 是否添加杂点
'useNoise' => true,
// 验证码字体大小(px)
'fontSize' => 26,
// 验证码字符集合
// 复杂版:2345678abcdefhijkmnpqrstuvwxyzABCDEFGHJKLMNPQRTUVWXY
'codeSet' => '23456ACEFHJKLMNPRTUVWXY',
// 验证码可重复验证的次数
'checkTimes' => 5,
];
+124
View File
@@ -0,0 +1,124 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use think\response\Json;
use app\api\service\User as UserService;
use app\api\model\UserAddress as UserAddressModel;
use cores\exception\BaseException;
/**
* 收货地址管理
* Class Address
* @package app\api\controller
*/
class Address extends Controller
{
/**
* 收货地址列表
* @return Json
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function list(): Json
{
// 获取收货地址列表
$model = new UserAddressModel;
$list = $model->getList();
return $this->renderSuccess(compact('list'));
}
/**
* 获取当前用户默认收货地址
* @return Json
* @throws BaseException
*/
public function defaultId(): Json
{
$useInfo = UserService::getCurrentLoginUser(true);
return $this->renderSuccess(['defaultId' => $useInfo['address_id']]);
}
/**
* 收货地址详情
* @param int $addressId 地址ID
* @return Json
* @throws BaseException
*/
public function detail(int $addressId): Json
{
$detail = UserAddressModel::detail($addressId);
return $this->renderSuccess(compact('detail'));
}
/**
* 添加收货地址
* @return Json
* @throws BaseException
*/
public function add(): Json
{
$model = new UserAddressModel;
if ($model->add($this->postForm())) {
return $this->renderSuccess([], '添加成功');
}
return $this->renderError($model->getError() ?: '添加失败');
}
/**
* 编辑收货地址
* @param int $addressId 地址ID
* @return Json
* @throws BaseException
*/
public function edit(int $addressId): Json
{
$model = UserAddressModel::detail($addressId);
if ($model->edit($this->postForm())) {
return $this->renderSuccess([], '更新成功');
}
return $this->renderError($model->getError() ?: '更新失败');
}
/**
* 设为默认地址
* @param int $addressId 地址ID
* @return Json
* @throws BaseException
*/
public function setDefault(int $addressId): Json
{
$model = UserAddressModel::detail($addressId);
if ($model->setDefault((int)$model['address_id'])) {
return $this->renderSuccess([], '设置成功');
}
return $this->renderError($model->getError() ?: '设置失败');
}
/**
* 删除收货地址
* @param int $addressId 地址ID
* @return Json
* @throws BaseException
*/
public function remove(int $addressId): Json
{
$model = UserAddressModel::detail($addressId);
if ($model->remove()) {
return $this->renderSuccess([], '删除成功');
}
return $this->renderError($model->getError() ?: '删除失败');
}
}
+48
View File
@@ -0,0 +1,48 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use app\api\model\Article as ArticleModel;
/**
* 文章控制器
* Class Article
* @package app\api\controller
*/
class Article extends Controller
{
/**
* 文章列表
* @param int $categoryId
* @return \think\response\Json
* @throws \think\db\exception\DbException
*/
public function list(int $categoryId = 0)
{
$model = new ArticleModel;
$list = $model->getList($categoryId);
return $this->renderSuccess(compact('list'));
}
/**
* 文章详情
* @param int $articleId
* @return \think\response\Json
* @throws \cores\exception\BaseException
*/
public function detail(int $articleId)
{
$detail = ArticleModel::getDetail($articleId);
return $this->renderSuccess(compact('detail'));
}
}
+49
View File
@@ -0,0 +1,49 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use think\response\Json;
use app\api\service\passport\{Captcha as CaptchaService, SmsCaptcha as SmsCaptchaService};
use cores\exception\BaseException;
/**
* 验证码管理
* Class Cart
* @package app\api\controller
*/
class Captcha extends Controller
{
/**
* 图形验证码
* @return Json
*/
public function image(): Json
{
$CaptchaService = new CaptchaService;
return $this->renderSuccess($CaptchaService->create());
}
/**
* 发送短信验证码
* @return Json
* @throws BaseException
*/
public function sendSmsCaptcha(): Json
{
$SmsCaptchaService = new SmsCaptchaService;
if ($SmsCaptchaService->handle($this->postForm())) {
return $this->renderSuccess('发送成功,请注意查收');
}
return $this->renderError($SmsCaptchaService->getError() ?: '短信发送失败');
}
}
+67
View File
@@ -0,0 +1,67 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use app\api\model\Card as CardModel;
use app\api\model\Setting as SettingModel;
use app\api\service\User as UserService;
use cores\exception\BaseException;
use app\common\service\QueueService;
/**
* 实体卡兑换管理
* Class Card
* @package app\api\controller
*/
class Card extends Controller
{
/**
* 确认兑换
* @param string|null $card_number 兑换卡号
* @param string|null $secret_key 卡密
* @return array|\think\response\Json
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function submit($card_number = null, $secret_key = null)
{
/*if (!$card_number) {
return $this->renderError('请输入兑换卡号');
}*/
if (!$secret_key) {
return $this->renderError('请输入卡密');
}
// 充值设置
$setting = SettingModel::getItem('exchange');
// 验证最低充值金额
if (!$setting['is_entrance']) {
return $this->renderError("很抱歉,兑换功能已关闭");
}
// 分销对象
$obj = CardModel::detail([['secret_key','=',$secret_key], ['is_used','=',10]]);
if(!$obj){
return $this->renderError('无效卡密');
}
// 当前用户信息
$userInfo = UserService::getCurrentLoginUser(true);
// 存入队列处理
$queueService = new QueueService();
$queueService->push('card_queue', json_encode(['card_id'=>$obj['card_id'],'user_id'=>$userInfo['user_id']],320));
return $this->renderSuccess('操作成功');
}
}
+118
View File
@@ -0,0 +1,118 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use think\response\Json;
use app\api\model\Cart as CartModel;
use app\api\service\Cart as CartService;
use cores\exception\BaseException;
/**
* 购物车管理
* Class Cart
* @package app\api\controller
*/
class Cart extends Controller
{
/**
* 购物车商品列表
* @return Json
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @throws \cores\exception\BaseException
*/
public function list(): Json
{
// 购物车商品列表
$service = new CartService;
$list = $service->getList();
// 购物车商品总数量
$cartTotal = (new CartModel)->getCartTotal();
return $this->renderSuccess(compact('cartTotal', 'list'));
}
/**
* 购物车商品总数量
* @return Json
* @throws BaseException
*/
public function total(): Json
{
$model = new CartModel;
$cartTotal = $model->getCartTotal();
return $this->renderSuccess(compact('cartTotal'));
}
/**
* 加入购物车
* @param int $goodsId 商品ID
* @param string $goodsSkuId 商品sku索引
* @param int $goodsNum 商品数量
* @return Json
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function add(int $goodsId, string $goodsSkuId, int $goodsNum): Json
{
$model = new CartModel;
if (!$model->add($goodsId, $goodsSkuId, $goodsNum)) {
return $this->renderError($model->getError() ?: '加入购物车失败');
}
// 购物车商品总数量
$cartTotal = $model->getCartTotal();
return $this->renderSuccess(compact('cartTotal'), '加入购物车成功');
}
/**
* 更新购物车商品数量
* @param int $goodsId 商品ID
* @param string $goodsSkuId 商品sku索引
* @param int $goodsNum 商品数量
* @return Json
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function update(int $goodsId, string $goodsSkuId, int $goodsNum): Json
{
$model = new CartModel;
if (!$model->sUpdate($goodsId, $goodsSkuId, $goodsNum)) {
return $this->renderError($model->getError() ?: '更新失败');
}
// 购物车商品总数量
$cartTotal = $model->getCartTotal();
return $this->renderSuccess(compact('cartTotal'), '更新成功');
}
/**
* 删除购物车中指定记录
* @param array $cartIds 购物车ID集, 如果为空删除所有
* @return Json
* @throws BaseException
*/
public function clear(array $cartIds = []): Json
{
$model = new CartModel;
if (!$model->clear($cartIds)) {
return $this->renderError($model->getError() ?: '操作失败');
}
// 购物车商品总数量
$cartTotal = $model->getCartTotal();
return $this->renderSuccess(compact('cartTotal'), '操作成功');
}
}
@@ -0,0 +1,37 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use app\api\model\Category as CategoryModel;
/**
* 商品分类控制器
* Class Category
* @package app\api\controller
*/
class Category extends Controller
{
/**
* 分类列表
* @return array|\think\response\Json
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function list()
{
$model = new CategoryModel;
$list = $model->getListPublic($this->request->param());
return $this->renderSuccess(compact('list'));
}
}
+213
View File
@@ -0,0 +1,213 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use app\api\model\Order as OrderModel;
use app\api\model\Setting as SettingModel;
use app\api\service\User as UserService;
use app\api\service\Cart as CartService;
use app\api\service\order\Checkout as CheckoutService;
use app\api\validate\order\Checkout as CheckoutValidate;
use app\common\enum\Setting as SettingEnum;
use cores\exception\BaseException;
use think\response\Json;
/**
* 订单结算控制器
* Class Checkout
* @package app\api\controller
*/
class Checkout extends Controller
{
// 结算台验证器
/* @var CheckoutValidate $validate */
private $validate;
/**
* 结算台订单信息
* @param string $mode
* @return Json
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function order(string $mode = 'buyNow'): Json
{
// 用户信息不存在 => 注册新用户 或者 跳转到绑定手机号页
$setting = SettingModel::getItem(SettingEnum::REGISTER);
// 当前用户信息
$userInfo = UserService::getCurrentLoginUser(true);
// 后台设置了需强制绑定手机号, 返回前端isBindMobile, 跳转到手机号验证页
if ($setting['isForceBindMpweixin'] && empty($userInfo['mobile'])) {
return $this->renderError('当前用户未绑定手机号', ['isBindMobile' => true]);
}
if ($mode === 'buyNow') {
return $this->buyNow();
} elseif ($mode === 'cart') {
return $this->cart();
}
return $this->renderError('结算模式不合法');
}
/**
* 订单提交
* @param string $mode
* @return Json
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function submit(string $mode = 'buyNow'): Json
{
return $this->order($mode);
}
/**
* 订单确认-立即购买
* @return Json
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function buyNow(): Json
{
// 实例化结算台服务
$Checkout = new CheckoutService;
// 订单结算api参数
$params = $Checkout->setParam($this->getParam([
'goodsId' => 0,
'goodsSkuId' => '',
'goodsNum' => 0,
]));
// 表单验证
if (!$this->getValidate()->scene('buyNow')->check($params)) {
return $this->renderError($this->getValidate()->getError(), ['isCreated' => false]);
}
// 立即购买:获取订单商品列表
$model = new OrderModel;
$goodsList = $model->getOrderGoodsListByNow(
(int)$params['goodsId'],
(string)$params['goodsSkuId'],
(int)$params['goodsNum']
);
// 获取订单确认信息
$orderInfo = $Checkout->onCheckout($goodsList);
if ($this->request->isGet()) {
return $this->renderSuccess([
'order' => $orderInfo,
'personal' => $Checkout->getPersonal(),
'setting' => $Checkout->getSetting(),
]);
}
// 验证订单是否存在错误
if ($Checkout->hasError()) {
return $this->renderError($Checkout->getError(), ['is_created' => false]);
}
// 创建订单
if (!$Checkout->createOrder($orderInfo)) {
return $this->renderError($Checkout->getError() ?: '订单创建失败', ['is_created' => false]);
}
// 构建微信支付请求
$payment = $model->onOrderPayment($Checkout->model, $params['payType']);
// 返回结算信息
return $this->renderSuccess([
'orderId' => $Checkout->model['order_id'], // 订单id
'payType' => $params['payType'], // 支付方式
'payment' => $payment // 微信支付参数
]);
}
/**
* 订单确认-购物车结算
* @return Json
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function cart(): Json
{
// 实例化结算台服务
$Checkout = new CheckoutService;
// 订单结算api参数
$params = $Checkout->setParam($this->getParam());
// 购物车ID集
$cartIds = $this->getCartIds();
// 商品结算信息
$CartModel = new CartService;
// 购物车商品列表
$goodsList = $CartModel->getOrderGoodsList($cartIds);
// 获取订单结算信息
$orderInfo = $Checkout->onCheckout($goodsList);
if ($this->request->isGet()) {
return $this->renderSuccess([
'order' => $orderInfo,
'personal' => $Checkout->getPersonal(),
'setting' => $Checkout->getSetting(),
]);
}
// 验证订单是否存在错误
if ($Checkout->hasError()) {
return $this->renderError($Checkout->getError(), ['is_created' => false]);
}
// 创建订单
if (!$Checkout->createOrder($orderInfo)) {
return $this->renderError($Checkout->getError() ?: '订单创建失败');
}
// 移出购物车中已下单的商品
$CartModel->clear($cartIds);
// 构建微信支付请求
$payment = $Checkout->onOrderPayment();
// 返回状态
return $this->renderSuccess([
'orderId' => $Checkout->model['order_id'], // 订单id
'payType' => $params['payType'], // 支付方式
'payment' => $payment // 微信支付参数
]);
}
/**
* 获取结算台验证器
* @return CheckoutValidate
*/
private function getValidate(): CheckoutValidate
{
if (!$this->validate) {
$this->validate = new CheckoutValidate;
}
return $this->validate;
}
/**
* 获取购物车ID集
* @return false|string[]
*/
private function getCartIds()
{
$cartIds = $this->request->param('cartIds');
return explode(',', $cartIds);
}
/**
* 订单结算提交的参数
* @param array $define
* @return array
*/
private function getParam(array $define = []): array
{
return array_merge($define, $this->request->param());
}
}
+396
View File
@@ -0,0 +1,396 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use app\api\model\Code as CodeModel;
use app\api\model\Notify as NotifyModel;
use app\api\model\Shop as ShopModel;
use app\api\model\Order as OrderModel;
use think\cache\driver\Redis;
use cores\exception\BaseException;
use think\facade\Cache;
use think\response\Json;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Cookie\CookieJar;
/**
* 产码控制器
* Class Code
* @package app\api\controller
*/
class Code extends Controller
{
/**
* 查询支付状态
* @throws \app\common\exception\BaseException
* @throws \think\exception\DbException
*/
public function payStatus()
{
$data = $this->request->get();
$zone = isset($data['zone'])?$data['zone']:1; //订单分区
$this->saveLog("进入支付查询");
//开始
$model = new CodeModel();
$orderModel = new OrderModel();
$NotifyModel = new NotifyModel();
$array = $model->getList($zone);
$this->saveLog("进入支付查询,分区:".$zone.",订单数量:".count($array));
//获取IP组
$iPGroup = $this->getIPGroup();
foreach ($array as $k=>$val) {
$payTotal = $orderModel->getZoneOrderTotal([['code_id', '=', $val['code_id']],['order_status', '=', 20]]);
$waitPayTotal = $orderModel->getZoneOrderTotal([['code_id', '=', $val['code_id']],['order_status', '=', 10]]);
$modelOr = OrderModel::detail([['code_id', '=', $val['code_id']],['order_status', '=', 10]]);
$text = $val['passageway'] == 'ZFBH5'?'订单已支付':'该订单已完成支付';
if (isset($modelOr['order_id']) && !empty($modelOr['order_id']) && $payTotal <= 0 && $waitPayTotal == 1) {
if(isset($iPGroup[0]['ip'])) {
$res = $this->checkStatusProxy(htmlspecialchars_decode($val['search_url']), $val['passageway'], $iPGroup[0]['ip'], $iPGroup[0]['port'], $text);
}else {
$res = $this->checkStatus(htmlspecialchars_decode($val['search_url']), $val['passageway'], $text);
}
if ($res !== false) { //支付成功
$pass = $modelOr['callback'] == 1 ? $NotifyModel->add($modelOr) : true;
if ($pass) {
$model->update([
'order_id' => $modelOr['order_id'],
'pay_status' => 1,
],['code_id'=>$val['code_id']]);
$modelOr->save([
'pay_status' => 20,
'pay_time' => time(),
'order_status' => 20,
]);
return $this->renderSuccess('操作成功');
} else {
return $this->renderError($NotifyModel->getError() ?: '操作失败');
}
}
}
}
$this->saveLog("支付查询结束,分区:".$zone.",订单数量:".count($array));
}
/**
* 查询失效状态
* @throws \app\common\exception\BaseException
* @throws \think\exception\DbException
*/
public function lapseStatus()
{
//连接本地的 Redis 服务
// 获取分布式锁
$lock_key = 'lapseStatus_lock';
$max_wait_time = 10; // 最大等待时间(秒)
$retry_interval = 100; // 重试间隔时间(毫秒)
$lock_ttl = 600; // 锁定时间(秒)
$lock_count = 0; // 锁的重试次数
// 获取分布式锁
$redis = Cache::store('redis');
$lock = false;
$wait_time = 0;
$lock_value = '';
while ($wait_time <= $max_wait_time) {
$lock_value = uniqid(); // 生成唯一的锁值
if ($redis->set($lock_key, $lock_value, 'EX', $lock_ttl, 'NX')) {
$lock = true;
break;
} else {
// 获取锁失败,等待一段时间后重试
$lock_count++;
usleep($retry_interval * 1000);
$wait_time += ($retry_interval / 1000);
if ($lock_count > 40) {
// 重试次数超过限制,抛出异常
$this->saveLog("失效查询重试次数超过限制");
}
}
}
if($lock) {
try {
// TODO: 需要加锁的业务逻辑
// 字符串操作
$conn = new \think\cache\driver\Redis(config('cache.stores.redis'));
$codesIp = $conn->get('codesIp');
$codesPort = $conn->get('codesPort');
$codeNum = $conn->get('codeNum');
if (empty($codesIp) || empty($codeNum) || $codeNum <= 0) {
//获取IP组
$iPGroup = $this->getIPGroup();
$codesIp = isset($iPGroup[0]['ip']) ? $iPGroup[0]['ip'] : '';
$codesPort = isset($iPGroup[0]['port']) ? $iPGroup[0]['port'] : '';
$codeNum = 20;
$conn->set('codesIp', $codesIp);
$conn->set('codesPort', $codesPort);
}
$modelOr = new OrderModel();
$model = new CodeModel();
$this->saveLog("失效查询开始");
//非失效码的状态更新
$nonFailure = $model->getNonFailure();
foreach ($nonFailure as $val) {
$codeM = CodeModel::detail($val['code_id']);
$create_time = is_numeric($val['create_time']) ? $val['create_time'] : strtotime($val['create_time']);
//支付码失效
if ($create_time + $val['expiration_time'] < time()) {
$codeM->save([
'status' => 3,
]);
//分配时间过长未支付,订单超时,支付码释放
} elseif ($val['allot_time'] + 300 < time()) {
$text = $val['passageway'] == 'ZFBH5' ? '订单已支付' : '该订单已完成支付';
if (!empty($codesIp)) {
$conn->set('codeNum', $codeNum - 1);
$res = $this->checkStatusProxy(htmlspecialchars_decode($val['search_url']), $val['passageway'], $codesIp, $codesPort, $text);
} else {
$res = $this->checkStatus(htmlspecialchars_decode($val['search_url']), $val['passageway'], $text);
}
$status = 1;
$pay_status = 0;
if ($res !== false) { //已支付 更改状态
$status = 3;
$pay_status = 1;
} else {
//重新写入队列左边(为的是后进先出,失败的一般代表比较前面的码,所以放在左边)
$code_queue = ['code_id' => (int)$val['code_id'], 'expire_time' => $create_time + (float)$val['expiration_time']]; // 过期时间
//先清楚队列再加入,避免重复
Cache::store('redis')->lRem($val['passageway'] . '_' . ($val['money'] * 1), json_encode($code_queue, 320), 1);
Cache::store('redis')->lPush($val['passageway'] . '_' . ($val['money'] * 1), json_encode($code_queue, 320));
$this->saveLog("回码:".json_encode($code_queue, 320));
}
$codeM->save([
'allot_time' => 0,
'back_time' => time(),
'status' => $status,
'pay_status' => $pay_status,
]);
}
if ($val['code_id']) {
$modelOr->update([
'code_id' => 0,
'order_status' => 30,
'old_code_id' => $val['code_id']
], ['code_id' => $val['code_id'],
'order_status' => 10]);
}
}
//处理未匹配上码的订单为超时
$modelOr->update([
'order_status' => 30,
], [['code_id', '=', 0],
['order_status', '=', 10], ['create_time', '<', time() - 120]]);
$this->saveLog("失效查询结束");
} finally {
// 释放锁
$lock_value_in_redis = $redis->get($lock_key);
if ($lock_value_in_redis === $lock_value) { // 如果当前锁的值和刚才设置的值相等,则说明当前线程持有该锁,可以进行释放
$redis->del($lock_key); // 删除锁
}
}
}
//未使用超过调起次数的支付码
/*$modelNew = new CodeModel();
$modelNew->setStatusLose([],['status' => array('=', 1),
'num' => array('>=', 100)]);*/
}
public function getIPGroup(): array
{
$html = @file_get_contents("http://http.tiqu.letecs.com/getip3?num=1&type=2&pro=&city=0&yys=0&port=1&time=1&ts=0&ys=0&cs=0&lb=1&sb=0&pb=4&mr=1&regions=");
$result = json_decode($html,true);
$ips = is_array($result['data'])?$result['data']:[];
return $ips;
}
public function test(){
$data = $this->request->get();
$queue_name = $data['passageway'].'_'.$data['money'];
$queue_length = Cache::store('redis')->lLen($queue_name);
var_dump($queue_length);
// 获取队列中的所有值
$queue_values = Cache::store('redis')->lRange($queue_name, 0, $queue_length - 1);
var_dump($queue_values);
die();
/*return $this->renderSuccess([], '提交成功');
$html = @file_get_contents("http://http.tiqu.letecs.com/getip3?num=1&type=2&pro=&city=0&yys=0&port=1&pack=301270&ts=0&ys=0&cs=0&lb=1&sb=0&pb=4&mr=1&regions=");
$result = json_decode($html,true);
$ips = $result['data'];
var_dump(date("Y-m-d H:i:s"));*/
$data = $this->request->get();
$order_id = $data['order_id'];
var_dump($this->checkQueue($order_id));die();
$val = OrderModel::detail($order_id);
$codesIp = '';
$codesPort = '';
//获取IP组
$iPGroup = $this->getIPGroup();
var_dump($iPGroup);
$codesIp = isset($iPGroup[0]['ip'])?$iPGroup[0]['ip']:'';
$codesPort = isset($iPGroup[0]['port'])?$iPGroup[0]['port']:'';
/*$aa = str_replace("&", "%26", $val['search_url']);
$bb = str_replace("amp;", "", $aa);
$stream_opts = [
"ssl" => [
"verify_peer" => false,
"verify_peer_name" => false,
]
];
$html = @file_get_contents(urldecode($bb), false, stream_context_create($stream_opts));
$res = strpos($html, '该订单已完成支付');*/
$text = $val['passageway'] == 'ZFBH5'?'订单已支付':'该订单已完成支付';
/*if(!empty($codesIp)) {
$res = $this->checkStatusProxy(htmlspecialchars_decode($val['search_url']), $val['passageway'], $codesIp, $codesPort, $text);
}else {
$res = $this->checkStatus(htmlspecialchars_decode($val['search_url']), $val['passageway'], $text);
}*/
$res = $this->checkStatusProxy(htmlspecialchars_decode($val['search_url']), $val['passageway'], $codesIp, $codesPort, $text);
//$res = $this->checkStatus(htmlspecialchars_decode($val['search_url']));
var_dump($res);
var_dump(date("Y-m-d H:i:s"));
}
/**
* 插入队列判断当前是否可执行
* @param $code_id
* @return
*/
public function checkQueue($code_id)
{
$message = Cache::store('redis')->lPop("queue:$code_id");
// 如果队列为空,则写入队列
if ($message === null || $message === false) {
// 消息内容
$message = 1;
// 监控客户的消息 Hash
Cache::store('redis')->watch("code:$code_id");
// 开始事务
Cache::store('redis')->multi();
// 将消息添加到队列末尾
Cache::store('redis')->rPush("queue:$code_id", $message);
// 提交事务
$result = Cache::store('redis')->exec();
if ($result !== null && $result !== false) {
return true;
}
}
return false;
}
public function checkStatus($url,$passageway,$text='该订单已完成支付'){
if(in_array($passageway,['WX','SNZFBH5'])){
$ch = curl_init();
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT,10);
curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt ($ch, CURLOPT_MAXREDIRS, 3);
$content = curl_exec($ch);
}else {
$publicPath = app()->getRootPath() . 'public/';
$escaped_url = escapeshellarg($url);
$command = "node {$publicPath}myscript.js {$escaped_url} 2>&1";
$content = shell_exec($command);
}
//$res = strpos((string)$content,$text);
return (string)$content;
}
public function checkStatusProxy($targetUrl,$passageway,$ip,$port,$text='该订单已完成支付'){
if(in_array($passageway,['WX','SNZFBH5'])){
// 代理服务器
$proxyServer = "http://" . $ip . ":" . $port;
// 隧道身份信息
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $targetUrl);
curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
// 设置代理服务器
//curl_setopt($ch, CURLOPT_PROXYTYPE, 0); //http
curl_setopt($ch, CURLOPT_PROXYTYPE, 5); //sock5
curl_setopt($ch, CURLOPT_PROXY, $proxyServer);
// 设置隧道验证信息
curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727;)");
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
}else{
$publicPath = app()->getRootPath() . 'public/';
$escaped_url = escapeshellarg($targetUrl);
//$command = "node {$publicPath}myscript_proxy.js {$escaped_url} {$ip} {$port} 2>&1";
$command = "node {$publicPath}myscript.js {$escaped_url} 2>&1";
$result = shell_exec($command);
}
$res = strpos((string)$result,$text);
return $res;
}
public function jysx(){
$res = $this->checkStatus('https://t-h5.einrkv.com/qAvYzu2Uraqq/ak7X8TC8Vq6TCkRvtlHzJZE2%252FeIBI0HjIVvQc0IIwXhcng%252FC2I3D0bicsYRpOpUqmtASUp6v7MiNCtPpPPV%2BKgeNvxF%2BQ%252FEXaPT886oB785uqOkFAlj6KDk8hEzwLQ4pjMuZ1xnPeU5fljvX84bwZPx9J%2Bb7nMmsvF2yTahh6FU%3D', 'zfb');
var_dump($res);
return;
$this->saveLog("码校验查询开始");
//开始
$model = new CodeModel();
//连接本地的 Redis 服务
$conn = new \Redis(); // 实例化
$conn->connect('127.0.0.1','6379');
$codepage = $conn->get('codepagejy');
$codepage = empty($codepage)?1:$codepage;
$array = $model->getSx($codepage);
$this->saveLog("进入码校验查询,页码:".$codepage.",码数:".count($array));
//获取IP组
$iPGroup = $this->getIPGroup();
foreach ($array as $k=>$val) {
$text = $val['passageway'] == 'ZFBH5'?'订单已支付':'该订单已完成支付';
if(isset($iPGroup[0]['ip'])) {
$res = $this->checkStatusProxy(htmlspecialchars_decode($val['search_url']), $iPGroup[0]['ip'], $iPGroup[0]['port'], $text);
}else {
$res = $this->checkStatus(htmlspecialchars_decode($val['search_url']), $text);
}
if ($res !== false) { //支付成功
$model->update([
'status' => 3,
],['code_id'=>$val['code_id']]);
}
}
if(count($array) < 20){
$conn->set('codepagejy',1);
}else{
$conn->set('codepagejy',$codepage+1);
}
$this->saveLog("码校验查询结束");
}
}
+76
View File
@@ -0,0 +1,76 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use app\api\model\Comment as CommentModel;
/**
* 商品评价控制器
* Class Comment
* @package app\api\controller
*/
class Comment extends Controller
{
/**
* 商品评价列表
* @param int $goodsId 商品ID
* @param int|null $scoreType 评价评分
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function list(int $goodsId, int $scoreType = null)
{
// 评价列表
$model = new CommentModel;
$list = $model->getCommentList($goodsId, $scoreType);
return $this->renderSuccess(compact('list'));
}
/**
* 商品评分总数
* @param int $goodsId
* @return array|\think\response\Json
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function total(int $goodsId)
{
// 指定评分总数
$model = new CommentModel;
$total = $model->getTotal($goodsId);
return $this->renderSuccess(compact('total'));
}
/**
* 商品评价列表 (限制数量, 用于商品详情页展示)
* @param int $goodsId
* @param int $limit
* @return array|\think\response\Json
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function listRows(int $goodsId, int $limit = 5)
{
// 评价列表
$model = new CommentModel;
$list = $model->listRows($goodsId, $limit);
// 评价总数量
$total = $model->rowsTotal($goodsId);
return $this->renderSuccess(compact('list', 'total'));
}
}
@@ -0,0 +1,480 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use app\common\crypto\Crypto;
use think\response\Json;
use cores\BaseController;
use app\api\model\User as UserModel;
use app\api\model\Store as StoreModel;
use app\api\model\Merchant as MerchantModel;
use app\api\service\User as UserService;
use cores\exception\BaseException;
use app\common\service\SybOil;
/**
* API控制器基类
* Class Controller
* @package app\store\controller
*/
class Controller extends BaseController
{
// 当前商城ID
protected $storeId;
protected $latitude;
protected $longitude;
protected $province;
/**
* API基类初始化
* @throws BaseException
*/
public function initialize()
{
// 当前商城id
$this->storeId = $this->getStoreId();
$this->latitude = input('get.latitude');
$this->longitude = input('get.longitude');
$res = $this->httpCurl('https://apis.map.qq.com/ws/geocoder/v1/',['location'=>$this->latitude.','.$this->longitude,'key'=>'ETFBZ-F4XCW-YOQRI-RWBQM-BAZIQ-2VFS5']);
if(isset($res['status']) && $res['status'] == 0){
$this->province = $res['result']['address_component']['province'];
}
// 验证当前商城状态
$this->checkStore();
// 验证当前客户端状态
$this->checkClient();
}
/**
* 获取当前商城ID
* @return int|null
* @throws BaseException
*/
protected function getStoreId(): ?int
{
$storeId = getStoreId(); // app/api/common.php
empty($storeId) && throwError('缺少必要的参数:storeId');
return $storeId;
}
/**
* 验证当前商城状态
* @return void
* @throws BaseException
*/
private function checkStore(): void
{
// 获取当前商城信息
$store = StoreModel::detail($this->storeId);
if (empty($store)) {
throwError('当前商城信息不存在');
}
if ($store['is_recycle'] || $store['is_delete']) {
throwError('当前商城已删除');
}
}
/**
* 验证当前客户端是否允许访问
* @throws BaseException
*/
private function checkClient()
{
$client = getPlatform();
$settingClass = [
'H5' => [\app\api\model\h5\Setting::class, 'checkStatus', 'H5端']
];
if (!isset($settingClass[$client])) {
return;
}
$status = call_user_func([$settingClass[$client][0], $settingClass[$client][1]]);
$status === false && throwError('很抱歉,当前' . $settingClass[$client][2] . '端暂不支持访问');
}
/**
* 获取当前用户信息
* @param bool $isForce 强制验证登录
* @return UserModel|bool|null
* @throws BaseException
*/
protected function getLoginUser(bool $isForce = true)
{
return UserService::getCurrentLoginUser($isForce);
}
/**
* 返回封装后的 API 数据到客户端
* @param string|null $code 状态码
* @param string $message
* @param string|null $errCode
* @param string|null $errMessage
* @param array $data
* @return Json
*/
protected function oilRenderJson(string $code = null, string $message = '', string $errCode = null, string $errMessage = null, array $data = []): Json
{
return json(compact('code', 'message', 'errCode', 'errMessage', 'data'));
}
/**
* 返回操作成功json
* @param array|string $data
* @param string $code
* @param string $message
* @return Json
*/
protected function oilRenderSuccess($data = [], string $code = '', string $message = ''): Json
{
if(empty($code)){
$code = '00';
}
if(empty($message)){
$message = config('api_status.response_code')[$code] ?? '';
}
if (is_string($data)) {
$message = $data;
$data = [];
}
return $this->oilRenderJson($code, $message, null, null, $data);
}
/**
* 返回操作失败json
* @param string $code
* @param string $errCode
* @param string $message
* @param string $errMessage
* @return Json
*/
protected function oilRenderError(string $code, string $errCode, string $message = '', string $errMessage = ''): Json
{
if(empty($message)){
$message = config('api_status.response_code')[$code] ?? '';
}
if(empty($errMessage)){
$errMessage = config('api_status.error_code')[$errCode] ?? '';
}
return $this->oilRenderJson($code, $message, $errCode, $errMessage);
}
/**
* 返回封装后的 API 数据到客户端
* @param int|null $status 状态码
* @param string $message
* @param array $data
* @return Json
*/
protected function renderJson(int $status = null, string $message = '', array $data = []): Json
{
return json(compact('status', 'message', 'data'));
}
/**
* 返回操作成功json
* @param array|string $data
* @param string $message
* @return Json
*/
protected function renderSuccess($data = [], string $message = 'success'): Json
{
if (is_string($data)) {
$message = $data;
$data = [];
}
return $this->renderJson(config('status.success'), $message, $data);
}
/**
* 返回操作失败json
* @param string $message
* @param array $data
* @return Json
*/
protected function renderError(string $message = 'error', array $data = []): Json
{
return $this->renderJson(config('status.error'), $message, $data);
}
/**
* 获取post数据 (数组)
* @param $key
* @return mixed
*/
protected function postData($key = null)
{
return $this->request->post(is_null($key) ? '' : $key . '/a');
}
/**
* 获取post数据 (数组)
* @param string $key
* @return mixed
*/
protected function postForm(string $key = 'form')
{
return $this->postData($key);
}
//创建sign
public function makeSign($data,$appKey) {
ksort($data);
$string = $this->toUrlParams($data);
$string = $string . "&key=" . $appKey;
$string = md5($string);
$result = strtoupper($string);
return $result;
}
//检验sign是否正确
public function verifySign($data) {
//check sign
if (!isset($data['sign']) || !$data['sign']) {
return ['code'=>1,'msg'=>'发送的数据签名不存在'];
}
//check sign
if (!isset($data['appid']) || !$data['appid']) {
return ['code'=>1,'msg'=>'发送的应用参数1不存在'];
}
//check timestamp
if (!isset($data['timestamp']) || !$data['timestamp']) {
return ['code'=>1,'msg'=>'缺少时间戳参数'];
}
// 验证请求, 10分钟失效
if (time() - $data['timestamp'] > 600) {
return ['code'=>1,'msg'=>'验证超时, 请重新发送请求'];
}
$merchant = MerchantModel::detail(['appId'=>$data['appid']]);
if (empty($merchant['merchant_id'])) {
return ['code'=>1,'msg'=>'appid错误'];
}
$clientSign = $data['sign'];
unset($data['sign']);
$serverSign = $this->makeSign($data,$merchant['appKey']);
if ($clientSign == $serverSign) {
return ['code'=>0,'msg'=>'签名验证通过','merchant_id'=>$merchant['merchant_id'],'callback'=>$merchant['callback']];
} else {
return ['code'=>1,'msg'=>'签名不合法'];
}
}
//生成url字符串
private function toUrlParams($values){
$buff = "";
foreach ($values as $k => $v)
{
//&& $v != ""
if($k != "sign" && !is_array($v)){
$buff .= $k . "=" . $v . "&";
}
}
$buff = trim($buff, "&");
return $buff;
}
/**
* http请求
*
* @param $url //请求地址
* @param $params //链接后拼接的参数数组
* @param $method //get/post
* @param $header //请求头数组
* @return array
*/
function httpCurl($url, $params, $method = 'GET', $header = array(), $multi = false): array
{
date_default_timezone_set('PRC'); //设置默认时区
$opts = array( //请求参数
CURLOPT_TIMEOUT => 30,
CURLOPT_RETURNTRANSFER => 1, //将curl_exec()获取的信息以文件流的形式返回
CURLOPT_SSL_VERIFYPEER => false, //不对认证证书来源的检查
CURLOPT_SSL_VERIFYHOST => false, //不从证书中检查SSL加密算法是否存在
CURLOPT_HTTPHEADER => $header, //Content-Type类型
CURLOPT_COOKIESESSION => true,
CURLOPT_FOLLOWLOCATION => 1, // 使用自动跳转
CURLOPT_COOKIE => session_name() . '=' . session_id(),
);
/* 根据请求类型设置特定参数 */
switch (strtoupper($method)) {
case 'GET':
// 链接后拼接参数 如xxx.com?key = value & key2=value
$opts[CURLOPT_URL] = $url . '?' . http_build_query($params);//将数组变成key=value&key2=value
break;
case 'POST': //判断是否传输文件
$params = $multi ? $params : http_build_query($params); //同上
$opts[CURLOPT_URL] = $url;
$opts[CURLOPT_POST] = 1;
$opts[CURLOPT_POSTFIELDS] = $params;
break;
default:
throw new BaseException(['message' => '不支持的请求方式!']);
}
/* 初始化并执行curl请求 */
$ch = curl_init();
curl_setopt_array($ch, $opts); // 数组形式设置URL和其他参数
$data = curl_exec($ch); // URL抓取并把它传递给浏览器
$error = curl_error($ch);
curl_close($ch);
if ($error){
$data = ['code'=>2,'message'=>$error];
}else {
$data = json_decode($data, true);
}
return $data;
}
public function sendRequest($company, $url, $businessParams = [], $appendHeaders = [], $file = null)
{
$crypto = new Crypto($company);
// 签名并组合header,并加密数据
$this->saveLog(json_encode($businessParams,320));
$requestData = $crypto->prepareRequest($appendHeaders, $businessParams);
$businessParams = $requestData['encryptData'];
// 构建默认的公共参数头
$headers = [];
foreach ($requestData['header'] as $k=>$val){
$headers[] = $k.': '.$val;
}
$this->saveLog(json_encode($requestData['header'],320));
$this->saveLog(json_encode($businessParams,320));
// 使用 cURL 发送请求
$ch = curl_init();
// 设置请求 URL
curl_setopt($ch, CURLOPT_URL, $url);
// 设置请求方式为 POST
curl_setopt($ch, CURLOPT_POST, true);
// 返回结果而不是输出
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// 包含响应头在输出中
curl_setopt($ch, CURLOPT_HEADER, true);
$headers[] = 'Charset: UTF-8';
if ($file) {
// 如果有文件上传,设置 multipart/form-data 表单
$filePath = $file->getPathname();
$fileName = $file->getOriginalName();
$fileMime = $file->getMimeType();
$postFields = [
'file' => new \CURLFile($filePath, $fileMime, $fileName),
'businessParams' => json_encode($businessParams, JSON_UNESCAPED_UNICODE),
];
curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
} else {
// 如果没有文件上传,直接发送业务参数的 JSON 数据
$postFields = json_encode($businessParams, JSON_UNESCAPED_UNICODE);
$headers[] = 'Content-Type: application/json';
curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
// 执行请求
$response = curl_exec($ch);
// 检查是否有错误
if (curl_errno($ch)) {
$error_msg = curl_error($ch);
curl_close($ch);
return ['status' => '01', 'message' => $error_msg];
}
// 获取响应头大小
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
// 分离响应头和响应体
$headerString = substr($response, 0, $header_size);
$bodyString = substr($response, $header_size);
// 关闭 cURL 句柄
curl_close($ch);
// 解析响应头为数组
$headerArray = [];
foreach (explode("\r\n", $headerString) as $header) {
if (trim($header) !== '' && strpos($header, ':') !== false) {
list($key, $value) = explode(': ', $header, 2);
$headerArray[strtolower(trim($key))] = trim($value);
}
}
$res = $crypto->processResponse(['header'=>$headerArray,'encryptData'=>json_decode($bodyString, true)]);
if(!$res){
return ['status' => '01', 'message' => '解密失败'];
}
// 返回结果
return $res;
}
/**
* xml/json数据的POST请求
*
* @param $url //请求地址
* @param $xmlData //xml 或 json数据
*/
public function SendData($url,$xmlData)
{
$curl = curl_init();
$param[CURLOPT_URL] = $url;
$param[CURLOPT_HEADER] = false;
$param[CURLOPT_RETURNTRANSFER] = true;
$param[CURLOPT_FOLLOWLOCATION] = true;
$param[CURLOPT_POST] = true;
$param[CURLOPT_POSTFIELDS] = $xmlData;
$param[CURLOPT_SSL_VERIFYPEER] = false;
$param[CURLOPT_SSL_VERIFYHOST] = false;
curl_setopt_array($curl,$param); //传参数
$data = curl_exec($curl); //执行命令
curl_close($curl);
return $data;
}
// 循环创建目录
public function mk_dir($dir, $mode = 0777)
{
if (is_dir($dir) || @mkdir($dir,$mode)) return true;
if (!$this->mk_dir(dirname($dir),$mode)) return false;
return @mkdir($dir,$mode);
}
/** 记录日志
* @param $data
*/
public function saveLog($data){
$SybOil = new SybOil();
$SybOil->saveLogStore($data);
}
/** 插入订单号
* @param $order_no
*/
public function insertNo($order_no){
return $order_no;
//return (int)$order_no-100000;
}
/** 获取订单号
* @param $order_no
*/
public function getOrderNo($order_no){
return $order_no;
//return (int)$order_no+100000;
}
}
+39
View File
@@ -0,0 +1,39 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use think\response\Json;
use app\api\model\Coupon as CouponModel;
/**
* 优惠券中心
* Class Coupon
* @package app\api\controller
*/
class Coupon extends Controller
{
/**
* 优惠券列表
* @return Json
* @throws \cores\exception\BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function list(): Json
{
$model = new CouponModel;
$list = $model->getList();
return $this->renderSuccess(compact('list'));
}
}
+37
View File
@@ -0,0 +1,37 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use app\api\model\Express as ExpressModel;
/**
* 物流公司管理
* Class Express
* @package app\api\controller
*/
class Express extends Controller
{
/**
* 物流公司列表
* @return array|\think\response\Json
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function list()
{
$model = new ExpressModel;
$list = $model->getAll();
return $this->renderSuccess(compact('list'));
}
}
+99
View File
@@ -0,0 +1,99 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use think\response\Json;
use app\api\model\{Goods as GoodsModel};
use app\api\service\{Goods as GoodsService};
/**
* 商品控制器
* Class Goods
* @package app\api\controller
*/
class Goods extends Controller
{
/**
* 商品列表
* @return \think\response\Json
* @throws \think\db\exception\DbException
*/
public function list(): \think\response\Json
{
// 获取列表数据
$model = new GoodsModel;
$param = $this->request->param();
$list = $model->getList($param);
return $this->renderSuccess(compact('list', 'param'));
}
/**
* 获取商品详情
* @param int $goodsId
* @return \think\response\Json
* @throws \cores\exception\BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function detail(int $goodsId): \think\response\Json
{
// 商品详情
$model = new GoodsModel;
$goodsInfo = $model->getDetails($goodsId);
return $this->renderSuccess(['detail' => $goodsInfo]);
}
/**
* 获取商品详情(基础信息)
* @param int $goodsId
* @param bool $verifyStatus
* @return \think\response\Json
* @throws \cores\exception\BaseException
*/
public function basic(int $goodsId, bool $verifyStatus = true): \think\response\Json
{
// 获取商品详情
$model = new GoodsModel;
$detail = $model->getBasic($goodsId, $verifyStatus);
return $this->renderSuccess(compact('detail'));
}
/**
* 获取商品规格数据
* @param int $goodsId 商品ID
* @return \think\response\Json
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function specData(int $goodsId): \think\response\Json
{
// 获取商品详情
$model = new GoodsModel;
$specData = $model->getSpecData($goodsId);
return $this->renderSuccess(compact('specData'));
}
/**
* 获取商品的指定SKU信息
* @param int $goodsId 商品ID
* @param string $goodsSkuId 商品SKU标识
* @return Json
*/
public function skuInfo(int $goodsId, string $goodsSkuId): Json
{
$skuInfo = GoodsService::getSkuInfo($goodsId, $goodsSkuId);
return $this->renderSuccess(compact('skuInfo'));
}
}
+36
View File
@@ -0,0 +1,36 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use app\api\model\Help as HelpModel;
/**
* 帮助中心
* Class help
* @package app\store\controller\wxapp
*/
class Help extends Controller
{
/**
* 获取列表记录
* @return array
* @throws \think\db\exception\DbException
*/
public function list()
{
$model = new HelpModel;
$list = $model->getList();
return $this->renderSuccess(compact('list'));
}
}
+16
View File
@@ -0,0 +1,16 @@
<?php
namespace app\api\controller;
/**
* 默认控制器
* Class Index
* @package app\api\controller
*/
class Index
{
public function index()
{
echo '当前访问的index.php,请将index.html设为默认站点入口';
}
}
@@ -0,0 +1,53 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use app\api\model\UserCoupon as UserCouponModel;
use app\api\service\User as UserService;
/**
* 用户优惠券
* Class Coupon
* @package app\api\controller
*/
class MyCoupon extends Controller
{
/**
* 用户优惠券列表
* @return \think\response\Json
* @throws \cores\exception\BaseException
* @throws \think\db\exception\DbException
*/
public function list(): \think\response\Json
{
$userId = UserService::getCurrentLoginUserId();
$model = new UserCouponModel;
$list = $model->getList($userId, $this->request->param());
return $this->renderSuccess(compact('list'));
}
/**
* 领取优惠券
* @param int $couponId
* @return \think\response\Json
* @throws \cores\exception\BaseException
*/
public function receive(int $couponId): \think\response\Json
{
$model = new UserCouponModel;
if ($model->receive($couponId)) {
return $this->renderSuccess([], '领取成功');
}
return $this->renderError($model->getError() ?: '领取失败');
}
}
+133
View File
@@ -0,0 +1,133 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use app\api\model\Notify as NotifyModel;
use app\api\model\Order as OrderModel;
use app\api\model\Merchant as MerchantModel;
use app\api\model\order\Record as RecordModel;
use app\common\library\wechat\WxPay;
use app\common\library\leshua\LsPay;
use think\response\Json;
/**
* 支付成功异步通知接口
* Class Notify
* @package app\api\controller
*/
class Notify extends Controller
{
/**
* 支付成功异步通知(微信小程序-微信支付)
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function wxpay()
{
// 微信支付组件:验证异步通知
$WxPay = new WxPay();
$WxPay->notify();
}
/**
* 支付成功异步通知(微信小程序-乐刷支付)
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function leshua()
{
// 微信支付组件:验证异步通知
$LsPay = new LsPay();
$LsPay->notify();
}
/**
* 发送通知
* @throws \app\common\exception\BaseException
* @throws \think\exception\DbException
*/
public function sendNotify()
{
$model = new NotifyModel();
$array = $model->getList();
$this->saveLog("进入回调查询");
$order_status = ['10'=>'等待支付','20'=>'支付成功','30'=>'支付超时'];
foreach ($array as $val){
$status = 0;
//发送通知
$model = new OrderModel;
$order = $model->getOrderDetailById($val['order_id']);
if(is_object($order)) {
$order_no = $this->getOrderNo($order['order_no']);
$merchant = MerchantModel::detail($order['merchant_id']);
$params = [
'appid' => $merchant['appId'],
'name' => $order['name'],
'money' => $order['money'],
'order_no' => $order_no,
'order_no_sn' => $order['order_no_sn'],
'order_status' => $order['order_status'],
'order_status_text' => $order_status[$order['order_status']],
'create_time' => $order['create_time'],
];
//$this->saveLog("回调数据,".json_encode($params,320));
$sign = $this->makeSign($params,$merchant['appKey']);
$params['sign'] = $sign;
$res = $this->httpCurl($val['notify_url'], $params, 'POST');
$this->saveLog("回调通知,订单:".$order_no.",结果:".json_encode($res,320));
//var_dump($res);
if ($res['code'] == '0000') {
$status = 1;
}
$nm = NotifyModel::detail($val['notify_id']);
$result = $nm->sureNotify(['status' => $status, 'num' => $nm['num'] + 1]);
$this->saveLog("回调通知订单状态修改,订单:".$order_no.",结果:".$result);
}
}
}
/**
* 发送通知
*/
public function notify()
{
$res = json_decode('{"optType":"cancel_share","amount":3,"oilCardNo":"YKA2407232037340001","type":"sub","order_id":10171,"user_id":10001,"store_id":10001}',true);
// 油卡变动通知
$order = OrderModel::detail(['oilCardNo'=>$res['oilCardNo'], 'amount'=>$res['amount']]);
$res['order_id'] = $order['order_id'];
$res['user_id'] = $order['user_id'];
$res['store_id'] = $order['store_id'];
$this->saveLog('油卡变动参数:'.json_encode($res));
$RecordModel = new RecordModel();
$this->saveLog('油卡变动记录写入结果:'. $RecordModel->add($res));
/*$header = [
'method' => 'syb.notify.oilCard.share',
];
$body = [
'shareNo' => '11',
'oilCardNo' => '22',
'saleOrderNo' => '33',
'amount' => 0.01,
'status' =>'success',
'msg' => '',
'oilCardType' => 'card',
];
$response = $this->sendRequest('http://139.129.21.253/index.php?s=/api/sybNotify/notify', $body, $header);
//var_dump($response);*/
}
}
+584
View File
@@ -0,0 +1,584 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use app\api\controller\Controller;
use app\api\model\partners\Order as OrderModel;
use app\common\model\Partners as PartnersModel;
use app\common\model\PartnersGoods as PartnersGoodsModel;
use app\common\model\Goods as GoodsModel;
use app\api\model\GoodsSku as GoodsSkuModel;
use app\common\crypto\RsaUtil;
use app\common\service\goods\source\Factory as StockFactory;
use app\common\service\IdingjuOil;
use app\store\model\Company as CompanyModel;
use app\store\model\order\QrCode as QrCodeModel;
use cores\exception\BaseException;
use think\facade\Request;
use think\response\Json;
use think\facade\Db;
use think\db\exception\PDOException;
use app\common\service\QueueService;
use think\facade\Validate;
/**
* 用户分油
* Class OilCard
* @package app\api\controller\v1_0_0\oil
*/
class OilCard extends Controller
{
/**
* 用户分油
* @return Json
* @throws BaseException
* @throws \think\db\exception\DbException
*/
public function share()
{
// 获取所有 HTTP 请求头
$headers = Request::header();
// 获取 JSON 格式的请求体
$jsonData = Request::instance()->getContent();
$data = json_decode($jsonData, true);
$appKey = $headers['appkey'] ?? '';
$requestId = $headers['requestid'] ?? '';
$method = $headers['method'] ?? '';
// 请求头METHOD参数不正确
if($method != 'syb.oil.oilCard.share'){
return $this->oilRenderError('12', '0005');
}
try {
Db::name('request_log')->insert([
'request_id' => $requestId,
'app_key' => $appKey,
'create_time' => time()
]);
} catch (\think\Exception $e) {
// 判断是否唯一索引冲突
if (strpos($e->getMessage(), 'Duplicate entry') !== false) {
return $this->oilRenderError('12', '0012'); // 请求流水号重复
}
// 其他数据库异常
return $this->oilRenderError('99', '9999'); // 未知错误
}
$partners = PartnersModel::detail(['appKey' => $appKey]);
if(!$partners){
return $this->oilRenderError('02','0004');
}
$crypto = new RsaUtil($partners);
$result = $crypto->processResponse(['header'=>$headers,'encryptData'=>$data]);
if ($result['code'] === '00') {
// 业务处理
$data = $result['data'];
$orgNo = $data['orgNo'] ?? '';
$goodsNo = $data['goodsNo'] ?? '';
$mobile = $data['mobile'] ?? '';
$saleOrderNo = $data['saleOrderNo'] ?? '';
$oilCardType = $data['oilCardType'] ?? '';
// 请求参数orgNo与请求头appKey不存在对应关系
if($partners['orgNo'] != $orgNo){
return $this->oilRenderError('12','0014');
}
if(!preg_match('/^1[3-9]\d{9}$/', $mobile)) {
return $this->oilRenderError('12','0013', '', '手机号格式不正确');
}
// 销售平台订单号重复
$order = OrderModel::detail(['partners_id' => $partners['partners_id'], 'partners_order_no' => $saleOrderNo]);
if($order){
return $this->oilRenderError('12','2023');
}
// 未找到卡券对应的信息
$goods = GoodsModel::detail(['goods_no' => $goodsNo, 'oilCardType' => $oilCardType]);
if(!$goods){
return $this->oilRenderError('12','2047');
}
// 判断商品库存
$detail = GoodsSkuModel::detail($goods['goods_id'], '0');
if (1 > $detail['stock_num']) {
return $this->oilRenderError('12','0013', '', "很抱歉,商品 [{$goods['goods_name']}] 平台库存不足");
}
$partnersGoods = PartnersGoodsModel::detail($partners['partners_id'], $goods['goods_id']);
if(!$partnersGoods || $partnersGoods['stock_num'] <= 0){
return $this->oilRenderError('01','2010');
}
$OrderModel = new OrderModel();
$oilCardNo = 'OIL' . self::createOrderNo();
if($OrderModel->saveOrder([
'province' => $goods['province'],
'mobile' => $mobile,
'oilCardType' => $oilCardType,
'oilCardNo' => $oilCardNo,
'partners_order_no' => $saleOrderNo,
'partners_id' => $partners['partners_id'],
'goods_id' => $goods['goods_id'],
'goods_name' => $goods['goods_name'],
'goods_no' => $goods['goods_no'],
'goods_price' => $goods['goods_price_min'],
'total_num' => 1,
'total_price' => $goods['goods_price_min'],
'total_pay_price' => $goods['goods_price_min'],
'store_id' => $this->storeId,
])){
// 更新商品库存 (针对下单减库存的商品)
$this->updateGoodsStockNum([
[
'deduct_stock_type' => 10,
'goods_id' => $goods['goods_id'],
'goods_sku_id' => $detail['id'],
'total_num' => 1,
]
]);
// 存入队列处理
$queueService = new QueueService();
$queueService->push('partners_queue', json_encode(['order_id'=>$OrderModel->order_id],320));
return $this->oilRenderSuccess([
'oilCardNo' => $oilCardNo,
'amount' => $goods['goods_price_min'],
]);
}
} else {
// 错误处理
return $this->oilRenderError($result['code'], $result['errCode'], '', $result['errMessage'] ?? '');
}
}
/**
* 更新商品库存 (针对下单减库存的商品)
* @param $order
* @return void
*/
private function updateGoodsStockNum($goodsList): void
{
StockFactory::getFactory(10)->updateGoodsStock($goodsList);
}
public static function createOrderNo(): string
{
// 获取当前时间戳到毫秒(13位)
$time = (int)(microtime(true) * 1000); // 返回形如 1716544103986
// 拼接一个 4 位随机数
$rand = mt_rand(1000, 9999);
return (string)($time . $rand); // 拼接成纯数字字符串
}
/**
* @param $goodsNo
* @return string
*/
public function getCompany($goodsNo): string
{
switch ($goodsNo) {
case 'djgdface100':
case 'djgdface200':
case 'djgdface300':
return 'umQZhIHKofyA';
case 'jmgxyyface100':
case 'jmgxyyface200':
case 'jmgxyyface300':
case 'jmgzface100':
case 'jmgzface200':
case 'jmgzface300':
case 'jmfjface100':
case 'jmfjface200':
case 'jmfjface300':
return 'HpWqXIgYvTBg';
case 'face003':
return 'NKJBgaaRNdiL'; // 测试参数
default:
return '';
}
}
/**
* 付款二维码申请
* @return Json
* @throws BaseException
* @throws \think\db\exception\DbException
*/
public function getPayQrCode()
{
// 获取所有 HTTP 请求头
$headers = Request::header();
// 获取 JSON 格式的请求体
$jsonData = Request::instance()->getContent();
$data = json_decode($jsonData, true);
$appKey = $headers['appkey'] ?? '';
$requestId = $headers['requestid'] ?? '';
$method = $headers['method'] ?? '';
// 请求头METHOD参数不正确
if($method != 'syb.pay.qrCode.request'){
return $this->oilRenderError('12', '0005');
}
try {
Db::name('request_log')->insert([
'request_id' => $requestId,
'app_key' => $appKey,
'create_time' => time()
]);
} catch (\think\Exception $e) {
// 判断是否唯一索引冲突
if (strpos($e->getMessage(), 'Duplicate entry') !== false) {
return $this->oilRenderError('12', '0012'); // 请求流水号重复
}
// 其他数据库异常
return $this->oilRenderError('99', '9999'); // 未知错误
}
$partners = PartnersModel::detail(['appKey' => $appKey]);
if(!$partners){
return $this->oilRenderError('02','0004');
}
$crypto = new RsaUtil($partners);
$result = $crypto->processResponse(['header'=>$headers,'encryptData'=>$data]);
if ($result['code'] === '00') {
// 业务处理
$data = $result['data'];
$orgNo = $data['orgNo'] ?? '';
$oilCardNo = $data['oilCardNo'] ?? '';
$oilCardType = $data['oilCardType'] ?? '';
$mobile = $data['mobile'] ?? '';
// 请求参数orgNo与请求头appKey不存在对应关系
if($partners['orgNo'] != $orgNo){
return $this->oilRenderError('12','0014');
}
if(!preg_match('/^1[3-9]\d{9}$/', $mobile)) {
return $this->oilRenderError('12','0013', '', '手机号格式不正确');
}
$order = OrderModel::detail(['oilCardNo' => $oilCardNo]);
if(!$order) {
return $this->oilRenderError('12','0013', '', '未找到对应订单');
}
$company = CompanyModel::detail(['orgNo' => $this->getCompany($order['goods_no'])]);
if (!$company) {
return $this->oilRenderError('12','0013', '', '没有可用参数:【' . $order['goods_no'] . '】');
}
$IdingjuOil = new IdingjuOil();
// 对接平台接口
$res = $IdingjuOil->payQrCodeRequest(['order_no'=>$oilCardNo], $company);
if(isset($res['code']) && $res['code'] == '1' && isset($res['data']['useQrCodeUrl'])){
// 插入支付码记录
$QrCodeModel = new QrCodeModel();
$QrCodeModel->add([
'oilCardNo'=>$order['oilCardNo'],
'qrCode'=>$res['data']['useQrCodeUrl'],
'amount'=>$order['goods_price'],
'order_id'=>$order['order_id'],
'user_id'=>0,
'store_id'=>$order['store_id'],
]);
return $this->oilRenderSuccess([
'qrCode'=>$res['data']['useQrCodeUrl']
]);
}else{
return $this->oilRenderError('12','0013', '', $res['message'] ?? '');
}
} else {
// 错误处理
return $this->oilRenderError($result['code'], $result['errCode'], '', $result['errMessage'] ?? '');
}
}
/**
* 油券库存查询
* @return Json
* @throws BaseException
* @throws \think\db\exception\DbException
*/
public function stock()
{
// 获取所有 HTTP 请求头
$headers = Request::header();
// 获取 JSON 格式的请求体
$jsonData = Request::instance()->getContent();
$data = json_decode($jsonData, true);
$appKey = $headers['appkey'] ?? '';
$requestId = $headers['requestid'] ?? '';
$method = $headers['method'] ?? '';
// 请求头METHOD参数不正确
if($method != 'syb.oil.oilCard.stockList'){
return $this->oilRenderError('12', '0005');
}
try {
Db::name('request_log')->insert([
'request_id' => $requestId,
'app_key' => $appKey,
'create_time' => time()
]);
} catch (\think\Exception $e) {
// 判断是否唯一索引冲突
if (strpos($e->getMessage(), 'Duplicate entry') !== false) {
return $this->oilRenderError('12', '0012'); // 请求流水号重复
}
// 其他数据库异常
return $this->oilRenderError('99', '9999'); // 未知错误
}
$partners = PartnersModel::detail(['appKey' => $appKey]);
if(!$partners){
return $this->oilRenderError('02','0004');
}
$crypto = new RsaUtil($partners);
$result = $crypto->processResponse(['header'=>$headers,'encryptData'=>$data]);
if ($result['code'] === '00') {
// 业务处理
$data = $result['data'];
$orgNo = $data['orgNo'] ?? '';
$goodsNo = $data['goodsNo'] ?? '';
// 请求参数orgNo与请求头appKey不存在对应关系
if($partners['orgNo'] != $orgNo){
return $this->oilRenderError('12','0014');
}
// 未找到卡券对应的信息
$goods = GoodsModel::detail(['goods_no' => $goodsNo]);
if(!$goods){
return $this->oilRenderError('12','2047');
}
$partnersGoods = PartnersGoodsModel::detail($partners['partners_id'], $goods['goods_id']);
if(!$partnersGoods){
return $this->oilRenderError('01','2010');
}
$orderModel = new OrderModel();
$sucNum = $orderModel->getCount(['partners_id' => $partners['partners_id'], 'goods_id' => $goods['goods_id']], 'all');
$useNum = $orderModel->getCount(['partners_id' => $partners['partners_id'], 'goods_id' => $goods['goods_id']], 'used');
return $this->oilRenderSuccess([
'goodsNo'=>$goods['goods_no'], // 商品编号
'canOrderNum'=>$partnersGoods['stock_num'], // 剩余可下单数量
'unUseNum'=>floatval($sucNum) - floatval($useNum), // 未使用商品数量
'useNum'=>$useNum, // 已使用商品数量
]);
} else {
// 错误处理
return $this->oilRenderError($result['code'], $result['errCode'], '', $result['errMessage'] ?? '');
}
}
/**
* 用户分油记录查询
* @return Json
* @throws BaseException
* @throws \think\db\exception\DbException
*/
public function shareList()
{
// 获取所有 HTTP 请求头
$headers = Request::header();
// 获取 JSON 格式的请求体
$jsonData = Request::instance()->getContent();
$data = json_decode($jsonData, true);
$appKey = $headers['appkey'] ?? '';
$requestId = $headers['requestid'] ?? '';
$method = $headers['method'] ?? '';
// 请求头METHOD参数不正确
if($method != 'syb.oil.oilCard.shareList'){
return $this->oilRenderError('12', '0005');
}
try {
Db::name('request_log')->insert([
'request_id' => $requestId,
'app_key' => $appKey,
'create_time' => time()
]);
} catch (\think\Exception $e) {
// 判断是否唯一索引冲突
if (strpos($e->getMessage(), 'Duplicate entry') !== false) {
return $this->oilRenderError('12', '0012'); // 请求流水号重复
}
// 其他数据库异常
return $this->oilRenderError('99', '9999'); // 未知错误
}
$partners = PartnersModel::detail(['appKey' => $appKey]);
if(!$partners){
return $this->oilRenderError('02','0004');
}
$crypto = new RsaUtil($partners);
$result = $crypto->processResponse(['header'=>$headers,'encryptData'=>$data]);
if ($result['code'] === '00') {
// 业务处理
$data = $result['data'];
$data['orgNo'] = $data['orgNo'] ?? '';
$data['mobile'] = $data['mobile'] ?? '';
$data['shareNo'] = $data['shareNo'] ?? '';
$data['saleOrderNo'] = $data['saleOrderNo'] ?? '';
$data['beginDate'] = $data['beginDate'] ?? '';
$data['endDate'] = $data['endDate'] ?? '';
$data['pageLimit'] = $data['pageLimit'] ?? 10;
$data['pageNum'] = $data['pageNum'] ?? 1;
$data['partners_id'] = $partners['partners_id'];
// 请求参数orgNo与请求头appKey不存在对应关系
if($partners['orgNo'] != $data['orgNo']){
return $this->oilRenderError('12','0014');
}
if(!preg_match('/^1[3-9]\d{9}$/', $data['mobile'])) {
return $this->oilRenderError('12','0013', '', '手机号格式不正确');
}
$rule = [
'beginDate' => 'require|dateFormat:Ymd',
'endDate' => 'require|dateFormat:Ymd',
'pageLimit' => 'number|between:1,30',
'pageNum' => 'number|min:1'
];
$message = [
'beginDate.require' => 'beginDate 不能为空',
'beginDate.dateFormat' => 'beginDate 格式错误,正确格式为 yyyyMMdd',
'endDate.require' => 'endDate 不能为空',
'endDate.dateFormat' => 'endDate 格式错误,正确格式为 yyyyMMdd',
'pageLimit.number' => 'pageLimit 必须是数字',
'pageLimit.between' => 'pageLimit 必须在 1-30 之间',
'pageNum.number' => 'pageNum 必须是数字',
'pageNum.min' => 'pageNum 必须大于等于 1',
];
$validate = Validate::rule($rule)->message($message);
if (!$validate->check($data)) {
return $this->oilRenderError('12','0013', '', $validate->getError());
}
// 检查日期间隔
$begin = date_create_from_format('Ymd', $data['beginDate']);
$end = date_create_from_format('Ymd', $data['endDate']);
if ($begin > $end) {
return $this->oilRenderError('12','0013', '', 'endDate 必须大于或等于 beginDate');
}
if ($begin->diff($end)->days > 365) {
return $this->oilRenderError('12','0013', '', '日期间隔不能超过 365 天');
}
$model = new OrderModel;
$list = $model->getList($data);
// 组装返回格式
$result = [
'totalNum' => $list->total(),
'totalPage' => $list->lastPage(),
'pageNum' => $list->currentPage(),
'pageLimit' => $list->listRows(),
'orderList' => array_map(function ($item) {
return [
'shareNo' => $item['shareNo'],
'mobile' => $item['mobile'],
'oilCardNo' => $item['oilCardNo'],
'productName' => $item['goods_name'],
'num' => $item['total_num'],
'amount' => $item['total_price'],
'createTime' => $item['create_time'],
];
}, $list->items())
];
return $this->oilRenderSuccess($result);
} else {
// 错误处理
return $this->oilRenderError($result['code'], $result['errCode'], '', $result['errMessage'] ?? '');
}
}
/**
* 订单状态查询
* @return Json
* @throws BaseException
* @throws \think\db\exception\DbException
*/
public function orderStatus()
{
// 获取所有 HTTP 请求头
$headers = Request::header();
// 获取 JSON 格式的请求体
$jsonData = Request::instance()->getContent();
$data = json_decode($jsonData, true);
$appKey = $headers['appkey'] ?? '';
$requestId = $headers['requestid'] ?? '';
$method = $headers['method'] ?? '';
// 请求头METHOD参数不正确
if($method != 'syb.oil.oilCard.orderStatus'){
return $this->oilRenderError('12', '0005');
}
try {
Db::name('request_log')->insert([
'request_id' => $requestId,
'app_key' => $appKey,
'create_time' => time()
]);
} catch (\think\Exception $e) {
// 判断是否唯一索引冲突
if (strpos($e->getMessage(), 'Duplicate entry') !== false) {
return $this->oilRenderError('12', '0012'); // 请求流水号重复
}
// 其他数据库异常
return $this->oilRenderError('99', '9999'); // 未知错误
}
$partners = PartnersModel::detail(['appKey' => $appKey]);
if(!$partners){
return $this->oilRenderError('02','0004');
}
$crypto = new RsaUtil($partners);
$result = $crypto->processResponse(['header'=>$headers,'encryptData'=>$data]);
if ($result['code'] === '00') {
// 业务处理
$data = $result['data'];
$data['orgNo'] = $data['orgNo'] ?? '';
$data['oilCardNo'] = $data['oilCardNo'] ?? '';
// $data['saleOrderNo'] = $data['saleOrderNo'] ?? '';
// 请求参数orgNo与请求头appKey不存在对应关系
if($partners['orgNo'] != $data['orgNo']){
return $this->oilRenderError('12','0014');
}
$rule = [
'oilCardNo' => 'require',
];
$message = [
'oilCardNo.require' => 'oilCardNo 不能为空',
];
$validate = Validate::rule($rule)->message($message);
if (!$validate->check($data)) {
return $this->oilRenderError('12','0013', '', $validate->getError());
}
$detail = OrderModel::detail(['oilCardNo' => $data['oilCardNo']]);
// 组装返回格式
$result = [
'province' => $detail['province'],
'mobile' => $detail['mobile'],
'oilCardNo' => $detail['oilCardNo'],
'shareNo' => $detail['shareNo'],
'saleOrderNo' => $detail['partners_order_no'],
'goods_name' => $detail['goods_name'],
'goods_no' => $detail['goods_no'],
'total_price' => $detail['total_price'],
'oil_status_zsy' => $detail['oil_status_zsy'],
'oil_status' => $detail['oil_status'],
'oil_time' => $detail['oil_time'],
'use_status' => $detail['use_status'],
'use_time' => $detail['use_time'],
];
return $this->oilRenderSuccess($result);
} else {
// 错误处理
return $this->oilRenderError($result['code'], $result['errCode'], '', $result['errMessage'] ?? '');
}
}
}
+401
View File
@@ -0,0 +1,401 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use app\api\model\Goods as GoodsModel;
use app\api\model\Order as OrderModel;
use app\api\model\OrderGoods as OrderGoodsModel;
use app\api\model\Code as CodeModel;
use app\api\model\Merchant as MerchantModel;
use app\api\model\Setting as SettingModel;
use app\common\service\SybOil;
use app\common\service\IdingjuOil;
use app\store\model\Company as CompanyModel;
use app\store\model\Express as ExpressModel;
use app\common\enum\order\PayType as OrderPayTypeEnum;
use app\store\model\order\QrCode as QrCodeModel;
use cores\exception\BaseException;
use think\facade\Request;
use think\response\Json;
use think\cache\driver\Redis;
use GatewayWorker\Lib\Gateway;
/**
* 我的订单控制器
* Class Order
* @package app\api\controller
*/
class Order extends Controller
{
private $redis = null;
/**
* 获取当前用户待处理的订单数量
* @return Json
* @throws BaseException
*/
public function todoCounts(): Json
{
$model = new OrderModel;
$counts = $model->getTodoCounts();
return $this->renderSuccess(compact('counts'));
}
/**
* 我的订单列表
* @param string $dataType 订单类型 (all全部 payment待付款 received待发货 deliver待收货 comment待评价)
* @return Json
* @throws \think\db\exception\DbException
* @throws BaseException
*/
public function list(string $dataType): Json
{
$model = new OrderModel;
$list = $model->getList($dataType);
return $this->renderSuccess(compact('list'));
}
/**
* 订单详情信息
* @param int $orderId 订单ID
* @return Json
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @throws BaseException
*/
public function detail(int $orderId): Json
{
// 订单详情
$model = OrderModel::getUserOrderDetail($orderId);
return $this->renderSuccess([
'order' => $model, // 订单详情
'setting' => [
// 积分名称
'points_name' => SettingModel::getPointsName(),
],
]);
}
/**
* 获取物流信息
* @param int $orderId 订单ID
* @return Json
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @throws BaseException
*/
public function express(int $orderId): Json
{
// 订单信息
$order = OrderModel::getDetail($orderId);
if (!$order['express_no']) {
return $this->renderError('没有物流信息');
}
// 获取物流信息
$model = ExpressModel::detail($order['express_id']);
$express = $model->dynamic($model['express_name'], $model['kuaidi100_code'], $order['express_no']);
if ($express === false) {
return $this->renderError($model->getError());
}
return $this->renderSuccess(compact('express'));
}
/**
* 取消订单
* @param int $orderId
* @return Json
* @throws BaseException
*/
public function cancel(int $orderId): Json
{
$model = OrderModel::getDetail($orderId);
if ($model->cancel()) {
return $this->renderSuccess('订单取消成功');
}
return $this->renderError($model->getError() ?: '订单取消失败');
}
/**
* 确认收货
* @param int $orderId
* @return Json
* @throws BaseException
*/
public function receipt(int $orderId): Json
{
$model = OrderModel::getDetail($orderId);
if ($model->receipt()) {
return $this->renderSuccess('确认收货成功');
}
return $this->renderError($model->getError());
}
/**
* 立即支付
* @param int $orderId 订单ID
* @param int $payType 支付方式
* @return Json
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @throws BaseException
*/
public function pay(int $orderId, int $payType = OrderPayTypeEnum::WECHAT): Json
{
// 获取订单详情
$model = OrderModel::getUserOrderDetail($orderId);
// 订单支付事件
if (!$model->onPay($payType)) {
return $this->renderError($model->getError() ?: '订单支付失败');
}
// 构建微信支付请求
$payment = $model->onOrderPayment($model, $payType);
// 支付状态提醒
return $this->renderSuccess([
'order_id' => $model['order_id'], // 订单id
'pay_type' => $payType, // 支付方式
'payment' => $payment // 微信支付参数
]);
}
/**
* 提交订单
* @return Json
* @throws \think\db\exception\DbException
* @throws BaseException
*/
public function submitOrder(): Json
{
$data = $this->postData();
$verify = $this->verifySign($data);
if($verify['code'] > 0){
return $this->renderError($verify['msg']);
}else {
$data['merchant_id'] = $verify['merchant_id'];
$data['callback'] = $verify['callback'];
$model = new OrderModel;
$data['order_no'] = $this->insertNo($data['order_no']);
$data['ip'] = Request::instance()->ip();
if(!$bool = $model->putInto($data)) {
$this->saveLog("提交订单,订单:" . $data['order_no'] . ",数据:".json_encode($data,320).",结果:" . $bool);
return $this->renderError('插入订单失败');
}
$domain = Request::instance()->domain();
$qrcode = $domain.'/pay?passageway='.$data['passageway'].'&orderId='.$model->order_id;
$res = [
'qrcode'=>$qrcode,
];
return $this->renderSuccess($res, '提交成功');
}
}
public function generateRandomString($length = 10, $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') {
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return $randomString;
}
/**
* 查询订单
* @return Json
* @throws \think\db\exception\DbException
* @throws BaseException
*/
public function searchOrder(): Json
{
$data = $this->postData();
$verify = $this->verifySign($data);
if($verify['code'] > 0){
return $this->renderError($verify['msg']);
}else {
$order = OrderModel::detail(['order_no'=>$data['order_no']]);
if(empty($order['order_id'])){
return $this->renderError('订单错误');
}
$res = [
'order_no'=>$order['order_no'],
'pay_status'=>$order['pay_status'],
'pay_time'=>$order['pay_time']
];
return $this->renderSuccess($res, '提交成功');
}
}
/**
* 提交订单
* @return
* @throws \app\common\exception\BaseException
* @throws \think\exception\DbException
* @throws \Exception
*/
public function testOrder()
{
$data = $this->request->get();
$money = isset($data['money'])?$data['money']:299;
$passageway = isset($data['passageway'])?$data['passageway']:'WX';
$shop_id = isset($data['shop_id'])?$data['shop_id']:'';
$merchant = MerchantModel::detail($shop_id);
if(empty($merchant['merchant_id'])){
return $this->renderError('商户不存在');
}
$domain = Request::instance()->domain();
$ip = Request::instance()->ip();
$data = [
'appid'=>$merchant['appId'],
'name'=>'系统订单',
'money'=>$money,
'order_no'=> 'XT'.$this->generateRandomString(10),
'timestamp'=>time(),
'passageway'=>$passageway,
'notifyUrl'=>$domain.'/index.php?s=/api/notify/received',
'ip'=>$ip,
];
$data['merchant_id'] = $merchant['merchant_id'];
$data['shop_id'] = 10033;
$model = new OrderModel;
$data['order_no'] = $this->insertNo($data['order_no']);
if(!$bool = $model->putInto($data)) {
$this->saveLog("提交订单,订单:" . $data['order_no'] . ",数据:".json_encode($data,320).",结果:" . $bool);
return $this->renderError('插入系统订单失败');
}
$domain = Request::instance()->domain();
$qrcode = $domain.'/pay?passageway='.$data['passageway'].'&orderId='.$model->order_id;
/*$qrcode = $domain.'/index.php?s=/store/passport/detail&orderId='.$model->order_id;
return $qrcode;*/
header('location: '.$qrcode.'');
exit();
}
/** 测试发送数据
*/
public function send()
{
//Gateway::sendToClient("7f00000107d00000001b", json_encode(['type' => 'test_send']));
var_export(Gateway::getAllUidList());
//Gateway::sendToClient('c0a8008a07d000000002',json_encode(['type' => 'test_send']));
if(Gateway::isUidOnline(10001))
{
// 在线就转发消息给对应的uid
Gateway::sendToUid(10001, json_encode(['type' => 'test_send']));
}
var_export(Gateway::isUidOnline(10001));
//Gateway::sendToUid('10001', json_encode(['type' => 'test_send']));
//return $this->renderSuccess([], '提交成功');
}
/**
* 获取支付二维码
* @return Json
* @throws \think\db\exception\DbException
*/
public function qrCode(): Json
{
$IdingjuOil = new IdingjuOil();
$postData = $this->request->param();
$postData['order_goods_id'] = $this->request->param('orderGoodsId');
$orderGoods = OrderGoodsModel::detail($postData['order_goods_id']);
if($orderGoods['use_status'] != 0){
return $this->renderError('油券已核销');
}else {
$company = CompanyModel::detail($orderGoods['company_id']);
// 对接平台接口
$res = $IdingjuOil->payQrCodeRequest(['order_no'=>$orderGoods['oilCardNo']], $company);
if($res['code'] == '1' && isset($res['data']['useQrCodeUrl'])){
// 插入支付码记录
$QrCodeModel = new QrCodeModel();
$QrCodeModel->add([
'oilCardNo'=>$orderGoods['oilCardNo'],
'qrCode'=>$res['data']['useQrCodeUrl'],
'amount'=>$orderGoods['goods_price'],
'order_id'=>$orderGoods['order_id'],
'user_id'=>$orderGoods['user_id'],
'store_id'=>$orderGoods['store_id'],
]);
$res = [
'qrCode'=>$res['data']['useQrCodeUrl']
];
return $this->renderSuccess($res, '提交成功');
}else{
return $this->renderError('平台创建用户失败【'.($res['errMessage'] ?? $res['message']).'】');
}
}
}
/**
* 获取支付二维码图片
* @return Json
* @throws \think\db\exception\DbException
*/
public function qrCodeImg(): Json
{
// $res = [
// 'base64'=> 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAGQCAIAAAAP3aGbAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGwElEQVR4nO3cwY4bRxAFQdPY//9l+roQ4IULVoGVmoizwO0ZUok+vdf7/f4LoODvTx8A4L8SLCBDsIAMwQIyBAvIECwgQ7CADMECMgQLyBAsIEOwgAzBAjIEC8gQLCBDsIAMwQIyBAvIECwgQ7CADMECMgQLyBAsIEOwgAzBAjIEC8gQLCBDsIAMwQIyBAvIECwgQ7CAjK/tP/B6vbb/xKO83+/Rv99+/9PzTE3Pf+39PM3278ENC8gQLCBDsIAMwQIyBAvIECwgQ7CADMECMgQLyBAsIEOwgAzBAjIEC8gQLCBDsICM9T2sqe09nWuu7VVNz3Pt/NuunWfbtb0wNywgQ7CADMECMgQLyBAsIEOwgAzBAjIEC8gQLCBDsIAMwQIyBAvIECwgQ7CADMECMs7tYU1d2+up7yVdO//0+62ff9u19zPlhgVkCBaQIVhAhmABGYIFZAgWkCFYQIZgARmCBWQIFpAhWECGYAEZggVkCBaQIVhARn4Pi5/V96SunYfPcsMCMgQLyBAsIEOwgAzBAjIEC8gQLCBDsIAMwQIyBAvIECwgQ7CADMECMgQLyBAsIMMe1h9uuid1bT/r2nn4LDcsIEOwgAzBAjIEC8gQLCBDsIAMwQIyBAvIECwgQ7CADMECMgQLyBAsIEOwgAzBAjLye1j2j36va/tWdX6fv5cbFpAhWECGYAEZggVkCBaQIVhAhmABGYIFZAgWkCFYQIZgARmCBWQIFpAhWECGYAEZ5/awnraXtG36Pqf7Tdc+f9u18zyNGxaQIVhAhmABGYIFZAgWkCFYQIZgARmCBWQIFpAhWECGYAEZggVkCBaQIVhAhmABGa/pPhF8t72HBd+5YQEZggVkCBaQIVhAhmABGYIFZAgWkCFYQIZgARmCBWQIFpAhWECGYAEZggVkCBaQ8fXpA/xf23tM08/fdu382+e59vnbrp3/2nncsIAMwQIyBAvIECwgQ7CADMECMgQLyBAsIEOwgAzBAjIEC8gQLCBDsIAMwQIyBAvIWN/DuranM3Vtj+navtX25197n9d+n0/jhgVkCBaQIVhAhmABGYIFZAgWkCFYQIZgARmCBWQIFpAhWECGYAEZggVkCBaQIVhAxuvavs+1faLt/ampa9/X1LX3OWVv67PcsIAMwQIyBAvIECwgQ7CADMECMgQLyBAsIEOwgAzBAjIEC8gQLCBDsIAMwQIyBAvIWN/Detoe0PbzPu19TtXfz/ZeWP335oYFZAgWkCFYQIZgARmCBWQIFpAhWECGYAEZggVkCBaQIVhAhmABGYIFZAgWkCFYQMbXpw/wq2t7QNuu7Q1t87w/u7ZPd40bFpAhWECGYAEZggVkCBaQIVhAhmABGYIFZAgWkCFYQIZgARmCBWQIFpAhWECGYAEZ63tY9T2jqWvPe21f7Nr7mdret7q2n3Xt+3LDAjIEC8gQLCBDsIAMwQIyBAvIECwgQ7CADMECMgQLyBAsIEOwgAzBAjIEC8gQLCDjtb13s73H9DTX9ommru1zXTvP1LX/X9vP64YFZAgWkCFYQIZgARmCBWQIFpAhWECGYAEZggVkCBaQIVhAhmABGYIFZAgWkCFYQMbXpw/wq/re09T2nlF972nq2j7U097/NjcsIEOwgAzBAjIEC8gQLCBDsIAMwQIyBAvIECwgQ7CADMECMgQLyBAsIEOwgAzBAjLO7WFNXds/eto+0dT0/Vzbk5qeZ/v3sH2ea8/rhgVkCBaQIVhAhmABGYIFZAgWkCFYQIZgARmCBWQIFpAhWECGYAEZggVkCBaQIVhARn4Pi5/V97nqe1LX1J/XDQvIECwgQ7CADMECMgQLyBAsIEOwgAzBAjIEC8gQLCBDsIAMwQIyBAvIECwgQ7CADHtYf7hr+0fT80xNz3/teZ92/ik3LCBDsIAMwQIyBAvIECwgQ7CADMECMgQLyBAsIEOwgAzBAjIEC8gQLCBDsIAMwQIy8ntY2/s7ddP3c23/aOra+et7Vde+XzcsIEOwgAzBAjIEC8gQLCBDsIAMwQIyBAvIECwgQ7CADMECMgQLyBAsIEOwgAzBAjLO7WFN933gu2v7Tdf2uaaund8NC8gQLCBDsIAMwQIyBAvIECwgQ7CADMECMgQLyBAsIEOwgAzBAjIEC8gQLCBDsICM17X9HYB/44YFZAgWkCFYQIZgARmCBWQIFpAhWECGYAEZggVkCBaQIVhAhmABGYIFZAgWkCFYQIZgARmCBWQIFpAhWECGYAEZggVkCBaQIVhAhmABGYIFZAgWkCFYQIZgARmCBWQIFpAhWEDGP+OBJg1/1F6rAAAAAElFTkSuQmCC'
//// 'base64'=> ''
// ];
// return $this->renderSuccess($res, '提交成功');
$IdingjuOil = new IdingjuOil();
$postData = $this->request->param();
$postData['order_goods_id'] = $this->request->param('orderGoodsId');
$orderGoods = OrderGoodsModel::detail($postData['order_goods_id']);
if($orderGoods['use_status'] != 0){
return $this->renderError('油券已核销');
}else {
/*$res = [
'base64'=> $this->getBase64($orderGoods['qrCode'])
];
return $this->renderSuccess($res, '提交成功');*/
$company = CompanyModel::detail($orderGoods['company_id']);
// 对接平台接口
$res = $IdingjuOil->payQrCodeRequest(['order_no'=>$orderGoods['oilCardNo']], $company);
//$res = $IdingjuOil->payQrCodeRequest(['oilCardNo'=>$orderGoods['oilCardNo'],'shareNo'=>$orderGoods['shareNo'],'mobile'=>$orderGoods['mobile'],'oilCardType'=>$orderGoods['oilCardType']], $company);
//if($res['code'] == '00' && isset($res['data']['qrCode'])){
if($res['code'] == '1' && isset($res['data']['useQrCodeUrl'])){
// 插入支付码记录
$QrCodeModel = new QrCodeModel();
$QrCodeModel->add([
'oilCardNo'=>$orderGoods['oilCardNo'],
'qrCode'=>$res['data']['useQrCodeUrl'],
'amount'=>$orderGoods['goods_price'],
'order_id'=>$orderGoods['order_id'],
'user_id'=>$orderGoods['user_id'],
'store_id'=>$orderGoods['store_id'],
]);
$res = [
'base64'=> $this->getBase64($res['data']['useQrCodeUrl'])
];
return $this->renderSuccess($res, '提交成功');
}else{
return $this->renderError('平台创建用户失败【'.($res['errMessage'] ?? $res['message']).'】');
}
}
}
public function getBase64($url){
$publicPath = app()->getRootPath() . 'public/';
$escaped_url = escapeshellarg($url);
$command = "node {$publicPath}myscript.js {$escaped_url} 2>&1";
$content = shell_exec($command);
return (string)$content;
}
}
+40
View File
@@ -0,0 +1,40 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use app\api\model\Page as PageModel;
/**
* 页面控制器
* Class Index
* @package app\api\controller
*/
class Page extends Controller
{
/**
* 页面数据
* @param int|null $pageId 页面ID, 不传的话默认为首页
* @return array|\think\response\Json
* @throws \cores\exception\BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function detail(int $pageId = null)
{
// 页面数据
$model = new PageModel;
$pageData = $model->getPageData($pageId);
return $this->renderSuccess(compact('pageData'));
}
}
@@ -0,0 +1,97 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use app\api\service\passport\Login as LoginService;
/**
* 用户认证模块
* Class Passport
* @package app\api\controller
*/
class Passport extends Controller
{
/**
* 登录接口 (需提交手机号、短信验证码、第三方用户信息)
* @return array|\think\response\Json
* @throws \cores\exception\BaseException
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function login()
{
// 执行登录
$LoginService = new LoginService;
if (!$LoginService->login($this->postForm())) {
return $this->renderError($LoginService->getError());
}
// 用户信息
$userInfo = $LoginService->getUserInfo();
return $this->renderSuccess([
'userId' => (int)$userInfo['user_id'],
'token' => $LoginService->getToken((int)$userInfo['user_id'])
], '登录成功');
}
/**
* 微信小程序快捷登录 (需提交wx.login接口返回的code、微信用户公开信息)
* 业务流程:判断openid是否存在 -> 存在: 更新用户登录信息 -> 返回userId和token
* -> 不存在: 返回false, 跳转到注册页面
* @return array|\think\response\Json
* @throws \cores\exception\BaseException
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function loginMpWx()
{
// 微信小程序一键登录
$LoginService = new LoginService;
if (!$LoginService->loginMpWx($this->postForm())) {
return $this->renderError($LoginService->getError());
}
// 获取登录成功后的用户信息
$userInfo = $LoginService->getUserInfo();
return $this->renderSuccess([
'userId' => (int)$userInfo['user_id'],
'token' => $LoginService->getToken((int)$userInfo['user_id'])
], '登录成功');
}
/**
* 快捷登录: 微信小程序授权手机号登录
* @return array|\think\response\Json
* @throws \cores\exception\BaseException
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function loginMpWxMobile()
{
// 微信小程序一键登录
$LoginService = new LoginService;
if (!$LoginService->loginMpWxMobile($this->postForm())) {
return $this->renderError($LoginService->getError());
}
// 获取登录成功后的用户信息
$userInfo = $LoginService->getUserInfo();
return $this->renderSuccess([
'userId' => (int)$userInfo['user_id'],
'token' => $LoginService->getToken((int)$userInfo['user_id'])
], '登录成功');
}
}
+122
View File
@@ -0,0 +1,122 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use app\api\model\recharge\Order as OrderModel;
use app\api\model\Setting as SettingModel;
use app\api\service\Payment as PaymentService;
use app\api\service\User as UserService;
use app\common\enum\OrderType as OrderTypeEnum;
use app\common\library\helper;
use cores\exception\BaseException;
use app\api\model\User as UserModel;
/**
* 用户充值管理
* Class Recharge
* @package app\api\controller
*/
class Recharge extends Controller
{
/**
* 确认充值
* @param int|null $planId 方案ID
* @param float|string|null $customMoney 自定义金额
* @return array|\think\response\Json
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function submit(int $planId = null, $customMoney = null)
{
if (getPlatform() !== 'MP-WEIXIN') {
return $this->renderError('很抱歉,余额充值暂时仅支持微信小程序端');
}
// 生成充值订单
$model = new OrderModel;
if (!$model->createOrder($planId, (float)$customMoney)) {
return $this->renderError($model->getError() ?: '充值失败');
}
// 构建微信支付
$payment = PaymentService::wechat(
$model['order_id'],
$model['order_no'],
$model['pay_price'],
OrderTypeEnum::RECHARGE
);
// 充值状态提醒
$message = ['success' => '充值成功', 'error' => '订单未支付'];
return $this->renderSuccess(compact('payment', 'message'));
}
/**
* 确认充值
* @param float|string|null $customMoney 自定义金额
* @param string|null $tel 手机号
* @return array|\think\response\Json
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function share($customMoney = null, $tel = null)
{
if ($customMoney === '' || $customMoney < 0) {
return $this->renderError('请输入正确的分销金额');
}
if (!preg_match('/^\d+$/', $customMoney)) {
return $this->renderError('金额只能输入正整数');
}
// 充值设置
$setting = SettingModel::getItem('recharge');
// 验证最低充值金额
if (helper::bccomp($customMoney, $setting['lowest_money']) === -1) {
return $this->renderError("很抱歉,当前最低充值金额不能低于{$setting['lowest_money']}元");
}
// 当前用户信息
$userInfo = UserService::getCurrentLoginUser(true);
if($customMoney > $userInfo['balance']){
return $this->renderError('分销金额不能大于余额');
}
// 分销对象
$obj = UserModel::detail([['mobile','=',$tel]]);
if(!$obj){
return $this->renderError('系统中不存在此用户,请提醒用户注册');
}
if($userInfo['user_id'] == $obj['user_id']){
return $this->renderError('不能自己分给自己');
}
// 减少当前用的余额
$dec = $userInfo->rechargeToBalance($obj['mobile'],[
'money'=>$customMoney,
'mode'=>'dec',
'remark'=>'转出余额',
]);
if(!$dec){
return $this->renderError('转出失败');
}
// 增加分销对象的余额
$inc = $obj->rechargeToBalance($userInfo['mobile'],[
'money'=>$customMoney,
'mode'=>'inc',
'remark'=>'转入余额',
]);
if(!$inc){
return $this->renderError('转入失败');
}
return $this->renderSuccess('操作成功');
}
}
+96
View File
@@ -0,0 +1,96 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use app\api\model\OrderRefund as OrderRefundModel;
use cores\exception\BaseException;
/**
* 订单售后服务
* Class service
* @package app\api\controller\user\order
*/
class Refund extends Controller
{
/**
* 售后单列表
* @param int $state
* @return array|\think\response\Json
* @throws BaseException
* @throws \think\db\exception\DbException
*/
public function list(int $state = -1)
{
$model = new OrderRefundModel;
$list = $model->getList($state);
return $this->renderSuccess(compact('list'));
}
/**
* 订单商品详情
* @param int $orderGoodsId 订单商品ID
* @return array|\think\response\Json
* @throws BaseException
*/
public function goods(int $orderGoodsId)
{
$model = new OrderRefundModel;
$goods = $model->getRefundGoods($orderGoodsId);
return $this->renderSuccess(compact('goods'));
}
/**
* 申请售后
* @param int $orderGoodsId 订单商品ID
* @return array|\think\response\Json
* @throws BaseException
*/
public function apply(int $orderGoodsId)
{
// 新增售后单记录
$model = new OrderRefundModel;
if ($model->apply($orderGoodsId, $this->postForm())) {
return $this->renderSuccess([], '提交成功');
}
return $this->renderError($model->getError() ?: '提交失败');
}
/**
* 售后单详情
* @param int $orderRefundId 售后单ID
* @return array|\think\response\Json
* @throws BaseException
*/
public function detail(int $orderRefundId)
{
$detail = OrderRefundModel::getDetail($orderRefundId, true);
return $this->renderSuccess(compact('detail'));
}
/**
* 用户发货
* @param int $orderRefundId 售后单ID
* @return array|\think\response\Json
* @throws BaseException
*/
public function delivery(int $orderRefundId)
{
// 售后单详情
$model = OrderRefundModel::getDetail($orderRefundId, false);
if ($model->delivery($this->postForm())) {
return $this->renderSuccess([], '操作成功');
}
return $this->renderError($model->getError() ?: '提交失败');
}
}
+50
View File
@@ -0,0 +1,50 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use app\api\model\Region as RegionModel;
/**
* 地区管理
* Class Region
* @package app\api\controller
*/
class Region extends Controller
{
/**
* 获取所有地区
* @return array|\think\response\Json
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function all()
{
$list = RegionModel::getCacheAll();
return $this->renderSuccess(compact('list'));
}
/**
* 获取所有地区(树状)
* @return array|\think\response\Json
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function tree()
{
$list = RegionModel::getCacheTree();
return $this->renderSuccess(compact('list'));
}
}
+37
View File
@@ -0,0 +1,37 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use app\api\service\Setting as SettingService;
/**
* 商城设置控制器
* Class Setting
* @package app\store\controller
*/
class Setting extends Controller
{
/**
* 商城公共设置(仅展示可公开的信息)
* @return array|\think\response\Json
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function data()
{
$service = new SettingService;
$setting = $service->getPublic();
return $this->renderSuccess(compact('setting'));
}
}
+78
View File
@@ -0,0 +1,78 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use app\api\model\Company as CompanyModel;
use think\facade\Db;
use think\response\Json;
use app\common\service\SybOil;
/**
* 站点列表
* Class Station
* @package app\api\controller
*/
class Station extends Controller
{
/**
* 余额账单明细列表
* @return Json
* @throws \cores\exception\BaseException
* @throws \think\db\exception\DbException
*/
public function list(): Json
{
$SybOil = new SybOil();
$company = CompanyModel::detail('2');
$param = $this->request->param();
$province = Db::name('area')->where(array(
['name', '=', $param['province']],
['level', '=', 1],
))->find();
$city = Db::name('area')->where(array(
['name', '=', $param['city']],
['pid', '=', $province['code']],
['level', '=', 2],
))->find();
$goods = Db::name('goods')->where(array(
['oilCardType', '=', 'zsy_ticket'],
['province', '=', $param['province']],
['status', '=', 10],
))->order('stock_total', 'desc')
->find();
$list = [];
if($goods) {
// 对接平台接口
$res = $SybOil->baseGasStationList(['goodsNo' => $goods['goods_no'], 'longitude' => $param['longitude'], 'latitude' => $param['latitude'], 'province' => $province['code'], 'city' => $city['code']], $company);
if (isset($res['data']['zsyResp']['count']) && $res['data']['zsyResp']['count'] > 0) {
$lists = $res['data']['zsyResp']['lists'];
foreach ($lists as $k => $array) {
$list[] = [
'id' => $k + 1,
'name' => $array['name'],
'brand' => $array['brand'] == 1 ? '中国石油' : '中国BP',
'latitude' => $array['lat'],
'longitude' => $array['lng'],
'address' => '',
'distance' => $array['nearBy'],
'width' => 30,
'height' => 30,
'iconPath' => '/static/marker.png',
'stationCode' => $array['stationCode'],
];
}
}
}
return $this->renderSuccess(compact('list'));
}
}
+161
View File
@@ -0,0 +1,161 @@
<?php
// +----------------------------------------------------------------------
// | 管理系统
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.zizai.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 自在科技
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use app\api\model\Company as CompanyModel;
use app\store\model\User as UserModel;
use app\common\crypto\Crypto;
use app\common\service\SybOil;
use app\store\model\card\CardLog as CardLogModel;
use think\facade\Db;
use think\facade\Request;
use app\common\service\QueueService;
/**
* 加油e卡通通知接口
* Class SybNotify
* @package app\api\controller
*/
class SybNotify extends Controller
{
public function yanzheng()
{
// 拿到队列数据处理
$data = json_decode('{"header":{"content-length":"428","connection":"keep-alive","host":"139.129.21.253","pragma":"no-cache","cache-control":"no-cache","content-type":"application/json;charset=UTF-8","version":"1.0.0","accept-language":"zh-CN,zh;q=0.8","accept-encoding":"gzip, deflate","appkey":"qlv4l3law1","sign":"R9A4Zw5/52bq2gsmaxGMt7QcSPr9RWuxSp40D36VKSeS8uZfifTD/Yknzt6uVZn5G5rhEgDumFiLo7A/eAgo5u/tA+AMizZ3sHHv7mu0dLPO8b9LUdf01I7nxYqyqPatnNJGIgq6dTZyyNdE4YaTEShemnlEC/XI9O1T29obpt8=","user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36 Hutool","requestid":"8232721b-ef72-40a7-aa24-bdbb536fd602","method":"syb.notify.oilCard.share","accept":"text/html,application/json,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"},"res":{"shareNo":"CDV2408082020420001","amount":"200.00","saleOrderNo":"2024080897521014","oilCardType":"zsy_ticket","oilCardNo":"CDV2408082020420001","status":"success"}}', true);
$headers = $data['header'];
$res = $data['res'];
// 存入队列处理
$queueService = new QueueService();
$queueService->push('callback_queue', json_encode(['header'=>$headers,'res'=>$res],320));
}
/** 通知接口
* @return array|mixed|string[]
*/
public function notifyOld()
{
// 获取所有 HTTP 请求头
$headers = Request::header();
// 获取 JSON 格式的请求体
$jsonData = Request::instance()->getContent();
$data = json_decode($jsonData, true);
$this->saveLog('callback_queue回调加密参数原文;header:'.json_encode($headers).',body:'.$jsonData);
$appKey = $headers['appKey'] ?? $headers['appkey'];
$company = CompanyModel::detail(['appKey' => $appKey]);
$crypto = new Crypto($company);
$res = $crypto->processResponse(['header'=>$headers,'encryptData'=>$data]);
// 记录日志等
$this->saveLog('callback_queue回调参数解密,'.$headers['method'].":".json_encode($res,320));
// 检查 JSON 解码是否成功
if (!$res) {
return json(['code' => '03', 'message' => '报文解密异常']);
}
// 存入队列处理
$queueService = new QueueService();
$queueService->push('callback_queue', json_encode(['header'=>$headers,'res'=>$res],320));
// 返回成功的 JSON 响应
return json(['code' => '00', 'message' => '请求成功']);
}
/** 分油下单回到
* @return string
*/
public function notify()
{
// 获取所有 HTTP 请求头
$headers = Request::header();
// 获取 GET 参数
$data = Request::param();
$this->saveLog('callback_queue回调参数原文;header:'.json_encode($headers).',body:'.json_encode($data));
/*$appKey = $headers['appKey'] ?? $headers['appkey'];
$company = CompanyModel::detail(['appKey' => $appKey]);
$crypto = new Crypto($company);
$res = $crypto->processResponse(['header'=>$headers,'encryptData'=>$data]);
// 记录日志等
$this->saveLog('callback_queue回调参数解密,'.$headers['method'].":".json_encode($res,320));
// 检查 JSON 解码是否成功
if (!$res) {
return json(['code' => '03', 'message' => '报文解密异常']);
}*/
$headers['method'] = 'oil';
// 存入队列处理
$queueService = new QueueService();
$queueService->push('callback_queue', json_encode(['header'=>$headers,'res'=>$data],320));
// 返回成功的 JSON 响应
return 'OK';
}
/** 使用结果回调
* @return string
*/
public function use()
{
// 获取所有 HTTP 请求头
$headers = Request::header();
// 获取 GET 参数
$data = Request::param();
$this->saveLog('callback_queue回调参数原文;header:'.json_encode($headers).',body:'.json_encode($data));
/*$appKey = $headers['appKey'] ?? $headers['appkey'];
$company = CompanyModel::detail(['appKey' => $appKey]);
$crypto = new Crypto($company);
$res = $crypto->processResponse(['header'=>$headers,'encryptData'=>$data]);
// 记录日志等
$this->saveLog('callback_queue回调参数解密,'.$headers['method'].":".json_encode($res,320));
// 检查 JSON 解码是否成功
if (!$res) {
return json(['code' => '03', 'message' => '报文解密异常']);
}*/
$headers['method'] = 'use';
// 存入队列处理
$queueService = new QueueService();
$queueService->push('callback_queue', json_encode(['header'=>$headers,'res'=>$data],320));
// 返回成功的 JSON 响应
return 'OK';
}
/** 分油下单回到
* @return string
*/
public function partnersNotify()
{
// 获取所有 HTTP 请求头
$headers = Request::header();
// 获取 GET 参数
$data = Request::param();
$this->saveLog('callback_queue回调参数原文;header:'.json_encode($headers).',body:'.json_encode($data));
$headers['method'] = 'oil_partners';
// 存入队列处理
$queueService = new QueueService();
$queueService->push('callback_queue', json_encode(['header'=>$headers,'res'=>$data],320));
// 返回成功的 JSON 响应
return 'OK';
}
/** 使用结果回调
* @return string
*/
public function partnersUse()
{
// 获取所有 HTTP 请求头
$headers = Request::header();
// 获取 GET 参数
$data = Request::param();
$this->saveLog('callback_queue回调参数原文;header:'.json_encode($headers).',body:'.json_encode($data));
$headers['method'] = 'use_partners';
// 存入队列处理
$queueService = new QueueService();
$queueService->push('callback_queue', json_encode(['header'=>$headers,'res'=>$data],320));
// 返回成功的 JSON 响应
return 'OK';
}
}
+77
View File
@@ -0,0 +1,77 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use app\api\model\Setting as SettingModel;
use app\api\model\UploadFile as UploadFileModel;
use app\api\service\User as UserService;
use app\common\enum\Setting as SettingEnum;
use app\common\enum\file\FileType as FileTypeEnum;
use app\common\library\storage\Driver as StorageDriver;
use cores\exception\BaseException;
/**
* 文件库管理
* Class Upload
* @package app\api\controller
*/
class Upload extends Controller
{
// 当前商城的上传设置
private $config;
/**
* 构造方法
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function initialize()
{
parent::initialize();
// 验证登录
UserService::isLogin(true);
// 存储配置信息
$this->config = SettingModel::getItem(SettingEnum::STORAGE);
}
/**
* 图片上传接口
* @return array|\think\response\Json
* @throws BaseException
* @throws \think\Exception
*/
public function image()
{
// 当前用户ID
$userId = UserService::getCurrentLoginUserId();
// 实例化存储驱动
$storage = new StorageDriver($this->config);
// 设置上传文件的信息
$storage->setUploadFile('file')
->setRootDirName((string)$this->storeId)
->setValidationScene('image');
// 执行文件上传
if (!$storage->upload()) {
return $this->renderError('图片上传失败:' . $storage->getError());
}
// 文件信息
$fileInfo = $storage->getSaveFileInfo();
// 添加文件库记录
$model = new UploadFileModel;
$model->add($fileInfo, FileTypeEnum::IMAGE, $userId);
// 图片上传成功
return $this->renderSuccess(['fileInfo' => $model->toArray()], '图片上传成功');
}
}
+92
View File
@@ -0,0 +1,92 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller;
use think\response\Json;
use app\api\model\User as UserModel;
use app\api\model\UserCoupon as UserCouponModel;
use app\api\service\User as UserService;
use cores\exception\BaseException;
/**
* 用户管理
* Class User
* @package app\api
*/
class User extends Controller
{
/**
* 当前用户详情
* @return Json
* @throws BaseException
*/
public function info(): Json
{
// 当前用户信息
$userInfo = UserService::getCurrentLoginUser(true);
// 获取用户头像
$userInfo['avatar'];
// 获取会员等级
$userInfo['grade'];
return $this->renderSuccess(compact('userInfo'));
}
/**
* 账户资产
* @return Json
* @throws BaseException
*/
public function assets(): Json
{
// 当前用户信息
$userInfo = UserService::getCurrentLoginUser(true);
// 用户优惠券模型
$model = new UserCouponModel;
// 返回数据
return $this->renderSuccess([
'assets' => [
'balance' => $userInfo['balance'], // 账户余额
'points' => $userInfo['points'], // 会员积分
'coupon' => $model->getCount($userInfo['user_id']), // 优惠券数量(可用)
]
]);
}
/**
* 手机号绑定
* @return Json
* @throws \cores\exception\BaseException
*/
public function bindMobile(): Json
{
$model = new UserModel;
if (!$model->bindMobile($this->postForm())) {
return $this->renderSuccess($model->getError() ?: '操作失败');
}
return $this->renderSuccess('恭喜您,手机号绑定成功');
}
/**
* 修改个人信息(头像昵称)
* @return Json
* @throws \cores\exception\BaseException
*/
public function personal(): Json
{
$model = new UserModel;
if (!$model->personal($this->postForm())) {
return $this->renderSuccess($model->getError() ?: '操作失败');
}
return $this->renderSuccess('恭喜您,信息修改成功');
}
}
@@ -0,0 +1,39 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller\article;
use app\api\controller\Controller;
use app\api\model\article\Category as CategoryModel;
/**
* 文章分类
* Class Category
* @package app\api\controller\article
*/
class Category extends Controller
{
/**
* 文章分类列表
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function list()
{
$model = new CategoryModel;
$list = $model->getShowList();
return $this->renderSuccess(compact('list'));
}
}
@@ -0,0 +1,38 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller\balance;
use think\response\Json;
use app\api\controller\Controller;
use app\api\model\user\BalanceLog as BalanceLogModel;
/**
* 余额账单明细
* Class Log
* @package app\api\controller\balance
*/
class Log extends Controller
{
/**
* 余额账单明细列表
* @return Json
* @throws \cores\exception\BaseException
* @throws \think\db\exception\DbException
*/
public function list(): Json
{
$model = new BalanceLogModel;
$list = $model->getList();
return $this->renderSuccess(compact('list'));
}
}
@@ -0,0 +1,38 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller\card;
use think\response\Json;
use app\api\controller\Controller;
use app\api\model\card\CardLog as CardLogModel;
/**
* 兑换明细
* Class Log
* @package app\api\controller\card
*/
class Log extends Controller
{
/**
* 余额账单明细列表
* @return Json
* @throws \cores\exception\BaseException
* @throws \think\db\exception\DbException
*/
public function list(): Json
{
$model = new CardLogModel;
$list = $model->getList();
return $this->renderSuccess(compact('list'));
}
}
@@ -0,0 +1,40 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller\goods;
use app\api\controller\Controller;
use app\api\model\goods\Service as ServiceModel;
/**
* 商品服务与承诺管理
* Class Service
* @package app\store\controller\goods
*/
class Service extends Controller
{
/**
* 获取指定商品的服务与承诺
* @param int $goodsId
* @return array|\think\response\Json
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function list(int $goodsId)
{
$model = new ServiceModel;
$list = $model->getListByGoods($goodsId);
return $this->renderSuccess(compact('list'));
}
}
@@ -0,0 +1,83 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller\order;
use app\api\controller\Controller;
use app\api\model\Order as OrderModel;
use app\api\model\Comment as CommentModel;
use app\api\model\OrderGoods as OrderGoodsModel;
/**
* 订单评价管理
* Class Comment
* @package app\api\controller\order
*/
class Comment extends Controller
{
/**
* 待评价订单商品列表
* @param int $orderId
* @return array
* @throws \Exception
* @throws \cores\exception\BaseException
* @throws \think\exception\DbException
*/
public function list(int $orderId)
{
// 订单信息
$orderInfo = OrderModel::getDetail($orderId);
// 验证订单是否已完成
$model = new CommentModel;
if (!$model->checkOrderAllowComment($orderInfo)) {
return $this->renderError($model->getError());
}
// 待评价商品列表
$goodsList = OrderGoodsModel::getNotCommentGoodsList($orderId);
if ($goodsList->isEmpty()) {
return $this->renderError('该订单没有可评价的商品');
}
return $this->renderSuccess(compact('goodsList'));
}
/**
* 创建商品评价
* @param int $orderId
* @return array|\think\response\Json
* @throws \cores\exception\BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function submit(int $orderId)
{
// 订单信息
$orderInfo = OrderModel::getDetail($orderId);
// 验证订单是否已完成
$model = new CommentModel;
if (!$model->checkOrderAllowComment($orderInfo)) {
return $this->renderError($model->getError());
}
// 待评价商品列表
$goodsList = OrderGoodsModel::getNotCommentGoodsList($orderId);
if ($goodsList->isEmpty()) {
return $this->renderError('该订单没有可评价的商品');
}
// 提交商品评价
$model = new CommentModel;
if ($model->increased($orderInfo, $goodsList, $this->postForm())) {
return $this->renderSuccess([], '评价发表成功');
}
return $this->renderError($model->getError() ?: '评价发表失败');
}
}
@@ -0,0 +1,37 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller\points;
use app\api\controller\Controller;
use app\api\model\user\PointsLog as PointsLogModel;
/**
* 积分明细
* Class Log
* @package app\api\controller\balance
*/
class Log extends Controller
{
/**
* 积分明细列表
* @return array
* @throws \cores\exception\BaseException
* @throws \think\db\exception\DbException
*/
public function list()
{
$model = new PointsLogModel;
$list = $model->getList();
return $this->renderSuccess(compact('list'));
}
}
@@ -0,0 +1,39 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller\recharge;
use app\api\controller\Controller;
use app\api\model\recharge\Order as OrderModel;
use cores\exception\BaseException;
/**
* 充值记录管理
* Class Order
* @package app\api\controller\recharge
*/
class Order extends Controller
{
/**
* 我的充值记录列表
* @return array
* @throws BaseException
* @throws \think\db\exception\DbException
*/
public function list()
{
$model = new OrderModel;
$list = $model->getList();
return $this->renderSuccess(compact('list'));
}
}
@@ -0,0 +1,36 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller\recharge;
use app\api\controller\Controller;
use app\api\model\recharge\Plan as PlanModel;
/**
* 充值套餐管理
* Class Plan
* @package app\api\controller\recharge
*/
class Plan extends Controller
{
/**
* 充值套餐列表
* @return array
* @throws \think\db\exception\DbException
*/
public function list()
{
$model = new PlanModel;
$list = $model->getList();
return $this->renderSuccess(compact('list'));
}
}
@@ -0,0 +1,66 @@
<?php
// +----------------------------------------------------------------------
// | 管理系统
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.zizai.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 自在科技
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller\syb;
use app\api\controller\Controller;
/**
* 加油e卡通基础数据
* Class SybBase
* @package app\api\controller
*/
class SybBase extends Controller
{
/** 油站查询
* @param $data
* @return array|mixed|string[]
*/
public function baseGasStationList($data)
{
$header = [
'method' => 'syb.base.gasStation.list',
];
$body = [
'province' => $data['province']??'',
'city' => $data['city']??'',
'longitude' => $data['longitude']??'',
'latitude' => $data['latitude']??'',
'pageLimit' => $data['pageLimit']??'',
'pageNum' => $data['pageNum']??'',
];
$response = $this->sendRequest(config('crypto.url').'/api/1.0.0/base/gasStationList', $body, $header);
$this->saveLog("油站查询".json_encode($response,320));
return $response;
}
/** 文件上传接口
* @param $data
* @return array|mixed|string[]
*/
public function baseFileUpload($data)
{
$header = [
'method' => 'syb.base.file.upload',
];
$body = [
'orgNo' => config('crypto.company_no'),
'file' => request()->file('file'),
];
$response = $this->sendRequest(config('crypto.url').'/api/1.0.0/base/uploadFile', $body, $header);
$this->saveLog("文件上传接口".json_encode($response,320));
return $response;
}
}
@@ -0,0 +1,98 @@
<?php
// +----------------------------------------------------------------------
// | 管理系统
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.zizai.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 自在科技
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller\syb;
use app\api\controller\Controller;
use app\api\model\Order as OrderModel;
use app\api\model\Order\Record as RecordModel;
use app\common\crypto\Crypto;
use think\facade\Request;
/**
* 加油e卡通通知接口
* Class SybUser
* @package app\api\controller
*/
class SybNotify extends Controller
{
/** 通知接口
* @return array|mixed|string[]
*/
public function notify()
{
// 获取所有 HTTP 请求头
$headers = Request::header();
// 获取 JSON 格式的请求体
$jsonData = Request::instance()->getContent();
$data = json_decode($jsonData, true);
$crypto = new Crypto();
$res = $crypto->processResponse(['header'=>$headers,'encryptData'=>$data]);
// 检查 JSON 解码是否成功
if (!$res) {
return json(['code' => '03', 'message' => '报文解密异常']);
}
// 此处可以根据业务逻辑处理接收到的数据
switch ($headers['method']) {
case "syb.notify.pay.result":
// 二维码交易结果通知
$where = array(
['oilCardNo', '=', $res['oilCardNo']],
['amount', '=', $res['amount']],
);
$field['qrCode'] = $res['qrCode'];
if($res['status'] == 'success'){
$field['order_status'] = 30;
$field['use_status'] = 1;
}else{
$field['use_text'] = $res['errMessage'];
}
OrderModel::orderUpdate($where, $field);
break;
case "syb.notify.oilCard.change":
// 油卡变动通知
$order = OrderModel::detail(['oilCardNo'=>$res['oilCardNo'], 'amount'=>$res['amount']]);
$res['order_id'] = $order['order_id'];
$res['user_id'] = $order['user_id'];
$RecordModel = new RecordModel();
$RecordModel->add($res);
break;
case "syb.notify.oilCard.share":
// 分油结果通知
$where = array(
['oilCardNo', '=', $res['oilCardNo']],
['amount', '=', $res['amount']],
);
$field = ['oil_time' => time()];
if($res['status'] == 'success'){
$field['order_status'] = 20;
$field['oil_status'] = 1;
}else{
$field['order_status'] = 60;
$field['oil_status'] = 0;
$field['oil_text'] = $res['msg'];
}
OrderModel::orderUpdate($where, $field);
break;
default:
return json(['code' => '03', 'message' => '报文解密异常']);
}
// 记录日志等
$this->saveLog($headers['method'].":".json_encode($res,320));
// 返回成功的 JSON 响应
return json(['code' => '00', 'message' => '请求成功']);
}
}
@@ -0,0 +1,122 @@
<?php
// +----------------------------------------------------------------------
// | 管理系统
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.zizai.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 自在科技
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller\syb;
use app\api\controller\Controller;
/**
* 加油e卡通油卡操作
* Class SybOil
* @package app\api\controller
*/
class SybOil extends Controller
{
/** 油卡查询
* @param $data
* @return array|mixed|string[]
*/
public function oilOilCardSelect($data)
{
$header = [
'method' => 'syb.oil.oilCard.select',
];
$body = [
'orgNo' => config('crypto.company_no'),
'mobile' => $data['mobile']??'',
'userNo' => $data['userNo']??'',
'oilCardNo' => $data['oilCardNo']??'',
'pageLimit' => $data['pageLimit']??'10',
'pageNum' => $data['pageNum']??'1',
'oilCardType' => $data['oilCardType']??'card', //不填时默认为“E卡通平台自营卡”
];
$response = $this->sendRequest(config('crypto.url').'/api/1.0.0/oil/oilCard/select', $body, $header);
$this->saveLog("油卡查询".json_encode($response,320));
return $response;
}
/** 用户分油
* @param $data
* @return array|mixed|string[]
*/
public function oilOilCardShare($data)
{
$header = [
'method' => 'syb.oil.oilCard.share',
];
$body = [
'orgNo' => config('crypto.company_no'),
'goodsNo' => $data['goodsNo']??'',
'amount' => $data['oilCardType']=='card' ? round($data['amount'],2) : '',
'userNo' => $data['userNo']??'',
'mobile' => $data['mobile']??'',
'saleOrderNo' => $data['saleOrderNo']??'',
'oilCardType' => $data['oilCardType']??'',
];
$response = $this->sendRequest(config('crypto.url').'/api/1.0.0/oil/oilCard/share', $body, $header);
$this->saveLog("用户分油".json_encode($response,320));
return $response;
}
/** 分油撤销接口
* @param $data
* @return array|mixed|string[]
*/
public function oilOilCardCancelShare($data)
{
$header = [
'method' => 'syb.oil.oilCard.cancelShare',
];
$body = [
'orgNo' => config('crypto.company_no'),
'shareNo' => $data['shareNo']??'',
'amount' => !empty($data['amount']??'') ? round($data['amount'],2) : '',
'saleOrderNo' => $data['saleOrderNo']??'',
'type' => $data['type']??'',
'oilCardType' => $data['oilCardType']??'',
];
$response = $this->sendRequest(config('crypto.url').'/api/1.0.0/oil/oilCard/cancelShare', $body, $header);
$this->saveLog("分油撤销接口".json_encode($response,320));
return $response;
}
/** 用户分油记录查询
* @param $data
* @return array|mixed|string[]
*/
public function oilOilCardShareList($data)
{
$header = [
'method' => 'syb.oil.oilCard.shareList',
];
$body = [
'orgNo' => config('crypto.company_no'),
'userNo' => $data['userNo']??'',
'mobile' => $data['mobile']??'',
'shareNo' => $data['shareNo']??'',
'saleOrderNo' => $data['saleOrderNo']??'',
'beginDate' => $data['beginDate']??'',
'endDate' => $data['endDate']??'',
'pageLimit' => $data['pageLimit']??'',
'pageNum' => $data['pageNum']??'',
];
$response = $this->sendRequest(config('crypto.url').'/api/1.0.0/opt/oilCard/shareList', $body, $header);
$this->saveLog("用户分油记录查询".json_encode($response,320));
return $response;
}
}
@@ -0,0 +1,48 @@
<?php
// +----------------------------------------------------------------------
// | 管理系统
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.zizai.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 自在科技
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller\syb;
use app\api\controller\Controller;
/**
* 加油e卡通加油记录查询
* Class SybOrder
* @package app\api\controller
*/
class SybOrder extends Controller
{
/** 加油记录查询
* @param $data
* @return array|mixed|string[]
*/
public function orderListSale($data)
{
$header = [
'method' => 'syb.order.list.sale',
];
$body = [
'orgNo' => config('crypto.company_no'),
'mobile' => $data['mobile']??'',
'shareNo' => $data['shareNo']??'',
'beginDate' => $data['beginDate']??'',
'endDate' => $data['endDate']??'',
'pageLimit' => $data['pageLimit']??'',
'pageNum' => $data['pageNum']??'',
];
$response = $this->sendRequest(config('crypto.url').'/api/1.0.0/opt/list/sale', $body, $header);
$this->saveLog("加油记录查询".json_encode($response,320));
return $response;
}
}
@@ -0,0 +1,154 @@
<?php
// +----------------------------------------------------------------------
// | 管理系统
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.zizai.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 自在科技
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller\syb;
use app\api\controller\Controller;
/**
* 加油e卡通支付财务
* Class SybOil
* @package app\api\controller
*/
class SybPay extends Controller
{
/** 付款二维码申请
* @param $data
* @return array|mixed|string[]
*/
public function payQrCodeRequest($data)
{
$header = [
'method' => 'syb.pay.qrCode.request',
];
$body = [
'orgNo' => config('crypto.company_no'),
'oilCardNo' => $data['oilCardNo']??'',
'mobile' => $data['mobile']??'',
'longitude' => $data['longitude']??'',
'oilCardType' => $data['oilCardType']??'',
'latitude' => $data['latitude']??'',
];
$response = $this->sendRequest(config('crypto.url').'/api/1.0.0/pay/getPayQrCode', $body, $header);
$this->saveLog("付款二维码申请".json_encode($response,320));
return $response;
}
/** 主扫订单创建
* @param $data
* @return array|mixed|string[]
*/
public function payActiveScan($data)
{
$header = [
'method' => 'syb.pay.active.scan',
];
$body = [
'orgNo' => config('crypto.company_no'),
'oilCardNo' => $data['oilCardNo']??'',
'qrInfo' => $data['qrInfo']??'',
'longitude' => $data['longitude']??'',
'latitude' => $data['latitude']??'',
];
$response = $this->sendRequest(config('crypto.url').'/api/1.0.0/pay/activeScan', $body, $header);
$this->saveLog("主扫订单创建".json_encode($response,320));
return $response;
}
/** 主扫订单信息确认
* @param $data
* @return array|mixed|string[]
*/
public function payActiveVerify($data)
{
$header = [
'method' => 'syb.pay.active.verify',
];
$body = [
'orgNo' => config('crypto.company_no'),
'activeOrderId' => $data['activeOrderId']??'',
'amount' => !empty($data['amount']??'') ? round($data['amount'],2) : '',
'deviceId' => $data['deviceId']??'',
];
$response = $this->sendRequest(config('crypto.url').'/api/1.0.0/pay/activeVerify', $body, $header);
$this->saveLog("主扫订单信息确认".json_encode($response,320));
return $response;
}
/** 账户余额查询
* @param $data
* @return array|mixed|string[]
*/
public function payAmountBalance($data)
{
$header = [
'method' => 'syb.pay.account.balance',
];
$body = [
'orgNo' => config('crypto.company_no'),
];
$response = $this->sendRequest(config('crypto.url').'/api/1.0.0/finance/account/balance', $body, $header);
$this->saveLog("账户余额查询".json_encode($response,320));
return $response;
}
/** 申请发票
* @param $data
* @return array|mixed|string[]
*/
public function payInvoiceRequest($data)
{
$header = [
'method' => 'syb.pay.invoice.request',
];
$body = [
'orgNo' => config('crypto.company_no'),
'amount' => !empty($data['amount']??'') ? round($data['amount'],2) : '',
'oilNo' => $data['oilNo']??'',
'invoiceAddress' => $data['invoiceAddress']??'',
'invoiceHeader' => $data['invoiceHeader']??'',
'invoicePhone' => $data['invoicePhone']??'',
'invoiceOpenBank' => $data['invoiceOpenBank']??'',
'taxIdentifyNo' => $data['taxIdentifyNo']??'',
'invoiceCardNo' => $data['invoiceCardNo']??'',
];
$response = $this->sendRequest(config('crypto.url').'/api/1.0.0/finance/invoice/request', $body, $header);
$this->saveLog("申请发票".json_encode($response,320));
return $response;
}
/** 开票状态查询
* @param $data
* @return array|mixed|string[]
*/
public function payInvoiceStatus($data)
{
$header = [
'method' => 'syb.pay.invoice.status',
];
$body = [
'orgNo' => config('crypto.company_no'),
'invoiceNo' => $data['invoiceNo']??'',
];
$response = $this->sendRequest(config('crypto.url').'/api/1.0.0/finance/invoice/status', $body, $header);
$this->saveLog("开票状态查询".json_encode($response,320));
return $response;
}
}
@@ -0,0 +1,46 @@
<?php
// +----------------------------------------------------------------------
// | 管理系统
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.zizai.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 自在科技
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller\syb;
use app\api\controller\Controller;
/**
* 加油e卡通用户账户
* Class SybUser
* @package app\api\controller
*/
class SybUser extends Controller
{
/** 添加用户
* @param $data
* @return array|mixed|string[]
*/
public function userOptAdd($data)
{
$header = [
'method' => 'syb.user.opt.add',
];
$body = [
'orgNo' => config('crypto.company_no'),
'mobile' => $data['mobile']??'',
'userName' => $data['userName']??'',
'userIdCard' => $data['userIdCard']??'',
'userType' => $data['userType']??'user',
];
$response = $this->sendRequest(config('crypto.url').'/api/1.0.0/user/opt/add', $body, $header);
$this->saveLog("添加用户".json_encode($response,320));
return $response;
}
}
@@ -0,0 +1,92 @@
<?php
// +----------------------------------------------------------------------
// | 管理系统
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.zizai.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 自在科技
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\controller\syb;
use app\api\controller\Controller;
/**
* 优惠券
* Class SybVoucher
* @package app\api\controller
*/
class SybVoucher extends Controller
{
/** 优惠券下单
* @param $data
* @return array|mixed|string[]
*/
public function voucherCreateOrder($data)
{
$header = [
'method' => 'syb.opt.voucher.createOrder',
];
$body = [
'orgNo' => config('crypto.company_no'),
'model' => $data['model']??'',
'voucherAmount' => $data['voucherAmount']??'',
'fullAmount' => $data['fullAmount']??'',
'storeNum' => $data['storeNum']??'',
'validTime' => $data['validTime']??'',
];
$response = $this->sendRequest(config('crypto.url').'/api/1.0.0/voucher/createOrder', $body, $header);
$this->saveLog("优惠券下单".json_encode($response,320));
return $response;
}
/** 优惠券订单查询
* @param $data
* @return array|mixed|string[]
*/
public function voucherOrderListPage($data)
{
$header = [
'method' => 'syb.opt.voucher.order.listPage',
];
$body = [
'orgNo' => config('crypto.company_no'),
'orderNo' => $data['orderNo']??'',
'model' => $data['model']??'',
'pageLimit' => $data['pageLimit']??'',
'pageNum' => $data['pageNum']??'',
];
$response = $this->sendRequest(config('crypto.url').'/api/1.0.0/voucher/order/listPage', $body, $header);
$this->saveLog("优惠券订单查询".json_encode($response,320));
return $response;
}
/** 卡券查询
* @param $data
* @return array|mixed|string[]
*/
public function voucherItemListPage($data)
{
$header = [
'method' => 'syb.opt.voucher.item.listPage',
];
$body = [
'orgNo' => config('crypto.company_no'),
'orderNo' => $data['orderNo']??'',
'model' => $data['model']??'',
'pageLimit' => $data['pageLimit']??'',
'pageNum' => $data['pageNum']??'',
];
$response = $this->sendRequest(config('crypto.url').'/api/1.0.0/voucher/item/listPage', $body, $header);
$this->saveLog("卡券查询".json_encode($response,320));
return $response;
}
}
+20
View File
@@ -0,0 +1,20 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
// 应用行为扩展定义文件
return [
'listen' => [
'OrderPaySuccess' => [
\app\api\listener\order\PaySuccess::class
]
]
];
@@ -0,0 +1,101 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\listener\order;
use app\common\service\Message as MessageService;
use app\common\enum\OrderType as OrderTypeEnum;
use app\common\enum\order\OrderSource as OrderSourceEnum;
/**
* 订单支付成功后扩展类
* Class PaySuccess
* @package app\api\behavior\order
*/
class PaySuccess
{
// 订单信息
private $order;
// 订单类型
private $orderType;
// 当前商城ID
private $storeId;
/**
* 订单来源回调业务映射类
* @var array
*/
protected $sourceCallbackClass = [
OrderSourceEnum::MAIN => \app\api\service\main\order\PaySuccess::class,
];
/**
* 执行句柄
* @param array $params
* @return bool
*/
public function handle(array $params)
{
// 解构赋值: 订单模型、订单类型
['order' => $order, 'orderType' => $orderType] = $params;
// 设置当前类的属性
$this->setAttribute($order, $orderType);
// 订单公共事件
$this->onCommonEvent();
// 订单来源回调业务
$this->onSourceCallback();
return true;
}
/**
* 设置当前类的属性
* @param $order
* @param int $orderType
*/
private function setAttribute($order, $orderType = OrderTypeEnum::ORDER)
{
$this->order = $order;
$this->storeId = $this->order['store_id'];
$this->orderType = $orderType;
}
/**
* 订单公共业务
*/
private function onCommonEvent()
{
// 发送消息通知
MessageService::send('order.payment', [
'order' => $this->order,
'order_type' => $this->orderType,
], $this->storeId);
}
/**
* 订单来源回调业务
* @return bool
*/
private function onSourceCallback()
{
if (!isset($this->order['order_source'])) {
return false;
}
if (!isset($this->sourceCallbackClass[$this->order['order_source']])) {
return false;
}
$class = $this->sourceCallbackClass[$this->order['order_source']];
return !is_null($class) ? (new $class)->onPaySuccess($this->order) : false;
}
}
+97
View File
@@ -0,0 +1,97 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use cores\exception\BaseException;
use app\common\model\Article as ArticleModel;
/**
* 商品评价模型
* Class Article
* @package app\api\model
*/
class Article extends ArticleModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'is_delete',
'store_id',
'create_time',
'update_time'
];
/**
* 获取器:文章详情HTML实体转换回普通字符
* @param $value
* @return string
*/
public function getArticleContentAttr($value)
{
return htmlspecialchars_decode($value);
}
/**
* 获取文章详情并累计阅读次数
* @param int $articleId 文章ID
* @return static|null
* @throws BaseException
*/
public static function getDetail(int $articleId)
{
// 获取文章详情
$detail = parent::detail($articleId, ['image']);
if (empty($detail) || $detail['is_delete']) {
throwError('很抱歉,当前文章不存在');
}
// 累积文章实际阅读数
static::setIncActualViews($articleId);
return $detail;
}
/**
* 累积文章实际阅读数
* @param int $articleId 文章ID
* @param int $num 递增的数量
* @return mixed
*/
private static function setIncActualViews(int $articleId, int $num = 1)
{
return (new static)->setInc($articleId, 'actual_views', $num);
}
/**
* 获取文章列表
* @param int $categoryId
* @param int $limit
* @return \think\Paginator
* @throws \think\db\exception\DbException
*/
public function getList(int $categoryId = 0, int $limit = 15)
{
// 检索查询条件
$filter = [];
$categoryId > 0 && $filter[] = ['category_id', '=', $categoryId];
// 获取列表数据
return $this->withoutField(['content'])
->with(['image', 'category'])
->where($filter)
->where('status', '=', 1)
->where('is_delete', '=', 0)
->order(['sort' => 'asc', 'create_time' => 'desc'])
->paginate($limit);
}
}
+33
View File
@@ -0,0 +1,33 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\Card as CardModel;
/**
* 兑换卡模型
* Class Card
* @package app\api\model
*/
class Card extends CardModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'update_time'
];
}
+167
View File
@@ -0,0 +1,167 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\api\model\Goods as GoodsModel;
use app\api\model\GoodsSku as GoodsSkuModel;
use app\api\service\User as UserService;
use app\common\model\Cart as CartModel;
use app\common\enum\goods\Status as GoodsStatusEnum;
use app\common\exception\BaseException;
/**
* 购物车管理
* Class Cart
* @package app\api\model
*/
class Cart extends CartModel
{
/**
* 加入购物车
* @param int $goodsId 商品ID
* @param string $goodsSkuId 商品sku唯一标识
* @param int $goodsNum 商品数量
* @return bool
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function add(int $goodsId, string $goodsSkuId, int $goodsNum)
{
// 判断是否已存在购物车记录
$detail = $this->getInfo($goodsId, $goodsSkuId, false);
// 如果已存在购物车记录, 则累计商品数量
// !empty($detail) && $goodsNum += $detail['goods_num'];
$goodsNum = 1;
// 验证商品的状态
$this->checkGoodsStatus($goodsId, $goodsSkuId, $goodsNum);
// 获取当前用户ID
$userId = UserService::getCurrentLoginUserId();
// 实例化模型
$model = $detail ?: (new static);
return $model->save([
'goods_id' => $goodsId,
'goods_sku_id' => $goodsSkuId,
'goods_num' => $goodsNum,
'user_id' => $userId,
'store_id' => self::$storeId,
]);
}
/**
* 更新购物车记录
* @param int $goodsId 商品ID
* @param string $goodsSkuId 商品sku唯一标识
* @param int $goodsNum 商品数量
* @return bool
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function sUpdate(int $goodsId, string $goodsSkuId, int $goodsNum)
{
// 验证商品的状态
$this->checkGoodsStatus($goodsId, $goodsSkuId, $goodsNum);
// 获取购物车记录
$model = $this->getInfo($goodsId, $goodsSkuId, true);
// 更新记录
return $model->save(['goods_num' => $goodsNum]);
}
/**
* 验证商品的状态
* @param int $goodsId 商品ID
* @param string $goodsSkuId 商品sku唯一标识
* @param int $goodsNum 商品数量
* @return bool
* @throws BaseException
*/
private function checkGoodsStatus(int $goodsId, string $goodsSkuId, int $goodsNum)
{
// 获取商品详情
$goods = GoodsModel::detail($goodsId);
// 商品不存在
if (empty($goods) || $goods['is_delete']) {
throwError('很抱歉, 商品信息不存在');
}
// 商品已下架
if ($goods['status'] == GoodsStatusEnum::OFF_SALE) {
throwError('很抱歉, 该商品已经下架');
}
// 获取SKU信息
$skuInfo = GoodsSkuModel::detail($goodsId, $goodsSkuId);
if ($skuInfo['stock_num'] < $goodsNum) {
throwError('很抱歉, 该商品库存数量不足');
}
return true;
}
/**
* 获取购物车记录
* @param int $goodsId 商品ID
* @param string $goodsSkuId 商品sku唯一标识
* @param bool $isForce
* @return static|bool
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function getInfo(int $goodsId, string $goodsSkuId, bool $isForce = true)
{
// 获取当前用户ID
$userId = UserService::getCurrentLoginUserId();
// 获取购物车记录
$model = static::detail($userId, $goodsId, $goodsSkuId);
if (empty($model)) {
$isForce && throwError('购物车中没有该记录');
return false;
}
return $model;
}
/**
* 删除购物车中指定记录
* @param array $cartIds 购物车ID集, 如果为空删除所有
* @return bool
* @throws BaseException
*/
public function clear(array $cartIds = [])
{
// 获取当前用户ID
$userId = UserService::getCurrentLoginUserId();
// 设置更新条件
$where = [['user_id', '=', $userId]];
// 购物车ID集
!empty($cartIds) && $where[] = ['id', 'in', $cartIds];
// 更新记录
return $this->updateBase(['is_delete' => 1], $where);
}
/**
* 获取当前用户购物车商品总数量
* @return float
* @throws BaseException
*/
public function getCartTotal()
{
if (!UserService::isLogin()) return 0;
$userId = UserService::getCurrentLoginUserId();
return $this->where('user_id', '=', $userId)
->where('is_delete', '=', 0)
->sum('goods_num');
}
}
+46
View File
@@ -0,0 +1,46 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\Category as CategoryModel;
/**
* 商品分类模型
* Class Category
* @package app\common\model
*/
class Category extends CategoryModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'create_time',
'update_time'
];
/**
* 获取列表记录
* @param array $param
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getListPublic(array $param = []): array
{
return parent::getList(array_merge($param, ['status' => 1]));
}
}
+489
View File
@@ -0,0 +1,489 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\Code as CodeModel;
use app\api\model\Order as OrderModel;
use app\common\library\helper;
use cores\exception\BaseException;
use think\facade\Cache;
use think\Request;
/**
* 订单模型
* Class Order
* @package app\api\model
*/
class Code extends CodeModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'update_time'
];
// 信息提示
private $message = '';
/**
* 等待支付产码列表
* @param $zone
* @return array
* @throws \think\exception\DbException
*/
public function getList($zone=1)
{
// 获取数据列表->where(" code_id in (select code_id from yoshop_order where order_status = 10) ")
return $this->where('status', '=', 2)
->where('order_id', '=', 0)
->where('zone', '=', $zone)
->order(['allot_time' => 'asc'])
->select()
->toArray();
}
/**
* 等待支付产码列表
* @param $page
* @return array
* @throws \think\exception\DbException
*/
/*public function getList($page=1)
{
// 获取数据列表
return $this->where('status', '=', 2)
->where('order_id', '=', 0)
->where(" code_id in (select code_id from yoshop_order where order_status = 10) ")
->order(['allot_time' => 'asc'])
->page($page, 20)
->select()
->toArray();
}*/
/**
* 等待支付产码列表倒序
* @param $page
* @return array
* @throws \think\exception\DbException
*/
public function getListDesc($page=1)
{
// 获取数据列表
return $this->where('status', '=', 2)
->where('order_id', '=', 0)
->where(" code_id in (select code_id from yoshop_order where order_status = 10) ")
->order(['allot_time' => 'desc'])
->page($page, 20)
->select()
->toArray();
}
/**
* 获取非失效码
* @return \think\Paginator
* @throws \think\exception\DbException
*/
public function getNonFailure()
{
// 获取数据列表
return $this->where('status != 3 ')
->where('order_id', '=', 0)
->where(" (((allot_time+360) < unix_timestamp(NOW()) and allot_time > 0) or (create_time+expiration_time+60) < unix_timestamp(NOW())) ")
->order(['allot_time' => 'asc'])
->paginate(1000);
}
/**
* 支付码
* @param $money
* @param $passageway
* @return null|static
* @throws \app\common\exception\BaseException
* @throws \think\exception\DbException
*/
public function getCodeDetailOld($money,$passageway)
{
//连接本地的 Redis 服务
// 字符串操作
$conn = new \think\cache\driver\Redis(config('cache.stores.redis'));
$codesIp = $conn->get('codesIp');
$codesPort = $conn->get('codesPort');
$codeNum = $conn->get('codeNum');
if(empty($codesIp) || empty($codeNum) || $codeNum <= 0){
//获取IP组
$iPGroup = $this->getIPGroup();
$codesIp = isset($iPGroup[0]['ip'])?$iPGroup[0]['ip']:'';
$codesPort = isset($iPGroup[0]['port'])?$iPGroup[0]['port']:'';
$codeNum = 20;
$conn->set('codesIp',$codesIp);
$conn->set('codesPort',$codesPort);
}
$filter = [];
$codeM = new CodeModel();
$zone = 0; //分区
//支付码未过期,并且过期剩余时间超过5分钟,并且退回码池超过2分钟
$where = " (create_time+expiration_time) > unix_timestamp(NOW()) and (create_time+expiration_time) - unix_timestamp(NOW()) > 300 and (back_time+120) < unix_timestamp(NOW()) ";
$filter[] = ['passageway', '=', $passageway]; //通道
$filter[] = ['status', '=', 1]; //未使用状态
$filter[] = ['state', '=', 1]; //启用状态
$filter[] = ['money', '=', $money]; //金额
$code = [];
//尝试三次
for ($i=0;$i<3;$i++) {
//随机起点
$offset = $this->field([
'FLOOR(RAND() * COUNT(*)) AS `offset`',
])->where($where)->where(
$filter
)->find();
$code = $this->field([
'order_no as order_no_sn',
'shop_id',
'code_id',
'store_user_id',
'search_url',
'link',
'alipay',
'passageway',
'num',
])->where($where)->where(
$filter
)->limit((int)$offset['offset'], 1)->select();
$code = isset($code[0]) ? $code[0] : [];
//未查到进入下一次尝试
if(!$code){
continue;
}
//查询队列
//if(!$this->checkQueue($code['code_id'])) continue;
//查询支付状态
if($passageway == 'ZFBH5'){
$res = $this->checkStatus(htmlspecialchars_decode($code['search_url']), $passageway, '订单未支付');
if ($res === false) { //订单不是未支付状态
continue;
}
}else{
if(!empty($codesIp)) {
$conn->set('codeNum',$codeNum-1);
$res = $this->checkStatusProxy(htmlspecialchars_decode($code['search_url']), $passageway, $codesIp, $codesPort, '该订单已完成支付');
}else {
$res = $this->checkStatus(htmlspecialchars_decode($code['search_url']), $passageway, '该订单已完成支付');
}
if ($res !== false) { //已支付 重新匹配
continue;
}
}
for ($j = 1; $j <= 6; $j++) {
$num = $this->getZoneCodeTotal(['status' => '2', 'order_id' => '0', 'zone' => $j]);
if ($num < 20) {
$zone = $j;
break 2;
}
}
}
if(!$code || $zone==0) {
throw new BaseException(['message' => '匹配支付码失败']);
}
$code['zone'] = $zone;
$codeM->update([
'num' => $code['num']+1,
'status' => 2,
'zone' => $zone,
'allot_time' => time(),
],['code_id'=>$code['code_id']]);
return $code;
}
/**
* 支付码
* @param $money
* @param $passageway
* @return null|array
* @throws \app\common\exception\BaseException
* @throws \think\exception\DbException
*/
public function getCodeDetail($money,$passageway)
{
if(empty($money) || empty($passageway)) {
throw new BaseException(['message' => '参数错误']);
}
$money = round($money,2);
//组成队列名称
$queue_name = $passageway.'_'.$money;
//连接本地的 Redis 服务
// 字符串操作-获取代理IP
/*$codesIp = Cache::store('redis')->get('codesIp');
$codesPort = Cache::store('redis')->get('codesPort');
$codeNum = Cache::store('redis')->get('codeNum');
if(empty($codesIp) || empty($codeNum) || $codeNum <= 0){
//获取IP组
$iPGroup = $this->getIPGroup();
$codesIp = isset($iPGroup[0]['ip'])?$iPGroup[0]['ip']:'';
$codesPort = isset($iPGroup[0]['port'])?$iPGroup[0]['port']:'';
$codeNum = 20;
Cache::store('redis')->set('codesIp',$codesIp);
Cache::store('redis')->set('codesPort',$codesPort);
}*/
// 获取分布式锁
$lock_key = $queue_name . '_lock';
$max_wait_time = 10; // 最大等待时间(秒)
$retry_interval = 100; // 重试间隔时间(毫秒)
$lock_ttl = 40; // 锁定时间(秒)
$lock_count = 0; // 锁的重试次数
// 获取分布式锁
$redis = Cache::store('redis');
$lock = false;
$wait_time = 0;
$lock_value = '';
while ($wait_time <= $max_wait_time) {
$lock_value = uniqid(); // 生成唯一的锁值
if ($redis->set($lock_key, $lock_value, 'EX', $lock_ttl, 'NX')) {
$lock = true;
break;
} else {
// 获取锁失败,等待一段时间后重试
$lock_count++;
usleep($retry_interval * 1000);
$wait_time += ($retry_interval / 1000);
if ($lock_count > 20) {
// 重试次数超过限制,抛出异常
throw new BaseException(['message' => '匹配支付码失败,超出重试次数']);
}
}
}
// 获取队列的长度
$queue_length = $redis->lLen($queue_name);
//数组初始化
$codeM = new CodeModel();
$zone = 0; //分区
$code = [];
// 获取锁成功
if ($lock && $queue_length > 0) {
try {
// TODO: 需要加锁的业务逻辑
// 开始匹配
for ($i = 0; $i < $queue_length; $i++) {
// 从队列中取出元素
$timeout = 0; // 不需要设置等待时间
$result_data = $redis->brpop($queue_name, $timeout);
// 反序列化产码信息
$code_data = json_decode($result_data[1],true);
// 判断码是否已经过期
if (time() > $code_data['expire_time']) {
continue;
}
if (empty($code_data['code_id'])) {
continue;
}
//匹配成功处理逻辑
$code = CodeModel::detail($code_data['code_id']);
//查询支付状态
if($passageway == 'ZFBH5'){
$res = $this->checkStatus(htmlspecialchars_decode($code['search_url']), $passageway, '订单未支付');
if ($res === false) { //订单不是未支付状态
continue;
}
}
/*else{
if(!empty($codesIp)) {
$redis->set('codeNum',$codeNum-1);
$res = $this->checkStatusProxy(htmlspecialchars_decode($code['search_url']), $passageway, $codesIp, $codesPort, '该订单已完成支付');
}else {
$res = $this->checkStatus(htmlspecialchars_decode($code['search_url']), $passageway, '该订单已完成支付');
}
if ($res !== false) { //已支付 重新匹配
continue;
}
}*/
for ($j = 1; $j <= 6; $j++) {
$num = $this->getZoneCodeTotal(['status' => '2', 'order_id' => '0', 'zone' => $j]);
if ($num < 20) {
$zone = $j;
break 2;
}
}
}
} finally {
// 释放锁
$lock_value_in_redis = $redis->get($lock_key);
if ($lock_value_in_redis === $lock_value) { // 如果当前锁的值和刚才设置的值相等,则说明当前线程持有该锁,可以进行释放
$redis->del($lock_key); // 删除锁
}else{
//throw new BaseException(['message' => '匹配支付码失败,锁竞争']);
}
}
}
if(!$code || $zone == 0) {
throw new BaseException(['message' => '匹配支付码失败']);
}
$code['zone'] = $zone;
$code['order_no_sn'] = $code['order_no'];
$codeM->update([
'num' => $code['num']+1,
'status' => 2,
'zone' => $zone,
'allot_time' => time(),
],['code_id'=>$code['code_id']]);
return $code;
}
public function checkStatus($url,$passageway,$text='该订单已完成支付'){
if(in_array($passageway,['WX','SNZFBH5'])){
$ch = curl_init();
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT,10);
curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt ($ch, CURLOPT_MAXREDIRS, 3);
$content = curl_exec($ch);
}else {
$publicPath = app()->getRootPath() . 'public/';
$escaped_url = escapeshellarg($url);
$command = "node {$publicPath}myscript.js {$escaped_url} 2>&1";
$content = shell_exec($command);
}
$res = strpos((string)$content,$text);
return $res;
}
/**
* 按条件修改支付码状态为失效
* @param array $field
* @param array $filter
* @return false|int
*/
public function setStatusLose($field,$filter)
{
return $this->update(array_merge(['status' => 3],$field),$filter) !== false;
}
/**
* 等待支付产码列表
* @param $page
* @return array
* @throws \think\exception\DbException
*/
public function getSx($page=1)
{
// 获取数据列表
return $this->where('status', '=', 1)
->where(" num > 0 ")
->order(['back_time' => 'asc'])
->page($page, 20)
->select()
->toArray();
}
public function getIPGroup(){
$html = @file_get_contents("http://http.tiqu.letecs.com/getip3?num=1&type=2&pro=&city=0&yys=0&port=1&time=1&ts=0&ys=0&cs=0&lb=1&sb=0&pb=4&mr=1&regions=");
$result = json_decode($html,true);
$ips = is_array($result['data'])?$result['data']:[];
return $ips;
}
public function checkStatusProxy($targetUrl,$passageway,$ip,$port,$text='该订单已完成支付'){
if(in_array($passageway,['WX','SNZFBH5'])){
// 代理服务器
$proxyServer = "http://" . $ip . ":" . $port;
// 隧道身份信息
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $targetUrl);
curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
// 设置代理服务器
//curl_setopt($ch, CURLOPT_PROXYTYPE, 0); //http
curl_setopt($ch, CURLOPT_PROXYTYPE, 5); //sock5
curl_setopt($ch, CURLOPT_PROXY, $proxyServer);
// 设置隧道验证信息
curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727;)");
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
}else{
$publicPath = app()->getRootPath() . 'public/';
$escaped_url = escapeshellarg($targetUrl);
//$command = "node {$publicPath}myscript_proxy.js {$escaped_url} {$ip} {$port} 2>&1";
$command = "node {$publicPath}myscript.js {$escaped_url} 2>&1";
$result = shell_exec($command);
}
$res = strpos((string)$result,$text);
return $res;
}
/**
* 获取分区产码总数量
* @param array $filter
* @return int|string
*/
public function getZoneCodeTotal($filter = [])
{
return $this->where($filter)->count();
}
/**
* 插入队列判断当前是否可执行
* @param $code_id
* @return
*/
public function checkQueue($code_id)
{
$message = Cache::store('redis')->lPop("queue:$code_id");
// 如果队列为空,则写入队列
if ($message === null || $message === false) {
// 消息内容
$message = 1;
// 监控客户的消息 Hash
Cache::store('redis')->watch("code:$code_id");
// 开始事务
Cache::store('redis')->multi();
// 将消息添加到队列末尾
Cache::store('redis')->rPush("queue:$code_id", $message);
// 提交事务
$result = Cache::store('redis')->exec();
if ($result !== null && $result !== false) {
return true;
}
}
return false;
}
}
+274
View File
@@ -0,0 +1,274 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\api\model\Order as OrderModel;
use app\common\model\Comment as CommentModel;
use app\api\model\OrderGoods as OrderGoodsModel;
use app\api\service\User as UserService;
use app\common\library\helper;
use app\common\exception\BaseException;
/**
* 商品评价模型
* Class Comment
* @package app\api\model
*/
class Comment extends CommentModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'status',
'sort',
'order_id',
'goods_id',
'order_goods_id',
'is_delete',
'update_time'
];
/**
* 获取指定商品评价列表
* @param int $goodsId 商品ID
* @param int|null $scoreType 评分 (10好评 20中评 30差评)
* @return \think\Paginator
* @throws \think\db\exception\DbException
*/
public function getCommentList(int $goodsId, int $scoreType = null)
{
$filter = $this->getFilter($goodsId, $scoreType);
return $this->with(['user.avatar', 'orderGoods', 'images.file'])
->where($filter)
->order(['sort' => 'asc', 'create_time' => 'desc'])
->paginate(15);
}
/**
* 获取指定商品评价列表 (限制数量, 不分页)
* @param int $goodsId 商品ID
* @param int $limit 限制的数量
* @return \think\Collection
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function listRows(int $goodsId, int $limit = 5)
{
$filter = $this->getFilter($goodsId);
return $this->with(['user.avatar'])
->where($filter)
->order(['sort' => 'asc', $this->getPk()])
->limit($limit)
->select();
}
/**
* 获取指定商品评价总数量
* @param int $goodsId
* @return int
*/
public function rowsTotal(int $goodsId)
{
$filter = $this->getFilter($goodsId);
return $this->where($filter)->count();
}
/**
* 获取查询条件
* @param int $goodsId 商品ID
* @param int|null $scoreType 评分 (10好评 20中评 30差评)
* @return array[]
*/
private function getFilter(int $goodsId, int $scoreType = null)
{
// 筛选条件
$filter = [
['goods_id', '=', $goodsId],
['status', '=', 1],
['is_delete', '=', 0],
];
// 评分
$scoreType > 0 && $filter[] = ['score', '=', $scoreType];
return $filter;
}
/**
* 获取指定评分总数
* @param int $goodsId
* @return array|null|\think\Model
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getTotal(int $goodsId)
{
return $this->field([
'count(comment_id) AS `all`',
'count(score = 10 OR NULL) AS `praise`',
'count(score = 20 OR NULL) AS `review`',
'count(score = 30 OR NULL) AS `negative`',
])->where([
'goods_id' => $goodsId,
'is_delete' => 0,
'status' => 1
])->find();
}
/**
* 验证订单是否允许评价
* @param OrderModel $order
* @return boolean
*/
public function checkOrderAllowComment(OrderModel $order)
{
// 验证订单是否已完成
if ($order['order_status'] != 30) {
$this->error = '该订单未完成,无法评价';
return false;
}
// 验证订单是否已评价
if ($order['is_comment'] == 1) {
$this->error = '该订单已完成评价';
return false;
}
return true;
}
/**
* 根据已完成订单商品 添加评价
* @param OrderModel $order
* @param $goodsList
* @param array $data
* @return boolean
* @throws BaseException
*/
public function increased(OrderModel $order, $goodsList, array $data)
{
// 生成 formData
$formData = $this->formatFormData($data);
// 生成评价数据
$data = $this->createCommentData($order['order_id'], $goodsList, $formData);
if (empty($data)) {
$this->error = '没有输入评价内容';
return false;
}
return $this->transaction(function () use ($order, $goodsList, $formData, $data) {
// 记录评价内容
$result = $this->addAll($data);
// 记录评价图片`
$this->saveAllImages($result, $formData);
// 更新订单评价状态
$isComment = count($goodsList) === count($data);
$this->updateOrderIsComment($order, $isComment, $result);
return true;
});
}
/**
* 更新订单评价状态
* @param OrderModel $order
* @param $isComment
* @param $commentList
* @return array|false
* @throws \Exception
*/
private function updateOrderIsComment(OrderModel $order, $isComment, $commentList)
{
// 更新订单商品
$orderGoodsData = [];
foreach ($commentList as $comment) {
$orderGoodsData[] = [
'where' => [
'order_goods_id' => $comment['order_goods_id'],
],
'data' => [
'is_comment' => 1
]
];
}
// 更新订单
$isComment && $order->save(['is_comment' => 1]);
return (new OrderGoods)->updateAll($orderGoodsData);
}
/**
* 生成评价数据
* @param int $orderId
* @param $goodsList
* @param array $formData
* @return array
* @throws BaseException
*/
private function createCommentData(int $orderId, $goodsList, array $formData)
{
$data = [];
foreach ($goodsList as $goods) {
if (!isset($formData[$goods['order_goods_id']])) {
throwError('提交的数据不合法');
}
$commentItem = $formData[$goods['order_goods_id']];
$commentItem['content'] = trim($commentItem['content']);
!empty($commentItem['content']) && $data[$goods['order_goods_id']] = [
'score' => $commentItem['score'],
'content' => $commentItem['content'],
'is_picture' => !empty($commentItem['uploaded']),
'sort' => 100,
'status' => 1,
'user_id' => UserService::getCurrentLoginUserId(),
'order_id' => $orderId,
'goods_id' => $commentItem['goods_id'],
'order_goods_id' => $commentItem['order_goods_id'],
'store_id' => self::$storeId
];
}
return $data;
}
/**
* 格式化 formData
* @param array $data
* @return array
*/
private function formatFormData(array $data)
{
return helper::arrayColumn2Key($data, 'order_goods_id');
}
/**
* 记录评价图片
* @param $commentList
* @param $formData
* @return bool
*/
private function saveAllImages($commentList, $formData)
{
// 生成评价图片数据
$imageData = [];
foreach ($commentList as $comment) {
$item = $formData[$comment['order_goods_id']];
foreach ($item['uploaded'] as $imageId) {
$imageData[] = [
'comment_id' => $comment['comment_id'],
'image_id' => $imageId,
'store_id' => self::$storeId
];
}
}
$model = new CommentImage;
return !empty($imageData) && $model->addAll($imageData) !== false;
}
}
+42
View File
@@ -0,0 +1,42 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\CommentImage as CommentImageModel;
/**
* 商品图片模型
* Class GoodsImage
* @package app\api\model
*/
class CommentImage extends CommentImageModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'create_time',
];
/**
* 关联文件库
* @return \think\model\relation\BelongsTo
*/
public function file()
{
return parent::file()->bind(['image_url' => 'preview_url']);
}
}
+36
View File
@@ -0,0 +1,36 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\Company as CompanyModel;
use app\common\library\helper;
use cores\exception\BaseException;
use think\cache\driver\Redis;
/**
* 产码模型
* Class Order
* @package app\api\model
*/
class Company extends CompanyModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'update_time'
];
}
+86
View File
@@ -0,0 +1,86 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\api\service\User as UserService;
use app\common\model\Coupon as CouponModel;
use cores\exception\BaseException;
/**
* 优惠券模型
* Class Coupon
* @package app\api\model
*/
class Coupon extends CouponModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'receive_num',
'is_delete',
'create_time',
'update_time',
];
/**
* 获取优惠券列表
* @param int|null $limit 获取的数量
* @param bool $onlyReceive 只显示可领取
* @return mixed
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getList(int $limit = null, bool $onlyReceive = false)
{
// 查询构造器
$query = $this->getNewQuery();
// 只显示可领取(未过期,未发完)的优惠券
if ($onlyReceive) {
$query->where('IF ( `total_num` > - 1, `receive_num` < `total_num`, 1 = 1 )')
->where('IF ( `expire_type` = 20, (`end_time` + 86400) >= ' . time() . ', 1 = 1 )');
}
// 查询数量
$limit > 0 && $query->limit($limit);
// 优惠券列表
$couponList = $query->where('status', '=', 1)
->where('is_delete', '=', 0)
->order(['sort', 'create_time' => 'desc'])
->select();
// 获取用户已领取的优惠券
return $this->setIsReceive($couponList);
}
/**
* 获取用户已领取的优惠券
* @param mixed $couponList
* @return mixed
* @throws BaseException
*/
private function setIsReceive($couponList)
{
// 获取用户已领取的优惠券
$userInfo = UserService::getCurrentLoginUser();
if ($userInfo !== false) {
$UserCouponModel = new UserCoupon;
$userCouponIds = $UserCouponModel->getUserCouponIds($userInfo['user_id']);
foreach ($couponList as $key => $item) {
$couponList[$key]['is_receive'] = in_array($item['coupon_id'], $userCouponIds);
}
}
return $couponList;
}
}
+34
View File
@@ -0,0 +1,34 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\Delivery as DeliveryModel;
/**
* 配送模板模型
* Class Delivery
* @package app\api\model
*/
class Delivery extends DeliveryModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'create_time',
'update_time'
];
}
+34
View File
@@ -0,0 +1,34 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\DeliveryRule as DeliveryRuleModel;
/**
* 配送模板区域及运费模型
* Class DeliveryRule
* @package app\api\model
*/
class DeliveryRule extends DeliveryRuleModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'create_time',
'update_time'
];
}
+36
View File
@@ -0,0 +1,36 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\Express as ExpressModel;
/**
* 物流公司模型
* Class Express
* @package app\api\model
*/
class Express extends ExpressModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'kuaidi100_code',
'sort',
'store_id',
'create_time',
'update_time'
];
}
+265
View File
@@ -0,0 +1,265 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\api\service\Goods as GoodsService;
use app\api\service\user\Grade as UserGradeService;
use app\api\model\GoodsSku as GoodsSkuModel;
use app\api\model\GoodsSpecRel as GoodsSpecRelModel;
use app\common\model\Goods as GoodsModel;
use app\common\enum\goods\Status as GoodsStatusEnum;
use cores\exception\BaseException;
/**
* 商品模型
* Class Goods
* @package app\api\model
*/
class Goods extends GoodsModel
{
/**
* 隐藏字段
* @var array
*/
public $hidden = [
'images',
'delivery',
'deduct_stock_type',
'sales_initial',
'sales_actual',
'sort',
'is_delete',
'store_id',
'create_time',
'update_time'
];
// 是否设置会员折扣价
private $isGoodsGradeMoney = true;
/**
* 商品详情:HTML实体转换回普通字符
* @param $value
* @return string
*/
public function getContentAttr($value): string
{
return htmlspecialchars_decode((string)$value);
}
/**
* 是否设置会员折扣价
* @param bool $value
* @return $this
*/
public function isGoodsGradeMoney(bool $value): Goods
{
$this->isGoodsGradeMoney = $value;
return $this;
}
/**
* 获取商品列表
* @param array $param 查询条件
* @param int $listRows 分页数量
* @return mixed|\think\model\Collection|\think\Paginator
* @throws \think\db\exception\DbException
*/
public function getList(array $param = [], int $listRows = 15)
{
// 整理查询参数
$params = array_merge($param, ['status' => GoodsStatusEnum::ON_SALE]);
// 获取商品列表
$list = parent::getList($params, $listRows);
if ($list->isEmpty()) {
return $list;
}
// 隐藏冗余的属性
$list->hidden(static::getHidden(['content', 'goods_images', 'images']));
// 整理列表数据并返回
return $this->setGoodsListDataFromApi($list);
}
/**
* 获取商品详情 (详细数据用于页面展示)
* @param int $goodsId 商品ID
* @param bool $verifyStatus 是否验证商品状态(上架)
* @return mixed
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getDetails(int $goodsId, bool $verifyStatus = true)
{
// 关联查询(商品图片、sku列表)
$with = ['images.file', 'skuList.image', 'video', 'videoCover'];
// 获取商品记录
$goodsInfo = $this->getGoodsMain($goodsId, $with, $verifyStatus);
// 商品规格列表
$goodsInfo['specList'] = GoodsSpecRelModel::getSpecList($goodsInfo['goods_id']);
return $goodsInfo->hidden(static::getHidden(['images']));
}
/**
* 获取商品详情 (仅包含主商品信息和商品图片)
* @param int $goodsId 商品ID
* @param bool $verifyStatus 是否验证商品状态(上架)
* @return mixed
* @throws BaseException
*/
public function getBasic(int $goodsId, bool $verifyStatus = true)
{
// 关联查询(商品图片)
$with = ['images.file'];
// 获取商品记录
return $this->getGoodsMain($goodsId, $with, $verifyStatus);
}
/**
* 获取商品规格数据
* @param int $goodsId
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getSpecData(int $goodsId): array
{
$data = [];
// 商品SKU列表
$data['skuList'] = GoodsSkuModel::getSkuList($goodsId);
// 商品规格列表
$data['specList'] = GoodsSpecRelModel::getSpecList($goodsId);
return $data;
}
/**
* 获取商品主体信息
* @param int $goodsId 商品ID
* @param array $with 关联查询
* @param bool $verifyStatus 是否验证商品状态(上架)
* @return mixed
* @throws BaseException
*/
private function getGoodsMain(int $goodsId, array $with = [], bool $verifyStatus = true)
{
// 获取商品记录
$goodsInfo = static::detail($goodsId, $with);
// 判断商品是否存在
if (empty($goodsInfo) || $goodsInfo['is_delete']) {
throwError('很抱歉,商品信息不存在');
}
// 判断商品状态(上架)
if ($verifyStatus && $goodsInfo['status'] == GoodsStatusEnum::OFF_SALE) {
throwError('很抱歉,当前商品已下架');
}
// 整理商品数据并返回
return $this->setGoodsDataFromApi($goodsInfo);
}
/**
* 根据商品id集获取商品列表
* @param array $goodsIds
* @return mixed
*/
public function getListByIdsFromApi(array $goodsIds)
{
// 获取商品列表
$data = $this->getListByIds($goodsIds, GoodsStatusEnum::ON_SALE);
// 整理列表数据并返回
return $this->setGoodsListDataFromApi($data);
}
/**
* 获取商品指定的sku信息并且设置商品的会员价
* @param mixed $goodsInfo 商品信息
* @param string $goodsSkuId 商品SKUID
* @param bool $isGoodsGradeMoney 是否设置会员折扣价
* @return \app\common\model\GoodsSku|array|null
* @throws BaseException
*/
public static function getSkuInfo($goodsInfo, string $goodsSkuId, bool $isGoodsGradeMoney = true)
{
$goodsInfo['skuInfo'] = GoodsService::getSkuInfo($goodsInfo['goods_id'], $goodsSkuId);
$isGoodsGradeMoney && (new static)->setGoodsGradeMoney($goodsInfo);
return $goodsInfo['skuInfo'];
}
/**
* 设置商品展示的数据 api模块
* @param $data
* @return mixed
*/
private function setGoodsListDataFromApi($data)
{
return $this->setGoodsListData($data, function ($goods) {
// 整理商品数据 api模块
$this->setGoodsDataFromApi($goods);
});
}
/**
* 整理商品数据 api模块
* @param $goodsInfo
* @return mixed
*/
private function setGoodsDataFromApi($goodsInfo)
{
return $this->setGoodsData($goodsInfo, function ($goods) {
// 计算并设置商品会员价
$this->isGoodsGradeMoney && $this->setGoodsGradeMoney($goods);
});
}
/**
* 设置商品的会员价
* @param Goods $goods
* @throws BaseException
*/
private function setGoodsGradeMoney(self $goods)
{
// 设置当前商品是否使用会员等级折扣价
$goods['is_user_grade'] = false;
// 获取当前登录用户的会员等级信息
$gradeInfo = UserGradeService::getCurrentGradeInfo();
// 判断商品是否参与会员折扣
if (empty($gradeInfo) || !$goods['is_enable_grade']) {
return;
}
// 默认的折扣比例
$discountRatio = $gradeInfo['equity']['discount'];
// 商品单独设置了会员折扣
if ($goods['is_alone_grade'] && isset($goods['alone_grade_equity'][$gradeInfo['grade_id']])) {
$discountRatio = $goods['alone_grade_equity'][$gradeInfo['grade_id']];
}
if (empty($discountRatio)) {
return;
}
// 标记参与会员折扣
$goods['is_user_grade'] = true;
// 会员折扣价: 商品基础价格
$goods['goods_price_min'] = UserGradeService::getDiscountPrice($goods['goods_price_min'], $discountRatio);
$goods['goods_price_max'] = UserGradeService::getDiscountPrice($goods['goods_price_max'], $discountRatio);
// 会员折扣价: 商品sku列表
if ($goods->getRelation('skuList')) {
foreach ($goods['skuList'] as &$skuItem) {
$skuItem['goods_price'] = UserGradeService::getDiscountPrice($skuItem['goods_price'], $discountRatio);
}
}
// 会员折扣价: 已选择的商品sku(用于购物车)
if ($goods->getAttr('skuInfo')) {
$goods['skuInfo']['goods_price'] = UserGradeService::getDiscountPrice($goods['skuInfo']['goods_price'], $discountRatio);
}
}
}
+33
View File
@@ -0,0 +1,33 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\GoodsImage as GoodsImageModel;
/**
* 商品图片模型
* Class GoodsImage
* @package app\api\model
*/
class GoodsImage extends GoodsImageModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'create_time',
];
}
+43
View File
@@ -0,0 +1,43 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\GoodsSku as GoodsSkuModel;
/**
* 商品规格模型
* Class GoodsSku
* @package app\api\model
*/
class GoodsSku extends GoodsSkuModel
{
/**
* 关联模型:规格图片
* @return \think\model\relation\HasOne
*/
public function image(): \think\model\relation\HasOne
{
return parent::image()->bind(['image_url' => 'preview_url']);
}
/**
* 隐藏字段
* @var array
*/
public $hidden = [
'image',
'store_id',
'create_time',
'update_time'
];
}
+24
View File
@@ -0,0 +1,24 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\GoodsSpecRel as GoodsSpecRelModel;
/**
* 商品规格关系模型
* Class GoodsSpecRel
* @package app\api\model
*/
class GoodsSpecRel extends GoodsSpecRelModel
{
}
+32
View File
@@ -0,0 +1,32 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\Help as HelpModel;
/**
* 模型类:帮助中心
* Class Help
* @package app\api\model
*/
class Help extends HelpModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'create_time',
'update_time',
];
}
+36
View File
@@ -0,0 +1,36 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\Merchant as MerchantModel;
use app\common\library\helper;
use cores\exception\BaseException;
use think\cache\driver\Redis;
/**
* 产码模型
* Class Order
* @package app\api\model
*/
class Merchant extends MerchantModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'update_time'
];
}
+80
View File
@@ -0,0 +1,80 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\Notify as NotifyModel;
use app\common\library\helper;
use cores\exception\BaseException;
use think\cache\driver\Redis;
/**
* 通知模型
* Class Order
* @package app\api\model
*/
class Notify extends NotifyModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'update_time'
];
// 信息提示
private $message = '';
private $redis = null;
/**
* 通知列表
* @return \think\Paginator
* @throws \think\exception\DbException
*/
public function getList()
{
// 获取数据列表
return $this->where('status', '=', 0)
->where('num', '<', 3)
->order(['create_time' => 'asc'])
->paginate(200);
}
/**
* 新增通知记录
* @param $order
* @return false|int
*/
public function add($order)
{
return $this->save([
'order_id' => $order['order_id'],
'notify_url' => $order['notify_url'],
'store_id' => 10001,
]);
}
/**
* 修改通知状态
* @param $data
* @return bool
*/
public function sureNotify($data)
{
return $this->save([
'status' => $data['status'],
'num' => $data['num'],
'last_time' => time(),
]) !== false;
}
}
+521
View File
@@ -0,0 +1,521 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\api\model\{Goods as GoodsModel, OrderRefund as OrderRefundModel, Setting as SettingModel};
use app\api\service\{User as UserService, Payment as PaymentService};
use app\api\service\order\{PaySuccess as OrderPaySuccesService, source\Factory as OrderSourceFactory};
use app\common\model\Order as OrderModel;
use app\common\service\{Order as OrderService, order\Complete as OrderCompleteService};
use app\common\enum\{
Setting as SettingEnum,
OrderType as OrderTypeEnum,
order\PayType as OrderPayTypeEnum,
order\PayStatus as PayStatusEnum,
order\OrderStatus as OrderStatusEnum,
// order\DeliveryType as DeliveryTypeEnum,
order\ReceiptStatus as ReceiptStatusEnum,
order\DeliveryStatus as DeliveryStatusEnum
};
use app\common\library\helper;
use cores\exception\BaseException;
/**
* 订单模型
* Class Order
* @package app\api\model
*/
class Order extends OrderModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'update_time'
];
// 信息提示
private $message = '';
/**
* 待支付订单详情
* @param string $orderNo 订单号
* @return null|static
*/
public static function getPayDetail(string $orderNo): ?Order
{
return self::detail(['order_no' => $orderNo, 'pay_status' => PayStatusEnum::PENDING, 'is_delete' => 0], ['goods', 'user']);
}
/**
* 订单支付事件
* @param int $payType
* @return bool
*/
public function onPay(int $payType = OrderPayTypeEnum::WECHAT): bool
{
// 判断订单状态
$orderSource = OrderSourceFactory::getFactory($this['order_source']);
if (!$orderSource->checkOrderStatusOnPay($this)) {
$this->error = $orderSource->getError();
return false;
}
// 余额支付
if ($payType == OrderPayTypeEnum::BALANCE) {
return $this->onPaymentByBalance($this['order_no']);
}
return true;
}
/**
* 构建支付请求的参数
* @param self $order 订单信息
* @param int $payType 订单支付方式
* @return array
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function onOrderPayment(self $order, int $payType): array
{
if ($payType == OrderPayTypeEnum::WECHAT) {
return $this->onPaymentByWechat($order);
}
return [];
}
/**
* 构建微信支付请求
* @param self $order 订单详情
* @return array
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function onPaymentByWechat(self $order): array
{
return PaymentService::wechat(
$order['order_id'],
$order['order_no'],
$order['pay_price'],
OrderTypeEnum::ORDER
);
}
/**
* 立即购买:获取订单商品列表
* @param int $goodsId 商品ID
* @param string $goodsSkuId 商品SKU
* @param int $goodsNum 购买数量
* @return mixed
* @throws BaseException
*/
public function getOrderGoodsListByNow(int $goodsId, string $goodsSkuId, int $goodsNum)
{
// 获取商品列表
$model = new GoodsModel;
$goodsList = $model->isGoodsGradeMoney(false)->getListByIdsFromApi([$goodsId]);
if ($goodsList->isEmpty()) {
throwError('未找到商品信息');
}
// 隐藏冗余的属性
$goodsList->hidden(GoodsModel::getHidden(['content', 'goods_images', 'images']));
foreach ($goodsList as &$item) {
// 商品sku信息
$goodsInfo['skuInfo'] = GoodsModel::getSkuInfo($item, $goodsSkuId, false);
// 商品封面 (优先sku封面)
$item['goods_image'] = $item['skuInfo']['goods_image'] ?: $item['goods_image'];
// 商品单价
$item['goods_price'] = $item['skuInfo']['goods_price'];
// 商品购买数量
$item['total_num'] = $goodsNum;
// 商品SKU索引
$item['goods_sku_id'] = $item['skuInfo']['goods_sku_id'];
// 商品购买总金额
$item['total_price'] = helper::bcmul($item['goods_price'], $goodsNum);
}
return $goodsList;
}
/**
* 余额支付标记订单已支付
* @param string $orderNo 订单号
* @return bool
*/
public function onPaymentByBalance(string $orderNo): bool
{
// 获取订单详情
$service = new OrderPaySuccesService($orderNo);
// 发起余额支付
$status = $service->onPaySuccess(OrderPayTypeEnum::BALANCE);
if (!$status) {
throwError($service->getError());
}
return $status;
}
/**
* 获取用户订单列表
* @param string $type 订单类型 (all全部 payment待付款 received待发货 deliver待收货 comment待评价)
* @return \think\Paginator
* @throws \think\db\exception\DbException
* @throws BaseException
*/
public function getList(string $type = 'all'): \think\Paginator
{
// 筛选条件
$filter = [];
// 订单数据类型
switch ($type) {
case 'all':
break;
case 'payment':
$filter['pay_status'] = PayStatusEnum::PENDING;
$filter['order_status'] = OrderStatusEnum::NORMAL;
break;
case 'progress':
$filter['pay_status'] = PayStatusEnum::SUCCESS;
$filter['order_status'] = OrderStatusEnum::NORMAL;
break;
case 'complete':
$filter['order_status'] = OrderStatusEnum::COMPLETED;
break;
case 'delivery':
$filter['pay_status'] = PayStatusEnum::SUCCESS;
$filter['delivery_status'] = DeliveryStatusEnum::NOT_DELIVERED;
$filter['order_status'] = OrderStatusEnum::NORMAL;
break;
case 'received':
$filter['pay_status'] = PayStatusEnum::SUCCESS;
$filter['delivery_status'] = DeliveryStatusEnum::DELIVERED;
$filter['receipt_status'] = ReceiptStatusEnum::NOT_RECEIVED;
$filter['order_status'] = OrderStatusEnum::NORMAL;
break;
case 'comment':
$filter['is_comment'] = 0;
$filter['order_status'] = OrderStatusEnum::COMPLETED;
break;
}
// 当前用户ID
$userId = UserService::getCurrentLoginUserId();
// 查询列表数据
return $this->with(['goods.image'])
->where($filter)
->where('user_id', '=', $userId)
->where('is_delete', '=', 0)
->order(['create_time' => 'desc'])
->paginate(15);
}
/**
* 取消订单
* @return bool|mixed
*/
public function cancel()
{
if ($this['delivery_status'] == DeliveryStatusEnum::DELIVERED) {
$this->error = '已发货订单不可取消';
return false;
}
// 订单是否已支付
$isPay = $this['pay_status'] == PayStatusEnum::SUCCESS;
// 提示信息
$this->message = $isPay ? '订单已申请取消,需等待后台审核' : '订单已取消成功';
// 订单取消事件
return $this->transaction(function () use ($isPay) {
// 订单取消事件
$isPay == false && OrderService::cancelEvent($this);
// 更新订单状态: 已付款的订单设置为"待取消", 等待后台审核
return $this->save(['order_status' => $isPay ? OrderStatusEnum::APPLY_CANCEL : OrderStatusEnum::CANCELLED]);
});
}
/**
* 确认收货
* @return bool|mixed
*/
public function receipt()
{
// 验证订单是否合法
// 条件1: 订单必须已发货
// 条件2: 订单必须未收货
if ($this['delivery_status'] != 20 || $this['receipt_status'] != 10) {
$this->error = '该订单不合法';
return false;
}
return $this->transaction(function () {
// 更新订单状态
$status = $this->save([
'receipt_status' => 20,
'receipt_time' => time(),
'order_status' => 30
]);
// 执行订单完成后的操作
$OrderCompleteService = new OrderCompleteService();
$OrderCompleteService->complete([$this], static::$storeId);
return $status;
});
}
/**
* 获取当前用户订单数量
* @param string $type 订单类型 (all全部 payment待付款 received待发货 deliver待收货 comment待评价)
* @return int
* @throws BaseException
*/
public function getCount(string $type = 'all'): int
{
// 筛选条件
$filter = [];
// 订单数据类型
switch ($type) {
case 'all':
break;
case 'payment':
$filter['pay_status'] = PayStatusEnum::PENDING;
break;
case 'progress':
$filter['pay_status'] = PayStatusEnum::SUCCESS;
$filter['order_status'] = OrderStatusEnum::NORMAL;
break;
case 'complete':
$filter['order_status'] = OrderStatusEnum::COMPLETED;
break;
case 'received':
$filter['pay_status'] = PayStatusEnum::SUCCESS;
$filter['delivery_status'] = DeliveryStatusEnum::DELIVERED;
$filter['receipt_status'] = ReceiptStatusEnum::NOT_RECEIVED;
break;
case 'delivery':
$filter['pay_status'] = PayStatusEnum::SUCCESS;
$filter['delivery_status'] = DeliveryStatusEnum::NOT_DELIVERED;
$filter['order_status'] = OrderStatusEnum::NORMAL;
break;
case 'comment':
$filter['is_comment'] = 0;
$filter['order_status'] = OrderStatusEnum::COMPLETED;
break;
}
// 当前用户ID
$userId = UserService::getCurrentLoginUserId();
// 查询数据
return $this->where('user_id', '=', $userId)
->where('order_status', '<>', 20)
->where($filter)
->where('is_delete', '=', 0)
->count();
}
/**
* 获取用户订单详情(含关联数据)
* @param int $orderId 订单ID
* @return Order|array|null
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public static function getUserOrderDetail(int $orderId)
{
// 关联查询
$with = [
'goods' => ['image', 'goods', 'refund'],
'address', 'express'
];
// 查询订单记录
$order = static::getDetail($orderId, $with);
// 该订单是否允许申请售后
$order['isAllowRefund'] = static::isAllowRefund($order);
return $order;
}
/**
* 获取用户订单详情(仅订单记录)
* @param int $orderId
* @param array $with
* @return Order|array|null
* @throws BaseException
*/
public static function getDetail(int $orderId, array $with = [])
{
// 查询订单记录
$order = static::detail([
'order_id' => $orderId,
// 'user_id' => UserService::getCurrentLoginUserId(),
], $with);
empty($order) && throwError('订单不存在');
return $order;
}
/**
* 获取当前用户待处理的订单数量
* @return array
* @throws BaseException
*/
public function getTodoCounts(): array
{
return [
'payment' => $this->getCount('payment'), // 待付款的订单
'delivery' => $this->getCount('delivery'), // 待发货的订单
'received' => $this->getCount('received'), // 待收货的订单
'progress' => $this->getCount('progress'), // 进行中的订单
'complete' => $this->getCount('complete'), // 已完成的订单
'refund' => OrderRefundModel::getCountByUnderway(), // 进行中的售后单
];
}
// 返回提示信息
public function getMessage(): string
{
return $this->message;
}
/**
* 当前订单是否允许申请售后
* @param Order $order
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private static function isAllowRefund(self $order): bool
{
// 必须是已发货的订单
if ($order['delivery_status'] != DeliveryStatusEnum::DELIVERED) {
return false;
}
// 允许申请售后期限(天)
$refundDays = SettingModel::getItem(SettingEnum::TRADE)['order']['refund_days'];
// 不允许售后
if ($refundDays == 0) {
return false;
}
// 当前时间超出允许申请售后期限
if (
$order['receipt_status'] == ReceiptStatusEnum::RECEIVED
&& time() > ($order->getData('receipt_time') + ((int)$refundDays * 86400))
) {
return false;
}
return true;
}
/**
* 订单详情
* @param $order_no
* @return null|static
* @throws BaseException
* @throws \think\exception\DbException
*/
public function getOrderDetail($order_no)
{
if (!$order = $this->field([
'name',
'bank_ownership',
'bank_no',
'total_price as `money`',
'order_no',
'client_status',
'order_status',
'create_time',
])->where([
['order_no', '=', $order_no],
])->find()) {
throw new BaseException(['msg' => '订单不存在']);
}
return $order;
}
/**
* 订单详情
* @param $order_id
* @return null|static
* @throws BaseException
* @throws \think\exception\DbException
*/
public function getOrderDetailById($order_id)
{
if (!$order = $this->field([
'name',
'total_price as `money`',
'order_no',
'order_no_sn',
'order_status',
'create_time',
'merchant_id',
])->where([
['order_id', '=', $order_id],
])->find()) {
throw new BaseException(['message' => '订单不存在']);
}
return $order;
}
/**
* 新增订单记录
* @param $order
* @return false|int
*/
public function putInto($order)
{
return $this->save([
'store_id' => 10001,
'name' => $order['name'],
'total_price' => $order['money'],
'order_no' => $order['order_no'],
'notify_url' => $order['notifyUrl'],
'pay_price' => $order['money'],
'merchant_id' => $order['merchant_id'],
'callback' => $order['callback'],
'passageway' => $order['passageway'],
'ip' => $order['ip'],
]);
}
/**
* 订单用户状态修改
* @param $order_no
* @return false|int
*/
public function setClientStatus($order_no)
{
$where = array(
['order_no', '=', $order_no],
);
return $this->where($where)->update(['client_status' => 20]) !== false;
}
/**
* 获取分区订单总数量
* @param array $filter
* @return int|string
*/
public function getZoneOrderTotal($filter = [])
{
return $this->where($filter)->count();
}
/**
* 修改订单状态
* @param $where
* @param $field
* @return false|int
*/
public static function orderUpdate($where, $field)
{
return (new static())->where($where)->update($field) !== false;
}
}
+33
View File
@@ -0,0 +1,33 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\OrderAddress as OrderAddressModel;
/**
* 订单收货地址模型
* Class OrderAddress
* @package app\api\model
*/
class OrderAddress extends OrderAddressModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'create_time',
];
}
+62
View File
@@ -0,0 +1,62 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\OrderGoods as OrderGoodsModel;
/**
* 订单商品模型
* Class OrderGoods
* @package app\api\model
*/
class OrderGoods extends OrderGoodsModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'image',
'content',
'store_id',
'create_time',
];
/**
* 获取未评价的商品
* @param int $orderId 订单ID
* @return \think\Collection
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public static function getNotCommentGoodsList(int $orderId)
{
return (new static)->with(['image'])
->where('order_id', '=', $orderId)
->where('is_comment', '=', 0)
->select();
}
/**
* 修改订单状态
* @param $where
* @param $field
* @return false|int
*/
public static function orderUpdate($where, $field)
{
return (new static())->where($where)->update($field) !== false;
}
}
+234
View File
@@ -0,0 +1,234 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\api\service\User as UserService;
use app\api\model\OrderGoods as OrderGoodsModel;
use app\common\model\OrderRefund as OrderRefundModel;
use app\common\enum\order\refund\RefundType as RefundTypeEnum;
use app\common\enum\order\refund\AuditStatus as AuditStatusEnum;
use app\common\enum\order\refund\RefundStatus as RefundStatusEnum;
use cores\exception\BaseException;
/**
* 售后单模型
* Class OrderRefund
* @package app\api\model
*/
class OrderRefund extends OrderRefundModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'update_time'
];
/**
* 追加字段
* @var array
*/
protected $append = [
'state_text', // 售后单状态文字描述
];
/**
* 售后单状态文字描述
* @param $value
* @param $data
* @return string
*/
public function getStateTextAttr($value, $data): string
{
// 已完成
if ($data['status'] == RefundStatusEnum::COMPLETED) {
$text = [RefundTypeEnum::RETURN => '已同意退货并已退款', RefundTypeEnum::EXCHANGE => '已同意换货'];
return $text[$data['type']];
}
// 已取消
if ($data['status'] == RefundStatusEnum::CANCELLED) {
return '已取消';
}
// 已拒绝
if ($data['status'] == RefundStatusEnum::REJECTED) {
// return '已拒绝';
return $data['type'] == RefundTypeEnum::RETURN ? '已拒绝退货退款' : '已拒绝换货';
}
// 进行中
if ($data['status'] == RefundStatusEnum::NORMAL) {
if ($data['audit_status'] == AuditStatusEnum::WAIT) {
return '等待审核中';
}
if ($data['type'] == RefundTypeEnum::RETURN) {
return $data['is_user_send'] ? '已发货,待平台确认' : '已同意退货,请及时发货';
}
}
return $value;
}
/**
* 获取用户售后单列表
* @param int $state 售后单状态 -1为全部
* @return \think\Paginator
* @throws \app\common\exception\BaseException
* @throws \think\db\exception\DbException
* @throws BaseException
*/
public function getList(int $state = -1): \think\Paginator
{
// 检索查询条件
$filter = [];
// 售后单状态
$state > -1 && $filter[] = ['status', '=', $state];
// 当前用户ID
$userId = UserService::getCurrentLoginUserId();
// 查询列表记录
return $this->with(['orderGoods.image'])
->where($filter)
->where('user_id', '=', $userId)
->order(['create_time' => 'desc'])
->paginate(15);
}
/**
* 获取当前用户的售后单详情
* @param int $orderRefundId 售后单ID
* @param bool $isWith 是否关联
* @return static|null
* @throws BaseException
*/
public static function getDetail(int $orderRefundId, bool $isWith = false): ?OrderRefund
{
// 关联查询
$with = $isWith ? ['orderGoods' => ['image'], 'images.file', 'address', 'express'] : [];
// 获取记录
$detail = static::detail([
'user_id' => UserService::getCurrentLoginUserId(),
'order_refund_id' => $orderRefundId
], $with);
if (empty($detail)) throwError('未找到该售后单');
return $detail;
}
/**
* 获取当前用户的售后单数量(进行中的)
* @return int
* @throws BaseException
*/
public static function getCountByUnderway(): int
{
$userId = UserService::getCurrentLoginUserId();
return (new static)->where('user_id', '=', $userId)
->where('status', '=', 0)
->count();
}
/**
* 订单商品详情
* @param int $orderGoodsId 订单商品ID
* @return \app\common\model\OrderGoods|null
* @throws BaseException
*/
public function getRefundGoods(int $orderGoodsId)
{
$goods = OrderGoodsModel::detail($orderGoodsId);
if (isset($goods['refund']) && !empty($goods['refund'])) {
throwError('当前商品已申请售后');
}
return $goods;
}
/**
* 用户发货
* @param $data
* @return false|int
*/
public function delivery(array $data)
{
if (
$this['type'] != RefundTypeEnum::RETURN
|| $this['audit_status'] != AuditStatusEnum::REVIEWED
|| $this['is_user_send'] != 0
) {
$this->error = '当前售后单不合法,不允许该操作';
return false;
}
if ($data['expressId'] <= 0) {
$this->error = '请选择物流公司';
return false;
}
if (empty($data['expressNo'])) {
$this->error = '请填写物流单号';
return false;
}
return $this->save([
'is_user_send' => 1,
'send_time' => time(),
'express_id' => (int)$data['expressId'],
'express_no' => $data['expressNo'],
]);
}
/**
* 新增售后单记录
* @param int $orderGoodsId 订单商品ID
* @param array $data 用户提交的表单数据
* @return mixed
* @throws BaseException
*/
public function apply(int $orderGoodsId, array $data)
{
// 订单商品详情
$goods = $this->getRefundGoods($orderGoodsId);
return $this->transaction(function () use ($orderGoodsId, $data, $goods) {
// 新增售后单记录
$this->save([
'order_goods_id' => $orderGoodsId,
'order_id' => $goods['order_id'],
'user_id' => UserService::getCurrentLoginUserId(),
'type' => $data['type'],
'apply_desc' => $data['content'],
'audit_status' => AuditStatusEnum::WAIT,
'status' => 0,
'store_id' => self::$storeId
]);
// 记录凭证图片关系
if (isset($data['images']) && !empty($data['images'])) {
$this->saveImages((int)$this['order_refund_id'], $data['images']);
}
return true;
});
}
/**
* 记录售后单图片
* @param int $orderRefundId 售后单ID
* @param array $images 图片列表
* @return bool
*/
private function saveImages(int $orderRefundId, array $images)
{
// 生成评价图片数据
$data = [];
foreach ($images as $imageId) {
$data[] = [
'order_refund_id' => $orderRefundId,
'image_id' => $imageId,
'store_id' => self::$storeId
];
}
return !empty($data) && (new OrderRefundImage)->addAll($data) !== false;
}
}
@@ -0,0 +1,33 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\OrderRefundAddress as OrderRefundAddressModel;
/**
* 售后单退货地址模型
* Class OrderRefundAddress
* @package app\api\model
*/
class OrderRefundAddress extends OrderRefundAddressModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'create_time'
];
}
@@ -0,0 +1,25 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\OrderRefundImage as OrderRefundImageModel;
/**
* 售后单图片模型
* Class OrderRefundImage
* @package app\api\model
*/
class OrderRefundImage extends OrderRefundImageModel
{
}
+161
View File
@@ -0,0 +1,161 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\api\model\Goods as GoodsModel;
use app\api\model\Coupon as CouponModel;
use app\common\model\Page as PageModel;
use app\common\library\helper;
use cores\exception\BaseException;
/**
* 页面模型
* Class Page
* @package app\api\model
*/
class Page extends PageModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'create_time',
'update_time'
];
/**
* DIY页面详情
* @param int|null $pageId 页面ID
* @return array
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getPageData(int $pageId = null)
{
// 页面详情
$detail = $pageId > 0 ? parent::detail($pageId) : parent::getHomePage();
if (empty($detail)) {
throwError('很抱歉,未找到该页面');
}
// 页面diy元素
$pageData = $detail['page_data'];
// 获取动态数据
foreach ($pageData['items'] as &$item) {
// 移出默认数据
if (array_key_exists('defaultData', $item)) {
unset($item['defaultData']);
}
if ($item['type'] === 'window') {
$item['data'] = array_values($item['data']);
} else if ($item['type'] === 'goods') {
$item['data'] = $this->getGoodsList($item);
} else if ($item['type'] === 'coupon') {
$item['data'] = $this->getCouponList($item);
} else if ($item['type'] === 'article') {
$item['data'] = $this->getArticleList($item);
} else if ($item['type'] === 'special') {
$item['data'] = $this->getSpecialList($item);
}
}
return $pageData;
}
/**
* 商品组件:获取商品列表
* @param $item
* @return array
* @throws \think\db\exception\DbException
*/
private function getGoodsList($item)
{
// 获取商品数据
$model = new GoodsModel;
if ($item['params']['source'] === 'choice') {
// 数据来源:手动
$goodsIds = helper::getArrayColumn($item['data'], 'goods_id');
if (empty($goodsIds)) return [];
$goodsList = $model->getListByIdsFromApi($goodsIds);
} else {
// 数据来源:自动
$goodsList = $model->getList([
'status' => 10,
'categoryId' => $item['params']['auto']['category'],
'sortType' => $item['params']['auto']['goodsSort'],
], $item['params']['auto']['showNum']);
}
if ($goodsList->isEmpty()) return [];
// 格式化商品列表
$data = [];
foreach ($goodsList as $goods) {
$data[] = [
'goods_id' => $goods['goods_id'],
'goods_name' => $goods['goods_name'],
'selling_point' => $goods['selling_point'],
'goods_image' => $goods['goods_images'][0]['preview_url'],
'goods_price_min' => $goods['goods_price_min'],
'goods_price_max' => $goods['goods_price_max'],
'line_price_min' => $goods['line_price_min'],
'line_price_max' => $goods['line_price_max'],
'goods_sales' => $goods['goods_sales'],
];
}
return $data;
}
/**
* 优惠券组件:获取优惠券列表
* @param $item
* @return array|mixed
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function getCouponList($item)
{
// 获取优惠券数据
return (new CouponModel)->getList($item['params']['limit'], true);
}
/**
* 文章组件:获取文章列表
* @param $item
* @return array
* @throws \think\db\exception\DbException
*/
private function getArticleList($item)
{
// 获取文章数据
$model = new Article;
$articleList = $model->getList($item['params']['auto']['category'], $item['params']['auto']['showNum']);
return $articleList->isEmpty() ? [] : $articleList->toArray()['data'];
}
/**
* 头条快报:获取头条列表
* @param $item
* @return array
* @throws \think\db\exception\DbException
*/
private function getSpecialList($item)
{
// 获取头条数据
$model = new Article;
$articleList = $model->getList($item['params']['auto']['category'], $item['params']['auto']['showNum']);
return $articleList->isEmpty() ? [] : $articleList->toArray()['data'];
}
}
+36
View File
@@ -0,0 +1,36 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\Partners as PartnersModel;
use app\common\library\helper;
use cores\exception\BaseException;
use think\cache\driver\Redis;
/**
* 产码模型
* Class Order
* @package app\api\model
*/
class Partners extends PartnersModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'store_id',
'update_time'
];
}
@@ -0,0 +1,27 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\model;
use app\common\model\PartnersGoods as PartnersGoodsModel;
use app\common\library\helper;
use cores\exception\BaseException;
/**
* 用户优惠券模型
* Class PartnersGoods
* @package app\api\model
*/
class PartnersGoods extends PartnersGoodsModel
{
}

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