first
This commit is contained in:
175
modules/User/Models/Account.php
Normal file
175
modules/User/Models/Account.php
Normal file
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Models\Model;
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Modules\User\Traits\BelongsToUser;
|
||||
|
||||
class Account extends Model
|
||||
{
|
||||
|
||||
use BelongsToUser;
|
||||
|
||||
protected $table = 'user_accounts';
|
||||
|
||||
protected $primaryKey = 'user_id';
|
||||
|
||||
const TYPES = [
|
||||
'balance' => '现金余额',
|
||||
'score' => '水滴',
|
||||
'coins' => '未使用',
|
||||
'other' => '其他',
|
||||
];
|
||||
|
||||
/**
|
||||
* Notes : 账户日志
|
||||
*
|
||||
* @Date : 2021/4/27 11:22 上午
|
||||
* @Author : < Jason.C >
|
||||
* @return HasMany
|
||||
*/
|
||||
public function logs(): HasMany
|
||||
{
|
||||
return $this->hasMany(AccountLog::class, 'account_id', 'user_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 执行账户规则
|
||||
*
|
||||
* @Author: <C.Jason>
|
||||
* @Date : 2019/11/28 1:24 下午
|
||||
* @param $rule string|int
|
||||
* @param float $variable
|
||||
* @param bool $frozen
|
||||
* @param array $source
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function rule($rule, float $variable = 0, bool $frozen = true, array $source = []): bool
|
||||
{
|
||||
if (is_numeric($rule)) {
|
||||
$rule = AccountRule::findOrFail($rule);
|
||||
} else {
|
||||
$rule = AccountRule::where('name', $rule)->firstOrFail();
|
||||
}
|
||||
|
||||
if ($rule->trigger == 0) {
|
||||
// 不限制执行的
|
||||
return $this->accountExecute($rule, $variable, $frozen, $source);
|
||||
} elseif ($rule->trigger > $this->logs()
|
||||
->where('rule_id', $rule->id)
|
||||
->whereDate('created_at', Carbon::today())
|
||||
->count()) {
|
||||
// 每日执行 trigger 次
|
||||
return $this->accountExecute($rule, $variable, $frozen, $source);
|
||||
} elseif ($rule->trigger < 0 && ! $this->logs()->where('rule_id', $rule->id)->first()) {
|
||||
// 终身只能执行一次
|
||||
return $this->accountExecute($rule, $variable, $frozen, $source);
|
||||
}
|
||||
|
||||
throw new Exception('达到最大可执行次数');
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 增加账户余额
|
||||
*
|
||||
* @Author: <C.Jason>
|
||||
* @Date : 2019/11/28 1:25 下午
|
||||
* @param $type
|
||||
* @param $variable
|
||||
* @return bool
|
||||
*/
|
||||
public function increase($type, $variable): bool
|
||||
{
|
||||
DB::transaction(function () use ($type, $variable) {
|
||||
$this->increment($type, $variable);
|
||||
$log = [
|
||||
'rule_id' => 0,
|
||||
'type' => $type,
|
||||
'variable' => $variable,
|
||||
'frozen' => 0,
|
||||
'balance' => $this->{$type},
|
||||
'source' => ['type' => 'increase'],
|
||||
];
|
||||
$this->logs()->create($log);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 扣除账户金额
|
||||
*
|
||||
* @Author: <C.Jason>
|
||||
* @Date : 2019/11/28 1:25 下午
|
||||
* @param $type
|
||||
* @param $variable
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function decrease($type, $variable): bool
|
||||
{
|
||||
|
||||
DB::transaction(function () use ($type, $variable) {
|
||||
$this->decrement($type, $variable);
|
||||
$log = [
|
||||
'rule_id' => 0,
|
||||
'type' => $type,
|
||||
'variable' => -$variable,
|
||||
'frozen' => 0,
|
||||
'balance' => $this->{$type},
|
||||
'source' => ['type' => 'deduct'],
|
||||
];
|
||||
$this->logs()->create($log);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 执行账户规则
|
||||
*
|
||||
* @Author: <C.Jason>
|
||||
* @Date : 2019/11/28 1:41 下午
|
||||
* @param AccountRule $rule
|
||||
* @param $variable
|
||||
* @param $frozen
|
||||
* @param $source
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function accountExecute(AccountRule $rule, $variable, $frozen, $source): bool
|
||||
{
|
||||
if ($variable != 0) {
|
||||
$rule->variable = $variable;
|
||||
}
|
||||
|
||||
DB::transaction(function () use ($rule, $frozen, $source) {
|
||||
// 如果是扣款,立即执行,如果非冻结,也立即执行
|
||||
if ($rule->variable < 0 || $rule->deductions == 1 || $frozen === false) {
|
||||
$this->increment($rule->type, $rule->variable);
|
||||
$frozen = false;
|
||||
}
|
||||
$log = [
|
||||
'rule_id' => $rule->id,
|
||||
'type' => $rule->type,
|
||||
'amount' => $rule->variable,
|
||||
'frozen' => $frozen,
|
||||
'balance' => $this->{$rule->type},
|
||||
'source' => $source ?: [],
|
||||
'remark' => $source['remark'] ?? $rule->remark,
|
||||
'settle_at' => $source['settle_at'] ?? null,
|
||||
'frozen_at' => $source['frozen_at'] ?? null,
|
||||
];
|
||||
// 写入记录
|
||||
$this->logs()->create($log);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
91
modules/User/Models/AccountLog.php
Normal file
91
modules/User/Models/AccountLog.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Models\Model;
|
||||
use App\Traits\OrderByIdDesc;
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class AccountLog extends Model
|
||||
{
|
||||
|
||||
use OrderByIdDesc;
|
||||
|
||||
protected $table = 'user_account_logs';
|
||||
|
||||
protected $dates = [
|
||||
'settle_at',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'source' => 'json',
|
||||
];
|
||||
|
||||
/**
|
||||
* Notes : 账户
|
||||
*
|
||||
* @Date : 2021/4/27 11:22 上午
|
||||
* @Author : < Jason.C >
|
||||
* @return BelongsTo
|
||||
*/
|
||||
public function account(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Account::class, 'account_id');
|
||||
}
|
||||
|
||||
public function rule(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(AccountRule::class, 'rule_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 冻结一条账户记录
|
||||
*
|
||||
* @Author: <C.Jason>
|
||||
* @Date : 2019/12/1 10:48 上午
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function freeze(): bool
|
||||
{
|
||||
if ($this->frozen == 0) {
|
||||
$this->account->decrement($this->type, $this->amount);
|
||||
$this->frozen = 1;
|
||||
$this->balance = $this->account->{$this->type};
|
||||
$this->save();
|
||||
|
||||
return true;
|
||||
} else {
|
||||
throw new Exception('账目已冻结');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 解冻一条记录
|
||||
*
|
||||
* @Author: <C.Jason>
|
||||
* @Date : 2019/12/1 10:48 上午
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function thaw(): bool
|
||||
{
|
||||
if ($this->frozen == 1) {
|
||||
$this->account->increment($this->type, $this->amount);
|
||||
$this->frozen = 0;
|
||||
$this->balance = $this->account->{$this->type};
|
||||
$this->save();
|
||||
|
||||
return true;
|
||||
} else {
|
||||
throw new Exception('已经领取');
|
||||
}
|
||||
}
|
||||
|
||||
public function getAmountFormatAttribute(): string
|
||||
{
|
||||
return ($this->amount > 0 ? '+' : '').$this->amount;
|
||||
}
|
||||
|
||||
}
|
||||
43
modules/User/Models/AccountRule.php
Normal file
43
modules/User/Models/AccountRule.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Models\Model;
|
||||
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class AccountRule extends Model
|
||||
{
|
||||
|
||||
use Cachable,
|
||||
SoftDeletes;
|
||||
|
||||
protected $table = 'user_account_rules';
|
||||
|
||||
public function logs(): HasMany
|
||||
{
|
||||
return $this->hasMany(AccountLog::class, 'rule_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 获取可执行次数的文本显示
|
||||
* @Date : 2021/5/21 2:37 下午
|
||||
* @Author : < Jason.C >
|
||||
* @return string
|
||||
*/
|
||||
protected function getTriggerTextAttribute(): string
|
||||
{
|
||||
switch ($this->trigger <=> 0) {
|
||||
case -1:
|
||||
return '仅一次';
|
||||
case 0:
|
||||
return '不限制';
|
||||
case 1:
|
||||
return $this->trigger . ' 次/日';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
271
modules/User/Models/Identity.php
Normal file
271
modules/User/Models/Identity.php
Normal file
@@ -0,0 +1,271 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Models\Model;
|
||||
use App\Traits\HasCovers;
|
||||
use App\Traits\OrderByOrderAsc;
|
||||
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Identity extends Model
|
||||
{
|
||||
|
||||
// use Cachable;
|
||||
use HasCovers,
|
||||
HasIdentityScopes,
|
||||
OrderByOrderAsc,
|
||||
SoftDeletes;
|
||||
|
||||
public $dates = [
|
||||
'end_at'
|
||||
];
|
||||
|
||||
const Conditions = [
|
||||
'cost' => '原价',
|
||||
'price' => '开通金额',
|
||||
];
|
||||
|
||||
const Rules = [
|
||||
'give_crystal' => '开通赠水滴',
|
||||
'recommend_rate' => '推荐比例',
|
||||
];
|
||||
|
||||
const CHANNEL_ONLINE = 1;
|
||||
const CHANNEL_OFFLINE = 2;
|
||||
|
||||
const CHANNELS = [
|
||||
self::CHANNEL_ONLINE => '线上',
|
||||
self::CHANNEL_OFFLINE => '线下'
|
||||
];
|
||||
|
||||
const EXPERIENCE_YES = 1;
|
||||
const EXPERIENCE_NO = 0;
|
||||
|
||||
const EXPERIENCES = [
|
||||
self::EXPERIENCE_YES => '是',
|
||||
self::EXPERIENCE_NO => '否'
|
||||
];
|
||||
|
||||
const JOB_YK = 0;
|
||||
const JOB_TY = 1;
|
||||
const JOB_JK = 2;
|
||||
const JOB_NK = 3;
|
||||
const JOB_CS = 4;
|
||||
const JOB_HH = 5;
|
||||
|
||||
const JOBS = [
|
||||
self::JOB_YK => '游客',
|
||||
self::JOB_TY => '体验官',
|
||||
self::JOB_JK => '季卡',
|
||||
self::JOB_NK => '年卡',
|
||||
self::JOB_CS => '创始',
|
||||
self::JOB_HH => '合伙人',
|
||||
];
|
||||
|
||||
protected $table = 'user_identities';
|
||||
|
||||
protected $casts = [
|
||||
'conditions' => 'json',
|
||||
'rules' => 'json',
|
||||
'rights' => 'json',
|
||||
'ruleshows' => 'json',
|
||||
];
|
||||
|
||||
public function setConditionsAttribute($value)
|
||||
{
|
||||
$this->attributes['conditions'] = json_encode(array_values($value));
|
||||
}
|
||||
|
||||
public function setRulesAttribute($value)
|
||||
{
|
||||
$rules = collect($this->rules);
|
||||
|
||||
foreach ($value as &$item) {
|
||||
$info = $rules->where('name', $item['name'])->first();
|
||||
if (! isset($item['icon']) && $info && isset($info['icon'])) {
|
||||
$item['icon'] = $info['icon'];
|
||||
}
|
||||
}
|
||||
$this->attributes['rules'] = json_encode(array_values($value));
|
||||
}
|
||||
|
||||
public function setRuleshowsAttribute($value)
|
||||
{
|
||||
$rules = collect($this->ruleshows);
|
||||
|
||||
foreach ($value as &$item) {
|
||||
$info = $rules->where('name', $item['name'])->first();
|
||||
if (! isset($item['icon']) && $info && isset($info['icon'])) {
|
||||
$item['icon'] = $info['icon'];
|
||||
}
|
||||
}
|
||||
$this->attributes['ruleshows'] = json_encode(array_values($value));
|
||||
}
|
||||
|
||||
public function setRightsAttribute($value)
|
||||
{
|
||||
$rights = collect($this->rights);
|
||||
|
||||
foreach ($value as &$item) {
|
||||
$info = $rights->where('name', $item['name'])->first();
|
||||
if (! isset($item['cover']) && $info && isset($info['cover'])) {
|
||||
$item['cover'] = $info['cover'];
|
||||
}
|
||||
}
|
||||
|
||||
$this->attributes['rights'] = json_encode(array_values($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 获取所有规则
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/21 13:03
|
||||
*/
|
||||
public function getRules()
|
||||
{
|
||||
$rules = $this->ruleshows;
|
||||
foreach ($rules as $key => $rule) {
|
||||
if (isset($rule['icon'])) {
|
||||
$rules[$key]['cover'] = $this->parseImageUrl($rule['icon']);
|
||||
}
|
||||
$rules[$key]['text'] = Arr::get(config('identity.show_rules'), $rule['name']);
|
||||
}
|
||||
return $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 获取未开通身份时反馈的数据
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/26 14:16
|
||||
* @return array|mixed
|
||||
*/
|
||||
public function getNotRules()
|
||||
{
|
||||
$rules = $this->rules;
|
||||
if ($this->job == Identity::JOB_JK) {
|
||||
return [
|
||||
'give_crystal' => [
|
||||
'cover' => $this->getRuleIcon('give_crystal'),
|
||||
'value' => $this->getRule('give_crystal'),
|
||||
'text' => '赠送水滴'
|
||||
],
|
||||
'recommend_coupon' => [
|
||||
'cover' => $this->getRuleIcon('recommend_coupon'),
|
||||
'value' => $this->getRule('recommend_coupon'),
|
||||
'text' => '赠送抵值券'
|
||||
],
|
||||
'stock' => [
|
||||
'value' => $this->stock,
|
||||
'text' => "赠送{$this->stock}箱水"
|
||||
],
|
||||
'year' => [
|
||||
'value' => $this->years,
|
||||
'text' => $this->years."个月有效期"
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
if ($this->job == Identity::JOB_NK) {
|
||||
return [
|
||||
'stock' => [
|
||||
'value' => $this->stock,
|
||||
'text' => "赠送{$this->stock}箱水"
|
||||
],
|
||||
'year' => [
|
||||
'value' => $this->years,
|
||||
'text' => $this->years."个月有效期"
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notes : 组内用户
|
||||
*
|
||||
* @Date : 2021/5/6 12:06 下午
|
||||
* @Author : < Jason.C >
|
||||
* @return BelongsToMany
|
||||
*/
|
||||
public function users(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(User::class, 'user_identity')
|
||||
->withTimestamps();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 不同的客服匹配不同的身份
|
||||
*
|
||||
* @Date : 2021/6/07 10:50
|
||||
* @Author : Mr.wang
|
||||
* @return BelongsToMany
|
||||
*/
|
||||
public function identities(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Service::class, 'user_service_identity')
|
||||
->withTimestamps();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回身份中的某一个规则
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @return mixed|string
|
||||
*/
|
||||
public function getRule(string $key = '', $default = '')
|
||||
{
|
||||
$values = collect($this->rules);
|
||||
$value = $values->where('name', $key)->first();
|
||||
if ($value) {
|
||||
return $value['value'];
|
||||
} else {
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 获取规则图标
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/26 14:24
|
||||
* @param string $key
|
||||
* @param $default
|
||||
* @return mixed|string
|
||||
*/
|
||||
public function getRuleIcon(string $key = '', $default = '')
|
||||
{
|
||||
$values = collect($this->rules);
|
||||
$value = $values->where('name', $key)->first();
|
||||
if ($value && isset($value['icon'])) {
|
||||
return $this->parseImageUrl($value['icon']);
|
||||
} else {
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回条件中的某一个字段
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @return mixed|string
|
||||
*/
|
||||
public function getCondition(string $key = '', $default = '')
|
||||
{
|
||||
$values = collect($this->conditions);
|
||||
$value = $values->where('name', $key)->first();
|
||||
if ($value) {
|
||||
return $value['value'];
|
||||
} else {
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
46
modules/User/Models/IdentityLog.php
Normal file
46
modules/User/Models/IdentityLog.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Models\Model;
|
||||
use App\Traits\OrderByIdDesc;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Modules\User\Traits\BelongsToUser;
|
||||
|
||||
class IdentityLog extends Model
|
||||
{
|
||||
|
||||
use BelongsToUser, OrderByIdDesc;
|
||||
|
||||
protected $table = 'user_identity_logs';
|
||||
|
||||
protected $casts = [
|
||||
'source' => 'json',
|
||||
];
|
||||
|
||||
const CHANNEL_AUTO = 'Auto';
|
||||
const CHANNEL_REG = 'Reg';
|
||||
|
||||
const CHANNEL_SYSTEM = 'System';
|
||||
|
||||
const CHANNEL_MAP = [
|
||||
self::CHANNEL_AUTO => '自动变更',
|
||||
self::CHANNEL_REG => '注册默认',
|
||||
self::CHANNEL_SYSTEM => '后台变更',
|
||||
];
|
||||
|
||||
public function before_identity(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Identity::class, 'before')->withDefault([
|
||||
'name' => '已删除',
|
||||
]);
|
||||
}
|
||||
|
||||
public function after_identity(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Identity::class, 'after')->withDefault([
|
||||
'name' => '已删除',
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
36
modules/User/Models/IdentityMiddle.php
Normal file
36
modules/User/Models/IdentityMiddle.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\Pivot;
|
||||
use Modules\User\Traits\BelongsToUser;
|
||||
|
||||
class IdentityMiddle extends Pivot
|
||||
{
|
||||
|
||||
use BelongsToUser, MorphManyTimeline;
|
||||
|
||||
protected $table = 'user_identity';
|
||||
protected $primaryKey = 'user_id';
|
||||
public $dates = [
|
||||
'started_at', 'ended_at'
|
||||
];
|
||||
|
||||
static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
self::created(function ($identity) {
|
||||
if ($identity->identity->order > 1) {
|
||||
$identity->addTimeline();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function identity(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Identity::class, 'identity_id');
|
||||
}
|
||||
|
||||
}
|
||||
96
modules/User/Models/Order.php
Normal file
96
modules/User/Models/Order.php
Normal file
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Models\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Modules\Payment\Traits\WithPayments;
|
||||
use Modules\User\Models\Traits\OrderActions;
|
||||
use Modules\User\Traits\BelongsToUser;
|
||||
|
||||
class Order extends Model
|
||||
{
|
||||
|
||||
use WithPayments,
|
||||
OrderActions,
|
||||
BelongsToUser;
|
||||
|
||||
protected $table = 'user_orders';
|
||||
|
||||
const STATE_INIT = 'INIT';
|
||||
const STATE_SUCCESS = 'SUCCESS';
|
||||
const STATE_REFUND = 'refund';
|
||||
|
||||
const STATES = [
|
||||
self::STATE_INIT => '待审核',
|
||||
self::STATE_SUCCESS => '已支付',
|
||||
self::STATE_REFUND => '已退款',
|
||||
];
|
||||
|
||||
const TYPE_OPEN = 1;
|
||||
const TYPE_RENEW = 2;
|
||||
|
||||
const TYPES = [
|
||||
self::TYPE_OPEN => '开通',
|
||||
self::TYPE_RENEW => '续费',
|
||||
];
|
||||
|
||||
const CHANNEL_IDENTITY = 1;
|
||||
const CHANNEL_EXPERIENCE = 2;
|
||||
const CHANNEL_PARTNER = 3;
|
||||
|
||||
const CHANNELS = [
|
||||
self::CHANNEL_IDENTITY => '开通身份',
|
||||
self::CHANNEL_EXPERIENCE => '开通体验官',
|
||||
self::CHANNEL_PARTNER => '开通合伙人',
|
||||
];
|
||||
|
||||
public $casts = [
|
||||
'source' => 'json'
|
||||
];
|
||||
|
||||
public function identity(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Identity::class, 'identity_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 设置订单支付
|
||||
* @Author: 玄尘
|
||||
* @Date : 2020/11/12 11:19
|
||||
*/
|
||||
public function pay()
|
||||
{
|
||||
$this->state = self::STATE_SUCCESS;
|
||||
$this->save();
|
||||
|
||||
event(new UserOrderPaid($this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 是否可以支付
|
||||
* @Author: 玄尘
|
||||
* @Date : 2021/6/4 10:19
|
||||
* @return bool
|
||||
*/
|
||||
public function canPay(): bool
|
||||
{
|
||||
return $this->state == self::STATE_INIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 是否可以退款
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/22 13:18
|
||||
* @return bool
|
||||
*/
|
||||
public function canRefund(): bool
|
||||
{
|
||||
return $this->isPay();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
75
modules/User/Models/Relation.php
Normal file
75
modules/User/Models/Relation.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Models\Model;
|
||||
use Encore\Admin\Traits\ModelTree;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
|
||||
use Modules\User\Traits\BelongsToUser;
|
||||
|
||||
class Relation extends Model
|
||||
{
|
||||
|
||||
use BelongsToUser,
|
||||
ModelTree;
|
||||
|
||||
protected $table = 'user_relations';
|
||||
|
||||
protected $primaryKey = 'user_id';
|
||||
|
||||
public function __construct(array $attributes = [])
|
||||
{
|
||||
parent::__construct($attributes);
|
||||
|
||||
$this->setParentColumn('parent_id');
|
||||
$this->setOrderColumn('created_at');
|
||||
$this->setTitleColumn('user_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 上级用户
|
||||
*
|
||||
* @return BelongsTo
|
||||
*/
|
||||
public function parent(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'parent_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 关联中间表
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/19 13:16
|
||||
*/
|
||||
public function identities(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(
|
||||
Identity::class,
|
||||
'user_identity',
|
||||
'user_id',
|
||||
'identity_id',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 所有下级用户
|
||||
*
|
||||
* @return HasManyThrough
|
||||
*/
|
||||
public function children(): HasManyThrough
|
||||
{
|
||||
return $this->hasManyThrough(
|
||||
User::class,
|
||||
Relation::class,
|
||||
'parent_id',
|
||||
'id',
|
||||
'user_id',
|
||||
'user_id'
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
34
modules/User/Models/Service.php
Normal file
34
modules/User/Models/Service.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Models\Model;
|
||||
use App\Traits\HasCovers;
|
||||
use App\Traits\HasStatus;
|
||||
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Service extends Model
|
||||
{
|
||||
|
||||
use Cachable,
|
||||
HasStatus,
|
||||
SoftDeletes,
|
||||
HasCovers;
|
||||
|
||||
protected $table = 'user_services';
|
||||
|
||||
/**
|
||||
* Notes : 不同的客服匹配不同的身份
|
||||
* @Date : 2021/6/07 10:40
|
||||
* @Author : Mr.wang
|
||||
* @return BelongsToMany
|
||||
*/
|
||||
public function identities(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Identity::class, 'user_service_identity')
|
||||
->withTimestamps();
|
||||
}
|
||||
|
||||
}
|
||||
61
modules/User/Models/Sign.php
Normal file
61
modules/User/Models/Sign.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Models\Model;
|
||||
use Modules\User\Traits\BelongsToUser;
|
||||
|
||||
class Sign extends Model
|
||||
{
|
||||
|
||||
use BelongsToUser;
|
||||
|
||||
protected $table = 'user_signs';
|
||||
|
||||
protected $dates = [
|
||||
'last_sign_at',
|
||||
'reset_at',
|
||||
];
|
||||
|
||||
const FINISH_INIT = 0;
|
||||
const FINISH_SIGN = 1;
|
||||
const FINISH_LOG = 2;
|
||||
const FINISHS = [
|
||||
self::FINISH_INIT => '进行中',
|
||||
self::FINISH_SIGN => '打卡完成',
|
||||
self::FINISH_LOG => '报告完成',
|
||||
];
|
||||
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
self::saved(function ($sign) {
|
||||
$params = SignConfig::getParams();
|
||||
|
||||
if ($params['open'] == 1 && $sign->need_case == 0 && $sign->continue_days >= $params['cycle_day']) {
|
||||
$sign->update(['need_case' => 1, 'is_finish' => 1]);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 获取最新连续签到数
|
||||
*
|
||||
* @Date : 2021/5/28 12:00
|
||||
* @Author : Mr.wang
|
||||
* @return int|mixed
|
||||
*/
|
||||
public function getContinueDays()
|
||||
{
|
||||
if ($this->last_sign_at->diffInDays() > 1) {
|
||||
$continue = 1;
|
||||
} else {
|
||||
$continue = $this->continue_days + 1;
|
||||
}
|
||||
|
||||
return $continue;
|
||||
}
|
||||
|
||||
}
|
||||
16
modules/User/Models/SignBanner.php
Normal file
16
modules/User/Models/SignBanner.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Models\Model;
|
||||
use App\Traits\HasCovers;
|
||||
use App\Traits\HasStatus;
|
||||
|
||||
class SignBanner extends Model
|
||||
{
|
||||
use HasStatus,
|
||||
HasCovers;
|
||||
|
||||
protected $table = 'user_sign_banners';
|
||||
|
||||
}
|
||||
55
modules/User/Models/SignConfig.php
Normal file
55
modules/User/Models/SignConfig.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Models\Model;
|
||||
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
|
||||
|
||||
class SignConfig extends Model
|
||||
{
|
||||
|
||||
use Cachable;
|
||||
|
||||
const TYPE_SINGLE = 'single';
|
||||
const TYPE_CONTINUOUS = 'continuous';
|
||||
const TYPE_CYCLE = 'cycle';
|
||||
const TYPES = [
|
||||
self::TYPE_SINGLE => '单日',
|
||||
self::TYPE_CONTINUOUS => '连续',
|
||||
self::TYPE_CYCLE => '周期连续',
|
||||
];
|
||||
const SHOWTYPES_DAY = 'day';
|
||||
const SHOWTYPES_WEEK = 'week';
|
||||
const SHOWTYPES_MONTH = 'month';
|
||||
const SHOWTYPES = [
|
||||
self::SHOWTYPES_DAY => '7天展示',
|
||||
self::SHOWTYPES_WEEK => '一周展示',
|
||||
self::SHOWTYPES_MONTH => '一月展示',
|
||||
];
|
||||
protected $table = 'user_sign_configs';
|
||||
protected $casts = [
|
||||
'params' => 'json',
|
||||
'tasks' => 'json',
|
||||
];
|
||||
|
||||
public static function getParams($key = '')
|
||||
{
|
||||
$model = SignConfig::find(1);
|
||||
if (! $key) {
|
||||
return collect($model->params);
|
||||
} else {
|
||||
return $model->params[$key] ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
public static function getTasks($key = '')
|
||||
{
|
||||
$model = SignConfig::find(1);
|
||||
if (! $key) {
|
||||
return collect($model->tasks);
|
||||
} else {
|
||||
return $model->tasks[$key] ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
30
modules/User/Models/SignLog.php
Normal file
30
modules/User/Models/SignLog.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Models\Model;
|
||||
use Modules\User\Traits\BelongsToUser;
|
||||
|
||||
class SignLog extends Model
|
||||
{
|
||||
|
||||
use BelongsToUser;
|
||||
|
||||
const UPDATED_AT = null;
|
||||
|
||||
protected $table = 'user_sign_logs';
|
||||
|
||||
protected $casts = [
|
||||
'date' => 'date',
|
||||
];
|
||||
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
self::created(function ($model) {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
13
modules/User/Models/SignText.php
Normal file
13
modules/User/Models/SignText.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Models\Model;
|
||||
use App\Traits\HasStatus;
|
||||
|
||||
class SignText extends Model
|
||||
{
|
||||
use HasStatus;
|
||||
|
||||
protected $table = 'user_sign_texts';
|
||||
}
|
||||
15
modules/User/Models/Sms.php
Normal file
15
modules/User/Models/Sms.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Models\Model;
|
||||
use App\Traits\OrderByIdDesc;
|
||||
|
||||
class Sms extends Model
|
||||
{
|
||||
|
||||
use OrderByIdDesc;
|
||||
|
||||
protected $table = 'user_sms';
|
||||
|
||||
}
|
||||
43
modules/User/Models/SmsConfig.php
Normal file
43
modules/User/Models/SmsConfig.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Models\Model;
|
||||
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
|
||||
|
||||
class SmsConfig extends Model
|
||||
{
|
||||
|
||||
use Cachable;
|
||||
|
||||
protected $table = 'user_sms_configs';
|
||||
|
||||
protected $casts = [
|
||||
'template' => 'json',
|
||||
];
|
||||
|
||||
public static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
self::saved(function ($model) {
|
||||
if ($model->in_use && $model->id) {
|
||||
self::where('id', '<>', $model->id)
|
||||
->where('in_use', 1)
|
||||
->update(['in_use' => 0]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 默认网关配置
|
||||
* @Date : 2021/5/27 5:18 下午
|
||||
* @Author : < Jason.C >
|
||||
* @return array
|
||||
*/
|
||||
public function getGateway(): array
|
||||
{
|
||||
return SmsGateway::where('slug', $this->default_gateway)->value('configs');
|
||||
}
|
||||
|
||||
}
|
||||
19
modules/User/Models/SmsGateway.php
Normal file
19
modules/User/Models/SmsGateway.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Models\Model;
|
||||
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
|
||||
|
||||
class SmsGateway extends Model
|
||||
{
|
||||
|
||||
use Cachable;
|
||||
|
||||
protected $table = 'user_sms_gateways';
|
||||
|
||||
protected $casts = [
|
||||
'configs' => 'json',
|
||||
];
|
||||
|
||||
}
|
||||
283
modules/User/Models/Traits/CertificationTrait.php
Normal file
283
modules/User/Models/Traits/CertificationTrait.php
Normal file
@@ -0,0 +1,283 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models\Traits;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
trait CertificationTrait
|
||||
{
|
||||
protected $params = [];
|
||||
|
||||
protected $header = [];
|
||||
|
||||
protected $errorMessage = '';
|
||||
|
||||
/**
|
||||
* Notes : 自动认证操作
|
||||
*
|
||||
* @Author: Mr.wang
|
||||
* @Date : 2021/12/7 13:53
|
||||
* @param $keys
|
||||
* @return array|int[]
|
||||
*/
|
||||
public function autoVerified($keys): array
|
||||
{
|
||||
if (config('userCertification.is_open')) {
|
||||
if (config('userCertification.is_ocr_open')) {
|
||||
$verified = $this->ocrVerified(Storage::url($keys['front_card']), 'front');
|
||||
if (! $verified) {
|
||||
return [
|
||||
'code' => 0,
|
||||
'message' => $this->getErrorMessage(),
|
||||
];
|
||||
} else {
|
||||
if ($verified['words_result']['姓名']['words'] != $keys['name']) {
|
||||
return [
|
||||
'code' => 0,
|
||||
'message' => '正面图片与填写信息不符',
|
||||
];
|
||||
}
|
||||
if ($verified['words_result']['公民身份号码']['words'] != $keys['idcard']) {
|
||||
return [
|
||||
'code' => 0,
|
||||
'message' => '正面图片与填写信息不符',
|
||||
];
|
||||
}
|
||||
}
|
||||
$verified = $this->ocrVerified(Storage::url($keys['back_card']), 'back');
|
||||
|
||||
if (! $verified) {
|
||||
return [
|
||||
'code' => 0,
|
||||
'message' => $this->getErrorMessage(),
|
||||
];
|
||||
} else {
|
||||
if ($verified['image_status'] != 'normal') {
|
||||
return [
|
||||
'code' => 0,
|
||||
'message' => '背面图片与填写信息不符',
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
$base = [
|
||||
'name' => $keys['name'],
|
||||
'idcard' => $keys['idcard'],
|
||||
];
|
||||
$data = $this->check($base);
|
||||
if ($data === false) {
|
||||
return [
|
||||
'code' => 0,
|
||||
'message' => $this->getErrorMessage(),
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
'code' => 1,
|
||||
];
|
||||
}
|
||||
} else {
|
||||
return [
|
||||
'code' => 1,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : ocr认证
|
||||
*
|
||||
* @Author: Mr.wang
|
||||
* @Date : 2021/12/7 13:54
|
||||
* @param $image
|
||||
* @param $type
|
||||
* @return bool
|
||||
*/
|
||||
public function ocrVerified($image, $type): bool
|
||||
{
|
||||
$AppID = config('userCertification.ocr_appid');
|
||||
$SecretKey = config('userCertification.ocr_secretkey');
|
||||
|
||||
if (empty($AppID)) {
|
||||
$this->setErrorMessage('请配置接口AppID');
|
||||
|
||||
return false;
|
||||
}
|
||||
if (empty($SecretKey)) {
|
||||
$this->setErrorMessage('请配置接口SecretKey');
|
||||
|
||||
return false;
|
||||
}
|
||||
$access = $this->getAccess($AppID, $SecretKey);
|
||||
if ($access === false) {
|
||||
$this->setErrorMessage('access_token不正确');
|
||||
|
||||
return false;
|
||||
}
|
||||
$token = $access->access_token;
|
||||
$apiUrl = 'https://aip.baidubce.com/rest/2.0/ocr/v1/idcard';
|
||||
$result = $this->getOcr($apiUrl, $token, $image, $type);
|
||||
if (($result['error_code'] ?? 0) == 100) {
|
||||
$this->setErrorMessage($result['error_msg'] ?? '未知错误');
|
||||
|
||||
return false;
|
||||
} else {
|
||||
if (empty($result['words_result']) || ! isset($result['words_result'])) {
|
||||
$this->setErrorMessage('图片未识别');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
protected function getAccess($AppID, $SecretKey)
|
||||
{
|
||||
$authUrl = 'https://aip.baidubce.com/oauth/2.0/token';
|
||||
try {
|
||||
$Client = new Client();
|
||||
$response = $Client->post($authUrl, [
|
||||
'query' => [
|
||||
'grant_type' => 'client_credentials',
|
||||
'client_id' => $AppID,
|
||||
'client_secret' => $SecretKey,
|
||||
],
|
||||
]);
|
||||
$result = json_decode($response->getBody()->getContents());
|
||||
|
||||
return $result;
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected function getOcr($url, $token, $image, $type)
|
||||
{
|
||||
$url = $url.'?access_token='.$token;
|
||||
$params = [
|
||||
'url' => $image,
|
||||
'id_card_side' => $type,
|
||||
];
|
||||
try {
|
||||
$Client = new Client();
|
||||
$response = $Client->post($url, ['form_params' => $params]);
|
||||
$result = json_decode($response->getBody()->getContents(), true);
|
||||
|
||||
return $result;
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function getErrorMessage()
|
||||
{
|
||||
return $this->errorMessage;
|
||||
}
|
||||
|
||||
protected function setErrorMessage($message)
|
||||
{
|
||||
$this->errorMessage = $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 网络验证
|
||||
*
|
||||
* @Date : 2021/9/25 15:42
|
||||
* @Author : Mr.wang
|
||||
* @param $keys
|
||||
* @return bool|mixed
|
||||
*/
|
||||
protected function check($keys): bool
|
||||
{
|
||||
$apiUrl = config('userCertification.url');
|
||||
if (empty($apiUrl)) {
|
||||
$this->setErrorMessage('请配置接口地址');
|
||||
|
||||
return false;
|
||||
}
|
||||
$apiCode = config('userCertification.code');
|
||||
if (empty($apiCode)) {
|
||||
$this->setErrorMessage('请配置接口Code');
|
||||
|
||||
return false;
|
||||
}
|
||||
$this->setParams($keys);
|
||||
$this->setHeaders();
|
||||
$result = $this->dopost($apiUrl);
|
||||
try {
|
||||
if (config('userCertification.type') == 2) {
|
||||
if ($result->code == 0 && $result->message == '成功') {
|
||||
if ($result->result->res == 1) {
|
||||
return true;
|
||||
} else {
|
||||
$this->setErrorMessage('信息'.$result->result->description);
|
||||
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$this->setErrorMessage('信息'.$result->result->description);
|
||||
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if ($result->code == 200 && $result->success === true) {
|
||||
if ($result->data->result == 0) {
|
||||
return true;
|
||||
} else {
|
||||
$this->setErrorMessage($result->data->desc);
|
||||
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$this->setErrorMessage($result->msg);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
protected function setParams($keys)
|
||||
{
|
||||
$this->params = $keys;
|
||||
}
|
||||
|
||||
protected function setHeaders()
|
||||
{
|
||||
$this->header = [
|
||||
"Authorization" => 'APPCODE '.config('userCertification.code'),
|
||||
"Accept" => "application/json",
|
||||
];
|
||||
}
|
||||
|
||||
protected function dopost($url)
|
||||
{
|
||||
try {
|
||||
$Client = new Client();
|
||||
$response = $Client->get($url, ['query' => $this->params, 'headers' => $this->header]);
|
||||
// switch (config('usercertification.request_method')) {
|
||||
// case 'get':
|
||||
// $response = $Client->get($url, ['query' => $this->params, 'headers' => $this->header]);
|
||||
// break;
|
||||
// case 'post':
|
||||
// $response = $Client->post($url, ['query' => $this->params, 'headers' => $this->header]);
|
||||
// break;
|
||||
// default:
|
||||
// $this->setErrorMessage('不允许的请求方式');
|
||||
//
|
||||
// return false;
|
||||
// break;
|
||||
// }
|
||||
$result = json_decode($response->getBody()->getContents());
|
||||
|
||||
return $result;
|
||||
} catch (\Exception $e) {
|
||||
preg_match_all('/[\x{4e00}-\x{9fff}]+/u', $e->getmessage(), $cn_name);
|
||||
$this->setErrorMessage($cn_name[0][0]);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
77
modules/User/Models/Traits/HasIdentityScopes.php
Normal file
77
modules/User/Models/Traits/HasIdentityScopes.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models\Traits;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Modules\User\Models\Identity;
|
||||
|
||||
trait HasIdentityScopes
|
||||
{
|
||||
|
||||
/**
|
||||
* Notes: 体验官
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/18 15:25
|
||||
* @param Builder $query
|
||||
* @return Builder
|
||||
*/
|
||||
public function scopeTy(Builder $query): Builder
|
||||
{
|
||||
return $query->where('job', Identity::JOB_TY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 季卡
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/18 15:26
|
||||
* @param Builder $query
|
||||
* @return Builder
|
||||
*/
|
||||
public function scopeJk(Builder $query): Builder
|
||||
{
|
||||
return $query->where('job', Identity::JOB_JK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 年卡
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/18 15:27
|
||||
* @param Builder $query
|
||||
* @return Builder
|
||||
*/
|
||||
public function scopeNk(Builder $query): Builder
|
||||
{
|
||||
return $query->where('job', Identity::JOB_NK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 创始
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/18 15:27
|
||||
* @param Builder $query
|
||||
* @return Builder
|
||||
*/
|
||||
public function scopeCs(Builder $query): Builder
|
||||
{
|
||||
return $query->where('job', Identity::JOB_CS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 合伙人
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/18 15:27
|
||||
* @param Builder $query
|
||||
* @return Builder
|
||||
*/
|
||||
public function scopeHh(Builder $query): Builder
|
||||
{
|
||||
return $query->where('job', Identity::JOB_HH);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
44
modules/User/Models/Traits/HasLog.php
Normal file
44
modules/User/Models/Traits/HasLog.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models\Traits;
|
||||
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Modules\User\Models\UserLog;
|
||||
|
||||
trait HasLog
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Notes: 库存
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/7/26 16:13
|
||||
* @return HasMany
|
||||
*/
|
||||
public function logs(): HasMany
|
||||
{
|
||||
return $this->hasMany(UserLog::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes:
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/9/7 14:22
|
||||
* @param $admin
|
||||
* @param $remark
|
||||
*/
|
||||
public function addLog($admin, $remark)
|
||||
{
|
||||
$this->logs()->create([
|
||||
'user_id' => $this->getKey(),
|
||||
'admin_id' => $admin->getKey(),
|
||||
'remark' => $remark
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
192
modules/User/Models/Traits/HasRelations.php
Normal file
192
modules/User/Models/Traits/HasRelations.php
Normal file
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models\Traits;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOneThrough;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Modules\User\Models\Relation;
|
||||
use Modules\User\Models\User;
|
||||
|
||||
trait HasRelations
|
||||
{
|
||||
|
||||
/**
|
||||
* 这个参数,是为了给用户创建事件监听模型使用的
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public int $parent_id = 0;
|
||||
|
||||
/**
|
||||
* Notes: 创建的监听,转移到这里了
|
||||
*
|
||||
* @Author: <C.Jason>
|
||||
* @Date : 2020/1/13 5:52 下午
|
||||
*/
|
||||
public static function bootHasRelations()
|
||||
{
|
||||
self::created(function ($model) {
|
||||
if (isset($model->parent_id) && is_numeric($model->parent_id) && $model->parent_id != 0) {
|
||||
$parent = User::find($model->parent_id);
|
||||
if ($parent && $model->id != $model->parent_id) {
|
||||
$model->relation()->create([
|
||||
'parent_id' => $parent->id,
|
||||
'bloodline' => $parent->relation->bloodline.$parent->id.',',
|
||||
'layer' => $parent->relation->layer + 1,
|
||||
]);
|
||||
} else {
|
||||
$model->relation()->create([
|
||||
'parent_id' => config('user.default_parent_id'),
|
||||
'bloodline' => config('user.default_parent_id').',',
|
||||
'layer' => 1,
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
$model->relation()->create([
|
||||
'parent_id' => config('user.default_parent_id'),
|
||||
'bloodline' => config('user.default_parent_id').',',
|
||||
'layer' => 1,
|
||||
]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 这个方法,是为了给用户创建事件监听模型使用的
|
||||
* 目的是去除attribute里面的parent_id参数,防止数据库写入错误
|
||||
*
|
||||
* @Author: <C.Jason>
|
||||
* @Date : 2020/1/13 5:58 下午
|
||||
* @param int $parentID
|
||||
*/
|
||||
protected function setParentIdAttribute(int $parentID)
|
||||
{
|
||||
$this->parent_id = $parentID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 用户关联关系
|
||||
*
|
||||
* @Author: <C.Jason>
|
||||
* @Date : 2020/1/13 5:51 下午
|
||||
* @return HasOne
|
||||
*/
|
||||
public function relation(): HasOne
|
||||
{
|
||||
return $this->hasOne(Relation::class)->withDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 上级用户
|
||||
*
|
||||
* @Author: <C.Jason>
|
||||
* @Date : 2020/1/13 5:51 下午
|
||||
* @return HasOneThrough
|
||||
*/
|
||||
public function parent(): HasOneThrough
|
||||
{
|
||||
return $this->hasOneThrough(
|
||||
User::class,
|
||||
Relation::class,
|
||||
'user_id',
|
||||
'id',
|
||||
'id',
|
||||
'parent_id'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 所有下级用户
|
||||
*
|
||||
* @Author: <C.Jason>
|
||||
* @Date : 2020/1/13 5:51 下午
|
||||
* @return mixed
|
||||
*/
|
||||
public function children(): HasManyThrough
|
||||
{
|
||||
return $this->hasManyThrough(
|
||||
User::class,
|
||||
Relation::class,
|
||||
'parent_id',
|
||||
'id',
|
||||
'id',
|
||||
'user_id'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 调整隶属
|
||||
*
|
||||
* @param int $parent_id
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function updateParent(int $parent_id = 0): bool
|
||||
{
|
||||
if ($parent_id == $this->id) {
|
||||
throw new Exception('不能绑定自己');
|
||||
}
|
||||
if (Relation::where('user_id', $parent_id)
|
||||
->where('bloodline', 'like', "%,".$this->id.",%")
|
||||
->exists()) {
|
||||
throw new Exception('不能绑定自己的下级用户');
|
||||
}
|
||||
|
||||
try {
|
||||
$relation = $this->relation;
|
||||
|
||||
$new_blood = '0,';
|
||||
$new_layer = 1;
|
||||
$new_parent_id = 0;
|
||||
|
||||
$blood = $relation->bloodline;
|
||||
$layer = $relation->layer;
|
||||
$parent = User::find($parent_id);
|
||||
if ($parent) {
|
||||
$new_parent_id = $parent->id;
|
||||
$new_blood = $parent->relation->bloodline.$new_parent_id.',';
|
||||
$new_layer = $parent->relation->layer + 1;
|
||||
}
|
||||
$relation->parent_id = $new_parent_id;
|
||||
$relation->bloodline = $new_blood;
|
||||
$relation->layer = $new_layer;
|
||||
if ($relation->save()) {
|
||||
$diffLayer = $layer - $new_layer;
|
||||
DB::update("UPDATE `user_relations` SET `bloodline`=CONCAT(?,SUBSTRING(bloodline,LENGTH(?)+1)),`layer`=`layer`-? WHERE `bloodline` LIKE ?",
|
||||
[$new_blood, $blood, $diffLayer, "%,".$this->id.",%"]);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 获取下级数量
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date : 2021/9/24 11:42
|
||||
*/
|
||||
public function getRelationCount(): array
|
||||
{
|
||||
return [
|
||||
'all' => Relation::query()
|
||||
->whereIn('layer', [$this->relation->layer + 1, $this->relation->layer + 2])
|
||||
->where('bloodline', 'like', "%,".$this->id.",%")
|
||||
->count(),
|
||||
'one' => Relation::query()
|
||||
->where('layer', $this->relation->layer + 1)
|
||||
->where('bloodline', 'like', "%,".$this->id.",%")
|
||||
->count(),
|
||||
'two' => Relation::query()
|
||||
->where('layer', $this->relation->layer + 2)
|
||||
->where('bloodline', 'like', "%,".$this->id.",%")
|
||||
->count(),
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
77
modules/User/Models/Traits/HasSign.php
Normal file
77
modules/User/Models/Traits/HasSign.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models\Traits;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Support\Arr;
|
||||
use Modules\User\Models\Sign;
|
||||
use Modules\User\Models\SignConfig;
|
||||
use Modules\User\Models\SignLog;
|
||||
|
||||
trait HasSign
|
||||
{
|
||||
/**
|
||||
* 用户签到
|
||||
*
|
||||
* @return HasOne
|
||||
*/
|
||||
public function sign(): HasOne
|
||||
{
|
||||
return $this->hasOne(Sign::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 当前日期是否签到
|
||||
*
|
||||
* @Date : 2022/1/6 13:25
|
||||
* @Author : Mr.wang
|
||||
* @param string $date
|
||||
* @return bool
|
||||
*/
|
||||
public function isSign($date = null): bool
|
||||
{
|
||||
$date = $date ?? Carbon::now()->format('Y-m-d');
|
||||
return $this->signLogs()->whereDate('date', $date)->exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 用户签到日志
|
||||
*
|
||||
* @Date : 2022/1/6 13:23
|
||||
* @Author : Mr.wang
|
||||
* @return HasMany
|
||||
*/
|
||||
public function signLogs(): HasMany
|
||||
{
|
||||
return $this->hasMany(SignLog::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 获取签到数据
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/3 15:35
|
||||
*/
|
||||
public function getSignData(): array
|
||||
{
|
||||
$all = Arr::get(SignConfig::getParams(), 'cycle_day', 0);
|
||||
$data = [
|
||||
'continue' => 0,
|
||||
'total' => 0,
|
||||
'all' => $all
|
||||
];
|
||||
if ($this->sign) {
|
||||
$data = [
|
||||
'continue' => $this->sign->continue_days,
|
||||
'total' => $this->sign->counts,
|
||||
'all' => $all,
|
||||
];
|
||||
}
|
||||
$data = array_merge($data, [
|
||||
'text' => '第'.$data['continue'].'/'.$data['all'].'天'
|
||||
]);
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
153
modules/User/Models/Traits/HasStock.php
Normal file
153
modules/User/Models/Traits/HasStock.php
Normal file
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models\Traits;
|
||||
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Support\Arr;
|
||||
use Modules\Mall\Facades\Item;
|
||||
use Modules\Mall\Facades\Order as OrderFacade;
|
||||
use Modules\Mall\Models\Address;
|
||||
use Modules\Mall\Models\Goods;
|
||||
use Modules\Mall\Models\GoodsSku;
|
||||
use Modules\Mall\Models\Order;
|
||||
use Modules\Mall\Models\OrderItem;
|
||||
use Modules\User\Models\Identity;
|
||||
use Modules\User\Models\UserStock;
|
||||
use Modules\User\Models\UserStockLog;
|
||||
|
||||
trait HasStock
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Notes: 库存
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/7/26 16:13
|
||||
* @return HasOne
|
||||
*/
|
||||
public function userStock(): HasOne
|
||||
{
|
||||
return $this->hasOne(UserStock::class)->withDefault([
|
||||
'stock' => 0,
|
||||
'hold' => 0,
|
||||
'residue' => 0,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 获取库存
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/7/29 13:58
|
||||
*/
|
||||
public function getStockData(): array
|
||||
{
|
||||
$identity = $this->identityFirst();
|
||||
$min = 1;
|
||||
if ($identity->job == Identity::JOB_TY) {
|
||||
$min = $identity->stock;
|
||||
}
|
||||
|
||||
$deliver = OrderItem::query()
|
||||
->whereHas('order', function ($q) {
|
||||
$q->TypeSample()->ByUser($this)->paid();
|
||||
})->sum('qty');
|
||||
|
||||
$deliverd = OrderItem::query()
|
||||
->whereHas('order', function ($q) {
|
||||
$q->TypeSample()->ByUser($this)->whereIn('state', [
|
||||
Order::STATUS_SIGNED,
|
||||
Order::STATUS_DELIVERED,
|
||||
]);
|
||||
})->sum('qty');
|
||||
|
||||
return [
|
||||
'case_id' => $this->case ? $this->case->id : 0,
|
||||
'stock' => $this->userStock->stock,//总库存
|
||||
'hold' => $this->userStock->hold,//已发货
|
||||
'residue' => (int) bcsub($this->userStock->residue, $deliver),//未提货
|
||||
'deliver' => $deliver,//待发货
|
||||
'deliverd' => $deliverd,//已发货
|
||||
'min_pick' => $min,//最少提货数量
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 增加库存
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/7/26 16:18
|
||||
*/
|
||||
public function addStock($identity_id, $type = null, $addStock = 0)
|
||||
{
|
||||
try {
|
||||
$identity = Identity::find($identity_id);
|
||||
|
||||
$stock = $identity->stock;
|
||||
if ($addStock) {
|
||||
$stock = $addStock;
|
||||
}
|
||||
|
||||
$userStock = $this->userStock;
|
||||
if (! $type) {
|
||||
$type = UserStockLog::TYPE_IN;
|
||||
}
|
||||
|
||||
if (isset($userStock->id)) {
|
||||
$userStock->increment('stock', $stock);
|
||||
} else {
|
||||
$userStock = UserStock::query()->updateOrCreate([
|
||||
'user_id' => $this->id,
|
||||
], [
|
||||
'stock' => $stock,
|
||||
]);
|
||||
}
|
||||
|
||||
$this->addStockLog($type, $stock, $identity_id);
|
||||
|
||||
return true;
|
||||
} catch (\Exception $exception) {
|
||||
return new \Exception($exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notes: 增加销量
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/7/29 14:44
|
||||
*/
|
||||
public function addHold($number)
|
||||
{
|
||||
$this->userStock->increment('hold', $number);
|
||||
|
||||
$this->addStockLog(UserStockLog::TYPE_OUT, -$number);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 增加日志
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/2 14:55
|
||||
* @param $type
|
||||
* @param $variable
|
||||
* @param int $identity_id
|
||||
*/
|
||||
public function addStockLog($type, $variable, int $identity_id = 0)
|
||||
{
|
||||
$userStock = UserStock::where('user_id', $this->id)->first();
|
||||
UserStockLog::query()
|
||||
->create([
|
||||
'user_stock_id' => $userStock->id,
|
||||
'type' => $type,
|
||||
'variable' => $variable,
|
||||
'identity_id' => $identity_id,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
65
modules/User/Models/Traits/HasVipOrders.php
Normal file
65
modules/User/Models/Traits/HasVipOrders.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models\Traits;
|
||||
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Modules\User\Models\Order;
|
||||
|
||||
trait HasVipOrders
|
||||
{
|
||||
|
||||
/**
|
||||
* Notes : 用户的订单列表
|
||||
*
|
||||
* @Date : 2021/4/19 10:28 上午
|
||||
* @Author : < Jason.C >
|
||||
* @return HasMany
|
||||
*/
|
||||
public function vipOrders(): HasMany
|
||||
{
|
||||
return $this->hasMany(Order::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 开通会员缴费
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/9/7 13:59
|
||||
*/
|
||||
public function getOpenVipPrices($type = 'all')
|
||||
{
|
||||
return $this->vipOrders
|
||||
->where('state', Order::STATE_SUCCESS)
|
||||
->where('price', '>', 0)
|
||||
->pluck('price');
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 创建订单
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/9/7 16:55
|
||||
*/
|
||||
public function createOrder($identity_id, $year, $price, $stock, $source = null)
|
||||
{
|
||||
$data = [
|
||||
'user_id' => $this->id,
|
||||
'identity_id' => $identity_id,
|
||||
'year' => $year,
|
||||
'type' => 1,
|
||||
'name' => '',
|
||||
'card_no' => '',
|
||||
'cover' => '',
|
||||
'stock' => $stock,
|
||||
'state' => Order::STATE_INIT,
|
||||
'price' => $price,
|
||||
'source' => $source,
|
||||
];
|
||||
|
||||
$order = Order::create($data);
|
||||
$order->pay();
|
||||
return $order;
|
||||
}
|
||||
|
||||
}
|
||||
56
modules/User/Models/Traits/HasWechat.php
Normal file
56
modules/User/Models/Traits/HasWechat.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models\Traits;
|
||||
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Modules\User\Models\UserWechat;
|
||||
|
||||
trait HasWechat
|
||||
{
|
||||
|
||||
/**
|
||||
* Notes : 用户微信信息
|
||||
*
|
||||
* @Date : 2021/5/26 11:14
|
||||
* @Author : Mr.wang
|
||||
* @return HasOne
|
||||
*/
|
||||
public function wechat(): HasOne
|
||||
{
|
||||
return $this->hasOne(UserWechat::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 是否关注公众号
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/3 16:23
|
||||
*/
|
||||
public function isOfficialSubscribe(): bool
|
||||
{
|
||||
return $this->wechat ? $this->wechat->isOfficialSubscribe() : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 获取openids
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/9/27 14:51
|
||||
* @return string[]
|
||||
*/
|
||||
public function getOpenids()
|
||||
{
|
||||
if ($this->wechat) {
|
||||
$data = $this->wechat->getOpenids();
|
||||
} else {
|
||||
$data = [
|
||||
'mini' => '',
|
||||
'official' => '',
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
247
modules/User/Models/Traits/JoinIdentity.php
Normal file
247
modules/User/Models/Traits/JoinIdentity.php
Normal file
@@ -0,0 +1,247 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models\Traits;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Modules\User\Events\UserJoinIdentity;
|
||||
use Modules\User\Events\UserRemoveIdentity;
|
||||
use Modules\User\Events\UserUpdateIdentity;
|
||||
use Modules\User\Models\Identity;
|
||||
use Modules\User\Models\IdentityLog;
|
||||
use Modules\User\Models\IdentityMiddle;
|
||||
|
||||
trait JoinIdentity
|
||||
{
|
||||
|
||||
/**
|
||||
* 用户加入身份
|
||||
*
|
||||
* @param int $identity_id 身份ID
|
||||
* @param string $channel 加入渠道
|
||||
* @param array $source 其他溯源信息
|
||||
* @throws Exception
|
||||
*/
|
||||
public function joinIdentity(
|
||||
int $identity_id = 0,
|
||||
string $channel = IdentityLog::CHANNEL_AUTO,
|
||||
array $source = []
|
||||
) {
|
||||
|
||||
// 单身份,并且已经开通身份
|
||||
if (config('identity.can_has_many_identity') == false && $this->identityMiddle->count() >= 1) {
|
||||
//续费
|
||||
if ($this->hasIdentity($identity_id)) {
|
||||
$this->renewIdentity($identity_id);
|
||||
} else {
|
||||
//升级
|
||||
self::updateIdentity($identity_id, $channel, $source);
|
||||
}
|
||||
} else {
|
||||
$identity = Identity::find($identity_id);
|
||||
if ($identity) {
|
||||
//未开通此身份
|
||||
if ($this->hasIdentity($identity_id) == false) {
|
||||
$remark = Arr::get($source, 'remark', '加入身份');
|
||||
$res = self::identityLog(0, $identity_id, $channel, $remark, $source);
|
||||
if ($res) {
|
||||
$serial = $source['serial'] ?? '';
|
||||
if ($identity->serial_open && empty($serial)) {
|
||||
$serial = self::getNewSerial($identity->serial_places);
|
||||
}
|
||||
|
||||
$value = [];
|
||||
if ($identity->years) {
|
||||
$value = [
|
||||
'started_at' => now(),
|
||||
'ended_at' => now()->addMonths($identity->years),
|
||||
];
|
||||
}
|
||||
|
||||
$this->identityMiddle()
|
||||
->updateOrCreate([
|
||||
'identity_id' => $identity_id,
|
||||
'serial' => $serial,
|
||||
], $value);
|
||||
|
||||
event(new UserJoinIdentity($this, $identity));
|
||||
} else {
|
||||
throw new Exception('添加日志失败');
|
||||
}
|
||||
} else {
|
||||
//已开通此身份
|
||||
$this->renewIdentity($identity_id);
|
||||
}
|
||||
} else {
|
||||
throw new Exception('身份信息不存在');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 续费
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date : 2021/6/8 9:49
|
||||
* @param int $identity_id
|
||||
*/
|
||||
public function renewIdentity(int $identity_id)
|
||||
{
|
||||
$identity = Identity::find($identity_id);
|
||||
$before = $this->identityMiddle()->where('identity_id', $identity_id)->first();
|
||||
|
||||
//vip
|
||||
if ($identity->years) {
|
||||
IdentityMiddle::where('user_id', $this->id)
|
||||
->where('identity_id', $identity_id)
|
||||
->update([
|
||||
'ended_at' => Carbon::parse($before->ended_at)->addMonths($identity->years),
|
||||
]);
|
||||
} else {
|
||||
IdentityMiddle::where('user_id', $this->id)
|
||||
->where('identity_id', $identity_id)
|
||||
->update([
|
||||
'started_at' => null,
|
||||
'ended_at' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
event(new UserJoinIdentity($this, $before->identity));
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户身份调整,当多身份关闭时由join触发
|
||||
*
|
||||
* @param int $identity_id
|
||||
* @param string $channel
|
||||
* @param array $source
|
||||
* @throws Exception
|
||||
*/
|
||||
public function updateIdentity(
|
||||
int $identity_id = 0,
|
||||
string $channel = IdentityLog::CHANNEL_AUTO,
|
||||
array $source = []
|
||||
) {
|
||||
$before = $this->identityMiddle()->first();
|
||||
if ($this->identityMiddle()->count() > 1) {
|
||||
$this->identityMiddle()->where('identity_id', '!=', $before->identity_id)->delete();
|
||||
}
|
||||
$identity = Identity::find($identity_id);
|
||||
if ($identity) {
|
||||
$remark = Arr::get($source, 'remark', '身份变更');
|
||||
$res = self::identityLog($before->identity_id, $identity_id, $channel, $remark, $source);
|
||||
if ($res) {
|
||||
$serial = $source['serial'] ?? '';
|
||||
if ($identity->serial_open && empty($serial)) {
|
||||
$serial = self::getNewSerial($identity->serial_places);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'identity_id' => $identity_id,
|
||||
'serial' => $serial,
|
||||
'started_at' => null,
|
||||
'ended_at' => null,
|
||||
];
|
||||
|
||||
if ($identity->years) {
|
||||
$data['started_at'] = now();
|
||||
$data['ended_at'] = now()->addMonths($identity->years);
|
||||
}
|
||||
|
||||
IdentityMiddle::where('user_id', $this->id)
|
||||
->where('identity_id', $before->identity_id)
|
||||
->update($data);
|
||||
|
||||
event(new UserUpdateIdentity($this, $before->identity, $identity));
|
||||
} else {
|
||||
throw new Exception('调整身份');
|
||||
}
|
||||
} else {
|
||||
throw new Exception('身份信息不存在');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断用户是否参与身份
|
||||
*
|
||||
* @param int $identity_id
|
||||
* @return bool
|
||||
*/
|
||||
public function hasIdentity(int $identity_id = 0): bool
|
||||
{
|
||||
if ($identity_id) {
|
||||
$res = $this->identityMiddle()->where('identity_id', $identity_id)->first();
|
||||
|
||||
return (bool) $res;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户移除身份
|
||||
*
|
||||
* @param int $identity_id 身份ID
|
||||
* @param string $channel 移除渠道
|
||||
* @param array $source 其他溯源信息
|
||||
* @throws Exception
|
||||
*/
|
||||
public function removeIdentity(
|
||||
int $identity_id = 0,
|
||||
string $channel = IdentityLog::CHANNEL_AUTO,
|
||||
array $source = []
|
||||
) {
|
||||
if ($this->identityMiddle()->where('identity_id', $identity_id)->first()) {
|
||||
$remark = Arr::get($source, 'remark', '身份移除');
|
||||
$res = self::identityLog($identity_id, 0, $channel, $remark, $source);
|
||||
if ($res) {
|
||||
$this->identityMiddle()->where('identity_id', $identity_id)->delete();
|
||||
event(new UserRemoveIdentity($this, Identity::find($identity_id)));
|
||||
} else {
|
||||
throw new Exception('移除记录失败');
|
||||
}
|
||||
} else {
|
||||
throw new Exception('用户不在身份组中');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成数据库中部存在的号码
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNewSerial($places = 8)
|
||||
{
|
||||
try {
|
||||
$min = pow(10, $places - 1);
|
||||
$max = 9 * $min;
|
||||
$query = 'SELECT code FROM (SELECT CEILING(RAND()*'.$max.'+'.$min.') AS code FROM user_identity UNION SELECT CEILING(RAND()*'.$max.'+'.$min.') AS code) AS ss WHERE "code" NOT IN (SELECT serial FROM user_identity where serial !=null) LIMIT 1';
|
||||
$res = DB::select($query);
|
||||
|
||||
return (int) $res[0]->code;
|
||||
} catch (Exception $e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
public function identityLog(
|
||||
$before = 0,
|
||||
$after = 0,
|
||||
$channel = '',
|
||||
$remark = '',
|
||||
$source = []
|
||||
): Model {
|
||||
return $this->identity_logs()->create([
|
||||
'before' => $before,
|
||||
'after' => $after,
|
||||
'channel' => $channel,
|
||||
'remark' => $remark,
|
||||
'source' => $source,
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
107
modules/User/Models/Traits/OrderActions.php
Normal file
107
modules/User/Models/Traits/OrderActions.php
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models\Traits;
|
||||
|
||||
use Modules\Coupon\Models\Coupon;
|
||||
use Modules\Payment\Models\Payment;
|
||||
use Modules\User\Events\UserOrderPaid;
|
||||
use Exception;
|
||||
use Modules\User\Models\Order;
|
||||
|
||||
trait OrderActions
|
||||
{
|
||||
/**
|
||||
* Notes: 设置订单支付
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date : 2020/11/12 11:19
|
||||
*/
|
||||
public function pay()
|
||||
{
|
||||
try {
|
||||
$this->state = self::STATE_SUCCESS;
|
||||
$this->save();
|
||||
event(new UserOrderPaid($this));
|
||||
return true;
|
||||
|
||||
} catch (\Exception $exception) {
|
||||
return $exception->getMessage();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 退款
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/22 13:09
|
||||
*/
|
||||
public function refund(): bool
|
||||
{
|
||||
try {
|
||||
$payment = $this->payment;
|
||||
if (! $payment) {
|
||||
throw new Exception("退款失败,未找到支付信息");
|
||||
}
|
||||
|
||||
$refund = $payment->refunds()->create([
|
||||
'total' => $this->price,
|
||||
]);
|
||||
//微信支付
|
||||
if ($payment->driver == Payment::DRIVER_WECHAT) {
|
||||
|
||||
$order = [
|
||||
'out_trade_no' => $payment->trade_id,
|
||||
'out_refund_no' => $refund->refund_no,
|
||||
'amount' => [
|
||||
'refund' => $payment->total * 100,
|
||||
'total' => $payment->total * 100,
|
||||
'currency' => 'CNY',
|
||||
],
|
||||
];
|
||||
|
||||
$result = app('pay.wechat')->refund($order);
|
||||
|
||||
if (isset($result->code) && $result->code == 'PARAM_ERROR') {
|
||||
throw new Exception("退款失败,".$result->message);
|
||||
}
|
||||
|
||||
$this->update([
|
||||
'state' => Order::STATE_REFUND
|
||||
]);
|
||||
|
||||
$refund->update([
|
||||
'refund_at' => now()
|
||||
]);
|
||||
|
||||
return true;
|
||||
} elseif ($payment->driver == Payment::DRIVER_ALIPAY) {//支付宝支付
|
||||
|
||||
$order = [
|
||||
'out_trade_no' => $this->order->order_no,
|
||||
'refund_amount' => $this->actual_total,
|
||||
];
|
||||
|
||||
$result = app('pay.alipay')->refund($order);
|
||||
|
||||
if ($result->code != '10000') {
|
||||
throw new Exception("退款失败,".$result->msg);
|
||||
}
|
||||
|
||||
$this->update([
|
||||
'state' => Order::STATE_REFUND
|
||||
]);
|
||||
|
||||
$refund->update([
|
||||
'refund_at' => now()
|
||||
]);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
throw new Exception("退款失败,未找到支付路径");
|
||||
}
|
||||
} catch (Exception $exception) {
|
||||
throw new Exception($exception->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
77
modules/User/Models/Traits/WechatAttribute.php
Normal file
77
modules/User/Models/Traits/WechatAttribute.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models\Traits;
|
||||
|
||||
trait WechatAttribute
|
||||
{
|
||||
|
||||
/**
|
||||
* Notes : 获取微信公众号openid
|
||||
*
|
||||
* @Date : 2021/5/26 17:03
|
||||
* @Author : Mr.wang
|
||||
* @return string
|
||||
*/
|
||||
public function getOfficialOpenidAttribute(): string
|
||||
{
|
||||
return $this->official->openid ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: description
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/3 16:22
|
||||
*/
|
||||
public function isOfficialSubscribe(): bool
|
||||
{
|
||||
return $this->official()->where('subscribe', 1)->exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 获取微信小程序openid
|
||||
*
|
||||
* @Date : 2021/5/26 17:03
|
||||
* @Author : Mr.wang
|
||||
* @return string
|
||||
*/
|
||||
public function getMiniOpenidAttribute(): string
|
||||
{
|
||||
return $this->mini->openid ?? '';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notes: 获取用户openid
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/9/26 13:52
|
||||
* @param $channel
|
||||
* @return mixed
|
||||
*/
|
||||
public function getUserOpenid($channel)
|
||||
{
|
||||
$channel = strtolower($channel);
|
||||
if ($channel == 'mp') {
|
||||
return Arr::get($this->getOpenids(), 'official');
|
||||
} else {
|
||||
return Arr::get($this->getOpenids(), 'mini');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 获取openids
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/9/26 15:06
|
||||
* @return array
|
||||
*/
|
||||
public function getOpenids(): array
|
||||
{
|
||||
return [
|
||||
'mini' => $this->mini()->value('openid') ?? '',
|
||||
'official' => $this->official()->value('openid') ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
306
modules/User/Models/User.php
Normal file
306
modules/User/Models/User.php
Normal file
@@ -0,0 +1,306 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Traits\Macroable;
|
||||
use App\Traits\OrderByIdDesc;
|
||||
use Encore\Admin\Traits\DefaultDatetimeFormat;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Foundation\Auth\User as Authenticate;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Laravel\Sanctum\HasApiTokens;
|
||||
use Modules\Coupon\Traits\UserHasCoupon;
|
||||
use Modules\Mall\Traits\HasAddresses;
|
||||
use Modules\Mall\Traits\HasOrders;
|
||||
use Modules\Task\Traits\HasTasks;
|
||||
use Modules\User\Models\Traits\HasChannel;
|
||||
use Modules\User\Models\Traits\HasInvite;
|
||||
use Modules\User\Models\Traits\HasLog;
|
||||
use Modules\User\Models\Traits\HasStock;
|
||||
use Modules\User\Models\Traits\HasVipOrders;
|
||||
use Modules\User\Models\Traits\HasWechat;
|
||||
use Modules\Withdraw\Traits\HasWithdraws;
|
||||
use Modules\User\Models\Order as UserOrder;
|
||||
use Overtrue\LaravelFavorite\Traits\Favoriter;
|
||||
use Overtrue\LaravelSubscribe\Traits\Subscriber;
|
||||
use SimpleSoftwareIO\QrCode\Facades\QrCode;
|
||||
use Vinkla\Hashids\Facades\Hashids;
|
||||
|
||||
class User extends Authenticate
|
||||
{
|
||||
|
||||
use HasApiTokens,
|
||||
DefaultDatetimeFormat,
|
||||
Macroable,
|
||||
HasStock,
|
||||
HasLog,
|
||||
HasGout,
|
||||
HasWithdraws,
|
||||
HasOrders,
|
||||
HasVipOrders,
|
||||
HasWechat,
|
||||
HasInvite,
|
||||
|
||||
HasAddresses,
|
||||
Notifiable,
|
||||
HasTasks,
|
||||
Subscriber,
|
||||
Favoriter,
|
||||
OrderByIdDesc,
|
||||
Traits\JoinIdentity,
|
||||
Traits\HasRelations,
|
||||
Traits\HasSign;
|
||||
|
||||
const STATUS_INIT = 1;
|
||||
const STATUS_REFUND = 2;
|
||||
|
||||
const STATUS = [
|
||||
self::STATUS_INIT => '正常',
|
||||
self::STATUS_REFUND => '退费',
|
||||
];
|
||||
|
||||
/**
|
||||
* 禁止写入的字段
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* 模型隐藏字段
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $hidden = [
|
||||
'password',
|
||||
'remember_token',
|
||||
];
|
||||
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
self::created(function ($user) {
|
||||
$user->info()->create([
|
||||
'nickname' => '用户'.substr($user->username, -4),
|
||||
]);
|
||||
$user->sign()->create([
|
||||
'continue_days' => 0,
|
||||
'counts' => 0,
|
||||
'last_sign_at' => null,
|
||||
]);
|
||||
$user->account()->create();
|
||||
|
||||
$defaultIdentity = Identity::where('default', 1)->first();
|
||||
if ($defaultIdentity) {
|
||||
$user->joinIdentity($defaultIdentity->id, IdentityLog::CHANNEL_REG);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 用户资料
|
||||
*
|
||||
* @Date : 2021/3/11 5:41 下午
|
||||
* @Author : < Jason.C >
|
||||
* @return HasOne
|
||||
*/
|
||||
public function info(): HasOne
|
||||
{
|
||||
return $this->hasOne(UserInfo::class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notes : 用户账户
|
||||
*
|
||||
* @Date : 2021/4/27 11:20 上午
|
||||
* @Author : < Jason.C >
|
||||
* @return HasOne
|
||||
*/
|
||||
public function account(): HasOne
|
||||
{
|
||||
return $this->hasOne(Account::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 当用户有密码的时候才加密
|
||||
*
|
||||
* @Date : 2021/3/11 1:43 下午
|
||||
* @Author : < Jason.C >
|
||||
* @param $password
|
||||
*/
|
||||
public function setPasswordAttribute($password)
|
||||
{
|
||||
if ($password) {
|
||||
$this->attributes['password'] = bcrypt($password);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 第一身份
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function identityFirst()
|
||||
{
|
||||
return $this->identities()->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 用户身份
|
||||
*
|
||||
* @Date : 2021/5/6 12:00 下午
|
||||
* @Author : < Jason.C >
|
||||
*/
|
||||
public function identities(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Identity::class, 'user_identity')
|
||||
->withTimestamps()
|
||||
->withPivot(['started_at', 'ended_at', 'serial']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户中间表关联
|
||||
*
|
||||
* @return HasMany
|
||||
*/
|
||||
public function identityMiddle(): HasMany
|
||||
{
|
||||
return $this->hasMany(IdentityMiddle::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 身份变动表关联
|
||||
*
|
||||
* @return HasMany
|
||||
*/
|
||||
public function identity_logs(): HasMany
|
||||
{
|
||||
return $this->hasMany(IdentityLog::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 升级缴费订单
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/9/7 13:57
|
||||
*/
|
||||
public function vipOrders(): HasMany
|
||||
{
|
||||
return $this->hasMany(UserOrder::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户个人认证
|
||||
*
|
||||
* @return HasOne
|
||||
*/
|
||||
public function certification(): HasOne
|
||||
{
|
||||
return $this->hasOne(UserCertification::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 获取状态信息
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/3 16:30
|
||||
*/
|
||||
public function getStateData(): array
|
||||
{
|
||||
$identity = $this->identities->first();
|
||||
|
||||
return [
|
||||
'isSubscribe' => $this->isOfficialSubscribe(),//关注
|
||||
'isVip' => $identity ? $identity->order : 0,//是否开会
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 获取当前状态
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/3 16:38
|
||||
*/
|
||||
public function getNowStatus(): array
|
||||
{
|
||||
$status = $this->getStateData();
|
||||
|
||||
if (! $status['isSubscribe']) {
|
||||
return [
|
||||
'value' => 'isSubscribe',
|
||||
'text' => '关注'
|
||||
];
|
||||
}
|
||||
|
||||
if (! $status['isCase']) {
|
||||
return [
|
||||
'value' => 'isCase',
|
||||
'text' => '健康档案'
|
||||
];
|
||||
}
|
||||
|
||||
if (! $status['isVip']) {
|
||||
return [
|
||||
'value' => 'isVip',
|
||||
'text' => '开通会员'
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'value' => 'upCase',
|
||||
'text' => '上传档案'
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notes: 开通季卡的次数
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/21 10:38
|
||||
*/
|
||||
public function getOpenJkCount(): int
|
||||
{
|
||||
$jkIdentity = Identity::query()->Jk()->first();
|
||||
$num = 0;
|
||||
if ($jkIdentity) {
|
||||
$num = UserOrder::query()
|
||||
->byUser($this)
|
||||
->where('identity_id', $jkIdentity->id)
|
||||
->where('state', UserOrder::STATE_SUCCESS)
|
||||
->count();
|
||||
}
|
||||
|
||||
return $num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: description
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/9/28 13:08
|
||||
*/
|
||||
public function getCodeAttribute()
|
||||
{
|
||||
$userIdentity = $this->identityFirst();
|
||||
|
||||
if ($userIdentity && $userIdentity->id > 1) {
|
||||
$invite = Hashids::connection('code')->encode($this->id);
|
||||
} else {
|
||||
$invite = '';
|
||||
}
|
||||
|
||||
$url = Config::get('user.invite_code.url').'?invite='.$invite;
|
||||
return 'data:image/png;base64,'.base64_encode(QrCode::format('png')
|
||||
->size(100)
|
||||
->margin(3)
|
||||
->generate($url));
|
||||
}
|
||||
|
||||
}
|
||||
27
modules/User/Models/UserCertification.php
Normal file
27
modules/User/Models/UserCertification.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Models\Model;
|
||||
use Modules\User\Events\UserCertificationSuccess;
|
||||
use Modules\User\Traits\BelongsToUser;
|
||||
|
||||
class UserCertification extends Model
|
||||
{
|
||||
|
||||
use BelongsToUser;
|
||||
|
||||
protected $casts = [
|
||||
'verified' => 'boolean',
|
||||
];
|
||||
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
self::created(function ($certification) {
|
||||
event(new UserCertificationSuccess($certification));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
48
modules/User/Models/UserCertificationConfig.php
Normal file
48
modules/User/Models/UserCertificationConfig.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Models\Model;
|
||||
use App\Traits\HasStatus;
|
||||
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Modules\User\Models\Traits\CertificationTrait;
|
||||
|
||||
class UserCertificationConfig extends Model
|
||||
{
|
||||
use HasStatus,
|
||||
Cachable,
|
||||
CertificationTrait;
|
||||
|
||||
const IDCARD = 1;
|
||||
const PHONECARD = 2;
|
||||
|
||||
const TYPE = [
|
||||
self::IDCARD => '姓名,身份证验证',
|
||||
self::PHONECARD => '姓名,手机号,身份证号验证',
|
||||
];
|
||||
|
||||
public static function loading()
|
||||
{
|
||||
$config = Cache::rememberForever('userCertification', function () {
|
||||
$conf = self::shown()
|
||||
->first();
|
||||
Artisan::call('queue:restart');
|
||||
|
||||
return $conf ? $conf->toArray() : '';
|
||||
});
|
||||
config(['userCertification' => $config]);
|
||||
}
|
||||
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
self::saved(function ($model) {
|
||||
if ($model->status == 1) {
|
||||
Cache::forget('userCertification');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
48
modules/User/Models/UserInfo.php
Normal file
48
modules/User/Models/UserInfo.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Models\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class UserInfo extends Model
|
||||
{
|
||||
|
||||
protected $primaryKey = 'user_id';
|
||||
|
||||
/**
|
||||
* Notes : 用户
|
||||
*
|
||||
* @Date : 2021/3/11 5:37 下午
|
||||
* @Author : < Jason.C >
|
||||
* @return BelongsTo
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 获取头像的实际地址
|
||||
*
|
||||
* @Date : 2021/3/12 10:53 上午
|
||||
* @Author : < Jason.C >
|
||||
* @param $avatar
|
||||
* @return string
|
||||
*/
|
||||
public function getAvatarAttribute($avatar): string
|
||||
{
|
||||
if (empty($avatar)) {
|
||||
$avatar = config('user.avatar');
|
||||
}
|
||||
|
||||
if (Str::startsWith($avatar, 'http')) {
|
||||
return $avatar;
|
||||
}
|
||||
|
||||
return $avatar ? Storage::url($avatar) : '';
|
||||
}
|
||||
|
||||
}
|
||||
18
modules/User/Models/UserLog.php
Normal file
18
modules/User/Models/UserLog.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
|
||||
use App\Models\Model;
|
||||
use Encore\Admin\Auth\Database\Administrator;
|
||||
use Modules\User\Traits\BelongsToUser;
|
||||
|
||||
class UserLog extends Model
|
||||
{
|
||||
use BelongsToUser;
|
||||
|
||||
public function admin()
|
||||
{
|
||||
return $this->belongsTo(Administrator::class);
|
||||
}
|
||||
}
|
||||
93
modules/User/Models/UserStock.php
Normal file
93
modules/User/Models/UserStock.php
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
|
||||
use App\Models\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Support\Arr;
|
||||
use Modules\Mall\Models\Order;
|
||||
use Modules\User\Traits\BelongsToUser;
|
||||
|
||||
class UserStock extends Model
|
||||
{
|
||||
use BelongsToUser;
|
||||
|
||||
const STATUS_PAID = 1;
|
||||
const STATUS_DELIVER = 2;
|
||||
const STATUS_DELIVERED = 3;
|
||||
const STATUS_SIGNED = 4;
|
||||
|
||||
const STOCK_ORDER_STATUS = [
|
||||
self::STATUS_PAID => '待提货',
|
||||
self::STATUS_DELIVER => '待发货',
|
||||
self::STATUS_DELIVERED => '待签收',
|
||||
self::STATUS_SIGNED => '已签收',
|
||||
];
|
||||
|
||||
const STOCK_ORDER_STATUS_MAP = [
|
||||
'待提货' => 'primary',
|
||||
'待发货' => 'success',
|
||||
'待签收' => 'danger',
|
||||
'已签收' => 'info',
|
||||
];
|
||||
|
||||
public $appends = ['residue'];
|
||||
|
||||
/**
|
||||
* Notes: 获取剩余
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/7/29 14:01
|
||||
* @return string
|
||||
*/
|
||||
public function getResidueAttribute()
|
||||
{
|
||||
return bcsub($this->stock, $this->hold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 日志
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/2 14:43
|
||||
* @return HasMany
|
||||
*/
|
||||
public function logs(): HasMany
|
||||
{
|
||||
return $this->hasMany(UserStockLog::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: 获取体验官提货订单状态
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/9/1 16:40
|
||||
*/
|
||||
public function getStockOrderStatusAttribute()
|
||||
{
|
||||
$order = $this->user->orders()->first();
|
||||
if (empty($order)) {
|
||||
return 1;
|
||||
} elseif ($order->state == Order::STATUS_PAID) {
|
||||
return 2;
|
||||
} elseif ($order->state == Order::STATUS_DELIVERED) {
|
||||
return 3;
|
||||
} elseif ($order->state == Order::STATUS_SIGNED) {
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notes: 获取体验官订单名称
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/9/1 16:45
|
||||
*/
|
||||
public function getStockOrderStatusTextAttribute()
|
||||
{
|
||||
return Arr::get(self::STOCK_ORDER_STATUS, $this->stock_order_status, '未知');
|
||||
}
|
||||
|
||||
}
|
||||
53
modules/User/Models/UserStockLog.php
Normal file
53
modules/User/Models/UserStockLog.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
|
||||
use App\Models\Model;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class UserStockLog extends Model
|
||||
{
|
||||
const TYPE_INIT = 'init';
|
||||
const TYPE_IN = 'in';
|
||||
const TYPE_OUT = 'out';
|
||||
|
||||
const TYPES = [
|
||||
self::TYPE_INIT => '开通会员',
|
||||
self::TYPE_IN => '续费',
|
||||
self::TYPE_OUT => '提货',
|
||||
];
|
||||
|
||||
public function identity()
|
||||
{
|
||||
return $this->belongsTo(Identity::class);
|
||||
}
|
||||
|
||||
public function userStock(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(UserStock::class);
|
||||
}
|
||||
|
||||
public function getTypeTextAttribute(): string
|
||||
{
|
||||
return self::TYPES[$this->type];
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes: description
|
||||
*
|
||||
* @Author: 玄尘
|
||||
* @Date: 2022/8/3 10:44
|
||||
* @param Builder $query
|
||||
* @param User $user
|
||||
* @return Builder
|
||||
*/
|
||||
public function scopeByUser(Builder $query, User $user): Builder
|
||||
{
|
||||
return $query->whereHas('userStock', function ($q) use ($user) {
|
||||
return $q->ByUser($user);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
11
modules/User/Models/UserSubscribe.php
Normal file
11
modules/User/Models/UserSubscribe.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
|
||||
use App\Models\Model;
|
||||
|
||||
class UserSubscribe extends Model
|
||||
{
|
||||
|
||||
}
|
||||
71
modules/User/Models/UserWechat.php
Normal file
71
modules/User/Models/UserWechat.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Models\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Support\Arr;
|
||||
use Modules\User\Models\Traits\WechatAttribute;
|
||||
use Modules\User\Traits\BelongsToUser;
|
||||
|
||||
class UserWechat extends Model
|
||||
{
|
||||
|
||||
use BelongsToUser,
|
||||
WechatAttribute;
|
||||
|
||||
const SEX = [
|
||||
'0' => '未知',
|
||||
'1' => '男',
|
||||
'2' => '女',
|
||||
];
|
||||
|
||||
/**
|
||||
* Notes : 小程序关联
|
||||
*
|
||||
* @Date : 2021/6/10 3:40 下午
|
||||
* @Author : Mr.wang
|
||||
* @return HasOne
|
||||
*/
|
||||
public function mini(): HasOne
|
||||
{
|
||||
return $this->hasOne(UserWechatMini::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 公众号关联
|
||||
*
|
||||
* @Date : 2021/6/10 3:40 下午
|
||||
* @Author : Mr.wang
|
||||
* @return HasOne
|
||||
*/
|
||||
public function official(): HasOne
|
||||
{
|
||||
return $this->hasOne(UserWechatOfficial::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : app关联
|
||||
*
|
||||
* @Date : 2021/6/10 3:40 下午
|
||||
* @Author : Mr.wang
|
||||
* @return HasOne
|
||||
*/
|
||||
public function app(): HasOne
|
||||
{
|
||||
return $this->hasOne(UserWechatApp::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes : 获取性别信息
|
||||
*
|
||||
* @Date : 2021/12/1 14:35
|
||||
* @Author : Mr.wang
|
||||
* @return string
|
||||
*/
|
||||
public function getSexAttribute(): string
|
||||
{
|
||||
return self::SEX[$this->sex] ?? '未知';
|
||||
}
|
||||
|
||||
}
|
||||
16
modules/User/Models/UserWechatApp.php
Normal file
16
modules/User/Models/UserWechatApp.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Models\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class UserWechatApp extends Model
|
||||
{
|
||||
|
||||
public function userWechat(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(UserWechat::class);
|
||||
}
|
||||
|
||||
}
|
||||
16
modules/User/Models/UserWechatMini.php
Normal file
16
modules/User/Models/UserWechatMini.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Models\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class UserWechatMini extends Model
|
||||
{
|
||||
|
||||
public function userWechat(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(UserWechat::class);
|
||||
}
|
||||
|
||||
}
|
||||
19
modules/User/Models/UserWechatOfficial.php
Normal file
19
modules/User/Models/UserWechatOfficial.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Models\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class UserWechatOfficial extends Model
|
||||
{
|
||||
public $dates = [
|
||||
'subscribe_at'
|
||||
];
|
||||
|
||||
public function userWechat(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(UserWechat::class);
|
||||
}
|
||||
|
||||
}
|
||||
10
modules/User/Models/UserWechatSubscribe.php
Normal file
10
modules/User/Models/UserWechatSubscribe.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\User\Models;
|
||||
|
||||
use App\Models\Model;
|
||||
|
||||
class UserWechatSubscribe extends Model
|
||||
{
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user