ActivityLogic.php 36KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846
  1. <?php
  2. /**
  3. * 活动逻辑类
  4. *
  5. * @author qifan
  6. * @date 2020-12-09
  7. */
  8. namespace app\crm\logic;
  9. use app\admin\controller\ApiCommon;
  10. use app\admin\model\Group;
  11. use app\crm\model\Activity;
  12. use think\Db;
  13. class ActivityLogic
  14. {
  15. # 活动类型 1 线索 2 客户 3 联系人 4 产品 5 商机 6 合同 7 回款 8 日志 9 审批 10 日程 11 任务 12 发邮件
  16. private $activityType = [
  17. 1 => ['en' => 'crm_leads', 'cn' => '线索'],
  18. 2 => ['en' => 'crm_customer', 'cn' => '客户'],
  19. 3 => ['en' => 'crm_contacts', 'cn' => '联系人'],
  20. 4 => ['en' => 'crm_product', 'cn' => '产品'],
  21. 5 => ['en' => 'crm_business', 'cn' => '商机'],
  22. 6 => ['en' => 'crm_contract', 'cn' => '合同'],
  23. 7 => ['en' => 'crm_receivables', 'cn' => '回款'],
  24. 8 => ['en' => 'oa_log', 'cn' => '日志'],
  25. 9 => ['en' => 'oa_examine', 'cn' => '审批'],
  26. 10 => ['en' => 'oa_event', 'cn' => '日程'],
  27. 11 => ['en' => 'oa_task', 'cn' => '任务'],
  28. 12 => ['en' => 'mail', 'cn' => '发邮件']
  29. ];
  30. private $moduleToNumber = [
  31. 'leads' => 1,
  32. 'customer' => 2,
  33. 'contacts' => 3,
  34. 'product' => 4,
  35. 'business' => 5,
  36. 'contract' => 6,
  37. 'receivables' => 7,
  38. 'log' => 8,
  39. 'examine' => 9,
  40. 'event' => 10,
  41. 'task' => 11,
  42. 'email' => 12
  43. ];
  44. /**
  45. * 活动列表
  46. *
  47. * @param $param
  48. * @return array
  49. * @throws \think\db\exception\DataNotFoundException
  50. * @throws \think\db\exception\ModelNotFoundException
  51. * @throws \think\exception\DbException
  52. */
  53. public function index($param)
  54. {
  55. $userId = $param['user_id'];
  56. unset($param['user_id']);
  57. unset($param['crmType']);
  58. $param['limit'] = !empty($param['limit']) ? $param['limit'] : 15;
  59. $param['page'] = !empty($param['page']) ? $param['page'] : 1;
  60. $recordWhere = [];
  61. $commonWhere = [];
  62. $leadsWhere = [];
  63. $customerWhere = function () {};
  64. $contactsWhere = function () {};
  65. $businessWhere = function () {};
  66. $contractWhere = function () {};
  67. $dateGroupWhere = function () {};
  68. # 跟进记录权限判断
  69. if (!checkPerByAction('crm', 'activity', 'index')) {
  70. $recordWhere['type'] = ['neq', 1];
  71. }
  72. # 处理公共查询参数
  73. if (!empty($param['interval_day'])) {
  74. $commonWhere['update_time'] = ['egt', time() - 86400 * $param['interval_day']];
  75. $commonWhere['update_time'] = ['elt', time()];
  76. }
  77. if (!empty($param['start_date']) && !empty($param['end_date'])) {
  78. $commonWhere['update_time'] = ['egt', strtotime($param['start_date'].' 00:00:00')];
  79. $commonWhere['update_time'] = ['elt', strtotime($param['end_date'].' 23:59:59')];
  80. }
  81. if (!empty($param['search'])) {
  82. $commonWhere['content'] = ['like', '%' . $param['search'] . '%'];
  83. }
  84. if (!empty($param['activity_type'])) {
  85. $commonWhere['activity_type'] = $param['activity_type'];
  86. }
  87. # 客户模块的额外查询条件
  88. $contactsData = [];
  89. $businessData = [];
  90. $contractData = [];
  91. $receivablesData = [];
  92. # 联系人ID串
  93. $contacts = Db::name('crm_contacts')->field(['contacts_id'])->where('customer_id', $param['activity_type_id'])->select();
  94. if (!empty($contacts)) {
  95. $contactsData['activity_type'] = 3;
  96. $contactsData['activity_type_id'] = array_reduce($contacts, function ($result, $value) {
  97. return array_merge($result, array_values($value));
  98. }, []);
  99. }
  100. # 商机ID串
  101. $business = Db::name('crm_business')->field(['business_id'])->where('customer_id', $param['activity_type_id'])->select();
  102. if (!empty($business)) {
  103. $businessData['activity_type'] = 5;
  104. $businessData['activity_type_id'] = array_reduce($business, function ($result, $value) {
  105. return array_merge($result, array_values($value));
  106. }, []);
  107. }
  108. # 合同ID串
  109. $contract = Db::name('crm_contract')->field(['contract_id'])->where('customer_id', $param['activity_type_id'])->select();
  110. if (!empty($contract)) {
  111. $contractData['activity_type'] = 6;
  112. $contractData['activity_type_id'] = array_reduce($contract, function ($result, $value) {
  113. return array_merge($result, array_values($value));
  114. }, []);
  115. }
  116. # 回款ID串
  117. $receivables = Db::name('crm_receivables')->field(['receivables_id'])->where('customer_id', $param['activity_type_id'])->select();
  118. if (!empty($receivables)) {
  119. $receivablesData['activity_type'] = 7;
  120. $receivablesData['activity_type_id'] = array_reduce($receivables, function ($result, $value) {
  121. return array_merge($result, array_values($value));
  122. }, []);
  123. }
  124. # 设置时间分组查询条件,第一页就是当天的数据,第二页就是下一天的数据
  125. $datetime = Db::name('crm_activity')
  126. ->field('update_time')
  127. ->where($recordWhere)
  128. ->where('status', 1)
  129. ->where(function ($query) use ($param, $contactsData, $businessData, $contractData, $receivablesData) {
  130. $query->whereOr(function ($query) use ($param) {
  131. $query->where('activity_type_id', $param['activity_type_id']);
  132. $query->where('activity_type', $this->moduleToNumber[$param['module']]);
  133. });
  134. $query->whereOr('customer_ids', 'like', '%,'.$param['activity_type_id'].',%');
  135. $query->whereOr('contacts_ids', 'like', '%,'.$param['activity_type_id'].',%');
  136. $query->whereOr('contract_ids', 'like', '%,'.$param['activity_type_id'].',%');
  137. $query->whereOr('business_ids', 'like', '%,'.$param['activity_type_id'].',%');
  138. $query->whereOr('leads_ids', 'like', '%,'.$param['activity_type_id'].',%');
  139. if (!empty($contactsData)) {
  140. $query->whereOr(function ($query) use ($contactsData) {
  141. $query->where('activity_type', $contactsData['activity_type']);
  142. $query->whereIn('activity_type_id', $contactsData['activity_type_id']);
  143. });
  144. }
  145. if (!empty($businessData)) {
  146. $query->whereOr(function ($query) use ($businessData) {
  147. $query->where('activity_type', $businessData['activity_type']);
  148. $query->whereIn('activity_type_id', $businessData['activity_type_id']);
  149. });
  150. }
  151. if (!empty($contractData)) {
  152. $query->whereOr(function ($query) use ($contractData) {
  153. $query->where('activity_type', $contractData['activity_type']);
  154. $query->whereIn('activity_type_id', $contractData['activity_type_id']);
  155. });
  156. }
  157. if (!empty($receivablesData)) {
  158. $query->whereOr(function ($query) use ($receivablesData) {
  159. $query->where('activity_type', $receivablesData['activity_type']);
  160. $query->whereIn('activity_type_id', $receivablesData['activity_type_id']);
  161. });
  162. }
  163. })
  164. ->where($commonWhere)
  165. ->order('update_time', 'desc')
  166. ->group('update_time')
  167. ->select();
  168. $dateGroup = [0 => '']; // 加一个占位,page从1开始
  169. $dateWhere = [0 => []]; // 加一个占位,page从1开始
  170. foreach ($datetime AS $key => $value) {
  171. $date = date('Y-m-d', $value['update_time']);
  172. if (!in_array($date, $dateGroup)) {
  173. $dateGroup[] = $date;
  174. $dateWhere[] = [
  175. 'start_time' => strtotime($date . ' 00:00:00'),
  176. 'end_time' => strtotime($date . ' 23:59:59')
  177. ];
  178. }
  179. }
  180. if (!empty($dateWhere[$param['page']])) {
  181. $dateGroupWhere = function ($query) use ($param, $dateWhere) {
  182. $query->where('update_time', '>=', $dateWhere[$param['page']]['start_time']);
  183. $query->where('update_time', '<=', $dateWhere[$param['page']]['end_time']);
  184. };
  185. }
  186. if (empty($dateWhere[$param['page']])) {
  187. return ['lastPage' => true, 'list' => [], 'time' => ''];
  188. }
  189. # 组织线索、客户、联系人、商机、合同下的查询条件
  190. switch ($param['module']) {
  191. case 'leads' :
  192. $leadsWhere = function ($query) use ($param) {
  193. $query->where('activity_type', 1);
  194. $query->where('activity_type_id', $param['activity_type_id']);
  195. };
  196. break;
  197. case 'customer' :
  198. # 客户模块查询条件
  199. $customerWhere = function ($query) use ($param, $contactsData, $businessData, $contractData, $receivablesData) {
  200. $query->whereOr(function ($query) use ($param) {
  201. $query->where('activity_type', 2);
  202. $query->where('activity_type_id', $param['activity_type_id']);
  203. });
  204. $query->whereOr(function ($query) use ($param) {
  205. $query->where('customer_ids', 'like', '%,' . $param['activity_type_id'] . ',%');
  206. $query->whereIn('activity_type', [8, 9, 11]);
  207. });
  208. if (!empty($contactsData)) {
  209. $query->whereOr(function ($query) use ($contactsData) {
  210. $query->where('activity_type', $contactsData['activity_type']);
  211. $query->whereIn('activity_type_id', $contactsData['activity_type_id']);
  212. });
  213. }
  214. if (!empty($businessData)) {
  215. $query->whereOr(function ($query) use ($businessData) {
  216. $query->where('activity_type', $businessData['activity_type']);
  217. $query->whereIn('activity_type_id', $businessData['activity_type_id']);
  218. });
  219. }
  220. if (!empty($contractData)) {
  221. $query->whereOr(function ($query) use ($contractData) {
  222. $query->where('activity_type', $contractData['activity_type']);
  223. $query->whereIn('activity_type_id', $contractData['activity_type_id']);
  224. });
  225. }
  226. if (!empty($receivablesData)) {
  227. $query->whereOr(function ($query) use ($receivablesData) {
  228. $query->where('activity_type', $receivablesData['activity_type']);
  229. $query->whereIn('activity_type_id', $receivablesData['activity_type_id']);
  230. });
  231. }
  232. };
  233. break;
  234. case 'contacts' :
  235. # 联系人模块查询条件
  236. $contactsWhere = function ($query) use ($param) {
  237. $query->whereOr(function ($query) use ($param) {
  238. $query->where('activity_type', 3);
  239. $query->where('activity_type_id', $param['activity_type_id']);
  240. });
  241. $query->whereOr(function ($query) use ($param) {
  242. $query->where('contacts_ids', 'like', '%,' . $param['activity_type_id'] . ',%');
  243. $query->whereIn('activity_type', [8, 9, 11]);
  244. });
  245. };
  246. break;
  247. case 'business' :
  248. # 商机模块查询条件
  249. $businessWhere = function ($query) use ($param) {
  250. $query->whereOr(function ($query) use ($param) {
  251. $query->where('activity_type', 5);
  252. $query->where('activity_type_id', $param['activity_type_id']);
  253. });
  254. $query->whereOr(function ($query) use ($param) {
  255. $query->where('business_ids', 'like', '%,' . $param['activity_type_id'] . ',%');
  256. $query->whereIn('activity_type', [8, 9, 11]);
  257. });
  258. };
  259. break;
  260. case 'contract' :
  261. # 合同模块查询条件
  262. $contractWhere = function ($query) use ($param) {
  263. $query->whereOr(function ($query) use ($param) {
  264. $query->where('activity_type', 6);
  265. $query->where('activity_type_id', $param['activity_type_id']);
  266. });
  267. $query->whereOr(function ($query) use ($param) {
  268. $query->where('contract_ids', 'like', '%,' . $param['activity_type_id'] . ',%');
  269. $query->whereIn('activity_type', [8, 9, 11]);
  270. });
  271. };
  272. break;
  273. }
  274. $field = [
  275. 'activity_id',
  276. 'type',
  277. 'category',
  278. 'activity_type',
  279. 'activity_type_id',
  280. 'content',
  281. 'contacts_ids',
  282. 'next_time',
  283. 'create_user_id',
  284. 'update_time',
  285. 'business_ids'
  286. ];
  287. $dataArray = Db::name('crm_activity')->field($field)
  288. ->where($dateGroupWhere)
  289. ->where($recordWhere)
  290. ->where($commonWhere)
  291. ->where($customerWhere)
  292. ->where($contactsWhere)
  293. ->where($businessWhere)
  294. ->where($contractWhere)
  295. ->where($leadsWhere)
  296. ->where('status', 1)
  297. ->order('update_time', 'desc')
  298. ->select();
  299. $fileModel = new \app\admin\model\File();
  300. foreach ($dataArray AS $key => $value) {
  301. # 用户信息
  302. $realname = Db::name('admin_user')->where('id', $dataArray[$key]['create_user_id'])->find();
  303. $dataArray[$key]['create_user_name'] = $realname['realname'];
  304. $dataArray[$key]['thumb_img'] = $realname['thumb_img'] ? getFullPath($realname['thumb_img']) : '';;
  305. # 附件信息
  306. if ($value['type'] = 1) {
  307. $files = [];
  308. $images = [];
  309. $fileList = $fileModel->getDataList(['module' => 'crm_activity', 'module_id' => $dataArray[$key]['activity_id']], 'all');
  310. if (!empty($fileList['list'])) {
  311. foreach ($fileList['list'] AS $k => $v) {
  312. if ($v['types'] == 'file') {
  313. $files[] = $v;
  314. } else {
  315. $images[] = $v;
  316. }
  317. }
  318. }
  319. $dataArray[$key]['fileList'] = $files ? : [];
  320. $dataArray[$key]['imgList'] = $images ? : [];
  321. }
  322. # 判断是不是本人添加的,如果不是将禁止删除修改
  323. $dataArray[$key]['auth'] = false;
  324. if ($dataArray[$key]['type'] == 1 && $dataArray[$key]['create_user_id'] == $userId) {
  325. $dataArray[$key]['auth'] = true;
  326. }
  327. # 查询联系人信息
  328. $dataArray[$key]['contacts_list'] = [];
  329. if ($dataArray[$key]['type'] == 1 && !empty($dataArray[$key]['contacts_ids'])) {
  330. $res = Db::name('crm_contacts')->where('contacts_id', trim($dataArray[$key]['contacts_ids'], ','))->value('name');
  331. $dataArray[$key]['contacts_list'][] = [
  332. 'contacts_id' => (int)trim($dataArray[$key]['contacts_ids'], ','),
  333. 'name' =>empty($res)? null : $res,
  334. ];
  335. }
  336. # 时间格式处理
  337. $dataArray[$key]['update_time'] = date('Y-m-d H:i:s', $value['update_time']);
  338. $dataArray[$key]['create_time'] = date('Y-m-d H:i:s', $value['create_time']);
  339. $dataArray[$key]['next_time'] = !empty($value['next_time']) ? date('Y-m-d H:i:s', $value['next_time']) : '';
  340. # 获取类型名称
  341. $dataArray[$key]['activity_type_name'] = $this->getActivityName($value['activity_type'], $value['activity_type_id']);
  342. # 客户模块跟进记录关联的商机
  343. $dataArray[$key]['business_list'] = $value['activity_type'] == 2 ? $this->getBusinessInfo($value['business_ids']) : [];
  344. # 去掉客户模块跟进记录联系人ID两端的逗号
  345. if ($value['type'] == 1 && $value['activity_type'] == 2) {
  346. $dataArray[$key]['contacts_ids'] = !empty($value['contacts_ids']) ? trim($value['contacts_ids'], ',') : '';
  347. }
  348. }
  349. # 是否是最后一页
  350. $lastPage = !empty($dateGroup[$param['page']]) && $param['page'] < count($dateGroup) - 1 ? false : true;
  351. return ['lastPage' => $lastPage, 'list' => $dataArray, 'time' => !empty($dateGroup[$param['page']]) ? $dateGroup[$param['page']] : ''];
  352. }
  353. /**
  354. * 活动详情【跟进记录】
  355. *
  356. * @param $activityId
  357. * @return array|bool|\PDOStatement|string|\think\Model|null
  358. * @throws \think\db\exception\DataNotFoundException
  359. * @throws \think\db\exception\ModelNotFoundException
  360. * @throws \think\exception\DbException
  361. */
  362. public function read($activityId)
  363. {
  364. # 查询跟进记录信息
  365. $field = ['activity_id', 'category', 'activity_type', 'activity_type_id', 'content', 'next_time', 'customer_ids', 'contacts_ids', 'contract_ids', 'business_ids'];
  366. $activityData = Activity::field($field)->where('type', 1)->where('activity_id', $activityId)->where('status', 1)->find();
  367. if (empty($activityData)) return [];
  368. # 查询与跟进记录关联的客户信息
  369. $customerData = Db::name('crm_customer')->field(['customer_id', 'name'])->whereIn('customer_id', $activityData['customer_ids'])->select();
  370. $activityData['customerInfo'] = $customerData;
  371. # 查询与跟进记录关联的联系人信息
  372. $contactsData = Db::name('crm_contacts')->field(['contacts_id', 'name'])->whereIn('contacts_id', $activityData['contacts_ids'])->select();
  373. $activityData['contactsInfo'] = $contactsData;
  374. # 查询与跟进记录关联的合同信息
  375. $contractData = Db::name('crm_contract')->field(['contract_id', 'name'])->whereIn('contract_id', $activityData['contract_ids'])->select();
  376. $activityData['contractInfo'] = $contractData;
  377. # 查询与跟进记录关联的商机信息
  378. $businessData = Db::name('crm_business')->field(['business_id', 'name'])->whereIn('business_id', $activityData['business_ids'])->select();
  379. $activityData['businessInfo'] = $businessData;
  380. # 查询与跟进记录关联的附件
  381. $fileData = (new \app\admin\model\File())->getDataList(['module' => 'crm_activity', 'module_id' => $activityId], 'all');
  382. $activityData['fileInfo'] = $fileData;
  383. return $activityData;
  384. }
  385. /**
  386. * 创建活动【跟进记录】
  387. *
  388. * @param $param
  389. * @return bool
  390. * @throws \think\Exception
  391. * @throws \think\exception\PDOException
  392. */
  393. public function save($param)
  394. {
  395. $userId = $param['user_id'];
  396. $isEvent = !empty($param['is_event']) ? $param['is_event'] : 0;
  397. $fileIds = !empty($param['file_id']) ? $param['file_id'] : [];
  398. unset($param['is_event']);
  399. unset($param['file_id']);
  400. unset($param['user_id']);
  401. $param['create_user_id'] = $userId;
  402. $param['type'] = 1;
  403. $param['next_time'] = !empty($param['next_time']) ? strtotime($param['next_time']) : 0;
  404. $param['business_ids'] = !empty($param['business_ids']) ? arrayToString($param['business_ids']) : '';
  405. $param['update_time'] = time();
  406. if(empty($param['excel'])){
  407. if (!empty($param['contacts_ids'])) $param['contacts_ids'] = ',' . $param['contacts_ids'] . ',';
  408. }else{
  409. $param['create_time'] = $param['create_time'];
  410. unset($param['excel']);
  411. }
  412. $activityJson = Activity::create($param);
  413. if (empty($activityJson)) return false;
  414. $activityArray = json_decode($activityJson, true);
  415. if (empty($activityArray['activity_id'])) return false;
  416. # 设置最后跟进记录
  417. $this->setFollowRecord($param['activity_type'], $param['activity_type_id'], $param['content']);
  418. # 下次联系时间
  419. $this->updateNextTime($this->activityType[$param['activity_type']]['en'], $param['activity_type_id'], $param['next_time'],false);
  420. # 处理附件关系
  421. if (!empty($fileIds)) {
  422. $fileModel = new \app\admin\model\File();
  423. $fileModel->createDataById($fileIds, 'crm_activity', $activityArray['activity_id']);
  424. }
  425. # 同时创建日程
  426. if ($isEvent) {
  427. $eventModel = new \app\oa\model\Event();
  428. $data['title'] = trim($param['content']);
  429. $data['content'] = trim($param['content']);
  430. $data['start_time'] = !empty($param['next_time']) ? $param['next_time'] : time();
  431. $data['end_time'] = $param['next_time'] + 86399;
  432. $data['create_user_id'] = $param['create_user_id'];
  433. $data['business_ids'] = $param['business_ids'];
  434. $data['contacts_ids'] = $param['contacts_ids'];
  435. $data['is_live'] = true;
  436. if ($param['activity_type'] == 'crm_customer') $data['customer_ids'] = $param['activity_type_id'];
  437. $eventModel->createData($data);
  438. }
  439. $activity=[1 =>'线索', 2=> '客户', 3 =>'联系人' ,4 =>'产品', 5 =>'商机', 6 =>'合同' ,7=>'回款' ,8=>'日志' ,9=>'审批' ,10=>'日程' ,11=>'任务' ,12 =>'发邮件'];
  440. RecordActionLog($param['create_user_id'],'crm_activity','save',$activity[$param['activity_type']],'','','新增了跟进记录'.$param['content']);
  441. return true;
  442. }
  443. /**
  444. * 修改活动【跟进记录】
  445. *
  446. * @param $param
  447. * @return bool
  448. * @throws \think\Exception
  449. * @throws \think\exception\PDOException
  450. */
  451. public function update($param)
  452. {
  453. $isEvent = !empty($param['is_event']) ? $param['is_event'] : 0;
  454. $fileIds = !empty($param['file_id']) ? $param['file_id'] : [];
  455. unset($param['is_event']);
  456. unset($param['file_id']);
  457. $param['type'] = 1;
  458. $param['next_time'] = strtotime($param['next_time']);
  459. $param['business_ids'] = !empty($param['business_ids']) ? arrayToString($param['business_ids']) : '';
  460. $param['update_time'] = time();
  461. $dataInfo=db('crm_activity')->where('activity_id',$param['activity_id'])->find();
  462. if (!Activity::update($param)) return false;
  463. # 设置最后跟进记录
  464. $this->setFollowRecord($param['activity_type'], $param['activity_type_id'], $param['content']);
  465. # 下次联系时间
  466. $this->updateNextTime($this->activityType[$param['activity_type']]['en'], $param['activity_type_id'], $param['next_time'],false);
  467. # 处理附件关系
  468. $fileModel = new \app\admin\model\File();
  469. if (!empty($fileIds)) {
  470. # 删除
  471. $fileModel->delRFileByModule('crm_activity', $param['activity_id']);
  472. # 添加
  473. $fileModel->createDataById($fileIds, 'crm_activity', $param['activity_id']);
  474. } else {
  475. # 删除
  476. $fileModel->delRFileByModule('crm_activity', $param['activity_id']);
  477. }
  478. # 同时创建日程
  479. if ($isEvent) {
  480. $eventModel = new \app\oa\model\Event();
  481. $data['title'] = trim($param['content']);
  482. $data['content'] = trim($param['content']);
  483. $data['start_time'] = !empty($param['next_time']) ? $param['next_time'] : time();
  484. $data['end_time'] = $param['next_time'] + 86399;
  485. $data['create_user_id'] = $param['create_user_id'];
  486. $data['business_ids'] = $param['business_ids'];
  487. $data['contacts_ids'] = $param['contacts_ids'];
  488. if ($param['activity_type'] == 2) $data['customer_ids'] = $param['activity_type_id'];
  489. $eventModel->createData($data);
  490. }
  491. return true;
  492. }
  493. /**
  494. * 删除活动【跟进记录】
  495. *
  496. * @param $activityId
  497. * @return Activity
  498. */
  499. public function delete($activityId,$userId)
  500. {
  501. $activityInfo = Db::name('crm_activity')->where(['activity_id' => $activityId])->find();
  502. if (Activity::update(['activity_id' => $activityId, 'status' => 0])) {
  503. $this->updateNextTime($this->activityType[$activityInfo['activity_type']]['en'], $activityInfo['activity_type_id'], '', true);
  504. # 删除附件
  505. $fileIds = db('crm_activity_file')->where('activity_id', $activityId)->column('file_id');
  506. if (!empty($fileIds)) {
  507. db('crm_activity_file')->where('activity_id', $activityId)->delete();
  508. db('admin_file')->whereIn('file_id', $fileIds)->delete();
  509. }
  510. if ($activityInfo['activity_type'] == 3) db('crm_contacts_file')->whereIn('file_id', $fileIds)->delete();
  511. if ($activityInfo['activity_type'] == 5) db('crm_business_file')->whereIn('file_id', $fileIds)->delete();
  512. if ($activityInfo['activity_type'] == 6) db('crm_contract_file')->whereIn('file_id', $fileIds)->delete();
  513. RecordActionLog($userId,'crm_activity','delete','删除跟进记录','','','删除了'.$recordModules[$types].$name);
  514. return true;
  515. } else {
  516. return false;
  517. }
  518. }
  519. /**
  520. * 相关模块下次联系时间
  521. *
  522. * @param $types
  523. * @param $types_id
  524. * @param string $next_time
  525. * @return bool
  526. * @throws \think\Exception
  527. * @throws \think\exception\PDOException
  528. */
  529. private function updateNextTime($types, $types_id, $next_time = '', $is_del = false)
  530. {
  531. switch ($types) {
  532. case 'crm_customer' : $dbName = db('crm_customer'); $dbId = 'customer_id'; $activity_type = 2; break;
  533. case 'crm_leads' : $dbName = db('crm_leads'); $dbId = 'leads_id'; $activity_type = 1; break;
  534. case 'crm_contacts' : $dbName = db('crm_contacts'); $dbId = 'contacts_id'; $activity_type = 3; break;
  535. case 'crm_business' : $dbName = db('crm_business'); $dbId = 'business_id'; $activity_type = 5; break;
  536. default : break;
  537. }
  538. if (!$dbName || !$dbId) return true;
  539. $data = [];
  540. $data['update_time'] = time();
  541. if (!empty($next_time)) {
  542. $data['next_time'] = $next_time;
  543. } else {
  544. if ($is_del) {
  545. # 查找最近一条下次联系时间补上,如果没有就置空
  546. $resActivity = Db::name('crm_activity')->where(['type'=>1, 'activity_type'=>$activity_type, 'activity_type_id' => $types_id,'status'=>['neq',0]])->order('activity_id desc')->find();
  547. $data['next_time'] = $resActivity['next_time'] ? : 0;
  548. unset($data['update_time']);
  549. } else {
  550. # 如果未填写下次联系时间,并且 原下次联系时间为当天,则把下次联系时间置空
  551. $next_time = $dbName->where([$dbId => $types_id])->value('next_time');
  552. list($start, $end) = getTimeByType();
  553. if ($next_time >= $start && $next_time <= $end) {
  554. $data['next_time'] = 0;
  555. }
  556. }
  557. }
  558. if (!$is_del && in_array($types, ['crm_customer', 'crm_leads'])) {
  559. $data['follow'] = '已跟进';
  560. }
  561. # 设置今日需联系线索、客户、商机
  562. if (!$is_del && in_array($types, ['crm_customer', 'crm_leads', 'crm_business'])) {
  563. if (!empty($next_time) && $next_time >= strtotime('Y-m-d 00:00:00')) $data['is_dealt'] = 0;
  564. }
  565. $dbName->where([$dbId => $types_id])->update($data);
  566. return true;
  567. }
  568. /**
  569. * 获取常用语
  570. *
  571. * @return mixed
  572. */
  573. public function getPhrase()
  574. {
  575. $dataJson = Db::name('crm_config')->where('name', 'activity_phrase')->value('value');
  576. return !empty($dataJson) ? unserialize($dataJson) : [];
  577. }
  578. /**
  579. * 设置常用语
  580. *
  581. * @param $param
  582. * @return int|string
  583. * @throws \think\Exception
  584. * @throws \think\exception\PDOException
  585. */
  586. public function setPhrase($param)
  587. {
  588. if (!Db::name('crm_config')->where('name', 'activity_phrase')->value('value')) {
  589. return Db::name('crm_config')->insert(['name' => 'activity_phrase', 'value' => serialize($param), 'description' => '跟进记录常用语']);
  590. }
  591. Db::name('crm_config')->where('name', 'activity_phrase')->update(['value' => serialize($param)]);
  592. return true;
  593. }
  594. /**
  595. * 获取修改过的跟进记录信息
  596. *
  597. * @param $activityId
  598. * @param $userId
  599. * @return array|bool|\PDOStatement|string|\think\Model|null
  600. * @throws \think\db\exception\DataNotFoundException
  601. * @throws \think\db\exception\ModelNotFoundException
  602. * @throws \think\exception\DbException
  603. */
  604. public function getFollowData($activityId, $userId)
  605. {
  606. $field = [
  607. 'activity_id',
  608. 'type',
  609. 'category',
  610. 'activity_type',
  611. 'activity_type_id',
  612. 'content',
  613. 'contacts_ids',
  614. 'next_time',
  615. 'create_user_id',
  616. 'update_time',
  617. 'business_ids'
  618. ];
  619. $data = db('crm_activity')->where('activity_id', $activityId)->field($field)->find();
  620. $fileModel = new \app\admin\model\File();
  621. $realname = Db::name('admin_user')->where('id', $data['create_user_id'])->value('realname');
  622. $data['create_user_name'] = $realname;
  623. # 附件信息
  624. if ($data['type'] = 1) {
  625. $files = [];
  626. $images = [];
  627. $fileList = $fileModel->getDataList(['module' => 'crm_activity', 'module_id' => $activityId], 'all');
  628. if (!empty($fileList['list'])) {
  629. foreach ($fileList['list'] AS $k => $v) {
  630. if ($v['types'] == 'file') {
  631. $files[] = $v;
  632. } else {
  633. $images[] = $v;
  634. }
  635. }
  636. }
  637. $data['fileList'] = $files ? : [];
  638. $data['imgList'] = $images ? : [];
  639. }
  640. # 判断是不是本人添加的,如果不是将禁止删除修改
  641. $data['auth'] = false;
  642. if ($data['type'] == 1 && $data['create_user_id'] == $userId) {
  643. $data['auth'] = true;
  644. }
  645. # 查询联系人信息
  646. $data['contacts_name'] = '';
  647. if ($data['type'] == 1 && !empty($data['contacts_ids'])) {
  648. $data['contacts_name'] = Db::name('crm_contacts')->where('contacts_id', $data['contacts_ids'])->value('name');
  649. }
  650. $data['update_time'] = date('Y-m-d H:i:s', $data['update_time']);
  651. $data['next_time'] = !empty($data['next_time']) ? date('Y-m-d H:i:s', $data['next_time']) : null;
  652. # 关联商机
  653. $data['business_list'] = $data['activity_type'] == 2 ? $this->getBusinessInfo($data['business_ids']) : [];
  654. return $data;
  655. }
  656. /**
  657. * 获取活动类型名称
  658. *
  659. * @param $activityType
  660. * @param $activityTypeId
  661. * @return float|mixed|string|\think\db\Query
  662. */
  663. private function getActivityName($activityType, $activityTypeId)
  664. {
  665. $activityTypeName = '';
  666. # 线索
  667. if ($activityType == 1) {
  668. $activityTypeName = Db::name('crm_leads')->where('leads_id', $activityTypeId)->value('name');
  669. }
  670. # 客户
  671. if ($activityType == 2) {
  672. $activityTypeName = Db::name('crm_customer')->where('customer_id', $activityTypeId)->value('name');
  673. }
  674. # 联系人
  675. if ($activityType == 3) {
  676. $activityTypeName = Db::name('crm_contacts')->where('contacts_id', $activityTypeId)->value('name');
  677. }
  678. # 产品
  679. if ($activityType == 4) {
  680. $activityTypeName = Db::name('crm_product')->where('product_id', $activityTypeId)->value('name');
  681. }
  682. # 商机
  683. if ($activityType == 5) {
  684. $activityTypeName = Db::name('crm_business')->where('business_id', $activityTypeId)->value('name');
  685. }
  686. # 合同
  687. if ($activityType == 6) {
  688. $activityTypeName = Db::name('crm_contract')->where('contract_id', $activityTypeId)->value('name');
  689. }
  690. # 回款
  691. if ($activityType == 7) {
  692. $activityTypeName = Db::name('crm_receivables')->where('receivables_id', $activityTypeId)->value('number');
  693. }
  694. # 日志
  695. if ($activityType == 8) {
  696. $activityTypeName = Db::name('oa_log')->where('log_id', $activityTypeId)->value('title');
  697. }
  698. # 审批
  699. if ($activityType == 9) {
  700. $categoryId = Db::name('oa_examine')->where('examine_id', $activityTypeId)->value('category_id');
  701. $activityTypeName = Db::name('oa_examine_category')->where('category_id', $categoryId)->value('title');
  702. }
  703. # 日程
  704. if ($activityType == 10) {
  705. $activityTypeName = Db::name('oa_event')->where('event_id', $activityTypeId)->value('title');
  706. }
  707. # 任务
  708. if ($activityType == 11) {
  709. $activityTypeName = Db::name('task')->where('task_id', $activityTypeId)->value('name');
  710. }
  711. return $activityTypeName;
  712. }
  713. /**
  714. * 获取客户跟进记录关联的商机
  715. *
  716. * @param $businessIds
  717. * @return bool|\PDOStatement|string|\think\Collection
  718. * @throws \think\db\exception\DataNotFoundException
  719. * @throws \think\db\exception\ModelNotFoundException
  720. * @throws \think\exception\DbException
  721. */
  722. private function getBusinessInfo($businessIds)
  723. {
  724. return Db::name('crm_business')->field(['business_id', 'name'])->whereIn('business_id', $businessIds)->select();
  725. }
  726. /**
  727. * 设置跟进记录
  728. *
  729. * @param $type
  730. * @param $typeId
  731. * @param $content
  732. * @throws \think\Exception
  733. * @throws \think\exception\PDOException
  734. */
  735. private function setFollowRecord($type, $typeId, $content)
  736. {
  737. $model = null;
  738. $primaryKey = null;
  739. switch ($type) {
  740. case 1 : $model = db('crm_leads'); $primaryKey = 'leads_id'; break;
  741. case 2 : $model = db('crm_customer'); $primaryKey = 'customer_id'; break;
  742. case 3 : $model = db('crm_contacts'); $primaryKey = 'contacts_id'; break;
  743. case 5 : $model = db('crm_business'); $primaryKey = 'business_id'; break;
  744. case 6 : $model = db('crm_contract'); $primaryKey = 'contract_id'; break;
  745. }
  746. $model->where($primaryKey, $typeId)->update(['last_time' => time(), 'last_record' => $content]);
  747. }
  748. /**
  749. * 跟进记录导出
  750. * @param $field_list
  751. * @param $data
  752. *
  753. * @author alvin guogaobo
  754. * @version 1.0 版本号
  755. * @since 2021/4/21 0021 09:35
  756. */
  757. public function excelExport($field_list,$data){
  758. $excelModel = new \app\admin\model\Excel();
  759. $file_name='activity_record';
  760. $title='跟进记录';
  761. $excelModel->taskExportCsv($file_name, $field_list, $title, $data);
  762. }
  763. }