配置: - manifest.json mp-weixin.appid = wx40ca4b02d4d1cb58(构建产物已自动同步) - .env 新增 [sms] 段:mock / mock_code,手机号登录验证码改为配置驱动 (Auth::login 不再硬编码 123456;mock=0 时返回 2010 提示接入短信) - 服务端 .env [wechat] appid/secret 已就位并与小程序一致 加固: - 新增 utils/wxlogin.js:微信登录单飞(防静默登录与手动登录抢同一个一次性 code) + 40029/40163 自动换新 code 重试一次 - Auth::wxlogin 失败时回传 wx_errcode,供客户端判断是否重试 - 登录失败自动展开手机号兜底通道 新增 tests/config_check.js:一键核对 appid 三处一致性 / 接口连通 / HTTPS 证书 / 短信开关 验证:config_check 8/8 + 163 项断言回归全通过
204 行
7.3 KiB
PHP
204 行
7.3 KiB
PHP
<?php
|
||
|
||
namespace app\api\controller;
|
||
|
||
use fast\Random;
|
||
use think\Db;
|
||
use think\Validate;
|
||
|
||
/**
|
||
* 登录 / 角色 / 个人信息
|
||
*/
|
||
class Auth extends Base
|
||
{
|
||
protected $noNeedLogin = ['login', 'wxlogin'];
|
||
|
||
/**
|
||
* 手机号 + 验证码登录(兜底通道)
|
||
* 验证码来源由 .env 的 [sms] 段控制:mock=1 时使用 mock_code(联调用),
|
||
* 接入真实短信后置 mock=0 并在此处改为 Sms::check($mobile, $code, 'mobilelogin')
|
||
* @ApiMethod (POST)
|
||
*/
|
||
public function login()
|
||
{
|
||
$mobile = $this->request->post('mobile');
|
||
$code = $this->request->post('code');
|
||
if (!$mobile || !$code) {
|
||
$this->error('请填写手机号和验证码');
|
||
}
|
||
if (!Validate::regex($mobile, "^1\d{10}$")) {
|
||
$this->error('手机号格式不正确');
|
||
}
|
||
|
||
$mockOn = (int)\think\Env::get('sms.mock', 1);
|
||
$mockCode = (string)\think\Env::get('sms.mock_code', '123456');
|
||
if (!($mockOn === 1 && $mockCode !== '' && (string)$code === $mockCode)) {
|
||
$this->error('短信通道尚未接入,请联系管理员开通', ['sms_ready' => 0], 2010);
|
||
}
|
||
|
||
$user = \app\common\model\User::getByMobile($mobile);
|
||
if ($user) {
|
||
if ($user['status'] !== 'normal') {
|
||
$this->error('账号已被禁用');
|
||
}
|
||
$this->auth->direct($user['id']);
|
||
} else {
|
||
$ret = $this->auth->register($mobile, Random::alnum(), '', $mobile, []);
|
||
if (!$ret) {
|
||
$this->error($this->auth->getError() ?: '注册失败');
|
||
}
|
||
}
|
||
|
||
$this->success('登录成功', [
|
||
'token' => $this->auth->getToken(),
|
||
'expires' => 2592000,
|
||
'userinfo' => $this->profileData(),
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 我的信息(含角色与师傅状态)
|
||
*/
|
||
public function profile()
|
||
{
|
||
$this->success('', $this->profileData());
|
||
}
|
||
|
||
/**
|
||
* 组装个人信息
|
||
*/
|
||
protected function profileData()
|
||
{
|
||
$uid = $this->uid();
|
||
$user = Db::name('user')->field('id,nickname,mobile,avatar,money,score,createtime')->where('id', $uid)->find();
|
||
$master = Db::name('master')->where('user_id', $uid)->find();
|
||
|
||
$couponCount = Db::name('user_coupon')->where('user_id', $uid)->where('status', 'unused')->count();
|
||
$unread = Db::name('message')->where('receive_type', 'user')->where('receive_id', $uid)->where('is_read', 0)->count();
|
||
|
||
$masterInfo = null;
|
||
if ($master) {
|
||
$masterInfo = [
|
||
'id' => (int)$master['id'],
|
||
'realname' => $master['realname'],
|
||
'verify_status' => $master['verify_status'],
|
||
'audit_msg' => $master['audit_msg'],
|
||
'work_status' => $master['work_status'],
|
||
'level' => (int)$master['level'],
|
||
'score' => (float)$master['score'],
|
||
'order_count' => (int)$master['order_count'],
|
||
'money' => (float)$master['money'],
|
||
'can_take' => $master['verify_status'] === 'pass',
|
||
];
|
||
}
|
||
|
||
$merchant = Db::name('merchant')->where('user_id', $uid)->find();
|
||
$merchantInfo = null;
|
||
if ($merchant) {
|
||
$merchantInfo = [
|
||
'id' => (int)$merchant['id'],
|
||
'name' => $merchant['name'],
|
||
'verify_status' => $merchant['verify_status'],
|
||
'audit_msg' => $merchant['audit_msg'],
|
||
'settle_type' => $merchant['settle_type'],
|
||
'can_order' => $merchant['verify_status'] === 'pass',
|
||
];
|
||
}
|
||
|
||
return [
|
||
'id' => (int)$user['id'],
|
||
'nickname' => $user['nickname'] ?: ('用户' . substr((string)$user['mobile'], -4)),
|
||
'mobile' => $user['mobile'],
|
||
'avatar' => $user['avatar'] ?: '',
|
||
'balance' => (float)$user['money'],
|
||
'coupon_count' => (int)$couponCount,
|
||
'unread_count' => (int)$unread,
|
||
'is_master' => $master ? true : false,
|
||
'master' => $masterInfo,
|
||
'is_merchant' => $merchant ? true : false,
|
||
'merchant' => $merchantInfo,
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 微信授权登录(小程序 uni.login 拿到的 code)
|
||
* @ApiMethod (POST)
|
||
*/
|
||
public function wxlogin()
|
||
{
|
||
$code = trim((string)$this->request->post('code'));
|
||
$nickname = trim((string)$this->request->post('nickname'));
|
||
$avatar = trim((string)$this->request->post('avatar'));
|
||
if ($code === '') {
|
||
$this->error('缺少微信登录凭证 code');
|
||
}
|
||
|
||
$wx = \app\common\library\WxLogin::jscode2session($code);
|
||
if (isset($wx['error'])) {
|
||
$this->error($wx['error'], ['wx_errcode' => isset($wx['errcode']) ? (int)$wx['errcode'] : 0]);
|
||
}
|
||
$ret = \app\common\library\WxLogin::provision(
|
||
$wx['openid'],
|
||
isset($wx['unionid']) ? $wx['unionid'] : '',
|
||
isset($wx['session_key']) ? $wx['session_key'] : '',
|
||
$nickname,
|
||
$avatar
|
||
);
|
||
$this->auth->direct($ret['user_id']);
|
||
|
||
$this->success('登录成功', [
|
||
'token' => $this->auth->getToken(),
|
||
'expires' => 2592000,
|
||
'userinfo' => $this->profileData(),
|
||
'is_new' => $ret['is_new'],
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 切换角色(用户 / 师傅)
|
||
* @ApiMethod (POST)
|
||
*/
|
||
public function switchRole()
|
||
{
|
||
$role = $this->request->post('role', 'user');
|
||
if (!in_array($role, ['user', 'master', 'merchant'], true)) {
|
||
$this->error('角色参数错误');
|
||
}
|
||
|
||
if ($role === 'master') {
|
||
$master = $this->masterInfo();
|
||
if (!$master) {
|
||
$this->error('请先完成师傅入驻', ['need_apply' => 1], 2001);
|
||
}
|
||
if ($master['verify_status'] === 'pending') {
|
||
$this->error('师傅资质审核中,请耐心等待', ['verify_status' => 'pending'], 2002);
|
||
}
|
||
if ($master['verify_status'] === 'reject') {
|
||
$this->error('资质未通过:' . $master['audit_msg'], ['verify_status' => 'reject'], 2003);
|
||
}
|
||
}
|
||
|
||
if ($role === 'merchant') {
|
||
$merchant = Db::name('merchant')->where('user_id', $this->uid())->find();
|
||
if (!$merchant) {
|
||
$this->error('请先完成商家入驻', ['need_apply' => 1], 2001);
|
||
}
|
||
if ($merchant['verify_status'] === 'pending') {
|
||
$this->error('商家资质审核中,请耐心等待', ['verify_status' => 'pending'], 2002);
|
||
}
|
||
if ($merchant['verify_status'] === 'reject') {
|
||
$this->error('资质未通过:' . $merchant['audit_msg'], ['verify_status' => 'reject'], 2003);
|
||
}
|
||
}
|
||
|
||
$redirect = '/YJYF/YJYF';
|
||
if ($role === 'master') {
|
||
$redirect = '/pages/master/workbench';
|
||
} elseif ($role === 'merchant') {
|
||
$redirect = '/pages/merchant/workbench';
|
||
}
|
||
|
||
$this->success('切换成功', ['role' => $role, 'redirect' => $redirect]);
|
||
}
|
||
}
|