Files

278 lines
8.7 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
// +----------------------------------------------------------------------
// | YwxApp [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: ywxapp<admin@ywxapp.cn>
// +----------------------------------------------------------------------
namespace ywxapp\library;
use BcMath\Number;
use think\exception\HttpResponseException;
use think\facade\Request;
use think\Response;
class Result
{
/**
* Summary of StatusCode
* @var int
*/
protected $StatusCode = 200;
public $Message = null;
/**
* Summary of Headers
* @var array
*/
protected $Headers = [];
protected $AccessToken;
protected $AccessExpired;
protected $RefreshToken;
protected $RefreshExpired;
protected $Total = 0;
/**
* Summary of Type
* @var string
*/
protected $Type = 'json';
protected $isCout = false;
public function __construct()
{
if (! Request::isAjax()) {
$this->Type = 'html';
}
}
public function success($data = null, $message = 'success', int $code = 0)
{
$result = ['code' => 0, 'message' => $message, 'timestamp' => time()];
if ($data) {
$result['data'] = $data;
}
if ($this->Total > 0) {
$result['count'] = $this->Total;
}
if ($this->AccessToken != null) {
$result['access_token'] = $this->AccessToken;
$result['access_expired'] = $this->AccessExpired;
}
if ($this->RefreshToken != null) {
$result['refresh_token'] = $this->RefreshToken;
$result['refresh_expired'] = $this->RefreshExpired;
}
$response = '';
if ('html' == strtolower($this->Type)) {
\think\facade\View::config(['view_path' => root_path() . 'ywxapp/view/']);
\think\facade\View::layout(false);
$result = \think\facade\View::fetch('success.html', $result);
}
$response = Response::create($result, strtolower($this->Type), $this->StatusCode)->header($this->Headers);
$this->applyTokenCookies($response);
$response->send();
app()->http->end($response);
exit;
// throw new HttpResponseException($response);
}
public function error($message = 'Error', int $code = 1, $data = null)
{
$result = ['code' => $code, 'message' => $message, 'timestamp' => time()];
if ($data) {
$result['data'] = $data;
}
if ($this->AccessToken != null) {
$result['access_token'] = $this->AccessToken;
$result['access_expired'] = $this->AccessExpired;
}
if ($this->RefreshToken != null) {
$result['refresh_token'] = $this->RefreshToken;
$result['refresh_expired'] = $this->RefreshExpired;
}
$response = '';
// 若已被强制为 JSON(如插件 API 在 MultiApp 中间件里 setType('json')),
// 或请求本身是 ajax,则统一返回 JSON;否则按 HTML 渲染。
$type = ($this->Type === 'json') ? 'json' : (Request::isAjax() ? 'json' : 'html');
if ($this->StatusCode == 401) {
$result['url'] = url('login/index');
$result['code'] = $this->StatusCode;
if ('html' == strtolower($type)) {
\think\facade\View::config(['view_path' => root_path() . 'ywxapp' . DIRECTORY_SEPARATOR . 'view' . DIRECTORY_SEPARATOR]);
$result = \think\facade\View::fetch('401.html', $result);
}
$response = Response::create($result, strtolower($type), 401);
$this->applyTokenCookies($response);
} else {
if ('html' == strtolower($type)) {
\think\facade\View::config(['view_path' => root_path() . 'ywxapp' . DIRECTORY_SEPARATOR . 'view' . DIRECTORY_SEPARATOR]);
\think\facade\View::layout(false);
$result = \think\facade\View::fetch('error.html', $result);
}
$response = Response::create($result, strtolower($type), $this->StatusCode)->header($this->Headers);
$this->applyTokenCookies($response);
}
$response->send();
app()->http->end($response);
exit;
throw new HttpResponseException($response);
}
/**
* 返回封装后的 API 数据到客户端.
*
* @param mixed $data 要返回的数据
* @param int $code 返回的 code
* @param mixed $msg 提示信息
* @param string $type 返回数据格式
* @param array $header 发送的 Header 信息
*/
protected function result($data, $code = 0, $msg = '', $type = '', array $header = [])
{
$result = [
'code' => $code,
'msg' => $msg,
'time' => Request::server('REQUEST_TIME'),
'data' => $data,
];
$type = $type ?: $this->getResponseType();
$response = Response::create($result, $type)->header($header);
throw new HttpResponseException($response);
}
/**
* URL 重定向.
*
* @param string $url 跳转的 URL 表达式
* @param array|int $params 其它 URL 参数
* @param int $code http code
* @param array $with 隐式传参
*/
public function redirect($url, $code = 302, $params = [], $with = []): self
{
if (is_int($params)) {
$code = $params;
}
$response = \redirect($url);
$response->code($code)->with($with);
throw new HttpResponseException($response);
}
/**
* 设置Token
* @param string $token
* @return void
*/
public function setAccessToken($token, $expired = null): self
{
$this->AccessToken = $token;
$this->AccessExpired = $expired;
return app()->result;
}
/**
* 设置Token
* @param string $token
* @return void
*/
public function setRefreshToken($token, $expired = null): self
{
$this->RefreshToken = $token;
$this->RefreshExpired = $expired;
return $this;
}
public function setStatusCode(int $code = 200): self
{
$this->StatusCode = $code;
return $this;
}
public function setMessage(string $message = ''): self
{
$this->Message = $message;
return $this;
}
public function setHeaders(array $header = []): self
{
$this->Headers = $header;
return $this;
}
/**
* 强制设置响应类型(json/html
* 插件 API 由小程序/APP 等客户端调用,请求不带 X-Requested-With
* 在 MultiApp 中间件里统一 setType('json') 以确保返回 JSON。
* @param string $type
* @return self
*/
public function setType(string $type = 'json'): self
{
$this->Type = strtolower($type);
return app()->result;
}
/**
* 把当前持有的 access/refresh token 写入响应 Cookiepath=/,非 httponly)。
*
* 背景:登录/注册的 token 经 JwtService 存入本 Result 单例(setAccessToken/setRefreshToken),
* 但 persistTokens() 用的全局 Cookie 门面与 Response 持有的 Cookie 实例并非同一个,
* 仅靠门面 set 的 token 不会被 Response::send() 输出,导致整页跳转(菜单点击、iframe)
* 不带 token → 后端读不到 → 跳登录页。此处直接写到 Response 实例上,确保 100% 随响应输出。
*
* @param Response $response
* @return void
*/
protected function applyTokenCookies(Response $response): void
{
if ($this->AccessToken !== null && $this->AccessToken !== '') {
$expire = $this->AccessExpired ? ((int) $this->AccessExpired - time()) : 0;
$response->cookie('access_token', (string) $this->AccessToken, [
'expire' => $expire,
'path' => '/',
'httponly' => false,
]);
}
if ($this->RefreshToken !== null && $this->RefreshToken !== '') {
$expire = $this->RefreshExpired ? ((int) $this->RefreshExpired - time()) : 0;
$response->cookie('refresh_token', (string) $this->RefreshToken, [
'expire' => $expire,
'path' => '/',
'httponly' => false,
]);
}
}
public function setCount(int $total): self
{
$this->Total = $total;
return app()->result;
}
public static function instance($options = []): Result
{
return app()->result;
}
}