UpdateUserTaskController.class.php
23.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
<?php
/**
* 更新用户常规任务进度
*
* 按照 /Frontend/Index/UpdateUserTask 接口改来
*/
namespace Frontend\Controller\Crontab;
use Common\Common\Constant;
use Common\Common\Integral;
use Common\Common\Msg;
use Common\Common\TaskCenter;
use Common\Service\CustomtaskService;
use Common\Service\DailytaskService;
use Common\Service\UserActionService;
use Common\Service\UserContentService;
use Common\Service\UserNoticeService;
use Common\Service\UserRewardService;
use Common\Service\UserTaskService;
use VcySDK\Member;
use VcySDK\Service;
/**
* Class UpdateUserTaskController
* @package Frontend\Controller\Crontab
* @property UserTaskService $userTaskServ
* @property UserContentService $userContentServ
* @property UserActionService $useractionServ
* @property CustomtaskService $customtaskServ
* @property DailytaskService $dailyTaskServ
* @property UserRewardService $userRewardServ
* @property UserNoticeService $userNoticeServ
*/
class UpdateUserTaskController extends AbstractController
{
protected $userTaskServ = null;
protected $userContentServ = null;
protected $useractionServ = null;
protected $customtaskServ = null;
protected $dailyTaskServ = null;
protected $userRewardServ = null;
protected $userNoticeServ = null;
/**
* 单次处理人数
*/
const DEAL_MEMBER_COUNT = 100;
/**
* 任务完成进度数值
*/
const TASK_COMPLETE_PROGRESS = 100;
/**
* 当前企业标识
* @var string
*/
private $domain = '';
public function Index()
{
set_time_limit(0);
$taskCenter = TaskCenter::instance();
$uids = [];
// 获取用户ID
while (count($uids) < self::DEAL_MEMBER_COUNT) {
$uid = $taskCenter->pop(TaskCenter::CACHE_KEY);
if ($uid === false) {
break;
}
$uids[] = $uid;
}
if (empty($uids)) {
exit('OK');
}
$this->userTaskServ = new UserTaskService();
$this->userContentServ = new UserContentService();
$this->useractionServ = new UserActionService();
$this->customtaskServ = new CustomtaskService();
$this->dailyTaskServ = new DailytaskService();
$this->userRewardServ = new UserRewardService();
$this->userNoticeServ = new UserNoticeService();
// 初始化 SDK (减少重复)
$config = array(
'apiUrl' => cfg('UC_APIURL'),
'enumber' => '',
'pluginIdentifier' => 'yuanquan',
'thirdIdentifier' => cfg('SDK_THIRD_IDENTIFIER'),
'logPath' => RUNTIME_PATH . '/Logs/VcySDK/',
'apiSecret' => cfg('API_SECRET'),
'apiSigExpire' => cfg('API_SIG_EXPIRE'),
'fileConvertApiUrl' => cfg('FILE_CONVERT_API_URL')
);
Service::instance()->initSdk($config);
// 同步人员进度
$this->syncProgress($uids);
// 检查每日任务
$this->checkDailytaskProgress($uids);
exit('OK');
}
/**
* 同步人员进度
* @param $uids
* @return bool
*/
private function syncProgress($uids)
{
// 获取进行中未完成的任务列表
$usertaskList = $this->userTaskServ->listWithOutDomian([
'uid' => $uids,
'complete_status' => Constant::USER_TASK_COMPLETE_STATUS_PROCESS,
'task_status' => Constant::CUSTOMTASK_STATUS_PROCESS,
], null, [], implode(',', [
'user_task_id',
'uid',
'username',
'customtask_id',
'progress',
'domain',
]));
if (empty($usertaskList)) {
return true;
}
// 按照企业标识分组
$domainWithUserTask = [];
foreach ($usertaskList as $item) {
$domainWithUserTask[$item['domain']][] = $item;
}
unset($usertaskList);
$service = Service::instance();
foreach ($domainWithUserTask as $this->domain => $item) {
// 初始化 SDK
$config['enumber'] = $this->domain;
$service->setConfig($config);
// 每个企业标识单独处理
try {
$this->dealWithSingleDomain($item);
} catch (\Exception $e) {
}
}
}
/**
* 处理单个 Domain 下的用户任务数据
* @param $item
*/
private function dealWithSingleDomain($item)
{
/**
* 当前企业下未完成的任务 ID 为 key 每个任务下对应的人员 (注意: 对应的人员数据不是该任务下的全部人员)
* 第一步 ($item):
* {
* "任务ID" => {
* "用户ID" => {
* 用户任务数据
* }
* ...
* }
* ...
* customtask_id, uid
* }
*/
$customtaskIdList = array_unique(array_column($item, 'customtask_id'));
$uidList = array_unique(array_column($item, 'uid'));
$temp = [];
foreach ($item as $value) {
$temp[$value['customtask_id']][$value['uid']] = $value;
}
$item = $temp;
unset($temp);
/**
* 第二步 获取用户动作 ($userActions):
* {
* "用户ID" => {
* "任务ID" => {
* "app 标识" => {
* "app data id" => "数据创建时间"
* ...
* }
* ...
* }
* ...
* }
* }
*/
$useractionList = $this->useractionServ->listWithOutDomian([
'uid' => $uidList,
'customtask_id' => $customtaskIdList,
], null, [], implode(',', ['customtask_id', 'app', 'app_data_id', 'created', 'uid',]));
// 格式化动作数据
$userActions = [];
foreach ($useractionList as $action) {
$userActions[$action['uid']][$action['customtask_id']][$action['app']][$action['app_data_id']] =
$action['created'];
}
unset($useractionList);
/**
* 第三步: 获取任务内容 (把任务内容放入第一步的数组内, 并且根据第二步的用户动作来判断是否完成任务)
* {
* "任务ID" => {
* "用户ID" => {
* 用户任务数据
* "用户任务内容" => [
*
* ]
* }
* ...
* }
* ...
* }
*/
$userContentList = $this->userContentServ->listWithOutDomian([
'uid' => $uidList,
'customtask_id' => $customtaskIdList,
], null, [], implode(',', [
'customtask_id',
'uid',
'username',
'app',
'app_data_id',
'user_content_id',
'content_status',
'complete_time'
]));
// 任务内容 放入用户任务中
foreach ($userContentList as $userContent) {
// 初始化用户任务完成度
if (!isset($item[$userContent['customtask_id']][$userContent['uid']]['completeCount'])) {
$item[$userContent['customtask_id']][$userContent['uid']]['completeCount'] = 0;
}
// 如果完成
if ($userContent['content_status'] == Constant::USER_CONTENT_STATUS_COMPLETE) {
// 增加完成任务数
$item[$userContent['customtask_id']][$userContent['uid']]['completeCount'] ++;
} else {
$customTaskId = $userContent['customtask_id'];
$app = $userContent['app'];
$appDataId = $userContent['app_data_id'];
// 用户动作已存在
if (isset($userActions[$userContent['uid']][$customTaskId][$app][$appDataId])) {
$completeTime = $userActions[$userContent['uid']][$customTaskId][$app][$appDataId];
// 更新内容完成状态为:已完成
$this->userContentServ->updateWithOutDomain($userContent['user_content_id'], [
'content_status' => Constant::USER_CONTENT_STATUS_COMPLETE,
'complete_time' => $completeTime,
]);
// 标记完成时间
$userContent['complete_time'] = $completeTime;
// 增加完成任务数
$item[$userContent['customtask_id']][$userContent['uid']]['completeCount'] ++;
}
}
// 放入统计数组内
$item[$userContent['customtask_id']][$userContent['uid']]['contents'][] = $userContent;
}
// 最后: 统计任务进度 (计算人员完成情况 并更新)
$completedTask = [];
foreach ($item as $taskId => $task) {
foreach ($task as $userId => $userTask) {
// 计算任务进度,精确到小数点后两位
$progress = round($userTask['completeCount'] / count($userTask['contents']), 2) * 100;
// 任务进度有变更
if ($progress != $userTask['progress']) {
$updateData = ['progress' => $progress];
// 如果完成了
if ($progress == self::TASK_COMPLETE_PROGRESS) {
$updateData['complete_status'] = Constant::USER_TASK_COMPLETE_STATUS_COMPLETE;
$updateData['complete_time'] = max(array_column($userTask['contents'], 'complete_time'));
// 记录有人完成了 的任务ID
$completedTask[$userTask['customtask_id']][$userId] = [
'username' => $userTask['username'],
'complete_time' => $updateData['complete_time']
];
}
$this->userTaskServ->updateWithOutDomain($userTask['user_task_id'], $updateData);
// 单人完成所有任务后增加任务完成数
if ($progress == 100) {
$this->customtaskServ->addCompleteTotal($userTask['customtask_id']);
}
}
}
}
// 发放激励
try {
$this->sendCustomtaskReward($completedTask);
} catch (\Exception $e) {}
}
/**
* 发放激励
* @param $completedTask
* {
* "任务ID" => {
* "人员ID" => {
* "人员姓名",
* "完成时间"
* }
* }
* }
* @return bool
*/
private function sendCustomtaskReward($completedTask)
{
if (empty($completedTask)) {
return true;
}
$taskIdArr = array_keys($completedTask);
$taskList = $this->customtaskServ->listWithOutDomian(
[
'customtask_id' => $taskIdArr
], null, [],
implode(',', [
'customtask_id',
'reward_setting',
'task_name'
])
);
$taskList = array_combine_by_key($taskList, 'customtask_id');
$integralServ = &Integral::instance();
$msgServ = &Msg::instance();
foreach ($completedTask as $taskId => $completeValue) {
// 任务详情
$taskDetail = $taskList[$taskId];
$rewardSetting = unserialize($taskDetail['reward_setting']);
foreach ($completeValue as $userId => $completeItem) {
switch ($rewardSetting['type']) {
// 勋章
case Constant::REWARD_TYPE_MEDAL:
// 获取勋章数据
$medal = $this->getMedal($rewardSetting['medal_id']);
if (empty($medal)) {
break;
}
// 发放勋章
$rpcUrl = sprintf(
'%s%s/%s%s',
cfg('PROTOCAL'),
$_SERVER['HTTP_HOST'],
$this->domain,
'/Integral/Rpc/Medal/Endow'
);
$rpcParams = [
$rewardSetting['medal_id'],
$userId,
$completeItem['username']
];
$rpcRe = \Com\Rpc::phprpc($rpcUrl)->invoke('Index', $rpcParams);
if ($rpcRe) {
$msg_data = [
[
'title' => "恭喜您,获得【{$medal['name']}】勋章",
'description' => "获取渠道:员圈任务-{$taskDetail['task_name']}\n获取时间:" .
rgmdate($completeItem['complete_time']),
'url' => oaUrl('Frontend/Index/Medal/Index', [], $this->domain),
],
];
$msgServ->sendNews($userId, null, null, $msg_data);
}
break;
// 积分
case Constant::REWARD_TYPE_INTEGRAL:
$integralServ->asynUpdateIntegral([
'memUid' => $userId,
'irKey' => 'taskcenter_customtask_complete',
'msgIdentifier' => 'yuanquan',
'integral' => $rewardSetting['integral'],
'remark' => '完成常规任务获得激励',
'businessKey' => 'task_center',
'businessAct' => 'normal_task',
]);
break;
}
}
}
return true;
}
/**
* 检查每日任务进度,如果完成则通知用户
* @param $uids
* @return bool
*/
private function checkDailytaskProgress($uids)
{
// 获取用户今日动作
$time = rstrtotime(rgmdate(MILLI_TIME, 'Y-m-d'), 1);
$actionList = $this->useractionServ->listWithOutDomian([
'uid' => $uids,
'created >= ?' => $time
]);
// 按照 uid 为 key 重组
$temp = [];
foreach ($actionList as $value) {
$temp[$value['domain']][$value['uid']][] = $value;
}
$actionList = $temp;
unset($temp);
$service = Service::instance();
foreach ($actionList as $this->domain => $userAction) {
// 初始化 SDK
$config['enumber'] = $this->domain;
$service->setConfig($config);
// 每个企业标识单独处理
$this-> dealWithSingleDomainDeaily($userAction);
}
return true;
}
/**
* 每个企业标识单独处理 每日任务
* @param $userAction array 人员 - 动作
* @return bool
*/
private function dealWithSingleDomainDeaily($userAction)
{
// 构建每日任务列表
$ruleList = $this->buildDailytaskList();
if (empty($ruleList)) {
return true;
}
$uids = array_keys($userAction);
// 获取通知列表
$noticeList = $this->userNoticeServ->listWithOutDomian([
'uid' => $uids,
'created >= ?' => rstrtotime(rgmdate(MILLI_TIME, 'Y-m-d')),
]);
// 格式化
$temp = [];
foreach ($noticeList as $item) {
$temp[$item['uid']][$item['app']][] = $item['rule_name'];
}
$noticeList = $temp;
unset($temp);
// 获取用户今日激励领取数据
$ruleNames = array_keys($ruleList);
$time = rstrtotime(rgmdate(MILLI_TIME, 'Y-m-d'), 1);
$rewardList = $this->userRewardServ->listWithOutDomian([
'uid' => $uids,
'rule_name' => $ruleNames,
'created >= ?' => $time,
]);
$temp = [];
foreach ($rewardList as $item) {
$temp[$item['uid']][$item['app']][] = $item['rule_name'];
}
$rewardList = $temp;
unset($temp);
// 获取人员数据
$userList = (new Member(Service::instance()))->listAll(['memUids' => $uids], 1, self::DEAL_MEMBER_COUNT);
$userList = array_combine_by_key($userList['list'], 'memUid');
// 需要发送消息
$noticeInsertList = [];
// 按一个个人来
foreach ($userList as $uid => $user) {
foreach ($ruleList as $name => $rule) {
// // 允许重复性 $unique true: 多条数据算一条 false: 多条数据算多条
// $unique = isset($rule['config']['unique']) ? $rule['config']['unique'] : false;
// 人员行为
foreach ($userAction[$uid] as $action) {
if (!in_array($action['action_key'], $rule['action_keys'])) {
continue;
}
$user['completed'][$action['action_key']] ++;
// 完成任务
if ($user['completed'][$action['action_key']] >= $rule['count'] &&
// 没有发送过消息
(!in_array($action['action_key'], $noticeList[$uid][$rule['app']])) &&
// 没有获取过奖励
(!in_array($action['action_key'], $rewardList[$uid][$rule['app']]))) {
$noticeInsertList[] = [
'uid' => $uid,
'username' => $userList[$uid]['memUsername'],
'app' => $action['app'],
'rule_name' => $action['action_key'],
// insert_all 补全字段信息 时就不会去自动补全了
'domain' => $this->domain
];
// 发送消息
$this->sendDailytaskCompleteMsg([
'app' => $action['app'],
'integral' => $rule['integral'],
'complete_time' => rgmdate(max(array_column($userAction[$uid], 'created')), 'Y-m-d H:i'),
'task_title' => $rule['task_title']
], $uid);
}
}
}
}
// 记录发送过的消息
$this->userNoticeServ->insert_all($noticeInsertList);
return true;
}
/**
* 构建每日任务列表
* @author zhonglei
* @param array $user 用户信息
* @return array
* + string app 应用
* + string app_url 应用Url
* + string rule_name 规则名称
* + string task_title 任务名称
* + int integral 积分
* + int require_total 需要完成总数
* + int complete_total 已完成总数
* + int is_get 是否已领取激励(1=未领取;2=已领取)
*/
private function buildDailytaskList()
{
$configList = $this->dailyTaskServ->listWithOutDomian([
'app' => [
Constant::APP_WORKMATE,
Constant::APP_ANSWER
],
'domain' => $this->domain
]);
// 获取已启用的任务规则
$ruleList = [];
foreach ($configList as $config) {
// 任务未开启
if ($config['is_open'] != Constant::DAILYTASK_IS_OPEN_TRUE) {
continue;
}
// 格式化任务名称
$config['rules'] = unserialize($config['rules']);
foreach ($config['rules'] as $name => $rule) {
$taskTitle = '';
switch ($name) {
// 员圈发表话题
case Constant::RULE_NAME_WORKMATE_CIRCLE:
$taskTitle = '在员圈发表%s个话题';
break;
// 员圈添加评论
case Constant::RULE_NAME_WORKMATE_COMMENT:
$unique = isset($rule['config']['unique']) ? $rule['config']['unique'] : false;
$taskTitle = $unique ? '在员圈不同话题下添加%s条评论' : '在员圈添加%s条评论';
break;
// 员圈点赞
case Constant::RULE_NAME_WORKMATE_LIKE:
$unique = isset($rule['config']['unique']) ? $rule['config']['unique'] : false;
$taskTitle = $unique ? '在员圈对话题进行%s个点赞' : '在员圈进行%s个点赞';
break;
// 问答中心发起提问
case Constant::RULE_NAME_ANSWER_QUESTION:
$taskTitle = '在问答中心发起%s个提问';
break;
// 问答中心添加回答
case Constant::RULE_NAME_ANSWER_ANSWER:
$unique = isset($rule['config']['unique']) ? $rule['config']['unique'] : false;
$taskTitle = $unique ? '在问答中心不同问题下添加%s个回答' : '在问答中心添加%s个回答';
break;
}
$rule['app'] = $config['app'];
$rule['task_title'] = sprintf($taskTitle, $rule['count']);
$ruleList[$name] = $rule;
}
}
return $ruleList;
}
/**
* 获取勋章详情
* @param int $imId 勋章ID
* @return array
*/
private function getMedal($imId = 0)
{
$rpcUrl = sprintf(
'%s%s/%s%s',
cfg('PROTOCAL'),
$_SERVER['HTTP_HOST'],
$this->domain,
'/Integral/Rpc/Medal/List'
);
$list = call_user_func(array(\Com\Rpc::phprpc($rpcUrl), 'Index'));
if (!empty($list)) {
$list = array_combine_by_key($list, 'im_id');
}
$medalInfo = isset($list[$imId]) ? $list[$imId] : [];
return $medalInfo;
}
/**
* 发送每日任务完成消息
* @author zhonglei
* @param array $dailytask 每日任务数据
* @param string $uid 用户ID
* @return bool
*/
private function sendDailytaskCompleteMsg($dailytask, $uid)
{
// 消息通知前缀
$prefix = cfg('NOTICE_PREFIX', null, '');
// 应用名称
$app_names = [
Constant::APP_WORKMATE => '员圈',
Constant::APP_ANSWER => '问答中心',
];
$app_name = isset($app_names[$dailytask['app']]) ? $app_names[$dailytask['app']] : '';
$reward = "+{$dailytask['integral']}积分";
$msgServ = &Msg::instance();
$msg_data = [
[
'title' => "{$prefix}您已完成了{$app_name}的日常任务,快来领取奖励吧",
'description' => "任务名称:{$dailytask['task_title']}\n积分奖励:{$reward}\n完成时间:{$dailytask['complete_time']}",
'url' => oaUrl('Frontend/Index/TaskIndex', [], $this->domain),
],
];
try {
$msgServ->sendNews($uid, null, null, $msg_data);
} catch (\Exception $e) {
// 不影响流程
}
return true;
}
}