1070 lines
35 KiB
PHP
1070 lines
35 KiB
PHP
<?php
|
||
|
||
namespace app\repository;
|
||
|
||
use app\exception\RepositoryException;
|
||
use app\exception\TraitException;
|
||
use app\model\Account;
|
||
use app\model\Account as AccountModel;
|
||
use app\model\AccountDataLog;
|
||
use app\model\AccountFootmarks;
|
||
use app\model\AccountLevel;
|
||
use app\model\AccountRecord;
|
||
use app\model\AccountRule;
|
||
use app\model\Activity;
|
||
use app\model\Archives;
|
||
use app\model\ArchivesCategory;
|
||
use app\model\Channel;
|
||
use app\model\CustomerReceive;
|
||
use app\model\Diary;
|
||
use app\model\DoctorRelation;
|
||
use app\model\Message as MessageModel;
|
||
use app\model\ShareRegLog;
|
||
use app\model\Staff;
|
||
use app\service\ExtraConfig;
|
||
use app\service\File;
|
||
use app\service\GdTool;
|
||
use app\service\Repository;
|
||
use app\traits\account\AccountAddressTrait;
|
||
use app\traits\account\AccountCoinTrait;
|
||
use app\traits\account\AccountCoinWithdrawalTrait;
|
||
use app\traits\account\AccountDataLogTrait;
|
||
use app\traits\account\AccountLevelTrait;
|
||
use app\traits\account\AccountMessageTrait;
|
||
use app\traits\account\AccountRecordTrait;
|
||
use app\traits\account\AccountScoreTrait;
|
||
use app\traits\account\AppointmentTrait;
|
||
use app\traits\account\CouponTrait;
|
||
use app\traits\account\TagTrait;
|
||
use app\traits\account\FeedbackTrait;
|
||
use app\traits\SignInTrait;
|
||
use app\traits\worker\DoctorTrait;
|
||
use app\traits\worker\StaffTrait;
|
||
use Endroid\QrCode\Builder\Builder;
|
||
use Endroid\QrCode\Encoding\Encoding;
|
||
use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelHigh;
|
||
use Endroid\QrCode\RoundBlockSizeMode\RoundBlockSizeModeMargin;
|
||
use Endroid\QrCode\Writer\PngWriter;
|
||
use Exception;
|
||
use GuzzleHttp\Exception\GuzzleException;
|
||
use think\Collection;
|
||
use think\db\exception\DataNotFoundException;
|
||
use think\db\exception\DbException;
|
||
use think\db\exception\ModelNotFoundException;
|
||
use think\facade\Config;
|
||
use think\facade\Config as CConfig;
|
||
use think\facade\Db;
|
||
use think\Model;
|
||
|
||
/**
|
||
* 账户域 相关操作(客户账号)
|
||
*
|
||
* Class AccountRepository
|
||
* @package app\repository
|
||
* @method self getInstance(Model $model = null) static
|
||
*/
|
||
class AccountRepository extends Repository
|
||
{
|
||
/**
|
||
* 获取用户列表
|
||
*
|
||
* @throws RepositoryException
|
||
*/
|
||
public function list(): ?array
|
||
{
|
||
return $this->findList();
|
||
}
|
||
|
||
/**
|
||
* 获取指定账户记录By手机号
|
||
*
|
||
* @param string $phone
|
||
* @param array $fields
|
||
* @return Model|null
|
||
* @throws DataNotFoundException
|
||
* @throws DbException
|
||
* @throws ModelNotFoundException
|
||
*/
|
||
public function infoByPhone(string $phone, array $fields = []): ?Model
|
||
{
|
||
$where[] = ['mobile', '=', $phone];
|
||
return $this->findOneByWhere($where, $fields);
|
||
}
|
||
|
||
/**
|
||
* 获取指定账户记录By用户名
|
||
*
|
||
* @param string $username
|
||
* @param array $fields
|
||
* @return Model|null
|
||
* @throws DataNotFoundException
|
||
* @throws DbException
|
||
* @throws ModelNotFoundException
|
||
*/
|
||
public function infoByUsername(string $username, array $fields = []): ?Model
|
||
{
|
||
$where[] = ['username', '=', $username];
|
||
return $this->findOneByWhere($where, $fields);
|
||
}
|
||
|
||
/**
|
||
* 混合查找记录
|
||
*
|
||
* @param string $username 混合查询 手机号或用户名
|
||
* @return array|Model|null
|
||
* @throws DataNotFoundException
|
||
* @throws DbException
|
||
* @throws ModelNotFoundException
|
||
*/
|
||
public function findByHybrid(string $username)
|
||
{
|
||
return $this->model->whereOr('username', $username)->whereOr('mobile', $username)->find();
|
||
}
|
||
|
||
/**
|
||
* 通过微信小程序的openID查询
|
||
*
|
||
* @param string $openID
|
||
* @return array|Model|null
|
||
* @throws DataNotFoundException
|
||
* @throws DbException
|
||
* @throws ModelNotFoundException
|
||
*/
|
||
public function findByOpenID(string $openID)
|
||
{
|
||
return $this->model->where('openid', $openID)->find();
|
||
}
|
||
|
||
/**
|
||
* 通过个人邀请码查询用户信息
|
||
*
|
||
* @param string $inviteCode
|
||
* @return array|Model|null
|
||
* @throws DataNotFoundException
|
||
* @throws DbException
|
||
* @throws ModelNotFoundException
|
||
*/
|
||
public function findByInviteCode(string $inviteCode)
|
||
{
|
||
if (empty($inviteCode)) {
|
||
return null;
|
||
}
|
||
return $this->model->where('invite_code', $inviteCode)->find();
|
||
}
|
||
|
||
/**
|
||
* 通过个人编号查询用户信息
|
||
*
|
||
* @param string $coding
|
||
* @return array|Model|null
|
||
* @throws DataNotFoundException
|
||
* @throws DbException
|
||
* @throws ModelNotFoundException
|
||
*/
|
||
public function findByUserCoding(string $coding)
|
||
{
|
||
if (empty($coding)) {
|
||
return null;
|
||
}
|
||
return $this->model->where('coding', $coding)->find();
|
||
}
|
||
|
||
/**
|
||
* 修改密码
|
||
*
|
||
* @param int $accountId
|
||
* @param string $oldPwd
|
||
* @param string $newPwd
|
||
* @return bool
|
||
* @throws RepositoryException
|
||
*/
|
||
public function modifyPwd(int $accountId, string $oldPwd, string $newPwd): bool
|
||
{
|
||
if (!$user = $this->findById($accountId)) {
|
||
throw new RepositoryException('用户不存在');
|
||
}
|
||
|
||
if ($user['password'] != md5($oldPwd)) {
|
||
throw new RepositoryException('原密码错误');
|
||
}
|
||
|
||
$user->password = md5($newPwd);
|
||
|
||
return $user->save();
|
||
}
|
||
|
||
/**********************************************
|
||
* TODO 分割线,上述与本项目无关的代码需要清除
|
||
*********************************************/
|
||
|
||
/**
|
||
* 修改用户数据
|
||
*
|
||
* @param int $accountId
|
||
* @param array $fieldsKV 修改内容:键值对
|
||
* @return mixed
|
||
* @throws RepositoryException
|
||
*/
|
||
public function accountEditInfo(int $accountId, array $fieldsKV)
|
||
{
|
||
$allowFields = ['headimgurl', 'real_name', 'nickname', 'mobile', 'gender', 'province', 'city', 'county', 'birthday'];
|
||
$fieldsKV = arrayKeysFilter($fieldsKV, $allowFields);
|
||
|
||
if (isset($fieldsKV['mobile']) && !empty($fieldsKV['mobile'])) {
|
||
if (!checkMobile($fieldsKV['mobile'])) {
|
||
throw new RepositoryException('手机号不正确');
|
||
}
|
||
}
|
||
|
||
if (!$account = $this->findById($accountId)) {
|
||
throw new RepositoryException('用户信息错误');
|
||
}
|
||
|
||
return $account->save($fieldsKV);
|
||
}
|
||
|
||
/**
|
||
* 统计用户分销人数(二级)
|
||
*/
|
||
public function shareAccountCount(int $accountId): array
|
||
{
|
||
$data = [
|
||
'first' => 0,
|
||
'second' => 0,
|
||
'total' => 0,
|
||
];
|
||
try {
|
||
$data['first'] = ShareRegLog::where('inviter_account_id', $accountId)->where('is_active', ShareRegLog::COMMON_ON)->count();
|
||
$data['second'] = ShareRegLog::where('inviter_parent_account_id', $accountId)->where('is_active', ShareRegLog::COMMON_ON)->count();
|
||
$data['total'] = $data['first'] + $data['second'];
|
||
} catch (Exception $e) {
|
||
|
||
}
|
||
|
||
return $data;
|
||
}
|
||
|
||
|
||
/**
|
||
* 添加分享注册关系绑定日志
|
||
*
|
||
* @param int $accountId
|
||
* @param int $inviterId
|
||
* @param string $grade 分享绑定关系层级
|
||
* @param bool $accountActive 是否为有效用户
|
||
* @return bool
|
||
*/
|
||
public function addShareRegLogBak(int $accountId, int $inviterId, string $grade, bool $accountActive = true): bool
|
||
{
|
||
if ($accountId <= 0 || $inviterId <= 0) {
|
||
return false;
|
||
}
|
||
|
||
Db::startTrans();
|
||
try {
|
||
$shareConf = ExtraConfig::share();
|
||
$score = $shareConf[$grade] ?? 0;
|
||
|
||
$regLog = ShareRegLog::where('reg_account_id', $accountId)
|
||
->where('inviter_account_id', $inviterId)
|
||
->find();
|
||
|
||
$isCreate = false;
|
||
$isUpdate = false;
|
||
|
||
if ($accountActive) {
|
||
if (!$regLog) {
|
||
$isCreate = true;
|
||
} elseif ($regLog['score'] == 0) {
|
||
// 用户激活后,获得积分
|
||
$isUpdate = true;
|
||
}
|
||
|
||
} else {
|
||
if ($regLog) {
|
||
throw new RepositoryException('已有绑定记录!');
|
||
} else {
|
||
// 未有效激活的用户,相关绑定的人员只有在该用户成功激活后才能获得积分
|
||
$score = 0;
|
||
$isCreate = true;
|
||
}
|
||
}
|
||
|
||
switch ($grade) {
|
||
case self::SHARE_CURRENT:
|
||
$grade = ShareRegLog::SHARE_GRADE_FIRST;
|
||
break;
|
||
case self::SHARE_PARENT:
|
||
$grade = ShareRegLog::SHARE_GRADE_SECOND;
|
||
break;
|
||
case self::SHARE_SERVICE:
|
||
$grade = ShareRegLog::SHARE_GRADE_SERVICE;
|
||
break;
|
||
default:
|
||
return false;
|
||
}
|
||
|
||
if ($isCreate) {
|
||
ShareRegLog::create([
|
||
'reg_account_id' => $accountId,
|
||
'inviter_account_id' => $inviterId,
|
||
'grade' => $grade,
|
||
'score' => $score,
|
||
'created_at' => date('Y-m-d H:i:s')
|
||
]);
|
||
} elseif ($isUpdate) {
|
||
$regLog->save(['score' => $score]);
|
||
}
|
||
|
||
if ($isCreate || $isUpdate) {
|
||
$inviter = $this->model->where('id', $inviterId)->lock(true)->find();
|
||
if ($inviter) {
|
||
Account::updateById($inviterId, [
|
||
'score' => $inviter['score'] + $score
|
||
]);
|
||
}
|
||
}
|
||
|
||
Db::commit();
|
||
} catch (RepositoryException | Exception $e) {
|
||
Db::rollback();
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 注册时邀请关系绑定
|
||
* 存在邀请人时。邀请人、邀请人当前的客服、邀请人的邀请人三者均可获得相应积分
|
||
*
|
||
* @param int $regAccountId 注册人ID
|
||
* @param int $inviterId 邀请人ID
|
||
* @param int $inviterParentAid 邀请人的邀请人ID
|
||
* @param int $serviceId 邀请人的当前客服ID
|
||
* @return bool
|
||
* @throws DataNotFoundException
|
||
* @throws DbException
|
||
* @throws ModelNotFoundException
|
||
*/
|
||
public function addShareRegLog(int $regAccountId, int $inviterId, int $inviterParentAid = 0, int $serviceId = 0): bool
|
||
{
|
||
if ($regAccountId <= 0 || $inviterId <= 0) {
|
||
return false;
|
||
}
|
||
|
||
$shareConf = ExtraConfig::share();
|
||
|
||
if (ShareRegLog::where('reg_account_id', $regAccountId)->find()) {
|
||
return true;
|
||
}
|
||
|
||
ShareRegLog::create([
|
||
'reg_account_id' => $regAccountId,
|
||
'inviter_account_id' => $inviterId,
|
||
'inviter_parent_account_id' => $inviterParentAid,
|
||
'inviter_service_account_id' => $serviceId,
|
||
'score' => $shareConf[self::SHARE_CURRENT] ?? 0,
|
||
'parent_score' => $shareConf[self::SHARE_PARENT] ?? 0,
|
||
'service_score' => $shareConf[self::SHARE_SERVICE] ?? 0,
|
||
'is_active' => ShareRegLog::COMMON_OFF,
|
||
'created_at' => date('Y-m-d H:i:s'),
|
||
]);
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 分享注册激活 【手机绑定时激活】
|
||
* 激活时:1、日志变更 2、积分发放【邀请人、邀请人上级、邀请人客服】 3、积分日志添加
|
||
*
|
||
* @param int $regAccountId
|
||
* @return bool
|
||
*/
|
||
public function activeShareRegLog(int $regAccountId): bool
|
||
{
|
||
if ($regAccountId <= 0) {
|
||
return false;
|
||
}
|
||
|
||
Db::startTrans();
|
||
try {
|
||
if (!$regLog = ShareRegLog::where('reg_account_id', $regAccountId)->find()) {
|
||
return false;
|
||
}
|
||
|
||
if ($regLog['is_active'] == ShareRegLog::COMMON_ON) {
|
||
return true;
|
||
}
|
||
|
||
ShareRegLog::where('reg_account_id', $regAccountId)->save(
|
||
['is_active' => ShareRegLog::COMMON_ON, 'activated_at' => date('Y-m-d H:i:s')]
|
||
);
|
||
|
||
$accountFields = ['id', 'score'];
|
||
|
||
// 邀请人积分添加
|
||
if ($regLog['score'] > 0) {
|
||
$inviter = Account::findById($regLog['inviter_account_id'], $accountFields);
|
||
|
||
AccountDataLog::log($regLog['inviter_account_id'], '分享注册', $regLog['score'],
|
||
AccountDataLog::TYPE_SCORE, AccountDataLog::ACTION_SHARE_REG,
|
||
$inviter['score'], '系统自动发放');
|
||
$inviter->save(
|
||
['score' => Db::raw('`score` + '.$regLog['score'])]
|
||
);
|
||
}
|
||
|
||
// 邀请人父级积分添加
|
||
if ($regLog['inviter_parent_account_id'] > 0 && $regLog['parent_score'] > 0) {
|
||
$inviterParent = Account::findById($regLog['inviter_parent_account_id'], $accountFields);
|
||
|
||
AccountDataLog::log($regLog['inviter_parent_account_id'], '分享注册-下级分享', $regLog['parent_score'],
|
||
AccountDataLog::TYPE_SCORE, AccountDataLog::ACTION_SHARE_REG_CHILD,
|
||
$inviterParent['score'], '系统自动发放');
|
||
$inviterParent->save(
|
||
['score' => Db::raw('`score` + '.$regLog['parent_score'])]
|
||
);
|
||
}
|
||
|
||
// 邀请人的客服积分添加
|
||
if ($regLog['inviter_service_account_id'] > 0 && $regLog['service_score']) {
|
||
$inviterService = Account::findById($regLog['inviter_service_account_id'], $accountFields);
|
||
|
||
AccountDataLog::log($regLog['inviter_service_account_id'], '分享注册-分享人客服获得积分', $regLog['service_score'],
|
||
AccountDataLog::TYPE_SCORE, AccountDataLog::ACTION_SHARE_REG_SERVICE,
|
||
$inviterService['score'], '系统自动发放');
|
||
$inviterService->save(
|
||
['score' => Db::raw('`score` + '.$regLog['service_score'])]
|
||
);
|
||
}
|
||
|
||
Db::commit();
|
||
} catch (Exception $e) {
|
||
self::log($e);
|
||
Db::rollback();
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 查看分享绑定的用户信息
|
||
*
|
||
* @param int $accountId
|
||
* @param string $grade
|
||
* @param int $page
|
||
* @param int $size
|
||
* @return array|null
|
||
*/
|
||
public function shareUsers(int $accountId, string $grade, int $page = 1, int $size = 10): ?array
|
||
{
|
||
$data = [
|
||
'total' => 0,
|
||
'current' => $page,
|
||
'size' => $size,
|
||
'list' => new Collection(),
|
||
];
|
||
|
||
try {
|
||
if (!in_array($grade, [self::SHARE_GRADE_FIRST, self::SHARE_GRADE_SECOND])) {
|
||
throw new RepositoryException('层级参数错误');
|
||
}
|
||
|
||
$fields = ['id', 'real_name', 'nickname', 'headimgurl', 'invite_source', 'phone_active'];
|
||
$whereMap = [];
|
||
|
||
switch ($grade) {
|
||
case self::SHARE_GRADE_FIRST:
|
||
$whereMap[] = ['inviter_account_id', '=', $accountId];
|
||
break;
|
||
case self::SHARE_GRADE_SECOND:
|
||
$whereMap[] = ['inviter_parent_account_id', '=', $accountId];
|
||
break;
|
||
}
|
||
$whereMap[] = ['is_active', '=', self::BOOL_TRUE];
|
||
$orders = ['id' => 'desc'];
|
||
|
||
$data = ShareRegLog::findList($whereMap, [], $page, $size, function ($q) use ($fields) {
|
||
return $q->with([
|
||
'account' => function ($q2) use ($fields) {
|
||
$q2->field($fields);
|
||
}
|
||
]);
|
||
}, $orders);
|
||
|
||
$inviteSourceTextList = self::inviteSourceList();
|
||
foreach ($data['list'] as $item) {
|
||
$item['desc'] = '';
|
||
$item['grade'] = $grade;
|
||
|
||
if ($grade == self::SHARE_GRADE_SECOND) {
|
||
$item['score'] = $item['parent_score'];
|
||
}
|
||
|
||
if ($grade == self::SHARE_GRADE_SERVICE) {
|
||
$item['score'] = $item['service_score'];
|
||
}
|
||
|
||
unset($item['parent_score']);
|
||
unset($item['service_score']);
|
||
|
||
$regAccount = $item['account'];
|
||
if ($regAccount) {
|
||
$regAccount['invite_source_desc'] = '';
|
||
if ($regAccount['invite_source'] != self::INVITE_SOURCE_DEF) {
|
||
$regAccount['invite_source_desc'] = $inviteSourceTextList[$regAccount['invite_source']] ?? '';
|
||
}
|
||
$regAccount['headimgurl'] = File::convertCompleteFileUrl($regAccount['headimgurl']);
|
||
}
|
||
$item['account'] = $regAccount;
|
||
}
|
||
|
||
} catch (RepositoryException | Exception $e) {
|
||
|
||
}
|
||
|
||
return $data;
|
||
}
|
||
|
||
/**
|
||
* 用户行为记录统计
|
||
* 点赞、收藏、分享等
|
||
* @param string $type
|
||
* @param string $action
|
||
* @param int $accountId
|
||
* @return int
|
||
*/
|
||
public function countRecordByAction(string $type, string $action, int $accountId = 0): int
|
||
{
|
||
if (!in_array($type, AccountRecord::allowTypes())) {
|
||
return 0;
|
||
}
|
||
|
||
if (!in_array($action, AccountRecord::allowActions())) {
|
||
return 0;
|
||
}
|
||
|
||
return AccountRecord::countByAction($type, $action, $accountId);
|
||
}
|
||
|
||
/**
|
||
* 获取用户绑定的客服人员Id
|
||
*/
|
||
public function getBoundServiceAId(int $accountId)
|
||
{
|
||
try {
|
||
return CustomerReceive::getBoundService($accountId);
|
||
} catch (Exception $e) {
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取用户绑定的客服人员
|
||
*/
|
||
public function getBoundService(int $customerAId, string $action)
|
||
{
|
||
try {
|
||
return CustomerReceive::where('customer_aid', $customerAId)
|
||
->where('action', $action)
|
||
->find();
|
||
} catch (Exception $e) {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取客户接待流转记录
|
||
*
|
||
* @param int $customerAId
|
||
* @param array $actions
|
||
* @return CustomerReceive[]|array|Collection
|
||
*/
|
||
public function findListCustomerReceive(int $customerAId, array $actions)
|
||
{
|
||
try {
|
||
return CustomerReceive::where('customer_aid', $customerAId)
|
||
->whereIn('action', $actions)
|
||
->select();
|
||
} catch (Exception $e) {
|
||
return new Collection();
|
||
}
|
||
}
|
||
|
||
// 足迹列表
|
||
public function footmarks(int $accountId, int $customerId = 0, string $keyword = '', int $page = 1, int $size = 20): array
|
||
{
|
||
$customerIds = [];
|
||
if (!$account = Account::findById($accountId)) {
|
||
throw new RepositoryException('账号信息不存在');
|
||
}
|
||
if (!$account->is_staff) {
|
||
throw new RepositoryException('您不是员工');
|
||
}
|
||
|
||
$exclude = $accountId == $customerId ? 0 : $accountId;
|
||
|
||
$rules = AccountRepository::getInstance()->getAccountRules($accountId);
|
||
$ruleChildren = in_array(AccountRule::RULE_FOOTMARKS, $rules);// 查看下级客户
|
||
$ruleAll = in_array(AccountRule::RULE_VIEW_ALL_FOOTMARKS, $rules); // 查看所有足迹
|
||
|
||
// 查看指定人足迹 检查该员工是否可查看
|
||
if (!$ruleChildren && !$ruleAll) {
|
||
throw new RepositoryException('权限不足');
|
||
}
|
||
if ($customerId > 0) {
|
||
$customerIds[] = $customerId;
|
||
}
|
||
|
||
if ($ruleAll) {
|
||
$accountId = 0;// 查看全部权限 则不指定员工account_id
|
||
}
|
||
|
||
return AccountFootmarks::fetch($accountId, $customerIds, $keyword, $page, $size, $exclude);
|
||
}
|
||
|
||
/**
|
||
* 客户列表
|
||
*
|
||
* @param array $where
|
||
* @param array $field
|
||
* @param int $accountId
|
||
* @param int $page
|
||
* @param int $size
|
||
* @param callable|null $call
|
||
* @return array
|
||
* @throws DataNotFoundException
|
||
* @throws DbException
|
||
* @throws ModelNotFoundException
|
||
* @throws RepositoryException
|
||
*/
|
||
public function customerList(array $where = [], array $field = [], int $accountId = 0, int $page = 1, int $size = 20, callable $call = null): array
|
||
{
|
||
if ($accountId > 0) {
|
||
if (!$staff = Staff::findOne(['account_id' => $accountId])) {
|
||
throw new RepositoryException('你不是员工');
|
||
}
|
||
|
||
$staffRules = explode(',', $staff['rules']);
|
||
|
||
if (!in_array('customer-list', $staffRules)) {
|
||
throw new RepositoryException('请获取客户列表查看权限');
|
||
}
|
||
|
||
// 是否具有查看所有用户权限
|
||
if (!in_array('view-all-customer-list', $staffRules)) {
|
||
// 查看自己的客户
|
||
// 获取指定用户的客户 TODO 此处若下级过多 会有性能影响
|
||
$customerIds = CustomerReceive::getChildrenIds($accountId);
|
||
|
||
$where[] = ['id', 'in', $customerIds];
|
||
}
|
||
}
|
||
|
||
return $this->getAndHandleAccountList($where, $field, $page, $size, $call);
|
||
}
|
||
|
||
/**
|
||
* 获取并处理用户列表 【后台用户列表】
|
||
*
|
||
* @param array $where
|
||
* @param array $field 必传字段coin_total
|
||
* @param int $page
|
||
* @param int $size
|
||
* @param callable|null $call
|
||
* @return array|null
|
||
* @throws DataNotFoundException
|
||
* @throws DbException
|
||
* @throws ModelNotFoundException
|
||
* @throws RepositoryException
|
||
*/
|
||
public function getAndHandleAccountList(array $where, array $field, int $page = 1, int $size = 20, callable $call = null): ?array
|
||
{
|
||
$items = self::findList($where, $field, $page, $size, function ($q) use ($call) {
|
||
if ($call !== null) {
|
||
$q = $call($q);
|
||
}
|
||
return $q
|
||
->with(['tags', 'staff', 'customer', 'serviceList'])
|
||
->order('id', 'desc');
|
||
});
|
||
|
||
$levelList = AccountRepository::getInstance()->getLevelList();
|
||
$items['list']->each(function ($item) use ($levelList) {
|
||
$item->channel_text = $this->model::channelTextList()[$item['channel']] ?? '未知来源';
|
||
|
||
$item->share_source = $item->is_staff > 0 ? ($item->staff->name ?? '') : ($item->customer->nickname ?? '');
|
||
$item->is_sign_text = $item->is_sign ? '是' : '否';
|
||
$item->tag = $item->tags->column('name');
|
||
$item->service = $item->serviceList->name ?? '';
|
||
$item->service_name = $item->serviceList->name ?? '';
|
||
$item->source_detail = AccountRepository::getInstance()->getSourceDetail($item->id);
|
||
$item->levelInfo = AccountRepository::getInstance()->getCurrentLevel($item->coin_total, $levelList);
|
||
|
||
$genderText = '保密';
|
||
if ($item->gender == 1) {
|
||
$genderText = '男';
|
||
}
|
||
if ($item->gender == 2) {
|
||
$genderText = '女';
|
||
}
|
||
$item->gender_text = $genderText;
|
||
});
|
||
|
||
return $items;
|
||
}
|
||
|
||
/**
|
||
* 获取账号详细来源
|
||
*
|
||
* @param int $accountId
|
||
* @return string
|
||
* @throws DataNotFoundException
|
||
* @throws DbException
|
||
* @throws ModelNotFoundException
|
||
* @throws RepositoryException
|
||
*/
|
||
public function getSourceDetail(int $accountId): string
|
||
{
|
||
if (!$account = $this->findById($accountId)) {
|
||
return '';
|
||
}
|
||
|
||
switch ($account['channel']) {
|
||
case AccountModel::CHANNEL_NORMAL:
|
||
return '自然流量进入';
|
||
case AccountModel::CHANNEL_MEMBER:
|
||
// 员工信息
|
||
if (!$source = Staff::findOne(['account_id' => $account['inviter_account_id']])) {
|
||
//员工不存在 查找用户信息
|
||
if (!$source = AccountModel::findById($account['inviter_account_id'])) {
|
||
//用户不存在
|
||
$member = '用户已不存在';
|
||
} else {
|
||
$member = $source['name'];
|
||
}
|
||
} else {
|
||
$member = $source['name'];
|
||
}
|
||
return sprintf("员工【%s】分享进入", $member);
|
||
case AccountModel::CHANNEL_CUSTOMER:
|
||
//客户不存在
|
||
$ddd = $account['inviter_account_id'];
|
||
if (!$source = AccountModel::findById($account['inviter_account_id'])) {
|
||
//用户不存在
|
||
$member = '客户已不存在';
|
||
} else {
|
||
$member = $source['nickname'].':'.$source['mobile'];
|
||
}
|
||
return sprintf("客户【%s】分享进入", $member);
|
||
case AccountModel::CHANNEL_ACTIVITY:
|
||
//活码
|
||
if (!$source = Activity::findOne(['code' => $account['source_code']])) {
|
||
//用户不存在
|
||
$member = '活码已不存在';
|
||
} else {
|
||
$member = $source['name'];
|
||
}
|
||
return sprintf("通过活码【%s】进入", $member);
|
||
default:
|
||
return AccountModel::channelTextList()[$account['channel']] ?? '未知渠道';
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 个人海报模板列表
|
||
*
|
||
* @param int $accountId
|
||
* @param int $page
|
||
* @param int $size
|
||
* @return array
|
||
* @throws DataNotFoundException
|
||
* @throws DbException
|
||
* @throws ModelNotFoundException
|
||
* @throws RepositoryException
|
||
*/
|
||
public function poster(int $accountId, int $page = 1, int $size = 10): array
|
||
{
|
||
if (!$account = Account::findById($accountId)) {
|
||
throw new RepositoryException('请先登录');
|
||
}
|
||
|
||
$list = [];
|
||
// 获取可用的会员海报
|
||
$levelPoster = AccountLevel::where('value', '<', $account['coin_total'])->order('value', 'desc')->column('poster');
|
||
|
||
foreach ($levelPoster as $poster) {
|
||
$list = array_merge($list, explode(',', $poster));
|
||
}
|
||
// 获取基础海报列表
|
||
Config::load('extra/mini_program', 'mini_program');
|
||
$conf = config('mini_program');
|
||
$basePoster = $conf['poster'] ?? [];
|
||
$list = array_merge($list, $basePoster);
|
||
$list = array_filter($list);
|
||
return [
|
||
'total' => count($list),
|
||
'current' => $page,
|
||
'size' => $size,
|
||
'list' => array_slice($list, ($page - 1) * $size, $size),
|
||
];
|
||
}
|
||
|
||
/**
|
||
* @throws RepositoryException
|
||
*/
|
||
public function posterInfo(int $accountId, string $posterSrc, string $domain)
|
||
{
|
||
$bgImg = $posterSrc;
|
||
$bgImg = empty($bgImg) ? '' : File::convertCompleteFileUrl($bgImg);
|
||
|
||
try {
|
||
if (!$account = AccountRepository::getInstance()->findById($accountId)) {
|
||
throw new RepositoryException('请先登录');
|
||
}
|
||
|
||
$inviteCode = $account['invite_code'] ?: md5($account['id']);
|
||
$inviteUrl = $domain.'/share?invite_code='.$inviteCode;
|
||
$logoImg = app()->getRootPath().'public/static/images/icon-logo.jpg';
|
||
|
||
$result = Builder::create()
|
||
->writer(new PngWriter())
|
||
->writerOptions([])
|
||
->data($inviteUrl)
|
||
->encoding(new Encoding('UTF-8'))
|
||
->errorCorrectionLevel(new ErrorCorrectionLevelHigh())
|
||
->size(300)
|
||
->margin(10)
|
||
->roundBlockSizeMode(new RoundBlockSizeModeMargin())
|
||
->logoPath($logoImg)
|
||
->logoResizeToHeight(100)
|
||
->logoResizeToWidth(100)
|
||
->logoPunchoutBackground(true)
|
||
->build();
|
||
|
||
$dataUri = $result->getDataUri();
|
||
return GdTool::generatePoster($dataUri, $bgImg);
|
||
} catch (Exception $e) {
|
||
AccountRepository::log('个人海报生成失败', $e);
|
||
throw $e;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取个人日记
|
||
*
|
||
* @param int $accountId
|
||
* @param int $page
|
||
* @param int $size
|
||
* @return array
|
||
* @throws Exception
|
||
*/
|
||
public function diary(int $accountId, int $page = 1, int $size = 10): array
|
||
{
|
||
$where = [];
|
||
$where[] = ['publish_account', '=', $accountId];
|
||
// $where[] = ['diary_check', '=', Archives::COMMON_ON];
|
||
|
||
$field = [];
|
||
return Archives::findList($where, $field, $page, $size, null, ['sort' => 'desc', 'id' => 'desc']);
|
||
}
|
||
|
||
/**
|
||
* 日记添加
|
||
*
|
||
* @param array $params
|
||
* @return bool
|
||
* @throws DataNotFoundException
|
||
* @throws DbException
|
||
* @throws ModelNotFoundException
|
||
* @throws RepositoryException
|
||
*/
|
||
public function diarySave(array $params): bool
|
||
{
|
||
$id = $params['id'] ?? 0;
|
||
$now = date('Y-m-d H:i:s');
|
||
|
||
if ($id > 0) {
|
||
// 修改
|
||
$item = Archives::findById($id);
|
||
if ($item) {
|
||
$item->save($params);
|
||
} else {
|
||
$id = 0;
|
||
}
|
||
}
|
||
|
||
$doctorArr = [];
|
||
if (isset($params['doctor_id'])) {
|
||
$doctorArr = explode(',', $params['doctor_id']);
|
||
}
|
||
|
||
// 新建日记
|
||
if ($id <= 0) {
|
||
$params['category_id'] = ArchivesCategory::where('name', ArchivesCategory::NAME_DIARY)->value('id');
|
||
$params['created_at'] = $now;
|
||
$params['published_at'] = $now;
|
||
$params['created_by'] = $params['publish_account'];
|
||
|
||
$diaryCollection = $this->getDiaryCollection($params['publish_account']);
|
||
if (!$diaryCollection) {
|
||
$diaryCollection = $this->createDiaryCollection($params['publish_account'], $params['disease_id'], $doctorArr);
|
||
}
|
||
|
||
$params['diary_id'] = $diaryCollection['id'];
|
||
|
||
$archives = Archives::create($params);
|
||
$id = $archives['id'];
|
||
}
|
||
|
||
if ($doctorArr) {
|
||
//关联医生
|
||
DoctorRelation::associateDoctor($doctorArr, $id, DoctorRelation::TYPE_CONTENT);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 删除日记
|
||
*
|
||
* @param array $ids
|
||
* @return bool
|
||
*/
|
||
public function diaryDel(array $ids): bool
|
||
{
|
||
Archives::whereIn('id', $ids)->delete();
|
||
// 删除关联医生
|
||
DoctorRelation::whereIn('relation_id', $ids)->where('type', DoctorRelation::TYPE_CONTENT)->delete();
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 日记详情
|
||
*
|
||
* @param int $id
|
||
* @return array|Model|null
|
||
* @throws DataNotFoundException
|
||
* @throws DbException
|
||
* @throws ModelNotFoundException
|
||
*/
|
||
public function diaryInfo(int $id)
|
||
{
|
||
return Archives::findById($id);
|
||
}
|
||
|
||
/**
|
||
* 获取用户日记合集
|
||
*
|
||
* @param int $accountId
|
||
* @return array|Diary|Model|null
|
||
* @throws DataNotFoundException
|
||
* @throws DbException
|
||
* @throws ModelNotFoundException
|
||
*/
|
||
public function getDiaryCollection(int $accountId)
|
||
{
|
||
if (!$diary = Diary::where('account_id', $accountId)->find()) {
|
||
return null;
|
||
}
|
||
return $diary;
|
||
}
|
||
|
||
/**
|
||
* 创建日记合集
|
||
*
|
||
* @param int $accountId
|
||
* @param int $diseaseId
|
||
* @param array $doctorIds 关联医生
|
||
* @return Diary|Model
|
||
* @throws RepositoryException
|
||
*/
|
||
public function createDiaryCollection(int $accountId, int $diseaseId, array $doctorIds = [])
|
||
{
|
||
if (!$account = AccountRepository::getInstance()->findById($accountId)) {
|
||
throw new RepositoryException('用户信息错误');
|
||
}
|
||
|
||
$now = date('Y-m-d H:i:s');
|
||
$diary = Diary::create([
|
||
'title' => '日记合集-'.$account['nickname'],
|
||
'disease_id' => $diseaseId,
|
||
'user' => $account['nickname'],
|
||
'headimg' => $account['headimgurl'],
|
||
'created_at' => $now,
|
||
'published_at' => $now,
|
||
'account_id' => $accountId,
|
||
]);
|
||
|
||
if ($doctorIds) {
|
||
DoctorRelation::associateDoctor($doctorIds, $diary['id'], DoctorRelation::TYPE_DIARY);
|
||
}
|
||
return $diary;
|
||
}
|
||
|
||
|
||
/**
|
||
* 创建消息 支持推送订阅消息和短信 支持批量
|
||
*
|
||
* @param array $item
|
||
* item[title]: 是生生世世 消息标题
|
||
* item[type]: notice 消息类型 此处固定为notice 通知
|
||
* item[target]: part 目标类型 all=所有人 part=部分人
|
||
* item[subscribe_temp_id]: d0efR-Ga27c6eIvx9mAwJcnAqzhM_Sq68XiFvjvlBJM 订阅消息模版ID
|
||
* item[subscribe_data][thing1]: 事实上 订阅消息内容 subscribe_data根据模版变动参数
|
||
* item[subscribe_data][time4]: 坎坎坷坷
|
||
* item[subscribe_data][thing5]: 哈对方的身份
|
||
* item[sms_temp_id]: SMS_231436568 短信模版ID
|
||
* item[content]: 收拾收拾 通知内容
|
||
*
|
||
* @param array $targetList [13,15] 发送人ID列表
|
||
* @throws GuzzleException
|
||
*/
|
||
public function createMessage(array $item, array $targetList)
|
||
{
|
||
$repo = AccountRepository::getInstance();
|
||
|
||
try {
|
||
$type = $item['type'] ?? '';
|
||
$target = $item['target'] ?? '';
|
||
|
||
$subscribeData = $item['subscribe_data'] ?? [];
|
||
$smsData = $item['sms_data'] ?? [];
|
||
|
||
$item["send_at"] = date('Y-m-d H:i:s');
|
||
$item["content"] = $item['content'];
|
||
|
||
$item['is_push'] = MessageModel::COMMON_ON;
|
||
$item['to_subscribe'] = (int) !empty($item['subscribe_temp_id']);
|
||
$item['to_sms'] = (int) !empty($item['sms_temp_id']);
|
||
|
||
$item['subscribe_data'] = json_encode($subscribeData, JSON_UNESCAPED_UNICODE);
|
||
$item['sms_data'] = json_encode($smsData, JSON_UNESCAPED_UNICODE);
|
||
$message = $repo->addMessage($type, $target, $targetList, $item);
|
||
} catch (Exception $e) {
|
||
AccountRepository::log('创建消息通知失败 ', $e);
|
||
}
|
||
|
||
try {
|
||
if ($item['to_sms']) {
|
||
// 批量发送短信
|
||
$res = AccountRepository::getInstance()->smsSend($message->id, $item['sms_temp_id'], $targetList, $smsData);
|
||
// var_dump($res);
|
||
}
|
||
} catch (Exception $e) {
|
||
AccountRepository::log('短信发送失败 ', $e);
|
||
}
|
||
|
||
try {
|
||
if ($item['to_subscribe'] > 0) {
|
||
// 订阅消息发送
|
||
AccountRepository::getInstance()->subscribeSend($message->id, $item['subscribe_temp_id'],
|
||
$targetList, $subscribeData,
|
||
\app\model\Config::MINI_PATH_MESSAGE_CENTER);
|
||
}
|
||
} catch (Exception $e) {
|
||
AccountRepository::log('订阅消息发送失败 ', $e);
|
||
}
|
||
}
|
||
|
||
} |