123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- <?php
- namespace App\Service;
- use Illuminate\Support\Facades\Redis;
- class DrbService extends Service
- {
- const RedisKey = 'DRBACCESSTOKENKEY';
- public function getAccessToken()
- {
- $token = Redis::get(self::RedisKey);
- if(! empty($token)) return [true, ['access_token' => $token]];
- $appKey = config('dingtalk.app_key');
- $appSecret = config('dingtalk.app_secret');
- $url = "https://api.dingtalk.com/v1.0/oauth2/accessToken";
- $resp = $this->curlOpen1($url, [
- 'request' => 'post',
- 'header' => ['Content-Type: application/json'],
- 'json' => [
- "appKey" => $appKey,
- "appSecret" => $appSecret
- ]
- ]);
- $res = json_decode($resp, true);
- $accessToken = $res['accessToken'] ?? "";
- $expires_in = $res['expires_in'] ?? 0;
- if(empty($accessToken)) return [false, 'AccessToken获取失败'];
- Redis::setex(self::RedisKey, $expires_in, $accessToken);
- return [true, ['access_token' => $accessToken]];
- }
- /**
- * 根据前端传来的免登 code 获取用户信息
- * @param string $code 前端 dd.getAuthCode 获取的 code
- * @return array [bool, data] bool 表示成功与否,data 成功返回用户信息,失败返回错误信息
- */
- public function getUserByCode($data)
- {
- $code = $data['code'] ?? "";
- if (empty($code)) return [false, '钉钉授权code不能为空'];
- // 1. 获取 access_token
- [$success, $tokenData] = $this->getAccessToken();
- if (! $success) return [false, $tokenData]; // tokenData 是错误信息
- $accessToken = $tokenData['access_token'];
- // 2. 用 code 换取用户信息(v2 接口)
- $url = "https://oapi.dingtalk.com/topapi/v2/user/getuserinfo?access_token={$accessToken}";
- $resp = $this->curlOpen1($url, [
- 'request' => 'post',
- 'header' => [
- "Content-Type: application/json",
- ],
- 'json' => [
- "code" => $code
- ]
- ]);
- $res = json_decode($resp, true);
- if (!isset($res['errcode'])) {
- return [false, '接口返回异常: ' . $resp];
- }
- if ($res['errcode'] !== 0) {
- return [false, '获取用户信息失败: ' . $res['errmsg']];
- }
- return [true, $res];
- }
- private function getManDetail($user){
- // 1. 获取 access_token
- [$success, $tokenData] = $this->getAccessToken();
- if (! $success) return [false, $tokenData]; // tokenData 是错误信息
- $accessToken = $tokenData['access_token'];
- // 3. 根据 userid 获取详细用户信息(包括部门)
- $urlDetail = "https://oapi.dingtalk.com/topapi/v2/user/get?access_token={$accessToken}";
- $respDetail = $this->curlOpen1($urlDetail, [
- 'request' => 'post',
- 'header' => ["Content-Type: application/json"],
- 'json' => ["userid" => $user['userId']]
- ]);
- $detail = json_decode($respDetail, true);
- if (!isset($detail['errcode'])) return [false, '获取用户详情接口异常: ' . $respDetail];
- if ($detail['errcode'] !== 0) return [false, '获取用户详情失败: ' . $detail['errmsg']];
- if (empty($detail['result'])) return [false, '获取用户详情失败,结果为空'];
- // 返回完整用户信息
- return [true, $detail['result']];
- }
- public function createProcessInstance($data, $user)
- {
- if(empty($data['type'])) return [false, '单据类型不能为空'];
- $type = $data['type'];
- $userId = $user['userId'];
- [$success, $userDetail] = $this->getManDetail($user);
- if(!$success) return [false, $userDetail];
- // 1. 获取 access_token
- [$success, $tokenData] = $this->getAccessToken();
- if (!$success) return [false, $tokenData];
- $accessToken = $tokenData['access_token'];
- //获取模板id
- $code = $this->getModelCode($type);
- //获取模板数据
- $formData = $this->getFormData($data);
- //创建审批
- [$success, $msg] = $this->createFlow($accessToken, $code, $userId, $userDetail, $formData);
- if(! $success) return [false, $msg];
- //记录信息
- return [true, ''];
- }
- private function createFlow($accessToken, $code, $userId, $userDetail, $formData){
- // 2. 请求 URL
- $url = "https://oapi.dingtalk.com/topapi/processinstance/create?access_token={$accessToken}";
- // 3. 请求体
- $payload = [
- "process_code" => $code, // 审批模板编码
- "originator_user_id" => $userId, // 发起人 userId
- "dept_id" => $userDetail['dept_id_list'], // 发起人部门 ID
- "form_component_values" => $formData, // 表单数据
- ];
- // 4. 发送请求
- $resp = $this->curlOpen1($url, [
- 'request' => 'post',
- 'header' => [
- "Content-Type: application/json",
- ],
- 'json' => $payload
- ]);
- $res = json_decode($resp, true);
- if (!isset($res['errcode'])) {
- return [false, "接口返回异常: " . $resp];
- }
- if ($res['errcode'] !== 0) {
- return [false, "创建审批实例失败: " . $res['errmsg']];
- }
- return [true, $res['process_instance_id']];
- }
- private function getModelCode($type){
- if($type == 1){
- // 采购单
- $code = "PROC-61E1D916-C7BE-4DE2-9D25-63505D8573B1";
- }elseif ($type == 2){
- // 请购单
- $code = "PROC-4FECC44D-993C-48E3-8623-CDC75B467622";
- }else{
- // 付款单
- $code = "PROC-F6D0C212-D8C6-4662-9AFD-EA9DE85A1F14";
- }
- return $code;
- }
- private function getFormData($data){
- $model = [];
- $formData = [
- [
- "name" => "订单日期",
- "value" => "2025-09-23" // 日期型字段,字符串 yyyy-MM-dd
- ],
- [
- "name" => "订单编号",
- "value" => "PO20250923001"
- ],
- [
- "name" => "业务类型",
- "value" => "标准采购"
- ],
- [
- "name" => "供应商",
- "value" => "XX供应商有限公司"
- ],
- [
- "name" => "制单人",
- "value" => "陈庆鹏"
- ],
- [
- "name" => "表格",
- "value" => json_encode([
- [
- [
- "name" => "存货名称",
- "value" => "打印机"
- ],
- [
- "name" => "数量",
- "value" => "2"
- ],
- [
- "name" => "主计量单位",
- "value" => "台"
- ],
- [
- "name" => "原币价税合计",
- "value" => "3000"
- ]
- ],
- [
- [
- "name" => "存货名称",
- "value" => "显示器"
- ],
- [
- "name" => "数量",
- "value" => "5"
- ],
- [
- "name" => "主计量单位",
- "value" => "个"
- ],
- [
- "name" => "原币价税合计",
- "value" => "5000"
- ]
- ]
- ], JSON_UNESCAPED_UNICODE) // 表格必须是字符串化的 JSON 数组
- ]
- ];
- return $model;
- }
- private function recordDatabase($data, $user, $process_instance_id){
- }
- public function getTemplateFields($data)
- {
- $processCode = $data['code'] ?? "";
- if (empty($processCode)) {
- return [false, '模板编号 process_code 不能为空'];
- }
- [$ok, $tokenData] = $this->getAccessToken();
- if (! $ok) return [false, $tokenData];
- $accessToken = $tokenData['access_token'];
- // 注意这里是 GET,并且 processCode 是 query 参数
- $url = "https://api.dingtalk.com/v1.0/workflow/forms/schemas/processCodes?processCode={$processCode}";
- $resp = $this->curlOpen1($url, [
- 'request' => 'get',
- 'header' => [
- "Content-Type: application/json",
- "x-acs-dingtalk-access-token: {$accessToken}"
- ],
- ]);
- $res = json_decode($resp, true);
- if (isset($res['schemas'])) {
- return [true, $res['schemas']];
- } else {
- return [false, $res];
- }
- }
- protected function curlOpen1($url, $config = [])
- {
- $default = [
- 'post' => false,
- 'request' => 'get',
- 'header' => [],
- 'json' => null,
- 'timeout' => 30
- ];
- $arr = array_merge($default, $config);
- $ch = curl_init();
- curl_setopt($ch, CURLOPT_URL, $url);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($ch, CURLOPT_TIMEOUT, $arr['timeout']);
- curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
- if (!empty($arr['header'])) {
- curl_setopt($ch, CURLOPT_HTTPHEADER, $arr['header']);
- }
- if ($arr['post'] || $arr['request'] !== 'get') {
- curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($arr['request']));
- if ($arr['json'] !== null) {
- curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($arr['json'], JSON_UNESCAPED_UNICODE));
- }
- }
- $result = curl_exec($ch);
- if ($result === false) {
- $err = curl_error($ch);
- curl_close($ch);
- return json_encode(['error' => $err]);
- }
- curl_close($ch);
- return $result;
- }
- }
|