chore: 重写初始提交(清空历史,整理后全量提交)

This commit is contained in:
ywxapp
2026-08-16 16:54:14 +08:00
commit 6c1a106bc1
1808 changed files with 238144 additions and 0 deletions
+430
View File
@@ -0,0 +1,430 @@
<?php
// +----------------------------------------------------------------------
// | YwxApp [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: ywxapp<admin@ywxapp.cn>
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace app\Api\Controller\V1;
use ywxapp\controller\ApiController;
use ywxapp\service\RemoteService;
use think\Request;
/**
* 插件商店接口(瘦分发器,不持有市场领域逻辑):
*
* - 客户机模式(is_market_client()=trueywxapp.api_url 指向中心站):
* 经 RemoteService 代理中心站 /appmall/api/addon/*。
* - 中心站模式(api_url 为空/指向本机):
* 进程内委托 appmall 插件的 MarketService(订单/授权/收益/支付回调全部在插件侧)。
* - 未安装 appmall 插件且非客户机:市场功能不可用,返回明确提示。
*
* 中心站领域数据(appmarket_* 表)已全部收敛到 addon/appmall,核心不再直接读写。
*/
class Addon extends ApiController
{
// notify/payResult 由支付平台回调/跳转,无需登录;info 公开
protected $noNeedLogin = ['info', 'notify', 'payResult'];
protected $needRight = ['*'];
/**
* 中心站模式下委托的插件市场服务
* @var \addon\appmall\service\MarketService|null
*/
protected $market = null;
public function initialize()
{
if (!is_market_client() && class_exists(\addon\appmall\service\MarketService::class)) {
$this->market = \addon\appmall\service\MarketService::instance();
$this->market->ensureTables();
}
}
/**
* 本机为中心站但未安装市场插件时的统一出口
*/
protected function marketUnavailable(): \think\response\Json
{
return $this->result->error('市场服务不可用:本机未配置中心站地址(ywxapp.api_url),也未安装 appmall 插件', 503);
}
/**
* 将插件领域异常转换为 Result 错误响应
*/
protected function marketError(\Throwable $e): \think\response\Json
{
$code = (int) $e->getCode();
$code = $code >= 400 && $code < 600 ? $code : 500;
if ($code === 404) {
return $this->result->setStatusCode(404)->error($e->getMessage(), 404);
}
return $this->result->error($e->getMessage(), $code);
}
/**
* 获取插件信息(支持列表和详情)
*/
public function info(Request $request): \think\response\Json
{
if (is_market_client()) {
return $this->remoteInfo($request);
}
if (!$this->market) {
return $this->marketUnavailable();
}
$id = (int) $request->get('id', 0);
if ($id > 0) {
try {
$data = $this->market->info($id, $this->getLoginUid($request) ?? 0);
} catch (\Throwable $e) {
return $this->marketError($e);
}
$data['installed'] = is_dir(ADDON_PATH . ($data['addon']['name'] ?? '') . DIRECTORY_SEPARATOR);
return $this->result->success($data, '获取成功');
}
$r = $this->market->lists(
max((int) $request->get('page', 1), 1),
(int) $request->get('per_page', 15)
);
$this->result->setCount($r['total']);
return $this->result->success(['data' => $r['items']], '获取成功');
}
/**
* 轻量解析请求中的 JWT,返回用户ID(不触发完整登录副作用)
*/
protected function getLoginUid(Request $request): ?int
{
$auth = $request->header('authorization');
if (!$auth || !str_starts_with($auth, 'Bearer ')) {
return null;
}
try {
$token = \ywxapp\service\JwtService::instance()->parseAndValidate(substr($auth, 7));
$uid = $token->claims()->get('uid');
return $uid ? (int) $uid : null;
} catch (\Throwable) {
return null;
}
}
/**
* 发起购买:创建/复用待支付订单并拉起支付(或模拟支付直接签发授权)
*/
public function buy(Request $request)
{
if (is_market_client()) {
return $this->remoteBuy($request);
}
if (!$this->market) {
return $this->marketUnavailable();
}
$userId = $this->auth->model->uid ?? null;
if (empty($userId)) {
return $this->result->setStatusCode(401)->error('请先登录后再购买');
}
try {
$r = $this->market->buy(
(int) $userId,
(int) $request->post('addon_id'),
(string) $request->post('method', 'alipay'),
(string) $request->root(true)
);
} catch (\Throwable $e) {
return $this->marketError($e);
}
return $this->result->success($r['data'], $r['message']);
}
/**
* 支付结果查询(前端轮询用)
*/
public function orderStatus(Request $request): \think\response\Json
{
if (is_market_client()) {
return $this->remoteOrderStatus($request);
}
if (!$this->market) {
return $this->marketUnavailable();
}
$userId = $this->auth->model->uid ?? null;
if (empty($userId)) {
return $this->result->setStatusCode(401)->error('请先登录');
}
try {
$data = $this->market->orderStatus((int) $userId, (string) $request->get('trade_no'));
} catch (\Throwable $e) {
return $this->marketError($e);
}
return $this->result->success($data, '获取成功');
}
/**
* 支付完成落地页(支付宝 return_url 跳转,无需登录,仅展示状态)
*/
public function payResult(Request $request): \think\response\Json
{
if (is_market_client()) {
$r = RemoteService::instance()->payResult($request->get());
return $this->result->success($r['data'] ?? ['status' => 0], $r['message'] ?: '获取成功');
}
if (!$this->market) {
return $this->marketUnavailable();
}
$r = $this->market->payResult((string) $request->get('out_trade_no', ''));
return $this->result->success($r['data'], $r['message']);
}
/**
* 退款 / 吊销授权(买家或运营)
* POST /api/v1/addon/refund {trade_no 或 order_id}
*/
public function refund(Request $request): \think\response\Json
{
if (is_market_client()) {
return $this->remoteRefund($request);
}
if (!$this->market) {
return $this->marketUnavailable();
}
$userId = $this->auth->model->uid ?? null;
if (empty($userId)) {
return $this->result->setStatusCode(401)->error('请先登录');
}
try {
$r = $this->market->refund(
(int) $userId,
(string) $request->post('trade_no', ''),
(int) $request->post('order_id', 0)
);
} catch (\Throwable $e) {
return $this->marketError($e);
}
return $this->result->success($r['data'], $r['message']);
}
/**
* 我的已购插件(买家视角):列出已购付费插件 + 授权状态 + 是否可退款
*/
public function mine(Request $request): \think\response\Json
{
if (is_market_client()) {
return $this->remoteMine($request);
}
if (!$this->market) {
return $this->marketUnavailable();
}
$userId = $this->auth->model->uid ?? null;
if (empty($userId)) {
return $this->result->setStatusCode(401)->error('请先登录');
}
return $this->result->success($this->market->mine((int) $userId), '获取成功');
}
/**
* 支付宝/微信异步回调:验签 -> 校验金额 -> 订单置已付 -> 生成授权
*/
public function notify()
{
if (is_market_client()) {
return response(RemoteService::instance()->notify(input()));
}
if (!$this->market) {
return response('fail');
}
return $this->market->notify((string) input('method', 'alipay'));
}
/**
* 用户下载已购插件(需登录 + 有效授权 + 次数限制)
*/
public function download(Request $request)
{
if (is_market_client()) {
return $this->remoteDownload($request);
}
if (!$this->market) {
return $this->marketUnavailable();
}
$userId = $this->auth->model->uid ?? null;
if (empty($userId)) {
return $this->result->setStatusCode(401)->error('请先登录');
}
try {
$r = $this->market->download((int) $userId, (int) $request->get('addon_id'), $request);
} catch (\Throwable $e) {
return $this->marketError($e);
}
return download($r['file'], $r['filename']);
}
// ============ 客户机模式(ywxapp.api_url 指向其他服务器,见 is_market_client())下的代理实现 ============
/**
* 远程:插件详情 / 列表(代理中心站)
*/
protected function remoteInfo(Request $request): \think\response\Json
{
$id = (int) $request->get('id', 0);
$uid = $this->getLoginUid($request) ?? 0;
if ($id > 0) {
$r = RemoteService::instance()->info($id, $uid);
if (!$r['success']) {
return $this->result->setStatusCode(404)->error($r['message'] ?: '获取失败', 404);
}
$addon = $r['data']['addon'] ?? [];
$installed = is_dir(ADDON_PATH . ($addon['name'] ?? '') . DIRECTORY_SEPARATOR);
return $this->result->success([
'addon' => $addon,
'purchased' => $r['data']['purchased'] ?? false,
'installed' => $installed,
], '获取成功');
}
// 透传分页/筛选参数给中心站,由服务端完成分页(避免全量拉回后本地切片)
$params = [
'keyword' => $request->get('keyword', ''),
'category' => $request->get('category', ''),
'order' => $request->get('order', ''),
'page' => max((int) $request->get('page', 1), 1),
'page_size' => min(max((int) $request->get('per_page', 15), 1), 50),
];
$r = RemoteService::instance()->lists($params);
if (!$r['success']) {
return $this->result->error($r['message'] ?: '获取失败');
}
// 优先消费中心站服务端分页(Market::lists 在 page>0 时返回 data.list/data.total);
// 兼容历史 data.count 键;老中心站未分页时降级为本地切片。
if (isset($r['data']['list']) && (isset($r['data']['total']) || isset($r['data']['count']))) {
$items = $r['data']['list'];
$total = (int) ($r['data']['total'] ?? $r['data']['count']);
} else {
$rows = $r['data']['list'] ?? [];
$perPage = min(max((int) $request->get('per_page', 15), 1), 50);
$page = max((int) $request->get('page', 1), 1);
$total = count($rows);
$items = array_slice($rows, ($page - 1) * $perPage, $perPage);
}
$this->result->setCount($total);
return $this->result->success(['data' => $items], '获取成功');
}
/**
* 远程:发起购买(代理中心站)
*/
protected function remoteBuy(Request $request): \think\response\Json
{
$userId = $this->auth->model->uid ?? null;
if (empty($userId)) {
return $this->result->setStatusCode(401)->error('请先登录后再购买');
}
$addonId = (int) $request->post('addon_id');
$method = $request->post('method', 'alipay');
$r = RemoteService::instance()->buy($addonId, $userId, $method);
if (!$r['success']) {
return $this->result->error($r['message'] ?: '购买失败');
}
return $this->result->success($r['data'] ?? [], $r['message'] ?: '操作成功');
}
/**
* 远程:订单状态(代理中心站)
*/
protected function remoteOrderStatus(Request $request): \think\response\Json
{
$tradeNo = $request->get('trade_no');
$userId = $this->auth->model->uid ?? null;
if (empty($userId)) {
return $this->result->setStatusCode(401)->error('请先登录');
}
$r = RemoteService::instance()->orderStatus($tradeNo, $userId);
if (!$r['success']) {
return $this->result->error($r['message'] ?: '查询失败');
}
return $this->result->success($r['data'] ?? [], '获取成功');
}
/**
* 远程:下载已购插件(代理中心站 /appmall/api/index,付费插件需已购买)
*/
protected function remoteDownload(Request $request)
{
$userId = $this->auth->model->uid ?? null;
if (empty($userId)) {
return $this->result->setStatusCode(401)->error('请先登录');
}
$addonId = (int) $request->get('addon_id');
$r = RemoteService::instance()->info($addonId, $userId);
if (!$r['success']) {
return $this->result->error($r['message'] ?: '插件信息获取失败');
}
$addon = $r['data']['addon'] ?? [];
$name = $addon['name'] ?? '';
$version = $addon['version'] ?? '';
if ($name === '' || $version === '') {
return $this->result->error('插件信息不完整', 404);
}
if (!empty($addon['price']) && (float) $addon['price'] > 0 && empty($r['data']['purchased'])) {
return $this->result->error('您尚未购买该插件', 403);
}
try {
$domain = (string) $request->domain();
$srcFile = RemoteService::instance()->downloadBinary($name, $version, $userId, $domain);
} catch (\Exception $e) {
return $this->result->error($e->getMessage(), 404);
}
$tmpDir = root_path() . 'runtime' . DIRECTORY_SEPARATOR . 'addon_download' . DIRECTORY_SEPARATOR;
if (!is_dir($tmpDir)) {
@mkdir($tmpDir, 0755, true);
}
$tmpFile = $tmpDir . $name . '-' . $version . '.zip';
if (is_file($srcFile)) {
copy($srcFile, $tmpFile);
@unlink($srcFile);
} else {
return $this->result->error('下载失败:未获取到文件', 404);
}
return new \ywxapp\library\StreamZipResponse($tmpFile, $name . '-' . $version . '.zip');
}
/**
* 远程:退款 / 吊销授权(代理中心站)
*/
protected function remoteRefund(Request $request): \think\response\Json
{
$userId = $this->auth->model->uid ?? null;
if (empty($userId)) {
return $this->result->setStatusCode(401)->error('请先登录');
}
$r = RemoteService::instance()->refund(
(string) $request->post('trade_no', ''),
(int) $request->post('order_id', 0),
$userId
);
if (!$r['success']) {
return $this->result->error($r['message'] ?: '退款失败');
}
return $this->result->success($r['data'] ?? [], $r['message'] ?: '退款成功');
}
/**
* 远程:我的已购插件(代理中心站)
*/
protected function remoteMine(Request $request): \think\response\Json
{
$userId = $this->auth->model->uid ?? null;
if (empty($userId)) {
return $this->result->setStatusCode(401)->error('请先登录');
}
$r = RemoteService::instance()->my($userId);
if (!$r['success']) {
return $this->result->error($r['message'] ?: '获取失败');
}
return $this->result->success($r['data'] ?? ['list' => []], $r['message'] ?: '获取成功');
}
}
+120
View File
@@ -0,0 +1,120 @@
<?php
// +----------------------------------------------------------------------
// | YwxApp [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: ywxapp<admin@ywxapp.cn>
// +----------------------------------------------------------------------
declare (strict_types = 1);
namespace app\Api\Controller\V1;
use think\facade\Validate;
use ywxapp\controller\ApiController;
use addon\articles\model\Article as ArticleModel;
class Article extends ApiController
{
protected $noNeedLogin = ['*'];
protected $needRight = ['*'];
public function initialize()
{
$this->model = new ArticleModel();
}
/**
* 文章列表
*/
public function index()
{
$page = $this->request->param('page/d', 1);
$limit = $this->request->param('limit/d', 15);
$list = $this->model->with(['category'])->page($page, $limit)->order('id', 'desc')->select();
$this->result->success($list);
}
/**
* 创建文章
*/
public function create(\think\Request $request)
{
$data = $request->post();
if (empty($data['title'])) {
$this->result->error('标题不能为空', 404);
}
$res = $this->model->create($data);
if ($res) {
event('article_create_after', $res);
$this->result->success($res, '创建成功');
}
$this->result->error('创建失败');
}
/**
* 文章详情
* @route GET /detail, method:GET
* @param int $uid 文章ID
*/
public function detail(\think\Request $request, int $uid= 0 ) {
if (!$uid)
$this->result->error('Invalid parameters', 404);
$info = $this->model->with(['category', 'tags'])->find($uid);
if (! $info) {
$this->result->error('文章不存在', 404);
}
$this->result->success($info);
}
/**
* 更新文章
* @route PUT /update, method:PUT
* @param int $uid 文章ID
*/
public function update(\think\Request $request, int $uid= 0 ) {
if (!$uid)
$this->result->error('Invalid parameters', 404);
$info = $this->model->find($uid);
if (! $info) {
$this->result->error('文章不存在', 404);
}
$data = $request->only(
['title', 'cover_image', 'summary', 'content', 'author', 'cid', 'status'],
'put'
);
$info->save($data);
event('article_update_after', $info);
$this->result->success($info, '更新成功');
}
/**
* 删除文章(软删除)
* @route DELETE /update, method:DELETE
* @param int $uid 文章ID
*/
public function delete(\think\Request $request, int $uid= 0 ) {
if (!$uid)
$this->result->error('Invalid parameters', 404);
$info = $this->model->find($uid);
if (! $info) {
$this->result->error('文章不存在', 404);
}
$info->delete();
event('article_delete_after', $info);
$this->result->success('', '删除成功');
}
private function getEncryptPassword($password, $salt = '')
{
return md5(md5($password) . $salt);
}
public function init()
{
return json(['message' => 'This is version 1 of the API']);
}
}
+93
View File
@@ -0,0 +1,93 @@
<?php
// +----------------------------------------------------------------------
// | YwxApp [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: ywxapp<admin@ywxapp.cn>
// +----------------------------------------------------------------------
declare (strict_types = 1);
namespace app\api\controller\v1;
use ywxapp\controller\ApiController;
use think\facade\Event;
use ywxapp\model\MemberUser as UserModel;
use ywxapp\library\Result;
use ywxapp\library\Email as EmailLib;
/**
* 邮箱验证码接口.
*/
class Ems extends ApiController
{
protected $noNeedLogin = '*';
protected $needRight = '*';
public function initialize()
{
}
/**
* 发送验证码
*
* @param string $email 邮箱
* @param string $event 事件名称
*/
public function send()
{
$email = $this->request->request('email');
$event = $this->request->request('event');
$event = $event ? $event : 'register';
Event::trigger('email_send', ['email'=>$email, 'event'=>'register'], true);
$userinfo = UserModel::getByEmail($email);
if ($event == 'register' && $userinfo)
Result::instance()->error(('已被注册'));
elseif (in_array($event, ['changeemail']) && $userinfo)
Result::instance()->error(('已被占用'));
elseif (in_array($event, ['changepwd', 'resetpwd']) && !$userinfo)
Result::instance()->error(('未注册'));
$ret = \ywxapp\library\Email::instance()->sendEmail($email, null, $event);
if (!$ret)
Result::instance()->error(('发送失败'));
Result::instance()->success(('发送成功'));
}
/**
* 检测验证码
*
* @param string $email 邮箱
* @param string $event 事件名称
* @param string $captcha 验证码
*/
public function check()
{
$email = $this->request->request('email');
$event = $this->request->request('event', 'register');
$captcha = $this->request->request('captcha');
$validate = validate([
'email' => 'email',
'event' => 'chsAlphaNum',
'code' => 'Num',
]);
if (!$validate->check(['email' => $email, 'event' => $event, 'code' => $captcha]))
Result::instance()->error($validate->getError());
$userinfo = UserModel::where('email', $email)->find();
if ($event == 'register' && $userinfo)
$this->result->error(('已被注册'));
elseif (in_array($event, ['changeemail']) && $userinfo)
Result::instance()->error(('已被占用'));
elseif (in_array($event, ['changepwd', 'resetpwd']) && !$userinfo)
Result::instance()->error(('未注册'));
$ret = EmailLib::instance()->check($email, $captcha, $event);
if (!$ret)
Result::instance()->error(('验证码不正确'));
Result::instance()->success(data: ('验证码正确'));
}
}
+42
View File
@@ -0,0 +1,42 @@
<?php
// +----------------------------------------------------------------------
// | YwxApp [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: ywxapp<admin@ywxapp.cn>
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace app\api\controller\v1;
use ywxapp\controller\ApiController;
use think\Response;
/**
* Example 类
*
* @author ywxapp <admin@ywxapp.cn>
*/
class Example extends ApiController
{
public function index(): Response
{
$user = \ywxapp\model\BackendAdmin::where('id', 1)->findOrEmpty();
if (!$user->isEmpty()) {
# code...
$roles = $user->roles;
foreach ($roles as $role) {
//echo $role->name;
// 获取中间表模型
// dump($role->pivot);
}
}
return json([
'message' => 'This is version 1 of the API',
'data' => $user,
'role' => $user->roles
]);
}
}
+35
View File
@@ -0,0 +1,35 @@
<?php
// +----------------------------------------------------------------------
// | YwxApp [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: ywxapp<admin@ywxapp.cn>
// +----------------------------------------------------------------------
declare (strict_types = 1);
namespace app\Api\Controller\V1;
use ywxapp\controller\ApiController;
use ywxapp\library\Result;
/**
* Index 类
*
* @author ywxapp <admin@ywxapp.cn>
*/
class Index extends ApiController
{
public function init(\think\Request $request)
{
$result = Result::instance()->success(['name' => 'ThinkPHP', 'version' => '8.0', 'ip' => $request->ip(),'param'=>$request->param()], 'success');
return $result;
}
public function index(\think\Request $request)
{
$result = Result::instance()->success(['name' => 'ThinkPHP', 'version' => '8.0', 'ip' => $request->ip(),'param'=>$request->param()], 'success');
return $result;
}
}
+141
View File
@@ -0,0 +1,141 @@
<?php
// +----------------------------------------------------------------------
// | YwxApp [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: ywxapp<admin@ywxapp.cn>
// +----------------------------------------------------------------------
declare (strict_types = 1);
namespace app\Api\Controller\V1;
use think\facade\Event;
use think\exception\ValidateException;
use ywxapp\controller\ApiController;
use ywxapp\library\Sms as Smslib;
use ywxapp\model\Sms as SmsModel;
use ywxapp\model\MemberUser as UserModel;
use ywxapp\utils\Random;
/**
* Sms 类
*
* @author ywxapp <admin@ywxapp.cn>
*/
class Sms extends ApiController
{
public function index()
{
return json(['message' => 'SMS API']);
}
/**
* 发送验证码
*
* @ApiMethod (POST)
* @ApiParams (name="mobile", type="string", required=true, description="手机号")
* @ApiParams (name="event", type="string", required=true, description="事件名称")
* @ApiParams (name="type", type="string", required=false, description="验证类型,auto为自动验证,system为系统验证码")
* @ApiParams (name="source_id", type="string", required=false, description="来源ID")
*/
public function send()
{
$mobile = $this->request->post("mobile");
$event = $this->request->post("event", 'register');
$type = $this->request->post("type", 'auto');
$source_id = $this->request->post("source_id", '');
try {
validate([
'mobile' => 'require|max:11',
'event' => 'require|alpha|lower',
])->message([
'mobile.require' => '手机号必须',
'mobile.max' => '手机号最多不能超过11个字符',
'event.require' => '事件名称必须',
'event.alpha' => '事件名称必须是字母',
'event.lower' => '事件名称必须是小写字母',
])->check([
'mobile' => $mobile,
'event' => $event,
]);
$last = Smslib::get($mobile, $event);
if ($last && time() - (int) $last['create_at'] < 60) {
$this->result->error('发送频繁');
}
$ipSendTotal = SmsModel::where(['ip' => $this->request->ip()])->whereTime('create_at', '-1 hours')->count();
if ($ipSendTotal >= 5) {
$this->result->error('发送频繁');
}
if ($event) {
$userinfo = UserModel::getByMobile($mobile);
if ($event == 'register' && $userinfo) {
//已被注册
$this->result->error('已被注册');
} elseif (in_array($event, ['changemobile']) && $userinfo) {
//被占用
$this->result->error('已被占用');
} elseif (in_array($event, ['changepwd', 'resetpwd']) && ! $userinfo) {
//未注册
$this->result->error('未注册');
}
}
if (! Event::hasListener('SmsSend')) {
$this->result->error('请在后台插件管理安装短信验证插件');
}
$ret = Smslib::send($mobile, null, $event);
if ($ret) {
$this->result->success('发送成功');
} else {
$this->result->error('发送失败,请检查短信配置是否正确');
}
} catch (ValidateException $e) {
$this->result->error($e->getError());
}
}
/**
* 检测验证码
*
* @ApiMethod (POST)
* @ApiParams (name="mobile", type="string", required=true, description="手机号")
* @ApiParams (name="event", type="string", required=true, description="事件名称")
* @ApiParams (name="captcha", type="string", required=true, description="验证码")
*/
public function check()
{
$mobile = $this->request->post("mobile");
$event = $this->request->post("event", 'register');
$captcha = $this->request->post("captcha");
if (! $mobile || ! \think\Validate::regex($mobile, "^1\d{10}$")) {
$this->result->error('手机号不正确');
}
if (! preg_match("/^[a-z0-9_\-]{3,30}\$/i", $event)) {
$this->result->error('事件名称错误');
}
if (! preg_match("/^[a-z0-9]{4,6}\$/i", $captcha)) {
$this->result->error('验证码格式错误');
}
if ($event) {
$userinfo = UserModel::getByMobile($mobile);
if ($event == 'register' && $userinfo) {
//已被注册
$this->result->error('已被注册');
} elseif (in_array($event, ['changemobile']) && $userinfo) {
//被占用
$this->result->error('已被占用');
} elseif (in_array($event, ['changepwd', 'resetpwd']) && ! $userinfo) {
//未注册
$this->result->error('未注册');
}
}
$ret = Smslib::check($mobile, $captcha, $event);
if ($ret) {
$this->result->success('成功');
} else {
$this->result->error('验证码不正确');
}
}
}
+206
View File
@@ -0,0 +1,206 @@
<?php
// +----------------------------------------------------------------------
// | YwxApp [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: ywxapp<admin@ywxapp.cn>
// +----------------------------------------------------------------------
declare (strict_types = 1);
namespace app\Api\Controller\V1;
use app\api\validate\Login as LoginValidate;
use think\facade\Event;
use think\facade\Validate;
use ywxapp\controller\ApiController;
use ywxapp\model\MemberUser as UserModel;
use ywxapp\service\JwtService;
class User extends ApiController
{
protected $noNeedLogin = ['*'];
protected $noNeedVerify = ['*'];
public function initialize()
{
$this->model = new \ywxapp\model\Members();
}
public function index()
{
return json(['message' => 'This is version 1 of the API']);
}
/**
* 注册会员.
* @route put /register, method:put
* @param string $username 用户名
* @param string $password 密码
* @param string $email 邮箱
* @param string $mobile 手机号
* @param string $code 验证码
* @return \think\Response
*/
public function register(\think\Request $request)
{
$data = $request->param();
$validate = validate([
'account|账户或手机号' => 'require',
'password' => 'alphaDash',
'code' => 'number|length:4',
'captcha' => 'alphaNum',
]);
if (! $validate->check($data)) {
$this->result->error($validate->getError());
}
$account = $request->param('account');
$password = $request->has('password') ? $request->param('password') : md5("xixingwl");
$code = $request->param('code');
if (Validate::is($account, 'email') && $request->has('code')) {
$ret = \ywxapp\library\Sms::instence()->check($account, $code, 'register');
if (! $ret) {
$this->result->error('Code is incorrect');
}
}
if (Validate::is($account, 'mobile') && $request->has('code')) {
$ret = \ywxapp\library\Sms::instence()->check($account, $code, 'register');
if (! $ret) {
$this->result->error('Code is incorrect');
}
}
$extend = [];
if ($request->param('avatar')) {
$extend['avatar'] = $request->param('avatar');
}
if ($request->param('nickname')) {
$extend['nickname'] = $request->param('nickname');
}
$this->user->create($account, $password, $extend);
$this->result->success(['userinfo' => $this->Member->info]);
}
/**
* Member Login.
*
* @param string $account 账号
* @param string $password 密码
* @return \think\Response
*/
public function login(\think\Request $request)
{
$data = $this->request->param();
try {
validate(LoginValidate::class)->check($data);
$info = UserModel::where('account', $data['username'])
->whereOr('mobile', $data['username'])
->whereOr('email', $data['username'])
->findOrEmpty();
if ($info->isEmpty()) {
$this->result->error('用户不存在', 4010);
}
// 检查账户状态
if ($info->status == 0) {
$this->result->error('账号已被禁用', 403);
}
// 检查是否被锁定
if ($info->isLocked()) {
$lockTime = strtotime($info->lock_time) + 1800 - time();
$minutes = ceil($lockTime / 60);
$this->result->error("账号被锁定,请 {$minutes} 分钟后重试", 403);
}
$info->resetPassword($data['password']);
// 验证密码
if (! $info->checkPassword($data['password'])) {
$info->recordLoginFail($this->request->ip()); // 记录失败
$this->result->error('密码错误', 4011);
}
Event::trigger('MemberLog', [
'uid' => $info->uid,
'action' => 'login',
'ip' => $this->request->ip(),
'remark' => '用户注册',
]);
$newClaims = [
'uid' => $info->uid,
'account' => $info->account,
];
JwtService::instance()->createToken($newClaims);
$this->result->success($info);
} catch (ValidateException $e) {
$this->result->error($e->getMessage(), 1);
}
}
/**
* Get user detail
* @route get /detail, method:get
* @param int $uid
* @return \think\Response
*/
public function detail(\think\Request $request, int $uid = 0)
{
if (! $uid) {
$this->result->error('Invalid parameters', 404);
}
$this->result->success($this->user->info);
}
/**
* update user detail
* @route put /update, method:get
* @param int $uid
* @return \think\Response
*/
public function update(\think\Request $request, int $uid = 0)
{
if (! $uid) {
$this->result->error('Invalid parameters', 404);
}
$this->result->success($this->user->info);
}
/**
* DELETE user detail
* @route DELETE /update, method:DELETE
* @param int $uid
* @return \think\Response
*/
public function delete(\think\Request $request, int $uid = 0)
{
if (! $uid) {
$this->result->error('Invalid parameters', 404);
}
}
private function getEncryptPassword($password, $salt = '')
{
return md5(md5($password) . $salt);
}
public function init()
{
return json(['message' => 'This is version 1 of the API']);
}
}