Merge branch 'master' into UI-09-03

This commit is contained in:
Your Name
2026-09-09 12:19:39 +08:00
8 changed files with 265 additions and 7 deletions
@@ -0,0 +1,71 @@
<?php
// +----------------------------------------------------------------------
// | 企业微信客服桌面端管理员认证接口
// +----------------------------------------------------------------------
namespace app\adminapi\controller;
use app\adminapi\logic\auth\AuthLogic;
use app\common\enum\AdminTerminalEnum;
use app\common\enum\YesNoEnum;
use app\common\model\auth\Admin;
use app\common\model\auth\AdminRole;
/**
* 用最小身份信息把 ZYT 管理员账号映射到客服软件租户。
*
* session 标为免登录是为了跳过管理后台的菜单权限和登录 IP 限制;它并非匿名
* 接口,方法内部仍会严格校验 token 以及 token 的桌面终端类型。客服后台从另一
* 台服务器验证 token 时,请求 IP 本来就不会等于桌面用户登录时的 IP。
*/
class DesktopController extends BaseAdminController
{
public array $notNeedLogin = ['session'];
public function session()
{
$identity = (array)($this->request->adminInfo ?? []);
if (empty($identity) || empty($identity['admin_id'])) {
return $this->fail('登录已失效,请重新登录');
}
if ((int)($identity['terminal'] ?? 0) !== AdminTerminalEnum::WECOM_RPA) {
return $this->fail('当前登录令牌不属于企业微信客服桌面端');
}
$admin = Admin::where(['id' => (int)$identity['admin_id']])
->field('id,account,name,avatar,disable,root')
->findOrEmpty();
if ($admin->isEmpty() || (int)$admin['disable'] === YesNoEnum::YES) {
return $this->fail('管理员不存在或已禁用');
}
// 身份和权限在专用接口一次返回,客服后台无需跨 IP 调用网页端 mySelf。
$roleIds = array_values(array_unique(array_map('intval',
AdminRole::where('admin_id', (int)$admin['id'])->column('role_id')
)));
sort($roleIds);
$permissions = AuthLogic::getBtnAuthByRoleId([
'id' => (int)$admin['id'],
'root' => (int)$admin['root'],
'role_id' => $roleIds,
]);
$account = trim((string)$admin['account']);
$name = trim((string)$admin['name']);
return $this->data([
// 加类型前缀,避免管理员 id 与普通用户 id 相同时落到同一个客服租户。
'user_id' => 'admin:' . (int)$admin['id'],
'sn' => $account,
'nickname' => $name !== '' ? $name : $account,
'mobile' => '',
'avatar' => (string)$admin['avatar'],
'terminal' => AdminTerminalEnum::WECOM_RPA,
'expire_time' => (int)($identity['expire_time'] ?? 0),
'status' => 'active',
'account_type' => 'admin',
'root' => (int)$admin['root'] === YesNoEnum::YES,
'role_ids' => $roleIds,
'permissions' => array_values($permissions),
]);
}
}
@@ -32,7 +32,8 @@ use think\facade\Log;
class LoginValidate extends BaseValidate
{
protected $rule = [
'terminal' => 'require|in:' . AdminTerminalEnum::PC . ',' . AdminTerminalEnum::MOBILE,
'terminal' => 'require|in:' . AdminTerminalEnum::PC . ',' . AdminTerminalEnum::MOBILE
. ',' . AdminTerminalEnum::WECOM_RPA,
'account' => 'require',
'password' => 'require|password',
];
@@ -143,4 +144,4 @@ class LoginValidate extends BaseValidate
return in_array($flag, ['1', 'true', 'yes', 'on'], true);
}
}
}
@@ -0,0 +1,44 @@
<?php
// +----------------------------------------------------------------------
// | 企业微信客服桌面端认证接口
// +----------------------------------------------------------------------
namespace app\api\controller;
use app\common\enum\user\UserTerminalEnum;
use app\common\enum\YesNoEnum;
use app\common\model\user\User;
/**
* 桌面端只通过这里确认一个 token 是否属于企业微信客服终端。
*
* 登录仍复用 LoginController::account;这个接口只返回建立外部账号映射所需的
* 最小身份信息,避免客服后台依赖面向普通 PC 页面的完整个人资料结构。
*/
class DesktopController extends BaseApiController
{
public function session()
{
if ((int)($this->userInfo['terminal'] ?? 0) !== UserTerminalEnum::WECOM_RPA) {
return $this->fail('当前登录令牌不属于企业微信客服桌面端');
}
$user = User::where(['id' => $this->userId])
->field('id,sn,nickname,mobile,avatar,is_disable')
->findOrEmpty();
if ($user->isEmpty() || (int)$user['is_disable'] === YesNoEnum::YES) {
return $this->fail('用户不存在或已禁用');
}
return $this->data([
'user_id' => (int)$user['id'],
'sn' => (string)$user['sn'],
'nickname' => (string)$user['nickname'],
'mobile' => (string)$user['mobile'],
'avatar' => (string)$user['avatar'],
'terminal' => UserTerminalEnum::WECOM_RPA,
'expire_time' => (int)($this->userInfo['expire_time'] ?? 0),
'status' => 'active',
]);
}
}
@@ -35,8 +35,8 @@ class LoginAccountValidate extends BaseValidate
protected $rule = [
'terminal' => 'require|in:' . UserTerminalEnum::WECHAT_MMP . ',' . UserTerminalEnum::WECHAT_OA . ','
. UserTerminalEnum::H5 . ',' . UserTerminalEnum::PC . ',' . UserTerminalEnum::IOS .
',' . UserTerminalEnum::ANDROID,
. UserTerminalEnum::H5 . ',' . UserTerminalEnum::PC . ',' . UserTerminalEnum::IOS
. ',' . UserTerminalEnum::ANDROID . ',' . UserTerminalEnum::WECOM_RPA,
'scene' => 'require|in:' . LoginEnum::ACCOUNT_PASSWORD . ',' . LoginEnum::MOBILE_CAPTCHA . '|checkConfig',
'account' => 'require',
];
@@ -158,4 +158,4 @@ class LoginAccountValidate extends BaseValidate
}
return '验证码错误';
}
}
}
+3 -1
View File
@@ -25,4 +25,6 @@ class AdminTerminalEnum
{
const PC = 1;
const MOBILE = 2;
}
// 企业微信客服桌面软件。与网页端分开保存会话,桌面登录不会顶掉浏览器登录。
const WECOM_RPA = 7;
}
@@ -28,6 +28,7 @@ class UserTerminalEnum
const PC = 4;//电脑PC
const IOS = 5;//苹果app
const ANDROID = 6;//安卓app
const WECOM_RPA = 7;//企业微信客服桌面端
const ALL_TERMINAL = [
@@ -37,6 +38,7 @@ class UserTerminalEnum
self::PC,
self::IOS,
self::ANDROID,
self::WECOM_RPA,
];
/**
@@ -55,10 +57,11 @@ class UserTerminalEnum
self::PC => '电脑PC',
self::IOS => '苹果APP',
self::ANDROID => '安卓APP',
self::WECOM_RPA => '企业微信客服桌面端',
];
if(true === $from){
return $desc;
}
return $desc[$from] ?? '';
}
}
}