阶段更新

This commit is contained in:
2023-01-12 14:47:38 +08:00
parent 088dd64b2f
commit 5b8901281c
626 changed files with 39326 additions and 12 deletions

17
modules/User/.styleci.yml Normal file
View File

@@ -0,0 +1,17 @@
risky: false
version: 7.4
preset: laravel
tab-width: 4
use-tabs: false
#enabled:
# - "align_phpdoc"
disabled:
- "unalign_equals"
- "no_blank_lines_after_class_opening"
- "no_blank_lines_after_phpdoc"

View File

@@ -0,0 +1,128 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| 模块名称
|--------------------------------------------------------------------------
*/
'name' => 'User',
//h5设置
'web' => [
'base' => env('USER_WEB_BASE', '')
],
//体验官配置
'experience' => [
'end_at' => '2022-08-31',//截止时间
'service' => [
'bank' => '中国银行深圳证券交易所支行',
'bank_no' => '762773656978',
],
],
//身份id
'identities' => [
'experience' => 2,
'jk' => 3,
'nk' => 4,
'cs' => 5,
'hhr' => 6,
],
/*
|--------------------------------------------------------------------------
| 后台是否显示新增用户按钮
|--------------------------------------------------------------------------
*/
'create_user_by_admin' => env('USER_CREATE_BY_ADMIN', true),
/*
|--------------------------------------------------------------------------
| 后台是否显示新增用户按钮
|--------------------------------------------------------------------------
*/
'edit_user_by_admin' => env('USER_EDIT_BY_ADMIN', true),
/*
|--------------------------------------------------------------------------
| 开启用户基础数据的缓存
|--------------------------------------------------------------------------
*/
'cache_user' => env('USER_USE_CACHE', false),
/*
|--------------------------------------------------------------------------
| 缓存用户的配置
|--------------------------------------------------------------------------
*/
'cache_config' => [
'cache_ttl' => env('CACHE_USER_TTL', 3600),
'cache_channel' => env('CACHE_USER_CHANNEL', 'every'),
'model_with' => env('CACHE_USER_MODEL_WITH'),
],
/*
|--------------------------------------------------------------------------
| 用户默认的头像地址
|--------------------------------------------------------------------------
*/
'avatar' => env('USER_DEFAULT_AVATAR', ''),
/*
|--------------------------------------------------------------------------
| 默认推荐用ID
|--------------------------------------------------------------------------
*/
'default_parent_id' => 0,
/*
|--------------------------------------------------------------------------
| 推广码的加密配置
|--------------------------------------------------------------------------
*/
'invite_code' => [
'url' => env('USER_INVITE_URL', ''),
'salt' => 'Uz.Tech',
'length' => 10,
],
/*
|--------------------------------------------------------------------------
| 社会化登录平台配置(暂时加入支付宝,微信,抖音的配置信息)
|--------------------------------------------------------------------------
*/
'socialite' => [
'alipay' => [
'client_id' => env('ALIPAY_CLIENT_ID', ''),
'rsa_private_key' => env('RSA_PRIVATE_KEY', ''),
'redirect' => '',
],
'douyin' => [
'client_id' => env('DOUYIN_CLIENT_ID', ''),
'client_secret' => env('DOUYIN_CLIENT_SECRET', ''),
'redirect' => '',
],
'wechat' => [
'client_id' => env('WECHAT_CLIENT_ID', ''),
'client_secret' => env('WECHAT_CLIENT_SECRET', ''),
'redirect' => '',
// 开放平台 - 第三方平台所需
'component' => [
// or 'app_id', 'component_app_id' as key
'id' => '',
// or 'app_token', 'access_token', 'component_access_token' as key
'token' => '',
],
],
'unicloud' => [
'key' => env('UNICLOUD_API_KEY', ''),
'secret' => env('UNICLOUD_API_SECRET', ''),
'self_secret' => env('UNICLOUD_SELF_SECRET', ''),
'domain' => env('UNICLOUD_DOMAIN', ''),
'cloud_function_url' => [
'one_key' => env('UNICLOUD_FUNCTION_URL_ONE_KEY', ''),
],
],
],
];

View File

@@ -0,0 +1,26 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| 用户是否可以拥有多个身份
|--------------------------------------------------------------------------
*/
'can_has_many_identity' => false,
'conditions' => [
'price' => '开通金额',
'cost' => '原价',
],
'rules' => [
],
'show_rules' => [
'open_get_goods' => '获得产品',
],
'stars' => [
'1' => '1星',
'2' => '2星',
'3' => '3星',
'4' => '4星',
'5' => '5星',
]
];

View File

@@ -0,0 +1,57 @@
<?php
namespace Modules\User\Console\Commands;
use App\Notifications\SystemUpdateCase;
use Illuminate\Console\Command;
use Modules\User\Models\Sign;
class AutoRemindUserCase extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'xuanchen:auto-remind-user-case';
/**
* The console command description.
*
* @var string
*/
protected $description = '自动提醒用户上传报告';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
Sign::query()
->whereHas('user', function ($q) {
$q->whereHas('identityMiddle', function ($q) {
$q->whereIn('identity_id', [2, 3, 4, 5, 6]);
});
})
->where('need_case', 1)
->where('is_finish', 1)
->chunkById(1000, function ($signs) {
foreach ($signs as $key => $sign) {
$sign->user->notify(new SystemUpdateCase());
}
});
}
}

View File

@@ -0,0 +1,70 @@
<?php
namespace Modules\User\Console\Commands;
use App\Notifications\SystemRemindUserSign;
use Illuminate\Console\Command;
use Modules\User\Models\Identity;
use Modules\User\Models\SignConfig;
use Modules\User\Models\User;
class AutoRemindUserSign extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'xuanchen:auto-remind-user-sign';
/**
* The console command description.
*
* @var string
*/
protected $description = '自动提醒用户签到打卡';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$tyIdentity = Identity::query()->ty()->first();
if ($tyIdentity) {
User::query()
->with('sign')
->whereHas('identityMiddle', function ($q) {
$q->whereIn('identity_id', [2, 3, 4, 5, 6]);
})
->whereHas('sign', function ($q) {
$q->where('is_finish', 0);
})
->where(function ($query) {
$query->whereDoesntHave('signLogs')
->orWhereHas('signLogs', function ($q) {
$q->whereDate('date', '<>', now()->format('Y-m-d'))->orWhere;
});
})
->chunkById(1000, function ($users) {
foreach ($users as $user) {
$user->notify(new SystemRemindUserSign());
}
});
}
}
}

View File

@@ -0,0 +1,57 @@
<?php
namespace Modules\User\Console\Commands;
use Illuminate\Console\Command;
use Modules\User\Models\Identity;
use Modules\User\Models\IdentityLog;
use Modules\User\Models\IdentityMiddle;
class UserIdentityOver extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'xuanchen:auto-set-user-identity-over';
/**
* The console command description.
*
* @var string
*/
protected $description = '检查会员是否过期';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$identity = Identity::query()->where('default', 1)->first();
if ($identity) {
IdentityMiddle::query()
->whereNotNull('ended_at')
->where('ended_at', '<', now())
->chunkById(1000, function ($middles) use ($identity) {
foreach ($middles as $middle) {
$middle->user->joinIdentity($identity->id, IdentityLog::CHANNEL_SYSTEM);
}
});
}
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace Modules\User\Console;
use Illuminate\Console\Scheduling\Schedule;
class Kernel
{
public function runCommand(Schedule $schedule)
{
$schedule->command('xuanchen:auto-set-user-identity-over')->everyMinute();
}
}

View File

