caipan_shop_admin/app/controller/api/User.php

1220 lines
42 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\controller\api;
use app\exception\ApiRedirectException;
use app\exception\RepositoryException;
use app\exception\TraitException;
use app\model\Account;
use app\model\AccountCoupon;
use app\model\AccountDataLog;
use app\model\AccountRecord;
use app\model\AccountWithdrawalCommission;
use app\model\Message;
use app\repository\AccountRepository;
use app\repository\ArchivesRepository;
use app\repository\OrderRepository;
use app\repository\SpuRepository;
use app\service\File;
use app\service\Jwt;
use app\service\Math;
use app\service\wx\WechatApplets;
use app\validate\User as UserValidate;
use EasyWeChat\Kernel\Exceptions\InvalidConfigException;
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 Intervention\Image\Image;
use Intervention\Image\ImageManagerStatic;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Config as CConfig;
use think\facade\Db;
use think\facade\Log;
use think\response\Json;
class User extends Base
{
protected $noNeedLogin = [
'login',
'tempLogin',
'feedbackTypes',
'shareUsers',
'homeCoupon',
'getCoupon',
'signByQr',
];
public function index(): Json
{
$userId = $this->request->user['user_id'] ?? 0;
return json(['code' => 0, 'msg' => 'Index page , I am '.$userId]);
}
/**
* 登录 成功返回token及用户信息
*
* @return Json
* @throws InvalidConfigException
*/
public function login(): Json
{
$params = $this->request->param();
Log::error('进入参数');
Log::error($params);
Log::error('参数结束');
$validate = new UserValidate();
if (!$validate->scene('wx_applets')->check($params)) {
return $this->json(4000, $validate->getError());
}
$minApp = WechatApplets::getInstance();
$jsCode = $params['code'];
$wxUser = $minApp->auth->session($jsCode);
if (isset($wxUser['errcode']) && $wxUser['errcode'] != 0) {
return $this->json(4001, $wxUser['errcode'].';'.$wxUser['errmsg'] ?? '登录失败');
}
// $wxUser success has [session_key, openid, unionid]
// 有效期2小时
$wxUser['expire_time'] = time() + 7200;
$wxUser['session_key'] = $wxUser['session_key'] ?? '';
$openID = $wxUser['openid'];
$unionid = $wxUser['unionid'] ?? '';
if (empty($openID) && empty($unionid)) {
return $this->json(4002, '登录失败');
}
$isActive = $params['is_active'] ?? 0;
$isActive = (is_numeric($isActive) && $isActive > 0) ? AccountRepository::BOOL_TRUE : AccountRepository::BOOL_FALSE;
$phoneActive = $params['phone_active'] ?? 0;
$phoneActive = (is_numeric($phoneActive) && $phoneActive > 0) ? AccountRepository::BOOL_TRUE : AccountRepository::BOOL_FALSE;
try {
$repo = AccountRepository::getInstance();
$account = $repo->findByOpenID($openID);
if (!$account && !empty($unionid)) {
$account = $repo->findByUnionId($unionid);
}
$inviteCode = $params['invite_code'] ?? '';
$now = date('Y-m-d H:i:s');
if (!$account) {
// 自动注册
$inviterAid = 0;
$inviterParentAid = 0;
$inviter = null;
// 存在邀请人
if (!empty($inviteCode)) {
$inviter = $repo->findByInviteCode($inviteCode);
if ($inviter) {
$inviterAid = $inviter['id'];
$inviterParentAid = $inviter['inviter_account_id'];
}
}
$account = $repo->create([
'unionid' => $unionid ?? '',
'openid' => $openID,
'last_login' => $now,
'login_ip' => $this->request->ip(),
'created_at' => $now,
'nickname' => $params['nickname'] ?? '',
'headimgurl' => $params['headimgurl'] ?? '',
'country' => $params['country'] ?? '',
'province' => $params['province'] ?? '',
'city' => $params['city'] ?? '',
'county' => $params['county'] ?? '',
'gender' => $params['gender'] ?? 0,
'language' => $params['language'] ?? 'zh_CN',
'mobile' => $params['mobile'] ?? '',
'status' => AccountRepository::STATUS_NORMAL,
'inviter_account_id' => $inviterAid,
'inviter_parent_id' => $inviterParentAid,
'is_active' => $isActive,
'phone_active' => $phoneActive,
'session_key' => $wxUser['session_key'] ?? '',
]);
$regAccountId = $account->id ?? 0;
// 存在邀请人
if ($inviter) {
$repo->addShareRegLog($regAccountId, $inviterAid, $inviterParentAid);
}
AccountRecord::record($regAccountId, AccountRecord::TYPE_OTHER, AccountRecord::ACTION_REGISTER);
} else {
$updateData = [
'last_login' => date('Y-m-d H:i:s'),
'login_ip' => $this->request->ip(),
'session_key' => $wxUser['session_key'] ?? '',
'language' => $params['language'] ?? 'zh_CN',
];
$phoneActiveOld = $account['phone_active'];
// 更新资料
$modifyStringList = ['headimgurl', 'nickname', 'mobile', 'country', 'province', 'city', 'county'];
foreach ($modifyStringList as $modifyKey) {
if (isset($account[$modifyKey]) && empty($account[$modifyKey])) {
$updateData[$modifyKey] = $params[$modifyKey] ?? '';
}
}
if (empty($account['gender'])) {
$updateData['gender'] = $params['gender'] ?? 0;
}
if (isset($account['is_active']) && $account['is_active'] == AccountRepository::BOOL_FALSE) {
$updateData['is_active'] = $isActive;
}
if (isset($account['phone_active']) && $account['phone_active'] == AccountRepository::BOOL_FALSE) {
$updateData['phone_active'] = $phoneActive;
}
$repo->update($updateData, ['id' => $account['id']]);
$account = $repo->findById($account['id']);
// 授权手机号后才能算有效激活用户,并更新相关业务数据
if ($phoneActiveOld == AccountRepository::BOOL_FALSE && $account['phone_active'] == AccountRepository::BOOL_TRUE) {
$repo->activeShareRegLog($account['id']);
}
}
} catch (RepositoryException | Exception $e) {
return $this->json(4003, '登录失败!'.$e->getMessage());
}
$account = $account->toArray();
$jwtData = [
'user_id' => $account['id'],
'open_id' => $openID,
'session_key' => $wxUser['session_key'],
'expire_time' => $wxUser['expire_time'],
];
$account['headimgurl'] = File::convertCompleteFileUrl($account['headimgurl']);
$fields = [
'coding', 'real_name', 'nickname', 'headimgurl', 'gender', 'mobile',
'province', 'city', 'county', 'country', 'birthday',
'score', 'status', 'position', 'invite_code', 'is_active', 'phone_active'
];
$accountData = arrayKeysFilter($account, $fields);
$data = [
'account_id' => $account['id'],
'token' => Jwt::generate($jwtData),
'expire' => $wxUser['expire_time'],
'openid' => $openID,
];
$data = array_merge($data, $accountData);
return $this->json(0, 'success', $data);
}
/**
* 获取用户信息
*
* @return Json
*/
public function info(): Json
{
try {
$accountId = $this->request->user['user_id'] ?? 0;
$fields = [
'id', 'coding', 'real_name', 'nickname', 'headimgurl', 'mobile',
// 'province', 'city', 'county', 'country', 'birthday', 'gender'
'score', 'status', 'invite_code', 'channel',
'is_active', "continuity_sign", "last_sign_online", 'phone_active','address','contacts'
];
$repo = AccountRepository::getInstance();
$user = $repo->findById($accountId, $fields);
if (empty($user)) {
return $this->json(4004, '没有相关的用户记录');
}
$user->headimgurl = File::convertCompleteFileUrl($user->headimgurl ?? '');
/**
* 补充信息:
* 文章收藏量、分享注册用户量包含2级
*/
// $user->collects = $repo->countRecordByAction(AccountRecord::TYPE_CONTENT, AccountRecord::ACTION_COLLECT, $accountId);
// $user->share_users = $repo->shareAccountCount($accountId);
// $user->unread_messages = $repo->countUnReadMessage($accountId);
$user = $user->toArray();
$user = arrayNullToString($user);
$user['order_count'] = OrderRepository::getInstance()->orderCount($accountId);
return $this->json(0, 'success', $user);
} catch (Exception $e) {
return $this->json(4000, '没有相关的用户记录'.$e->getMessage());
}
}
/**
* 首页优惠券
*
* @return Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function homeCoupon(): Json
{
$accountId = $this->request->user['user_id'] ?? 0;
//是否有可领取的推荐优惠券(进入首页时弹出)
$homeCoupon = AccountCoupon::homeCoupon($accountId);
$data['has_coupon'] = (int) !empty($homeCoupon);
$data['home_coupon'] = $homeCoupon;
return $this->json(0, 'success', $data);
}
/**
* 修改用户资料
* 修改内容范围:姓名、昵称、联系电话、性别、地址(省、市、区/县)
* array $params 键值对形式
*/
public function editInfo(): Json
{
if (!$this->request->isPost()) {
return $this->json(4000, '无效请求');
}
$params = $this->request->param();
$validate = new UserValidate();
if (!$validate->scene('edit')->check($params)) {
return $this->json(4001, $validate->getError());
}
$accountId = $this->request->user['user_id'] ?? 0;
try {
AccountRepository::getInstance()->accountEditInfo($accountId, $params);
} catch (RepositoryException $e) {
return $this->json(4002, $e->getMessage());
} catch (Exception $e) {
return $this->json(5000, '资料修改失败');
}
return $this->json();
}
/**
* 临时登录 通过openid登录 仅用于接口测试阶段
*
* @return Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function tempLogin(): Json
{
$params = $this->request->param();
if (!isset($params['openid'])) {
return $this->json(4001, '参数错误');
}
if (!$user = AccountRepository::getInstance()->findByOpenID($params['openid'])) {
return $this->json(4004, '账号不存在');
}
$data = [
'token' => Jwt::generate(['user_id' => $user['id'], 'nickname' => $user['nickname']]),
'expire' => Jwt::expire()
];
return $this->json(0, 'success', $data);
}
/**
* 个人分享中心
* 统计:累计积分、累计绑定的客户数量(包含2级分销)
*/
public function shareCount(): Json
{
$accountId = $this->request->user['user_id'] ?? 0;
$res = [
'score' => 0,
'user_count' => [
'first' => 0,
'second' => 0,
'total' => 0,
],
'order_count' => 0,
];
try {
$repo = AccountRepository::getInstance();
$account = $repo->findById($accountId);
if (!empty($account)) {
$res['score'] = $account['score'] ?? 0;
$res['user_count'] = $repo->shareAccountCount($accountId);
}
} catch (Exception $e) {
}
return $this->json(0, 'success', $res);
}
/**
* 查看分享绑定用户的信息
*/
public function shareUsers(): Json
{
$accountId = $this->request->user['user_id'] ?? 2;
$page = $this->request->param('page/d', 1);
$size = $this->request->param('size/d', 10);
$grade = $this->request->param('grade/s', 'first'); // 层级[first|second]
$grade = $grade ?: 'first';
if (!in_array($grade, [AccountRepository::SHARE_GRADE_FIRST, AccountRepository::SHARE_GRADE_SECOND])) {
return $this->json(4001, '层级参数错误');
}
$page = $page <= 0 ? 1 : $page;
$size = $size <= 0 ? 10 : $size;
$list = AccountRepository::getInstance()->shareUsers($accountId, $grade, $page, $size);
return $this->json(0, 'success', $list);
}
/**
* 生成用户个人海报 使用intervention/image库
*/
public function personalPoster(): Json
{
$accountId = $this->request->user['user_id'] ?? 0;
$bgImg = $this->request->param('bg_src/s', '');
$bgImg = empty($bgImg) ? '' : File::convertCompleteFileUrl($bgImg);
try {
$account = AccountRepository::getInstance()->findById($accountId);
if (empty($account)) {
return $this->json(4000, '无效请求');
}
$domain = $this->request->domain();
$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(275)
->margin(10)
->roundBlockSizeMode(new RoundBlockSizeModeMargin())
->logoPath($logoImg)
->logoResizeToHeight(100)
->logoResizeToWidth(100)
->logoPunchoutBackground(true)
->build();
$qrBase64 = $result->getDataUri();
$bgImg = $bgImg ?: app()->getRootPath().'public/static/images/poster-bg1.png';
$headimg = $account['headimgurl'] ?? app()->getRootPath().'public/static/images/icon-logo.jpg';
$name = mb_substr($account['nickname'], 0, 4);
$name = $name ?: '商城';
// 圆形头像
$head = $this->getCircleImg($headimg, 60, 60);
$poster = (string) ImageManagerStatic::make($bgImg)
->insert($qrBase64, 'bottom-right', 10, 100)
->insert($head, 'bottom-left', 30, 80)
->text($name.'...邀您关注', 100, 1080, function ($font) {
$font->file('./static/bb4171.ttf');
$font->size(36);
$font->color('#000000');
$font->align('left');
$font->valign('top');
})
->encode('data-url');
// ->save('aaa.png');
return $this->json(0, 'success', ['poster' => $poster]);
} catch (Exception $e) {
AccountRepository::log('个人海报生成失败', $e);
return $this->json(5000, '个人海报生成失败');
}
}
/**
* 圆形头像.
*
* @see https://github.com/Intervention/image/issues/223
*
* @param $img
* @param int $width
* @param int $height
* @return Image
*/
protected function getCircleImg($img, int $width, int $height): Image
{
$avatar_img = ImageManagerStatic::make($img)->resize($width, $height);
$r = $width / 2;
$temp_image = ImageManagerStatic::canvas(185, 185);
for ($x = 0; $x < $avatar_img->width(); $x++) {
for ($y = 0; $y < $avatar_img->height(); $y++) {
if (((($x - $r) * ($x - $r) + ($y - $r) * ($y - $r)) < ($r * $r))) {
$c = $avatar_img->pickColor($x, $y, 'array');
$temp_image->pixel($c, $x, $y);
}
}
}
return $temp_image;
}
/**
* 用户操作记录 分享、咨询
*
* @return Json
* @throws Exception
*/
public function record(): Json
{
if (!$this->request->isPost()) {
return $this->json(4000, '无效请求');
}
$accountId = $this->request->user['user_id'] ?? 0;
$params = input('post.');
$rules = [
'type|操作类型' => 'require|in:content,other,spu,activity',
'action|操作' => 'require',
];
if (isset($params['type']) && $params['type'] == AccountRecord::TYPE_CONTENT) {
$rules['id|ID'] = 'require';
}
$validate = $this->validateByApi($params, $rules, ['type.in' => '类型错误', 'id.require' => '此类型 ID必传']);
if ($validate !== true) {
return $validate;
}
try {
$relationId = $params['id'] ?? 0;
$relationId = is_numeric($relationId) ? $relationId : 0;
AccountRecord::record($accountId, $params['type'], $params['action'], $relationId);
} catch (Exception $e) {
AccountRepository::log('记录用户操作失败', $e);
return $this->json(5001, '操作失败');
}
return $this->json();
}
/**
* 个人二维码
*/
public function personalQr(): Json
{
$accountId = $this->request->user['user_id'] ?? 0;
try {
$account = AccountRepository::getInstance()->findById($accountId);
if (empty($account)) {
return $this->json(4000, '无效请求');
}
$nonceStr = uniqid();
$qrDataStr = json_encode([
'user_coding' => $account['coding'],
'nonce_str' => $nonceStr,
]);
$logoImg = File::convertCompleteFileUrl($account['headimgurl']);
if (empty($logoImg)) {
$logoImg = app()->getRootPath().'public/static/images/icon-logo.jpg';
}
$result = Builder::create()
->writer(new PngWriter())
->writerOptions([])
->data($qrDataStr)
->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 $this->json(0, 'success', ['qr' => $dataUri, 'nonce_str' => $nonceStr]);
} catch (Exception $e) {
AccountRepository::log('个人二维码生成失败', $e);
return $this->json(5000, '个人二维码生成失败');
}
}
/**
* 提交反馈意见
*/
public function addFeedback(): Json
{
if (!$this->request->isPost()) {
return $this->json(4000, '无效请求');
}
$accountId = $this->request->user['user_id'] ?? 0;
$params = [
'type_id' => $this->request->param('type_id/d', 0),
'content' => postFilter($this->request->param('content/s', '')),
'user_name' => postFilter($this->request->param('user_name/s', '')),
'user_phone' => postFilter($this->request->param('user_phone/s', '')),
];
try {
AccountRepository::getInstance()->addFeedback($accountId, $params);
} catch (TraitException $e) {
return $this->json(4001, $e->getMessage());
}
return $this->json(0, '您已提交成功,感谢您的反馈!');
}
/**
* 用户消息
*/
public function messages(): Json
{
$accountId = $this->request->user['user_id'] ?? 0;
$page = $this->request->param('page/d', 1);
$size = $this->request->param('size/d', 10);
$type = $this->request->param('type/s', '');
$page = $page <= 0 ? 1 : $page;
$size = $size <= 0 ? 10 : $size;
$repo = AccountRepository::getInstance();
$whereMap = [];
$fields = [
'id', 'type', 'target', 'title', 'summary', 'content', 'status',
'sort', 'created_at', 'send_at'
];
$orders = ['sort' => 'desc', 'id' => 'desc'];
$regTime = '';
$account = $repo->findById($accountId);
if ($account) {
$regTime = $account['created_at'] ?? '';
}
if ($type) {
if ($type == 'message') {
$whereMap[] = ['type', 'in', [Message::TYPE_NOTICE, Message::TYPE_SYSTEM]];
} else {
$whereMap[] = ['type', '=', $type];
}
}
$resp = $repo->messageList($whereMap, $fields, $page, $size, function ($q) use ($accountId, $regTime) {
return $q->whereTime('send_at', '<=', date('Y-m-d H:i:s'))
->when(!empty($regTime), function ($q3) use ($regTime) {
$q3->whereTime('send_at', '>=', $regTime);
})
->where(function ($q3) use ($accountId) {
$q3->whereRaw('(target = "part" and find_in_set("'.$accountId.'", target_list)) or target <> "part"');
});
}, $orders);
$msgIds = $resp['list']->column('id');
$hadReadMsgIds = $repo->getHadReadMessageIds($accountId, $msgIds);
$msgTypeTextList = $repo->messageTypeTextList();
foreach ($resp['list'] as $item) {
$item['type_text'] = $msgTypeTextList[$item['type']] ?? '';
$item['is_read'] = in_array($item['id'], $hadReadMsgIds) ? AccountRepository::BOOL_TRUE : AccountRepository::BOOL_FALSE;
}
// todo 获取列表后更新阅览日志记录
$repo->addReadLogs($accountId, $msgIds);
return $this->json(0, 'success', $resp);
}
/**
* 查看消息详情
* 添加阅览日志记录
*/
public function messageInfo(): Json
{
$accountId = $this->request->user['user_id'] ?? 0;
$msgId = $this->request->param('message_id/d', 0);
$repo = AccountRepository::getInstance();
$fields = [
'id', 'type', 'target', 'title', 'summary', 'content', 'target_list',
'status', 'sort', 'created_at', 'send_at'
];
$message = $repo->messageInfo($msgId, $fields);
if (empty($message)) {
return $this->json(4004, '没有相关的消息记录');
}
if ($message['target'] == Message::TARGET_PART) {
$targetList = empty($message['target_list']) ? [] : explode(',', $message['target_list']);
if (!in_array($accountId, $targetList)) {
return $this->json(4001, '没有查看权限');
}
} elseif (!empty($message['send_at']) && strtotime($message['send_at']) > time()) {
return $this->json(4001, '没有查看权限');
}
$repo->addReadLogs($accountId, [$msgId]);
$msgTypeTextList = $repo->messageTypeTextList();
$message['type_text'] = $msgTypeTextList[$message['type']] ?? '';
$message['is_read'] = AccountRepository::BOOL_TRUE;
unset($message['target_list']);
return $this->json(0, 'success', $message);
}
/**
* 客户列表
*
* @return Json
* @throws Exception
*/
public function customer(): Json
{
$accountId = $this->request->user['user_id'] ?? 0;
$type = input('type/s', 'all');
$keyword = input('keyword/s', '');
$page = input('page/d', 1);
$size = input('size/d', 20);
try {
if ($accountId == 0) {
return $this->json(6001, '请先登录');
}
$where = [];
if ($type !== 'all') {
$where[] = ['channel', '=', $type];
}
if (!empty($keyword)) {
$where[] = ['nickname|real_name|mobile', 'like', '%'.$keyword.'%'];
}
$where[] = ['phone_active', '=', Account::COMMON_ON];
$field = ['id', 'nickname', 'real_name', 'headimgurl', 'mobile', 'channel', 'created_at', 'customer_service', 'coin_total'];
$data = AccountRepository::getInstance()->getAndHandleAccountList($where, $field, $page, $size);
$data['list'] = $data['list']->each(function ($item) {
$item->real_name = $item->real_name ?? '';
unset($item->tags);
});
return $this->json(0, 'success', $data);
} catch (RepositoryException $e) {
return $this->json(4001, $e->getMessage());
} catch (Exception $e) {
ArchivesRepository::log($e->getMessage(), $e);
return $this->json(5000, '操作失败');
}
}
/**
* 绑定手机
*
* @return bool|Json
* @throws Exception
*/
public function bindPhone()
{
if (!$this->request->isPost()) {
return $this->json(4000, '无效请求');
}
$accountId = $this->request->user['user_id'] ?? 0;
$params = input('post.');
$rules = [
'encryptedData|加密数据' => 'require',
'iv|IV' => 'require',
];
$validate = $this->validateByApi($params, $rules);
if ($validate !== true) {
return $validate;
}
try {
if (!$account = Account::findById($accountId)) {
return $this->json(4000, '用户不存在');
}
$oldPhoneActive = $account['phone_active'];
// 解密手机相关数据 若存在手机则覆盖
$minApp = WechatApplets::getInstance();
$sessionKey = $this->request->user['session_key'] ?? '';
$decryptData = $minApp->encryptor->decryptData($sessionKey, $params['iv'], $params['encryptedData']);
$phone = $decryptData['phoneNumber'] ?? ''; // 通过iv和加密数据 解密出手机号
if (Account::where('id', '<>', $accountId)->where('mobile', $phone)->count() > 0) {
return $this->json(4000, '该手机已被绑定,若有绑定错误,请联系客服');
}
if ($phone) {
$account->save(['mobile' => $phone, 'phone_active' => Account::COMMON_ON]);
}
if ($oldPhoneActive == Account::COMMON_OFF) {
AccountRepository::getInstance()->activeShareRegLog($account['id']);
}
return $this->json(0, 'success', ['phone' => $phone]);
} catch (Exception $e) {
AccountRepository::log('手机绑定失败', $e);
return $this->json(5001, '手机绑定失败');
}
}
/**
* 领取优惠券
*
* @return Json
* @throws Exception
*/
public function getCoupon(): Json
{
$accountId = $this->request->user['user_id'] ?? 0;
$couponID = input('coupon_id/d', 0);
try {
AccountRepository::getInstance()->getCoupon($accountId, $couponID);
return $this->json();
} catch (ApiRedirectException $e) {
return $this->json(302, $e->getMessage());
} catch (RepositoryException $e) {
return $this->json(4000, $e->getMessage());
} catch (Exception $e) {
AccountRepository::log('领取优惠券失败', $e);
return $this->json(5001, '领取优惠券失败');
}
}
/**
* 展示体验券 生成token
*
* @return Json
* @throws Exception
*/
public function exhibitionExperienceCoupon(): Json
{
$accountId = $this->request->user['user_id'] ?? 0;
$couponID = input('coupon_id/d', 0);
try {
$coupon = AccountRepository::getInstance()->userCouponInfo($accountId, $couponID);
$time = time();
//不存在
if (empty($coupon) || !isset($coupon['coupon'])) {
return $this->json(4002, "优惠券不存在");
}
//状态异常
if ($coupon['status'] != AccountCoupon::STATUS_NORMAL) {
return $this->json(4002, "优惠券状态已经不能使用");
}
//未开始
if (strtotime($coupon['coupon']["begin_at"]) > $time) {
return $this->json(4002, "优惠券还未到开始使用时间");
}
//过期
if (strtotime($coupon['coupon']["end_at"]) < $time) {
return $this->json(4002, "优惠券已过期");
}
if ($coupon['is_taste'] != AccountCoupon::COMMON_ON) {
return $this->json(4002, "优惠券不是体验券");
}
$secret = AccountRepository::getInstance()->createExperienceCouponQR($accountId, $couponID);
$url = ($this->request->domain()."/api/staff/coupon/write-off-experience-coupon?account_id=$accountId&&coupon_id=$couponID&&secret=$secret");
return $this->json(0, "success", ["url" => $url, "secret" => $secret]);
} catch (ApiRedirectException $e) {
return $this->json(302, $e->getMessage());
} catch (RepositoryException $e) {
return $this->json(4000, $e->getMessage());
} catch (Exception $e) {
AccountRepository::log('获取优惠券失败', $e);
return $this->json(5001, '获取优惠券失败');
}
}
/**
* 获取优惠券列表
*
* @return Json
* @throws Exception
*/
public function getCouponList(): Json
{
$accountId = $this->request->user['user_id'] ?? 0;
$status = input('status/s', AccountCoupon::STATUS_NORMAL);
$page = input('page/d', 1);
$size = input('size/d', 0);
try {
$data = AccountRepository::getInstance()->couponList($status, $accountId, $page, $size);
return $this->json(0, 'success', $data);
} catch (Exception $e) {
AccountRepository::log('获取优惠券列表失败', $e);
return $this->json(5001, '获取优惠券列表失败');
}
}
/**
* 获取地址列表
*
* @return Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function address(): Json
{
$userId = $this->request->user['user_id'] ?? 0;
$list = AccountRepository::getInstance()->findAddressByUid($userId);
return $this->json(0, 'success', $list);
}
/**
* 保存地址
*
* @return Json
*/
public function addressSave(): Json
{
$userId = $this->request->user['user_id'] ?? 0;
$params = $this->request->param();
$validate = new UserValidate();
$params['user_id'] = $userId;
if (!$validate->scene('address')->check($params)) {
return $this->json(4000, $validate->getError());
}
AccountRepository::getInstance()->saveAddress($params);
return $this->json();
}
/**
* 地址详情
*
* @return Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function addressInfo(): Json
{
if (!$id = input('id/d', 0)) {
return $this->json(4000, '参数错误');
}
$info = AccountRepository::getInstance()->findAddressById($id);
return $this->json(0, 'success', $info);
}
/**
* 地址删除
*
* @return Json
*/
public function addressDel(): Json
{
if (!$id = input('id/d', 0)) {
return $this->json(4000, '参数错误');
}
AccountRepository::getInstance()->delAddress($id);
return $this->json();
}
/**
* 积分收支记录
*
* @return Json
* @throws Exception
*/
public function scoreLog(): Json
{
$page = input('page/d', 1);
$limit = input('size/d', 10);
$type = input("type/s", "in"); //in=收入 out=支出 默认in
$accountId = $this->request->user['user_id'] ?? 0;
$where = [];
$where[] = ["account_id", "=", $accountId];
$where[] = ["type", "=", AccountDataLog::TYPE_SCORE];
if ($type == 'in') {
$where[] = ["num", ">", 0];
}
if ($type == 'out') {
$where[] = ["num", "<", 0];
}
$items = AccountDataLog::findList($where, [], $page, $limit, null, ['id' => 'desc']);
return $this->json(0, '操作成功', $items);
}
/**
* 我的订单
*
* @return Json
* @throws RepositoryException
*/
public function order(): Json
{
$userId = $this->request->user['user_id'] ?? 0;
$page = $this->request->param('page/d', 1);
$size = $this->request->param('size/d', 20);
$tag = $this->request->param('tag/s', 'all');
$domain = $this->request->domain();
$res = OrderRepository::getInstance()->mine($userId, $tag, $page, $size);
$orderStatusTextList = OrderRepository::getInstance()->orderStatusTextList();
$res['list'] = $res['list']->each(function ($item) use ($domain,$orderStatusTextList) {
$item->skus->each(function ($sku) use ($domain,$orderStatusTextList) {
if (!$sku->spec_text) {
$sku->spec_text = [];
$sku->spec_info = [];
} else {
$specArr = json_decode($sku->spec_text, true);
$sku->spec_text = $specArr;
$sku->spec_info = SpuRepository::getInstance()->convertSpecInfo($specArr);
}
$sku->spu_cover = resourceJoin($sku->spu_cover, $domain);
$sku->sku_cover = resourceJoin($sku->sku_cover, $domain);
});
$item->status_text = $orderStatusTextList[$item["status"]];
});
return $this->json(0, 'success', $res);
}
/**
* 立即免拼 需要单人开团允许
*
* @return Json
*/
public function openOne(): Json
{
$userId = $this->request->user['user_id'] ?? 0;
$coding = input('order_coding/s');
try {
if (empty($coding)) {
return $this->json(4001, '参数错误');
}
OrderRepository::getInstance()->openOne($userId, $coding);
return $this->json();
} catch (RepositoryException $e) {
return $this->json(4000, $e->getMessage());
} catch (Exception $e) {
AccountRepository::log('立即免拼失败', $e);
return $this->json(5001, '立即免拼失败');
}
}
/**
* 订单详情
*
* @return Json
* @throws RepositoryException
*/
public function orderDetail(): Json
{
$id = input('id/d', 0);
$userId = $this->request->user['user_id'] ?? 0;
$domain = $this->request->domain();
$res = OrderRepository::getInstance()->detail($id);
$res["status_text"] = OrderRepository::getInstance()->orderStatusTextList()[$res["status"]];
$res->skus->each(function ($sku) use ($domain) {
$specArr = json_decode($sku->spec_text, true);
$sku->spec_text = $specArr;
$sku->spec_info = SpuRepository::getInstance()->convertSpecInfo($specArr);
if (!empty($sku->spu_cover) && !isHttpUrl($sku->spu_cover)) {
$sku->spu_cover = $domain.$sku->spu_cover;
}
if (!empty($sku->sku_cover) && !isHttpUrl($sku->sku_cover)) {
$sku->sku_cover = $domain.$sku->sku_cover;
}
});
if (!$res) {
return $this->json(4000, '订单不存在');
}
if ($res['account_id'] !== $userId) {
return $this->json(4000, '不是您的订单');
}
return $this->json(0, 'success', $res);
}
/**
* 发起提现【佣金】
*
* @return Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function commissionWithdrawal(): Json
{
$commission = input("commission/f", 0);//单位元
$wechat = input("wechat/s");//微信号
$accountId = $this->request->user['user_id'];
$account = Account::findById($accountId, [], function ($q) {
return $q->lock(true);
});
if (empty($commission) || empty($wechat)) {
return $this->json(4001, '参数错误');
}
if (empty($account)) {
return $this->json(6001, '未登录');
}
CConfig::load('extra/commission_withdrawal', 'commission');
// 提现最低限制
$config = config('commission');
$limitCount = $config['limit_withdraw_commission'] ?? 0;
if ($commission < $limitCount) {
return $this->json(4000, '提现佣金不能小于'.$limitCount);
}
//换算出 1元 = 多少佣金
try {
//本次提现共计金额
$totalMoney = AccountWithdrawalCommission::convertCommissionOrMoney($commission * 100, 'money');
$totalMoney = $totalMoney / 100;//分转元
if ($account['commission'] < $commission) {
return $this->json(4004, '佣金不足');
}
} catch (RepositoryException $e) {
return $this->json(4000, $e->getMessage());
} catch (Exception $e) {
Log::error('发起提现失败 MSG:'.$e->getMessage().' Line:'.$e->getLine().' File:'.$e->getFile());
return $this->json(5000, '提现失败');
}
//条件满足 开始写入提现
Db::startTrans();
try {
//写入日志
AccountDataLog::log($account['id'],
"提现-扣除佣金",
$commission * -1,
AccountDataLog::TYPE_COMMISSION,
AccountDataLog::ACTION_WITHDRAWAL,
Math::sub($account[AccountDataLog::TYPE_COMMISSION], $commission)
);
$rate = $config['withdrawal_proportion'] ?? [];
//写入提现记录
$insert = [
"account_id" => $account['id'],
"number" => $commission,
"role" => '',
"money" => $totalMoney,
"proportion" => $rate['commission'].":".$rate['money'],
"status" => AccountWithdrawalCommission::$status_default,
"created_at" => date("Y-m-d H:i:s"),
"remarks" => '微信号:'.$wechat
];
AccountWithdrawalCommission::create($insert);
//扣除佣金
$account->save(["commission" => Db::raw('`commission` - '.$commission)]);
Db::commit();
return $this->json();
} catch (Exception $e) {
Db::rollback();
Log::error('发起提现失败 MSG:'.$e->getMessage().' Line:'.$e->getLine().' File:'.$e->getFile());
return $this->json(5000, "发起提现失败");
}
}
/**
* 佣金详情
*
* @return Json
* @throws RepositoryException
*/
public function commission(): Json
{
$page = input('page/d', 1);
$size = input('size/d', 10);
$userId = $this->request->user['user_id'] ?? 0;
$repo = AccountRepository::getInstance();
if (!$account = $repo->findById($userId, ['id', 'commission'])) {
return $this->json(6001, '请先登录');
}
$data = [
'commission' => $account['commission'],
'invite_count' => $repo->getInviteCount($userId),
'commission_total' => $repo->getCommissionTotal($userId),//累计佣金 元
'withdrawal_total' => $repo->getCommissionWithdrawalTotal($userId),//累计提现 元
'withdrawing_total' => $repo->getCommissionWithdrawalIngTotal($userId),//提现中 元
'log' => $repo->getCommissionLog($userId, $page, $size)
];
return $this->json(0, 'success', $data);
}
/**
* 获取佣金兑换金额 单位元
*
* @throws RepositoryException
*/
public function commission2money(): Json
{
$num = input('num/f', 0); //元
CConfig::load('extra/commission_withdrawal', 'commission_withdrawal');
$config = config('commission_withdrawal')['withdrawal_proportion'] ?? [];
$res['money'] = Math::fen2Yuan(AccountWithdrawalCommission::convertCommissionOrMoney($num * 100, 'money'));
$res['rate']['commission'] = $config['commission'] ?? '比例未设置';
$res['rate']['money'] = $config['money'] ?? '比例未设置';
return $this->json(0, 'success', $res);
}
}