2164 lines
74 KiB
PHP
2164 lines
74 KiB
PHP
<?php
|
||
|
||
namespace app\controller\api;
|
||
|
||
use app\exception\ApiRedirectException;
|
||
use app\exception\RepositoryException;
|
||
use app\exception\TraitException;
|
||
use app\model\Account;
|
||
use app\model\AccountCoinWithdrawal;
|
||
use app\model\AccountCoupon;
|
||
use app\model\AccountDataLog;
|
||
use app\model\AccountRecord;
|
||
use app\model\AccountRole;
|
||
use app\model\AccountRule;
|
||
use app\model\Activity;
|
||
use app\model\Appointment;
|
||
use app\model\Coupon;
|
||
use app\model\CustomerReceive;
|
||
use app\model\Message;
|
||
use app\model\ScanLog;
|
||
use app\model\Staff;
|
||
use app\repository\AccountRepository;
|
||
use app\repository\ArchivesRepository;
|
||
use app\repository\OrderRepository;
|
||
use app\service\File;
|
||
use app\service\GdTool;
|
||
use app\service\Jwt;
|
||
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 think\Collection;
|
||
use think\db\exception\DataNotFoundException;
|
||
use think\db\exception\DbException;
|
||
use think\db\exception\ModelNotFoundException;
|
||
use think\facade\Config;
|
||
use think\facade\Db;
|
||
use think\facade\Log;
|
||
use think\response\Json;
|
||
|
||
class User extends Base
|
||
{
|
||
protected $noNeedLogin = [
|
||
'login',
|
||
'tempLogin',
|
||
'appointmentParameters',
|
||
'appointmentPeriodFull',
|
||
'feedbackTypes',
|
||
'doctorList',
|
||
'doctorInfo',
|
||
'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();
|
||
|
||
$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'];
|
||
|
||
if (empty($openID)) {
|
||
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);
|
||
$inviteCode = $params['invite_code'] ?? '';
|
||
$inviteSource = $params['invite_source'] ?? AccountRepository::INVITE_SOURCE_DEF;
|
||
$channel = $params['channel'] ?? '';
|
||
|
||
if (!$account) {
|
||
// 自动注册
|
||
$inviterAid = 0;
|
||
$inviterParentAid = 0;
|
||
$inviter = null;
|
||
|
||
$customerService = 0;// 所属客服
|
||
if (!empty($inviteCode)) {
|
||
$inviter = $repo->findByInviteCode($inviteCode);
|
||
if ($inviter) {
|
||
$inviterAid = $inviter['id'];
|
||
$inviterParentAid = $inviter['inviter_account_id'];
|
||
$channel = (empty($channel) && $inviter['is_staff'] > 0) ? AccountRepository::CHANNEL_MEMBER : AccountRepository::CHANNEL_CUSTOMER;
|
||
if ($inviter['is_staff'] > 0) {
|
||
//若分享人是员工 自动绑定为客服
|
||
$customerService = $inviter['id'];
|
||
}
|
||
}
|
||
}
|
||
|
||
// 活码进入 绑定客服
|
||
if (isset($params['source_code']) && !empty($params['source_code'])) {
|
||
if ($sourceUser = Activity::findOne(['code' => $params['source_code']])) {
|
||
$customerService = $sourceUser['account_id'] ?? 0;
|
||
}
|
||
}
|
||
$inviteSource = in_array($inviteSource, array_keys(AccountRepository::inviteSourceList())) ? $inviteSource : AccountRepository::INVITE_SOURCE_DEF;
|
||
|
||
$channelList = $repo->channelList();
|
||
$channel = (empty($channel) || !in_array($channel, array_keys($channelList))) ? AccountRepository::CHANNEL_NORMAL : $channel;
|
||
|
||
$account = $repo->create([
|
||
'unionid' => $wxUser['unionid'] ?? '',
|
||
'openid' => $openID,
|
||
'last_login' => date('Y-m-d H:i:s'),
|
||
'login_ip' => $this->request->ip(),
|
||
'created_at' => date('Y-m-d H:i:s'),
|
||
'created_year' => date('Y'),
|
||
'created_month' => date('n'),
|
||
'created_day' => date('j'),
|
||
'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,
|
||
'invite_source' => $inviteSource,
|
||
'inviter_account_id' => $inviterAid,
|
||
'inviter_parent_id' => $inviterParentAid,
|
||
'channel' => $channel,
|
||
'is_staff' => AccountRepository::BOOL_FALSE,
|
||
'is_active' => $isActive,
|
||
'phone_active' => $phoneActive,
|
||
'customer_service' => $customerService,
|
||
'source_code' => $params['source_code'] ?? '',
|
||
'session_key' => $wxUser['session_key'] ?? '',
|
||
]);
|
||
|
||
// 存在所属客服 添加绑定记录
|
||
if ($customerService > 0) {
|
||
CustomerReceive::firstBoundService($account['id'], $customerService);
|
||
}
|
||
|
||
$regAccountId = $account->id ?? 0;
|
||
$accountActive = $phoneActive > 0;
|
||
|
||
if ($inviter) {
|
||
$repo->addShareRegLog($regAccountId, $inviter['id'], AccountRepository::SHARE_GRADE_FIRST, $accountActive);
|
||
if ($inviterParentAid > 0) {
|
||
$repo->addShareRegLog($regAccountId, $inviterParentAid, AccountRepository::SHARE_GRADE_SECOND, $accountActive);
|
||
}
|
||
|
||
// 邀请人绑定的客服可获得积分, 有效用户才关联
|
||
if ($accountActive) {
|
||
$boundServiceAid = $repo->getBoundServiceAId($inviter['id']);
|
||
if ($boundServiceAid > 0) {
|
||
$repo->addShareRegLog($regAccountId, $boundServiceAid, AccountRepository::SHARE_GRADE_SERVICE, true);
|
||
}
|
||
}
|
||
}
|
||
|
||
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) {
|
||
if ($account['inviter_account_id'] > 0) {
|
||
$repo->addShareRegLog($account['id'], $account['inviter_account_id'], AccountRepository::SHARE_GRADE_FIRST, true);
|
||
|
||
// 邀请人绑定的客服可获得积分
|
||
$boundServiceAid = $repo->getBoundServiceAId($account['inviter_account_id']);
|
||
if ($boundServiceAid > 0) {
|
||
$repo->addShareRegLog($account['id'], $boundServiceAid, AccountRepository::SHARE_GRADE_SERVICE, true);
|
||
}
|
||
}
|
||
if ($account['inviter_parent_id'] > 0) {
|
||
$repo->addShareRegLog($account['id'], $account['inviter_parent_id'], AccountRepository::SHARE_GRADE_SECOND, true);
|
||
}
|
||
}
|
||
}
|
||
|
||
} 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', 'channel',
|
||
'is_staff', 'is_active', 'phone_active'
|
||
];
|
||
|
||
$accountData = arrayKeysFilter($account, $fields);
|
||
$account['is_active'] = ($account['is_active'] == Account::COMMON_ON && $account['phone_active'] == Account::COMMON_ON);
|
||
$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', 'gender', 'mobile',
|
||
'province', 'city', 'county', 'country', 'birthday',
|
||
'score', 'status', 'position', 'invite_code', 'channel',
|
||
'is_staff', 'is_active', "continuity_sign", "last_sign_online", 'coin_total', 'coin', 'phone_active'
|
||
];
|
||
$repo = AccountRepository::getInstance();
|
||
$user = $repo->infoWithRelation($accountId, $fields);
|
||
|
||
//更新连续签到次数
|
||
AccountRepository::getInstance()->checkContinuitySign($user);
|
||
|
||
if (empty($user)) {
|
||
return $this->json(4004, '没有相关的用户记录');
|
||
}
|
||
|
||
$user->headimgurl = File::convertCompleteFileUrl($user->headimgurl ?? '');
|
||
|
||
// 职工身份,校验纠正当前用户是否为职工
|
||
$isWorker = (empty($user->worker) || $user->worker['status'] == Staff::STATUS_DISABLE) ? self::BOOL_FALSE : self::BOOL_TRUE;
|
||
$user['is_staff'] = $isWorker ? AccountRepository::BOOL_TRUE : AccountRepository::BOOL_FALSE;
|
||
|
||
/**
|
||
* 补充信息:
|
||
* 文章收藏量、分享注册用户量(包含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['rules'] = $repo->getAccountRules($user['id']);
|
||
$user['order_count'] = OrderRepository::getInstance()->orderCount($accountId);
|
||
$user["level"] = $repo->getUserLevel($user['coin_total']);
|
||
|
||
unset($user['worker']);
|
||
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()
|
||
{
|
||
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);
|
||
}
|
||
|
||
/**
|
||
* 获取自主预约的参数信息
|
||
* 支持7天内预约
|
||
*
|
||
* @return Json
|
||
*/
|
||
public function appointmentParameters(): Json
|
||
{
|
||
$resp = [
|
||
'types' => [],
|
||
'days' => [],
|
||
'times' => [],
|
||
'types_appointment' => [],
|
||
];
|
||
|
||
try {
|
||
$repo = AccountRepository::getInstance();
|
||
$timesResp = $repo->appointmentPeriodNormalList();
|
||
$typesResp = $repo->appointmentTypes(['id', 'title', 'max']);
|
||
|
||
$days = $repo->appointmentAllowDays();
|
||
$times = $timesResp['list']->toArray();
|
||
$types = $typesResp->toArray();
|
||
$nowTime = time();
|
||
|
||
$typesAppointment = [];
|
||
$hadCountList = $repo->appointmentPeriodGroupCount(reset($days), end($days));
|
||
foreach ($types as $type) {
|
||
$allowMax = $type['max'];
|
||
$daysTimes = [];
|
||
|
||
foreach ($days as $day) {
|
||
$dayTimes = [];
|
||
foreach ($times as $time) {
|
||
$hadCount = $hadCountList[$type['id']][$day][$time['id']] ?? 0;
|
||
$isFull = false;
|
||
$disable = false;
|
||
$timeList = $repo->parsePeriodToTime($time['name']);
|
||
$endTime = 0;
|
||
if (!empty($timeList)) {
|
||
$endTime = strtotime($day.' '.$timeList['end']);
|
||
}
|
||
if ($hadCount >= $allowMax) {
|
||
$isFull = true;
|
||
$disable = true;
|
||
}
|
||
if ($endTime <= $nowTime) {
|
||
$disable = true;
|
||
}
|
||
$time['is_full'] = $isFull ? AccountRepository::BOOL_TRUE : AccountRepository::BOOL_FALSE;
|
||
$time['disable'] = $disable ? AccountRepository::BOOL_TRUE : AccountRepository::BOOL_FALSE;
|
||
$dayTimes[] = $time;
|
||
}
|
||
|
||
$daysTimes[] = [
|
||
'day' => $day,
|
||
'times' => $dayTimes
|
||
];
|
||
}
|
||
|
||
$typesAppointment[] = [
|
||
'type' => $type,
|
||
'days_times' => $daysTimes
|
||
|
||
];
|
||
}
|
||
|
||
// 现阶段暂不做工作日排班安排,默认7天内均可预约
|
||
$daysList = [];
|
||
$weekList = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
|
||
$weekStatus = AccountRepository::BOOL_TRUE;
|
||
foreach ($days as $day) {
|
||
$daysList[] = [
|
||
'week' => $weekList[date('w', strtotime($day))],
|
||
'day' => $day,
|
||
'status' => $weekStatus
|
||
];
|
||
}
|
||
|
||
$resp = [
|
||
'types' => $types,
|
||
'days' => $daysList,
|
||
'times' => $times,
|
||
'types_appointment' => $typesAppointment,
|
||
];
|
||
|
||
} catch (TraitException $e) {
|
||
|
||
}
|
||
|
||
return $this->json(0, 'success', $resp);
|
||
}
|
||
|
||
/**
|
||
* 查询指定预约类型下某天禁选的时间段
|
||
* 已约满、时间段已过(超时)
|
||
*/
|
||
public function appointmentPeriodFull(): Json
|
||
{
|
||
$typeId = $this->request->param('type_id/d', 0);
|
||
$appointmentDay = $this->request->param('day/s', '');
|
||
|
||
if ($typeId <= 0 || empty($appointmentDay) || !strtotime($appointmentDay)) {
|
||
return $this->json();
|
||
}
|
||
$appointmentDay = date('Y-m-d', strtotime($appointmentDay));
|
||
|
||
try {
|
||
$repo = AccountRepository::getInstance();
|
||
|
||
$type = $repo->appointmentTypeInfo($typeId);
|
||
if (empty($type)) {
|
||
return $this->json();
|
||
}
|
||
|
||
$hadCountList = $repo->appointmentPeriodGroupCount($appointmentDay, $appointmentDay, [$typeId]);
|
||
$typeDayCounts = $hadCountList[$typeId][$appointmentDay] ?? [];
|
||
$timesResp = $repo->appointmentPeriodNormalList();
|
||
$times = $timesResp['list']->toArray();
|
||
$nowTime = time();
|
||
|
||
$disablePeriods = [];
|
||
foreach ($times as $time) {
|
||
$hadCount = $typeDayCounts[$time['id']] ?? 0;
|
||
$timeList = $repo->parsePeriodToTime($time['name']);
|
||
$endTime = 0;
|
||
$disable = false;
|
||
$isFull = false;
|
||
if (!empty($timeList)) {
|
||
$endTime = strtotime($appointmentDay.' '.$timeList['end']);
|
||
}
|
||
if ($endTime <= $nowTime || $hadCount >= $type['max']) {
|
||
$disable = true;
|
||
$isFull = ($hadCount >= $type['max']);
|
||
}
|
||
|
||
if ($disable) {
|
||
$time['is_full'] = $isFull ? AccountRepository::BOOL_TRUE : AccountRepository::BOOL_FALSE;
|
||
$time['disable'] = AccountRepository::BOOL_TRUE;
|
||
$disablePeriods[] = $time;
|
||
}
|
||
}
|
||
|
||
return $this->json(0, 'success', $disablePeriods);
|
||
} catch (TraitException $e) {
|
||
return $this->json();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 提交预约申请
|
||
*/
|
||
public function appointmentApply(): Json
|
||
{
|
||
if (!$this->request->isPost()) {
|
||
return $this->json(4000, '无效请求');
|
||
}
|
||
|
||
$accountId = $this->request->user['user_id'] ?? 0;
|
||
$params = $this->request->param();
|
||
|
||
try {
|
||
AccountRepository::getInstance()->addAppointment($accountId, $params);
|
||
} catch (TraitException $e) {
|
||
return $this->json(4001, $e->getMessage());
|
||
}
|
||
|
||
return $this->json();
|
||
}
|
||
|
||
/**
|
||
* 用户预约记录
|
||
*
|
||
* @return Json
|
||
*/
|
||
public function appointmentList(): Json
|
||
{
|
||
$accountId = $this->request->user['user_id'] ?? 0;
|
||
$page = $this->request->param('page/d', 1);
|
||
$size = $this->request->param('size/d', 10);
|
||
|
||
$page = $page <= 0 ? 1 : $page;
|
||
$size = $size <= 0 ? 10 : $size;
|
||
|
||
try {
|
||
$repo = AccountRepository::getInstance();
|
||
$resp = $repo->appointmentList($accountId, $page, $size);
|
||
$statusTextList = $repo->appointmentStatusTextList();
|
||
foreach ($resp['list'] as $item) {
|
||
$item['status_text'] = '';
|
||
// 现阶段预约完成,小程序端不显示状态描述
|
||
if ($item['status'] != Appointment::STATUS_OVER) {
|
||
$item['status_text'] = $statusTextList[$item['status']] ?? '';
|
||
}
|
||
}
|
||
|
||
} catch (TraitException $e) {
|
||
$resp = [
|
||
'total' => 0,
|
||
'current' => $page,
|
||
'size' => $size,
|
||
'list' => new Collection(),
|
||
];
|
||
}
|
||
|
||
return $this->json(0, 'success', $resp);
|
||
}
|
||
|
||
/**
|
||
* 取消预约
|
||
*/
|
||
public function appointmentCancel(): Json
|
||
{
|
||
if (!$this->request->isPost()) {
|
||
return $this->json(4000, '无效请求');
|
||
}
|
||
|
||
$accountId = $this->request->user['user_id'] ?? 0;
|
||
$appointId = $this->request->param('appointment_id/d', 0);
|
||
try {
|
||
AccountRepository::getInstance()->cancelAppointment($accountId, $appointId);
|
||
} catch (TraitException $e) {
|
||
return $this->json(4001, $e->getMessage());
|
||
}
|
||
|
||
return $this->json();
|
||
}
|
||
|
||
/**
|
||
* 搜索历史
|
||
*
|
||
* @return Json
|
||
*/
|
||
public function searchHistory(): Json
|
||
{
|
||
$page = input('page/d', 1);
|
||
$size = input('size/d', 10);
|
||
$accountId = $this->request->user['user_id'] ?? 0;
|
||
|
||
try {
|
||
$data = AccountRecord::findSearch($accountId, $page, $size);
|
||
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 Json
|
||
*/
|
||
public function clearSearch(): Json
|
||
{
|
||
$accountId = $this->request->user['user_id'] ?? 0;
|
||
|
||
try {
|
||
AccountRecord::clearSearch($accountId);
|
||
return $this->json(0, 'success');
|
||
} catch (Exception $e) {
|
||
ArchivesRepository::log($e->getMessage(), $e);
|
||
return $this->json(5000, '操作失败');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 个人分享中心
|
||
* 统计:累计积分、累计绑定的客户数量(包含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]
|
||
|
||
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);
|
||
}
|
||
|
||
/**
|
||
* 生成用户个人海报
|
||
*/
|
||
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(300)
|
||
->margin(10)
|
||
->roundBlockSizeMode(new RoundBlockSizeModeMargin())
|
||
->logoPath($logoImg)
|
||
->logoResizeToHeight(100)
|
||
->logoResizeToWidth(100)
|
||
->logoPunchoutBackground(true)
|
||
->build();
|
||
|
||
$dataUri = $result->getDataUri();
|
||
$posterData = GdTool::generatePoster($dataUri, $bgImg);
|
||
|
||
return $this->json(0, 'success', ['poster' => $posterData]);
|
||
} catch (Exception $e) {
|
||
AccountRepository::log('个人海报生成失败', $e);
|
||
return $this->json(5000, '个人海报生成失败');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 用户操作记录 分享、咨询
|
||
*
|
||
* @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',
|
||
'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 signIn(): Json
|
||
{
|
||
if (!$this->request->isPost()) {
|
||
return $this->json(4000, '无效请求');
|
||
}
|
||
|
||
Log::info('用户签到绑定:');
|
||
Log::info(json_encode($this->request->param(), JSON_UNESCAPED_UNICODE));
|
||
|
||
$accountId = $this->request->user['user_id'] ?? 0;
|
||
$userCoding = $this->request->param('user_coding/s', '');
|
||
$nonceStr = $this->request->param('nonce_str/s', '');
|
||
|
||
if (empty($userCoding)) {
|
||
return $this->json(4000, '无效请求');
|
||
}
|
||
|
||
try {
|
||
$repo = AccountRepository::getInstance();
|
||
$signAccount = $repo->findByUserCoding($userCoding);
|
||
if (empty($signAccount)) {
|
||
return $this->json(4001, '签到失败,没有相关的用户记录');
|
||
}
|
||
|
||
// 记录扫码日志
|
||
ScanLog::log($signAccount['id'], $accountId, $nonceStr);
|
||
|
||
$boundSign = $repo->getBoundService($signAccount['id'], CustomerReceive::ACTION_OFFLINE_SIGN);
|
||
if ($boundSign) {
|
||
$signAccount->save(['is_sign' => Account::COMMON_ON]);
|
||
return $this->json(0, '签到成功');
|
||
}
|
||
|
||
$signData = [
|
||
'customer_aid' => $signAccount['id'],
|
||
'worker_aid' => $accountId,
|
||
'created_at' => date('Y-m-d H:i:s'),
|
||
'action' => CustomerReceive::ACTION_OFFLINE_SIGN,
|
||
'pid' => 0,
|
||
'path' => ',0,'
|
||
];
|
||
$boundService = $repo->getBoundService($signAccount['id'], CustomerReceive::ACTION_ONLINE_SERVICE);
|
||
if ($boundService) {
|
||
$signData['pid'] = $boundService['id'];
|
||
$signData['path'] = $boundService['path'].$boundService['id'].',';
|
||
}
|
||
|
||
CustomerReceive::create($signData);
|
||
$signAccount->save(['is_sign' => Account::COMMON_ON, 'customer_service' => $accountId]);
|
||
|
||
} catch (Exception $e) {
|
||
return $this->json(5000, '签到失败');
|
||
}
|
||
|
||
return $this->json();
|
||
}
|
||
|
||
/**
|
||
* 二维码打卡
|
||
* 线下二维码扫码器扫码打卡
|
||
*/
|
||
public function signByQr()
|
||
{
|
||
if (!$this->request->isPost()) {
|
||
return $this->json(4000, '无效请求');
|
||
}
|
||
|
||
Log::info('扫码器提交内容:');
|
||
Log::info(file_get_contents("php://input"));
|
||
|
||
try {
|
||
$input = file_get_contents("php://input");
|
||
// $input = 'vgdecoderesult={"user_coding":"210000000013","nonce_str":"618e1ad5bdded"}&&devicenumber=111&&otherparams=';
|
||
$info = [];
|
||
parse_str($input, $info);
|
||
|
||
$parseInfo = json_decode($info['vgdecoderesult'], true);
|
||
$userCoding = $parseInfo['user_coding'] ?? '';
|
||
$nonceStr = $parseInfo['nonce_str'] ?? '';
|
||
|
||
$deviceNumber = $info['devicenumber'] ?? '';
|
||
|
||
$repo = AccountRepository::getInstance();
|
||
$signAccount = $repo->findByUserCoding($userCoding);
|
||
if (empty($signAccount)) {
|
||
return 'code=4000';
|
||
}
|
||
|
||
// 记录扫码日志
|
||
ScanLog::log($signAccount['id'], 0, $nonceStr, ScanLog::TYPE_SIGN, ScanLog::ACTION_SCAN_BY_MACHINE, $deviceNumber);
|
||
|
||
return 'code=0000';
|
||
} catch (Exception $e) {
|
||
return 'code=4000';
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 检测扫码是否成功
|
||
*
|
||
* @return Json
|
||
*/
|
||
public function checkScan(): Json
|
||
{
|
||
if (!$this->request->isPost()) {
|
||
return $this->json(4000, '无效请求');
|
||
}
|
||
|
||
$accountId = $this->request->user['user_id'] ?? 0;
|
||
if (empty($accountId)) {
|
||
return $this->json(4002, '请先登录');
|
||
}
|
||
|
||
$nonceStr = $this->request->param('nonce_str/s', '');
|
||
if (empty($nonceStr)) {
|
||
return $this->json(4001, '随机字符串必填');
|
||
}
|
||
|
||
return $this->json(0, 'success', ['result' => (int) ScanLog::isScan($accountId, $nonceStr)]);
|
||
}
|
||
|
||
/**
|
||
* 投诉与建议类型选择列表
|
||
* (问题类型列表)
|
||
*/
|
||
public function feedbackTypes(): Json
|
||
{
|
||
$list = AccountRepository::getInstance()->feedbackTypes();
|
||
return $this->json(0, 'success', $list);
|
||
}
|
||
|
||
/**
|
||
* 提交反馈意见
|
||
*/
|
||
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 == 'reminders') {
|
||
$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);
|
||
}
|
||
|
||
/**
|
||
* 医生列表
|
||
*/
|
||
public function doctorList(): Json
|
||
{
|
||
$page = $this->request->param('page/d', 1);
|
||
$size = $this->request->param('size/d', 10);
|
||
$keyword = $this->request->param('keyword/s', '');
|
||
|
||
$page = $page <= 0 ? 1 : $page;
|
||
$size = $size <= 0 ? 10 : $size;
|
||
|
||
$repo = AccountRepository::getInstance();
|
||
|
||
$whereMap = [];
|
||
$fields = [];
|
||
$searchName = '';
|
||
if (!empty($keyword)) {
|
||
/**
|
||
* 关键词查询范围:问题、病种、医生姓名
|
||
*/
|
||
$doctorIds = $repo->searchRelationDoctorIds($keyword);
|
||
if (count($doctorIds)) {
|
||
$whereMap[] = ['id', 'in', $doctorIds];
|
||
} else {
|
||
$searchName = $keyword;
|
||
}
|
||
}
|
||
|
||
$resp = $repo->findDoctorListByWhere($whereMap, $fields, $page, $size, [], function ($q) use ($searchName) {
|
||
if (empty($searchName)) {
|
||
return $q;
|
||
} else {
|
||
// 二维数组JSON查询
|
||
return $q->whereRaw('(JSON_CONTAINS(`extra`, JSON_OBJECT("name", "'.$searchName.'")) or (`name` like "'.$searchName.'%") )');
|
||
}
|
||
});
|
||
|
||
$list = $resp['list']->toArray();
|
||
$diseaseFields = ['disease_id', 'disease_name', 'disease_pid'];
|
||
$accountFields = [
|
||
'id', 'coding', 'real_name', 'nickname', 'headimgurl', 'gender', 'mobile',
|
||
'province', 'city', 'county', 'country', 'birthday', 'status', 'invite_code',
|
||
];
|
||
|
||
foreach ($list as &$item) {
|
||
$diseases = [];
|
||
foreach ($item['diseases'] as $disease) {
|
||
$diseases[$disease['disease_id']] = arrayKeysFilter($disease, $diseaseFields);
|
||
}
|
||
$item['diseases'] = array_values($diseases);
|
||
|
||
$account = arrayKeysFilter($item['account'], $accountFields);
|
||
$account['headimgurl'] = File::convertCompleteFileUrl($account['headimgurl'] ?? '');
|
||
$item['account'] = $account;
|
||
}
|
||
unset($item);
|
||
|
||
$resp['list'] = arrayNullToString($list);
|
||
|
||
return $this->json(0, 'success', $resp);
|
||
}
|
||
|
||
/**
|
||
* 医生详情
|
||
*/
|
||
public function doctorInfo(): Json
|
||
{
|
||
$doctorId = $this->request->param('doctor_id/d', 0);
|
||
|
||
$repo = AccountRepository::getInstance();
|
||
$whereMap = ['id' => $doctorId];
|
||
$doctor = $repo->findDoctorByWhere($whereMap);
|
||
if (empty($doctor)) {
|
||
return $this->json(4004, '没有相关的记录');
|
||
}
|
||
$doctor = $doctor->toArray();
|
||
|
||
// 过滤负责的病种,避免重复
|
||
$diseases = [];
|
||
$diseaseFields = ['disease_id', 'disease_name', 'disease_pid'];
|
||
foreach ($doctor['diseases'] as $item) {
|
||
$diseases[$item['disease_id']] = arrayKeysFilter($item, $diseaseFields);
|
||
}
|
||
$doctor['diseases'] = array_values($diseases);
|
||
|
||
// 管理的前端用户信息过滤
|
||
$accountFields = [
|
||
'id', 'coding', 'real_name', 'nickname', 'headimgurl', 'gender', 'mobile',
|
||
'province', 'city', 'county', 'country', 'birthday', 'status', 'invite_code',
|
||
];
|
||
$account = arrayKeysFilter($doctor['account'], $accountFields);
|
||
$account['headimgurl'] = File::convertCompleteFileUrl($account['headimgurl'] ?? '');
|
||
$doctor['account'] = $account;
|
||
|
||
// null空值转换
|
||
$doctor = arrayNullToString($doctor);
|
||
return $this->json(0, 'success', $doctor);
|
||
}
|
||
|
||
|
||
/**
|
||
* 客户足迹
|
||
*
|
||
* @return Json
|
||
*/
|
||
public function footmarks(): Json
|
||
{
|
||
$page = input('page/d', 1);
|
||
$size = input('size/d', 20);
|
||
$customerId = input('customer_id/d', 0); //指定查询的客户 默认全部
|
||
$keyword = input('keyword/s', ''); //用户姓名或电话
|
||
$accountId = $this->request->user['user_id'] ?? 0;
|
||
|
||
try {
|
||
$data = AccountRepository::getInstance()->footmarks($accountId, $customerId, $keyword, $page, $size);
|
||
|
||
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 Json
|
||
*/
|
||
public function ruleList(): Json
|
||
{
|
||
try {
|
||
$data = AccountRule::field('id,title,name,sort')
|
||
->order('sort', 'desc')
|
||
->order('id', 'asc')
|
||
->select();
|
||
|
||
return $this->json(0, 'success', $data);
|
||
} catch (Exception $e) {
|
||
ArchivesRepository::log($e->getMessage(), $e);
|
||
return $this->json(5000, '操作失败');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取已绑定线上客服的客户列表
|
||
*/
|
||
public function getBindServiceList(): Json
|
||
{
|
||
$accountId = $this->request->user['user_id'] ?? 0;
|
||
$keyword = input('keyword/s', '');
|
||
$page = input('page/d', 1);
|
||
$size = input('size/d', 20);
|
||
$type = input('type/s', '');//mine个人绑定的客户 其他获取全部
|
||
|
||
try {
|
||
$where = [];
|
||
$where[] = ['customer_service', '>', 0];
|
||
if ($type == 'mine') {
|
||
$where[] = ['customer_service', '=', $accountId];
|
||
}
|
||
|
||
if (!empty($keyword)) {
|
||
$where[] = ['nickname|mobile', 'like', '%'.$keyword.'%'];
|
||
}
|
||
|
||
$list = Account::findList($where, ['id', 'nickname', 'mobile', 'customer_service'], $page, $size, function ($q) {
|
||
return $q->with([
|
||
'serviceList' => function ($query) {
|
||
$query->field('id,account_id,name,phone');
|
||
}
|
||
])->order('id', 'desc');
|
||
|
||
});
|
||
|
||
$list['list'] = $list['list']->each(function ($item) {
|
||
if (!$item->serviceList) {
|
||
$item->serviceList = new Staff();
|
||
$item->serviceList->id = 0;
|
||
$item->serviceList->account_id = 0;
|
||
$item->serviceList->name = '所属员工已失效';
|
||
$item->serviceList->phone = '';
|
||
}
|
||
if (isset($item->serviceList->phone)) {
|
||
$item->serviceList->phone = !empty($item->serviceList->phone) ? stringDesensitization($item->serviceList->phone) : '';
|
||
}
|
||
|
||
$item->service = $item->serviceList;
|
||
unset($item->serviceList);
|
||
|
||
if (isset($item->mobile)) {
|
||
$item->mobile = !empty($item->mobile) ? stringDesensitization($item->mobile) : '';
|
||
}
|
||
});
|
||
|
||
return $this->json(0, 'success', $list);
|
||
} catch (Exception $e) {
|
||
Log::error('获取客户绑定列表失败'.$e->getMessage());
|
||
return $this->json(5000, '获取客户绑定列表失败!');
|
||
}
|
||
|
||
}
|
||
|
||
/**
|
||
* 随机绑定客服(线上客服)
|
||
*/
|
||
public function randBindService(): Json
|
||
{
|
||
// 目前关掉随机绑定客服功能
|
||
return $this->json();
|
||
if (!$this->request->isPost()) {
|
||
return $this->json(4000, '无效请求');
|
||
}
|
||
|
||
$accountId = $this->request->user['user_id'] ?? 0;
|
||
|
||
try {
|
||
$repo = AccountRepository::getInstance();
|
||
|
||
if (!$account = $repo->findById($accountId)) {
|
||
return $this->json(4001, '请先登录');
|
||
}
|
||
|
||
$boundService = $repo->getBoundService($accountId, CustomerReceive::ACTION_ONLINE_SERVICE);
|
||
if ($boundService) {
|
||
return $this->json(0, '绑定成功');
|
||
}
|
||
|
||
// 客服列表
|
||
$servicerList = Staff::getStaff(Staff::ROLE_CUSTOMER_ONLINE);
|
||
|
||
if ($servicerList['total'] <= 0) {
|
||
return $this->json(4002, '还没有客服!');
|
||
}
|
||
|
||
$accountIds = $servicerList['list']->where('status', Staff::COMMON_ON)->column('account_id');
|
||
$servicerId = $accountIds[array_rand($accountIds)];//随机获取一个客服ID
|
||
|
||
$boundData = [
|
||
'customer_aid' => $accountId,
|
||
'worker_aid' => $servicerId,
|
||
'action' => CustomerReceive::ACTION_ONLINE_SERVICE,
|
||
'pid' => 0,
|
||
'path' => ',0,',
|
||
'created_at' => date('Y-m-d H:i:s')
|
||
];
|
||
|
||
CustomerReceive::create($boundData);
|
||
$account->save(['customer_service' => $servicerId]);
|
||
|
||
} catch (Exception $e) {
|
||
Log::error('随机绑定客服失败'.$e->getMessage());
|
||
return $this->json(5000, '绑定失败!');
|
||
}
|
||
|
||
return $this->json();
|
||
}
|
||
|
||
/**
|
||
* 用户绑定客服人员(线上客服)
|
||
*/
|
||
public function bindService(): Json
|
||
{
|
||
if (!$this->request->isPost()) {
|
||
return $this->json(4000, '无效请求');
|
||
}
|
||
Log::info('线上客服绑定:');
|
||
Log::info(json_encode($this->request->param(), JSON_UNESCAPED_UNICODE));
|
||
$accountId = $this->request->user['user_id'] ?? 0;
|
||
$serviceCoding = $this->request->param('service_coding/s', '');
|
||
if (empty($serviceCoding)) {
|
||
return $this->json(4000, '无效请求');
|
||
}
|
||
|
||
try {
|
||
$repo = AccountRepository::getInstance();
|
||
$serviceAccount = $repo->findByUserCoding($serviceCoding);
|
||
if (empty($serviceAccount)) {
|
||
return $this->json(4001, '绑定客服失败!没有相关的客服记录');
|
||
}
|
||
|
||
$boundService = $repo->getBoundService($accountId, CustomerReceive::ACTION_ONLINE_SERVICE);
|
||
if ($boundService) {
|
||
return $this->json(0, '绑定成功');
|
||
}
|
||
|
||
$service = $repo->findServiceByWhere(['account_id' => $serviceAccount['id']]);
|
||
if (empty($service)) {
|
||
return $this->json(4002, '绑定客服失败!没有相关的客服记录');
|
||
} elseif ($service['status'] == staff::STATUS_DISABLE) {
|
||
return $this->json(4003, '绑定客服失败!该客服账号已被冻结');
|
||
}
|
||
|
||
$boundData = [
|
||
'customer_aid' => $accountId,
|
||
'worker_aid' => $serviceAccount['id'],
|
||
'action' => CustomerReceive::ACTION_ONLINE_SERVICE,
|
||
'pid' => 0,
|
||
'path' => ',0,'
|
||
];
|
||
|
||
CustomerReceive::create($boundData);
|
||
|
||
} catch (Exception $e) {
|
||
return $this->json(5000, '绑定失败!');
|
||
}
|
||
|
||
return $this->json();
|
||
}
|
||
|
||
/**
|
||
* 客服二维码
|
||
* @return Json
|
||
*/
|
||
public function serviceQr(): Json
|
||
{
|
||
$accountId = $this->request->user['user_id'] ?? 0;
|
||
try {
|
||
$account = AccountRepository::getInstance()->findById($accountId);
|
||
if (empty($account)) {
|
||
return $this->json(4000, '无效请求');
|
||
}
|
||
|
||
$qrDataStr = $this->request->domain().'/bind-servicer?coding='.$account['coding'];
|
||
$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]);
|
||
} catch (Exception $e) {
|
||
AccountRepository::log('客服二维码生成失败', $e);
|
||
return $this->json(5000, '客服二维码生成失败');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 客户列表
|
||
*
|
||
* @return Json
|
||
* @throws Exception
|
||
*/
|
||
public function customer(): Json
|
||
{
|
||
$accountId = $this->request->user['user_id'] ?? 0;
|
||
$type = input('type/s', 'all');
|
||
$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];
|
||
}
|
||
$field = ['id', 'nickname', 'real_name', 'headimgurl', 'mobile', 'channel', 'created_at', 'customer_service'];
|
||
$data = AccountRepository::getInstance()->customerList($where, $field, $accountId, $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 Json
|
||
* @throws Exception
|
||
*/
|
||
public function channel(): Json
|
||
{
|
||
return $this->json(0, 'success', Account::channelTextList());
|
||
}
|
||
|
||
/**
|
||
* 客户分配(分配给在线客服)
|
||
*
|
||
* @return Json
|
||
* @throws Exception
|
||
*/
|
||
public function customerAllot(): Json
|
||
{
|
||
if (!$this->request->isPost()) {
|
||
return $this->json(4000, '无效请求');
|
||
}
|
||
|
||
$accountId = $this->request->user['user_id'] ?? 0;
|
||
$params = input('post.');
|
||
|
||
$rules = [
|
||
'customer_id|客户' => 'require|number',
|
||
'staff_id|员工' => 'require|number',
|
||
];
|
||
|
||
$validate = $this->validateByApi($params, $rules);
|
||
|
||
if ($validate !== true) {
|
||
return $validate;
|
||
}
|
||
|
||
try {
|
||
if (!$staff = Staff::findOne(['account_id' => $accountId])) {
|
||
return $this->json(4001, '你不是员工');
|
||
}
|
||
|
||
$staffRules = explode(',', $staff['rules']);
|
||
|
||
if (!in_array('customer-allot', $staffRules)) {
|
||
return $this->json(4002, '无此权限');
|
||
}
|
||
|
||
CustomerReceive::allotService($params['customer_id'], $params['staff_id']);
|
||
} catch (RepositoryException $e) {
|
||
return $this->json(4001, $e->getMessage());
|
||
} catch (Exception $e) {
|
||
AccountRepository::log('分配客户失败', $e);
|
||
return $this->json(5001, '操作失败');
|
||
}
|
||
|
||
return $this->json();
|
||
}
|
||
|
||
/**
|
||
* 客服列表
|
||
*
|
||
* @return Json
|
||
* @throws DataNotFoundException
|
||
* @throws DbException
|
||
* @throws ModelNotFoundException
|
||
*/
|
||
public function servicerList(): Json
|
||
{
|
||
$roleName = 'customer-online';//在线客服的角色
|
||
$roleId = AccountRole::where('name', $roleName)->value('id');
|
||
$serviceList = Staff::whereRaw('FIND_IN_SET('.$roleId.', account_roles)')
|
||
->field('name,account_id as id')
|
||
->order('id', 'asc')
|
||
->select();
|
||
|
||
return $this->json(0, 'success', $serviceList);
|
||
}
|
||
|
||
/**
|
||
* 绑定手机
|
||
*
|
||
* @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, '用户不存在');
|
||
}
|
||
// 解密手机相关数据 若存在手机则覆盖
|
||
$minApp = WechatApplets::getInstance();
|
||
$sessionKey = $this->request->user['session_key'] ?? '';
|
||
$decryptData = $minApp->encryptor->decryptData($sessionKey, $params['iv'], $params['encryptedData']);
|
||
$phone = $decryptData['phoneNumber'] ?? ''; // 通过iv和加密数据 解密出手机号
|
||
|
||
if ($phone) {
|
||
$account->save(['mobile' => $phone, 'phone_active' => Account::COMMON_ON]);
|
||
}
|
||
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 DataNotFoundException
|
||
* @throws DbException
|
||
* @throws ModelNotFoundException
|
||
*/
|
||
public function coinLoad()
|
||
{
|
||
$accountId = $this->request->user['user_id'];
|
||
$account = Account::findById($accountId);
|
||
if (empty($account)) {
|
||
return $this->json(6001, '未登录');
|
||
}
|
||
|
||
Config::load('extra/coin_withdrawal', 'coin_withdrawal');
|
||
$coinWithdrawal = config('coin_withdrawal');
|
||
|
||
|
||
//审核中的提现金额
|
||
$withdrawalIng = AccountRepository::getInstance()->withdrawalIng($accountId);
|
||
//已经提现金额
|
||
$withdrawald = AccountRepository::getInstance()->withdrawald($accountId);
|
||
|
||
$key = $account['is_staff'] ? "withdrawal_proportion_staff" : "withdrawal_proportion_account";
|
||
return $this->json(0, "ok",
|
||
[
|
||
"coin" => $account["coin"],
|
||
"withdrawal_ing" => $withdrawalIng,
|
||
"withdrawald" => $withdrawald,
|
||
"withdrawal_proportion" => $coinWithdrawal[$key] ?? ["coin" => 0, "money" => 0],
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 提现和获取孔雀币记录列表
|
||
*
|
||
* @param $type string coin / withdrawal
|
||
* @return Json
|
||
*/
|
||
public function withdrawalAndGetCoinList()
|
||
{
|
||
$page = input('page/d', 1);
|
||
$limit = input('size/d', 10);
|
||
$type = input("type/s", "coin");
|
||
$accountId = $this->request->user['user_id'];
|
||
//如果是获取列表
|
||
if ($type == AccountDataLog::TYPE_COIN) {
|
||
$items = AccountDataLog::findList([
|
||
["account_id", "=", $accountId,],
|
||
["type", "=", AccountDataLog::TYPE_COIN],
|
||
["action", "not in", [AccountDataLog::ACTION_WITHDRAWAL, AccountDataLog::ACTION_WITHDRAWAL_RETURN]],
|
||
|
||
], [], $page, $limit,
|
||
null, ["id" => "desc"]);
|
||
} else {
|
||
$items = AccountDataLog::findList([
|
||
["account_id", "=", $accountId,],
|
||
["type", "=", AccountDataLog::TYPE_COIN],
|
||
["action", "in", [AccountDataLog::ACTION_WITHDRAWAL, AccountDataLog::ACTION_WITHDRAWAL_RETURN]],
|
||
|
||
], [], $page, $limit,
|
||
null, ["id" => "desc"]);
|
||
}
|
||
|
||
return $this->json(0, '操作成功', $items);
|
||
}
|
||
|
||
/**
|
||
* 孔雀币收支记录
|
||
*
|
||
* @return Json
|
||
* @throws Exception
|
||
*/
|
||
public function coinLog(): 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_COIN];
|
||
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 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 DataNotFoundException
|
||
* @throws DbException
|
||
* @throws ModelNotFoundException
|
||
*/
|
||
public function scoreLoad(): Json
|
||
{
|
||
$accountId = $this->request->user['user_id'];
|
||
$account = Account::findById($accountId);
|
||
if (empty($account)) {
|
||
return $this->json(6001, '未登录');
|
||
}
|
||
|
||
return $this->json(0, "ok",
|
||
[
|
||
"score" => $account["score"],
|
||
"share" => AccountRepository::getInstance()->shareAccountCount($accountId),
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 发起提现孔雀币
|
||
*
|
||
* @param $type string coin / withdrawal
|
||
* @return Json
|
||
*/
|
||
public function withdrawalCoin()
|
||
{
|
||
$coin = input("coin/d", 0);
|
||
$accountId = $this->request->user['user_id'];
|
||
$account = Account::findOne(["id" => $accountId], [], function ($q) {
|
||
return $q->lock(true);
|
||
});
|
||
if (empty($account)) {
|
||
return $this->json(6001, '未登录');
|
||
}
|
||
if ($coin <= 0) {
|
||
return $this->json(4000, '提现孔雀币不能小于0');
|
||
}
|
||
|
||
//换算出 1元 = 多少孔雀币
|
||
|
||
|
||
try {
|
||
//本次提现共计金额
|
||
$totalMoney = AccountRepository::getInstance()->transformationCoinOrMoney($coin, "money", $account['is_staff']);
|
||
$totalMoney = $totalMoney / 100;//分转元
|
||
if ($account['coin'] < $coin) {
|
||
return $this->json(4004, '孔雀币不足');
|
||
}
|
||
|
||
$key = ($account['is_staff'] ? AccountDataLog::withdrawal_proportion_staff : AccountDataLog::withdrawal_proportion_account);
|
||
$coinWithdrawal = config('coin_withdrawal');
|
||
$withdrawalProportion = $coinWithdrawal[$key];
|
||
} catch (Exception $e) {
|
||
return $this->json(5004, '提现失败');
|
||
} catch (RepositoryException $e) {
|
||
return $this->json(5005, $e->getMessage());
|
||
}
|
||
|
||
//条件满足 开始写入提现
|
||
Db::startTrans();
|
||
try {
|
||
//写入--积分孔雀币日志
|
||
AccountDataLog::log($account['id'],
|
||
"提现-扣除孔雀币",
|
||
$coin * -1,
|
||
AccountDataLog::TYPE_COIN,
|
||
AccountDataLog::ACTION_WITHDRAWAL,
|
||
$account[AccountDataLog::TYPE_COIN] - $coin
|
||
);
|
||
|
||
//写入提现记录
|
||
$accountCoinWithdrawalData = [
|
||
"account_id" => $account['id'],
|
||
"coin_number" => $coin,
|
||
"role" => ($account["is_staff"] == 0) ? AccountCoinWithdrawal::$role_account : AccountCoinWithdrawal::$role_staff,
|
||
"money" => $totalMoney,
|
||
"proportion" => $withdrawalProportion["coin"].":".$withdrawalProportion["money"],
|
||
"status" => AccountCoinWithdrawal::$status_default,
|
||
"created_at" => date("Y-m-d H:i:s"),
|
||
];
|
||
AccountCoinWithdrawal::create($accountCoinWithdrawalData);
|
||
|
||
//扣除孔雀币
|
||
$account->save(["coin" => ($account["coin"] - $coin)]);
|
||
Db::commit();
|
||
return $this->json();
|
||
|
||
} catch (Exception $e) {
|
||
Db::rollback();
|
||
return $this->json(5000, "提现失败-2");
|
||
} catch (RepositoryException $e) {
|
||
Db::rollback();
|
||
return $this->json(5000, "提现失败-3");
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取孔雀币抵扣金额
|
||
*
|
||
* @return Json
|
||
* @throws Exception
|
||
*/
|
||
public function getCoinPrice(): Json
|
||
{
|
||
$accountId = $this->request->user['user_id'] ?? 0;
|
||
$amount = input('amount/f', 0);
|
||
$type = input('get_type/s', 'money');//获取类型 money=根据孔雀币获取金额 coin=根据金额获取孔雀币
|
||
|
||
try {
|
||
if (!$account = AccountRepository::getInstance()->findById($accountId)) {
|
||
return $this->json(4001, '用户不存在');
|
||
}
|
||
if ($type == 'money') {
|
||
$amount = AccountRepository::getInstance()
|
||
->transformationCoinOrMoney($amount, 'money', $account['is_staff'] == 1);
|
||
} else {
|
||
$amount = AccountRepository::getInstance()
|
||
->transformationCoinOrMoney($amount, 'coin', $account['is_staff'] == 1);
|
||
}
|
||
return $this->json(0, 'success', ['amount' => $amount]);
|
||
} 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 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');
|
||
|
||
$res = OrderRepository::getInstance()->mine($userId, $tag, $page, $size);
|
||
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;
|
||
|
||
$res = OrderRepository::getInstance()->detail($id);
|
||
if (!$res) {
|
||
return $this->json(4000, '订单不存在');
|
||
}
|
||
|
||
if ($res['account_id'] !== $userId) {
|
||
return $this->json(4000, '不是您的订单');
|
||
}
|
||
|
||
return $this->json(0, 'success', $res);
|
||
}
|
||
|
||
|
||
/**
|
||
* 我的海报列表
|
||
*
|
||
* @return Json
|
||
*/
|
||
public function poster(): Json
|
||
{
|
||
$page = input('page/d', 1);
|
||
$size = input('size/d', 10);
|
||
$userId = $this->request->user['user_id'] ?? 0;
|
||
|
||
try {
|
||
$list = AccountRepository::getInstance()->poster($userId, $page, $size);
|
||
return $this->json(0, 'success', $list);
|
||
} catch (RepositoryException $e) {
|
||
return $this->json(4000, $e->getMessage());
|
||
} catch (Exception $e) {
|
||
AccountRepository::log('获取个人海报列表失败', $e);
|
||
return $this->json(5001, '海报列表获取失败');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 生成用户指定海报
|
||
*/
|
||
public function posterInfo(): Json
|
||
{
|
||
$accountId = $this->request->user['user_id'] ?? 0;
|
||
$src = $this->request->param('poster_src/s', '');
|
||
$domain = $this->request->domain();
|
||
try {
|
||
$posterData = AccountRepository::getInstance()->posterInfo($accountId, $src, $domain);
|
||
|
||
return $this->json(0, 'success', ['poster' => $posterData]);
|
||
} catch (RepositoryException $e) {
|
||
return $this->json(4000, $e->getMessage());
|
||
} catch (Exception $e) {
|
||
AccountRepository::log('个人海报生成失败', $e);
|
||
return $this->json(5000, '个人海报生成失败');
|
||
}
|
||
}
|
||
|
||
} |