@@ -0,0 +1,41 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUserAccountLogsTable extends Migration
{
/**
* Run the migrations.
* @return void
*/
public function up()
{
Schema::create('user_account_logs', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('account_id');
$table->unsignedBigInteger('rule_id');
$table->string('type', 50)->nullable();
$table->decimal('amount');
$table->decimal('balance');
$table->boolean('frozen')->default(0);
$table->string('remark')->nullable();
$table->json('source')->nullable();
$table->timestamp('settle_at')->nullable()->comment('列入结算日期');
$table->timestamp('frozen_at')->nullable()->comment('可解冻时间');
$table->timestamps();
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
Schema::dropIfExists('user_account_logs');
}
}

View File

@@ -0,0 +1,39 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUserAccountRulesTable extends Migration
{
/**
* Run the migrations.
* @return void
*/
public function up()
{
Schema::create('user_account_rules', function (Blueprint $table) {
$table->id();
$table->string('title', 50);
$table->string('name', 50);
$table->string('type', 50);
$table->decimal('variable')->default(0);
$table->integer('trigger')->default(0);
$table->boolean('deductions');
$table->string('remark', 200);
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
Schema::dropIfExists('user_account_rules');
}
}

View File

@@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUserAccountsTable extends Migration
{
/**
* Run the migrations.
* @return void
*/
public function up()
{
Schema::create('user_accounts', function (Blueprint $table) {
$table->unsignedBigInteger('user_id')->primary();
$table->decimal('balance', 20, 2)->default(0);
$table->decimal('score', 20, 2)->default(0);
$table->decimal('coins', 20, 2)->default(0);
$table->decimal('other', 20, 2)->default(0);
$table->timestamps();
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
Schema::dropIfExists('user_accounts');
}
}

View File

@@ -0,0 +1,37 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUserCertificationsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('user_certifications', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id')->index();
$table->boolean('verified')->default(0);
$table->string('name', 32);
$table->string('id_card', 32)->index();
$table->string('front_card')->nullable();
$table->string('back_card')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('user_certifications');
}
}

View File

@@ -0,0 +1,55 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUserIdentitiesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('user_identities', function (Blueprint $table) {
$table->id();
$table->string('name')->comment('身份名称');
$table->string('cover')->nullable()->comment('身份的LOGO');
$table->string('description')->nullable()->comment('简介');
$table->integer('stock')->default(0)->comment('水的库存');
$table->unsignedInteger('order')->default(0)->comment('展示排序');
$table->json('conditions')->nullable()->comment('升级的条件JSON');
$table->json('rules')->nullable()->comment('身份权益JSON');
$table->json('rights')->nullable()->comment('前台显示的权益');
$table->json('ruleshows')->nullable()->comment('前台显示的权益');
$table->tinyInteger('can_buy')->default(0)->comment('是否可以前台购买');
$table->tinyInteger('years')->default(0)->comment('有效期(年)');
$table->boolean('status')->default(0);
$table->boolean('serial_open')->default(0)->comment('是否开启身份编号');
$table->unsignedInteger('serial_places')->default(0)->comment('身份编号位数');
$table->string('serial_prefix', 4)->nullable()->comment('身份编号前缀');
$table->string('protocol_url')->nullable()->comment('协议地址');
$table->boolean('default')->default(0)->comment('是否默认身份');
$table->tinyInteger('channel')->default(1)->comment('缴费渠道');
$table->integer('total')->default(0)->comment('可开通总数');
$table->tinyInteger('job')->default(0)->comment('职位');
$table->timestamp('end_at')->nullable()->comment('结束时间');
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('user_identities');
}
}

View File

@@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUserIdentityLogsTable extends Migration
{
/**
* Run the migrations.
* @return void
*/
public function up()
{
Schema::create('user_identity_logs', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id')->comment('用户ID');
$table->unsignedBigInteger('before')->comment('变化前身份');
$table->unsignedBigInteger('after')->comment('变化后身份');
$table->string('channel', 20)->nullable()->comment('变化渠道');
$table->string('remark', 200)->nullable()->comment('备注');
$table->json('source')->nullable()->comment('附加溯源信息');
$table->timestamps();
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
Schema::dropIfExists('user_identity_logs');
}
}

View File

@@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUserIdentityTable extends Migration
{
/**
* Run the migrations.
* @return void
*/
public function up()
{
Schema::create('user_identity', function (Blueprint $table) {
$table->unsignedBigInteger('user_id')->index();
$table->unsignedBigInteger('identity_id')->index();
$table->dateTime('started_at')->nullable()->comment('身份的开始时间');
$table->dateTime('ended_at')->nullable()->comment('角色的结束时间');
$table->string('serial', '25')->nullable()->comment('身份生成的编号');
$table->timestamps();
$table->primary(['user_id', 'identity_id']);
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
Schema::dropIfExists('user_identitie');
}
}

View File

@@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUserInfosTable extends Migration
{
/**
* Run the migrations.
* @return void
*/
public function up()
{
Schema::create('user_infos', function (Blueprint $table) {
$table->unsignedInteger('user_id')->primary();
$table->string('nickname')->nullable();
$table->string('avatar')->nullable();
$table->json('extends')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
Schema::dropIfExists('user_infos');
}
}

View File

@@ -0,0 +1,44 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUserOrdersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('user_orders', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->unsignedBigInteger('identity_id');
$table->decimal('price');
$table->tinyInteger('year')->default(1)->comment('开通年限');
$table->string('state');
$table->string('name')->comment('姓名');
$table->string('card_no')->comment('银行卡号');
$table->string('cover')->comment('凭证');
$table->tinyInteger('type')->comment('1 开通 2 续费');
$table->tinyInteger('channel')->default(1)->comment('1 身份 2 体验官');
$table->timestamps();
$table->index(['user_id', 'identity_id']);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('user_orders');
}
}

View File

@@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUserRelationsTable extends Migration
{
/**
* Run the migrations.
* @return void
*/
public function up()
{
Schema::create('user_relations', function (Blueprint $table) {
$table->unsignedInteger('user_id')->primary();
$table->unsignedInteger('parent_id')->default(0)->comment('上级用户ID');
$table->unsignedInteger('layer')->default(1)->comment('所在层级');
$table->longText('bloodline')->nullable()->comment('血缘线');
$table->timestamps();
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
Schema::dropIfExists('user_relations');
}
}

View File

@@ -0,0 +1,33 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUserServiceIdentityTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('user_service_identity', function (Blueprint $table) {
$table->unsignedBigInteger('service_id')->index();
$table->unsignedBigInteger('identity_id')->index();
$table->timestamps();
$table->primary(['service_id', 'identity_id']);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('user_service_identity');
}
}

View File

@@ -0,0 +1,36 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUserServicesTable extends Migration
{
/**
* Run the migrations.
* @return void
*/
public function up()
{
Schema::create('user_services', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('mobile');
$table->string('cover');
$table->boolean('status');
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
Schema::dropIfExists('user_services');
}
}

View File

@@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUserSignBannersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('user_sign_banners', function (Blueprint $table) {
$table->id();
$table->boolean('type')->default(1);
$table->string('title')->nullable();
$table->string('cover')->nullable();
$table->boolean('status');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('user_sign_banners');
}
}

View File

@@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUserSignConfigsTable extends Migration
{
/**
* Run the migrations.
* @return void
*/
public function up()
{
Schema::create('user_sign_configs', function (Blueprint $table) {
$table->id();
$table->json('params')->nullable()->comment('参数');
$table->json('tasks')->nullable()->comment('参数');
$table->timestamps();
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
Schema::dropIfExists('user_sign_configs');
}
}

View File

@@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUserSignLogsTable extends Migration
{
/**
* Run the migrations.
* @return void
*/
public function up()
{
Schema::create('user_sign_logs', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id')->index();
$table->date('date');
$table->boolean('type')->default(0)->comment('0:签到,1:补签');
$table->string('remark')->nullable()->comment('预留');
$table->timestamp('created_at');
$table->unique(['user_id', 'date']);
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
Schema::dropIfExists('user_sign_logs');
}
}

View File

@@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUserSignTextsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('user_sign_texts', function (Blueprint $table) {
$table->id();
$table->string('title')->nullable();
$table->string('description')->nullable();
$table->string('sub_description')->nullable();
$table->boolean('status');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('user_sign_texts');
}
}

View File

@@ -0,0 +1,40 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUserSignsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('user_signs', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id')->index();
$table->unsignedInteger('continue_days')->default(0)->comment('连续签到天数');
$table->unsignedInteger('counts')->default(0)->comment('累计签到天数');
$table->timestamp('last_sign_at')->nullable();
$table->tinyInteger('need_case')->default(0)->comment('是否需要上传报告');
$table->timestamp('reset_at')->nullable()->comment('重置连续次数日期');
$table->tinyInteger('is_finish')->default(0)->comment('是否完成');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('user_signs');
}
}

View File

@@ -0,0 +1,38 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUserSmsConfigsTable extends Migration
{
/**
* Run the migrations.
* @return void
*/
public function up()
{
Schema::create('user_sms_configs', function (Blueprint $table) {
$table->id();
$table->boolean('debug')->default(1);
$table->string('debug_code', 16);
$table->tinyInteger('length')->default(4);
$table->tinyInteger('expires')->default(5)->comment('有效期,单位:分钟');
$table->json('template')->nullable();
$table->string('default_gateway', 16);
$table->boolean('in_use')->default(0);
$table->timestamps();
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
Schema::dropIfExists('user_sms_configs');
}
}

View File

@@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUserSmsGatewaysTable extends Migration
{
/**
* Run the migrations.
* @return void
*/
public function up()
{
Schema::create('user_sms_gateways', function (Blueprint $table) {
$table->id();
$table->string('name', 16);
$table->string('slug', 16);
$table->json('configs');
$table->timestamps();
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
Schema::dropIfExists('user_sms_gateways');
}
}

View File

@@ -0,0 +1,38 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUserSmsTable extends Migration
{
/**
* Run the migrations.
* @return void
*/
public function up()
{
Schema::create('user_sms', function (Blueprint $table) {
$table->id();
$table->string('mobile', 16);
$table->string('channel', 16)->comment('验证渠道一般对应TEMPLATE_ID');
$table->string('gateway', 16)->nullable()->comment('发送网关');
$table->string('content')->comment('短信内容,验证或通知');
$table->boolean('used')->default(0);
$table->timestamps();
$table->index(['mobile', 'channel']);
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
Schema::dropIfExists('user_sms');
}
}

View File

@@ -0,0 +1,34 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUserSocialiteConfigsTable extends Migration
{
/**
* Run the migrations.
* @return void
*/
public function up()
{
Schema::create('user_socialite_configs', function (Blueprint $table) {
$table->id();
$table->string('name', 100);
$table->string('slug', 100);
$table->json('configs')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
Schema::dropIfExists('user_socialite_configs');
}
}

View File

@@ -0,0 +1,33 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUserWechatAppsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('user_wechat_apps', function (Blueprint $table) {
$table->id();
$table->foreignId('user_wechat_id');
$table->string('openid')->unique();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('user_wechat_apps');
}
}

View File

@@ -0,0 +1,33 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUserWechatMinisTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('user_wechat_minis', function (Blueprint $table) {
$table->id();
$table->foreignId('user_wechat_id');
$table->string('openid')->unique();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('user_wechat_minis');
}
}

View File

@@ -0,0 +1,36 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUserWechatOfficialsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('user_wechat_officials', function (Blueprint $table) {
$table->id();
$table->foreignId('user_wechat_id');
$table->string('openid');
$table->boolean('subscribe')->comment('关注公众平台')->default(0);
$table->timestamp('subscribed_at')->nullable();
$table->string('subscribe_scene', 32)->comment('关注场景')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('user_wechat_officials');
}
}

View File

@@ -0,0 +1,39 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUserWechatsTable extends Migration
{
/**
* Run the migrations.
* @return void
*/
public function up()
{
Schema::create('user_wechats', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id');
$table->string('unionid')->comment('unionid')->nullable();
$table->string('nickname')->comment('微信昵称')->nullable();
$table->string('avatar')->comment('微信头像')->nullable();
$table->boolean('sex')->comment('性别')->default(0);
$table->string('country')->nullable();
$table->string('province')->nullable();
$table->string('city')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
Schema::dropIfExists('user_wechats');
}
}

View File

@@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id()->startingValue(10000);
$table->string('username')->unique();
$table->string('password')->nullable();
$table->string('remember_token')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('users');
}
}

View File

@@ -0,0 +1,45 @@
<?php
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Modules\User\Database\Seeders\UserCertificationConfigsSeeder;
class CreateUserCertificationConfigsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('user_certification_configs', function (Blueprint $table) {
$table->id();
$table->boolean('is_open')->default(0)->comment('开通第三方认证');
$table->boolean('is_ocr_open')->default(0)->comment('开通OCR认证,第三方认证开启时有效');
$table->boolean('type')->default(1);
$table->string('code')->nullable()->comment('个人认证接口code');
$table->string('url')->nullable()->comment('个人认证接口地址');
$table->string('ocr_appid')->nullable()->comment('ocr认证配置');
$table->string('ocr_secretkey')->nullable()->comment('ocr认证配置');
$table->boolean('status')->default(0);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('user_certification_configs');
Artisan::call('db:seed', [
'--class' => UserCertificationConfigsSeeder::class,
]);
}
}

View File

@@ -0,0 +1,34 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUserStocksTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('user_stocks', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->integer('stock')->comment('总数');
$table->integer('hold')->default(0)->comment('持有数量');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('user_stocks');
}
}

View File

@@ -0,0 +1,35 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUserStockLogsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('user_stock_logs', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_stock_id')->index();
$table->unsignedBigInteger('identity_id')->index();
$table->string('type')->comment('类型');
$table->integer('variable');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('user_stock_logs');
}
}

View File

@@ -0,0 +1,38 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUserPervesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('user_perves', function (Blueprint $table) {
$table->id();
$table->unsignedInteger('user_id');
$table->morphs('order');
$table->unsignedInteger('layer');
$table->unsignedInteger('parent_id');
$table->longText('bloodline');
$table->unsignedDecimal('perf', 12, 2)->default(0);
$table->string('remark')->nullable()->comment('描述');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('user_perves');
}
}

View File

@@ -0,0 +1,36 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUserIdentityCouponsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('user_identity_coupons', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->unsignedBigInteger('identity_id');
$table->unsignedBigInteger('source_id')->comment('来源用户');
$table->tinyInteger('type')->comment('获取优惠券类型');
$table->string('code')->comment('优惠券编号');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('user_identity_coupons');
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddStarToUserIdentityTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('user_identity', function (Blueprint $table) {
$table->tinyInteger('star')->default(0)->after('serial');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('user_identity', function (Blueprint $table) {
});
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddStatusToUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->boolean('status')->default(1)->comment('状态')->after('password');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
});
}
}

View File

@@ -0,0 +1,34 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUserLogsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('user_logs', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id')->index();
$table->unsignedBigInteger('admin_id')->index();
$table->string('remark')->comment('备注内容');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('user_logs');
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddStockToUserOrdersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('user_orders', function (Blueprint $table) {
$table->integer('stock')->default(0)->comment('水数量')->after('year');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('user_orders', function (Blueprint $table) {
});
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddScourceToUserOrdersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('user_orders', function (Blueprint $table) {
$table->json('source')->nullable()->after('cover');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('user_orders', function (Blueprint $table) {
});
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddTagToUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->boolean('tag')->default(1)->comment('标签')->after('status');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
});
}
}

View File

@@ -0,0 +1,39 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUserInvitesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('user_invites', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id')->index()->comment('归属人');
$table->unsignedBigInteger('active_id')->index()->comment('激活人');
$table->string('number');
$table->string('code');
$table->boolean('status')->default(1)->comment('状态');
$table->timestamp('start_at')->nullable();
$table->timestamp('end_at')->nullable();
$table->timestamp('actived_at')->nullable()->comment('激活时间');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('user_invites');
}
}

View File

@@ -0,0 +1,34 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUserSubscribesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('user_subscribes', function (Blueprint $table) {
$table->id();
$table->string('unionid')->index();
$table->string('openid')->index();
$table->string('subscribe')->default(0);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('user_subscribes');
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddChannelToUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->integer('channel_id')->nullable()->after('tag')->index();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
});
}
}

View File

@@ -0,0 +1,38 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUserChannelsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('user_channels', function (Blueprint $table) {
$table->id();
$table->string('name')->comment('渠道名称');
$table->string('cover')->nullable()->comment('封面');
$table->string('code')->unique()->comment('渠道码');
$table->string('mini_code')->nullable()->comment('小程序码');
$table->string('mini_path')->nullable()->comment('小程序路径');
$table->string('official_code')->nullable()->comment('h5码');
$table->boolean('status')->default(1);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('user_channels');
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddUserIdToMallOrderItemsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('mall_order_items', function (Blueprint $table) {
$table->unsignedBigInteger('user_id')->index()->after('id');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('mall_order_items', function (Blueprint $table) {
});
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Modules\User\Database\Seeders;
use Illuminate\Database\Seeder;
use Modules\User\Models\UserCertificationConfig;
class UserCertificationConfigsSeeder extends Seeder
{
public function run()
{
UserCertificationConfig::create([
'is_open' => 0,
'is_ocr_open' => 0,
'type' => 1,
'code' => '',
'url' => '',
'ocr_appid' => '',
'ocr_secretkey' => '',
'status' => 0,
]);
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace Modules\User\Events;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Modules\User\Models\UserCertification;
class UserCertificationSuccess
{
use Dispatchable,
SerializesModels;
/**
* 认证模型
*
* @var UserCertification
*/
public UserCertification $certification;
public function __construct(UserCertification $certification)
{
$this->certification = $certification;
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Modules\User\Events;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Modules\User\Models\Identity;
use Modules\User\Models\User;
class UserJoinIdentity
{
use Dispatchable,
SerializesModels;
/**
* 用户模型
*
* @var User
*/
public User $user;
public Identity $identity;
/**
* 创建一个事件的实例
*
* @param User $user
* @param Identity $identity
* @return void
*/
public function __construct(User $user, Identity $identity)
{
$this->user = $user;
$this->identity = $identity;
}
}

View File

@@ -0,0 +1,51 @@
<?php
namespace Modules\User\Events;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Http\Request;
use Illuminate\Queue\SerializesModels;
use Modules\User\Models\User;
class UserLoginSuccess
{
use Dispatchable,
SerializesModels;
/**
* 用户模型
*
* @var User
*/
public User $user;
/**
* 当前请求
*
* @var Request
*/
public Request $request;
/**
* 登录渠道
*
* @var string
*/
public string $gateway;
/**
* 创建一个事件的实例
*
* @param User $user
* @param Request $request
* @param string $gateway
*/
public function __construct(User $user, Request $request, string $gateway = '')
{
$this->user = $user;
$this->request = $request;
$this->gateway = $gateway;
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace Modules\User\Events;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Modules\User\Models\Order;
class UserOrderPaid implements ShouldQueue
{
use Dispatchable,
SerializesModels;
public Order $order;
/**
* UserOrderPaid 开通身份.
*
* @param Order $order
*/
public function __construct(Order $order)
{
info('UserOrderPaid');
$this->order = $order;
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Modules\User\Events;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Modules\User\Models\Identity;
use Modules\User\Models\User;
class UserRemoveIdentity
{
use Dispatchable,
SerializesModels;
/**
* 用户模型
*
* @var User
*/
public User $user;
public Identity $identity;
/**
* 创建一个事件的实例
*
* @param User $user
* @param Identity $identity
* @return void
*/
public function __construct(User $user, Identity $identity)
{
$this->user = $user;
$this->identity = $identity;
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace Modules\User\Events;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Modules\User\Models\SignLog;
class UserSignReplenishSuccess
{
use Dispatchable,
SerializesModels;
/**
* @var SignLog
*/
public SignLog $log;
public function __construct(SignLog $log)
{
$this->log = $log;
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace Modules\User\Events;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Modules\User\Models\SignLog;
class UserSignSuccess
{
use Dispatchable,
SerializesModels;
/**
* @var SignLog
*/
public SignLog $log;
public function __construct(SignLog $log)
{
$this->log = $log;
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace Modules\User\Events;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Modules\User\Models\Identity;
use Modules\User\Models\User;
class UserUpdateIdentity
{
use Dispatchable,
SerializesModels;
/**
* 用户模型
*
* @var User
*/
public User $user;
public Identity $before;
public Identity $after;
/**
* 创建一个事件的实例
*
* @param User $user
* @param Identity $before
* @param Identity $after
* @return void
*/
public function __construct(User $user, Identity $before, Identity $after)
{
$this->user = $user;
$this->before = $before;
$this->after = $after;
}
}

View File

@@ -0,0 +1,109 @@
<?php
namespace Modules\User\Facades;
use Carbon\Carbon;
use Carbon\CarbonPeriod;
use Modules\User\Models\User;
class Calendar
{
/**
* Notes : 获取日历展示图,设置每周开始为周日
*
* @Date : 2022/1/21 10:23
* @Author : Mr.wang
* @param string $date
* @return array
*/
public static function show(string $date = ''): array
{
$start = Carbon::parse($date)->startOfMonth()->startOfWeek(0)->toDateString();
$end = Carbon::parse($date)->endOfMonth()->endOfWeek(6)->toDateString();
$data = self::getBetweenDate($start, $end);
$calendar = Carbon::parse($date);
$days = $data->map(function ($today) use ($calendar) {
return [
'today' => $today->toDateString(),
'day' => (int) $today->format('j'),
'isPast' => $today->isPast(),//是否为之前的日期
'isMonth' => $today->isSameMonth($calendar),//当前月
];
});
return [
'start' => $start,
'end' => $end,
'calendar' => $days
];
}
/**
* Notes: 返回日期区间
*
* @Author: 玄尘
* @Date: 2022/2/8 16:52
* @param string $start_at 开始日期
* @param string $end_at 结束日期
*/
public static function getBetweenDate(string $start_at, string $end_at)
{
return collect(CarbonPeriod::create($start_at, $end_at));
}
/**
* Notes: 获取日期 某一天的前一天后一天
*
* @Author: 玄尘
* @Date: 2022/1/21 11:03
* @param string $today
* @param string $type
* @return string
*/
public static function day(string $today = '', string $type = ''): string
{
$variate = ['before' => -1, 'after' => 1, '' => 0][$type];
return Carbon::parse($today)->addDays($variate)->toDateString();
}
/**
* Notes: 获取日期 某一天的前一天后一天
*
* @Author: 玄尘
* @Date: 2022/1/21 11:03
* @param string $month
* @param string $type
* @return string
*/
public static function getFirstDayByMonth(string $month = '', string $type = ''): string
{
$month = Carbon::parse($month);
if ($type == 'before') {
$month = $month->subMonth();
}
if ($type == 'after') {
$month = $month->addMonth();
}
return $month->startOfMonth()->toDateString();
}
/**
* Notes: 获取年份
*
* @Author: 玄尘
* @Date: 2022/8/10 9:30
* @param $start
*/
public static function getYears($startYear)
{
$years = CarbonPeriod::years($startYear);
return $years;
}
}

View File

@@ -0,0 +1,122 @@
<?php
namespace Modules\User\Facades;
use Illuminate\Support\Arr;
use Modules\User\Models\Sms as SmsModel;
use Modules\User\Models\SmsConfig;
use Modules\User\Services\VerificationCode;
use Overtrue\EasySms\Exceptions\InvalidArgumentException;
use Overtrue\EasySms\Exceptions\NoGatewayAvailableException;
use Overtrue\EasySms\Strategies\OrderStrategy;
class Sms
{
/**
* Notes : 获取短信配置
*
* @Date : 2021/5/27 4:01 下午
* @Author : <Jason.C>
* @param string|null $key 配置的主键
* @return mixed
*/
public static function getConfig(string $key = null)
{
$model = SmsConfig::orderByDesc('in_use')->first();
$config = [
'debug' => $model->debug ?? true,
'debug_code' => $model->debug_code ?? '0000',
'length' => $model->length ?? 4,
'template' => $model->template ?? [],
'default' => [
'strategy' => OrderStrategy::class,
'gateways' => [
$model->default_gateway ?? 'aliyun',
],
],
'gateways' => [
$model->default_gateway => $model->getGateway(),
],
];
// dd($config);
if (isset($config['gateways']['aliyun'])) {
$config['gateways']['aliyun']['access_key_id'] = $config['gateways']['aliyun']['APP_ID'];
$config['gateways']['aliyun']['access_key_secret'] = $config['gateways']['aliyun']['APP_SECRET'];
$config['gateways']['aliyun']['sign_name'] = $config['gateways']['aliyun']['SIGN_NAME'];
}
return Arr::get($config, $key) ?? $config;
}
/**
* Notes : 发送验证码短信
*
* @Date : 2021/5/26 4:17 下午
* @Author : <Jason.C>
* @param string $mobile 手机号码
* @param string $channel 验证通道
* @throws InvalidArgumentException
* @throws NoGatewayAvailableException
*/
public static function sendVerificationCode(string $mobile, string $channel = 'DEFAULT')
{
$message = new VerificationCode(self::getConfig(), $channel);
if (! self::getConfig('debug')) {
app('sms')->send($mobile, $message);
}
SmsModel::create([
'mobile' => $mobile,
'channel' => $channel,
'gateway' => self::getConfig('debug') ? 'debug' : self::getConfig('default.gateways.0'),
'content' => $message->code,
]);
}
/**
* 验证短信
*
* @Author:<C.Jason>
* @Date :2018-11-07T14:26:38+0800
* @param string $mobile 手机号码
* @param string $code 验证码
* @param string $channel 验证通道
* @return bool
*/
public static function checkCode(string $mobile, string $code, string $channel = 'DEFAULT'): bool
{
$Sms = SmsModel::where('mobile', $mobile)->where('channel', $channel)->first();
if ($Sms && $Sms->content == $code) {
if ($Sms->used && ! self::getConfig('debug')) {
return false;
}
# todo 有效期判定
$Sms->used = 1;
$Sms->save();
return true;
} else {
return false;
}
}
/**
* Notes : 发送通知短信
*
* @Date : 2021/5/26 5:08 下午
* @Author : <Jason.C>
* @param string|array $mobile 接受短信的手机号
* @param string $content 短信内容
*/
public static function sendNotification($mobile, string $content)
{
# todo. 这里要实现批量发送,短信通道等操作,待测试
}
}

View File

@@ -0,0 +1,308 @@
<?php
namespace Modules\User\Facades;
use Carbon\Carbon;
use DateTime;
use Exception;
use Illuminate\Support\HigherOrderCollectionProxy;
use Modules\Gout\Models\GoutCase;
use Modules\User\Models\SignConfig;
use Modules\User\Models\SignLog;
use Modules\User\Models\User;
/**
* 用户签到
* Class UserSign
*
* @package Modules\User\Facades
*/
class UserSign
{
/**
* @param User $user
* @return array
*/
public static function signIn(User $user, $date = ''): array
{
try {
$date = Carbon::parse($date);//签到日期
$params = SignConfig::getParams();
if (! $params['open']) {
throw new Exception('签到功能未开启');
}
if (! self::canSign($user, $date)) {
throw new Exception(self::getNotSignText($user, $date));
}
$continue_days = $user->sign->continue_days;
$counts = $user->sign->counts;
if (SignLog::where('user_id', $user->id)
->whereDate('date', (clone $date)->subDay()->toDateString())
->exists()) {
$continue_days++;
} else {
$continue_days = 1;
}
$crystals = self::getSignCrystal($continue_days);
$rule_name = $params['rule_name'];
$str = "{$continue_days}天签到";
if ($crystals > 0 && $user->isExperience()) {
$user->account->rule($rule_name, 0, false, [
'frozen_at' => now()->toDateTimeString(),
'settle_at' => now()->toDateTimeString(),
'remark' => '第'.$continue_days.'天签到',
]);
$str .= ",获得{$crystals}水滴"."\n";
// $str .= '第'.$continue_days.'天签到';
}
$task_crystals = self::getTaskCrystal($continue_days);
if ($task_crystals > 0) {
// $user->account->rule($rule_name, $task_crystals, true, [
// 'frozen_at' => now()->toDateTimeString(),
// 'settle_at' => now()->toDateTimeString(),
// 'remark' => '连续签到'.$continue_days.'天',
// ]);
// $str .= '连续签到'.$continue_days.'天,获得水晶'.$task_crystals;
$str .= '连续签到'.$continue_days.'天';
}
$user->sign->update([
'continue_days' => $continue_days,
'counts' => ++$counts,
'last_sign_at' => $date,
]);
SignLog::create([
'user_id' => $user->id,
'date' => $date,
'type' => 0,
]);
return [true, $str];
} catch (Exception $e) {
return [false, $e->getMessage()];
}
}
/**
* 返回连续签到额外任务
*
* @param int $continue_days
* @return int
*/
public static function getTaskCrystal(int $continue_days = 1): int
{
$tasks = SignConfig::getTasks();
$task = $tasks->firstWhere('day', $continue_days);
return $task['number'] ?? 0;
}
public static function getNextTaskCrystal($continue_days = 1)
{
$tasks = SignConfig::getTasks();
return $tasks->where('day', ' > ', $continue_days)
->sortBy('day')
->first();
}
/**
* 返回签到奖励
*
* @param int $continue_days
* @return HigherOrderCollectionProxy|int|mixed
*/
public static function getSignCrystal(int &$continue_days = 1)
{
$params = SignConfig::getParams();
$crystals = 0;
switch ($params['type']) {
case 'single':
$crystals = $params['single_number'];
break;
case 'continuous':
$crystals = (int) $params['continuous_base'] + (int) bcmul($continue_days - 1,
$params['continuous_incremental'],
0);
break;
case 'cycle':
if ($continue_days > $params['cycle_day']) {
$continue_days -= $params['cycle_day'];
}
$crystals = (int) $params['cycle_base'] + (int) bcmul($continue_days - 1, $params['cycle_incremental'],
0);
break;
}
return $crystals;
}
/**
* Notes : 某一天是否可签到
*
* @Date : 2021/5/28 3:25 下午
* @Author : <Jason.C>
* @param User $user
* @param Carbon $date
* @return bool
*/
public static function canSign(User $user, DateTime $date): bool
{
$identityMiddle = $user->identityMiddle()->first();
$start_at = $identityMiddle->started_at;
if (! $start_at) {
$start_at = $identityMiddle->created_at;
}
return $identityMiddle->identity->order > 1 &&
Carbon::parse($date)->endOfDay()->gt($start_at) &&
! $user->IsSign($date) &&
$date->isToday();
}
/**
* Notes: 是否可以补签
*
* @Author: 玄尘
* @Date: 2022/8/12 8:51
* @param User $user
* @param DateTime $date
* @return bool
*/
public static function canReSign(User $user, DateTime $date): bool
{
$identityMiddle = $user->identityMiddle()->first();
$start_at = $identityMiddle->started_at;
if (! $start_at) {
$start_at = $identityMiddle->created_at;
}
return ! $user->IsSign($date) &&
now()->endOfDay()->gt($date) &&
! $date->isToday() &&
Carbon::parse($date)->endOfDay()->gt($start_at);
}
/**
* Notes: 获取不可打卡的信息
*
* @Author: 玄尘
* @Date: 2022/8/10 13:18
*/
public static function getNotSignText(User $user, DateTime $date)
{
$identityMiddle = $user->identityMiddle()->first();
if (SignLog::where('user_id', $user->id)->whereDate('date', $date)->exists()) {
return '今日已打卡';
}
if ($identityMiddle->identity->order < 2) {
return '未开通会员';
}
$started_at = $identityMiddle->started_at;
if (! $started_at) {
$started_at = $identityMiddle->created_at;
}
if ($started_at->gt(Carbon::parse($date)->startOfDay())) {
return '当前时间还未开通会员';
}
}
/**
* Notes : 补签
*
* @Date : 2021/5/28 3:15 下午
* @Author : <Jason.C>
* @param User $user
* @param DateTime $date
* @return bool
* @throws Exception
*/
public static function replenish(User $user, DateTime $date): array
{
if (! self::canReSign($user, $date)) {
throw new Exception(self::getNotSignText($user, $date));
}
$params = SignConfig::getParams();
$continue_days = $user->sign->continue_days;
$crystals = self::getSignCrystal($continue_days);
$rule_name = $params['rule_name'];
$str = $date->format('Y-m-d')."号补签";
if ($crystals > 0 && $user->isExperience()) {
$user->account->rule($rule_name, 0, false, [
'frozen_at' => now()->toDateTimeString(),
'settle_at' => now()->toDateTimeString(),
'remark' => now()->toDateTimeString().'天补签到',
]);
$str .= ",获得{$crystals}水滴"."\n";
}
$counts = $user->sign->counts;
$user->sign->update([
'counts' => ++$counts,
]);
$log = SignLog::create([
'user_id' => $user->id,
'date' => $date,
'type' => 1,
]);
self::recalculateContinueDays($user);
return [true, $str];
}
/**
* Notes: 重新计算连续签到日期
*
* @Author: 玄尘
* @Date: 2022/8/4 9:34
*/
public static function recalculateContinueDays(User $user)
{
$reset_at = $user->sign->reset_at;
$days = SignLog::query()
->byUser($user)
->when($reset_at, function ($q) use ($reset_at) {
$q->where('date', '>=', $reset_at);
})
->latest('date')
->pluck('date');
$continue_days = 1;
foreach ($days as $key => $day) {
if (isset($days[$key + 1])) {
if ($day->subDay()->isSameDay($days[$key + 1])) {
$continue_days++;
} else {
break;
}
}
}
$user->sign->update([
'continue_days' => max($continue_days, 1),
'counts' => $user->signLogs()->count()
]);
return true;
}
}

View File

@@ -0,0 +1,80 @@
<?php
namespace Modules\User\Http\Controllers\Admin;
use Encore\Admin\Controllers\AdminController;
use Encore\Admin\Grid;
use Modules\User\Models\Account;
use Modules\User\Models\AccountLog;
class AccountController extends AdminController
{
protected $title = '用户账户';
public function grid(): Grid
{
$grid = new Grid(new Account());
$grid->model()->orderByDesc('user_id');
$grid->filter(function (Grid\Filter $filter) {
$filter->column(1 / 3, function (Grid\Filter $filter) {
$filter->like('user.username', '用户名');
});
$filter->column(1 / 3, function (Grid\Filter $filter) {
$filter->like('user.info.nickname', '用户昵称');
});
});
$grid->disableActions();
$grid->disableCreateButton();
$grid->model()->with(['user.info']);
$grid->column('user.username', '用户名');
$grid->column('用户昵称')->display(function () {
return $this->user->info->nickname;
});
$grid->column('balance', '余额');
$grid->column('score', '水滴');
// $grid->column('coins');
// $grid->column('other');
$grid->column('updated_at', '更新时间');
$grid->column('账户日志')->display(function () {
return '账户日志';
})->link(function () {
return route('admin.user.account.logs', $this);
}, '_self');
return $grid;
}
public function detail($id): Grid
{
$grid = new Grid(new AccountLog());
$grid->disableCreateButton();
$grid->disableActions();
if (is_numeric($id)) {
$grid->model()->where('account_id', $id);
} else {
$grid->column('用户')
->display(function () {
return $this->account->user->username."({$this->account->user->info->nickname})";
});
}
$grid->column('type', '账户类型');
$grid->column('rule.title', '账变规则');
$grid->column('amount', '账变金额');
$grid->column('balance', '当期余额');
$grid->column('remark', '备注');
$grid->column('source', '详情')->hide();
$grid->column('created_at', '账变时间');
return $grid;
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace Modules\User\Http\Controllers\Admin\Actions;
use Encore\Admin\Actions\Response;
use Encore\Admin\Actions\RowAction;
use Encore\Admin\Facades\Admin;
use Illuminate\Http\Request;
use Modules\User\Models\User;
class AddUserRemark extends RowAction
{
public $name = '增加备注';
public function handle(User $user, Request $request): Response
{
try {
$user->addLog(Admin::user(), $request->remark);
return $this->response()->success('添加备注成功')->refresh();
} catch (\Exception $exception) {
return $this->response()->error($exception->getMessage())->refresh();
}
}
public function form(User $user)
{
$this->textarea('remark', '备注')->required();
}
}

View File

@@ -0,0 +1,75 @@
<?php
namespace Modules\User\Http\Controllers\Admin\Actions;
use Encore\Admin\Actions\Action;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Modules\User\Models\User;
use Modules\User\Models\UserInvite;
class AllotCard extends Action
{
protected $selector = '.report-posts';
public function handle(Request $request)
{
$request->validate([
'startNum' => 'required|integer|min:1|lte:endNum',
'endNum' => 'required|integer|min:1',
], [
'startNum.required' => '开始号码必须填写',
'startNum.integer' => '开始号码必须是整数',
'startNum.min' => '开始号码最小为1',
'startNum.lte' => '开始号码要小于结束号码',
'endNum.required' => '结束号码必须填写',
'endNum.integer' => '结束号码必须是整数',
'endNum.min' => '结束号码最小为1',
]);
$response = $this->response();
$startNum = $request->startNum ?: 0;
$endNum = $request->endNum ?: 0;
$user_id = $request->user_id;
// $startNum = sprintf("%'.08d", $startNum);
// $endNum = sprintf("%'.08d", $endNum++);
$isActive = UserInvite::whereBetween('id', [$startNum, $endNum])->where('status', '!=', 1)->value('code');
if ($isActive) {
$response->status = false;
return $response->error($isActive.'不可分配');
}
UserInvite::whereBetween('id', [$startNum, $endNum])->update([
'user_id' => $user_id,
'status' => UserInvite::STATUS_ALLOT,
]);
return $response->success('卡分配完毕')->refresh();
}
public function form()
{
$users = User::leftJoin('user_infos as info', 'users.id', '=', 'info.user_id')
// ->whereHas('identities', function ($q) {
// $q->where('id', 6);
// })
->select('id', DB::raw('CONCAT(username, " [", info.nickname, "]") as text'))
->pluck('text', 'id');
$this->select('user_id', '会员')
->options($users)
->required();
$this->text('startNum', '开始')->rules('required|integer|min:1');
$this->text('endNum', '结束')->rules('required|integer|min:1');
}
public function html()
{
return "<a class='report-posts btn btn-sm btn-danger'><i class='fa fa-info-circle'></i>分配激活码</a>";
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Modules\User\Http\Controllers\Admin\Actions\Certification;
use Encore\Admin\Actions\RowAction;
use Illuminate\Database\Eloquent\Model;
use Modules\User\Models\UserCertificationConfig;
class ConfigPublish extends RowAction
{
public $name = '使用配置';
public function handle(Model $model)
{
UserCertificationConfig::where('id', '<>', $model->id)->update(['status' => 0]);
$model->status = 1;
$model->save();
return $this->response()->success('发布配置完成')->refresh();
}
public function dialog()
{
$this->confirm('确定使用配置么?');
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace Modules\User\Http\Controllers\Admin\Actions\Certification;
use Encore\Admin\Actions\RowAction;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
class Replicate extends RowAction
{
public $name = '复制配置';
public function handle(Model $model)
{
try {
DB::transaction(function () use ($model) {
$new = $model->replicate();
$new->status = 0;
$new->save();
});
return $this->response()->success('复制菜单完成')->refresh();
} catch (\Exception $exception) {
return $this->response()->error('复制菜单出错了')->refresh();
}
}
public function dialog()
{
$this->confirm('确定复制配置么?');
}
}

View File

@@ -0,0 +1,70 @@
<?php
namespace Modules\User\Http\Controllers\Admin\Actions;
use Encore\Admin\Actions\Response;
use Encore\Admin\Actions\RowAction;
use Exception;
use Illuminate\Http\Request;
use Modules\User\Models\Identity;
use Modules\User\Models\Order;
use Modules\User\Models\User;
class JoinIdentity extends RowAction
{
public $name = '加入身份';
public function handle(User $user, Request $request): Response
{
try {
$identity_id = $request->join_identity_id;
$remark = $request->remark;
$identity = Identity::find($identity_id);
$price = $identity->getCondition('price', '0');
$data = [
'user_id' => $user->id,
'identity_id' => $identity_id,
'year' => 1,
'type' => 1,
'stock' => $identity->stock,
'name' => '',
'card_no' => '',
'cover' => '',
'state' => Order::STATE_INIT,
'price' => $price,
];
$order = Order::create($data);
$order->pay();
//
// $user->joinIdentity($identity_id, 'System', [
// 'remark' => $remark,
// ]);
return $this->response()->success('加入身份成功')->refresh();
} catch (Exception $e) {
return $this->response()->error($e->getMessage())->refresh();
}
}
public function form(User $user)
{
$userIdentity = $user->identityFirst();
if (empty($userIdentity)) {
$identities = Identity::whereIn('order', [2, 3, 4, 5])->pluck('name', 'id');
} elseif ($userIdentity->job == Identity::JOB_YK) {
$identities = Identity::whereIn('order', [2, 3, 4, 5])->pluck('name', 'id');
} else {
$identities = Identity::where('order', '>', $userIdentity->order)->pluck('name', 'id');
}
$this->select('join_identity_id', '加入身份')
->options($identities)
->required();
$this->text('remark', '加入备注');
$this->confirm('确认加入该身份?');
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace Modules\User\Http\Controllers\Admin\Actions;
use Encore\Admin\Actions\RowAction;
class LinkJoinCsVip extends RowAction
{
public $name = '开通初始会员';
/**
* @return string
*/
public function href(): string
{
return admin_url('user/'.$this->row->id.'/join');
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace Modules\User\Http\Controllers\Admin\Actions;
use Encore\Admin\Actions\Response;
use Encore\Admin\Actions\RowAction;
use Modules\User\Models\Order;
class Pay extends RowAction
{
public $name = '已支付';
public function handle(Order $order): Response
{
try {
$order->pay();
return $this->response()->success('支付状态调整成功')->refresh();
} catch (\Exception $exception) {
return $this->response()->error($exception->getMessage())->refresh();
}
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace Modules\User\Http\Controllers\Admin\Actions;
use Encore\Admin\Actions\Response;
use Encore\Admin\Actions\RowAction;
use Modules\User\Models\Order;
class Refund extends RowAction
{
public $name = '退款';
public function handle(Order $order): Response
{
try {
$order->refund();
return $this->response()->success('退款成功')->refresh();
} catch (\Exception $exception) {
return $this->response()->error($exception->getMessage())->refresh();
}
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace Modules\User\Http\Controllers\Admin\Actions;
use Encore\Admin\Actions\Response;
use Encore\Admin\Actions\RowAction;
use Exception;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Modules\User\Models\Identity;
use Modules\User\Models\IdentityLog;
class RemoveIdentity extends RowAction
{
public $name = '移除身份';
public function handle(Model $user, Request $request): Response
{
try {
$identity_id = $request->remove_identity_id;
$remark = $request->remark;
$user->removeIdentity($identity_id, 'System', [
'remark' => $remark,
]);
$defaultIdentity = Identity::where('default', 1)->first();
if ($defaultIdentity) {
$user->joinIdentity($defaultIdentity->id, IdentityLog::CHANNEL_SYSTEM);
}
return $this->response()->success('移除身份成功')->refresh();
} catch (Exception $e) {
return $this->response()->error($e->getMessage())->refresh();
}
}
public function form(Model $model)
{
$this->select('remove_identity_id', '移除身份')
->options(Identity::whereIn('id', $model->identities()->get()->pluck('id'))
->pluck('name', 'id'))
->required();
$this->text('remark', '移除说明');
$this->confirm('确认移除该身份?');
}
}

View File

@@ -0,0 +1,41 @@
<?php
namespace Modules\User\Http\Controllers\Admin\Actions;
use Encore\Admin\Actions\Response;
use Encore\Admin\Actions\RowAction;
use Exception;
use Illuminate\Http\Request;
use Modules\User\Models\Identity;
use Modules\User\Models\Order;
use Modules\User\Models\User;
class SetTag extends RowAction
{
public $name = '设置标签';
public function handle(User $user, Request $request): Response
{
try {
$tag = $request->tag;
$user->update([
'tag' => $tag
]);
return $this->response()->success('加入标签成功')->refresh();
} catch (Exception $e) {
return $this->response()->error($e->getMessage())->refresh();
}
}
public function form(User $user)
{
$this->select('tag', '标签')
->options(User::TAGS)
->required();
$this->confirm('确认加入该标签?');
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace Modules\User\Http\Controllers\Admin\Actions;
use Encore\Admin\Actions\Response;
use Encore\Admin\Actions\RowAction;
use Exception;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
class UpdateRelation extends RowAction
{
public $name = '变更隶属';
public function handle(Model $model, Request $request): Response
{
try {
if ($model->updateParent($request->parent_id)) {
return $this->response()->success('变更成功')->refresh();
} else {
return $this->response()->error('变更失败')->refresh();
}
} catch (Exception $exception) {
return $this->response()->error($exception->getMessage())->refresh();
}
}
public function form()
{
$this->text('parent_id', '目标ID');
$this->confirm('确认变更隶属?');
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace Modules\User\Http\Controllers\Admin\Actions;
use Encore\Admin\Actions\Response;
use Encore\Admin\Actions\RowAction;
use Modules\User\Models\User;
class UserStatusInit extends RowAction
{
public $name = '正常';
public function handle(User $user): Response
{
try {
$user->update([
'status' => User::STATUS_INIT
]);
return $this->response()->success('设置成功')->refresh();
} catch (\Exception $exception) {
return $this->response()->error($exception->getMessage())->refresh();
}
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace Modules\User\Http\Controllers\Admin\Actions;
use Encore\Admin\Actions\Response;
use Encore\Admin\Actions\RowAction;
use Modules\User\Models\User;
class UserStatusRefund extends RowAction
{
public $name = '已退费';
public function handle(User $user): Response
{
try {
$user->update([
'status' => User::STATUS_REFUND
]);
return $this->response()->success('设置成功')->refresh();
} catch (\Exception $exception) {
return $this->response()->error($exception->getMessage())->refresh();
}
}
}

View File

@@ -0,0 +1,68 @@
<?php
namespace Modules\User\Http\Controllers\Admin;
use Encore\Admin\Controllers\AdminController;
use Encore\Admin\Form;
use Encore\Admin\Grid;
use Modules\User\Http\Controllers\Admin\Actions\Certification\ConfigPublish;
use Modules\User\Http\Controllers\Admin\Actions\Certification\Replicate;
use Modules\User\Models\UserCertificationConfig;
class CertificationConfigController extends AdminController
{
protected $title = '认证配置';
protected function grid(): Grid
{
$grid = new Grid(new UserCertificationConfig());
$grid->disableFilter();
$grid->model()->orderBy('id', 'desc');
$grid->actions(function ($action) {
$action->disableView();
$action->add(new Replicate);
if ($this->row->status == 0) {
$action->add(new ConfigPublish);
} else {
$action->disableEdit();
$action->disableDelete();
}
});
$grid->column('id', 'ID');
$grid->column('配置HASH')->display(function () {
return md5($this->created_at);
});
$grid->column('is_open', '开通网络认证')->bool();
$grid->column('is_ocr_open', '开通OCR认证')->bool();
$grid->column('type', '认证类型')
->using(UserCertificationConfig::TYPE)
->label();
$grid->column('status', '状态')->bool();
$grid->column('created_at', '创建时间');
return $grid;
}
protected function form(): Form
{
$form = new Form(new UserCertificationConfig());
$states = [
'on' => ['value' => 1, 'text' => '开启', 'color' => 'success'],
'off' => ['value' => 0, 'text' => '关闭', 'color' => 'danger'],
];
$form->switch('is_open', '开通网络认证')->states($states);
$form->switch('is_ocr_open', '开通OCR认证')->states($states);
$form->radioButton('type', '认证类型')
->options(UserCertificationConfig::TYPE)
->required();
$form->password('code', '阿里云code')->help('开启认证时必填');
$form->url('url', '阿里云接口地址')->help('开启OCR认证时必填');
$form->text('ocr_appid', 'OCRAPPID')->help('开启OCR认证时必填');
$form->password('ocr_secretkey', 'OCRSecret')->help('开启OCR认证时必填');
return $form;
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace Modules\User\Http\Controllers\Admin;
use Encore\Admin\Controllers\AdminController;
use Encore\Admin\Grid;
use Modules\User\Models\UserCertification;
class CertificationController extends AdminController
{
protected $title = '认证记录';
protected function grid(): Grid
{
$grid = new Grid(new UserCertification());
$grid->disableCreateButton();
$grid->disableActions();
$grid->filter(function (Grid\Filter $filter) {
$filter->column(1 / 3, function (Grid\Filter $filter) {
$filter->like('name', '姓名');
});
$filter->column(1 / 3, function (Grid\Filter $filter) {
$filter->equal('id_card', '身份证号');
});
});
$grid->column('id', '#ID#');
$grid->column('name', '姓名');
$grid->column('id_card', '身份证号');
$grid->column('created_at', '申请时间');
return $grid;
}
}

View File

@@ -0,0 +1,81 @@
<?php
namespace Modules\User\Http\Controllers\Admin;
use App\Admin\Traits\WithUploads;
use EasyWeChat\Kernel\Http\StreamResponse;
use Encore\Admin\Controllers\AdminController;
use Encore\Admin\Form;
use Encore\Admin\Grid;
use Illuminate\Support\Facades\Storage;
use Modules\User\Models\UserChannel;
class ChannelController extends AdminController
{
use WithUploads;
protected $title = '渠道管理';
public function grid(): Grid
{
$grid = new Grid(new UserChannel());
$grid->disableFilter();
$grid->column('name', '名称');
$grid->column('code', '渠道码');
$grid->column('mini_path', '小程序地址');
$grid->column('mini_code', '小程序码')->display(function () {
return Storage::url($this->mini_code);
})->image();
$grid->column('official_code', 'h5二维码')->display(function () {
return Storage::url($this->official_code);
})->image();
$grid->column('status', '状态')->bool();
return $grid;
}
protected function form(): Form
{
$form = new Form(new UserChannel());
$form->text('name', '名称')->required();
$this->cover($form);
$form->text('code', '渠道码')->required();
$form->text('mini_path', '小程序路径')->required();
$form->switch('status', '显示')->default(1);
$form->saved(function (Form $form) {
$url = 'channel/code';
$info = $form->model();
//h5
$base64_img = $info->official_code_base64;
preg_match('/^(data:\s*image\/(\w+);base64,)/', $base64_img, $res);
$base64_img = base64_decode(str_replace($res[1], '', $base64_img));
$h5Name = 'official_code_'.$info->id.'.png';
$H5path = $url.'/'.$h5Name;
Storage::put($H5path, $base64_img);
$data['official_code'] = $H5path;
//小程序
$app = app('wechat.mini_program');
$arr['channel'] = $info->code;
$str = $info->mini_path.'?'.http_build_query($arr);
$response = $app->app_code->getQrCode($str);
if ($response instanceof StreamResponse) {
$file = $response->saveAs(storage_path('app/public/'.$url), 'mini_code_'.$info->id.'.png');
$data['mini_code'] = $url.'/'.$file;
}
$form->model()->update($data);
});
return $form;
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace Modules\User\Http\Controllers\Admin;
use Encore\Admin\Controllers\AdminController;
use Encore\Admin\Form;
use Encore\Admin\Grid;
use Modules\User\Models\SmsGateway;
class GatewayController extends AdminController
{
protected $title = '短信网关';
public function grid(): Grid
{
$grid = new Grid(new SmsGateway());
$grid->disableFilter();
$grid->column('name', '网关名称');
$grid->column('slug', '网关标识');
$grid->column('created_at', '创建时间');
return $grid;
}
public function form(): Form
{
$form = new Form(new SmsGateway());
$form->text('name', '网关名称')->required();
$form->text('slug', '网关标识')->required();
$form->keyValue('configs', '网关配置')->value([
'APP_ID' => '',
'APP_SECRET' => '',
'SIGN_NAME' => '',
]);
return $form;
}
}

View File

@@ -0,0 +1,226 @@
<?php
namespace Modules\User\Http\Controllers\Admin;
use App\Admin\Traits\WithUploads;
use Encore\Admin\Controllers\AdminController;
use Encore\Admin\Form;
use Encore\Admin\Form\NestedForm;
use Encore\Admin\Grid;
use Modules\User\Models\Identity;
class IdentitiesController extends AdminController
{
use WithUploads;
protected $title = '用户身份';
public function grid(): Grid
{
$grid = new Grid(new Identity());
$grid->model()->oldest('id')->oldest('order');
$grid->filter(function (Grid\Filter $filter) {
$filter->scope('trashed', '回收站')->onlyTrashed();
$filter->column(1 / 3, function (Grid\Filter $filter) {
$filter->like('name', '身份名称');
});
$filter->column(1 / 3, function (Grid\Filter $filter) {
$filter->equal('status', '状态')->select([
0 => '禁用',
1 => '正常',
]);
});
});
$grid->model()->oldest()->withCount('users');
$grid->column('id', '#ID#');
$grid->column('cover', '展示图片')->image('', 40);
$grid->column('name', '身份名称');
$grid->column('order', '排序');
$grid->column('status', '状态')->bool();
$grid->column('serial_open', '是否开启编号')->bool();
$grid->column('serial_places', '编号长度');
$grid->column('serial_prefix', '编号前缀');
$grid->column('years', '有效期(月)')
->display(function () {
return $this->years > 0 ? $this->years : '永久';
});
$grid->column('stock', '送水(箱)');
$grid->column('users_count', '组内用户');
$grid->column('job', '身份')->using(Identity::JOBS)->label();
// $grid->column('total', '可开通总数');
$grid->column('channel', '缴费渠道')
->using(Identity::CHANNELS)
->label([
Identity::CHANNEL_ONLINE => 'primary',
Identity::CHANNEL_OFFLINE => 'success',
]);
foreach (config('identity.conditions') as $key => $title) {
$grid->column($title)->display(function () use ($key) {
return $this->getCondition($key, '无');
});
}
foreach (config('identity.rules') as $key => $title) {
$grid->column($title)->display(function () use ($key) {
return $this->getRule($key, '无');
});
}
$states = [
'on' => ['value' => 1, 'text' => '是', 'color' => 'primary'],
'off' => ['value' => 0, 'text' => '否', 'color' => 'default'],
];
$grid->column('default', '默认身份')->switch($states);
$grid->column('can_buy', '前台开通')->switch($states);
$grid->column('created_at', '创建时间');
return $grid;
}
public function form(): Form
{
$form = new Form(new Identity());
$form->text('name', '身份名称')
->required()
->rules([
'unique:Modules\User\Models\Identity,name,{{id}}',
], [
'unique' => '身份名称已经存在',
]);
$this->cover($form, 'cover', '展示图片');
$form->number('order', '排序')
->required()
->default(0);
$form->textarea('description', '身份简介')
->rules(['max:255'], [
'max' => '简介内容最大不能超过:max个字符',
]);
$form->switch('default', '默认身份')
->default(0);
$form->switch('can_buy', '前台开通')
->help('是否可以在前台开通身份')
->default(0);
$form->number('stock', '库存')
->help('开通身份送多少水')
->default(0);
$form->number('years', '有效期(月)')
->help('0未长期有效')
->default(0);
$form->switch('status', '状态')
->required()
->default(1);
$form->select('serial_open', '是否开启编号')
->options([
false => '关闭',
true => '开启',
])
->required();
$form->number('serial_places', '编号长度')
->rules([
'exclude_if:serial_open,true',
'required',
], [
'required' => '编号开启必填',
]);
$form->text('serial_prefix', '编号前缀');
$form->text('protocol_url', '协议地址')->help('显示开通身份签署的协议');
$form->radioButton('channel', '缴费渠道')
->options(Identity::CHANNELS)
->default(1);
$form->radioButton('job', '身份')
->options(Identity::JOBS)
->default(0)
->when(Identity::JOB_TY, function (Form $form) {
$form->number('total', '可开通总数')->default(100);
$form->date('end_at', '结束日期');
});
$form->divider();
$form->table('conditions', '升级条件', function (NestedForm $form) {
$form->select('name', '条件')
->required()
->options(config('identity.conditions'))
->rules('required');
$form->select('compare', '规则')
->options([
'>' => '大于',
'>=' => '大于等于',
'=' => '等于',
'<' => '小于',
'<=' => '小于等于',
])
->required()
->rules('required');
$form->text('value', '值')
->required()
->rules('required');
});
//
$form->table('rules', '身份权益', function (NestedForm $form) {
$form->select('name', '权益')
->required()
->options(config('identity.rules'))
->rules('required');
$form->select('compare', '规则')
->options([
'>' => '大于',
'>=' => '大于等于',
'=' => '等于',
'<' => '小于',
'<=' => '小于等于',
])
->required()
->rules('required');
$form->text('value', '值')
->required()
->rules('required');
});
$form->table('ruleshows', '身份权益(前台展示)', function (NestedForm $form) {
$form->image('icon', '权益图片');
$form->select('name', '权益')
->options(config('identity.show_rules'))
->required()
->rules('required');
$form->text('value', '值')
->required()
->rules('required');
});
//
$form->table('rights', '可享受权益', function (NestedForm $form) {
$form->text('name', '名称')
->required()
->rules('required');
$form->image('cover', '权益图片');
$form->text('remark', '备注')
->required()
->rules('required');
$form->number('order', '排序');
});
// $form->saving(function ($form) {
//// dd(request()->all());
// });
$form->saved(function ($form) {
$model = $form->model();
if ($model->default == 1) {
Identity::where('id', '!=', $model->id)
->where('default', 1)
->update([
'default' => 0,
]);
}
});
return $form;
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace Modules\User\Http\Controllers\Admin;
use Encore\Admin\Controllers\AdminController;
use Encore\Admin\Grid;
use Modules\User\Models\IdentityLog;
class IdentityLogController extends AdminController
{
protected $title = '身份变动记录';
public function grid(): Grid
{
$grid = new Grid(new IdentityLog());
$grid->disableActions();
$grid->disableCreateButton();
$grid->filter(function (Grid\Filter $filter) {
$filter->column(1 / 3, function (Grid\Filter $filter) {
$filter->like('user.username', '用户名');
});
$filter->column(1 / 3, function (Grid\Filter $filter) {
$filter->like('user.info.nickname', '用户昵称');
});
$filter->column(1 / 3, function (Grid\Filter $filter) {
$filter->equal('channel', '变更方式')->select(IdentityLog::CHANNEL_MAP);
});
});
$grid->column('user.username', '用户名');
$grid->column('用户昵称')->display(function () {
return $this->user->info->nickname;
});
$grid->column('before_identity.name', '变更前身份')->display(function () {
if ($this->before == 0) {
return '无';
}
return $this->before_identity->name;
});
$grid->column('after_identity.name', '变更后身份')->display(function () {
if ($this->after == 0) {
return '无';
}
return $this->after_identity->name;
});
$grid->column('channel', '变更方式')->using(IdentityLog::CHANNEL_MAP);
$grid->column('remark', '备注');
$grid->column('created_at', '变更时间');
return $grid;
}
}

View File

@@ -0,0 +1,179 @@
<?php
namespace Modules\User\Http\Controllers\Admin;
use Encore\Admin\Controllers\AdminController;
use Encore\Admin\Form;
use Encore\Admin\Grid;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Modules\User\Http\Controllers\Admin\Actions\JoinIdentity;
use Modules\User\Http\Controllers\Admin\Actions\OpenPartner;
use Modules\User\Http\Controllers\Admin\Actions\RemoveIdentity;
use Modules\User\Http\Controllers\Admin\Actions\SetTag;
use Modules\User\Http\Controllers\Admin\Actions\UpdateRelation;
use Modules\User\Models\Identity;
use Modules\User\Models\User;
use Modules\User\Models\UserChannel;
use Vinkla\Hashids\Facades\Hashids;
class IndexController extends AdminController
{
protected $title = '用户管理';
/**
* Notes : 用户管理列表
*
* @Date : 2021/3/11 1:59 下午
* @Author : <Jason.C>
* @return Grid
*/
public function grid(): Grid
{
$grid = new Grid(new User());
if (config('user.create_user_by_admin')) {
$grid->quickCreate(function (Grid\Tools\QuickCreate $create) {
$create->text('username', '用户名')->required();
$create->password('password', '登录密码')->required();
$create->text('info.nickname', '用户昵称')->required();
});
} else {
$grid->disableCreateButton();
}
$grid->actions(function (Grid\Displayers\Actions $actions) {
if (! config('user.edit_user_by_admin')) {
$actions->disableEdit();
}
$actions->disableDelete();
$actions->disableView();
$actions->add(new JoinIdentity());
$actions->add(new RemoveIdentity());
$actions->add(new UpdateRelation());
});
$grid->quickSearch('username')->placeholder('快速搜索用户名');
$grid->filter(function (Grid\Filter $filter) {
$filter->column(1 / 3, function (Grid\Filter $filter) {
$filter->like('username', '用户名');
});
$filter->column(1 / 3, function (Grid\Filter $filter) {
$filter->like('info.nickname', '用户昵称');
$filter->like('identityMiddle.serial', '会员编号(数字)');
});
$filter->column(1 / 3, function (Grid\Filter $filter) {
$filter->equal('identities.id', '身份')->select(Identity::pluck('name', 'id'));
$filter->equal('parent.username', '推荐人');
});
});
$grid->model()->withCount('addresses')->with(['info', 'parent', 'identities', 'addresses']);
$grid->column('info.avatar', '头像')->image('', 32);
$grid->column('id', '用户ID');
$grid->column('username', '用户名');
$grid->column('info.nickname', '用户昵称');
$grid->column('tag', '标签')
->using(User::TAGS)
->label([
User::TAG_USER => 'primary',
User::TAG_WALKER => 'success',
User::TAG_ACADEMY => 'danger',
]);
// $grid->column('addresses_count', '收货地址')
// ->link(function () {
// return route('admin.mall.addresses.index', ['user_id' => $this->id]);
// }, '_self');
$grid->column('推荐人')->display(function () {
return $this->parent->username ?? '无';
});
$grid->column('identities', '用户身份')
->display(function () {
$data = [];
foreach ($this->identities as $identity) {
$data[] = $identity->name.' : '.$identity->serial_prefix.$identity->getOriginal('pivot_serial');
}
return $data;
})
->label();
// $grid->column('star', '星级')
// ->display(function () {
// $data = [];
// foreach ($this->identities as $identity) {
// $data[] = $identity->getOriginal('pivot_star').' 星';
// }
//
// return $data;
// })
// ->label();
// $grid->column('是否关注')
// ->display(function () {
// return $this->isOfficialSubscribe();
// })
// ->bool();
$grid->column('邀请码')
->display(function () {
return Hashids::connection('code')->encode($this->id);
});
$grid->column('created_at', '注册时间');
return $grid;
}
/**
* Notes : 编辑表单
*
* @Date : 2021/7/15 5:09 下午
* @Author : <Jason.C>
* @return Form
* @throws Exception
*/
public function form(): Form
{
$form = new Form(new User());
if ($form->isCreating() && ! config('user.create_user_by_admin')) {
throw new Exception('不运允许添加用户');
}
if ($form->isCreating() && ! config('user.edit_user_by_admin')) {
throw new Exception('不运允许编辑用户');
}
$form->text('username', '用户名')
->required()
->rules('unique:users,username,{{id}}');
$form->password('password', '登录密码')
->required()
->rules('min:6');
$form->text('info.nickname', '用户昵称');
return $form;
}
/**
* Notes : User 列表选择, 这里没有判断,用户是否已经有店铺了,如果判断的情况,可能导致当前用户 无法被选中
*
* @Date : 2021/5/6 4:35 下午
* @Author : <Jason.C>
*/
public function ajax(Request $request)
{
$q = $request->get('q');
return User::leftJoin('user_infos as info', 'users.id', '=', 'info.user_id')
->where('username', 'like', "%$q%")
->orWhere('info.nickname', 'like', "%$q%")
->select('id', DB::raw('CONCAT(username, " [", info.nickname, "]") as text'))
->paginate();
}
}

View File

@@ -0,0 +1,115 @@
<?php
namespace Modules\User\Http\Controllers\Admin;
use Encore\Admin\Controllers\AdminController;
use Encore\Admin\Grid;
use Encore\Admin\Widgets\Box;
use Encore\Admin\Widgets\Form;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Modules\User\Http\Controllers\Admin\Actions\AllotCard;
use Modules\User\Models\UserInvite;
use Vinkla\Hashids\Facades\Hashids;
class InviteController extends AdminController
{
protected $title = '激活码管理';
protected function grid()
{
$grid = new Grid(new UserInvite());
$grid->disableCreateButton();
$grid->disableRowSelector();
$grid->disableActions();
$grid->disableColumnSelector();
$grid->tools(function (Grid\Tools $tools) {
$tools->append(new AllotCard());
});
$grid->header(function ($query) {
$form = new Form();
$form->action(admin_url('/users/invites/createCard'));
// $form->hidden('_token')->default(csrf_token());
$form->disableReset();
$form->text('num', '生成数量')->rules('required|integer|min:1');
$box = new Box('生成激活码', $form->render());
$box->collapsable();
$box->style('success');
$box->solid();
return $box->render();
});
$grid->model()->orderBy('id', 'desc');
$grid->column('id', '序号')->sortable();
// $grid->column('number', '编号')->sortable();
$grid->column('归属')->display(function () {
return ($this->user->username ?? '---')."<br>".($this->user->info->nickname ?? '---');
});
$grid->column('code', '激活码');
$grid->column('status', '状态')
->using(UserInvite::STATUS)
->label([
1 => 'warning',
2 => 'success',
3 => 'info',
]);
$grid->column('激活用户')->display(function () {
return ($this->activeUser->username ?? '---')."<br>".($this->activeUser->info->nickname ?? '---');
});
$grid->column('actived_at', '激活时间');
$grid->column('created_at', '创建时间');
$grid->filter(function (Grid\Filter $filter) {
$filter->column(1 / 3, function (Grid\Filter $filter) {
$filter->like('code', '激活码');
});
$filter->column(1 / 3, function (Grid\Filter $filter) {
$filter->like('user.username', '归属');
});
$filter->column(1 / 3, function (Grid\Filter $filter) {
$filter->equal('status', '状态')->select(UserInvite::STATUS);
});
});
return $grid;
}
public function createCard(Request $request)
{
$request->validate([
'num' => 'required|integer|min:1',
], [
'num.required' => '数量必须填写',
'num.integer' => '数量必须是整数',
'num.min' => '数量最小为1',
]);
$num = $request->num;
$codeStart = (UserInvite::max('id') ?? 0) + 1;
$data = [];
while ($num > 0) {
$data[] = [
'number' => sprintf("%'.08d", $codeStart++),
'code' => Str::random(14),
'status' => UserInvite::STATUS_INIT,
'created_at' => now(),
'updated_at' => now(),
];
--$num;
}
UserInvite::insert($data);
admin_success('成功生成', $request->num.'个码已经生成。');
return back();
}
}

View File

@@ -0,0 +1,166 @@
<?php
namespace Modules\User\Http\Controllers\Admin;
use Encore\Admin\Controllers\HasResourceActions;
use Encore\Admin\Form;
use Encore\Admin\Layout\Content;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller as AdminController;
use Illuminate\Support\MessageBag;
use Modules\User\Models\User;
class JoinCsVIpController extends AdminController
{
use HasResourceActions;
/**
* Title for current resource.
*
* @var string
*/
protected $title = '开通初始会员';
/**
* Get content title.
*
* @return string
*/
protected function title(): string
{
return $this->title;
}
/**
* Create interface.
*
* @param Content $content
* @return Content
*/
public function create(Content $content, User $user): Content
{
return $content
->title($this->title())
->description($this->description['create'] ?? trans('admin.create'))
->body($this->form($user));
}
public function form($user): Form
{
$channel = config('account.sms.template.balance');
$form = new Form(new User);
$form->tools(function (Form\Tools $tools) {
// 去掉`列表`按钮
$tools->disableList();
});
$form->display('联名卡会员账户')->default($user->account->drill);
$form->display('用户昵称')->default($user->info->nickname)->readonly();
$form->display('手机号')->default($user->username)->readonly();
$form->select('rule_id', '规则')
->options(function () {
return AccountRule::query()
->whereIn('name', [
'system_drill_in',
])
->get()
->pluck('longname', 'id');
})
->required();
$form->text('mobile', '手机号')
->value(config('account.sms.mobile'))
->disable()
->required();
$form->text('amount', '数值')->required();
$form->hidden('user_id', '用户id')->value($user->id);
$form->text('remark', '备注')->help('告知用户调整原因')->required();
$form->html(view('admin.tools.sms', compact('channel')), '验证码');
$form->setAction('/admin/user/csvip');
return $form;
}
/**
* Notes: 设置积分
*
* @Author: 玄尘
* @Date : 2021/4/26 13:52
* @param \Illuminate\Http\Request $request
*/
public function setIdentity(Request $request)
{
$validator = \Validator::make($request->all(), [
'user_id' => 'required',
'rule_id' => 'required',
'amount' => 'required|integer',
'code' => 'required',
], [
'user_id.required' => '缺少操作的用户',
'rule_id.required' => '缺少规则id',
'amount.required' => '缺少增加/减少的数值',
'amount.integer' => '数值必须是整数',
'code.required' => '缺少短信验证码',
]);
if ($validator->fails()) {
return $this->backErrorMessage($validator->errors()->first());
}
$amount = $request->amount;
$channel = $request->channel ?? config('account.sms.template.default');
$user = User::find($request->user_id);
$res = \Sms::check(config('account.sms.mobile'), $request->code, $channel);
if ($res != true) {
return $this->backErrorMessage('验证码校验失败');
}
$rule = AccountRule::find($request->rule_id);
if (! $rule) {
return $this->backErrorMessage('规则未找到');
}
if (in_array($rule->name, config('account.system_set_score.in'))) {
$res = $user->account->rule($rule->id, $amount, false, [
'expired_at' => now()->addYear(),
'remark' => '后台操作增加余额',
]);
} elseif (in_array($rule->name, config('account.system_set_score.out'))) {
if ($user->account->{$rule->type} < $amount) {
return $this->backErrorMessage('账户余额不足。扣除失败');
}
$res = $user->account->rule($rule->id, -$amount, false, [
'remark' => '后台操作扣除余额',
]);
} else {
return $this->backErrorMessage('规则出错');
}
if ($res === true) {
admin_toastr('操作完成');
return redirect()->to('/admin/users?username='.$user->username);
}
return $this->backErrorMessage('操作失败'.$res);
}
public function backErrorMessage($message)
{
$error = new MessageBag([
'title' => '错误',
'message' => $message,
]);
return back()->withInput()->with(compact('error'));
}
}

View File

@@ -0,0 +1,98 @@
<?php
namespace Modules\User\Http\Controllers\Admin;
use Encore\Admin\Controllers\AdminController;
use Encore\Admin\Form;
use Encore\Admin\Grid;
use Exception;
use Modules\User\Http\Controllers\Admin\Actions\Pay;
use Modules\User\Http\Controllers\Admin\Actions\Refund;
use Modules\User\Models\Identity;
use Modules\User\Models\Order;
class OrderController extends AdminController
{
protected $title = '升级订单';
/**
* Notes: 升级订单
*
* @Author: 玄尘
* @Date : 2021/6/7 15:19
* @return Grid
*/
public function grid(): Grid
{
try {
trait_exists('Modules\Payment\Traits\WithPayments');
$grid = new Grid(new Order());
$grid->model()->latest();
$grid->disableCreateButton();
$grid->actions(function (Grid\Displayers\Actions $actions) {
$actions->disableEdit();
$actions->disableDelete();
$actions->disableView();
if ($actions->row->canPay()) {
$actions->add(new Pay());
}
if ($actions->row->canRefund()) {
$actions->add(new Refund());
}
});
$grid->filter(function (Grid\Filter $filter) {
$filter->column(1 / 2, function (Grid\Filter $filter) {
$filter->like('user.username', '用户名');
$filter->like('user.info.nickname', '用户昵称');
});
$filter->column(1 / 2, function (Grid\Filter $filter) {
$filter->equal('identity.id', '身份')->select(function () {
return Identity::query()->where('order', '>', 1)->pluck('name', 'id');
});
$filter->equal('state', '状态')->select(Order::STATES);
});
});
$grid->column('id', '用户ID');
$grid->column('升级用户')->display(function () {
return $this->user->username."({$this->user->info->nickname})";
});
$grid->column('name', '打款人姓名');
$grid->column('cover', '打款凭证')->gallery(['width' => 60, 'height' => 60]);
$grid->column('identity.name', '开通身份');
$grid->column('price', '应打款额')->editable();
$grid->column('state', '状态')->using(Order::STATES)->label();
$grid->column('type', '类型')->using(Order::TYPES)->label();
$grid->column('coupon', '优惠券')
->display(function () {
if ($this->useCouponLog) {
return $this->useCouponLog->couponGrant->code;
} else {
return '---';
}
});
$grid->column('created_at', '升级时间');
return $grid;
} catch (Exception $exception) {
dd('Payment 模块不存在,无法加载订单数据');
}
}
public function form(): Form
{
$form = new Form(new Order());
$form->decimal('price', '金额')->required();
return $form;
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace Modules\User\Http\Controllers\Admin;
use Encore\Admin\Controllers\AdminController;
use Encore\Admin\Form;
use Encore\Admin\Grid;
use Modules\User\Models\Account;
use Modules\User\Models\AccountRule;
class RuleController extends AdminController
{
protected $title = '账变规则管理';
public function grid(): Grid
{
$grid = new Grid(new AccountRule());
$grid->disableTools();
$grid->actions(function (Grid\Displayers\Actions $actions) {
$actions->disableView();
$actions->disableDelete();
});
$grid->column('id', '#ID#');
$grid->column('title', '规则名称');
$grid->column('name', '规则关键字');
$grid->column('type', '规则账户')->using(Account::TYPES);
$grid->column('variable', '固定额度');
$grid->column('created_at', '创建时间');
$grid->column('updated_at', '更新时间');
return $grid;
}
public function form(): Form
{
$form = new Form(new AccountRule());
$form->text('title', '规则名称')->required();
if ($form->isCreating()) {
$form->text('name', '规则关键字')->required();
} else {
$form->text('name', '规则关键字')
->readonly()
->required();
}
$form->select('type', '规则账户')
->options(Account::TYPES)
->required();
$form->number('variable', '固定额度')->default(0);
$states = [
'on' => ['value' => 1, 'text' => '是', 'color' => 'success'],
'off' => ['value' => 0, 'text' => '否', 'color' => 'danger'],
];
$form->switch('deductions', '立即扣款')->states($states);
$form->textarea('remark', '描述')->required();
return $form;
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Modules\User\Http\Controllers\Admin\Selectable;
use Closure;
use Encore\Admin\Grid\Filter;
use Encore\Admin\Grid\Selectable;
use Modules\User\Models\Identity;
class Identities extends Selectable
{
public $model = Identity::class;
public static function display(): Closure
{
return function ($value) {
if (is_array($value)) {
return implode(';', array_column($value, 'name'));
}
return optional($this->identities)->name;
};
}
public function make()
{
$this->column('id', '#ID#');
$this->column('name', '身份名称');
$this->column('status', '状态')->bool();
$this->column('created_at', '时间');
$this->filter(function (Filter $filter) {
$filter->like('name', '身份名称');
});
}
}

View File

@@ -0,0 +1,51 @@
<?php
namespace Modules\User\Http\Controllers\Admin;
use App\Admin\Traits\WithUploads;
use Encore\Admin\Controllers\AdminController;
use Encore\Admin\Form;
use Encore\Admin\Grid;
use Modules\User\Http\Controllers\Admin\Selectable\Identities;
use Modules\User\Models\Service;
class ServiceController extends AdminController
{
use WithUploads;
public $title = '客服中心';
public function grid(): Grid
{
$grid = new Grid(new Service());
$grid->disableTools();
$grid->model()->with(['identities']);
$grid->column('id', '#ID#');
$grid->column('name', '姓名');
$grid->column('mobile', '联系方式');
$grid->column('status', '状态')->bool();
$grid->column('identities', '服务身份')
->belongsToMany(Identities::class);
$grid->column('created_at', '创建时间');
$grid->column('updated_at', '更新时间');
return $grid;
}
public function form(): Form
{
$form = new Form(new Service());
$form->text('name', '姓名')->required();
$form->mobile('mobile', '联系方式')->required();
$this->cover($form, 'cover', '客服二维码');
$form->switch('status', '显示')->default(1);
$form->belongsToMany('identities', Identities::class, '服务身份');
return $form;
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace Modules\User\Http\Controllers\Admin;
use App\Admin\Traits\WithUploads;
use Encore\Admin\Controllers\AdminController;
use Encore\Admin\Form;
use Encore\Admin\Grid;
use Modules\User\Models\SignBanner;
use Modules\User\Models\SignChainLog;
class SignBannerController extends AdminController
{
use WithUploads;
protected $title = '签到背景图片';
public function grid(): Grid
{
$grid = new Grid(new SignBanner());
$grid->column('id', '#ID#');
$grid->column('title', '标题');
$grid->column('cover', '封面图')->image('', 100, 100);
$grid->column('status', '状态')->bool();
return $grid;
}
public function form(): Form
{
$form = new Form(new SignBanner());
$form->text('title', '标题')->required();
$this->cover($form);
$form->switch('status', '状态')->default(1);
return $form;
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace Modules\User\Http\Controllers\Admin;
use Encore\Admin\Controllers\AdminController;
use Encore\Admin\Form;
use Encore\Admin\Layout\Content;
use Modules\User\Models\SignConfig;
use Encore\Admin\Form\EmbeddedForm;
class SignConfigController extends AdminController
{
protected $title = '签到配置管理';
public function index(Content $content)
{
return redirect(admin_url('users/signs/1/edit'));
}
public function form(): Form
{
SignConfig::firstOrCreate(['id' => 1]);
$form = new Form(new SignConfig());
$form->disableCreatingCheck();
$form->disableEditingCheck();
$form->tools(function (Form\Tools $tools) {
$tools->disableDelete();
$tools->disableView();
$tools->disableList();
});
$form->embeds('params', '配置', function (EmbeddedForm $form) {
$form->radio('open', '是否开启')->options([
0 => '关闭',
1 => '开启',
])->required();
$form->text('rule_name', '签到账变关键字')->default('');
$form->radio('show_type', '签到展示类型')
->options(SignConfig::SHOWTYPES)
->default(SignConfig::SHOWTYPES_DAY)
->required();
$form->radio('type', '签到类型')
->options(SignConfig::TYPES)
->required();
$form->number('single_number', '单次奖励')->default(0);
$form->number('continuous_base', '连续基础值')->default(0);
$form->number('continuous_incremental', '连续增量')->default(0);
$form->number('cycle_day', '周期天数')->default(0);
$form->number('cycle_base', '周期基础值')->default(0);
$form->number('cycle_incremental', '周期增量')->default(0);
});
$form->table('tasks', '特殊奖励', function ($form) {
$form->number('day', '天数')->default(0);
$form->number('number', '奖励')->default(0);
});
return $form;
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Modules\User\Http\Controllers\Admin;
use Encore\Admin\Controllers\AdminController;
use Encore\Admin\Form;
use Encore\Admin\Grid;
use Modules\User\Models\SignText;
class SignTextController extends AdminController
{
protected $title = '签到展示文字';
public function grid(): Grid
{
$grid = new Grid(new SignText());
$grid->column('id', '#ID#');
$grid->column('title', '标题');
$grid->column('description', '一级描述');
$grid->column('sub_description', '二级描述');
$grid->column('status', '状态')->bool();
return $grid;
}
public function form(): Form
{
$form = new Form(new SignText());
$form->text('title', '标题')->required();
$form->text('description', '一级描述')->required();
$form->text('sub_description', '二级描述')->required();
$form->switch('status', '状态')->default(1);
return $form;
}
}

View File

@@ -0,0 +1,54 @@
<?php
namespace Modules\User\Http\Controllers\Admin;
use Encore\Admin\Controllers\AdminController;
use Encore\Admin\Form;
use Encore\Admin\Grid;
use Modules\User\Models\SmsConfig;
use Modules\User\Models\SmsGateway;
class SmsConfigController extends AdminController
{
protected $title = '短信配置';
public function grid(): Grid
{
$grid = new Grid(new SmsConfig());
$grid->disableFilter();
$grid->model()->orderByDesc('in_use');
$grid->column('debug', '调试模式')->bool();
$grid->column('debug_code', '调试验证码');
$grid->column('length', '验证码位数');
$grid->column('expires', '有效期/分钟');
$grid->column('default_gateway', '默认网关');
$grid->column('in_use', '使用中')->bool();
$grid->column('created_at', '创建时间');
return $grid;
}
public function form(): Form
{
$form = new Form(new SmsConfig());
$form->select('default_gateway', '默认网关')->options(function () {
return SmsGateway::pluck('name', 'slug');
})->required();
$form->switch('debug', '调试模式');
$form->text('debug_code', '调试验证码')->setWidth(2)->required();
$form->number('length', '验证码位数')->default(4)->required();
$form->number('expires', '有效期/分钟')->default(5)->required();
$form->keyValue('template', '渠道模板')->value([
'DEFAULT' => '',
'LOGIN' => '',
'REGISTER' => '',
])->required();
$form->switch('in_use', '使用中');
return $form;
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace Modules\User\Http\Controllers\Admin;
use Encore\Admin\Controllers\AdminController;
use Encore\Admin\Grid;
use Modules\User\Models\Sms;
class SmsController extends AdminController
{
protected $title = '短信记录';
public function grid(): Grid
{
$grid = new Grid(new Sms());
$grid->disableCreateButton();
$grid->disableActions();
$grid->filter(function (Grid\Filter $filter) {
$filter->column(1 / 3, function (Grid\Filter $filter) {
$filter->equal('mobile', '接收手机');
});
});
$grid->column('mobile', '接收手机');
$grid->column('channel', '短信渠道');
$grid->column('gateway', '发送网关');
$grid->column('content', '短信内容');
$grid->column('used', '使用')->bool();
$grid->column('created_at', '发送时间');
return $grid;
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace Modules\User\Http\Controllers\Admin;
use Encore\Admin\Controllers\AdminController;
use Encore\Admin\Grid;
use Modules\User\Models\UserStock;
use Modules\User\Models\UserStockLog;
class StockController extends AdminController
{
protected $title = '会员库存';
/**
* Notes : 用户管理列表
*
* @Date : 2021/3/11 1:59 下午
* @Author : <Jason.C>
* @return Grid
*/
public function grid(): Grid
{
$grid = new Grid(new UserStock());
$grid->disableCreateButton();
$grid->disableActions();
$grid->filter(function (Grid\Filter $filter) {
$filter->column(1 / 3, function (Grid\Filter $filter) {
$filter->like('user.username', '用户名');
});
});
$grid->model()->withCount('logs')->with(['user.info']);
$grid->column('user.username', '用户名');
$grid->column('用户昵称')
->display(function () {
return $this->user->info->nickname;
});
$grid->column('stock', '总数');
$grid->column('hold', '提货数')
->link(function () {
return admin_url('/users/stocks/'.$this->id.'/logs');
}, '_blank');
$grid->column('剩余')
->display(function () {
return $this->residue;
});
$grid->column('created_at', '注册时间');
return $grid;
}
}

View File

@@ -0,0 +1,58 @@
<?php
namespace Modules\User\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Encore\Admin\Grid;
use Encore\Admin\Layout\Content;
use Modules\Gout\Models\GoutCase;
use Modules\User\Models\UserStock;
use Modules\User\Models\UserStockLog;
class StockLogController extends Controller
{
protected $title = '库存记录';
public function index(Content $content, UserStock $stock)
{
return $content
->header($stock->user->info->nickname)
->description('库存记录')
->body($this->grid($stock));
}
/**
* Notes : 用户管理列表
*
* @Date : 2021/3/11 1:59 下午
* @Author : <Jason.C>
* @return Grid
*/
public function grid($stock): Grid
{
$grid = new Grid(new UserStockLog());
$grid->disableCreateButton();
$grid->disableActions();
$grid->model()->where('user_stock_id', $stock->id)->with(['userStock']);
$grid->column('id', 'ID');
$grid->column('身份')
->display(function () {
if ($this->identity) {
return $this->identity->name;
} else {
return '---';
}
});
$grid->column('type', '类型')
->using(UserStockLog::TYPES)
->label();
$grid->column('variable', '数量');
$grid->column('created_at', '操作时间');
return $grid;
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace Modules\User\Http\Controllers\Api\Account;
use App\Api\Controllers\Controller;
use Illuminate\Http\Request;
use Jason\Api\Api;
use Modules\User\Http\Resources\Account\UserAccountLogCollection;
class LogController extends Controller
{
/**
* Notes:水滴
*
* @Author: 玄尘
* @Date: 2022/8/18 13:57
*/
public function score(): \Illuminate\Http\JsonResponse
{
$user = Api::user();
$logs = $user->account->logs()
->where('type', 'score')
->paginate();
$data = [
'score' => $user->account->score,
'logs' => new UserAccountLogCollection($logs)
];
return $this->success($data);
}
/**
* Notes:现金账户
*
* @Author: 玄尘
* @Date: 2022/8/19 8:37
*/
public function balance(): \Illuminate\Http\JsonResponse
{
$user = Api::user();
$logs = $user->account->logs()->where('type', 'balance')->paginate();
$yesterday = $user->account->logs()
->whereDate('created_at', now()->subDay()->toDateTime())
->where('type', 'balance')
->where('amount', '>', 0)
->sum('amount') ?? 0;
$withdraw = $user->withdraws()->sum('amount') ?? 0;
$data = [
'account' => [
'balance' => floatval($user->account->balance),
'yesterday' => floatval($yesterday),
'withdraw' => floatval($withdraw),
],
'logs' => new UserAccountLogCollection($logs)
];
return $this->success($data);
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace Modules\User\Http\Controllers\Api\Auth;
use App\Api\Controllers\Controller;
use Illuminate\Http\JsonResponse;
use Jason\Api\Api;
use Modules\User\Events\UserLoginSuccess;
use Modules\User\Http\Requests\LoginRequest;
use Modules\User\Models\User;
class LoginController extends Controller
{
/**
* Notes : 用户名密码登录
*
* @Date : 2021/3/11 5:03 下午
* @Author : <Jason.C>
* @param LoginRequest $request
* @return JsonResponse
*/
public function index(LoginRequest $request): JsonResponse
{
$credentials = [
'username' => $request->username,
'password' => $request->password,
];
$token = Api::attempt($credentials);
if ($token) {
$user = User::where('username', $request->username)->first();
event(new UserLoginSuccess($user, $request, '账号密码'));
return $this->success([
'access_token' => $token,
'token_type' => 'Bearer',
]);
} else {
return $this->failed('用户名或密码错误');
}
}
/**
* Notes : 退出登录,撤销所有令牌,这个需要配合 api:^5.0 使用
*
* @Date : 2021/9/22 11:07 上午
* @Author : <Jason.C>
* @return JsonResponse
*/
public function logout(): JsonResponse
{
$user = Api::user();
if ($user) {
$user->tokens()->delete();
}
return $this->success('');
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace Modules\User\Http\Controllers\Api\Auth;
use App\Api\Controllers\Controller;
use Illuminate\Http\JsonResponse;
use Jason\Api\Api;
use Modules\User\Events\UserLoginSuccess;
use Modules\User\Http\Requests\RegisterRequest;
use Modules\User\Models\User;
class RegisterController extends Controller
{
/**
* Notes : 注册
*
* @Date : 2021/3/14 1:24 下午
* @Author : <Jason.C>
* @param RegisterRequest $request
* @return JsonResponse
*/
public function index(RegisterRequest $request): JsonResponse
{
$username = $request->username;
$password = $request->password;
$user = User::create([
'username' => $username,
'password' => $password,
]);
$token = Api::login($user);
event(new UserLoginSuccess($user, $request, '用户注册'));
return $this->success([
'access_token' => $token,
'token_type' => 'Bearer',
]);
}
}

View File

@@ -0,0 +1,132 @@
<?php
namespace Modules\User\Http\Controllers\Api\Auth;
use App\Api\Controllers\Controller;
use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Arr;
use Jason\Api\Api;
use Modules\User\Events\UserLoginSuccess;
use Modules\User\Facades\Sms;
use Modules\User\Http\Requests\LoginSmsRequest;
use Modules\User\Http\Requests\SmsRequest;
use Modules\User\Models\User;
use Modules\User\Models\UserChannel;
use Vinkla\Hashids\Facades\Hashids;
class SmsController extends Controller
{
/**
* Notes : 获取登录短信验证码
*
* @Date : 2021/5/26 4:59 下午
* @Author : <Jason.C>
* @param SmsRequest $request
* @return JsonResponse
*/
public function send(SmsRequest $request): JsonResponse
{
$mobile = $request->mobileNo;
try {
Sms::sendVerificationCode($mobile);
if (Arr::get(Sms::getConfig(), 'debug')) {
$message = '短信发送成功,测试短信码'.Arr::get(Sms::getConfig(), 'debug_code');
} else {
$message = '短信发送成功';
}
return $this->success($message);
//
// $isExists = User::where('username', $mobile)->exists();
//
// return $this->success([
// 'new' => ! $isExists,
// 'message' => $message,
// ]);
} catch (Exception $exception) {
return $this->failed($exception->getException('aliyun')->getMessage());
}
}
/**
* Notes : 短信验证码登录
*
* @Date : 2021/7/20 10:15 上午
* @Author : <Jason.C>
* @param LoginSmsRequest $request
* @return JsonResponse
*/
public function login(LoginSmsRequest $request): JsonResponse
{
$mobileNo = $request->mobileNo;
$code = $request->code;
$invite_code = $request->invite ?? '';
$channel_code = $request->channel ?? '';//渠道
$name = $request->name ?? '';//姓名
$delivery_code = $request->delivery_code ?? '';//提货码
$channel = '';
if ($channel_code) {
$channel = UserChannel::query()
->where('code', $channel_code)
->first();
}
$parent = 0;
if ($invite_code) {
$invite = Hashids::connection('code')->decode($invite_code);
if (empty($invite)) {
return $this->failed('邀请码不正确');
}
$parent = $invite[0];
}
$check = Sms::checkCode($mobileNo, $code);
if ($check == false) {
return $this->failed('验证码不正确', 422);
}
$user = User::firstOrCreate([
'username' => $mobileNo,
], [
'parent_id' => $parent,
'channel_id' => $channel ? $channel->id : null,
'password' => 111111,
]);
$is_new = $user->wasRecentlyCreated;
$message = '';
if ($is_new) {
if ($user->parent && $parent && $user->parent->id != $parent) {
$message = "您已与用户{$user->parent->info->nickname}绑定隶属关系,此次邀请码无效";
}
}
if ($name) {
$user->info->update([
'nickname' => $name
]);
}
$token = Api::login($user);
event(new UserLoginSuccess($user, $request, '手机验证码'));
return $this->success([
'token_type' => 'Bearer',
'access_token' => $token,
'message' => $message,
'invite' => Hashids::connection('code')->encode($user->id),
'is_new' => $is_new,
]);
}
}

View File

@@ -0,0 +1,154 @@
<?php
namespace Modules\User\Http\Controllers\Api\Auth;
use App\Api\Controllers\Controller;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Modules\User\Traits\WechatTrait;
class WechatController extends Controller
{
use WechatTrait;
/**
* Notes: 获取授权的跳转地址
*
* @Author: 玄尘
* @Date : 2021/6/25 13:21
* @param Request $request
* @return mixed
*/
public function getAuthUrl(Request $request)
{
$app = app('wechat.official_account');
$pages = $request->url ?? '';
$scopes = $request->scopes ?? ['snsapi_userinfo'];
$web_url = config('user.web.base');
$redirect = $web_url.$pages;
if (! is_array($scopes)) {
$scopes = [$scopes];
}
$response = $app->oauth->scopes($scopes)->redirect($redirect);
return $this->success($response);
}
/**
* Notes: 获取jssdk
*
* @Author: 玄尘
* @Date : 2021/7/1 11:08
* @param Request $request
* @return JsonResponse
*/
public function getJsSdk(Request $request)
{
$url = $request->url;
$jsApiList = $request->jsApiList ?? [];
$openTagList = $request->openTagList ?? [];
$app = app('wechat.official_account');
if ($url) {
$app->jssdk->setUrl($url);
}
if (! is_array($jsApiList)) {
$jsApiList = [$jsApiList];
}
if (! is_array($openTagList)) {
$openTagList = [$openTagList];
}
return $this->success($app->jssdk->buildConfig($jsApiList, false, false, true, $openTagList));
}
/**
* Notes: 微信分享
*
* @Author: 玄尘
* @Date : 2021/10/26 16:52
* @param Request $request
* @return JsonResponse|mixed
* @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
* @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
* @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws \Psr\SimpleCache\InvalidArgumentException
*/
public function officialShare(Request $request)
{
$url = $request->url ?? '';
if (empty($url)) {
return $this->failed('地址必须传');
}
$app = app('wechat.official_account');
$apis = [
'updateAppMessageShareData',
'updateTimelineShareData',
// 'showOptionMenu',
// 'showMenuItems',
'showAllNonBaseMenuItem',
];
$app->jssdk->setUrl($url);
$cog = $app->jssdk->buildConfig($apis);
return $this->success($cog);
}
/**
* Notes: 获取小程序openid
*
* @Author: 玄尘
* @Date: 2022/9/26 14:17
* @return mixed|void
*/
public function getMiniOpenid(Request $request)
{
$validator = \Validator::make($request->all(), [
'code' => 'required',
], [
'code.required' => '缺少参数code',
]);
if ($validator->fails()) {
return $this->failed($validator->errors()->first());
}
$weChat = app('wechat.mini_program');
$session = $weChat->auth->session($request->code);
if (isset($session->errcode)) {
return $this->failed($session->errmsg);
}
return $this->success($session->openid);
}
/**
* Notes: 获取公众号openid
*
* @Author: 玄尘
* @Date: 2022/9/26 14:21
*/
public function getOfficialOpenid()
{
try {
$weUser = $this->getUserFromCode();
return $this->success([
'openid' => $weUser->getId()
]);
} catch (\Exception $exception) {
return $this->failed($exception->getMessage());
}
}
}

Some files were not shown because too many files have changed in this diff Show More