caipan_shop_admin/app/repository/AccountRepository.php

624 lines
19 KiB
PHP
Executable File
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?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);
}
}