caipan_shop_admin/app/repository/AccountRepository.php

624 lines
19 KiB
PHP
Raw Normal View History

2022-05-25 11:35:57 +00:00
<?php
namespace app\repository;
use app\exception\RepositoryException;
use app\model\Account;
use app\model\AccountDataLog;
use app\model\AccountRecord;
use app\model\AccountWithdrawalCommission;
use app\model\Channel;
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\Repository;
use app\traits\account\AccountAddressTrait;
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\CouponTrait;
use app\traits\account\TagTrait;
use app\traits\account\FeedbackTrait;
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\Db;
use think\Model;
/**
* 账户域 相关操作(客户账号)
*
* Class AccountRepository
* @package app\repository
* @method self getInstance(Model $model = null) static
*/
class AccountRepository extends Repository
{
use AccountScoreTrait;
use AccountRecordTrait;
use AccountAddressTrait;
use AccountDataLogTrait;
use AccountLevelTrait;
use FeedbackTrait;
use AccountMessageTrait;
use CouponTrait;
use TagTrait;
public const STATUS_NORMAL = Account::STATUS_NORMAL; //正常
public const STATUS_DISABLE = Account::STATUS_DISABLE;//禁用
// 性别
public const GENDER_UNDEFINED = Account::GENDER_UNDEFINED; // 未知
public const GENDER_MALE = Account::GENDER_MALE; // 男性
public const GENDER_FEMALE = Account::GENDER_FEMALE; // 女性
// 分享用户层级
public const SHARE_GRADE_FIRST = ShareRegLog::SHARE_GRADE_FIRST; // 一级
public const SHARE_GRADE_SECOND = ShareRegLog::SHARE_GRADE_SECOND; // 二级
public const SHARE_GRADE_SERVICE = ShareRegLog::SHARE_GRADE_SERVICE; // 二级
// 分享后 可获得积分的层级
public const SHARE_CURRENT = 'share_current'; // 分享者本人
public const SHARE_PARENT = 'share_parent'; // 分享者上级
/**
* 获取用户详情和职工关系
*
* @param int $id
* @param array $fields 若不为空则必须包含id字段否则会导致with关联查询失败
* @return array|Model|null
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function infoWithRelation(int $id, array $fields = [])
{
return $this->model->with(['worker'])
->where('id', $id)
->field($fields)
->find();
}
/**
* 获取用户列表
*
* @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();
}
/**
* 通过微信小程序的unionid查询
*
* @param string $id
* @return array|Model|null
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function findByUnionId(string $id)
{
if (empty($id)) {
return null;
}
return $this->model->whereOr('unionid', $id)->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();
}
/**
* 修改用户数据
*
* @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 $regAccountId 注册人ID
* @param int $inviterId 邀请人ID
* @param int $inviterParentAid 邀请人的邀请人ID
* @return bool
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function addShareRegLog(int $regAccountId, int $inviterId, int $inviterParentAid = 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,
'score' => $shareConf[self::SHARE_CURRENT] ?? 0,
'parent_score' => $shareConf[self::SHARE_PARENT] ?? 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')]
);
// TODO 若激活后需要增加佣金、积分等等在此添加逻辑
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);
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['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);
}
/**
* 获取并处理用户列表 【后台用户列表】
*
* @param array $where
* @param array $field 必传字段coin_total
* @param int $page
* @param int $size
* @param callable|null $call
* @return array|null
* @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'])
->order('id', 'desc');
});
$items['list']->each(function ($item) {
$item->tag = $item->tags->column('name');
$genderText = '保密';
if ($item->gender == 1) {
$genderText = '男';
}
if ($item->gender == 2) {
$genderText = '女';
}
$item->gender_text = $genderText;
});
return $items;
}
/**
* 创建消息 支持推送订阅消息和短信 支持批量
*
* @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);
}
}
/**
* 获取邀请人 仅统计手机授权成功的用户
*
* @param int $accountId
* @return int
*/
public function getInviteCount(int $accountId)
{
return Account::where('inviter_account_id', $accountId)
->where('phone_active', Account::COMMON_ON)
->count();
}
/**
* 获取累计佣金
*
* @param int $accountId
* @return float
*/
public function getCommissionTotal(int $accountId): float
{
return AccountDataLog::where('account_id', $accountId)
->where('type', AccountDataLog::TYPE_COMMISSION)
->where('action', '<>', AccountDataLog::ACTION_WITHDRAWAL_RETURN)
->where('num', '>', 0)
->sum('num');
}
/**
* 获取累计提现
*
* @param int $accountId
* @return float
*/
public function getCommissionWithdrawalTotal(int $accountId): float
{
return AccountWithdrawalCommission::where('account_id', $accountId)
->where('status', AccountWithdrawalCommission::COMMON_ON)
->sum('number');
}
/**
* 获取提现中佣金
*
* @param int $accountId
* @return float
*/
public function getCommissionWithdrawalIngTotal(int $accountId): float
{
return AccountWithdrawalCommission::where('account_id', $accountId)
->where('status', AccountWithdrawalCommission::COMMON_OFF)
->sum('number');
}
/**
* 获取佣金日志
*
* @param int $accountId
* @param int $page
* @param int $size
* @return array
* @throws Exception
*/
public function getCommissionLog(int $accountId, int $page = 1, int $size = 10): array
{
$where[] = ['type', '=', AccountDataLog::TYPE_COMMISSION];
$where[] = ['account_id', '=', $accountId];
$order = ['created_at' => 'desc'];
$fields = ['id', 'name', 'num', 'created_at'];
return AccountDataLog::findList($where, $fields, $page, $size, null, $order);
}
}