1
0

WeworkSingle.php 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008
  1. <?php
  2. namespace app\api\controller;
  3. use app\logics\SmsLogic;
  4. use app\logics\UserLogic;
  5. use app\model\Customer;
  6. use app\model\Employee;
  7. use app\model\Miniprogram;
  8. use app\model\Org;
  9. use app\model\User;
  10. use app\model\UserSignLog;
  11. use app\model\WeworksingleCompanySetting;
  12. use app\model\WeworksingleChatRecord;
  13. use app\model\WeworksingleCustomer;
  14. use app\model\WeworksingleUser;
  15. use EasyWeChat\Factory;
  16. use Firebase\JWT\JWT;
  17. use openssl\Aes;
  18. use think\facade\Log;
  19. use app\model\Company;
  20. use toolkits\Aec;
  21. use weworkapi\api\apiSingle;
  22. /**
  23. * 企业微信登录相关(单应用部署)
  24. * Class Wework
  25. * @package app\apiSingle\controller
  26. */
  27. class WeworkSingle extends Base
  28. {
  29. /**
  30. * 获取授权链接
  31. */
  32. public function getAuthLink(){
  33. $ticket = input('ticket', '', 'trim');
  34. $config = WeworksingleCompanySetting::where('ticket', '=', $ticket)->find();
  35. $single_config['corp_id'] = $config['corp_id'];
  36. $single_config['agent_id'] = $config['agent_id'];
  37. $single_config['secret'] = $config['agent_secret'];
  38. /*$single_config['token'] = $config['receive_token'];
  39. $single_config['aes_key'] = $config['receive_aes_key'];*/
  40. $app = Factory::work($single_config);
  41. $redirectUrl = request()->domain() . '/weworksingle.html#/signLogin';
  42. //$redirectUrl = input('redirectUrl', '', 'trim');
  43. $app->oauth->redirect($redirectUrl);
  44. $link = $app->oauth->getAuthUrl();
  45. return json(['code' => self::success, 'data' => $link, 'msg' => '获取成功']);
  46. }
  47. /**
  48. * 根据授权code换取用户信息,查询到信息则返回token,没有则返回对应的状态节点信息。
  49. * 返回码 -1、未绑定企业 0、正常 2、跳转到手机号登录页 3、跳转到选择企业页面,选择完之后再去登录 4、选择企业页面,选择完直接进入系统(弃用,不安全,默认进入最近进入的账号)
  50. * @return \think\response\Json
  51. * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
  52. * @throws \think\db\exception\DataNotFoundException
  53. * @throws \think\db\exception\DbException
  54. * @throws \think\db\exception\ModelNotFoundException
  55. */
  56. public function getUserByCode(){
  57. $code = input('code', '', 'trim');
  58. $ticket = input('ticket', '', 'trim');
  59. $config = WeworksingleCompanySetting::where('ticket', '=', $ticket)->find();
  60. $single_config['corp_id'] = $config['corp_id'];
  61. $single_config['agent_id'] = $config['agent_id'];
  62. $single_config['secret'] = $config['agent_secret'];
  63. $single_config['token'] = $config['receive_token'];
  64. $single_config['aes_key'] = $config['receive_aes_key'];
  65. $app = Factory::work($single_config);
  66. $user = $app->oauth->detailed()->userFromCode($code);
  67. //return json(['code'=> self::error_msg, 'msg'=> '获取授权信息失败', 'data'=> '']);
  68. // 获取用户信息
  69. $userid = $user->getId(); // 对应企业微信英文名(userid)
  70. $info = $user->getRaw(); // 获取企业微信接口返回的原始信息
  71. $where[] = ['userid', '=', $userid];
  72. $company_ids = WeworksingleCompanySetting::where('ticket', '=', $ticket)->column('company_id');
  73. if (empty($company_ids)){
  74. return json(['code'=> -1, 'msg'=> '未绑定企业', 'data'=> []]);
  75. }
  76. $where[] = ['company_id', 'in', $company_ids];
  77. $users = WeworksingleUser::where($where)->select()->toArray();
  78. $wx_uid = 0;
  79. $company_id = 0; //能直接登录的企业
  80. if (empty($users)) {
  81. // 查询有已创建的用户信息,但是未绑定所在店面的企业微信用户数据
  82. $wx_result = WeworksingleUser::where([['userid', '=', $userid], ['company_id', '=', 0]])->findOrEmpty();
  83. if ($wx_result->isEmpty()) {
  84. $info['company_id'] = 0;
  85. $info['name'] = !empty($info['name']) ? $info['name'] : '';
  86. $info['mobile'] = !empty($info['mobile']) ? $info['mobile'] : '';
  87. $info['department'] = !empty($info['department']) ? implode(',', $info['department']) : '';
  88. $info['order_department'] = !empty($info['order']) ? implode(',', $info['order']) : '';
  89. $info['position'] = !empty($info['position']) ? $info['position'] : '';
  90. $info['gender'] = !empty($info['gender']) ? $info['gender'] : '';
  91. $info['email'] = !empty($info['email']) ? $info['email'] : '';
  92. $info['biz_mail'] = !empty($info['biz_mail']) ? $info['biz_mail'] : '';
  93. $info['is_leader_in_dept'] = !empty($info['is_leader_in_dept']) ? implode(',', $info['is_leader_in_dept']) : '';
  94. $info['direct_leader'] = !empty($info['direct_leader']) ? implode(',', $info['direct_leader']) : '';
  95. $info['avatar'] = !empty($info['avatar']) ? $info['avatar'] : '';
  96. $info['thumb_avatar'] = !empty($info['thumb_avatar']) ? $info['thumb_avatar'] : '';
  97. $info['telephone'] = !empty($info['telephone']) ? $info['telephone'] : '';
  98. $info['alias'] = !empty($info['alias']) ? $info['alias'] : '';
  99. $info['extattr'] = !empty($info['extattr']) ? json_encode($info['extattr']) : '';
  100. $info['status'] = !empty($info['status']) ? $info['status'] : '';
  101. $info['qr_code'] = !empty($info['qr_code']) ? $info['qr_code'] : '';
  102. $info['external_profile'] = !empty($info['external_profile']) ? json_encode($info['external_profile']) : '';
  103. $info['external_position'] = !empty($info['external_position']) ? $info['external_position'] : '';
  104. $info['address'] = !empty($info['address']) ? $info['address'] : '';
  105. $info['open_userid'] = !empty($info['open_userid']) ? $info['open_userid'] : '';
  106. $info['main_department'] = !empty($info['main_department']) ? $info['main_department'] : '';
  107. $info['chat_record'] = 0;
  108. $wx_result = WeworksingleUser::create($info);
  109. $wx_uid = $wx_result->id;
  110. } else {
  111. $wx_uid = $wx_result->id;
  112. }
  113. if (count($company_ids) > 1) {
  114. return json(['code'=> 3, 'msg'=> '请选择要进入的企业', 'data'=> ['wx_uid'=> $wx_uid]]);
  115. } else {
  116. $wx_result->company_id = $company_ids[0];
  117. $wx_result->save();
  118. return json(['code'=> 2, 'msg'=> '请先登录', 'data'=> ['wx_uid'=> $wx_uid, 'company_id'=> $company_ids[0]]]);
  119. }
  120. } else {
  121. $bind_count = 0; //判断这多个用户信息绑定了几家店面
  122. $weworksingle_uid = array_column($users, 'id');
  123. $bind_employee = Employee::where([['weworksingle_uid', 'in', $weworksingle_uid], ['state', '=', '在职']])->order('updatetime desc')->select();
  124. $bind_count = $bind_employee->count();
  125. if ($bind_count > 0){ //多店面账号 和 单一账号都默认最近登录的账号进入
  126. // 找最近登录的账号默认进入
  127. $wx_uid = $bind_employee[0]['weworksingle_uid'];
  128. foreach ($users as $u) {
  129. if ($u['id'] == $wx_uid){
  130. $company_id = $u['company_id'];
  131. }
  132. }
  133. } else {
  134. //没有有效用户,去登陆 离职、审核中、企业微信没绑定 这些用户
  135. $wx_uid = implode(',', array_column($users, 'id'));
  136. if (count($company_ids) > 1) {
  137. return json(['code'=> 3, 'msg'=> '请选择要进入的企业', 'data'=> ['wx_uid'=> $wx_uid]]);
  138. } else {// 企业微信没绑定
  139. return json(['code'=> 2, 'msg'=> '请先登录', 'data'=> ['wx_uid'=> $wx_uid, 'company_id'=> $company_ids[0]]]);
  140. }
  141. }
  142. }
  143. // 先判断公司账号情况
  144. $company = Company::where(['id'=> $company_id])->find();
  145. if ($company['status'] == 1) {
  146. return json(['code' => 2, 'msg' => '集团账号被禁用,请联系管理员', 'data'=> ['wx_uid'=> $wx_uid, 'company_id'=> $company_id]]);
  147. } elseif ($company['end_date'] . ' 23:59:59' < date('Y-m-d H:i:s', time())) {
  148. return json(['code' => 2, 'msg' => '集团账号已过期,请联系管理员', 'data'=> ['wx_uid'=> $wx_uid, 'company_id'=> $company_id]]);
  149. }
  150. // 查询是否有绑定员工
  151. $employee = Employee::where('weworksingle_uid', '=', $wx_uid)->find();
  152. $employee->save(['updatetime' => date('Y-m-d H:i:s')]);
  153. // 查询到员工,返回token
  154. $token = [
  155. 'root_org' => $employee['root_id'],
  156. 'isEmployee' => true,
  157. 'uid' => $employee['uid'],
  158. 'employee_id'=> $employee['id'],
  159. 'org_id' => $employee['org_id'],
  160. 'isManager' => $employee['is_manager']
  161. ];
  162. $logic = new UserLogic();
  163. $user = $logic->getInfo([['id', '=', $employee['uid']]], ['id', 'nickname', 'headimgurl', 'sex', 'subscribe', 'phone']);
  164. $company = Company::where('root_id', $employee['root_id'])->find();
  165. $company['client_type'] = Miniprogram::where('root_id', '=', $employee['root_id'])->value('notify');
  166. $token['client_type'] = $company['client_type'];
  167. // 查询是设计部门还是销售部门
  168. $orgType = Org::where('id', $employee->org_id)->value('org_type');
  169. $token['org_type'] = $orgType;
  170. // 信息加密
  171. $data = http_build_query($token);
  172. $aes = new Aes(config('app.jwt_key'));
  173. $key = $aes->encrypt($data);
  174. // token数据设置
  175. $payload = array(
  176. "iss" => "https://" . request()->domain(),
  177. "aud" => 'mini',
  178. "iat" => time(),
  179. "nbf" => time(),
  180. "data" => $key
  181. );
  182. // 自定义登陆状态
  183. $token = JWT::encode($payload, config('app.jwt_key'));
  184. $returnData = ['code' => self::success, 'token' => $token, 'user' => $user, 'company' =>$company->company_name, 'company_data'=>$company];
  185. return json($returnData);
  186. }
  187. /**
  188. * 根据ticket获取绑定的企业列表
  189. */
  190. public function getCompanyByTicket(){
  191. $ticket = input('ticket', '', 'trim');
  192. $company_ids = WeworksingleCompanySetting::where('ticket', '=', $ticket)->column('company_id');
  193. $companyList = Company::where([['id', 'in', $company_ids]])->field('id,company_name,logo,status,end_date')->select()->toArray();
  194. foreach ($companyList as $k => $v) {
  195. if ($v['status'] == 1 || $v['end_date'] < date('Y-m-d')) {
  196. unset($companyList[$k]);
  197. }
  198. }
  199. return json(['code' => 0, 'data' => array_values($companyList)]);
  200. }
  201. /**
  202. * 获取手机验证码
  203. */
  204. public function sms($phone)
  205. {
  206. $content = '验证码:%code%(请勿转告他人),有效时间15分钟,请尽快完成验证';
  207. $smsLogic = new SmsLogic();
  208. $rs = $smsLogic->sendSms($phone, 'employee_login_phone', $content);
  209. if (!$rs) return json(['code' => 1, 'msg' => '短信发送失败']);
  210. return json(['code' => 0, 'msg' => '短信发送成功']);
  211. }
  212. /**
  213. * 手机号验证码登陆
  214. */
  215. public function phone_login($phone)
  216. {
  217. $aec = new Aec(config('app.aec_key'), config('app.aec_iv'));
  218. $phone = $aec->encrypt($phone);
  219. $wx_uid = input('wx_uid', '', 'trim');
  220. $company_id = input('company_id', '', 'intval');
  221. $wx_user = WeworksingleUser::where([['id', 'in', $wx_uid], ['company_id', '=', $company_id]])->findOrEmpty();
  222. if ($wx_user->isEmpty()) {
  223. // 首次绑定
  224. $wx_user = WeworksingleUser::where([['id', 'in', $wx_uid], ['company_id', '=', 0]])->findOrEmpty();
  225. if ($wx_user->isEmpty()){
  226. return json(['code' => self::error_msg, 'msg' => '账号异常']);
  227. } else {
  228. $wx_user->company_id = $company_id;
  229. $wx_user->save();
  230. }
  231. }
  232. $company = Company::where(['id'=> $company_id])->find();
  233. if ($company['status'] == 1) {
  234. return json(['code' => self::error_msg, 'msg' => '账号被禁用,请联系管理员']);
  235. } elseif ($company['end_date'] . ' 23:59:59' < date('Y-m-d H:i:s', time())) {
  236. return json(['code' => self::error_msg, 'msg' => '账号已过期,请联系管理员']);
  237. }
  238. $employee = Employee::where([['phone', '=', $phone], ['root_id', '=', $company['root_id']], ['state', '=', '在职'], ['uid', '>', 0]])->find();
  239. if (empty($employee)) return json(['code' => self::error_msg, 'msg' => '未查询到此账号']);
  240. $employee->weworksingle_uid = $wx_user->id; // 关联企业微信用户信息到系统用户
  241. $employee->updatetime = date('Y-m-d H:i:s');
  242. $employee->save();
  243. // 查询到员工,返回token
  244. $token = [
  245. 'root_org' => $employee['root_id'],
  246. 'isEmployee' => true,
  247. 'uid' => $employee['uid'],
  248. 'employee_id'=> $employee['id'],
  249. 'org_id' => $employee['org_id'],
  250. 'isManager' => $employee['is_manager']
  251. ];
  252. $logic = new UserLogic();
  253. $user = $logic->getInfo([['id', '=', $employee['uid']]], ['id', 'nickname', 'headimgurl', 'sex', 'subscribe', 'phone']);
  254. $company = Company::where('root_id', $employee['root_id'])->find();
  255. $company['client_type'] = Miniprogram::where('root_id', '=', $employee['root_id'])->value('notify');
  256. $token['client_type'] = $company['client_type'];
  257. // 查询是设计部门还是销售部门
  258. $orgType = Org::where('id', $employee->org_id)->value('org_type');
  259. $token['org_type'] = $orgType;
  260. // 信息加密
  261. $data = http_build_query($token);
  262. $aes = new Aes(config('app.jwt_key'));
  263. $key = $aes->encrypt($data);
  264. // token数据设置
  265. $payload = array(
  266. "iss" => "https://" . request()->domain(),
  267. "aud" => 'mini',
  268. "iat" => time(),
  269. "nbf" => time(),
  270. "data" => $key
  271. );
  272. // 自定义登陆状态
  273. $token = JWT::encode($payload, config('app.jwt_key'));
  274. $returnData = ['code' => self::success, 'token' => $token, 'user' => $user, 'company' =>$company->company_name, 'company_data'=>$company];
  275. return json($returnData);
  276. }
  277. public function company()
  278. {
  279. $ticket = input('ticket', '', 'trim');
  280. if (empty($ticket)) {
  281. return json(['code' => 0, 'data' => []]);
  282. }
  283. $token = $this->request->token;
  284. // 用token中的openid获取用户的uid列表
  285. $uidList = User::where(['mini_openid' => $token['openid']])->column('id');
  286. $employees = Employee::where([['uid', 'in', $uidList], ['state', '=', '在职']])->column('root_id, is_manager, org_id', 'root_id');
  287. $orgs = Org::where([['id', 'in', array_column($employees, 'org_id')]])->column('id,name', 'id');
  288. $notifyList = Miniprogram::where([['root_id', 'in', array_column($employees, 'root_id')]])->column('root_id,notify', 'root_id');
  289. $company_ids = WeworksingleCompanySetting::where('ticket', '=', $ticket)->column('company_id');
  290. $companyList = Company::with(['brand'])->where([['root_id', 'in', array_column($employees, 'root_id')], ['id', 'in', $company_ids]])->select()->visible(['company_name', 'root_id','status','end_date'])->toArray();
  291. foreach ($companyList as &$item) {
  292. $item['client_type'] = isset($notifyList[$item['root_id']]) ? $notifyList[$item['root_id']]['notify'] : '';
  293. $item['is_manager'] = isset($employees[$item['root_id']]) ? $employees[$item['root_id']]['is_manager'] : 0;
  294. $item['org_name'] = (isset($employees[$item['root_id']]) && isset($orgs[$employees[$item['root_id']]['org_id']])) ? $orgs[$employees[$item['root_id']]['org_id']]['name'] : '';
  295. if ($item['status']==1) {
  296. $item['off'] = 1;
  297. $item['off_remark'] = '账号被禁用';
  298. }elseif ($item['end_date']<date('Y-m-d')) {
  299. $item['off'] = 1;
  300. $item['off_remark'] = '账号已过期';
  301. }else{
  302. $item['off'] = 0;
  303. $item['off_remark'] = '账号正常';
  304. }
  305. }
  306. return json(['code' => self::success, 'data' => $companyList]);
  307. }
  308. /**
  309. * 切换店面
  310. */
  311. public function changeCompany(){
  312. $company_id = input('company_id', '', 'intval');
  313. $company_info = Company::where('id', $company_id)->find();
  314. if ($company_info['end_date'] < date('Y-m-d') || $company_info['status'] == 1) { //账号过期或关闭
  315. return json(['code'=> self::error_msg, 'msg'=> '店面账号异常']);
  316. }
  317. $token = $this->request->token;
  318. $wx_uid = Employee::where('id', '=', $token['employee_id'])->value('weworksingle_uid');
  319. $wx_user = WeworksingleUser::where('id', '=', $wx_uid)->findOrEmpty();
  320. if ($wx_user->isEmpty()) {
  321. return json(['code'=> self::error_msg, 'msg'=> '操作失败']);
  322. }
  323. $old_user = User::where('id', '=', $token['uid'])->find();
  324. // 选择的企业
  325. $company_root = Company::where('id', '=', $company_id)->value('root_id');
  326. $uidList = User::where([['mini_openid', '=', $old_user['mini_openid']], ['root_id', '=', $company_root]])->column('id');
  327. if (count($uidList) == 0) {
  328. $employee = null;
  329. } else {
  330. $condition = [['uid', 'in', $uidList], ['state', 'in', ['在职']]];
  331. $employee = Employee::where($condition)->order('updatetime desc')->find();
  332. }
  333. if (empty($employee)) {
  334. return json(['code'=> self::error_msg, 'msg'=> '操作失败', 'data'=> []]);
  335. } else {
  336. $employee->updatetime = date('Y-m-d H:i:s');
  337. $employee->save();
  338. }
  339. //企业微信用户表信息copy
  340. $company_user = WeworksingleUser::where([['userid', '=', $wx_user['userid']], ['company_id', '=', $company_id]])->findOrEmpty();
  341. if ($company_user->isEmpty()){
  342. $data = $wx_user;
  343. unset($data['id']);
  344. $data['company_id'] = $company_id;
  345. WeworksingleUser::create($data);
  346. }
  347. $user = User::where('id', '=', $employee['uid'])->find();
  348. $miniType = Miniprogram::where('root_id', '=', $employee['root_id'])->value('notify');
  349. // 初始token
  350. $token = [
  351. 'client_type' => $miniType,
  352. 'root_org' => $employee['root_id'],
  353. 'isEmployee' => true,
  354. 'uid' => $employee['uid'],
  355. 'employee_id'=> $employee['id'],
  356. 'org_id' => $employee['org_id'],
  357. 'isManager' => $employee['is_manager']
  358. ];
  359. // 查询是设计部门还是销售部门
  360. $orgType = Org::where('id', $employee->org_id)->value('org_type');
  361. $token['org_type'] = $orgType;
  362. $user->updatetime = date('Y-m-d H:i:s');
  363. $user->save();
  364. $logic = new UserLogic();
  365. $user = $logic->getInfo([['id', '=', $employee['uid']]], ['id', 'nickname', 'headimgurl', 'sex', 'subscribe', 'phone']);
  366. $company = Company::where('root_id', $employee['root_id'])->find();
  367. $company['client_type'] = $miniType;
  368. // 信息加密
  369. $data = http_build_query($token);
  370. $aes = new Aes(config('app.jwt_key'));
  371. $key = $aes->encrypt($data);
  372. // token数据设置
  373. $payload = array(
  374. "iss" => "https://" . request()->domain(),
  375. "aud" => 'mini',
  376. "iat" => time(),
  377. "nbf" => time(),
  378. "data" => $key
  379. );
  380. // 自定义登陆状态
  381. $token = JWT::encode($payload, config('app.jwt_key'));
  382. $returnData = ['code' => self::success, 'token' => $token, 'user' => $user, 'company' =>$company->company_name, 'company_data'=>$company];
  383. return json($returnData);
  384. }
  385. /**
  386. * 企业微信和员工账号解绑
  387. */
  388. public function unbind(){
  389. $token = $this->request->token;
  390. $employee = Employee::where('id', '=', $token['employee_id'])->find();
  391. $employee->weworksingle_uid = '';
  392. $result = $employee->save();
  393. if ($result){
  394. return json(['code'=> self::success, 'msg'=> '解绑成功']);
  395. } else {
  396. return json(['code'=> self::error_msg, 'msg'=> '操作失败']);
  397. }
  398. }
  399. /**
  400. * 返回JS-SDK所需配置
  401. */
  402. public function getJsSdk(){
  403. $url = input('url', '', 'trim');
  404. $root_org = $this->request->token['root_org'];
  405. $company_id = Company::where('root_id', '=', $root_org)->value('id');
  406. $setting = WeworksingleCompanySetting::where('company_id', '=', $company_id)->find();
  407. if (empty($setting)) {
  408. return json(['code'=> self::error_msg, 'msg'=> '请求失败']);
  409. }
  410. $config['corp_id'] = $setting['corp_id'];
  411. $config['agent_id'] = $setting['agentid'];
  412. $config['secret'] = $setting['agent_secret'];
  413. $app = Factory::work($config);
  414. $jssdk = $app->jssdk->buildConfig([],false, false, false, [], $url);
  415. return json(['code'=> self::success, 'data'=> $jssdk, 'msg'=> '请求成功']);
  416. }
  417. /**
  418. * 返回应用的JS-SDK所需配置
  419. */
  420. public function getAgentJsSdk(){
  421. $url = input('url', '', 'trim');
  422. $root_org = $this->request->token['root_org'];
  423. $company_id = Company::where('root_id', '=', $root_org)->value('id');
  424. $setting = WeworksingleCompanySetting::where('company_id', '=', $company_id)->find();
  425. if (empty($setting)) {
  426. return json(['code'=> self::error_msg, 'msg'=> '请求失败']);
  427. }
  428. $config['corp_id'] = $setting['corp_id'];
  429. $config['agent_id'] = $setting['agentid'];
  430. $config['secret'] = $setting['agent_secret'];
  431. $app = Factory::work($config);
  432. $jssdk = $app->jssdk->buildAgentConfig([], $setting['agentid'], true, false, false, [], $url);
  433. return json(['code'=> self::success, 'data'=> $jssdk, 'msg'=> '请求成功']);
  434. }
  435. /**
  436. * 获取某位员工的外部联系人列表
  437. */
  438. public function getExternalContact(){
  439. $search = $this->request->param('name', '', 'trim');
  440. $external_userid = $this->request->param('external_userid', '', 'trim');
  441. $page = $this->request->param('page', 1, 'intval');
  442. $employee_id = $this->request->token['employee_id'];
  443. $employee = Employee::find($employee_id)->toArray();
  444. $wx_user = WeworksingleUser::find($employee['weworksingle_uid']);
  445. if (empty($wx_user)){
  446. return json(['code'=> self::error_msg, 'msg'=> '获取失败']);
  447. }
  448. $config = WeworksingleCompanySetting::where('company_id', '=', $wx_user['company_id'])->find();
  449. if (empty($config['customer_secret']) || empty($config['customer_token']) || empty($config['customer_aes_key'])){
  450. return json(['code'=> self::error_msg, 'msg'=> '获取失败']);
  451. }
  452. $customer_config['corp_id'] = $config['corp_id'];
  453. $customer_config['secret'] = $config['customer_secret'];
  454. $customer_config['token'] = $config['customer_token'];
  455. $customer_config['aes_key'] = $config['customer_aes_key'];
  456. // 外部联系人id
  457. /*$external_ids_result = Factory::work($customer_config)->external_contact->list($wx_user['userid']);
  458. $external_ids = $external_ids_result['external_userid'];*/
  459. // 外部联系人拉取并更新
  460. $app = (new apiSingle($customer_config));
  461. $external_list = $app->getCustomerDetailByUser([$wx_user['userid']]);
  462. $old_list = (new WeworksingleCustomer())->where('userid', '=', $wx_user['userid'])->select()->toArray();
  463. $save_data = []; // 需要保存的数组
  464. foreach ($external_list as $k => $v) {
  465. unset($data);
  466. $data['customer_id'] = 0;
  467. // 如果用户存在,则默认更新
  468. foreach ($old_list as $h_k => $h_v){
  469. if ($v['external_contact']['external_userid'] == $h_v['external_userid'] && $v['follow_info']['userid'] == $h_v['userid']) {
  470. $data['id'] = $h_v['id'];
  471. $data['customer_id'] = $h_v['customer_id'];
  472. unset($old_list[$h_k]); // 匹配到则删除,剩余的为被删除的客户。
  473. }
  474. }
  475. $data['userid'] = $wx_user['userid'];
  476. $data['employee_id'] = $employee_id;
  477. $data['company_id'] = $wx_user['company_id'];
  478. $data['external_userid'] = !empty($v['external_contact']['external_userid']) ? $v['external_contact']['external_userid'] : '';
  479. $data['status'] = 0;
  480. $data['name'] = !empty($v['external_contact']['name']) ? $v['external_contact']['name'] : '';
  481. $data['avatar'] = !empty($v['external_contact']['avatar']) ? $v['external_contact']['avatar'] : '';
  482. $data['type'] = !empty($v['external_contact']['type']) ? $v['external_contact']['type'] : '';
  483. $data['gender'] = !empty($v['external_contact']['gender']) ? $v['external_contact']['gender'] : '';
  484. $data['unionid'] = !empty($v['external_contact']['unionid']) ? $v['external_contact']['unionid'] : '';
  485. $data['position'] = !empty($v['external_contact']['position']) ? $v['external_contact']['position'] : '';
  486. $data['corp_name'] = !empty($v['external_contact']['corp_name']) ? $v['external_contact']['corp_name'] : '';
  487. $data['corp_full_name'] = !empty($v['external_contact']['corp_full_name']) ? $v['external_contact']['corp_full_name'] : '';
  488. $data['external_profile'] = !empty($v['external_contact']['external_profile']) ? json_encode($v['external_contact']['external_profile']) : '';
  489. $data['remark'] = !empty($v['follow_info']['remark']) ? $v['follow_info']['remark'] : '';
  490. $data['description'] = !empty($v['follow_info']['description']) ? $v['follow_info']['description'] : '';
  491. $data['createtime'] = !empty($v['follow_info']['createtime']) ? $v['follow_info']['createtime'] : '';
  492. $data['tags'] = !empty($v['follow_info']['tag_id']) ? json_encode($v['follow_info']['tag_id']) : '';
  493. $data['remark_corp_name'] = !empty($v['follow_info']['remark_corp_name']) ? $v['follow_info']['remark_corp_name'] : '';
  494. $data['remark_mobiles'] = !empty($v['follow_info']['remark_mobiles']) ? implode(',', $v['follow_info']['remark_mobiles']) : '';
  495. $data['add_way'] = !empty($v['follow_info']['add_way']) ? $v['follow_info']['add_way'] : '';
  496. $data['oper_userid'] = !empty($v['follow_info']['oper_userid']) ? $v['follow_info']['oper_userid'] : '';
  497. $data['state'] = !empty($v['follow_info']['state']) ? $v['follow_info']['state'] : '';
  498. $save_data[] = $data;
  499. }
  500. // 被删除的客户
  501. if (!empty($old_list)){
  502. foreach ($old_list as $k => $v){
  503. unset($data);
  504. if ($v['status'] !== 1) {
  505. //
  506. $data['status'] = 1;
  507. $data['deletetime'] = date('Y-m-d H:i:s', time());
  508. $data['id'] = $v['id'];
  509. $save_data[] = $data;
  510. }
  511. }
  512. }
  513. // 更新此用户的所有外部联系人状态
  514. (new WeworksingleCustomer())->saveAll($save_data);
  515. $where[] = ['status', '=', 0];
  516. $where[] = ['employee_id', '=', $employee_id];
  517. $where[] = ['customer_id', '=', 0];
  518. if ($search) {
  519. $where[] = ['name', 'like', '%'.$search.'%'];
  520. }
  521. if ($external_userid) {
  522. $where[] = ['external_userid', '=', $external_userid];
  523. }
  524. $list = WeworksingleCustomer::where($where)->page($page, 10)->select();
  525. return json(['code'=> self::success, 'data'=> $list, 'msg'=> '请求成功']);
  526. }
  527. /**
  528. * 通过手机号返回此员工名下对应的客户ID
  529. */
  530. public function getCustomerByPhone(){
  531. $phone = input('phone', '', 'trim');
  532. if (empty($phone)) {
  533. return json(['code'=> self::error_msg, 'msg'=> '请输入手机号']);
  534. }
  535. $phone = cypherphone($phone);
  536. $orgids = orgSubIds($this->request->token['root_org']);
  537. $c_where = [
  538. ['phone', '=', $phone],
  539. ['org_id', 'in', $orgids],
  540. ['employee_id', '=', $this->request->token['employee_id']]
  541. ];
  542. $customer = Customer::where($c_where)->find();
  543. if (empty($customer)) {
  544. return json(['code'=> self::success, 'msg'=> '未匹配到客户', 'data'=> []]);
  545. } else {
  546. $external_where['customer_id'] = $customer['id'];
  547. $external_where['employee_id'] = $this->request->token['employee_id'];
  548. $external_find = WeworksingleCustomer::where($external_where)->find();
  549. if (!empty($external_find)) {
  550. if ($external_find['status'] == 1) {
  551. // 该外部联系人被删除,可以选择绑定新的外部联系人
  552. $external_find->customer_id = 0;
  553. $external_find->save();
  554. } else {
  555. return json(['code'=> self::error_msg, 'msg'=> '该客户已绑定', 'data'=> []]);
  556. }
  557. }
  558. return json(['code'=> self::success, 'msg'=> '请求成功', 'data'=> $customer]);
  559. }
  560. }
  561. /**
  562. * 企业微信外部联系人绑定已有客户
  563. */
  564. public function bindCustomer(){
  565. $external_userid = $this->request->param('external_userid', '', 'trim');
  566. $employee_id = $this->request->token['employee_id'];
  567. $phone = $this->request->param('phone', '', 'trim');
  568. if (empty($external_userid) || empty($phone)) {
  569. return json(['code'=> self::error_msg, 'msg'=> '绑定失败']);
  570. }
  571. $phone = cypherphone($phone);
  572. $orgids = orgSubIds($this->request->token['root_org']);
  573. $c_where = [
  574. ['phone', '=', $phone],
  575. ['org_id', 'in', $orgids]
  576. ];
  577. $customer = Customer::where($c_where)->find();
  578. if (empty($customer)) {
  579. return json(['code'=> self::error_msg, 'msg'=> '客户不存在,请手动添加']);
  580. } else {
  581. // 属于本员工( 或者 无人跟进且此客户属于本组织 此情况排除)
  582. if ($customer['employee_id'] == $employee_id) {
  583. // 先查询是否有之前的绑定数据,清除
  584. WeworksingleCustomer::where('customer_id', '=', $customer['id'])->save(['customer_id'=> 0]);
  585. // 匹配上客户则绑定
  586. $where['external_userid'] = $external_userid;
  587. $where['employee_id'] = $employee_id;
  588. $result = WeworksingleCustomer::where($where)->save(['customer_id'=> $customer['id']]);
  589. // Customer::where('id', '=', $customer['id'])->save(['employee_id'=> $employee_id]); // 客户自动领取
  590. if ($result !== false) {
  591. return json(['code'=> self::success, 'msg'=> '绑定成功']);
  592. } else {
  593. return json(['code'=> self::error_msg, 'msg'=> '绑定失败']);
  594. }
  595. } else {
  596. return json(['code'=> self::error_msg, 'msg'=> '绑定失败']);
  597. }
  598. }
  599. }
  600. /**
  601. * 根据外部联系人userid返回系统内对应的客户信息
  602. */
  603. public function getCustomerByExternalUid(){
  604. $externalUid = input('uid', '', 'trim');
  605. $employee_id = $this->request->token['employee_id'];
  606. $where['employee_id'] = $employee_id;
  607. $where['external_userid'] = $externalUid;
  608. $find = WeworksingleCustomer::where($where)->find();
  609. if (empty($find)) {
  610. // 判断系统内是否有这个外部联系人,没有则拉取
  611. $wx_uid = Employee::where('id','=', $employee_id)->value('weworksingle_uid');
  612. if (!empty($wx_uid)) {
  613. // 企业微信用户
  614. $wx_user = WeworksingleUser::find($wx_uid);
  615. $e_where['userid'] = $wx_user['userid'];
  616. $e_where['external_userid'] = $externalUid;
  617. $e_find = WeworksingleCustomer::where($e_where)->find();
  618. if (empty($e_find)) {
  619. $root_org = $this->request->token['root_org'];
  620. $company_id = Company::where('root_id', '=', $root_org)->value('id');
  621. $setting = WeworksingleCompanySetting::where('company_id', '=', $company_id)->find();
  622. if (!empty($setting)) {
  623. $config['corp_id'] = $setting['corp_id'];
  624. $config['agent_id'] = $setting['agentid'];
  625. $config['secret'] = $setting['customer_secret'];
  626. $config['token'] = $setting['customer_token'];
  627. $config['aes_key'] = $setting['customer_aes_key'];
  628. $app = (new apiSingle($config));
  629. $external_info = $app->getCustomerDetailById($externalUid);
  630. $data['userid'] = $wx_user['userid'];
  631. $data['employee_id'] = $employee_id;
  632. $data['company_id'] = $company_id;
  633. $data['customer_id'] = 0;
  634. $data['external_userid'] = $externalUid;
  635. $data['status'] = 0;
  636. $data['deletetime'] = null;
  637. $data['name'] = !empty($external_info['external_contact']['name']) ? $external_info['external_contact']['name'] : '';
  638. $data['avatar'] = !empty($external_info['external_contact']['avatar']) ? $external_info['external_contact']['avatar'] : '';
  639. $data['type'] = !empty($external_info['external_contact']['type']) ? $external_info['external_contact']['type'] : '';
  640. $data['gender'] = !empty($external_info['external_contact']['gender']) ? $external_info['external_contact']['gender'] : '';
  641. $data['unionid'] = !empty($external_info['external_contact']['unionid']) ? $external_info['external_contact']['unionid'] : '';
  642. $data['position'] = !empty($external_info['external_contact']['position']) ? $external_info['external_contact']['position'] : '';
  643. $data['corp_name'] = !empty($external_info['external_contact']['corp_name']) ? $external_info['external_contact']['corp_name'] : '';
  644. $data['corp_full_name'] = !empty($external_info['external_contact']['corp_full_name']) ? $external_info['external_contact']['corp_full_name'] : '';
  645. $data['external_profile'] = !empty($external_info['external_contact']['external_profile']) ? json_encode($external_info['external_contact']['external_profile']) : '';
  646. foreach ($external_info['follow_user'] as $v){
  647. if ($v['userid'] == $wx_user['userid']) {
  648. $data['remark'] = !empty($v['remark']) ? $v['remark'] : '';
  649. $data['description'] = !empty($v['description']) ? $v['description'] : '';
  650. $data['createtime'] = !empty($v['createtime']) ? $v['createtime'] : '';
  651. $data['tags'] = !empty($v['tags']) ? json_encode($v['tags']) : '';
  652. $data['remark_corp_name'] = !empty($v['remark_corp_name']) ? $v['remark_corp_name'] : '';
  653. $data['remark_mobiles'] = !empty($v['remark_mobiles']) ? implode(',', $v['remark_mobiles']) : '';
  654. $data['add_way'] = !empty($v['add_way']) ? $v['add_way'] : '';
  655. $data['oper_userid'] = !empty($v['oper_userid']) ? $v['oper_userid'] : '';
  656. $data['state'] = !empty($v['state']) ? $v['state'] : '';
  657. }
  658. }
  659. WeworksingleCustomer::create($data);
  660. }
  661. } else {
  662. $data['id'] = $e_find['id'];
  663. $data['status'] = 0;
  664. $data['deletetime'] = null;
  665. $e_find->save($data);
  666. }
  667. }
  668. return json(['code'=> self::success, 'msg'=> '请求成功', 'data'=> '']);
  669. } else {
  670. return json(['code'=> self::success, 'msg'=> '请求成功', 'data'=> $find['customer_id']]);
  671. }
  672. }
  673. public function sendMessage(){
  674. $msg = [
  675. 'external_userid' => [
  676. 'wmpEonCwAA1WyNGdGcPr5h7WO_Gy_elA',
  677. 'wmpEonCwAA9BWQW6_yFQ8YLgyrWidZ7g',
  678. ],
  679. 'sender' => 'WuHao',
  680. 'text' => [
  681. 'content' => '此条是测试消息',
  682. ]/*,
  683. 'image' => [
  684. 'media_id' => 'MEDIA_ID',
  685. ],
  686. 'link' => [
  687. 'title' => '消息标题',
  688. 'picurl' => '',
  689. 'desc' => '消息描述',
  690. 'url' => 'https://example.link.com/path',
  691. ],
  692. 'miniprogram' => [
  693. 'title' => '消息标题',
  694. 'pic_media_id' => 'MEDIA_ID',
  695. 'appid' => 'wx8bd80126147df384',
  696. 'page' => '/path/index',
  697. ],*/
  698. ];
  699. $config = WeworksingleCompanySetting::where('company_id', '=', 2)->find();
  700. if (empty($config['customer_secret']) || empty($config['customer_token']) || empty($config['customer_aes_key'])){
  701. return json(['code'=> self::error_msg, 'msg'=> '发送失败']);
  702. }
  703. $customer_config['corp_id'] = $config['corp_id'];
  704. $customer_config['secret'] = $config['customer_secret'];
  705. $customer_config['token'] = $config['customer_token'];
  706. $customer_config['aes_key'] = $config['customer_aes_key'];
  707. $app = Factory::work($customer_config);
  708. $result = $app->external_contact_message->submit($msg);
  709. Log::record($result)->save();
  710. }
  711. /**
  712. * 获取客户聊天记录(企业微信)
  713. */
  714. public function getChatRecord(){
  715. $customer_id = input('customer_id', '', 'intval');
  716. $customer_id = input('customer_id', '', 'intval');
  717. $employee_id = request()->token['employee_id'];
  718. $p = input('page', 1, 'intval');
  719. $wework_customer = WeworksingleCustomer::where([['employee_id', '=', $employee_id], ['customer_id', '=', $customer_id]])->findOrEmpty();
  720. if ($wework_customer->isEmpty()) {
  721. return json(['code'=> 0, 'msg'=> 'success', 'data'=> []]);
  722. }
  723. $employee_uid = Employee::where('id', $employee_id)->value('weworksingle_uid');
  724. if (empty($employee_uid)) {
  725. return json(['code'=> 0, 'msg'=> 'success', 'data'=> []]);
  726. }
  727. $employee_user = WeworksingleUser::where('id', $employee_uid)->findOrEmpty();
  728. if ($employee_user->isEmpty()) {
  729. return json(['code'=> 0, 'msg'=> 'success', 'data'=> []]);
  730. }
  731. $company_id = Company::where('root_id', '=', request()->token['root_org'])->value('id');
  732. $where[] = ['msgtype', '<>', 'revoke'];
  733. $where[] = ['company_id', '=', $company_id];
  734. $where[] = ['msgfrom', 'in', [$employee_user['userid'], $wework_customer['external_userid']]];
  735. $where[] = ['msgtype', 'not in', ['revoke', 'switch', 'meeting_voice_call']];
  736. $chat_list = WeworksingleChatRecord::with('chatFile')->where($where)->order('msgtime desc id desc')->field('id,msgid,action,msgfrom,msgtime,msgtype,content,json_content,is_recall')->page($p, 10)->select()->each(function($item) use ($wework_customer, $employee_user){
  737. $msgtime = strtotime(get_microtime_format($item['msgtime']));
  738. $item['msgtime'] = date('Y-m-d H:i:s', $msgtime);
  739. $item['json_content'] = json_decode($item['json_content'], 'true');
  740. $msgfrom = $item['msgfrom'];
  741. if ($wework_customer['external_userid'] == $msgfrom) {
  742. $item['msgfrom'] = $wework_customer['name'];
  743. $item['msg_loaction'] = 'left';
  744. } else if ($employee_user['userid'] == $msgfrom) {
  745. $item['msgfrom'] = $employee_user['name'];
  746. $item['msg_loaction'] = 'right';
  747. }
  748. // 判断聊天文件位置
  749. if (!empty($item['chatFile'])) {
  750. if ($item['chatFile']['is_local'] == 1) {
  751. $item['chatFile']['path'] = request()->domain() . '/' . $item['chatFile']['path'];
  752. } else {
  753. $ali_oss_bindurl = config('app.wework_ali_oss_bindurl');
  754. $url = 'https://' . $ali_oss_bindurl . '/';
  755. $item['chatFile']['path'] = $url . $item['chat_file']['oss_path'];
  756. }
  757. }
  758. switch ($item['msgtype']) {
  759. case 'text':
  760. $item['msgtype_name'] = '文本';
  761. break;
  762. case 'image':
  763. $item['msgtype_name'] = '图片';
  764. break;
  765. case 'revoke':
  766. $item['msgtype_name'] = '撤回消息';
  767. break;
  768. case 'agree':
  769. $item['msgtype_name'] = '同意会话聊天内容';
  770. break;
  771. case 'voice':
  772. $item['msgtype_name'] = '语音消息';
  773. break;
  774. case 'video':
  775. $item['msgtype_name'] = '视频消息';
  776. break;
  777. case 'card':
  778. $item['msgtype_name'] = '名片消息';
  779. break;
  780. case 'location':
  781. $item['msgtype_name'] = '位置消息';
  782. break;
  783. case 'emotion':
  784. $item['msgtype_name'] = '表情消息';
  785. $item['width'] = $item['json_content']['emotion']['width'] ?? 240;
  786. $item['height'] = $item['json_content']['emotion']['height'] ?? 240;
  787. break;
  788. case 'file':
  789. $item['msgtype_name'] = '文件消息';
  790. break;
  791. case 'link':
  792. $item['msgtype_name'] = '链接消息';
  793. break;
  794. case 'weapp':
  795. $item['msgtype_name'] = '小程序消息';
  796. break;
  797. case 'chatrecord':
  798. $item['msgtype_name'] = '会话记录消息';
  799. break;
  800. case 'todo':
  801. $item['msgtype_name'] = '待办消息';
  802. break;
  803. case 'vote':
  804. $item['msgtype_name'] = '投票消息';
  805. break;
  806. case 'collect':
  807. $item['msgtype_name'] = '填表消息';
  808. break;
  809. case 'redpacket':
  810. $item['msgtype_name'] = '红包消息';
  811. break;
  812. case 'meeting':
  813. $item['msgtype_name'] = '会议邀请消息';
  814. break;
  815. case 'docmsg':
  816. $item['msgtype_name'] = '在线文档消息';
  817. break;
  818. case 'markdown':
  819. $item['msgtype_name'] = '系统消息';
  820. break;
  821. case 'news':
  822. $item['msgtype_name'] = '图文消息';
  823. break;
  824. case 'calendar':
  825. $item['msgtype_name'] = '日程消息';
  826. break;
  827. case 'mixed':
  828. $item['msgtype_name'] = '混合消息';
  829. break;
  830. case 'meeting_voice_call':
  831. $item['msgtype_name'] = '音频存档消息';
  832. break;
  833. case 'voip_doc_share':
  834. $item['msgtype_name'] = '音频共享文档消息';
  835. break;
  836. case 'external_redpacket':
  837. $item['msgtype_name'] = '互通红包消息';
  838. if (!empty($item['json_content']['redpacket'])) {
  839. switch (intval($item['json_content']['redpacket']['type'])) {
  840. case 1:
  841. $item['redpacket_type'] = '普通红包';
  842. break;
  843. case 2:
  844. $item['redpacket_type'] = '拼手气群红包';
  845. break;
  846. case 3:
  847. $item['redpacket_type'] = '激励群红包';
  848. break;
  849. default:
  850. $item['redpacket_type'] = '普通红包';
  851. break;
  852. }
  853. $item['redpacket_wish'] = $item['json_content']['redpacket']['wish'];
  854. $item['redpacket_total'] = $item['json_content']['redpacket']['totalcnt'];
  855. $item['redpacket_totalamount'] = round($item['json_content']['redpacket']['totalcnt']/100, 2);
  856. } else {
  857. $item['redpacket_type'] = '未知';
  858. $item['redpacket_wish'] = '未知';
  859. $item['redpacket_total'] = '未知';
  860. $item['redpacket_totalamount'] = '未知';
  861. }
  862. break;
  863. case 'sphfeed':
  864. $item['msgtype_name'] = '视频号消息';
  865. break;
  866. case 'voiptext':
  867. // 音视频通话
  868. switch ($item['json_content']['info']['invitetype']) {
  869. case 1:
  870. $voiptext_name = '视频通话';
  871. break;
  872. case 2:
  873. $voiptext_name = '语音通话';
  874. break;
  875. case 3:
  876. $voiptext_name = '多人视频通话';
  877. break;
  878. case 4:
  879. $voiptext_name = '多人语音通话';
  880. break;
  881. default:
  882. $voiptext_name = '音视频通话';
  883. break;
  884. }
  885. $item['msgtype_name'] = $voiptext_name;
  886. $long = $item['json_content']['info']['callduration'];
  887. $long_s = $long > 60 ? $long % 60 : $long;
  888. $long_m = $long > 60 ? intval($long / 60) : 0;
  889. $item['content'] = $long_m > 0 ? $long_m . '分' . $long_s . '秒' : $long_s . '秒';
  890. break;
  891. case 'qydiskfile':
  892. // 微盘文件
  893. $once_msg['content'] = $msg['info']['filename'];
  894. break;
  895. default:
  896. $item['msgtype_name'] = '未知格式消息';
  897. break;
  898. }
  899. });
  900. return json(['code'=> 0, 'msg'=> 'success', 'data'=> $chat_list]);
  901. }
  902. }