diff --git a/app/controller/FeishuController.php b/app/controller/FeishuController.php
new file mode 100644
index 0000000..3465cb0
--- /dev/null
+++ b/app/controller/FeishuController.php
@@ -0,0 +1,186 @@
+all();
+
+ // 获取凭证
+ $certificate = config('feishu.mbaf');
+
+ // 飞书服务
+ $class = new \app\service\FeishuService($certificate['appId'], $certificate['appSecret'], $certificate['state']);
+
+ if (isset($param['code']) && $param['code']) {
+
+ // 获取token
+ $userAccessToken = $class->userAccessToken($param['code'], $certificate['rUrl']);
+
+ // 获取用户信息
+ $rst = $class->userInfo($userAccessToken['access_token']);
+ if ($rst['code'] != 0) {
+ throw new BusinessException('授权失败,请重试');
+ }
+
+ // var_dump($rst);
+ // array(3) {
+ // ["code"]=>
+ // int(0)
+ // ["data"]=>
+ // array(11) {
+ // ["avatar_big"]=>
+ // string(168) "https://s1-imfile.feishucdn.com/static-resource/v1/v3_00ie_7cc82f38-0a89-43d4-8b2c-d90fc9d9176g~?image_size=640x640&cut_type=&quality=&format=image&sticker_format=.webp"
+ // ["avatar_middle"]=>
+ // string(168) "https://s1-imfile.feishucdn.com/static-resource/v1/v3_00ie_7cc82f38-0a89-43d4-8b2c-d90fc9d9176g~?image_size=240x240&cut_type=&quality=&format=image&sticker_format=.webp"
+ // ["avatar_thumb"]=>
+ // string(166) "https://s1-imfile.feishucdn.com/static-resource/v1/v3_00ie_7cc82f38-0a89-43d4-8b2c-d90fc9d9176g~?image_size=72x72&cut_type=&quality=&format=image&sticker_format=.webp"
+ // ["avatar_url"]=>
+ // string(166) "https://s1-imfile.feishucdn.com/static-resource/v1/v3_00ie_7cc82f38-0a89-43d4-8b2c-d90fc9d9176g~?image_size=72x72&cut_type=&quality=&format=image&sticker_format=.webp"
+ // ["en_name"]=>
+ // string(9) "李佳博"
+ // ["mobile"]=>
+ // string(14) "+8615738985690"
+ // ["name"]=>
+ // string(9) "李佳博"
+ // ["open_id"]=>
+ // string(35) "ou_37bb7cfc4311c858ea32461700fa1a43"
+ // ["tenant_key"]=>
+ // string(16) "14e7bc0fe5985740"
+ // ["union_id"]=>
+ // string(35) "on_a3fdbca48cd9477a140c7f2167a63691"
+ // ["user_id"]=>
+ // string(8) "481g947d"
+ // }
+ // ["msg"]=>
+ // string(7) "success"
+ // }
+
+ return json($rst);
+ } else {
+ // 授权地址
+ $rst = $class->authorize($certificate);
+ // 拉起授权
+ return redirect($rst);
+ }
+ }
+
+
+ public function send()
+ {
+ // 获取凭证
+ $certificate = config('feishu.mbaf');
+
+ // 飞书服务
+ $class = new \app\service\FeishuService($certificate['appId'], $certificate['appSecret'], $certificate['state']);
+
+ // $receiveId = 'ou_37bb7cfc4311c858ea32461700fa1a43';
+ $receiveId = 'ou_a3b97543acbf1b28d978356bb08f85dd';
+
+ // 富文本 类型
+ // $content = "{
+ // \"zh_cn\":{
+ // \"title\":\"演示-消息提醒\",
+ // \"content\":[
+ // [{
+ // \"tag\":\"text\",
+ // \"text\":\"示例内容 - demo\",
+ // \"style\":[\"bold\"]
+ // }],
+ // [{
+ // \"tag\":\"hr\"
+ // }],
+ // [{
+ // \"tag\":\"a\",
+ // \"href\":\"http://219.157.255.213:25321/feishu/show\",
+ // \"text\":\"查看详情\"
+ // }]
+ // ]
+ // }
+ // }";
+
+ // 卡片 类型
+ $content = "{
+ \"config\":{
+ \"wide_screen_mode\":true
+ },
+ \"elements\":[{
+ \"tag\":\"div\",
+ \"text\":{
+ \"content\":\"**测试内容**,测试内容,测试内容。\\n 测试内容,测试内容,测试内容。\\n\\n 📬 示例1 示例1 示例1 \\n 😍 示例1 示例1 示例1 \\n 📝 示例1 示例1 示例1 \\n 🙌 示例1 示例1 示例1 \",
+ \"tag\":\"lark_md\"
+ }},{
+ \"actions\":[{
+ \"tag\":\"button\",
+ \"text\":{
+ \"content\":\"立即查看\",
+ \"tag\":\"plain_text\"
+ },
+ \"type\":\"primary\",
+ \"url\":\"http://219.157.255.213:25321/feishu/show\"
+ }],
+ \"tag\":\"action\"
+ }],
+ \"header\":{
+ \"template\":\"turquoise\",
+ \"title\":{
+ \"content\":\"📚标题\",
+ \"tag\":\"plain_text\"
+ }
+ }
+ }";
+ $msgType = 'interactive';
+ $receiveIdtype = 'open_id';
+
+ $result = $class->sendMessages($receiveId, $content, $msgType, $receiveIdtype);
+ return json($result);
+ }
+
+ public function show()
+ {
+ return '
查看详情 - 示例页面
';
+ }
+}
+
+// 凭证
+function certificate($gs = ''){
+ $data = [];
+ switch ($gs) {
+ case "xinyouhe":
+ $data = [
+ 'appId' => "cli_a73e1e6406fa501c",
+ 'appSecret' => "9cMfxujjGG9JPmNfNcOwUdCoIXqaM1wY",
+ 'rUrl' => "https://server.xyh.hnzhwlkj.club",
+ 'scope' => "contact:user.base:readonly contact:contact.base:readonly contact:user.employee_id:readonly im:message:send_as_bot",
+ 'state' => "xinyouhe"
+ ];
+ break;
+
+ case "mbaf":
+ $data = [
+ 'appId' => "cli_a75839fb4ff85028",
+ 'appSecret' => "VsqLvwsRzpmisBVbrTIuKdNCvRCO447d",
+ 'rUrl' => "https://server.xyh.hnzhwlkj.club",
+ 'scope' => "contact:user.base:readonly contact:contact.base:readonly contact:user.employee_id:readonly im:message:send_as_bot",
+ 'state' => "mbaf"
+ ];
+ break;
+
+ default:
+ throw new BusinessException('未授权应用');
+ break;
+ }
+ return $data;
+}
\ No newline at end of file
diff --git a/app/service/FeishuService.php b/app/service/FeishuService.php
new file mode 100644
index 0000000..e38e6a8
--- /dev/null
+++ b/app/service/FeishuService.php
@@ -0,0 +1,210 @@
+baseUri = 'https://open.larksuite.com/open-apis/';
+ } else {
+ $this->baseUri = 'https://open.feishu.cn/open-apis/';
+ }
+
+ $this->appId = $appId;
+ $this->appSecret = $appSecret;
+ $this->gs = $gs;
+
+ $this->client = new Client([
+ 'base_uri' => $this->baseUri
+ ]);
+
+ $this->options = [
+ 'headers' => [
+ 'Content-Type' => 'application/json; charset=utf-8'
+ ]
+ ];
+ }
+
+ /**
+ * 异常
+ */
+ public function error()
+ {
+ return $this->error;
+ }
+
+ /**
+ * 请求
+ */
+ public function requestResult($url = "", $method = "POST")
+ {
+ try {
+ $res = $this->client->request($method, $this->baseUri.$url, $this->options);
+ if ($res->getBody()) {
+ $result = json_decode($res->getBody(), true);
+ // var_dump($result);
+ if ($result["code"] === 0) {
+ return $result;
+ } else {
+ $this->error = $result["msg"];
+ return false;
+ }
+ } else {
+ $this->error = "result error";
+ return false;
+ }
+ } catch (RequestException $e) {
+ if ($e->hasResponse()) {
+ var_dump('2 :'.$e->getResponse()->getBody());
+ throw new BusinessException($e->getResponse()->getBody());
+ } else {
+ var_dump('3 :'.$e->getMessage());
+ throw new BusinessException($e->getMessage());
+ }
+ } catch (\Throwable $th) {
+ var_dump('4 :'.$th->getFile()."|".$th->getLine()."|".$th->getMessage());
+ $this->error = $th->getFile()."|".$th->getLine()."|".$th->getMessage();
+ return false;
+ }
+ }
+
+ /**
+ * 授权
+ */
+ public function authorize($certificate, $url = 'authen/v1/authorize')
+ {
+ $arr = [
+ 'app_id' => $certificate['appId'],
+ 'redirect_uri' => $certificate['rUrl'],
+ 'scope' => $certificate['scope'],
+ 'state' => $certificate['state']
+ ];
+ $queryData = http_build_query($arr);
+ return $this->baseUri.$url.'?'.$queryData;
+ }
+
+ /**
+ * 自建应用获取 tenant_access_token
+ */
+ public function tenantAccessToken()
+ {
+ $tenantAccessToken = Cache::get($this->gs.'-tenantAccessToken');
+ if (!$tenantAccessToken) {
+ $this->options["json"] = [
+ "app_id" => $this->appId,
+ "app_secret" => $this->appSecret
+ ];
+ $rst = $this->requestResult('auth/v3/tenant_access_token/internal', 'POST');
+ // var_dump($rst);
+ if ($rst) {
+ $tenantAccessToken = $rst['tenant_access_token'];
+ Cache::set($this->gs.'-tenantAccessToken', $tenantAccessToken, $rst['expire']);
+ } else {
+ throw new BusinessException('tenant_access_token 获取失败');
+ }
+ }
+ return $tenantAccessToken;
+ }
+
+ /**
+ * 通过手机号或邮箱获取用户 ID
+ */
+ public function getUserIdByPhoneOrEmail($phone = '', $userIdType = 'open_id')
+ {
+ $this->options["headers"] = [
+ "Authorization" => "Bearer " . $this->tenantAccessToken(),
+ "Content-Type" => "application/json; charset=utf-8"
+ ];
+ $this->options["json"] = [
+ "emails" => [],
+ "mobiles" => [$phone],
+ "include_resigned" => false
+ ];
+ $rst = $this->requestResult('contact/v3/users/batch_get_id?user_id_type='.$userIdType, 'POST');
+ return $rst;
+ }
+
+ /**
+ * 发送消息
+ */
+ public function sendMessages($receiveId = '', $content = '', $msgType = 'text', $receiveIdtype = 'open_id')
+ {
+ $this->options["headers"] = [
+ "Authorization" => "Bearer " . $this->tenantAccessToken(),
+ "Content-Type" => "application/json; charset=utf-8"
+ ];
+ $this->options["json"] = [
+ "receive_id" => $receiveId,
+ "msg_type" => $msgType,
+ "content" => $content
+ ];
+ $rst = $this->requestResult('im/v1/messages?receive_id_type='.$receiveIdtype, 'POST');
+ return $rst;
+ }
+
+ /**
+ * 编辑消息
+ */
+ public function updateSendMessages($messageId = '', $content = '', $msgType = 'text')
+ {
+ $this->options["headers"] = [
+ "Authorization" => "Bearer " . $this->tenantAccessToken(),
+ "Content-Type" => "application/json; charset=utf-8"
+ ];
+ $this->options["json"] = [
+ "msg_type" => $msgType,
+ "content" => $content
+ ];
+ $rst = $this->requestResult('im/v1/messages/'.$messageId, 'PUT');
+ return $rst;
+ }
+
+ /**
+ * 用户 user_access_token
+ */
+ public function userAccessToken($code = "", $redirect_uri = "")
+ {
+ $this->options["headers"] = [
+ "Content-Type" => "application/json; charset=utf-8"
+ ];
+ $this->options["json"] = [
+ "grant_type" => "authorization_code",
+ "client_id" => $this->appId,
+ "client_secret" => $this->appSecret,
+ "code" => $code,
+ "redirect_uri" => $redirect_uri
+ ];
+ return $this->requestResult('authen/v2/oauth/token');
+ }
+
+ /**
+ * 用户信息
+ */
+ public function userInfo($userAccessToken = "")
+ {
+ $this->options["headers"] = [
+ "Authorization" => "Bearer " . $userAccessToken,
+ "Content-Type" => "application/json; charset=utf-8"
+ ];
+ return $this->requestResult('authen/v1/user_info', "GET");
+ }
+}
\ No newline at end of file
diff --git a/config/cache.php b/config/cache.php
new file mode 100644
index 0000000..74775dc
--- /dev/null
+++ b/config/cache.php
@@ -0,0 +1,31 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+return [
+ 'default' => 'file',
+ 'stores' => [
+ 'file' => [
+ 'driver' => 'file',
+ 'path' => runtime_path('cache')
+ ],
+ 'redis' => [
+ 'driver' => 'redis',
+ 'connection' => 'default'
+ ],
+ 'array' => [
+ 'driver' => 'array'
+ ]
+ ]
+];
\ No newline at end of file
diff --git a/config/feishu.php b/config/feishu.php
new file mode 100644
index 0000000..4b30c07
--- /dev/null
+++ b/config/feishu.php
@@ -0,0 +1,20 @@
+ [
+ 'appId' => "cli_a73e1e6406fa501c",
+ 'appSecret' => "9cMfxujjGG9JPmNfNcOwUdCoIXqaM1wY",
+ 'rUrl' => "http://219.157.255.213:25321/feishu/auth",
+ 'scope' => "contact:user.base:readonly contact:contact.base:readonly contact:user.employee_id:readonly im:message:send_as_bot",
+ 'state' => "xinyouhe",
+ 'baseUri' => "https://open.feishu.cn/open-apis/"
+ ],
+ 'mbaf' => [
+ 'appId' => "cli_a75839fb4ff85028",
+ 'appSecret' => "VsqLvwsRzpmisBVbrTIuKdNCvRCO447d",
+ 'rUrl' => "http://219.157.255.213:25321/feishu/auth",
+ 'scope' => "contact:user.base:readonly contact:contact.base:readonly contact:user.employee_id:readonly im:message:send_as_bot",
+ 'state' => "mbaf",
+ 'baseUri' => "https://open.larksuite.com/open-apis/"
+ ]
+];
\ No newline at end of file
diff --git a/config/route.php b/config/route.php
index 17514e0..7ad9935 100644
--- a/config/route.php
+++ b/config/route.php
@@ -27,7 +27,7 @@ Route::any('/login', [app\controller\UserController::class, 'login'])->middlewar
Route::any('/upload', [app\controller\UploadController::class, 'uploadImage'])->middleware([app\middleware\CrossDomain::class]);
-
-
-
-
+// 飞书
+Route::post('/feishu/auth', [app\controller\FeishuController::class, 'auth']);
+Route::post('/feishu/show', [app\controller\FeishuController::class, 'show']);
+Route::post('/feishu/send', [app\controller\FeishuController::class, 'send']);
\ No newline at end of file
diff --git a/start.php b/start.php
index 2399638..41ad7ef 100644
--- a/start.php
+++ b/start.php
@@ -2,5 +2,4 @@