chore: 添加静态资源文件和版本配置文件
添加大量图片、字体、音频等静态资源文件,包括用户界面图片、模板文件和安装界面素材 添加系统版本配置文件(.version)和常量定义文件(.constant) 更新供应商依赖文件,包括Symfony VarDumper组件和相关许可证文件 添加验证码配置文件(captcha.php)和.gitignore规则
This commit is contained in:
93
app/services/work/WorkChannelCategoryServices.php
Normal file
93
app/services/work/WorkChannelCategoryServices.php
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
use app\services\other\CategoryServices;
|
||||
use crmeb\services\FormBuilder;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
/**
|
||||
* 渠道码分类
|
||||
* Class WorkChannelCategoryServices
|
||||
* @package app\services\work
|
||||
*/
|
||||
class WorkChannelCategoryServices extends CategoryServices
|
||||
{
|
||||
|
||||
const TYPE = 4;
|
||||
|
||||
/**
|
||||
* @param array $where
|
||||
* @param array|string[] $field
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getCateList(array $where = [], array $field = ['*'])
|
||||
{
|
||||
$where['group'] = self::TYPE;
|
||||
$where['owner_id'] = 0;
|
||||
return parent::getCateList($where, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取标签全部分类
|
||||
* @param int $type
|
||||
* @param int $relation_id
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCateAll(int $type = self::TYPE, int $relation_id = 0)
|
||||
{
|
||||
return $this->dao->getCateList(['type' => 0, 'owner_id' => 0, 'relation_id' => $relation_id, 'group' => $type]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 标签分类表单
|
||||
* @param array $cataData
|
||||
* @return mixed
|
||||
*/
|
||||
public function cateForm(array $cataData = [])
|
||||
{
|
||||
$f[] = FormBuilder::input('name', '分类名称', $cataData['name'] ?? '')->maxlength(20)->required();
|
||||
$f[] = FormBuilder::number('sort', '排序', (int)($cataData['sort'] ?? 0))->min(0);
|
||||
return $f;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建表单
|
||||
* @return array
|
||||
*/
|
||||
public function createForm()
|
||||
{
|
||||
return create_form('添加渠道二维码分类', $this->cateForm(), $this->url('/work/channel/cate'), 'POST');
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改分类标签表单
|
||||
* @param int $id
|
||||
* @return array
|
||||
* @throws \FormBuilder\Exception\FormBuilderException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function updateForm(int $id)
|
||||
{
|
||||
$cate = $this->dao->get($id);
|
||||
if (!$cate) {
|
||||
throw new ValidateException('渠道二维码分类没有查到');
|
||||
}
|
||||
return create_form('编辑渠道二维码分类', $this->cateForm($cate->toArray()), $this->url('work/channel/cate/' . $id), 'PUT');
|
||||
}
|
||||
|
||||
}
|
||||
369
app/services/work/WorkChannelCodeServices.php
Normal file
369
app/services/work/WorkChannelCodeServices.php
Normal file
@@ -0,0 +1,369 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkChannelCodeDao;
|
||||
use app\services\BaseServices;
|
||||
use app\services\user\label\UserLabelServices;
|
||||
use crmeb\services\wechat\Work;
|
||||
use crmeb\traits\service\ContactWayQrCode;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
/**
|
||||
* 渠道码
|
||||
* Class WorkChannelCodeServices
|
||||
* @package app\services\work
|
||||
*/
|
||||
class WorkChannelCodeServices extends BaseServices
|
||||
{
|
||||
|
||||
use ContactWayQrCode;
|
||||
|
||||
/**
|
||||
* @var WorkChannelCodeDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkChannelCodeDao $dao;
|
||||
|
||||
/**
|
||||
* 获取渠道二维码列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function getList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getDataList($where, ['*'], $page, $limit, 'create_time', ['category' => function ($query) {
|
||||
$query->field(['id', 'name']);
|
||||
}]);
|
||||
//获取标签
|
||||
$labelIds = [];
|
||||
foreach ($list as $item) {
|
||||
$labelIds = array_merge($labelIds, $item['label_id']);
|
||||
}
|
||||
$labelIds = array_merge(array_unique(array_filter($labelIds)));
|
||||
$labelList = [];
|
||||
if ($labelIds) {
|
||||
/** @var UserLabelServices $labelServices */
|
||||
$labelServices = app()->make(UserLabelServices::class);
|
||||
$labelList = $labelServices->getColumn([
|
||||
['tag_id', 'in', $labelIds]
|
||||
], 'label_name', 'tag_id');
|
||||
}
|
||||
$workClientFollowServices = app()->make(WorkClientFollowServices::class);
|
||||
foreach ($list as &$item) {
|
||||
foreach ($labelList as $key => $value) {
|
||||
if (in_array($key, $item['label_id'])) {
|
||||
$item['label_name'][] = $value;
|
||||
}
|
||||
}
|
||||
$item["client_num"] =$workClientFollowServices->getChannelCodeClientCount($item["id"]);
|
||||
}
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取渠道码详情
|
||||
* @param int $id
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getChannelInfo(int $id)
|
||||
{
|
||||
$channelInfo = $this->dao->get($id, ['*'], ['cycle', 'useridLimit' => function ($query) {
|
||||
$query->with(['member']);
|
||||
}]);
|
||||
if (!$channelInfo) {
|
||||
throw new ValidateException('没有查询到渠道二维码信息');
|
||||
}
|
||||
|
||||
/** @var WorkMemberServices $make */
|
||||
$make = app()->make(WorkMemberServices::class);
|
||||
|
||||
//重组周期数据
|
||||
if (!empty($channelInfo['cycle'])) {
|
||||
$userIds = [];
|
||||
foreach ($channelInfo['cycle'] as $item) {
|
||||
$userIds = array_merge($userIds, $item['userids']);
|
||||
}
|
||||
if ($userIds) {
|
||||
$userIds = array_merge(array_unique(array_filter($userIds)));
|
||||
$userList = $make->getColumn([['userid', 'in', $userIds]], 'name', 'userid');
|
||||
foreach ($channelInfo['cycle'] as &$item) {
|
||||
$userItem = [];
|
||||
foreach ($userList as $key => $value) {
|
||||
if (in_array($key, $item['userids'])) {
|
||||
$userItem[] = ['name' => $value, 'userid' => $key];
|
||||
}
|
||||
}
|
||||
$item['userItem'] = $userItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
$channelInfo = $channelInfo->toArray();
|
||||
$channelInfo['presentUseUserIds'] = $this->getPresentUseUserIds((int)$channelInfo['type'], $channelInfo['cycle'] ?? [], $channelInfo['useridLimit'] ?? [], [
|
||||
'reserve_userid' => $channelInfo['reserve_userid'],
|
||||
'userids' => $channelInfo['userids'],
|
||||
'code_id' => $channelInfo['id'],
|
||||
'add_upper_limit' => $channelInfo['add_upper_limit'],
|
||||
]);
|
||||
|
||||
$channelInfo['presentUseUserList'] = $make->getColumn([['userid', 'in', $channelInfo['presentUseUserIds']]], 'name');
|
||||
$channelInfo['reserve_user_list'] = $make->getColumn([['userid', 'in', $channelInfo['reserve_userid']]], 'name');
|
||||
$channelInfo['user_list'] = $make->getColumn([['userid', 'in', $channelInfo['userids']]], 'name,userid,avatar');
|
||||
return $channelInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存和修改渠道二维码
|
||||
* @param array $data
|
||||
* @param int $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function saveChanne(array $data, int $id = 0)
|
||||
{
|
||||
$data['type'] = (int)$data['type'];
|
||||
$cycle = $data['cycle'];
|
||||
$useridLimit = $data['useridLimit'];
|
||||
unset($data['cycle'], $data['useridLimit']);
|
||||
//验证数据
|
||||
if (1 == $data['type']) {
|
||||
if (!count($cycle)) {
|
||||
throw new ValidateException('至少设置一个周期');
|
||||
}
|
||||
$this->checkEmployee($cycle);
|
||||
} else {
|
||||
if (!$data['userids']) {
|
||||
throw new ValidateException('必须选择一个成员');
|
||||
}
|
||||
if (count($data['userids']) > 100) {
|
||||
throw new ValidateException('选择的成员不能大于100个');
|
||||
}
|
||||
}
|
||||
//验证欢迎语
|
||||
$this->checkWelcome($data['welcome_words'], (int)$data['welcome_type']);
|
||||
|
||||
/** @var WorkChannelCycleServices $cycleService */
|
||||
$cycleService = app()->make(WorkChannelCycleServices::class);
|
||||
/** @var WorkChannelLimitServices $limitService */
|
||||
$limitService = app()->make(WorkChannelLimitServices::class);
|
||||
//保存数据
|
||||
$id = $this->transaction(function () use ($cycle, $id, $data, $cycleService, $useridLimit, $limitService) {
|
||||
$configId = null;
|
||||
if ($id) {
|
||||
$this->dao->update($id, $data);
|
||||
$configId = $this->dao->value(['id' => $id], 'config_id');
|
||||
} else {
|
||||
$data['create_time'] = time();
|
||||
$res = $this->dao->save($data);
|
||||
if (!$res) {
|
||||
throw new ValidateException('保存失败');
|
||||
}
|
||||
$id = $res->id;
|
||||
}
|
||||
$newCycle = $cycle;
|
||||
foreach ($cycle as &$item) {
|
||||
$item['channel_id'] = $id;
|
||||
$item['userids'] = json_encode($item['userids']);
|
||||
$item['wokr_time'] = json_encode($item['wokr_time']);
|
||||
}
|
||||
|
||||
foreach ($useridLimit as &$item) {
|
||||
$item['channel_id'] = $id;
|
||||
}
|
||||
$cycleService->delete(['channel_id' => $id]);
|
||||
$cycleService->saveAll($cycle);
|
||||
$limitService->delete(['channel_id' => $id]);
|
||||
$limitService->saveAll($useridLimit);
|
||||
|
||||
//提取在线成员生成二维码
|
||||
$userIds = $this->getPresentUseUserIds((int)$data['type'], $newCycle, $useridLimit, [
|
||||
'reserve_userid' => $data['reserve_userid'],
|
||||
'userids' => $data['userids'],
|
||||
'code_id' => $id,
|
||||
'add_upper_limit' => $data['add_upper_limit'],
|
||||
]);
|
||||
$this->handleQrCode((int)$id, $userIds, !!$data['skip_verify'], $configId);
|
||||
|
||||
return $id;
|
||||
});
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前时间内值班的成员userid
|
||||
* @param int $type
|
||||
* @param array $cycle
|
||||
* @param array $useridLimit
|
||||
* @param array $option
|
||||
* @return array|mixed
|
||||
*/
|
||||
public function getPresentUseUserIds(int $type, array $cycle, array $useridLimit, array $option = [])
|
||||
{
|
||||
$addUpperLimit = (int)($option['add_upper_limit'] ?? 0);
|
||||
if (0 !== $type) {
|
||||
$newUserIdLimit = [];
|
||||
foreach ($useridLimit as $item) {
|
||||
$newUserIdLimit[$item['userid']] = $item;
|
||||
}
|
||||
$userIds = $this->cycleByUserid($cycle, $newUserIdLimit, $option['code_id'], $addUpperLimit);
|
||||
} else {
|
||||
//限制添加成员
|
||||
if (1 === $addUpperLimit) {
|
||||
$userIds = $this->addClientLimit($option['userids'] ?? [], $useridLimit, $option['code_id']);
|
||||
} else {
|
||||
$userIds = $option['userids'] ?? [];
|
||||
}
|
||||
}
|
||||
if (!$userIds) {
|
||||
$userIds = $option['reserve_userid'] ?? [];
|
||||
}
|
||||
return $userIds;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检测成员限制
|
||||
* @param array $cycle
|
||||
*/
|
||||
public function checkEmployee(array $cycle)
|
||||
{
|
||||
$week = [];
|
||||
foreach ($cycle as $item) {
|
||||
foreach ($item['wokr_time'] as $num) {
|
||||
$week[$num] = array_merge(($week[$num] ?? []), $item['userids']);
|
||||
}
|
||||
}
|
||||
foreach ($week as $item) {
|
||||
if (count($item) > 100) {
|
||||
throw new ValidateException('周期内每个联系方式最多配置100个使用成员');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据周期规则获取当前值班成员userid
|
||||
* @param array $cycle
|
||||
* @param array $useridLimit
|
||||
* @param int $codeId
|
||||
* @param int $addUpperLimit
|
||||
* @return array
|
||||
*/
|
||||
public function cycleByUserid(array $cycle, array $useridLimit = [], int $codeId = 0, int $addUpperLimit = 0)
|
||||
{
|
||||
$userids = [];
|
||||
$weekNam = date('w');
|
||||
$nowHon = date('H:i');
|
||||
foreach ($cycle as $item) {
|
||||
//查询出当前周期内工作的值班人员
|
||||
if (in_array($weekNam, $item['wokr_time']) && $item['start_time'] <= $nowHon && $nowHon <= $item['end_time']) {
|
||||
$userids = array_merge($userids, $item['userids']);
|
||||
}
|
||||
//24小时值班人员
|
||||
if (in_array($weekNam, $item['wokr_time']) && $item['start_time'] == $item['end_time']) {
|
||||
$userids = array_merge($userids, $item['userids']);
|
||||
}
|
||||
}
|
||||
//每日值班人数大于100的需要使用备用人员
|
||||
$userids = array_merge(array_unique($userids));
|
||||
if ($userids && count($userids) > 100) {
|
||||
return [];
|
||||
}
|
||||
//不限制添加客户上限
|
||||
if (0 === $addUpperLimit) {
|
||||
return $userids;
|
||||
}
|
||||
return $this->addClientLimit($userids, $useridLimit, $codeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取添加员工上限
|
||||
* @param array $userids
|
||||
* @param array $useridLimit
|
||||
* @param int $codeId
|
||||
* @return array
|
||||
*/
|
||||
protected function addClientLimit(array $userids, array $useridLimit, int $codeId)
|
||||
{
|
||||
/** @var WorkClientFollowServices $followService */
|
||||
$followService = app()->make(WorkClientFollowServices::class);
|
||||
$userCount = $followService->userIdByCilentCount($userids, $codeId);
|
||||
if (!$userCount) {
|
||||
return $userids;
|
||||
}
|
||||
$useridLimitNew = [];
|
||||
foreach ($useridLimit as $value) {
|
||||
$useridLimitNew[$value['userid']] = $value;
|
||||
}
|
||||
$returnUserId = [];
|
||||
//限制员工每日添加客户个数
|
||||
foreach ($userids as $userid) {
|
||||
foreach ($userCount as $item) {
|
||||
if ($userid == $item['userid'] && $useridLimitNew[$userid]['max'] > $item['sum']) {
|
||||
$returnUserId[] = $userid;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $returnUserId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function deleteChannel(int $id)
|
||||
{
|
||||
$configId = $this->dao->value(['id' => $id], 'config_id');
|
||||
return $this->transaction(function () use ($id, $configId) {
|
||||
if ($configId) {
|
||||
Work::deleteQrCode($configId);
|
||||
}
|
||||
return $this->dao->destroy($id);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行生成渠道二维码
|
||||
* @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
|
||||
* @throws \GuzzleHttp\Exception\GuzzleException
|
||||
*/
|
||||
public function cronHandle()
|
||||
{
|
||||
$channelList = $this->dao->getDataList(['status' => 1, 'type' => 1], ['*'], 0, 0, null, ['cycle', 'useridLimit']);
|
||||
|
||||
foreach ($channelList as $item) {
|
||||
|
||||
//提取在线成员生成二维码
|
||||
$userIds = $this->getPresentUseUserIds(
|
||||
(int)$item['type'],
|
||||
$item['cycle'] ?? [],
|
||||
$item['useridLimit'] ?? [],
|
||||
[
|
||||
'reserve_userid' => $item['reserve_userid'],
|
||||
'userids' => $item['userids'],
|
||||
'code_id' => $item['id'],
|
||||
'add_upper_limit' => $item['add_upper_limit'],
|
||||
]
|
||||
);
|
||||
|
||||
if ($userIds) {
|
||||
$this->handleQrCode((int)$item['id'], $userIds, !!$item['skip_verify'], $item['config_id']);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
34
app/services/work/WorkChannelCycleServices.php
Normal file
34
app/services/work/WorkChannelCycleServices.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkChannelCycleDao;
|
||||
use app\services\BaseServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* 渠道码周期规则
|
||||
* Class WorkChannelCycleServices
|
||||
* @package app\services\work
|
||||
* @mixin WorkChannelCycleDao
|
||||
*/
|
||||
class WorkChannelCycleServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var WorkChannelCycleDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkChannelCycleDao $dao;
|
||||
|
||||
}
|
||||
33
app/services/work/WorkChannelLimitServices.php
Normal file
33
app/services/work/WorkChannelLimitServices.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkChannelLimitDao;
|
||||
use app\services\BaseServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* Class WorkChannelLimitServices
|
||||
* @package app\services\\work
|
||||
* @mixin WorkChannelLimitDao
|
||||
*/
|
||||
class WorkChannelLimitServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var WorkChannelLimitDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkChannelLimitDao $dao;
|
||||
|
||||
}
|
||||
61
app/services/work/WorkClientFollowServices.php
Normal file
61
app/services/work/WorkClientFollowServices.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkClientFollowDao;
|
||||
use app\services\BaseServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* 企业微信客户跟踪
|
||||
* Class WorkClientFollowServices
|
||||
* @package app\services\work
|
||||
* @mixin WorkClientFollowDao
|
||||
*/
|
||||
class WorkClientFollowServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var WorkClientFollowDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkClientFollowDao $dao;
|
||||
|
||||
|
||||
/**
|
||||
* 获取扫描渠道码添加的客户列表
|
||||
* @param int $channelId
|
||||
* @param string $name
|
||||
* @return array
|
||||
*/
|
||||
public function getChannelCodeClientList(int $channelId, string $name = '')
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$where = ['state' => 'channelCode-' . $channelId, 'user_name' => $name, 'is_del_user' => 0];
|
||||
$list = $this->dao->getDataList($where, ['createtime as create_time', 'client_id'], $page, $limit, 'create_time', ['client' => function ($query) {
|
||||
$query->field(['id', 'name', 'avatar']);
|
||||
}]);
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取渠道码客户数量
|
||||
* @param int $channelId 渠道码ID
|
||||
* @return int
|
||||
*/
|
||||
public function getChannelCodeClientCount($channelId)
|
||||
{
|
||||
return $this->dao->count(['state' => 'channelCode-' . $channelId, 'is_del_user' => 0]) ?? 0;
|
||||
}
|
||||
}
|
||||
34
app/services/work/WorkClientFollowTagsServices.php
Normal file
34
app/services/work/WorkClientFollowTagsServices.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkClientFollowTagsDao;
|
||||
use app\services\BaseServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* 企业微信客户跟踪标签
|
||||
* Class WorkClientFollowTagsServices
|
||||
* @package app\services\work
|
||||
* @mixin WorkClientFollowTagsDao
|
||||
*/
|
||||
class WorkClientFollowTagsServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var WorkClientFollowTagsDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkClientFollowTagsDao $dao;
|
||||
|
||||
}
|
||||
614
app/services/work/WorkClientServices.php
Normal file
614
app/services/work/WorkClientServices.php
Normal file
@@ -0,0 +1,614 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkClientDao;
|
||||
use app\jobs\work\WorkClientJob;
|
||||
use app\services\BaseServices;
|
||||
use app\services\user\label\UserLabelServices;
|
||||
use app\services\user\UserServices;
|
||||
use app\services\wechat\WechatUserServices;
|
||||
use crmeb\services\wechat\config\WorkConfig;
|
||||
use crmeb\services\wechat\WechatResponse;
|
||||
use crmeb\services\wechat\Work;
|
||||
use think\annotation\Inject;
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\DbException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
use think\exception\ValidateException;
|
||||
use think\facade\Log;
|
||||
|
||||
/**
|
||||
* 企业微信客户
|
||||
* Class WorkClientServices
|
||||
* @package app\services\work
|
||||
* @mixin WorkClientDao
|
||||
*/
|
||||
class WorkClientServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var WorkClientDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkClientDao $dao;
|
||||
|
||||
/**
|
||||
* @param array $where
|
||||
* @param array $field
|
||||
* @param bool $isPage
|
||||
* @return array
|
||||
*/
|
||||
public function getList(array $where, array $field = ['*'], bool $isPage = true)
|
||||
{
|
||||
$page = $limit = 0;
|
||||
if ($isPage) {
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
}
|
||||
$list = $this->dao->getDataList($where, $field, $page, $limit, 'create_time', [
|
||||
'followOne' => function ($query) {
|
||||
$query->with([
|
||||
'member' => function ($query) {
|
||||
$query->field(['userid', 'id', 'name', 'main_department'])
|
||||
->with(['mastareDepartment']);
|
||||
}
|
||||
])->field(['userid', 'client_id', 'state', 'id']);
|
||||
},
|
||||
'follow' => function ($query) {
|
||||
$query->field(['id', 'client_id'])->with(['tags']);
|
||||
},
|
||||
]);
|
||||
foreach ($list as &$item) {
|
||||
if (!empty($item['follow'])) {
|
||||
$tags = [];
|
||||
foreach ($item['follow'] as $value) {
|
||||
if (!empty($value['tags'])) {
|
||||
$tags = array_merge($tags, $value['tags']);
|
||||
}
|
||||
}
|
||||
$newTags = [];
|
||||
foreach ($tags as $tag) {
|
||||
if (!in_array($tag['tag_name'], array_column($newTags, 'tag_name'))) {
|
||||
$newTags[] = $tag;
|
||||
}
|
||||
}
|
||||
$item['followOne']['tags'] = $newTags;
|
||||
}
|
||||
}
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动同步客户
|
||||
* @param int $page
|
||||
* @param string $cursor
|
||||
* @return bool
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function authGetExternalcontact(int $page = 1, string $cursor = '')
|
||||
{
|
||||
/** @var WorkConfig $config */
|
||||
$config = app()->make(WorkConfig::class);
|
||||
$corpId = $config->corpId;
|
||||
if (!$corpId) {
|
||||
return true;
|
||||
}
|
||||
/** @var WorkMemberServices $memberService */
|
||||
$memberService = app()->make(WorkMemberServices::class);
|
||||
$menmberList = $memberService->getDataList(['corp_id' => $corpId], ['userid'], $page, 1);
|
||||
//没有数据就返回成功
|
||||
if (!$menmberList) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$tagRes = Work::getCorpTags();
|
||||
$tagMap = [];
|
||||
foreach ($tagRes["tag_group"]??[] as $tagGroupItem){
|
||||
foreach ($tagGroupItem["tag"]??[] as $tagItem){
|
||||
$tagMap[$tagItem["id"]] = $tagItem +["group_id"=>$tagGroupItem["group_id"],"group_name"=>$tagGroupItem["group_name"]];
|
||||
}
|
||||
}
|
||||
|
||||
$userids = array_column($menmberList, 'userid');
|
||||
try {
|
||||
$response = Work::getBatchClientList($userids, $cursor);
|
||||
$externalContactList = $response['external_contact_list'] ?? [];
|
||||
}catch (\Throwable $e){
|
||||
WorkClientJob::dispatchDo('authClient', [$page + 1, '']);
|
||||
return true;
|
||||
}
|
||||
|
||||
$external = [];
|
||||
$followUser = [];//内部人员跟踪
|
||||
$externalUserids = [];//客户信息
|
||||
$this->transaction(function () use ($externalContactList, $corpId, $externalUserids, $followUser, $external, $tagMap) {
|
||||
/** @var WechatUserServices $wechatUserService */
|
||||
$wechatUserService = app()->make(WechatUserServices::class);
|
||||
foreach ($externalContactList as $item) {
|
||||
$externalContact = $item['external_contact'];
|
||||
$unionid = $externalContact['unionid'] ?? '';
|
||||
if (isset($externalContact['unionid'])) {
|
||||
unset($externalContact['unionid']);
|
||||
}
|
||||
$corpName = $corpFullName = $position = '';
|
||||
if (isset($externalContact['corp_name'])) {
|
||||
$corpName = $externalContact['corp_name'];
|
||||
unset($externalContact['corp_name']);
|
||||
}
|
||||
if (isset($externalContact['corp_full_name'])) {
|
||||
$corpFullName = $externalContact['corp_full_name'];
|
||||
unset($externalContact['corp_full_name']);
|
||||
}
|
||||
if (isset($externalContact['position'])) {
|
||||
$position = $externalContact['position'];
|
||||
unset($externalContact['position']);
|
||||
}
|
||||
|
||||
$externalContact['position'] = $position;
|
||||
$externalContact['external_profile'] = json_encode($externalContact['external_profile'] ?? [],JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
|
||||
$followUserData = [
|
||||
'userid' => $item['follow_info']['userid'],
|
||||
'remark' => $item['follow_info']['remark'] ?? '',
|
||||
'description' => $item['follow_info']['description'] ?? '',
|
||||
'createtime' => $item['follow_info']['createtime'] ?? '',
|
||||
'remark_corp_name' => $item['follow_info']['remark_corp_name'] ?? '',
|
||||
'remark_mobiles' => json_encode($item['follow_info']['remark_mobiles'] ?? ''),
|
||||
'add_way' => $item['follow_info']['add_way'] ?? '',
|
||||
'state' => $item['follow_info']['state'] ?? '',
|
||||
'oper_userid' => $item['follow_info']['oper_userid'] ?? '',
|
||||
'create_time' => time(),
|
||||
'tags' => [],
|
||||
];
|
||||
|
||||
foreach ($item['follow_info']['tag_id']??[] as $tagId){
|
||||
$tag = $tagMap[$tagId]??[];
|
||||
$followUserData['tags'][] = [
|
||||
'group_name' => $tag['group_name'] ?? '',
|
||||
'tag_name' => $tag['name'] ?? '',
|
||||
'type' => $tag['type'] ?? 1,
|
||||
'tag_id' => $tag['id'],
|
||||
'create_time' => time()
|
||||
];
|
||||
}
|
||||
|
||||
$followUser[$externalContact['external_userid']] = $followUserData;
|
||||
$externalUserids[] = $externalContact['external_userid'];
|
||||
$externalUserid = $externalContact['external_userid'];
|
||||
$externalContact['uid'] = $wechatUserService->getOne(["unionid"=>$unionid],"uid")["uid"]??0;
|
||||
$externalContact['corp_id'] = $corpId;
|
||||
$externalContact['unionid'] = $unionid;
|
||||
$externalContact['corp_name'] = $corpName;
|
||||
$externalContact['corp_full_name'] = $corpFullName;
|
||||
if ($this->dao->count(['external_userid' => $externalUserid, 'corp_id' => $corpId])) {
|
||||
unset($externalContact['external_userid']);
|
||||
$this->dao->update(['external_userid' => $externalUserid], $externalContact);
|
||||
} else {
|
||||
$externalContact['create_time'] = $item['follow_info']['createtime'] ??time();
|
||||
$externalContact['update_time'] = time();
|
||||
$external[] = $externalContact;
|
||||
}
|
||||
}
|
||||
if ($external) {
|
||||
|
||||
$this->dao->saveAll($external);
|
||||
}
|
||||
$clientList = $this->dao->getColumn([['external_userid', 'in', $externalUserids], ['corp_id', '=', $corpId]], 'id', 'external_userid');
|
||||
/** @var WorkClientFollowServices $followService */
|
||||
$followService = app()->make(WorkClientFollowServices::class);
|
||||
if ($followUser) {
|
||||
/** @var WorkClientFollowTagsServices $tagService */
|
||||
$tagService = app()->make(WorkClientFollowTagsServices::class);
|
||||
foreach ($followUser as $userid => $items) {
|
||||
if(!isset($clientList[$userid])){
|
||||
continue;
|
||||
}
|
||||
$items['client_id'] = $clientList[$userid];
|
||||
if (($id = $followService->value(['client_id' => $clientList[$userid], 'userid' => $items['userid']], 'id'))) {
|
||||
$followService->update($id, [
|
||||
'remark' => $items['remark'],
|
||||
'description' => $items['description'],
|
||||
'createtime' => $items['createtime'],
|
||||
'remark_corp_name' => $items['remark_corp_name'],
|
||||
'remark_mobiles' => $items['remark_mobiles'],
|
||||
'add_way' => $items['add_way'],
|
||||
'oper_userid' => $items['oper_userid'],
|
||||
]);
|
||||
} else {
|
||||
$res = $followService->save($items);
|
||||
$id = $res->id;
|
||||
}
|
||||
if (!empty($items['tags'])) {
|
||||
$tagService->delete(['follow_id' => $id]);
|
||||
foreach ($items['tags'] as &$tag) {
|
||||
$tag['follow_id'] = $id;
|
||||
}
|
||||
$tagService->saveAll($items['tags']);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (isset($response['next_cursor']) && $response['next_cursor']) {
|
||||
WorkClientJob::dispatchDo('authClient', [$page, $response['next_cursor']]);
|
||||
} else if (empty($response['next_cursor'])) {
|
||||
WorkClientJob::dispatchDo('authClient', [$page + 1, '']);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 保存客户标签
|
||||
* @param array $tagGroup 标签组数据
|
||||
* @return void
|
||||
*/
|
||||
public function saveClientTags(array $tagGroup)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建客户
|
||||
* @param array $payload
|
||||
* @return mixed
|
||||
*/
|
||||
public function createClient(array $payload)
|
||||
{
|
||||
$corpId = $payload['ToUserName'];//企业id
|
||||
$externalUserID = $payload['ExternalUserID'];//外部企业userid
|
||||
$state = $payload['State'] ?? '';//扫码值
|
||||
$userId = $payload['UserID'];//成员userid
|
||||
|
||||
//保存客户
|
||||
$clientId = $this->saveOrUpdateClient($corpId, $externalUserID, $userId);
|
||||
|
||||
//发送欢迎语
|
||||
try {
|
||||
event('work.welcome', [$payload['WelcomeCode'] ?? '', $state, $clientId, $userId]);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error("发送欢迎语失败:" . json_encode([
|
||||
'message' => $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine()
|
||||
],JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
|
||||
//设置欢客户标签
|
||||
try {
|
||||
event('work.label', [$state, $userId, $externalUserID]);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error("设置欢客户标签失败:" . json_encode([
|
||||
'message' => $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine()
|
||||
],JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
|
||||
//关联客户与商城用户
|
||||
try {
|
||||
event('work.user', [$clientId]);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error("关联客户与商城用户失败:" . json_encode([
|
||||
'message' => $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine()
|
||||
],JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
|
||||
return $clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新客户信息
|
||||
* @param array $payload
|
||||
* @return mixed
|
||||
*/
|
||||
public function updateClient(array $payload)
|
||||
{
|
||||
$corpId = $payload['ToUserName'];
|
||||
$externalUserID = $payload['ExternalUserID'];
|
||||
$userId = $payload['UserID'];//成员serid
|
||||
|
||||
$clientId = $this->saveOrUpdateClient($corpId, $externalUserID, $userId);
|
||||
|
||||
//关联客户与商城用户
|
||||
try {
|
||||
event('work.user', [$clientId]);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error("关联客户与商城用户失败:" . json_encode([
|
||||
'message' => $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine()
|
||||
],JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
|
||||
return $clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 企业成员删除客户
|
||||
* @param array $payload
|
||||
* @return bool
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function deleteClient(array $payload)
|
||||
{
|
||||
$corpId = $payload['ToUserName'];
|
||||
$externalUserID = $payload['ExternalUserID'];
|
||||
$userId = $payload['UserID'];//成员serid
|
||||
$clientInfo = $this->dao->get(['external_userid' => $externalUserID, 'corp_id' => $corpId], ['id']);
|
||||
if ($clientInfo) {
|
||||
$this->transaction(function () use ($clientInfo, $userId) {
|
||||
$this->dao->destroy($clientInfo->id);
|
||||
/** @var WorkClientFollowServices $followService */
|
||||
$followService = app()->make(WorkClientFollowServices::class);
|
||||
$followService->update(['client_id' => $clientInfo->id, 'userid' => $userId], ['is_del_user' => 1]);
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户删除企业微信成员
|
||||
* @param array $payload
|
||||
* @return bool
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function deleteFollowClient(array $payload)
|
||||
{
|
||||
$corpId = $payload['ToUserName'];
|
||||
$externalUserID = $payload['ExternalUserID'];
|
||||
$userId = $payload['UserID'];//成员serid
|
||||
$clientInfo = $this->dao->get(['external_userid' => $externalUserID, 'corp_id' => $corpId], ['id']);
|
||||
/** @var WorkClientFollowServices $followService */
|
||||
$followService = app()->make(WorkClientFollowServices::class);
|
||||
if ($clientInfo) {
|
||||
$followService->update(['client_id' => $clientInfo->id, 'userid' => $userId], ['is_del_user' => 1]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新或者添加客户信息
|
||||
* @param string $corpId
|
||||
* @param string $externalUserID
|
||||
* @param string $userId
|
||||
* @return mixed
|
||||
*/
|
||||
public function saveOrUpdateClient(string $corpId, string $externalUserID, string $userId)
|
||||
{
|
||||
$response = Work::getClientInfo($externalUserID);
|
||||
$externalContact = $response['external_contact'] ?? [];
|
||||
$followUser = $response['follow_user'] ?? [];
|
||||
$res = true;
|
||||
$externalContact['corp_id'] = $corpId;
|
||||
$externalContact['external_profile'] = json_encode($externalContact['external_profile'] ?? []);
|
||||
$clientId = $this->dao->value(['external_userid' => $externalContact['external_userid'], 'corp_id' => $corpId], 'id');
|
||||
|
||||
try {
|
||||
$clientId = $this->transaction(function () use ($userId, $res, $clientId, $externalContact, $followUser) {
|
||||
if ($clientId) {
|
||||
$this->dao->update($clientId, $externalContact);
|
||||
} else {
|
||||
$res = $this->dao->save($externalContact);
|
||||
$clientId = $res->id;
|
||||
}
|
||||
$userids = [];
|
||||
$res1 = false;
|
||||
foreach ($followUser as &$item) {
|
||||
$item['create_time'] = time();
|
||||
if ($userId === $item['userid']) {
|
||||
$res1 = true;
|
||||
}
|
||||
$userids[] = $item['userid'];
|
||||
$item['client_id'] = $clientId;
|
||||
if (isset($item['wechat_channels'])) {
|
||||
unset($item['wechat_channels']);
|
||||
}
|
||||
}
|
||||
if (!$res1 && $userId) {
|
||||
$followUser[] = [
|
||||
'client_id' => $clientId,
|
||||
'userid' => $userId,
|
||||
'state' => $item["state"] ?? '',
|
||||
'createtime' => time(),
|
||||
'tags' => []
|
||||
];
|
||||
}
|
||||
//添加了此外部联系人的企业成员
|
||||
if ($followUser) {
|
||||
/** @var WorkClientFollowServices $followService */
|
||||
$followService = app()->make(WorkClientFollowServices::class);
|
||||
/** @var WorkClientFollowTagsServices $tagService */
|
||||
$tagService = app()->make(WorkClientFollowTagsServices::class);
|
||||
foreach ($followUser as $item) {
|
||||
if (($id = $followService->value(['client_id' => $clientId, 'userid' => $item['userid']], 'id'))) {
|
||||
$followService->update($id, [
|
||||
'remark' => $item['remark'],
|
||||
'description' => $item['description'],
|
||||
'remark_corp_name' => $item['remark_corp_name'] ?? '',
|
||||
'state' => $item["state"] ?? '',
|
||||
'add_way' => $item['add_way'] ?? '',
|
||||
'oper_userid' => $item['oper_userid'] ?? '',
|
||||
]);
|
||||
} else {
|
||||
$res = $followService->save($item);
|
||||
$id = $res->id;
|
||||
}
|
||||
$tagService->delete(['follow_id' => $id]);
|
||||
if (!empty($item['tags'])) {
|
||||
$tagsNews = [];
|
||||
foreach ($item['tags'] as $tag) {
|
||||
$tag['follow_id'] = $id;
|
||||
$tagsNews[] = $tag;
|
||||
}
|
||||
$tagService->saveAll($tagsNews);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$res) {
|
||||
throw new ValidateException('保存失败');
|
||||
}
|
||||
return $clientId;
|
||||
});
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
Log::error(json_encode([
|
||||
'message' => $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine()
|
||||
],JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
return $clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $userid
|
||||
* @param array $clientInfo
|
||||
* @return array
|
||||
*/
|
||||
public function getClientInfo(string $userid, array $clientInfo)
|
||||
{
|
||||
$clientInfo['userInfo'] = [];
|
||||
if ($clientInfo['uid']) {
|
||||
/** @var UserServices $make */
|
||||
$make = app()->make(UserServices::class);
|
||||
$userInfo = $make->get($clientInfo['uid'], ['*'], ['label', 'userGroup', 'spreadUser']);
|
||||
if ($userInfo) {
|
||||
$clientInfo['userInfo'] = $userInfo->toArray();
|
||||
// $clientInfo['userInfo']['birthday'] = $clientInfo['userInfo']['birthday'] ? date('Y-m-d', $clientInfo['userInfo']['birthday']) : '';
|
||||
}
|
||||
}
|
||||
return $clientInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步批量设置标签
|
||||
* @param array $addTag
|
||||
* @param array $removeTag
|
||||
* @param array $userId
|
||||
* @param array $where
|
||||
* @param int $isAll
|
||||
* @return bool
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function synchBatchLabel(array $addTag, array $removeTag, array $userId, array $where, int $isAll = 0)
|
||||
{
|
||||
if ($isAll) {
|
||||
$clientList = $this->dao->getDataList($where, ['external_userid', 'id', 'unionid', 'uid'], 0, 0, null, ['followOne']);
|
||||
} else {
|
||||
$clientList = $this->dao->getDataList(['external_userid' => $userId], ['external_userid', 'id', 'unionid', 'uid'], 0, 0, null, ['followOne']);
|
||||
}
|
||||
$batchClient = [];
|
||||
foreach ($clientList as $item) {
|
||||
if (!empty($item['followOne'])) {
|
||||
$batchClient[] = [
|
||||
'external_userid' => $item['external_userid'],
|
||||
'userid' => $item['followOne']['userid'],
|
||||
'add_tag' => $addTag,
|
||||
'remove_tag' => $removeTag,
|
||||
];
|
||||
}
|
||||
}
|
||||
if ($batchClient) {
|
||||
foreach ($batchClient as $item) {
|
||||
WorkClientJob::dispatchDo('setLabel', [$item]);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置客户标签
|
||||
* @param array $markTag
|
||||
* @return WechatResponse|false
|
||||
*/
|
||||
public function setClientMarkTag(array $markTag)
|
||||
{
|
||||
try {
|
||||
$res = Work::markTags($markTag['userid'], $markTag['external_userid'], $markTag['add_tag'], $markTag['remove_tag']);
|
||||
$res = new WechatResponse($res);
|
||||
//同步标签后同步用户信息
|
||||
/** @var WorkConfig $config */
|
||||
$config = app()->make(WorkConfig::class);
|
||||
WorkClientJob::dispatchSece(2, 'saveClientInfo', [$config->corpId, $markTag['external_userid'], $markTag['userid']]);
|
||||
return $res;
|
||||
} catch (\Throwable $e) {
|
||||
Log::error("修改客户标签发生错误:" . json_encode([
|
||||
'message' => $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine()
|
||||
],JSON_UNESCAPED_UNICODE));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找成员下附带的客户人数
|
||||
* @param array $where
|
||||
* @return int
|
||||
*/
|
||||
public function getUserIdsByCount(array $where)
|
||||
{
|
||||
if ($where['is_all']) {
|
||||
unset($where['time'], $where['label'], $where['notLabel']);
|
||||
}
|
||||
$where['timeKey'] = 'create_time';
|
||||
|
||||
if (!empty($where['label'])) {
|
||||
/** @var UserLabelServices $service */
|
||||
$service = app()->make(UserLabelServices::class);
|
||||
$tagId = $service->getColumn([
|
||||
['id', 'in', $where['label']],
|
||||
], 'tag_id');
|
||||
$where['label'] = array_unique($tagId);
|
||||
}
|
||||
if (!empty($where['notLabel'])) {
|
||||
/** @var UserLabelServices $service */
|
||||
$service = app()->make(UserLabelServices::class);
|
||||
$tagId = $service->getColumn([
|
||||
['id', 'in', $where['notLabel']],
|
||||
], 'tag_id');
|
||||
$where['notLabel'] = array_unique($tagId);
|
||||
}
|
||||
return $this->dao->getClientCount($where);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解绑用户
|
||||
* @param int $uid
|
||||
*/
|
||||
public function unboundUser(int $uid)
|
||||
{
|
||||
try {
|
||||
$this->dao->update(['uid' => $uid], ['uid' => 0]);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error("解绑用户失败:" . json_encode([
|
||||
'message' => $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine()
|
||||
],JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
}
|
||||
}
|
||||
56
app/services/work/WorkConfigServices.php
Normal file
56
app/services/work/WorkConfigServices.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\services\BaseServices;
|
||||
use crmeb\services\wechat\config\WorkConfig;
|
||||
use crmeb\services\wechat\contract\WorkAppConfigHandlerInterface;
|
||||
|
||||
/**
|
||||
* 企业微信配置
|
||||
* Class WorkConfigServices
|
||||
* @package app\services
|
||||
*/
|
||||
class WorkConfigServices extends BaseServices implements WorkAppConfigHandlerInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* 获取应用配置
|
||||
* @param string $corpId
|
||||
* @param string $type
|
||||
* @return array
|
||||
*/
|
||||
public function getAppConfig(string $corpId, string $type): array
|
||||
{
|
||||
$config = [];
|
||||
switch ($type) {
|
||||
case WorkConfig::TYPE_USER:
|
||||
$config = [
|
||||
'secret' => sys_config('wechat_work_user_secret')
|
||||
];
|
||||
break;
|
||||
case WorkConfig::TYPE_ADDRESS:
|
||||
$config = [
|
||||
'secret' => sys_config('wechat_work_address_secret'),
|
||||
];
|
||||
break;
|
||||
case WorkConfig::TYPE_USER_APP:
|
||||
$config = [
|
||||
'agent_id' => sys_config('wechat_work_build_agent_id'),
|
||||
'secret' => sys_config('wechat_work_build_secret'),
|
||||
];
|
||||
break;
|
||||
}
|
||||
return $config;
|
||||
}
|
||||
}
|
||||
210
app/services/work/WorkDepartmentServices.php
Normal file
210
app/services/work/WorkDepartmentServices.php
Normal file
@@ -0,0 +1,210 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkDepartmentDao;
|
||||
use app\jobs\work\WorkMemberJob;
|
||||
use app\services\BaseServices;
|
||||
use crmeb\services\wechat\config\WorkConfig;
|
||||
use crmeb\services\wechat\Work;
|
||||
use think\annotation\Inject;
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\DbException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
/**
|
||||
* 企业微信部门
|
||||
* Class WorkDepartmentServices
|
||||
* @package app\services\work
|
||||
* @mixin WorkDepartmentDao
|
||||
*/
|
||||
class WorkDepartmentServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var WorkDepartmentDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkDepartmentDao $dao;
|
||||
|
||||
|
||||
/**
|
||||
* 获取组织架构
|
||||
* @return mixed
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function getDepartmentList()
|
||||
{
|
||||
/** @var WorkConfig $config */
|
||||
$config = app()->make(WorkConfig::class);
|
||||
$data = $this->dao->getDataList(['corp_id' => $config->corpId], ['department_id', 'parentid', 'name', 'name_en']);
|
||||
$departmentId = array_column($data, 'department_id');
|
||||
if ($departmentId) {
|
||||
/** @var WorkMemberRelationServices $memberRelationService */
|
||||
$memberRelationService = app()->make(WorkMemberRelationServices::class);
|
||||
$memberList = $memberRelationService->getMemberRelationList([
|
||||
['department', 'in', $departmentId]
|
||||
], ['member_id', 'department']);
|
||||
foreach ($data as &$item) {
|
||||
$memberId = [];
|
||||
foreach ($memberList as $value) {
|
||||
if ($value['department'] == $item['department_id']) {
|
||||
$memberId[] = $value['member_id'];
|
||||
}
|
||||
}
|
||||
$item['count'] = count($memberId);
|
||||
}
|
||||
}
|
||||
return get_tree_children($data, 'children', 'department_id', 'parentid');
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步企业微信部门和成员信息
|
||||
*/
|
||||
public function authDepartment()
|
||||
{
|
||||
$res = Work::getDepartment();
|
||||
$department = $res['department'] ?? [];
|
||||
$data = [];
|
||||
$ids = [];
|
||||
/** @var WorkConfig $config */
|
||||
$config = app()->make(WorkConfig::class);
|
||||
$corpId = $config->corpId;
|
||||
if (!$corpId) {
|
||||
throw new ValidateException('请先配置企业微信ID');
|
||||
}
|
||||
foreach ($department as $item) {
|
||||
$item['srot'] = $item['order'] ?? '';
|
||||
$item['name_en'] = $item['name_en'] ?? '';
|
||||
$item['department_leader'] = json_encode($item['department_leader'] ?? []);
|
||||
$item['department_id'] = $item['id'] ?? '';
|
||||
unset($item['order'], $item['id']);
|
||||
if ($this->dao->count(['department_id' => $item['department_id'], 'corp_id' => $corpId])) {
|
||||
$this->dao->update(['department_id' => $item['department_id'], 'corp_id' => $corpId], [
|
||||
'name' => $item['name'] ?? '',
|
||||
'srot' => $item['srot'],
|
||||
'department_leader' => $item['department_leader'],
|
||||
'parentid' => $item['parentid']
|
||||
]);
|
||||
} else {
|
||||
$item['create_time'] = time();
|
||||
$item['corp_id'] = $corpId;
|
||||
$data[] = $item;
|
||||
}
|
||||
$ids[] = $item['department_id'];
|
||||
}
|
||||
if ($data) {
|
||||
$this->dao->saveAll($data);
|
||||
}
|
||||
if ($ids) {
|
||||
foreach ($ids as $id) {
|
||||
WorkMemberJob::dispatchDo('run', [$id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取部门+成员tree型数据
|
||||
* @param string $corpId
|
||||
* @param array $mobile
|
||||
* @return array
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function getMailChildren(string $corpId)
|
||||
{
|
||||
$list = $this->dao->getDataList(['corp_id' => $corpId], ['department_id', 'parentid', 'name', 'name_en'], 0, 0, 'srot', [
|
||||
'member' => fn($query) => $query->where('corp_id', $corpId)
|
||||
->field(['userid', 'id', 'mobile', 'avatar', 'thumb_avatar', 'name'])
|
||||
->with('departmentRelation')
|
||||
]);
|
||||
$userList = [];
|
||||
foreach ($list as $item) {
|
||||
if ($item['member'] && is_array($item['member'])) {
|
||||
$userList = array_merge($userList, $item['member']);
|
||||
}
|
||||
}
|
||||
foreach ($list as &$item) {
|
||||
$item['member'] = [];
|
||||
$user = [];
|
||||
foreach ($userList as $value) {
|
||||
$frameIds = $value['departmentRelation'] ? array_column($value['departmentRelation'], 'department') : [];
|
||||
unset($value['departmentRelation']);
|
||||
if (in_array($item['department_id'], $frameIds)) {
|
||||
$user[] = $value;
|
||||
}
|
||||
}
|
||||
$item['member'] = $user;
|
||||
$item['member_count'] = count($user);
|
||||
}
|
||||
return get_tree_children($list, 'children', 'department_id', 'parentid');
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建部门
|
||||
* @param array $payload
|
||||
* @return \crmeb\basic\BaseModel|mixed|\think\Model
|
||||
*/
|
||||
public function createDepartment(array $payload)
|
||||
{
|
||||
$corpId = $payload['ToUserName'];
|
||||
$where = ['corp_id' => $corpId, 'department_id' => $payload['Id']];
|
||||
|
||||
$departmentInfo = Work::getDepartmentInfo($payload['Id']);
|
||||
|
||||
if ($this->dao->count($where)) {
|
||||
return $this->updateDepartment($corpId, (int)$payload['Id'], $departmentInfo['department']['name']);
|
||||
} else {
|
||||
return $this->dao->save([
|
||||
'corp_id' => $corpId,
|
||||
'department_id' => $payload['Id'] ?? '',
|
||||
'name' => $departmentInfo['department']['name'] ?? '',
|
||||
'parentid' => $departmentInfo['department']['parentid'] ?? '',
|
||||
'sort' => $payload['order'] ?? '',
|
||||
'create_time' => time()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新部门
|
||||
* @param string $corpId
|
||||
* @param int $department_id
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function updateDepartment(string $corpId, int $departmentId, string $name)
|
||||
{
|
||||
if (!$name) {
|
||||
$departmentInfo = Work::getDepartmentInfo($departmentId);
|
||||
$name = $departmentInfo['department']['name'] ?? '';
|
||||
}
|
||||
|
||||
return $this->dao->update(['corp_id' => $corpId, 'department_id' => $departmentId], ['name' => $name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除部门
|
||||
* @param string $corpId
|
||||
* @param int $departmentId
|
||||
* @return mixed
|
||||
*/
|
||||
public function deleteDepartment(string $corpId, int $departmentId)
|
||||
{
|
||||
return $this->dao->delete(['corp_id' => $corpId, 'department_id' => $departmentId]);
|
||||
}
|
||||
}
|
||||
224
app/services/work/WorkGroupChatAuthServices.php
Normal file
224
app/services/work/WorkGroupChatAuthServices.php
Normal file
@@ -0,0 +1,224 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkGroupChatAuthDao;
|
||||
use app\services\BaseServices;
|
||||
use app\services\user\label\UserLabelServices;
|
||||
use crmeb\services\wechat\Work;
|
||||
use crmeb\traits\service\ContactWayQrCode;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
/**
|
||||
* 企业微信自动拉群
|
||||
* Class WorkGroupChatAuthServices
|
||||
* @package app\services\work
|
||||
*/
|
||||
class WorkGroupChatAuthServices extends BaseServices
|
||||
{
|
||||
|
||||
use ContactWayQrCode;
|
||||
|
||||
/**
|
||||
* @var WorkGroupChatAuthDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkGroupChatAuthDao $dao;
|
||||
|
||||
|
||||
/**
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getDataList($where, ['*'], $page, $limit, 'create_time');
|
||||
$chatIds = [];
|
||||
$labels = [];
|
||||
foreach ($list as $item) {
|
||||
$chatIds = array_merge($chatIds, $item['chat_id']);
|
||||
$labels = array_merge($labels, $item['label'] ?? []);
|
||||
}
|
||||
$chatIds = array_merge(array_unique(array_filter($chatIds)));
|
||||
$labels = array_merge(array_unique(array_filter($labels)));
|
||||
/** @var UserLabelServices $userLabelService */
|
||||
$userLabelService = app()->make(UserLabelServices::class);
|
||||
$labelList = $userLabelService->getColumn([
|
||||
['tag_id', 'in', $labels]
|
||||
], 'label_name', 'tag_id');
|
||||
/** @var WorkGroupChatServices $service */
|
||||
$service = app()->make(WorkGroupChatServices::class);
|
||||
$chatList = $service->getColumn([
|
||||
['chat_id', 'in', $chatIds]
|
||||
], 'name', 'chat_id');
|
||||
foreach ($list as &$item) {
|
||||
$chatNewList = $labelNewList = [];
|
||||
foreach ($chatList as $key => $val) {
|
||||
if (in_array($key, $item['chat_id'])) {
|
||||
$chatNewList[] = ['name' => $val, 'chat_id' => $key];
|
||||
}
|
||||
}
|
||||
if ($item['label']) {
|
||||
foreach ($labelList as $k => $v) {
|
||||
if (in_array($k, $item['label'])) {
|
||||
$labelNewList[] = ['name' => $v, 'label_id' => $k];
|
||||
}
|
||||
}
|
||||
}
|
||||
$item['chat_list'] = $chatNewList;
|
||||
$item['label_list'] = $labelNewList;
|
||||
}
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存或者修改自动拉群
|
||||
* @param array $data
|
||||
* @param int $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function saveGroupChatAuth(array $data, int $id = 0)
|
||||
{
|
||||
return $this->transaction(function () use ($data, $id) {
|
||||
if ($id) {
|
||||
$authInfo = $this->dao->get(['id' => $id], ['config_id']);
|
||||
$this->dao->update($id, $data);
|
||||
$this->handleGroupChat($data, $id, $authInfo->config_id);
|
||||
} else {
|
||||
$res = $this->dao->save($data);
|
||||
$id = $res->id;
|
||||
$this->handleGroupChat($data, $id);
|
||||
}
|
||||
return $id;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置加入群聊并获取二维码
|
||||
* @param string $configId
|
||||
* @param array $data
|
||||
* @param int $id
|
||||
* @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
|
||||
* @throws \GuzzleHttp\Exception\GuzzleException
|
||||
*/
|
||||
protected function handleGroupChat(array $data, int $id, string $configId = '')
|
||||
{
|
||||
//设置进群配置
|
||||
if ($configId) {
|
||||
$qrCode = Work::instance()->groupChat()->updateJoinWay($configId, $data['group_name'], $data['chat_id'], 'groupChat-' . $id, (int)$data['auth_group_chat'], (int)$data['group_num']);
|
||||
} else {
|
||||
$qrCode = Work::instance()->groupChat()->addJoinWay($data['group_name'], $data['chat_id'], 'groupChat-' . $id, (int)$data['auth_group_chat'], (int)$data['group_num']);
|
||||
}
|
||||
|
||||
if (0 !== $qrCode['errcode']) {
|
||||
throw new ValidateException($qrCode['errmsg']);
|
||||
}
|
||||
|
||||
if (!$configId) {
|
||||
$this->dao->update($id, ['config_id' => $qrCode['config_id']]);
|
||||
$configId = $qrCode['config_id'];
|
||||
}
|
||||
|
||||
//获取群二维码
|
||||
$qrCodeInfo = Work::instance()->groupChat()->getJoinWay($configId);
|
||||
if (0 !== $qrCodeInfo['errcode']) {
|
||||
throw new ValidateException($qrCodeInfo['errmsg']);
|
||||
}
|
||||
|
||||
$this->dao->update($id, ['qr_code' => $qrCodeInfo['join_way']['qr_code']]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除客户进群配置
|
||||
* @param int $id
|
||||
* @return bool
|
||||
* @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
|
||||
* @throws \GuzzleHttp\Exception\GuzzleException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function deleteGroupChatAuth(int $id)
|
||||
{
|
||||
$groupChatAuthInfo = $this->dao->get($id);
|
||||
|
||||
if (!$groupChatAuthInfo) {
|
||||
throw new ValidateException('删除的群聊配置不存在');
|
||||
}
|
||||
|
||||
//删除入群配置
|
||||
if ($groupChatAuthInfo->config_id) {
|
||||
$qrCode = Work::instance()->groupChat()->deleteJoinWay($groupChatAuthInfo->config_id);
|
||||
if (0 !== $qrCode['errcode']) {
|
||||
throw new ValidateException($qrCode['errmsg']);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->dao->destroy($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取群配置
|
||||
* @param int $id
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getGrouChatAuthInfo(int $id)
|
||||
{
|
||||
$groupChatAuthInfo = $this->dao->get($id);
|
||||
if (!$groupChatAuthInfo) {
|
||||
throw new ValidateException('删除的群聊配置不存在');
|
||||
}
|
||||
$groupChatAuthInfo['labelList'] = $groupChatAuthInfo['chatList'] = [];
|
||||
if ($groupChatAuthInfo->label) {
|
||||
/** @var UserLabelServices $userLabelService */
|
||||
$userLabelService = app()->make(UserLabelServices::class);
|
||||
$groupChatAuthInfo['labelList'] = $userLabelService->getColumn([
|
||||
['tag_id', 'in', $groupChatAuthInfo->label]
|
||||
], 'label_name,tag_id');
|
||||
}
|
||||
if ($groupChatAuthInfo->chat_id) {
|
||||
/** @var WorkGroupChatServices $service */
|
||||
$service = app()->make(WorkGroupChatServices::class);
|
||||
$groupChatAuthInfo['chatList'] = $service->getColumn([
|
||||
['chat_id', 'in', $groupChatAuthInfo->chat_id]
|
||||
], 'name,chat_id');
|
||||
}
|
||||
return $groupChatAuthInfo->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param int $groupAuthId
|
||||
* @param string $userid
|
||||
* @param string $externalUserID
|
||||
*/
|
||||
public function clientAddLabel(int $groupAuthId, string $userid, string $externalUserID)
|
||||
{
|
||||
$label = $this->dao->value(['id' => $groupAuthId], 'label');
|
||||
|
||||
$resTage = Work::markTags($userid, $externalUserID, $label);
|
||||
if (0 !== $resTage['errcode']) {
|
||||
throw new ValidateException($resTage['errmsg']);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
102
app/services/work/WorkGroupChatMemberServices.php
Normal file
102
app/services/work/WorkGroupChatMemberServices.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkGroupChatMemberDao;
|
||||
use app\services\BaseServices;
|
||||
use app\services\user\UserServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* 企业微信群成员
|
||||
* Class WorkGroupChatMemberServices
|
||||
* @package app\services\work
|
||||
* @mixin WorkGroupChatMemberDao
|
||||
*/
|
||||
class WorkGroupChatMemberServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var WorkGroupChatMemberDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkGroupChatMemberDao $dao;
|
||||
|
||||
/**
|
||||
* 获取群成员
|
||||
* @param int $chatId
|
||||
* @param string $name
|
||||
* @return array
|
||||
*/
|
||||
public function getChatMemberList(int $chatId, string $name = '')
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getDataList(['group_id' => $chatId, 'name_like' => $name, 'status' => 1], ['*'], $page, $limit, 'create_time', [
|
||||
'member' => function ($query) {
|
||||
$query->field(['name', 'userid', 'gender', 'avatar', 'id', 'mobile']);
|
||||
},
|
||||
'client' => function ($query) {
|
||||
$query->field(['name', 'external_userid', 'gender', 'avatar', 'id']);
|
||||
}
|
||||
]);
|
||||
$clientId = $mobile = [];
|
||||
|
||||
foreach ($list as &$item) {
|
||||
$item['group_chat_num'] = $this->dao->getChatSum($item['userid']);
|
||||
if ($item['group_chat_num'] > 0) {
|
||||
$item['group_chat_num']--;
|
||||
}
|
||||
if (isset($item['client']['id'])) {
|
||||
$clientId[] = $item['client']['id'];
|
||||
}
|
||||
if (isset($item['member'])) {
|
||||
$mobile[] = $item['member']['mobile'];
|
||||
}
|
||||
}
|
||||
/** @var WorkClientFollowServices $followService */
|
||||
$followService = app()->make(WorkClientFollowServices::class);
|
||||
$followList = $followService->getDataList(['client_id' => $clientId], ['id', 'client_id',], 0, 0, 'create_time', ['tags']);
|
||||
if ($followList) {
|
||||
foreach ($list as &$item) {
|
||||
$newTag = [];
|
||||
if (isset($item['client']['id'])) {
|
||||
foreach ($followList as $value) {
|
||||
if ($item['client']['id'] == $value['client_id'] && !empty($value['tags'])) {
|
||||
$newTag = array_column($value['tags'], 'tag_name');
|
||||
}
|
||||
}
|
||||
$item['tags'] = $newTag;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($mobile) {
|
||||
/** @var UserServices $userService */
|
||||
$userService = app()->make(UserServices::class);
|
||||
$userList = $userService->getList(['phone' => $mobile], 'phone,uid', 0, 0);
|
||||
if ($userList) {
|
||||
foreach ($list as &$item) {
|
||||
$newTag = [];
|
||||
if (isset($item['member'])) {
|
||||
foreach ($userList as $value) {
|
||||
if ($item['member']['mobile'] == $value['phone'] && !empty($value['label'])) {
|
||||
$newTag = array_column($value['label'], 'label_name');
|
||||
}
|
||||
}
|
||||
$item['tags'] = $newTag;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$count = $this->dao->count(['group_id' => $chatId, 'name_like' => $name, 'status' => 1]);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
}
|
||||
435
app/services/work/WorkGroupChatServices.php
Normal file
435
app/services/work/WorkGroupChatServices.php
Normal file
@@ -0,0 +1,435 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkGroupChatDao;
|
||||
use app\jobs\work\WorkClientJob;
|
||||
use app\jobs\work\WorkGroupChatJob;
|
||||
use app\services\BaseServices;
|
||||
use crmeb\services\wechat\config\WorkConfig;
|
||||
use crmeb\services\wechat\Work;
|
||||
use think\annotation\Inject;
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\DbException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
/**
|
||||
* Class WorkGroupChatServices
|
||||
* @package app\services\work
|
||||
* @mixin WorkGroupChatDao
|
||||
*/
|
||||
class WorkGroupChatServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var WorkGroupChatDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkGroupChatDao $dao;
|
||||
|
||||
/**
|
||||
* 获取客户群群发列表
|
||||
* @param array $where
|
||||
* @param array $with
|
||||
* @return array
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function groupChatList(array $where, array $with = [])
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->groupChat($where)->with($with)->page($page, $limit)->select()->toArray();
|
||||
$count = $this->dao->groupChat($where)->count();
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 群发详情列表
|
||||
* @param array $chatIds
|
||||
* @return array
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function getOwnerChatList(array $chatIds, $status = null)
|
||||
{
|
||||
return $this->groupChatList(['chat_id' => $chatIds, 'status' => $status], [
|
||||
'sendResult' => function ($query) {
|
||||
$query->field(['chat_id', 'status']);
|
||||
}, 'chatMember' => function ($query) {
|
||||
$query->field(['count(*) as sun', 'group_id']);
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步企业微信客户群
|
||||
* @param string|null $nextCursor
|
||||
* @return bool
|
||||
* @author 等风来
|
||||
* @email 136327134@qq.com
|
||||
* @date 2022/10/10
|
||||
*/
|
||||
public function authGroupChat(string $nextCursor = null)
|
||||
{
|
||||
$res = Work::getGroupChats([], 100, $nextCursor);
|
||||
if (0 !== $res['errcode']) {
|
||||
throw new ValidateException($res['errmsg']);
|
||||
}
|
||||
$groupChatList = $res['group_chat_list'] ?? [];
|
||||
/** @var WorkConfig $confg */
|
||||
$config = app()->make(WorkConfig::class);
|
||||
$corpId = $config->corpId;
|
||||
if (!$corpId) {
|
||||
throw new ValidateException('请先配置企业微信ID');
|
||||
}
|
||||
if ($groupChatList) {
|
||||
$groupChat = [];
|
||||
foreach ($groupChatList as $item) {
|
||||
$item['corp_id'] = $corpId;
|
||||
if (($id = $this->dao->value(['chat_id' => $item['chat_id'], 'corp_id' => $corpId], 'id'))) {
|
||||
$this->dao->update($id, $item);
|
||||
} else {
|
||||
$item['create_time'] = time();
|
||||
$groupChat[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
if ($groupChat) {
|
||||
$this->dao->saveAll($groupChat);
|
||||
}
|
||||
|
||||
foreach ($groupChatList as $item) {
|
||||
WorkGroupChatJob::dispatchDo('authChat', [$corpId, $item['chat_id']]);
|
||||
}
|
||||
|
||||
//如果有下一页继续执行
|
||||
if (!empty($res['next_cursor'])) {
|
||||
WorkGroupChatJob::dispatchDo('authGroupChat', [$res['next_cursor']]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存群详情
|
||||
* @param string $corpId
|
||||
* @param string $chatId
|
||||
* @return bool
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function saveWorkGroupChat(string $corpId, string $chatId)
|
||||
{
|
||||
$response = Work::getGroupChat($chatId);
|
||||
if (0 !== $response['errcode']) {
|
||||
throw new ValidateException($response['errmsg']);
|
||||
}
|
||||
$groupInfo = $response['group_chat'] ?? [];
|
||||
$groupInfo['admin_list'] = json_encode(array_column($groupInfo['admin_list'], 'userid'));
|
||||
$memberList = $groupInfo['member_list'] ?? [];
|
||||
unset($groupInfo['member_list']);
|
||||
$group = $this->dao->get(['corp_id' => $corpId, 'chat_id' => $chatId]);
|
||||
return $this->transaction(function () use ($chatId, $corpId, $group, $groupInfo, $memberList) {
|
||||
if ($group) {
|
||||
$group->name = $groupInfo['name'];
|
||||
$group->owner = $groupInfo['owner'];
|
||||
$group->notice = $groupInfo['notice'] ?? '';
|
||||
$group->group_create_time = $groupInfo['create_time'];
|
||||
$group->member_num = count($memberList);
|
||||
$group->save();
|
||||
} else {
|
||||
$group = $this->dao->save([
|
||||
'corp_id' => $corpId,
|
||||
'chat_id' => $chatId,
|
||||
'name' => $groupInfo['name'],
|
||||
'owner' => $groupInfo['owner'],
|
||||
'notice' => $groupInfo['notice'] ?? '',
|
||||
'member_num' => count($memberList),
|
||||
'group_create_time' => $groupInfo['create_time'],
|
||||
'status' => $groupInfo['status'] ?? 0,
|
||||
]);
|
||||
}
|
||||
$this->saveMember($memberList, $group->id, $group->member_num);
|
||||
return $group->id;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function getList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$where['timeKey'] = 'group_create_time';
|
||||
$where['status'] = [0, 2, 3];
|
||||
$list = $this->dao->getDataList($where, ['*'], $page, $limit, 'group_create_time', [
|
||||
'ownerInfo' => function ($query) {
|
||||
$query->field(['userid', 'name']);
|
||||
},
|
||||
]);
|
||||
|
||||
//提取管理员数据
|
||||
$adminUserId = [];
|
||||
foreach ($list as $item) {
|
||||
$adminUserId = array_merge($adminUserId, $item['admin_list'] ?? []);
|
||||
}
|
||||
$adminUserId = array_merge(array_unique(array_filter($adminUserId)));
|
||||
if ($adminUserId) {
|
||||
/** @var WorkMemberServices $memberService */
|
||||
$memberService = app()->make(WorkMemberServices::class);
|
||||
$adminUserList = $memberService->getColumn([
|
||||
['userid', 'in', $adminUserId],
|
||||
], 'name', 'userid');
|
||||
foreach ($list as &$item) {
|
||||
$newAdminUser = [];
|
||||
if (!empty($item['admin_list'])) {
|
||||
foreach ($adminUserList as $key => $value) {
|
||||
if (in_array($key, $item['admin_list'])) {
|
||||
$newAdminUser[] = ['name' => $value, 'userid' => $key];
|
||||
}
|
||||
}
|
||||
}
|
||||
$item['admin_user_list'] = $newAdminUser;
|
||||
}
|
||||
}
|
||||
|
||||
$count = $this->dao->count();
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 企业微信客户群变动
|
||||
* @param array $payload
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function updateGroupChat(array $payload)
|
||||
{
|
||||
$corpId = $payload['ToUserName'];
|
||||
$chatId = $payload['ChatId'];
|
||||
|
||||
$groupInfo = $this->dao->get(['corp_id' => $corpId, 'chat_id' => $chatId]);
|
||||
if (!$groupInfo) {
|
||||
$groupId = $this->saveWorkGroupChat($corpId, $chatId);
|
||||
$groupInfo = $this->dao->get($groupId);
|
||||
}
|
||||
$response = Work::getGroupChat($chatId);
|
||||
if (0 !== $response['errcode']) {
|
||||
throw new ValidateException($response['errmsg'] ?? '企业微信查询群详情失败');
|
||||
}
|
||||
$groupChat = $response['group_chat'] ?? [];
|
||||
$memberList = $groupChat['member_list'];
|
||||
|
||||
/** @var WorkGroupChatStatisticServices $statisticService */
|
||||
$statisticService = app()->make(WorkGroupChatStatisticServices::class);
|
||||
|
||||
$this->transaction(function () use ($payload, $groupInfo, $groupChat, $memberList, $statisticService) {
|
||||
switch ($payload['UpdateDetail']) {
|
||||
case 'add_member':
|
||||
$groupInfo->member_num++;
|
||||
$this->saveMember($memberList, $groupInfo->id, $groupInfo->member_num, true);
|
||||
$statisticService->saveOrUpdate($groupInfo->id, true, false, $groupInfo->member_num, $groupInfo->retreat_group_num);
|
||||
break;
|
||||
case 'del_member':
|
||||
$groupInfo->member_num--;
|
||||
$groupInfo->retreat_group_num++;
|
||||
$this->saveMember($memberList, $groupInfo->id, $groupInfo->member_num, false);
|
||||
$statisticService->saveOrUpdate($groupInfo->id, false, true, $groupInfo->member_num, $groupInfo->retreat_group_num);
|
||||
break;
|
||||
case 'change_owner':
|
||||
$groupInfo->owner = $groupChat['owner'];
|
||||
break;
|
||||
case 'change_name':
|
||||
$groupInfo->name = $groupChat['name'];
|
||||
break;
|
||||
case 'change_notice':
|
||||
$groupInfo->notice = $groupChat['notice'];
|
||||
break;
|
||||
}
|
||||
if (!empty($groupChat['admin_list'])) {
|
||||
$groupInfo->admin_list = json_encode(array_column($groupChat['admin_list'], 'userid'));
|
||||
}
|
||||
$groupInfo->save();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存群成员
|
||||
* @param array $memberList
|
||||
* @param int $groupId
|
||||
* @param int $sum
|
||||
* @param bool $plus
|
||||
* @return mixed
|
||||
*/
|
||||
public function saveMember(array $memberList, int $groupId, int $sum = 0, bool $plus = false)
|
||||
{
|
||||
$data = [];
|
||||
/** @var WorkGroupChatMemberServices $chatMemberService */
|
||||
$chatMemberService = app()->make(WorkGroupChatMemberServices::class);
|
||||
$newUserIds = array_column($memberList, 'userid');
|
||||
$userids = $chatMemberService->getColumn(['group_id' => $groupId], 'userid');
|
||||
$unUserIds = array_diff($userids, $newUserIds);
|
||||
$labelList = [];
|
||||
foreach ($memberList as $item) {
|
||||
$item['group_id'] = $groupId;
|
||||
$state = $item['state'] ?? '';
|
||||
if (isset($item['state'])) {
|
||||
unset($item['state']);
|
||||
}
|
||||
$item['invitor_userid'] = $item['invitor']['userid'] ?? '';
|
||||
$unionid = $item['unionid'] ?? '';
|
||||
unset($item['invitor'], $item['unionid']);
|
||||
if ($chatMemberService->count(['group_id' => $groupId, 'userid' => $item['userid']])) {
|
||||
$chatMemberService->update(['group_id' => $groupId, 'userid' => $item['userid']], [
|
||||
'type' => $item['type'],
|
||||
'unionid' => $unionid,
|
||||
'chat_sum' => $sum,
|
||||
'status' => 1,
|
||||
'join_time' => $item['join_time'],
|
||||
'join_scene' => $item['join_scene'],
|
||||
'invitor_userid' => $item['invitor_userid'],
|
||||
'group_nickname' => $item['group_nickname'],
|
||||
]);
|
||||
} else {
|
||||
if ($state) {
|
||||
$labelList[] = ['userid' => $item['userid'], 'type' => $item['type'], 'state' => $state];
|
||||
}
|
||||
$item['unionid'] = $unionid;
|
||||
$item['chat_sum'] = $sum;
|
||||
$item['state'] = $state;
|
||||
$item['create_time'] = time();
|
||||
$data[] = $item;
|
||||
}
|
||||
}
|
||||
if ($data) {
|
||||
$chatMemberService->saveAll($data);
|
||||
//如果没有客户信息同步客户信息
|
||||
/** @var WorkClientServices $clientService */
|
||||
$clientService = app()->make(WorkClientServices::class);
|
||||
$corpId = app()->make(WorkConfig::class)->corpId;
|
||||
foreach ($data as $item) {
|
||||
if (2 == $item['type'] && $clientService->count(['external_userid' => $item['userid']])) {
|
||||
WorkClientJob::dispatchDo('saveClientInfo', [$corpId, $item['userid'], '']);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($unUserIds) {
|
||||
$chatMemberService->update([
|
||||
['userid', 'in', $unUserIds]
|
||||
], ['status' => 0]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解散客户群
|
||||
* @param string $corpId
|
||||
* @param string $chatId
|
||||
* @return mixed
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function dismissGroupChat(string $corpId, string $chatId)
|
||||
{
|
||||
$groupChat = $this->dao->get(['corp_id' => $corpId, 'chat_id' => $chatId], ['id']);
|
||||
if (!$groupChat) {
|
||||
throw new ValidateException('没有查询到群');
|
||||
}
|
||||
return $this->transaction(function () use ($groupChat) {
|
||||
/** @var WorkGroupChatMemberServices $chatMemberService */
|
||||
$chatMemberService = app()->make(WorkGroupChatMemberServices::class);
|
||||
$chatMemberService->delete(['group_id' => $groupChat->id]);
|
||||
return $groupChat->delete();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 群统计
|
||||
* @param int $id
|
||||
* @param string $time
|
||||
* @return array
|
||||
*/
|
||||
public function getChatStatistics(int $id, string $time)
|
||||
{
|
||||
/** @var WorkGroupChatMemberServices $chatMemberService */
|
||||
$chatMemberService = app()->make(WorkGroupChatMemberServices::class);
|
||||
$data = [
|
||||
'toDaySum' => $chatMemberService->getToDaySum($id),
|
||||
'toDayReturn' => $chatMemberService->getToDayReturn($id),
|
||||
'groupChatSum' => $this->dao->value(['id' => $id], 'member_num'),
|
||||
'groupChatReturnSum' => $this->dao->value(['id' => $id], 'retreat_group_num')
|
||||
];
|
||||
$data['groupChatList'] = $chatMemberService->getChatMemberStatistics($id, 'join_time', ['count(*) as sum'], 1, $time);
|
||||
$data['groupChatReturnList'] = $chatMemberService->getChatMemberStatistics($id, 'join_time', ['count(*) as sum'], 0, $time);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 群成员统计
|
||||
* @param int $id
|
||||
* @param string $time
|
||||
* @return array
|
||||
*/
|
||||
public function getChatStatisticsList(int $id, string $time)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
/** @var WorkGroupChatMemberServices $chatMemberService */
|
||||
$chatMemberService = app()->make(WorkGroupChatMemberServices::class);
|
||||
$newCount = $chatMemberService->getChatMemberStatisticsCount($id, 1, $time);
|
||||
$returnCount = $chatMemberService->getChatMemberStatisticsCount($id, 0, $time);
|
||||
$SumCount = $newCount > $returnCount ? $newCount : $returnCount;
|
||||
$groupChatList = $chatMemberService->getChatMemberStatistics($id, 'join_time', ['count(*) as sum', 'chat_sum', 'retreat_chat_num'], 1, $time, $page, $limit);
|
||||
$groupChatReturnList = $chatMemberService->getChatMemberStatistics($id, 'join_time', ['count(*) as retreat_sum'], 0, $time, $page, $limit);
|
||||
$count = ($rCount = count($groupChatReturnList)) > ($count = count($groupChatList)) ? $rCount : $count;
|
||||
$data = [];
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$data[] = [
|
||||
'time' => $groupChatList[$i]['time'] ?? $groupChatReturnList[$i]['time'] ?? '',
|
||||
'sum' => $groupChatList[$i]['sum'] ?? 0,
|
||||
'retreat_chat_num' => $groupChatList[$i]['retreat_chat_num'] ?? 0,
|
||||
'chat_sum' => $groupChatList[$i]['chat_sum'] ?? 0,
|
||||
'retreat_sum' => $groupChatReturnList[$i]['retreat_sum'] ?? 0,
|
||||
];
|
||||
}
|
||||
return ['list' => $data, 'count' => $SumCount];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $chatId
|
||||
* @param string $corpId
|
||||
* @return array
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function getGroupInfo(string $chatId, string $corpId)
|
||||
{
|
||||
$groupInfo = $this->dao->get(['chat_id' => $chatId, 'corp_id' => $corpId]);
|
||||
if (!$groupInfo) {
|
||||
throw new ValidateException('客户群未查到');
|
||||
}
|
||||
/** @var WorkGroupChatMemberServices $service */
|
||||
$service = app()->make(WorkGroupChatMemberServices::class);
|
||||
$groupInfo['todaySum'] = $service->getToDaySum($groupInfo->id);
|
||||
$groupInfo['todayReturnSum'] = $service->getToDayReturn($groupInfo->id);
|
||||
return $groupInfo->toArray();
|
||||
}
|
||||
}
|
||||
83
app/services/work/WorkGroupChatStatisticServices.php
Normal file
83
app/services/work/WorkGroupChatStatisticServices.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkGroupChatStatisticDao;
|
||||
use app\services\BaseServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* 群聊统计
|
||||
* Class WorkGroupChatStatisticServices
|
||||
* @package app\services\work
|
||||
* @mixin WorkGroupChatStatisticDao
|
||||
*/
|
||||
class WorkGroupChatStatisticServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var WorkGroupChatStatisticDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkGroupChatStatisticDao $dao;
|
||||
|
||||
|
||||
/**
|
||||
* 保存或者修改
|
||||
* @param int $chatId
|
||||
* @param bool $todaySum
|
||||
* @param bool $todayReturnSum
|
||||
* @param int $chatSum
|
||||
* @param int $chatReturnSum
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function saveOrUpdate(int $chatId, bool $todaySum, bool $todayReturnSum, int $chatSum, int $chatReturnSum)
|
||||
{
|
||||
$info = $this->dao->getToDayInfo($chatId);
|
||||
if ($info) {
|
||||
if ($todaySum) {
|
||||
$info->today_sum++;
|
||||
}
|
||||
if ($todayReturnSum) {
|
||||
$info->today_return_sum++;
|
||||
}
|
||||
$info->chat_sum = $chatSum;
|
||||
$info->chat_return_sum = $chatReturnSum;
|
||||
$info->save();
|
||||
} else {
|
||||
$this->dao->save([
|
||||
'group_id' => $chatId,
|
||||
'today_sum' => $todaySum ? 1 : 0,
|
||||
'today_return_sum' => $todayReturnSum ? 1 : 0,
|
||||
'chat_sum' => $chatSum,
|
||||
'chat_return_sum' => $chatReturnSum,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 群统计列表
|
||||
* @param int $id
|
||||
* @param string $time
|
||||
* @return array
|
||||
*/
|
||||
public function getChatStatisticsList(int $id, string $time)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getDataList(['time' => $time, 'group_id' => $id], ['*'], $page, $limit);
|
||||
$count = $this->dao->count(['time' => $time, 'group_id' => $id]);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
}
|
||||
34
app/services/work/WorkGroupMsgRelationServices.php
Normal file
34
app/services/work/WorkGroupMsgRelationServices.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkGroupMsgRelationDao;
|
||||
use app\services\BaseServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* 企业微信群发关联表
|
||||
* Class WorkGroupMsgRelationServices
|
||||
* @package app\services\work
|
||||
* @mixin WorkGroupMsgRelationDao
|
||||
*/
|
||||
class WorkGroupMsgRelationServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var WorkGroupMsgRelationDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkGroupMsgRelationDao $dao;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkGroupMsgSendResultGroupChatDao;
|
||||
use app\services\BaseServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* Class WorkGroupMsgSendResultGroupChatServices
|
||||
* @package app\services\work
|
||||
* @mixin WorkGroupMsgSendResultGroupChatDao
|
||||
*/
|
||||
class WorkGroupMsgSendResultGroupChatServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var WorkGroupMsgSendResultGroupChatDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkGroupMsgSendResultGroupChatDao $dao;
|
||||
|
||||
/**
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
|
||||
$list = $this->dao->groupChat($where)->page($page, $limit)->select()->toArray();
|
||||
$count = $this->dao->groupChat($where)->count();
|
||||
return compact('list', 'count');
|
||||
}
|
||||
}
|
||||
123
app/services/work/WorkGroupMsgSendResultServices.php
Normal file
123
app/services/work/WorkGroupMsgSendResultServices.php
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkGroupMsgSendResultDao;
|
||||
use app\jobs\work\WorkGroupMsgJob;
|
||||
use app\services\BaseServices;
|
||||
use crmeb\services\wechat\Work;
|
||||
use think\annotation\Inject;
|
||||
use think\facade\Log;
|
||||
|
||||
/**
|
||||
* 企业微信群发消息客户发送详情
|
||||
* Class WorkGroupMsgSendResultServices
|
||||
* @package app\services\work
|
||||
* @mixin WorkGroupMsgSendResultDao
|
||||
*/
|
||||
class WorkGroupMsgSendResultServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var WorkGroupMsgSendResultDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkGroupMsgSendResultDao $dao;
|
||||
|
||||
/**
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getClientList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getDataList($where, ['*'], $page, $limit, 'create_time', ['client']);
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取群主发送详情
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getGroupChatMsgList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getGroupChatMsg($where)->whereNotNull('chat_id')->page($page, $limit)->select()->toArray();
|
||||
$count = $this->dao->getGroupChatMsg($where)->whereNotNull('chat_id')->count();
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取企业群发成员执行结果
|
||||
* @param int $type
|
||||
* @param string $userid
|
||||
* @param string $msgid
|
||||
* @param string|null $cursor
|
||||
* @return bool
|
||||
*/
|
||||
public function getSendResult(int $type, string $userid, string $msgid, string $cursor = null)
|
||||
{
|
||||
try {
|
||||
$response = Work::getGroupmsgSendResult($msgid, $userid, 500, $cursor);
|
||||
|
||||
$sendList = $response['send_list'] ?? [];
|
||||
foreach ($sendList as $item) {
|
||||
$where = ['msg_id' => $msgid, 'userid' => $userid];
|
||||
if ($type) {
|
||||
$where['chat_id'] = $item['chat_id'];
|
||||
} else {
|
||||
$where['external_userid'] = $item['external_userid'];
|
||||
}
|
||||
$info = $this->dao->get($where);
|
||||
if (!$info) {
|
||||
$this->dao->save([
|
||||
'msg_id' => $msgid,
|
||||
'userid' => $item['userid'],
|
||||
'chat_id' => $item['chat_id'] ?? null,
|
||||
'status' => $item['status'],
|
||||
'send_time' => $item['send_time'] ?? 0,
|
||||
'external_userid' => $item['external_userid'] ?? null,
|
||||
]);
|
||||
} else {
|
||||
$info->status = $item['status'];
|
||||
$info->send_time = $item['send_time'] ?? 0;
|
||||
$info->save();
|
||||
}
|
||||
}
|
||||
|
||||
if ($response['next_cursor']) {
|
||||
WorkGroupMsgJob::dispatchDo('getSendResult', [$type, $userid, $msgid, $response['next_cursor']]);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (\Throwable $e) {
|
||||
Log::error(
|
||||
json_encode([
|
||||
'message' => '获取企业群发成员执行结果失败:' . $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine(),
|
||||
], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
116
app/services/work/WorkGroupMsgTaskServices.php
Normal file
116
app/services/work/WorkGroupMsgTaskServices.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkGroupMsgTaskDao;
|
||||
use app\jobs\work\WorkGroupMsgJob;
|
||||
use app\services\BaseServices;
|
||||
use crmeb\services\wechat\Work;
|
||||
use think\annotation\Inject;
|
||||
use think\facade\Log;
|
||||
|
||||
/**
|
||||
* 企业微信群发消息任务
|
||||
* Class WorkGroupMsgTaskServices
|
||||
* @package app\services\work
|
||||
* @mixin WorkGroupMsgTaskDao
|
||||
*/
|
||||
class WorkGroupMsgTaskServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var WorkGroupMsgTaskDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkGroupMsgTaskDao $dao;
|
||||
|
||||
/**
|
||||
* 获取成员列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function getTaksList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getDataList($where, ['*'], $page, $limit, 'send_time', [
|
||||
'member', 'sendResult' => function ($query) use ($where) {
|
||||
$query->whereIn('msg_id', $where['msg_id'])->field(['userid', 'count(*) as num_count'])->group('userid');
|
||||
}
|
||||
]);
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取群发成员发送任务列表
|
||||
* @param int $type
|
||||
* @param string $msgid
|
||||
* @param string|null $cursor
|
||||
* @return bool
|
||||
*/
|
||||
public function getTaks(int $type, string $msgid, string $cursor = null)
|
||||
{
|
||||
try {
|
||||
$response = Work::getGroupmsgTask($msgid, 500, $cursor);
|
||||
|
||||
$taskList = $response['task_list'] ?? [];
|
||||
|
||||
foreach ($taskList as $item) {
|
||||
$info = $this->dao->get(['msg_id' => $msgid, 'userid' => $item['userid']]);
|
||||
if (!$info) {
|
||||
$info = $this->dao->save([
|
||||
'msg_id' => $msgid,
|
||||
'userid' => $item['userid'],
|
||||
'status' => $item['status'],
|
||||
'create_time' => time(),
|
||||
'send_time' => $item['send_time'] ?? 0
|
||||
]);
|
||||
} else {
|
||||
$info->status = $item['status'];
|
||||
$info->send_time = $item['send_time'] ?? 0;
|
||||
$info->save();
|
||||
}
|
||||
WorkGroupMsgJob::dispatchDo('getSendResult', [$type, $item['userid'], $msgid, null]);
|
||||
}
|
||||
|
||||
if ($response['next_cursor']) {
|
||||
WorkGroupMsgJob::dispatchDo('getTaks', [$type, $msgid, $cursor]);
|
||||
}
|
||||
return true;
|
||||
} catch (\Throwable $e) {
|
||||
Log::error(
|
||||
json_encode([
|
||||
'message' => '获取群发成员发送任务列表失败:' . $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine(),
|
||||
], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计群发模板数据
|
||||
* @param array $msgIds
|
||||
* @return array
|
||||
*/
|
||||
public function getSendMsgStatistics(array $msgIds, int $type = 0)
|
||||
{
|
||||
$data = [];
|
||||
$data['user_count'] = $data['unuser_count'] = $data['external_user_count'] = $data['external_unuser_count'] = 0;
|
||||
$data['user_count'] = $this->dao->count(['msg_id' => $msgIds, 'status' => 2]);
|
||||
$data['unuser_count'] = $this->dao->count(['msg_id' => $msgIds, 'status' => 0]);
|
||||
/** @var WorkGroupMsgSendResultServices $service */
|
||||
$service = app()->make(WorkGroupMsgSendResultServices::class);
|
||||
if ($type) {
|
||||
$data['external_user_count'] = $service->count(['msg_id' => $msgIds, 'notChatId' => true, 'status' => 1]);
|
||||
$data['external_unuser_count'] = $service->count(['msg_id' => $msgIds, 'notChatId' => true, 'status' => [0, 2, 3]]);
|
||||
} else {
|
||||
$data['external_user_count'] = $service->count(['msg_id' => $msgIds, 'status' => 1]);
|
||||
$data['external_unuser_count'] = $service->count(['msg_id' => $msgIds, 'status' => [0, 2, 3]]);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
334
app/services/work/WorkGroupTemplateServices.php
Normal file
334
app/services/work/WorkGroupTemplateServices.php
Normal file
@@ -0,0 +1,334 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkGroupTemplateDao;
|
||||
use app\jobs\work\WorkGroupMsgJob;
|
||||
use app\services\BaseServices;
|
||||
use crmeb\services\wechat\WechatResponse;
|
||||
use crmeb\traits\service\ContactWayQrCode;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
use think\facade\Event;
|
||||
use think\facade\Log;
|
||||
|
||||
/**
|
||||
* 企业微信群发模板
|
||||
* Class WorkGroupTemplateServices
|
||||
* @package app\services\work
|
||||
* @mixin WorkGroupTemplateDao
|
||||
*/
|
||||
class WorkGroupTemplateServices extends BaseServices
|
||||
{
|
||||
|
||||
use ContactWayQrCode;
|
||||
|
||||
/**
|
||||
* @var WorkGroupTemplateDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkGroupTemplateDao $dao;
|
||||
|
||||
/**
|
||||
* 获取群聊模板列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getGroupTemplate(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getDataList($where, ['*'], $page, $limit, 'create_time', ['msgIds']);
|
||||
/** @var WorkGroupMsgTaskServices $taskService */
|
||||
$taskService = app()->make(WorkGroupMsgTaskServices::class);
|
||||
foreach ($list as &$item) {
|
||||
$item['user_count'] = $item['unuser_count'] = $item['external_user_count'] = $item['external_unuser_count'] = 0;
|
||||
if (!empty($item['msgIds'])) {
|
||||
$msgIds = [];
|
||||
foreach ($item['msgIds'] as $value) {
|
||||
$msgIds[] = $value['msg_id'];
|
||||
if ($value['msg_id']) {
|
||||
WorkGroupMsgJob::dispatchDo('getTaks', [(int)$item['type'], $value['msg_id'], null]);
|
||||
}
|
||||
}
|
||||
$item = array_merge($item, $taskService->getSendMsgStatistics($msgIds, (int)$item['type']));
|
||||
}
|
||||
}
|
||||
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建或者修改
|
||||
* @param array $data
|
||||
*/
|
||||
public function saveGroupTemplate(array $data)
|
||||
{
|
||||
$this->checkWelcome($data['welcome_words'], 0);
|
||||
|
||||
$this->transaction(function () use ($data) {
|
||||
$res = $this->dao->save($data);
|
||||
//立即发送或者选择的时间小于当前时间
|
||||
if (!$data['template_type'] || ($data['template_type'] == 1 && $data['send_time'] < time())) {
|
||||
if ($data['type']) {
|
||||
WorkGroupMsgJob::dispatchDo('batch', [$res->id, '', 0]);
|
||||
} else {
|
||||
foreach ($data['userids'] as $key => $userid) {
|
||||
WorkGroupMsgJob::dispatchDo('batch', [$res->id, $userid, $key + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量发送
|
||||
* @param int $id
|
||||
* @param string $userId
|
||||
* @param int $count
|
||||
* @return bool
|
||||
*/
|
||||
public function batch(int $id, string $userId, int $count)
|
||||
{
|
||||
try {
|
||||
$groupTempInfo = $this->dao->get($id);
|
||||
if (!$groupTempInfo) {
|
||||
return true;
|
||||
}
|
||||
if ($groupTempInfo->send_type == 1) {
|
||||
return true;
|
||||
}
|
||||
$groupTempInfo = $groupTempInfo->toArray();
|
||||
$externalUserid = [];
|
||||
if (!$groupTempInfo['type']) {
|
||||
/** @var WorkClientServices $service */
|
||||
$service = app()->make(WorkClientServices::class);
|
||||
$where = ['userid' => $userId];
|
||||
if ($groupTempInfo['client_type']) {
|
||||
//条件筛选
|
||||
if ($groupTempInfo['where_time']) {
|
||||
$where['time'] = $groupTempInfo['where_time'];
|
||||
$where['timeKey'] = 'create_time';
|
||||
}
|
||||
if ($groupTempInfo['where_label']) {
|
||||
$where['label'] = $groupTempInfo['where_label'];
|
||||
}
|
||||
if ($groupTempInfo['notLabel']) {
|
||||
$where['notLabel'] = $groupTempInfo['where_not_label'];
|
||||
}
|
||||
}
|
||||
$externalUserid = $service->getClientUserIds($where);
|
||||
}
|
||||
$this->sendTask($id, $externalUserid, $groupTempInfo, $count);
|
||||
return true;
|
||||
} catch (\Throwable $e) {
|
||||
Log::error(
|
||||
json_encode([
|
||||
'message' => '创建群发任务失败:' . $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine()
|
||||
], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
|
||||
);
|
||||
//记录发送失败原因
|
||||
try {
|
||||
$this->dao->update($id, ['send_type' => -1, 'fail_message' => '创建群发任务失败:' . $e->getMessage()]);
|
||||
} catch (\Throwable $e) {
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param array $externalUserid
|
||||
* @param array $data
|
||||
* @param int $count
|
||||
*/
|
||||
public function sendTask(int $id, array $externalUserid, array $data, int $count)
|
||||
{
|
||||
$update = [];
|
||||
/** @var WorkGroupMsgRelationServices $msgRelationService */
|
||||
$msgRelationService = app()->make(WorkGroupMsgRelationServices::class);
|
||||
if ($data['type']) {
|
||||
//群主群发
|
||||
$failList = [];
|
||||
$msgIdData = [];
|
||||
foreach ($data['userids'] as $item) {
|
||||
$res = $this->sendMsgTemplate([], $data['welcome_words'], 'group', $item);
|
||||
$failList = array_merge($failList, $res['fail_list'] ?? []);
|
||||
if (isset($res['msgid'])) {
|
||||
$msgIdData[] = $res['msgid'];
|
||||
}
|
||||
}
|
||||
$update['send_type'] = 1;
|
||||
if ($failList) {
|
||||
$update['fail_external_userid'] = json_encode($failList);
|
||||
}
|
||||
if ($update) {
|
||||
$this->dao->update($id, $update);
|
||||
}
|
||||
$msgRelation = [];
|
||||
foreach ($msgIdData as $msgId) {
|
||||
$msgRelation[] = ['template_id' => $id, 'msg_id' => $msgId];
|
||||
WorkGroupMsgJob::dispatchSece(60, 'getTaks', [(int)$data['type'], $msgId, null]);
|
||||
}
|
||||
$msgRelationService->saveAll($msgRelation);
|
||||
} else {
|
||||
//成员群发
|
||||
$sendTemplateWelcome = $this->sendMsgTemplate($externalUserid, $data['welcome_words']);
|
||||
$failList = $sendTemplateWelcome['fail_list'] ?? [];
|
||||
if ($failList) {
|
||||
$update['fail_external_userid'] = json_encode($failList);
|
||||
}
|
||||
if ($count == count($data['userids'])) {
|
||||
$update['send_type'] = 1;
|
||||
} else {
|
||||
$update['send_type'] = 2;
|
||||
}
|
||||
if ($update) {
|
||||
$this->dao->update($id, $update);
|
||||
}
|
||||
$msgRelationService->save(['template_id' => $id, 'msg_id' => $sendTemplateWelcome['msgid']]);
|
||||
WorkGroupMsgJob::dispatchSece(60, 'getTaks', [(int)$data['type'], $sendTemplateWelcome['msgid'], null]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 群发任务详情
|
||||
* @param int $id
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getGroupTemplateInfo(int $id)
|
||||
{
|
||||
$info = $this->dao->get($id, ['*'], ['msgIds']);
|
||||
|
||||
if (!$info) {
|
||||
throw new ValidateException('没有查到此数据');
|
||||
}
|
||||
$msgIds = [];
|
||||
$info = $info->toArray();
|
||||
if (!empty($info['msgIds'])) {
|
||||
$msgIds = array_column($info['msgIds'], 'msg_id');
|
||||
}
|
||||
$info['user_count'] = $info['unuser_count'] = $info['external_user_count'] = $info['external_unuser_count'] = 0;
|
||||
$info['user_list'] = [];
|
||||
if ($info['userids']) {
|
||||
/** @var WorkMemberServices $service */
|
||||
$service = app()->make(WorkMemberServices::class);
|
||||
$info['user_list'] = $service->getColumn([
|
||||
['userid', 'in', $info['userids']]
|
||||
], 'userid,name');
|
||||
}
|
||||
if ($msgIds) {
|
||||
/** @var WorkGroupMsgTaskServices $taskService */
|
||||
$taskService = app()->make(WorkGroupMsgTaskServices::class);
|
||||
$info = array_merge($info, $taskService->getSendMsgStatistics($msgIds, (int)$info['type']));
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除群发模板
|
||||
* @param int $id
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteGroupTemplate(int $id)
|
||||
{
|
||||
/** @var WorkGroupMsgTaskServices $taskService */
|
||||
$taskService = app()->make(WorkGroupMsgTaskServices::class);
|
||||
/** @var WorkGroupMsgRelationServices $msgRelationService */
|
||||
$msgRelationService = app()->make(WorkGroupMsgRelationServices::class);
|
||||
/** @var WorkGroupMsgSendResultServices $sendResultService */
|
||||
$sendResultService = app()->make(WorkGroupMsgSendResultServices::class);
|
||||
$msgIds = $msgRelationService->getColumn(['template_id' => $id], 'msg_id');
|
||||
$this->transaction(function () use ($id, $msgRelationService, $msgIds, $taskService, $sendResultService) {
|
||||
$this->dao->delete($id);
|
||||
if ($msgIds) {
|
||||
$taskService->delete(['msg_id' => $msgIds]);
|
||||
$sendResultService->delete(['msg_id' => $msgIds]);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行定时发送群发内容
|
||||
*/
|
||||
public function cornHandle()
|
||||
{
|
||||
$time = time();
|
||||
$list = $this->dao->getDataList(['send_time' => $time, 'send_type' => 0], ['*'], 0, 0, null, ['msgIds']);
|
||||
foreach ($list as $item) {
|
||||
if ($item['type']) {
|
||||
WorkGroupMsgJob::dispatchDo('batch', [$item['id'], '', 0]);
|
||||
} else {
|
||||
foreach ($item['userids'] as $count => $userid) {
|
||||
WorkGroupMsgJob::dispatchDo('batch', [$item['id'], $userid, $count + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送应用消息
|
||||
* @param int $id
|
||||
* @param string $userid
|
||||
* @param string $sendTime
|
||||
* @return WechatResponse
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function sendMessage(int $id, string $userid, string $sendTime)
|
||||
{
|
||||
if ($id) {
|
||||
$template = $this->dao->get(['id' => $id], ['userids', 'type', 'name', 'create_time']);
|
||||
if (!$template) {
|
||||
throw new ValidateException('没有查到群发模板');
|
||||
}
|
||||
$template = $template->toArray();
|
||||
if (isset($template[0]['userid'])) {
|
||||
$template['userids'] = array_column($template['userids'], 'userid');
|
||||
}
|
||||
$userids = $template['userids'];
|
||||
$task = $template['type'] ? '客户群群发任务' : '客户群发任务';
|
||||
$text = "【任务提醒】有新的任务啦!\n" .
|
||||
"任务类型:{$task}\n" .
|
||||
"任务名称:{$template['name']}\n" .
|
||||
"创建时间:{$template['create_time']}\n" .
|
||||
"可前往【群发助手】中确认发送,记得及时完成哦\n";
|
||||
} else {
|
||||
$userids = [$userid];
|
||||
$text = "【任务提醒】有新的任务啦!\n" .
|
||||
"任务类型:客户群发任务\n" .
|
||||
"创建时间:{$sendTime}\n" .
|
||||
"可前往【群发助手】中确认发送,记得及时完成哦\n";
|
||||
}
|
||||
|
||||
$res = Event::until('work.message', [
|
||||
'text', $text, ['toUser' => $userids], []
|
||||
]);
|
||||
if ($res === false) {
|
||||
throw new ValidateException('发送消息失败');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
34
app/services/work/WorkLabelServices.php
Normal file
34
app/services/work/WorkLabelServices.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkLabelDao;
|
||||
use app\services\BaseServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* 企业微信标签
|
||||
* Class WorkLabelServices
|
||||
* @package app\services\\work
|
||||
* @mixin WorkLabelDao
|
||||
*/
|
||||
class WorkLabelServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var WorkLabelDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkLabelDao $dao;
|
||||
|
||||
}
|
||||
206
app/services/work/WorkMediaServices.php
Normal file
206
app/services/work/WorkMediaServices.php
Normal file
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkMediaDao;
|
||||
use app\services\BaseServices;
|
||||
use crmeb\basic\BaseModel;
|
||||
use crmeb\services\FileService;
|
||||
use crmeb\services\wechat\Work;
|
||||
use EasyWeChat\Kernel\Exceptions\InvalidConfigException;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use think\annotation\Inject;
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\DbException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
use think\exception\ValidateException;
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* 企业微信素材
|
||||
* Class WorkMediaServices
|
||||
* @package app\services\work
|
||||
* @mixin WorkMediaDao
|
||||
*/
|
||||
class WorkMediaServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var WorkMediaDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkMediaDao $dao;
|
||||
|
||||
/**
|
||||
* 获取附件资源
|
||||
* @param string $url
|
||||
* @param string $type
|
||||
* @param int $uploadType
|
||||
* @return array|bool
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws GuzzleException
|
||||
* @throws InvalidConfigException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function getPathMediaInfo(string $url, string $type, int $uploadType = 0)
|
||||
{
|
||||
$pathInfo = parse_url($url);
|
||||
$path = $pathInfo['path'];
|
||||
$mediaInfo = [];
|
||||
$md5Path = md5($path);
|
||||
$info = $this->dao->get(['md5_path' => $md5Path, 'type' => $type, 'upload_type' => $uploadType], ['media_id', 'url', 'temporary']);
|
||||
if ($info) {
|
||||
if ($info->temporary && $info->media_id) {
|
||||
$mediaInfo = $info->toArray();
|
||||
}
|
||||
if (((int)$info->temporary) === 0) {
|
||||
$mediaInfo = $info->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
if (!$mediaInfo) {
|
||||
if (str_starts_with($path, '/')) {
|
||||
$path = substr($path, 1);
|
||||
}
|
||||
$pathUrl = public_path() . $path;
|
||||
if (is_file($pathUrl)) {
|
||||
$uploadInfo = $this->mediaUpload($uploadType, $pathUrl, $type, $md5Path, $info);
|
||||
$mediaInfo['media_id'] = $uploadInfo['media_id'];
|
||||
} else {
|
||||
//获取文件内容
|
||||
$stream = file_get_contents($url);
|
||||
|
||||
//创建文件路径
|
||||
$dir = public_path() . 'uploads' . DS . 'temp';
|
||||
try {
|
||||
FileService::mkDir($dir);
|
||||
} catch (\Throwable $e) {
|
||||
throw new ValidateException($e->getMessage());
|
||||
}
|
||||
|
||||
//把文件流保存到本地
|
||||
$pathUrl = $dir . DS . basename($url);
|
||||
file_put_contents($pathUrl, $stream);
|
||||
|
||||
//上传到素材附件
|
||||
$uploadInfo = $this->mediaUpload($uploadType, $pathUrl, $type, $md5Path, $info);
|
||||
unlink($pathUrl);
|
||||
|
||||
$mediaInfo['media_id'] = $uploadInfo['media_id'];
|
||||
|
||||
}
|
||||
}
|
||||
return $mediaInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传临时素材
|
||||
* @param int $uploadType
|
||||
* @param string $pathUrl
|
||||
* @param string $type
|
||||
* @param string $md5Path
|
||||
* @param $info
|
||||
* @return BaseModel|Model
|
||||
* @throws GuzzleException
|
||||
* @throws InvalidConfigException
|
||||
*/
|
||||
public function mediaUpload(int $uploadType, string $pathUrl, string $type, string $md5Path, $info)
|
||||
{
|
||||
if ($uploadType) {
|
||||
$resMedia = Work::mediaUploadAttachment($pathUrl, $type);
|
||||
} else {
|
||||
$resMedia = Work::mediaUpload($pathUrl, $type);
|
||||
}
|
||||
if ($info) {
|
||||
$info->media_id = $resMedia['media_id'];
|
||||
$info->valid_time = (int)$resMedia['created_at'] + 60 * 60 * 24 * 3 - 60;//3天有效期
|
||||
$info->save();
|
||||
return $info;
|
||||
} else {
|
||||
return $this->dao->save([
|
||||
'path' => $pathUrl,
|
||||
'md5_path' => $md5Path,
|
||||
'type' => $type,
|
||||
'upload_type' => $uploadType,
|
||||
'media_id' => $resMedia['media_id'],
|
||||
'valid_time' => (int)$resMedia['created_at'] + 60 * 60 * 24 * 3 - 60,//3天有效期
|
||||
'create_time' => time(),
|
||||
'temporary' => 1
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取欢迎语
|
||||
* @param array $welcome
|
||||
* @return array
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws GuzzleException
|
||||
* @throws InvalidConfigException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function resolvingWelcome(array $welcome, int $uploadType = 0)
|
||||
{
|
||||
//清除过期的附件
|
||||
$this->dao->deleteValidFile();
|
||||
$attachments = [];
|
||||
foreach ($welcome['attachments'] as $item) {
|
||||
switch ($item['msgtype']) {
|
||||
case 'image':
|
||||
$mediaInfo = $this->getPathMediaInfo($item['image']['pic_url'], 'image', $uploadType);
|
||||
if (!empty($mediaInfo['media_id'])) {
|
||||
$item['image']['media_id'] = $mediaInfo['media_id'];
|
||||
unset($item['image']['pic_url']);
|
||||
$attachments[] = $item;
|
||||
}
|
||||
break;
|
||||
case 'link':
|
||||
|
||||
break;
|
||||
case 'miniprogram':
|
||||
$mediaInfo = $this->getPathMediaInfo($item['miniprogram']['pic_url'], 'image', $uploadType);
|
||||
if (!empty($mediaInfo['media_id'])) {
|
||||
$item['miniprogram']['pic_media_id'] = $mediaInfo['media_id'];
|
||||
unset($item['miniprogram']['pic_url']);
|
||||
$attachments[] = $item;
|
||||
}
|
||||
break;
|
||||
case 'video':
|
||||
$mediaInfo = $this->getPathMediaInfo($item['video']['url'], 'video', $uploadType);
|
||||
if (!empty($mediaInfo['media_id'])) {
|
||||
$item['video']['media_id'] = $mediaInfo['media_id'];
|
||||
unset($item['video']['url']);
|
||||
$attachments[] = $item;
|
||||
}
|
||||
break;
|
||||
case 'file':
|
||||
$mediaInfo = $this->getPathMediaInfo($item['file']['url'], 'file', $uploadType);
|
||||
if (!empty($mediaInfo['media_id'])) {
|
||||
$item['file']['media_id'] = $mediaInfo['media_id'];
|
||||
unset($item['file']['url']);
|
||||
$attachments[] = $item;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return [
|
||||
'text' => [
|
||||
'content' => $welcome['text']['content'],
|
||||
],
|
||||
'attachments' => $attachments
|
||||
];
|
||||
}
|
||||
}
|
||||
33
app/services/work/WorkMemberOtherServices.php
Normal file
33
app/services/work/WorkMemberOtherServices.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkMemberOtherDao;
|
||||
use app\services\BaseServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* Class WorkMemberOtherServices
|
||||
* @package app\services\\work
|
||||
* @mixin WorkMemberOtherDao
|
||||
*/
|
||||
class WorkMemberOtherServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var WorkMemberOtherDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkMemberOtherDao $dao;
|
||||
|
||||
}
|
||||
62
app/services/work/WorkMemberRelationServices.php
Normal file
62
app/services/work/WorkMemberRelationServices.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkMemberRelationDao;
|
||||
use app\services\BaseServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* 企业微信成员关联表
|
||||
* Class WorkMemberRelationServices
|
||||
* @package app\services\\work
|
||||
* @mixin WorkMemberRelationDao
|
||||
*/
|
||||
class WorkMemberRelationServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var WorkMemberRelationDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkMemberRelationDao $dao;
|
||||
|
||||
|
||||
/**
|
||||
* 添加成员部门
|
||||
* @param int $memberId
|
||||
* @param string $isLeaderInDept
|
||||
* @param string $department
|
||||
* @return mixed
|
||||
*/
|
||||
public function saveMemberDepartment(int $memberId, string $isLeaderInDept, string $department)
|
||||
{
|
||||
$res = true;
|
||||
if ($department) {
|
||||
$department = explode(',', $department);
|
||||
$isLeaderInDept = $isLeaderInDept ? explode(',', $isLeaderInDept) : [];
|
||||
$departmentData = [];
|
||||
for ($i = 0; $i < count($department); $i++) {
|
||||
$departmentData[] = [
|
||||
'department' => $department[$i],
|
||||
'is_leader_in_dept' => $isLeaderInDept[$i] ?? 0,
|
||||
'member_id' => $memberId,
|
||||
'create_time' => time()
|
||||
];
|
||||
}
|
||||
$this->dao->delete(['member_id' => $memberId]);
|
||||
$res = $this->dao->saveAll($departmentData);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
428
app/services/work/WorkMemberServices.php
Normal file
428
app/services/work/WorkMemberServices.php
Normal file
@@ -0,0 +1,428 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkMemberDao;
|
||||
use app\jobs\work\WorkMemberJob;
|
||||
use app\services\BaseServices;
|
||||
use crmeb\services\wechat\config\WorkConfig;
|
||||
use crmeb\services\wechat\Work;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
use think\facade\Log;
|
||||
use think\helper\Str;
|
||||
|
||||
/**
|
||||
* 企业微信成员
|
||||
* Class WorkMemberServices
|
||||
* @package app\services\work
|
||||
* @mixin WorkMemberDao
|
||||
*/
|
||||
class WorkMemberServices extends BaseServices
|
||||
{
|
||||
|
||||
const TABLE_FIELD = ['Name', 'MainDepartment', 'DirectLeader',
|
||||
'Mobile', 'Position', 'Gender', 'Email', 'BizMail', 'Status', 'Avatar', 'Alias',
|
||||
'Telephone', 'Address'];
|
||||
|
||||
/**
|
||||
* @var WorkMemberDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkMemberDao $dao;
|
||||
|
||||
/**
|
||||
* 员工列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function getList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getDataList($where, ['*'], $page, $limit, 'create_time', [
|
||||
'departmentRelation',
|
||||
'clientFollow' => function ($query) {
|
||||
$query->group('userid')->where('is_del_user', 0)->field(['count(*) as sum_follow', 'userid']);
|
||||
},
|
||||
'chat' => function ($query) {
|
||||
$query->group('userid')->field(['count(*) as sum_chat', 'userid']);
|
||||
},
|
||||
]);
|
||||
$departmentIds = [];
|
||||
foreach ($list as &$item) {
|
||||
if (!empty($item['departmentRelation'])) {
|
||||
$item['departmentId'] = array_column($item['departmentRelation'], 'department');
|
||||
} else {
|
||||
$item['departmentId'] = [];
|
||||
}
|
||||
$departmentIds = array_merge($departmentIds, $item['departmentId']);
|
||||
}
|
||||
$departmentIds = array_merge(array_unique(array_filter($departmentIds)));
|
||||
if ($departmentIds) {
|
||||
/** @var WorkDepartmentServices $services */
|
||||
$services = app()->make(WorkDepartmentServices::class);
|
||||
$departmentList = $services->getColumn([
|
||||
['department_id', 'in', $departmentIds],
|
||||
], 'name', 'department_id');
|
||||
foreach ($list as &$item) {
|
||||
$department = [];
|
||||
foreach ($departmentList as $k => $v) {
|
||||
if (in_array($k, $item['departmentId'])) {
|
||||
$department[] = ['name' => $v, 'department' => $k];
|
||||
}
|
||||
}
|
||||
$item['department_list'] = $department;
|
||||
}
|
||||
}
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存成员数据
|
||||
* @param array $members
|
||||
* @return bool
|
||||
*/
|
||||
public function saveMember(array $members)
|
||||
{
|
||||
/** @var WorkConfig $config */
|
||||
$config = app()->make(WorkConfig::class);
|
||||
$corpId = $config->corpId;
|
||||
if (!$corpId) {
|
||||
return true;
|
||||
}
|
||||
/** @var WorkDepartmentServices $departmentService */
|
||||
$departmentService = app()->make(WorkDepartmentServices::class);
|
||||
$defaultDepartment = $departmentService->value(['corp_id' => $corpId, 'parentid' => 0], 'department_id');
|
||||
|
||||
$this->transaction(function () use ($members, $corpId, $defaultDepartment) {
|
||||
$data = [];
|
||||
$relation = [];
|
||||
$other = [];
|
||||
$userids = array_column($members, 'userid');
|
||||
foreach ($members as $member) {
|
||||
if (isset($member['english_name'])) {
|
||||
unset($member['english_name']);
|
||||
}
|
||||
$address = $bizMail = '';
|
||||
if (isset($member['address'])) {
|
||||
$address = $member['address'];
|
||||
unset($member['address']);
|
||||
}
|
||||
if (isset($member['biz_mail'])) {
|
||||
$bizMail = $member['biz_mail'];
|
||||
unset($member['biz_mail']);
|
||||
}
|
||||
$member['address'] = $address;
|
||||
$member['biz_mail'] = $bizMail;
|
||||
if (isset($member['extattr']) && $member['extattr']) {
|
||||
$other[$member['userid']] = [
|
||||
'extattr' => json_encode($member['extattr'] ?? []),
|
||||
'external_profile' => json_encode($member['external_profile'] ?? []),
|
||||
];
|
||||
}
|
||||
if (!empty($member['department'])) {
|
||||
foreach ($member['department'] as $i => $department) {
|
||||
$relation[$member['userid']][] = [
|
||||
'department' => $member['department'][$i] ?? 0,
|
||||
'srot' => $member['order'][$i] ?? 0,
|
||||
'is_leader_in_dept' => $member['is_leader_in_dept'][$i] ?? 0
|
||||
];
|
||||
}
|
||||
} else {
|
||||
//写入默认部门
|
||||
$relation[$member['userid']][] = ['department' => $defaultDepartment, 'srot' => 0, 'is_leader_in_dept' => 0];
|
||||
}
|
||||
$externalPosition = '';
|
||||
if (isset($member['external_position'])) {
|
||||
$externalPosition = $member['external_position'];
|
||||
unset($member['external_position']);
|
||||
}
|
||||
$member['external_position'] = $externalPosition;
|
||||
$member['direct_leader'] = json_encode($member['direct_leader']);
|
||||
$member['is_leader'] = $member['isleader'];
|
||||
$member['corp_id'] = $corpId;
|
||||
if (isset($member['external_profile'])) {
|
||||
unset($member['external_profile']);
|
||||
}
|
||||
unset($member['isleader'], $member['is_leader_in_dept'], $member['order'], $member['department'], $member['extattr']);
|
||||
if ($this->dao->count(['userid' => $member['userid'], 'corp_id' => $corpId])) {
|
||||
$this->dao->update(['userid' => $member['userid']], $member);
|
||||
} else {
|
||||
$member['create_time'] = time();
|
||||
$data[] = $member;
|
||||
}
|
||||
}
|
||||
//写入成员数据
|
||||
if ($data) {
|
||||
$this->dao->saveAll($data);
|
||||
}
|
||||
$userList = $this->dao->getColumn([['userid', 'in', $userids], ['corp_id', '=', $corpId]], 'id', 'userid');
|
||||
$userValueAll = array_values($userList);
|
||||
//写入关联数据
|
||||
if (count($relation)) {
|
||||
/** @var WorkMemberRelationServices $relationService */
|
||||
$relationService = app()->make(WorkMemberRelationServices::class);
|
||||
$relationService->delete([['member_id', 'in', $userValueAll]]);
|
||||
$saveRelation = [];
|
||||
foreach ($relation as $userid => $item) {
|
||||
$memberId = $userList[$userid];
|
||||
foreach ($item as $value) {
|
||||
$saveRelation[] = [
|
||||
'member_id' => $memberId,
|
||||
'create_time' => time(),
|
||||
'department' => $value['department'],
|
||||
'srot' => $value['srot'],
|
||||
'is_leader_in_dept' => $value['is_leader_in_dept'],
|
||||
];
|
||||
}
|
||||
}
|
||||
$relationService->saveAll($saveRelation);
|
||||
}
|
||||
//写入其他数据
|
||||
if (count($other)) {
|
||||
/** @var WorkMemberOtherServices $otherService */
|
||||
$otherService = app()->make(WorkMemberOtherServices::class);
|
||||
$otherService->delete([['member_id', 'in', $userValueAll]]);
|
||||
foreach ($other as $userid => &$item) {
|
||||
$memberId = $userList[$userid];
|
||||
$item['member_id'] = $memberId;
|
||||
}
|
||||
$otherService->saveAll($other);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动更新企业成员
|
||||
* @param int $departmentId
|
||||
*/
|
||||
public function authUpdataMember(int $departmentId)
|
||||
{
|
||||
$res = Work::getDetailedDepartmentUsers($departmentId);
|
||||
$members = $res['userlist'] ?? [];
|
||||
$maxCount = 500;
|
||||
$sumCount = count($members);
|
||||
if ($sumCount > $maxCount) {
|
||||
$page = ceil($maxCount / $sumCount);
|
||||
for ($i = 1; $i < $page; $i++) {
|
||||
$res = collect($members)->slice($maxCount * $i, $maxCount)->toArray();
|
||||
WorkMemberJob::dispatchDo('save', [$res]);
|
||||
}
|
||||
} else {
|
||||
$this->saveMember($members);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取提交字段
|
||||
* @param array $payload
|
||||
* @return array
|
||||
*/
|
||||
protected function getTableField(array $payload)
|
||||
{
|
||||
$data = [];
|
||||
foreach (self::TABLE_FIELD as $key) {
|
||||
$strKey = Str::snake($key);
|
||||
if (isset($payload[$strKey])) {
|
||||
$data[$strKey] = $payload[$strKey];
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新企业成员
|
||||
* @param array $payload
|
||||
* @return mixed
|
||||
*/
|
||||
public function updateMember(array $payload)
|
||||
{
|
||||
$corpId = $payload['ToUserName'] ?? '';
|
||||
$userId = $payload['UserID'] ?? '';
|
||||
$updateData = $this->getTableField($payload);
|
||||
if (!empty($payload['NewUserID'])) {
|
||||
$updateData['userid'] = $payload['NewUserID'];
|
||||
}
|
||||
|
||||
$memberInfo = Work::getMemberInfo($userId);
|
||||
if (0 !== $memberInfo['errcode']) {
|
||||
throw new ValidateException($memberInfo['errmsg']);
|
||||
}
|
||||
$extattr = $memberInfo['extattr'] ?? [];
|
||||
$externalProfile = $memberInfo['external_profile'] ?? [];
|
||||
unset($memberInfo['errcode'], $memberInfo['errmsg'], $memberInfo['department'],
|
||||
$memberInfo['order'], $memberInfo['is_leader_in_dept'], $memberInfo['extattr'],
|
||||
$memberInfo['external_profile']);
|
||||
$updateData = array_merge($updateData, $memberInfo);
|
||||
|
||||
$memberId = $this->dao->value(['userid' => $userId], 'id');
|
||||
if ($memberId) {
|
||||
if ($updateData) {
|
||||
$dbCorpId = $this->dao->value(['userid' => $userId], 'corp_id');
|
||||
if (!$dbCorpId) {
|
||||
$updateData['corp_id'] = $corpId;
|
||||
}
|
||||
$this->dao->update(['corp_id' => $corpId, 'userid' => $userId], $updateData);
|
||||
}
|
||||
} else {
|
||||
if (!empty($payload['NewUserID'])) {
|
||||
$updateData['userid'] = $payload['NewUserID'];
|
||||
}
|
||||
$res = $this->dao->save($updateData);
|
||||
$memberId = $res->id;
|
||||
}
|
||||
/** @var WorkMemberRelationServices $relationServices */
|
||||
$relationServices = app()->make(WorkMemberRelationServices::class);
|
||||
$relationServices->saveMemberDepartment($memberId, $payload['IsLeaderInDept'] ?? '', $payload['Department'] ?? '');
|
||||
|
||||
//写入其他数据
|
||||
if (!empty($extattr['attrs']) || !empty($externalProfile)) {
|
||||
/** @var WorkMemberOtherServices $otherService */
|
||||
$otherService = app()->make(WorkMemberOtherServices::class);
|
||||
$otherInfo = $otherService->get(['member_id' => $memberId]);
|
||||
if ($otherInfo) {
|
||||
$otherInfo->extattr = json_encode($extattr);
|
||||
$otherInfo->external_profile = json_encode($externalProfile);
|
||||
$otherInfo->save();
|
||||
} else {
|
||||
$otherService->save([
|
||||
'member_id' => $memberId,
|
||||
'extattr' => json_encode($extattr),
|
||||
'external_profile' => json_encode($externalProfile),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return $memberId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建企业微信成员
|
||||
* @param array $payload
|
||||
* @return mixed
|
||||
*/
|
||||
public function createMember(array $payload)
|
||||
{
|
||||
$corpId = $payload['ToUserName'] ?? '';
|
||||
if (!$corpId) {
|
||||
/** @var WorkConfig $config */
|
||||
$config = app()->make(WorkConfig::class);
|
||||
$corpId = $config->corpId;
|
||||
}
|
||||
$userId = $payload['UserID'] ?? '';
|
||||
$data = $this->getTableField($payload);
|
||||
$memberInfo = Work::getMemberInfo($userId);
|
||||
if (0 !== $memberInfo['errcode']) {
|
||||
throw new ValidateException($memberInfo['errmsg']);
|
||||
}
|
||||
$extattr = $memberInfo['extattr'] ?? [];
|
||||
$externalProfile = $memberInfo['external_profile'] ?? [];
|
||||
unset($memberInfo['errcode'], $memberInfo['errmsg'], $memberInfo['department'],
|
||||
$memberInfo['order'], $memberInfo['is_leader_in_dept'], $memberInfo['extattr'],
|
||||
$memberInfo['external_profile']);
|
||||
$data = array_merge($data, $memberInfo);
|
||||
$memberId = $this->dao->value(['userid' => $userId], 'id');
|
||||
if ($memberId) {
|
||||
if ($data) {
|
||||
$dbCorpId = $this->dao->value(['userid' => $userId], 'corp_id');
|
||||
if (!$dbCorpId) {
|
||||
$data['corp_id'] = $corpId;
|
||||
}
|
||||
$this->dao->update(['userid' => $userId], $data);
|
||||
}
|
||||
} else {
|
||||
$data['corp_id'] = $corpId;
|
||||
$res = $this->dao->save($data);
|
||||
$memberId = $res->id;
|
||||
}
|
||||
|
||||
//记录
|
||||
$isLeaderInDept = $payload['IsLeaderInDept'] ?? '';
|
||||
$department = $payload['Department'] ?? '';
|
||||
if (!$department && !$isLeaderInDept) {
|
||||
//写入主部门
|
||||
/** @var WorkDepartmentServices $departmentService */
|
||||
$departmentService = app()->make(WorkDepartmentServices::class);
|
||||
$id = $departmentService->value(['corp_id' => $corpId, 'parentid' => 0], 'department_id');
|
||||
if ($id) {
|
||||
$department = (string)$id;
|
||||
$isLeaderInDept = '0';
|
||||
}
|
||||
}
|
||||
/** @var WorkMemberRelationServices $relationServices */
|
||||
$relationServices = app()->make(WorkMemberRelationServices::class);
|
||||
$relationServices->saveMemberDepartment($memberId, $isLeaderInDept, $department);
|
||||
|
||||
//写入其他数据
|
||||
if (!empty($extattr['attrs']) || !empty($externalProfile)) {
|
||||
/** @var WorkMemberOtherServices $otherService */
|
||||
$otherService = app()->make(WorkMemberOtherServices::class);
|
||||
$otherInfo = $otherService->get(['member_id' => $memberId]);
|
||||
if ($otherInfo) {
|
||||
$otherInfo->extattr = json_encode($extattr);
|
||||
$otherInfo->external_profile = json_encode($externalProfile);
|
||||
$otherInfo->save();
|
||||
} else {
|
||||
$otherService->save([
|
||||
'member_id' => $memberId,
|
||||
'extattr' => json_encode($extattr),
|
||||
'external_profile' => json_encode($externalProfile),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return $memberId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除企业微信成员
|
||||
* @param string $corpId
|
||||
* @param string $userid
|
||||
*/
|
||||
public function deleteMember(string $corpId, string $userid)
|
||||
{
|
||||
$memberId = $this->dao->value(['corp_id' => $corpId, 'userid' => $userid], 'id');
|
||||
if ($memberId) {
|
||||
$this->transaction(function () use ($memberId) {
|
||||
/** @var WorkMemberRelationServices $relationServices */
|
||||
$relationServices = app()->make(WorkMemberRelationServices::class);
|
||||
$relationServices->delete(['member_id' => $memberId]);
|
||||
/** @var WorkMemberOtherServices $otherServices */
|
||||
$otherServices = app()->make(WorkMemberOtherServices::class);
|
||||
$otherServices->delete(['member_id' => $memberId]);
|
||||
$this->dao->delete($memberId);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户注销解绑用户
|
||||
* @param int $uid
|
||||
*/
|
||||
public function unboundUser(int $uid)
|
||||
{
|
||||
try {
|
||||
$this->dao->update(['uid' => $uid], ['uid' => 0]);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error(
|
||||
json_encode([
|
||||
'message' => '解绑用户失败:' . $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine()
|
||||
], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
149
app/services/work/WorkMomentSendResultServices.php
Normal file
149
app/services/work/WorkMomentSendResultServices.php
Normal file
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkMomentSendResultDao;
|
||||
use app\jobs\work\WorkMomentJob;
|
||||
use app\services\BaseServices;
|
||||
use crmeb\services\wechat\Work;
|
||||
use think\annotation\Inject;
|
||||
use think\facade\Log;
|
||||
|
||||
/**
|
||||
* Class WorkMomentSendResultServices
|
||||
* @package app\services\work
|
||||
* @mixin WorkMomentSendResultDao
|
||||
*/
|
||||
class WorkMomentSendResultServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var WorkMomentSendResultDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkMomentSendResultDao $dao;
|
||||
|
||||
/**
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getDataList($where, ['*'], $page, $limit, 'create_time', ['member']);
|
||||
$externalUserid = [];
|
||||
foreach ($list as $item) {
|
||||
$externalUserid = array_merge($externalUserid, $item['external_userid']);
|
||||
}
|
||||
if ($externalUserid) {
|
||||
$externalUserid = array_merge(array_unique(array_filter($externalUserid)));
|
||||
/** @var WorkClientServices $clientService */
|
||||
$clientService = app()->make(WorkClientServices::class);
|
||||
$externalUserList = $clientService->getColumn([
|
||||
['external_userid', 'in', $externalUserid]
|
||||
], 'name', 'external_userid');
|
||||
foreach ($list as &$item) {
|
||||
$item['external_user_list'] = [];
|
||||
foreach ($externalUserList as $k => $v) {
|
||||
if (in_array($k, $item['external_userid'])) {
|
||||
$item['external_user_list'][] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任务执行详情
|
||||
* @param string $momentId
|
||||
* @param string $cursor
|
||||
* @return bool
|
||||
*/
|
||||
public function getTaskInfo(string $momentId, string $cursor = '')
|
||||
{
|
||||
try {
|
||||
$resInfo = Work::getMomentTaskInfo($momentId, $cursor, 100);
|
||||
$taskList = $resInfo['task_list'] ?? [];
|
||||
foreach ($taskList as $item) {
|
||||
$res = $this->dao->get(['user_id' => $item['userid'], 'moment_id' => $momentId]);
|
||||
if (!$res) {
|
||||
$res = $this->dao->save([
|
||||
'user_id' => $item['userid'],
|
||||
'status' => $item['publish_status'],
|
||||
'moment_id' => $momentId,
|
||||
'create_time' => time()
|
||||
]);
|
||||
} else {
|
||||
if ($res->status != $item['publish_status']) {
|
||||
$res->status = $item['publish_status'];
|
||||
$res->save();
|
||||
}
|
||||
}
|
||||
WorkMomentJob::dispatchDo('getCustomerPage', [$res->id, $momentId, $item['userid'], '']);
|
||||
|
||||
}
|
||||
|
||||
if ($resInfo['next_cursor']) {
|
||||
WorkMomentJob::dispatchDo('getTaskPage', [$momentId, $resInfo['next_cursor']]);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
Log::error(
|
||||
json_encode([
|
||||
'message' => '获取任务执行详情失败:' . $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine()
|
||||
], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某个人发送朋友圈详情
|
||||
* @param int $id
|
||||
* @param string $momentId
|
||||
* @param string $userId
|
||||
* @param string $cursor
|
||||
* @return bool
|
||||
*/
|
||||
public function getCustomerList(int $id, string $momentId, string $userId, string $cursor = '')
|
||||
{
|
||||
try {
|
||||
$resInfo = Work::getMomentCustomerList($momentId, $userId, $cursor, 1000);
|
||||
|
||||
$externalUserids = array_column($resInfo['customer_list'], 'external_userid');
|
||||
|
||||
if ($externalUserids) {
|
||||
$value = $this->dao->value(['id' => $id], 'external_userid');
|
||||
$value = $value ? (is_array($value) ? $value : json_decode($value, true)) : [];
|
||||
$value = array_merge($value, $externalUserids);
|
||||
$this->dao->update($id, ['external_userid' => $value]);
|
||||
}
|
||||
|
||||
if ($resInfo['next_cursor']) {
|
||||
WorkMomentJob::dispatchDo('getCustomerPage', [$id, $momentId, $userId, $resInfo['next_cursor']]);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
Log::error(
|
||||
json_encode([
|
||||
'message' => '获取某个人发送朋友圈详情失败:' . $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine()
|
||||
], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
228
app/services/work/WorkMomentServices.php
Normal file
228
app/services/work/WorkMomentServices.php
Normal file
@@ -0,0 +1,228 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkMomentDao;
|
||||
use app\jobs\work\WorkMomentJob;
|
||||
use app\services\BaseServices;
|
||||
use crmeb\services\wechat\Work;
|
||||
use crmeb\traits\service\ContactWayQrCode;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
use think\facade\Log;
|
||||
|
||||
/**
|
||||
* 创建发布朋友圈
|
||||
* Class WorkMomentServices
|
||||
* @package app\services\work
|
||||
* @mixin WorkMomentDao
|
||||
*/
|
||||
class WorkMomentServices extends BaseServices
|
||||
{
|
||||
|
||||
use ContactWayQrCode;
|
||||
|
||||
/**
|
||||
* @var WorkMomentDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkMomentDao $dao;
|
||||
|
||||
/**
|
||||
* @param array $where
|
||||
* @return array
|
||||
*/
|
||||
public function getList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getDataList($where, ['*'], $page, $limit, 'create_time', [
|
||||
'sendResult' => function ($query) {
|
||||
$query->field(['status', 'moment_id']);
|
||||
}
|
||||
]);
|
||||
$userIds = $userList = [];
|
||||
foreach ($list as $v) {
|
||||
$userIds = array_merge($userIds, $v['user_ids']);
|
||||
}
|
||||
if ($userIds) {
|
||||
$userIds = array_merge(array_unique(array_filter($userIds)));
|
||||
/** @var WorkMemberServices $service */
|
||||
$service = app()->make(WorkMemberServices::class);
|
||||
$userList = $service->getColumn([
|
||||
['userid', 'in', $userIds]
|
||||
], 'name', 'userid');
|
||||
}
|
||||
foreach ($list as &$item) {
|
||||
$item['user_count'] = $item['unuser_count'] = $userCount = $unuserCount = 0;
|
||||
if (!empty($item['sendResult'])) {
|
||||
foreach ($item['sendResult'] as $value) {
|
||||
if ($value['status']) {
|
||||
$userCount++;
|
||||
} else {
|
||||
$unuserCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
$item['user_count'] = $userCount;
|
||||
$item['unuser_count'] = $unuserCount;
|
||||
$item['user_list'] = [];
|
||||
foreach ($userList as $k => $v) {
|
||||
if (in_array($k, $item['user_ids'])) {
|
||||
$item['user_list'][] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加发送朋友圈任务
|
||||
* @param array $data
|
||||
* @return mixed
|
||||
*/
|
||||
public function createMomentTask(array $data)
|
||||
{
|
||||
$this->checkWelcome($data['welcome_words'], 0);
|
||||
|
||||
return $this->transaction(function () use ($data) {
|
||||
|
||||
$res = $this->dao->save($data);
|
||||
//立即发送或者过了发送时间直接发送
|
||||
if (!$data['send_type'] || ($data['send_type'] == 1 && $data['send_time'] < time())) {
|
||||
$this->sendMomentTask($res->id, $data['welcome_words'], $data['type'] ? $data['user_ids'] : [], $data['type'] ? $data['client_tag_list'] : []);
|
||||
}
|
||||
return $res;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送
|
||||
* @param int $id
|
||||
* @param array $content
|
||||
* @param array $userIds
|
||||
* @param array $tags
|
||||
*/
|
||||
public function sendMomentTask(int $id, array $content, array $userIds, array $tags = [])
|
||||
{
|
||||
|
||||
$resTask = $this->addMomentTask($content, $userIds, $tags);
|
||||
|
||||
$this->dao->update($id, ['jobid' => $resTask['jobid']]);
|
||||
|
||||
WorkMomentJob::dispatchSece(60 * 3, 'task', [$resTask['jobid']]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取异步任务执行结果
|
||||
* @param string $jobId
|
||||
* @return bool
|
||||
*/
|
||||
public function getTaskInfo(string $jobId)
|
||||
{
|
||||
try {
|
||||
|
||||
$res = Work::getMomentTask($jobId);
|
||||
|
||||
if ($res['status'] !== 3) {
|
||||
WorkMomentJob::dispatchSece(60 * 3, 'task', [$jobId]);
|
||||
return true;
|
||||
}
|
||||
$this->dao->update(['jobid' => $jobId], [
|
||||
'moment_id' => $res['result']['moment_id'],
|
||||
'invalid_sender_list' => isset($res['result']['invalid_sender_list']) ? json_encode($res['result']['invalid_sender_list']) : null,
|
||||
'invalid_external_contact_list' => isset($res['result']['invalid_external_contact_list']) ? json_encode($res['result']['invalid_external_contact_list']) : null,
|
||||
]);
|
||||
|
||||
//执行获取任务详情
|
||||
WorkMomentJob::dispatchDo('getTaskPage', [$res['result']['moment_id'], '']);
|
||||
|
||||
return true;
|
||||
} catch (\Throwable $e) {
|
||||
Log::error(
|
||||
json_encode([
|
||||
'message' => '获取异步任务结果失败:' . $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine()
|
||||
], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取发送朋友圈详情
|
||||
* @param int $id
|
||||
* @return array
|
||||
*/
|
||||
public function getMomentInfo(int $id)
|
||||
{
|
||||
$info = $this->dao->get($id);
|
||||
if (!$info) {
|
||||
throw new ValidateException('没有查询到此朋友圈信息');
|
||||
}
|
||||
$userCount = $sendUserCount = $unSendUserCount = $externalUserCount = 0;
|
||||
if ($info->moment_id) {
|
||||
/** @var WorkMomentSendResultServices $service */
|
||||
$service = app()->make(WorkMomentSendResultServices::class);
|
||||
$userCount = $service->count(['moment_id' => $info->moment_id]);
|
||||
$sendUserCount = $service->count(['moment_id' => $info->moment_id, 'status' => 1]);
|
||||
$unSendUserCount = $service->count(['moment_id' => $info->moment_id, 'status' => 0]);
|
||||
$list = $service->getMomentList(['moment_id' => $info->moment_id, 'status' => 1], ['external_userid']);
|
||||
$externalUserid = [];
|
||||
foreach ($list as $item) {
|
||||
$externalUserid = array_merge($externalUserid, $item['external_userid']);
|
||||
}
|
||||
$externalUserCount = count($externalUserid);
|
||||
|
||||
if ($info->moment_id) {
|
||||
//执行获取任务详情
|
||||
WorkMomentJob::dispatchDo('getTaskPage', [$info->moment_id, '']);
|
||||
}
|
||||
}
|
||||
$info = $info->toArray();
|
||||
$info['info'] = compact('userCount', 'sendUserCount', 'unSendUserCount', 'externalUserCount');
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function deleteMoment(int $id)
|
||||
{
|
||||
$info = $this->dao->get($id);
|
||||
if (!$info) {
|
||||
throw new ValidateException('没有查询到此朋友圈信息');
|
||||
}
|
||||
|
||||
/** @var WorkMomentSendResultServices $service */
|
||||
$service = app()->make(WorkMomentSendResultServices::class);
|
||||
return $this->transaction(function () use ($info, $id, $service) {
|
||||
if ($info->moment_id) {
|
||||
$service->delete(['moment_id' => $info->moment_id]);
|
||||
}
|
||||
return $info->delete();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行定时任务发送朋友圈
|
||||
*/
|
||||
public function cronHandle()
|
||||
{
|
||||
$time = time();
|
||||
|
||||
$list = $this->dao->getDataList(['send_time' => $time, 'send_type' => 1, 'jobid_null' => true]);
|
||||
|
||||
foreach ($list as $item) {
|
||||
$this->sendMomentTask($item['id'], $item['welcome_words'], $item['type'] ? $item['user_ids'] : [], $item['type'] ? $item['client_tag_list'] : []);
|
||||
}
|
||||
}
|
||||
}
|
||||
33
app/services/work/WorkWelcomeRelationServices.php
Normal file
33
app/services/work/WorkWelcomeRelationServices.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkWelcomeRelationDao;
|
||||
use app\services\BaseServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
/**
|
||||
* Class WorkWelcomeRelationServices
|
||||
* @package app\services\work
|
||||
* @mixin WorkWelcomeRelationDao
|
||||
*/
|
||||
class WorkWelcomeRelationServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var WorkWelcomeRelationDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkWelcomeRelationDao $dao;
|
||||
|
||||
}
|
||||
180
app/services/work/WorkWelcomeServices.php
Normal file
180
app/services/work/WorkWelcomeServices.php
Normal file
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\services\work;
|
||||
|
||||
|
||||
use app\dao\work\WorkWelcomeDao;
|
||||
use app\services\BaseServices;
|
||||
use crmeb\traits\service\ContactWayQrCode;
|
||||
use think\annotation\Inject;
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\DbException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
use think\exception\ValidateException;
|
||||
|
||||
/**
|
||||
* 企业微信欢迎语
|
||||
* Class WorkWelcomeServices
|
||||
* @package app\services\\work
|
||||
* @mixin WorkWelcomeDao
|
||||
*/
|
||||
class WorkWelcomeServices extends BaseServices
|
||||
{
|
||||
|
||||
use ContactWayQrCode;
|
||||
|
||||
/**
|
||||
* @var WorkWelcomeDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected WorkWelcomeDao $dao;
|
||||
|
||||
/**
|
||||
* 获取列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function getList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$list = $this->dao->getDataList($where, ['*'], $page, $limit, ['sort', 'create_time'], [
|
||||
'userList' => function ($query) {
|
||||
$query->with([
|
||||
'member' => function ($query) {
|
||||
$query->field(['userid', 'name']);
|
||||
}
|
||||
]);
|
||||
}
|
||||
]);
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取欢迎语
|
||||
* @param int $id
|
||||
* @return array
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function getWelcomeInfo(int $id)
|
||||
{
|
||||
$welcomeInfo = $this->dao->get($id, ['*'], [
|
||||
'userList' => function ($query) {
|
||||
$query->with([
|
||||
'member' => function ($query) {
|
||||
$query->field(['userid', 'name']);
|
||||
}
|
||||
]);
|
||||
}
|
||||
]);
|
||||
if (!$welcomeInfo) {
|
||||
throw new ValidateException('没有查到欢迎语');
|
||||
}
|
||||
|
||||
return $welcomeInfo->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存欢迎语
|
||||
* @param array $data
|
||||
* @param int $id
|
||||
* @return bool
|
||||
*/
|
||||
public function saveWelcome(array $data, int $id = 0)
|
||||
{
|
||||
$userids = $data['userids'];
|
||||
unset($data['userids']);
|
||||
|
||||
$this->checkWelcome(['text' => ['content' => $data['content']], 'attachments' => $data['attachments']], 0);
|
||||
|
||||
/** @var WorkWelcomeRelationServices $relationServices */
|
||||
$relationServices = app()->make(WorkWelcomeRelationServices::class);
|
||||
|
||||
$this->transaction(function () use ($data, $id, $relationServices, $userids) {
|
||||
if ($id) {
|
||||
$this->dao->update($id, $data);
|
||||
} else {
|
||||
$res = $this->dao->save($data);
|
||||
$id = $res->id;
|
||||
}
|
||||
$userData = [];
|
||||
foreach ($userids as $userid) {
|
||||
$userData[] = [
|
||||
'welcome_id' => $id,
|
||||
'userid' => $userid
|
||||
];
|
||||
}
|
||||
$relationServices->delete(['welcome_id' => $id]);
|
||||
if ($userData) {
|
||||
$relationServices->saveAll($userData);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取欢迎语
|
||||
* @param string $userId
|
||||
* @return array
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function getWorkWelcome(string $userId)
|
||||
{
|
||||
|
||||
if ($userId) {
|
||||
/** @var WorkWelcomeRelationServices $service */
|
||||
$service = app()->make(WorkWelcomeRelationServices::class);
|
||||
$welcomeIds = $service->getColumn(['userid' => $userId], 'welcome_id');
|
||||
if ($welcomeIds) {
|
||||
$welcomeList = $this->dao->getDataList(['id' => $welcomeIds], ['*'], 1, 1, ['sort' => 'desc', 'create_time' => 'desc']);
|
||||
$welcomeWords = $welcomeList[0] ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($welcomeWords)) {
|
||||
$welcomeList = $this->dao->getDataList(['type' => 0], ['*'], 1, 1, ['sort' => 'desc', 'create_time' => 'desc']);
|
||||
$welcomeWords = $welcomeList[0] ?? [];
|
||||
}
|
||||
|
||||
return [
|
||||
'text' => [
|
||||
'content' => $welcomeWords['content'] ?? '',
|
||||
],
|
||||
'attachments' => $welcomeWords['attachments'] ?? [],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除欢迎语
|
||||
* @param int $id
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteWelcome(int $id)
|
||||
{
|
||||
/** @var WorkWelcomeRelationServices $relationServices */
|
||||
$relationServices = app()->make(WorkWelcomeRelationServices::class);
|
||||
|
||||
$this->transaction(function () use ($id, $relationServices) {
|
||||
$relationServices->delete(['welcome_id' => $id]);
|
||||
$this->dao->delete($id);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user