WorkMemberServices.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. namespace app\services\work;
  12. use app\dao\work\WorkMemberDao;
  13. use app\jobs\work\WorkMemberJob;
  14. use app\services\BaseServices;
  15. use crmeb\services\wechat\config\WorkConfig;
  16. use crmeb\services\wechat\Work;
  17. use crmeb\traits\ServicesTrait;
  18. use think\exception\ValidateException;
  19. use think\facade\Log;
  20. use think\helper\Str;
  21. /**
  22. * 企业微信成员
  23. * Class WorkMemberServices
  24. * @package app\services\work
  25. * @mixin WorkMemberDao
  26. */
  27. class WorkMemberServices extends BaseServices
  28. {
  29. use ServicesTrait;
  30. const TABLE_FIELD = ['Name', 'MainDepartment', 'DirectLeader',
  31. 'Mobile', 'Position', 'Gender', 'Email', 'BizMail', 'Status', 'Avatar', 'Alias',
  32. 'Telephone', 'Address'];
  33. /**
  34. * WorkMemberServices constructor.
  35. * @param WorkMemberDao $dao
  36. */
  37. public function __construct(WorkMemberDao $dao)
  38. {
  39. $this->dao = $dao;
  40. }
  41. /**
  42. * 员工列表
  43. * @param array $where
  44. * @return array
  45. */
  46. public function getList(array $where)
  47. {
  48. [$page, $limit] = $this->getPageValue();
  49. $list = $this->dao->getDataList($where, ['*'], $page, $limit, 'create_time', [
  50. 'departmentRelation',
  51. 'clientFollow' => function ($query) {
  52. $query->group('userid')->where('is_del_user', 0)->field(['count(*) as sum_follow', 'userid']);
  53. },
  54. 'chat' => function ($query) {
  55. $query->group('userid')->field(['count(*) as sum_chat', 'userid']);
  56. },
  57. ]);
  58. $departmentIds = [];
  59. foreach ($list as &$item) {
  60. if (!empty($item['departmentRelation'])) {
  61. $item['departmentId'] = array_column($item['departmentRelation'], 'department');
  62. } else {
  63. $item['departmentId'] = [];
  64. }
  65. $departmentIds = array_merge($departmentIds, $item['departmentId']);
  66. }
  67. $departmentIds = array_merge(array_unique(array_filter($departmentIds)));
  68. if ($departmentIds) {
  69. /** @var WorkDepartmentServices $services */
  70. $services = app()->make(WorkDepartmentServices::class);
  71. $departmentList = $services->getColumn([
  72. ['department_id', 'in', $departmentIds],
  73. ], 'name', 'department_id');
  74. foreach ($list as &$item) {
  75. $department = [];
  76. foreach ($departmentList as $k => $v) {
  77. if (in_array($k, $item['departmentId'])) {
  78. $department[] = ['name' => $v, 'department' => $k];
  79. }
  80. }
  81. $item['department_list'] = $department;
  82. }
  83. }
  84. $count = $this->dao->count($where);
  85. return compact('list', 'count');
  86. }
  87. /**
  88. * 保存成员数据
  89. * @param array $members
  90. * @return bool
  91. */
  92. public function saveMember(array $members)
  93. {
  94. /** @var WorkConfig $config */
  95. $config = app()->make(WorkConfig::class);
  96. $corpId = $config->get('corpId');
  97. if (!$corpId) {
  98. return true;
  99. }
  100. /** @var WorkDepartmentServices $departmentService */
  101. $departmentService = app()->make(WorkDepartmentServices::class);
  102. $defaultDepartment = $departmentService->value(['corp_id' => $corpId, 'parentid' => 0], 'department_id');
  103. $this->transaction(function () use ($members, $corpId, $defaultDepartment) {
  104. $data = [];
  105. $relation = [];
  106. $other = [];
  107. $userids = array_column($members, 'userid');
  108. foreach ($members as $member) {
  109. if (isset($member['english_name'])) {
  110. unset($member['english_name']);
  111. }
  112. $address = $bizMail = '';
  113. if (isset($member['address'])) {
  114. $address = $member['address'];
  115. unset($member['address']);
  116. }
  117. if (isset($member['biz_mail'])) {
  118. $bizMail = $member['biz_mail'];
  119. unset($member['biz_mail']);
  120. }
  121. $member['address'] = $address;
  122. $member['biz_mail'] = $bizMail;
  123. if (isset($member['extattr']) && $member['extattr']) {
  124. $other[$member['userid']] = [
  125. 'extattr' => json_encode($member['extattr'] ?? []),
  126. 'external_profile' => json_encode($member['external_profile'] ?? []),
  127. ];
  128. }
  129. if (!empty($member['department'])) {
  130. foreach ($member['department'] as $i => $department) {
  131. $relation[$member['userid']][] = [
  132. 'department' => $member['department'][$i] ?? 0,
  133. 'srot' => $member['order'][$i] ?? 0,
  134. 'is_leader_in_dept' => $member['is_leader_in_dept'][$i] ?? 0
  135. ];
  136. }
  137. } else {
  138. //写入默认部门
  139. $relation[$member['userid']][] = ['department' => $defaultDepartment, 'srot' => 0, 'is_leader_in_dept' => 0];
  140. }
  141. $externalPosition = '';
  142. if (isset($member['external_position'])) {
  143. $externalPosition = $member['external_position'];
  144. unset($member['external_position']);
  145. }
  146. $member['external_position'] = $externalPosition;
  147. $member['direct_leader'] = json_encode($member['direct_leader']);
  148. $member['is_leader'] = $member['isleader'];
  149. $member['corp_id'] = $corpId;
  150. if (isset($member['external_profile'])) {
  151. unset($member['external_profile']);
  152. }
  153. unset($member['isleader'], $member['is_leader_in_dept'], $member['order'], $member['department'], $member['extattr']);
  154. if ($this->dao->count(['userid' => $member['userid'], 'corp_id' => $corpId])) {
  155. $this->dao->update(['userid' => $member['userid']], $member);
  156. } else {
  157. $member['create_time'] = time();
  158. $data[] = $member;
  159. }
  160. }
  161. //写入成员数据
  162. if ($data) {
  163. $this->dao->saveAll($data);
  164. }
  165. $userList = $this->dao->getColumn([['userid', 'in', $userids], ['corp_id', '=', $corpId]], 'id', 'userid');
  166. $userValueAll = array_values($userList);
  167. //写入关联数据
  168. if (count($relation)) {
  169. /** @var WorkMemberRelationServices $relationService */
  170. $relationService = app()->make(WorkMemberRelationServices::class);
  171. $relationService->delete([['member_id', 'in', $userValueAll]]);
  172. $saveRelation = [];
  173. foreach ($relation as $userid => $item) {
  174. $memberId = $userList[$userid];
  175. foreach ($item as $value) {
  176. $saveRelation[] = [
  177. 'member_id' => $memberId,
  178. 'create_time' => time(),
  179. 'department' => $value['department'],
  180. 'srot' => $value['srot'],
  181. 'is_leader_in_dept' => $value['is_leader_in_dept'],
  182. ];
  183. }
  184. }
  185. $relationService->saveAll($saveRelation);
  186. }
  187. //写入其他数据
  188. if (count($other)) {
  189. /** @var WorkMemberOtherServices $otherService */
  190. $otherService = app()->make(WorkMemberOtherServices::class);
  191. $otherService->delete([['member_id', 'in', $userValueAll]]);
  192. foreach ($other as $userid => &$item) {
  193. $memberId = $userList[$userid];
  194. $item['member_id'] = $memberId;
  195. }
  196. $otherService->saveAll($other);
  197. }
  198. });
  199. return true;
  200. }
  201. /**
  202. * 自动更新企业成员
  203. * @param int $departmentId
  204. */
  205. public function authUpdataMember(int $departmentId)
  206. {
  207. $res = Work::getDetailedDepartmentUsers($departmentId);
  208. $members = $res['userlist'] ?? [];
  209. $maxCount = 500;
  210. $sumCount = count($members);
  211. if ($sumCount > $maxCount) {
  212. $page = ceil($maxCount / $sumCount);
  213. for ($i = 1; $i < $page; $i++) {
  214. $res = collect($members)->slice($maxCount * $i, $maxCount)->toArray();
  215. WorkMemberJob::dispatchDo('save', [$res]);
  216. }
  217. } else {
  218. $this->saveMember($members);
  219. }
  220. }
  221. /**
  222. * 获取提交字段
  223. * @param array $payload
  224. * @return array
  225. */
  226. protected function getTableField(array $payload)
  227. {
  228. $data = [];
  229. foreach (self::TABLE_FIELD as $key) {
  230. $strKey = Str::snake($key);
  231. if (isset($payload[$strKey])) {
  232. $data[$strKey] = $payload[$strKey];
  233. }
  234. }
  235. return $data;
  236. }
  237. /**
  238. * 更新企业成员
  239. * @param array $payload
  240. * @return mixed
  241. */
  242. public function updateMember(array $payload)
  243. {
  244. $corpId = $payload['ToUserName'] ?? '';
  245. $userId = $payload['UserID'] ?? '';
  246. $updateData = $this->getTableField($payload);
  247. if (!empty($payload['NewUserID'])) {
  248. $updateData['userid'] = $payload['NewUserID'];
  249. }
  250. $memberInfo = Work::getMemberInfo($userId);
  251. if (0 !== $memberInfo['errcode']) {
  252. throw new ValidateException($memberInfo['errmsg']);
  253. }
  254. $extattr = $memberInfo['extattr'] ?? [];
  255. $externalProfile = $memberInfo['external_profile'] ?? [];
  256. unset($memberInfo['errcode'], $memberInfo['errmsg'], $memberInfo['department'],
  257. $memberInfo['order'], $memberInfo['is_leader_in_dept'], $memberInfo['extattr'],
  258. $memberInfo['external_profile']);
  259. $updateData = array_merge($updateData, $memberInfo);
  260. $memberId = $this->dao->value(['userid' => $userId], 'id');
  261. if ($memberId) {
  262. if ($updateData) {
  263. $dbCorpId = $this->dao->value(['userid' => $userId], 'corp_id');
  264. if (!$dbCorpId) {
  265. $updateData['corp_id'] = $corpId;
  266. }
  267. $this->dao->update(['corp_id' => $corpId, 'userid' => $userId], $updateData);
  268. }
  269. } else {
  270. if (!empty($payload['NewUserID'])) {
  271. $updateData['userid'] = $payload['NewUserID'];
  272. }
  273. $res = $this->dao->save($updateData);
  274. $memberId = $res->id;
  275. }
  276. /** @var WorkMemberRelationServices $relationServices */
  277. $relationServices = app()->make(WorkMemberRelationServices::class);
  278. $relationServices->saveMemberDepartment($memberId, $payload['IsLeaderInDept'] ?? '', $payload['Department'] ?? '');
  279. //写入其他数据
  280. if (!empty($extattr['attrs']) || !empty($externalProfile)) {
  281. /** @var WorkMemberOtherServices $otherService */
  282. $otherService = app()->make(WorkMemberOtherServices::class);
  283. $otherInfo = $otherService->get(['member_id' => $memberId]);
  284. if ($otherInfo) {
  285. $otherInfo->extattr = json_encode($extattr);
  286. $otherInfo->external_profile = json_encode($externalProfile);
  287. $otherInfo->save();
  288. } else {
  289. $otherService->save([
  290. 'member_id' => $memberId,
  291. 'extattr' => json_encode($extattr),
  292. 'external_profile' => json_encode($externalProfile),
  293. ]);
  294. }
  295. }
  296. return $memberId;
  297. }
  298. /**
  299. * 创建企业微信成员
  300. * @param array $payload
  301. * @return mixed
  302. */
  303. public function createMember(array $payload)
  304. {
  305. $corpId = $payload['ToUserName'] ?? '';
  306. if (!$corpId) {
  307. /** @var WorkConfig $config */
  308. $config = app()->make(WorkConfig::class);
  309. $corpId = $config->get('corpId');
  310. }
  311. $userId = $payload['UserID'] ?? '';
  312. $data = $this->getTableField($payload);
  313. $memberInfo = Work::getMemberInfo($userId);
  314. if (0 !== $memberInfo['errcode']) {
  315. throw new ValidateException($memberInfo['errmsg']);
  316. }
  317. $extattr = $memberInfo['extattr'] ?? [];
  318. $externalProfile = $memberInfo['external_profile'] ?? [];
  319. unset($memberInfo['errcode'], $memberInfo['errmsg'], $memberInfo['department'],
  320. $memberInfo['order'], $memberInfo['is_leader_in_dept'], $memberInfo['extattr'],
  321. $memberInfo['external_profile']);
  322. $data = array_merge($data, $memberInfo);
  323. $memberId = $this->dao->value(['userid' => $userId], 'id');
  324. if ($memberId) {
  325. if ($data) {
  326. $dbCorpId = $this->dao->value(['userid' => $userId], 'corp_id');
  327. if (!$dbCorpId) {
  328. $data['corp_id'] = $corpId;
  329. }
  330. $this->dao->update(['userid' => $userId], $data);
  331. }
  332. } else {
  333. $data['corp_id'] = $corpId;
  334. $res = $this->dao->save($data);
  335. $memberId = $res->id;
  336. }
  337. //记录
  338. $isLeaderInDept = $payload['IsLeaderInDept'] ?? '';
  339. $department = $payload['Department'] ?? '';
  340. if (!$department && !$isLeaderInDept) {
  341. //写入主部门
  342. /** @var WorkDepartmentServices $departmentService */
  343. $departmentService = app()->make(WorkDepartmentServices::class);
  344. $id = $departmentService->value(['corp_id' => $corpId, 'parentid' => 0], 'department_id');
  345. if ($id) {
  346. $department = (string)$id;
  347. $isLeaderInDept = '0';
  348. }
  349. }
  350. /** @var WorkMemberRelationServices $relationServices */
  351. $relationServices = app()->make(WorkMemberRelationServices::class);
  352. $relationServices->saveMemberDepartment($memberId, $isLeaderInDept, $department);
  353. //写入其他数据
  354. if (!empty($extattr['attrs']) || !empty($externalProfile)) {
  355. /** @var WorkMemberOtherServices $otherService */
  356. $otherService = app()->make(WorkMemberOtherServices::class);
  357. $otherInfo = $otherService->get(['member_id' => $memberId]);
  358. if ($otherInfo) {
  359. $otherInfo->extattr = json_encode($extattr);
  360. $otherInfo->external_profile = json_encode($externalProfile);
  361. $otherInfo->save();
  362. } else {
  363. $otherService->save([
  364. 'member_id' => $memberId,
  365. 'extattr' => json_encode($extattr),
  366. 'external_profile' => json_encode($externalProfile),
  367. ]);
  368. }
  369. }
  370. return $memberId;
  371. }
  372. /**
  373. * 删除企业微信成员
  374. * @param string $corpId
  375. * @param string $userid
  376. */
  377. public function deleteMember(string $corpId, string $userid)
  378. {
  379. $memberId = $this->dao->value(['corp_id' => $corpId, 'userid' => $userid], 'id');
  380. if ($memberId) {
  381. $this->transaction(function () use ($memberId) {
  382. /** @var WorkMemberRelationServices $relationServices */
  383. $relationServices = app()->make(WorkMemberRelationServices::class);
  384. $relationServices->delete(['member_id' => $memberId]);
  385. /** @var WorkMemberOtherServices $otherServices */
  386. $otherServices = app()->make(WorkMemberOtherServices::class);
  387. $otherServices->delete(['member_id' => $memberId]);
  388. $this->dao->delete($memberId);
  389. });
  390. }
  391. }
  392. /**
  393. * 用户注销解绑用户
  394. * @param int $uid
  395. */
  396. public function unboundUser(int $uid)
  397. {
  398. try {
  399. $this->dao->update(['uid' => $uid], ['uid' => 0]);
  400. } catch (\Throwable $e) {
  401. Log::error([
  402. 'message' => '解绑用户失败:' . $e->getMessage(),
  403. 'file' => $e->getFile(),
  404. 'line' => $e->getLine()
  405. ]);
  406. }
  407. }
  408. }