Commit 71605a7f authored by jinyonson's avatar jinyonson

源码

parents
APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
BROADCAST_DRIVER=log
CACHE_DRIVER=file
SESSION_DRIVER=file
SESSION_LIFETIME=120
QUEUE_DRIVER=sync
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
* text=auto
*.css linguist-vendored
*.scss linguist-vendored
*.js linguist-vendored
CHANGELOG.md export-ignore
/node_modules
/public/hot
/public/storage
/storage/*.key
/vendor
/.idea
/.vscode
/.vagrant
Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log
.env
/smg
/.php_cs.cache
/storage/api-docs/api-docs.json
/storage/api-docs/*.json
/composer.lock
/public/uploads
\ No newline at end of file
.DS_Store
phpunit.phar
/vendor
composer.phar
composer.lock
*.project
.idea/
.php_cs.cache
\ No newline at end of file
<?php
use PhpCsFixer\Config;
use PhpCsFixer\Finder;
$rules = array(
'@PSR2' => true,
'array_syntax' => array(
'syntax' => 'short',
),
'binary_operator_spaces' => array(
'align_double_arrow' => false,
'align_equals' => false,
),
'blank_line_before_return' => true,
'cast_spaces' => true,
'concat_space' => array(
'spacing' => 'none',
),
'ereg_to_preg' => true,
'method_separation' => true,
'no_blank_lines_after_phpdoc' => true,
'no_extra_consecutive_blank_lines' => true,
'no_short_bool_cast' => true,
'no_unneeded_control_parentheses' => true,
'no_unused_imports' => true,
'no_whitespace_in_blank_line' => true,
'ordered_imports' => true,
'phpdoc_align' => true,
'phpdoc_indent' => true,
'phpdoc_inline_tag' => true,
'phpdoc_no_access' => true,
'phpdoc_no_alias_tag' => array(
'type' => 'var',
),
'phpdoc_no_package' => true,
'phpdoc_order' => true,
'phpdoc_scalar' => true,
'phpdoc_separation' => true,
'phpdoc_to_comment' => true,
'phpdoc_trim' => true,
'phpdoc_types' => true,
'phpdoc_var_without_name' => true,
'self_accessor' => true,
'single_quote' => true,
'space_after_semicolon' => true,
'standardize_not_equals' => true,
'ternary_operator_spaces' => true,
'trailing_comma_in_multiline_array' => true,
'trim_array_spaces' => true,
'unary_operator_spaces' => true,
'line_ending' => true,
'blank_line_after_namespace' => true,
'no_unused_imports' => true,
);
return Config::create()->setRules($rules)
->setFinder(
Finder::create()->in(__DIR__)
->exclude('api_annotations')
->exclude('Database')
->exclude('api_annotations')
->exclude('Tests')
)
->setUsingCache(true)
->setRiskyAllowed(true);
<?php
return [
'name' => 'Base',
];
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\Schema;
class UpdateAdminMenuTables extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
\DB::table(config('admin.database.menu_table'))->where('id', 1)->update(['title' => '首页']);
\DB::table(config('admin.database.menu_table'))->where('id', 2)->update(['title' => '后台管理']);
\DB::table(config('admin.database.menu_table'))->where('id', 3)->update(['title' => '用户']);
\DB::table(config('admin.database.menu_table'))->where('id', 4)->update(['title' => '角色']);
\DB::table(config('admin.database.menu_table'))->where('id', 5)->update(['title' => '权限']);
\DB::table(config('admin.database.menu_table'))->where('id', 6)->update(['title' => '菜单']);
\DB::table(config('admin.database.menu_table'))->where('id', 7)->update(['title' => '操作日志']);
try {
\Schema::table(config('admin.database.menu_table'), function ($table) {
$table->string('uri', 150)->nullable()->change();
$table->unique('uri');
});
} catch (\Exception $e) {
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
}
}
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddExtInfoToUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('avatar')->nullable()->comment("用户头像");
//$table->string('introduction')->nullable()->comment('用户说明');
$table->string('phone')->nullable()->unique()->after('name')->comment("用户手机号");
$table->string('email')->nullable()->change();
$table->string('name')->nullable()->change();
$table->tinyInteger('sex')->default(0)->comment('性别');
$table->json('ext')->nullable()->comment('用户扩展信息');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('avatar');
//$table->dropColumn('introduction');
$table->dropColumn('phone');
$table->dropColumn('sex');
$table->string('email')->nullable(false)->change();
$table->string('name')->nullable(false)->change();
});
}
}
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateFilesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('files', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->index()->comment('用户ID');
$table->string('type')->index()->comment('文件类型');
$table->string('path')->comment('文件路径');
$table->integer('size')->default(0)->comment('文件大小');
$table->string('mime')->enablenull()->comment('文件类型');
$table->string('name')->comment('文件名称');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('files');
}
}
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateOpenidsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('openids', function (Blueprint $table) {
$table->increments('id');
$table->string('type');
$table->string('openid');
$table->integer('user_id');
$table->unique(['type', 'openid']);
$table->json('extra')->nullable()->comment('额外信息');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('openids');
}
}
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateActivitiesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('activities', function (Blueprint $table) {
$table->increments('id');
$table->string('title')->comment('活动名称');
$table->timestamp('start')->nullable()->comment('开始日期');
$table->timestamp('end')->nullable()->comment('结束日期');
$table->timestamp('enroll_start')->nullable()->comment('报名开始日期');
$table->timestamp('enroll_end')->nullable()->comment('报名结束日期');
$table->string('sponsor')->comment('主办人');
$table->string('address')->comment('位置');
$table->string('contact')->comment('联系信息');
$table->text('content')->comment('详情');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('activities');
}
}
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateEnrollmentsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('enrollments', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('user_id')->comment('用户ID');
$table->unsignedInteger('activity_id')->comment('活动ID');
$table->string('name', 50)->comment('姓名');
$table->string('mobile', 20)->comment('手机号');
$table->string('company')->comment('公司');
$table->string('recommender', 50)->nullable()->comment('推荐人');
$table->boolean('pay_status')->default(false)->comment('是否支付报名费');
$table->unique(['user_id', 'activity_id']);
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->foreign('activity_id')->references('id')->on('activities')->onDelete('cascade');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('enrollments');
}
}
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddCoverAndPriceToActivitiesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('activities', function (Blueprint $table) {
$table->string('cover')->nullable()->comment('封面图');
$table->decimal('price', 10, 2)->default(0)->comment('报名费');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('activities', function (Blueprint $table) {
//
});
}
}
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddLimitToActivitiesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('activities', function (Blueprint $table) {
$table->integer('limit')->default(0)->comment('名额限制');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('activities', function (Blueprint $table) {
//
});
}
}
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddIntroductionToActivitiesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('activities', function (Blueprint $table) {
$table->string('introduction')->comment('活动名称');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('activities', function (Blueprint $table) {
$table->dropColumn('introduction');
});
}
}
<?php
namespace Modules\Base\Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
class BaseDatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
Model::unguard();
// $this->call("OthersTableSeeder");
}
}
<?php
namespace Modules\Base\Entities;
use Illuminate\Database\Eloquent\Model;
class Activity extends Model
{
protected $fillable = ['title', 'start', 'end', 'enroll_start', 'enroll_end', 'sponsor', 'address', 'contact', 'content', 'cover', 'price', 'limit'];
/**
* 获取是否已报名
* @return bool
*/
public function getIsEnrolledAttribute()
{
$id = \Auth::id();
if (!$id) return false;
return Enrollment::where('user_id', $id)->where('activity_id', $this->id)->exist();
}
/**
* 报信信息列表
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function enrollments()
{
return $this->hasMany(Enrollment::class);
}
public function enrollment()
{
return $this->hasMany(Enrollment::class);
}
/**
* 报名数量
* @return mixed
*/
public function getEnrolledCountAttribute()
{
//debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
return $this->enrollments()->count();
//return Enrollment::where('activity_id', $this->id)->count();
}
}
<?php
namespace Modules\Base\Entities;
use Illuminate\Database\Eloquent\Model;
class BaseModel extends Model
{
protected $fillable = [];
}
<?php
namespace Modules\Base\Entities;
class Enrollment extends BaseModel
{
protected $fillable =['name', 'mobile', 'company', 'recommender', 'activity_id'];
public function user()
{
return $this->belongsTo(User::class);
}
public function activity()
{
return $this->belongsTo(Activity::class);
}
}
<?php
namespace Modules\Base\Entities;
class File extends BaseModel
{
protected $fillable = ['user_id', 'type', 'path', 'size','mime', 'name'];
}
<?php
namespace Modules\Base\Entities;
use Illuminate\Database\Eloquent\Model;
class Openid extends Model
{
protected $fillable = ['type', 'openid', 'user_id', 'extra'];
protected $casts = [
'extra' => 'array',
];
public function user()
{
return $this->belongsTo(User::class);
}
}
<?php
namespace Modules\Base\Entities;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Overtrue\LaravelFollow\Traits\CanFavorite;
use SMG\Support\Traits\Macroable;
use Tymon\JWTAuth\Contracts\JWTSubject;
class User extends Authenticatable implements JWTSubject
{
use Notifiable, Macroable, CanFavorite;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password', 'avatar', 'ext','phone','company',
];
protected $casts = [
'ext' => 'array',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* Get the identifier that will be stored in the subject claim of the JWT.
*
* @return mixed
*/
public function getJWTIdentifier()
{
return $this->getKey();
}
/**
* Return a key value array, containing any custom claims to be added to the JWT.
*
* @return array
*/
public function getJWTCustomClaims()
{
return [];
}
public function enrollment()
{
return $this->hasOne(Enrollment::class);
}
public function enrollments()
{
return $this->hasMany(Enrollment::class);
}
public function UserWallet()
{
return $this->hasOne(UserWallet::class);
}
}
<?php
namespace Modules\Base\Entities;
use Illuminate\Database\Eloquent\Model;
class UserWallet extends Model
{
const CHARGE = 1;
const PAY_ORDER = 2;
const WITHDRAWAL = 3;
const ORDER_REWARD = 4;
const ADMIN_ADD = 5;
const WITHDRAWAL_FAIL_BACK = 6;
protected $primaryKey = 'user_id';
public $incrementing = false;
protected $fillable = ['money', 'user_id', 'pay_password'];
/**使用钱包金额
* @param $value
* @param $type
* @param int $type_id
* @param string $wallet_type
* @return mixed
* @throws \Exception
*/
public function useWallet($value, $type, $type_id = 0, $wallet_type = 'money')
{
return $this->changeWalllet(-$value, $type, $type_id, $wallet_type);
}
/**
* 增加钱包金额
*
* @param $value
* @param $type
* @param int $type_id
* @param string $wallet_type
*
* @throws \Exception
*
* @return mixed
*/
public function addWallet($value, $type, $type_id = 0, $wallet_type = 'money')
{
return $this->changeWalllet($value, $type, $type_id, $wallet_type);
}
/**
* 改变钱包金额
*
* @param $value
* @param $type
* @param int $type_id
* @param string $wallet_type
*
* @throws \Exception
*
* @return mixed
*/
public function changeWalllet($value, $type, $type_id = 0, $wallet_type = 'money')
{
$this->exists || $this->save();
if ($value < 0 && $this->$wallet_type < -$value) {
throw new \Exception('余额不足');
}
$type_id = ($type_id == 0 && $type == self::ADMIN_ADD) ? self::getAdminAddId() : $type_id;
$result = $this->log()->create(compact('value', 'type', 'type_id', 'wallet_type'));
if ($result) {
return self::get($this->user_id);
}
throw new \Exception('未知错误');
}
/**
* 日志关联关系
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function log()
{
return $this->hasMany(UserWalletLog::class, 'user_id');
}
/**
* 获取钱包实例
*
* @param null $user_id
*
* @return mixed
*/
public static function get($user_id = null)
{
if ($user_id == null) {
$user_id = \Auth::id();
}
abort_unless($user_id, 401);
$wallet = static::firstOrCreate(['user_id' => $user_id]);
return $wallet;
}
/**
* @param null $type_id
* @param string $wallet_type
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function walletLog($type = null, $wallet_type = 'money')
{
$query = $this->log()->where('wallet_type', $wallet_type);
$query->when($type, function ($query, $type) {
$query->where('type', $type);
});
return $query->orderByDesc('id');
}
/**
* @return int
*/
public static function getAdminAddId()
{
return UserWalletLog::where('wallet_type', 'money')->where('type', self::ADMIN_ADD)->max('type_id') + 1;
}
}
<?php
namespace Modules\Base\Events;
use Illuminate\Queue\SerializesModels;
use Modules\Base\Entities\Enrollment;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
class EnrollmentCreated
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(Enrollment $enrollment)
{
$this->enrollment = $enrollment;
}
/**
* Get the channels the event should be broadcast on.
*
* @return array
*/
public function broadcastOn()
{
return [];
}
}
<?php
namespace Modules\Base\Events;
use Illuminate\Queue\SerializesModels;
use Modules\Base\Entities\File;
class FileUploaded
{
use SerializesModels;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(File $file)
{
$this->file = $file;
}
/**
* Get the channels the event should be broadcast on.
*
* @return array
*/
public function broadcastOn()
{
return [];
}
}
<?php
namespace Modules\Base\Http\Controllers\Admin;
use Modules\Base\Entities\Activity;
use App\Http\Controllers\Controller;
use SMG\Admin\Controllers\HasResourceActions;
use SMG\Admin\Facades\Admin;
use SMG\Admin\Form;
use SMG\Admin\Grid;
use SMG\Admin\Layout\Content;
use SMG\Admin\Show;
class ActivityController extends Controller
{
use HasResourceActions;
/**
* Index interface.
*
* @param Content $content
* @return mixed
*/
public function index(Content $content)
{
return $content
->header('活动列表')
->body($this->grid());
}
/**
* Show interface.
*
* @param mixed $id
* @param Content $content
* @return mixed
*/
public function show($id, Content $content)
{
return $content
->header('详情')
->body($this->detail($id));
}
/**
* Edit interface.
*
* @param mixed $id
* @param Content $content
* @return mixed
*/
public function edit($id, Content $content)
{
return $content
->header('编辑')
->description('description')
->body($this->form()->edit($id));
}
/**
* Create interface.
*
* @param Content $content
* @return mixed
*/
public function create(Content $content)
{
return $content
->header('新增')
->body($this->form());
}
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
return Admin::Grid(new Activity, function($grid) {
$grid->model()->withCount('enrollments')->orderBy('id', 'desc');
$grid->id('Id');
$grid->title('活动名称');
$grid->start('开始时间');
$grid->end('结束时间');
$grid->enroll_start('报名开始时间');
$grid->enroll_end('报名结束时间');
$grid->sponsor('主办人');
$grid->address('地址');
$grid->contact('联系人');
//$grid->content('Content');
$grid->enrollments_count('报名人数');
$grid->created_at('添加时间');
//$grid->updated_at('Updated at');
});
}
/**
* Make a show builder.
*
* @param mixed $id
* @return Show
*/
protected function detail($id)
{
$show = new Show(Activity::findOrFail($id));
$show->id('Id');
$show->title('Title');
$show->start('Start');
$show->end('End');
$show->enroll_start('Enroll start');
$show->enroll_end('Enroll end');
$show->sponsor('Sponsor');
$show->address('Address');
$show->contact('Contact');
$show->content('Content');
$show->created_at('Created at');
$show->updated_at('Updated at');
return $show;
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
$form = new Form(new Activity);
$form->text('title', '名称')->rules('required');;
//$form->datetime('start', '开始时间')->rules('required');;
//$form->datetime('end', '结束时间')->rules('required');
$form->datetimeRange('start', 'end', '活动时间')->rules('required');
//$form->datetime('enroll_start', '报名开始时间')->rules('required');;
//$form->datetime('enroll_end', '报名结束时间')->rules('required');;
$form->datetimeRange('enroll_start', 'enroll_end', '报名时间')->rules('required');
$form->image('cover', '封面图')->rules('required');;
$form->currency('price', '报名费')->symbol('¥')->rules('required');
$form->text('sponsor', '主办人')->rules('required');
$form->text('address', '地址')->rules('required');
$form->text('contact', '联系人')->rules('required');
$form->number('limit', '数量限制')->default(0)->help('0为不限制人数');
$form->textarea('introduction', '简介')->rules('required');
$form->editor('content', '内容')->rules('required');
return $form;
}
}
<?php
namespace Modules\Base\Http\Controllers\Admin;
use Modules\Base\Entities\Activity;
use Modules\Base\Entities\Enrollment;
use App\Http\Controllers\Controller;
use SMG\Admin\Facades\Admin;
use SMG\Admin\Controllers\HasResourceActions;
use SMG\Admin\Form;
use SMG\Admin\Grid;
use SMG\Admin\Layout\Content;
use SMG\Admin\Show;
class EnrollmentController extends Controller
{
use HasResourceActions;
/**
* Index interface.
*
* @param Content $content
* @return mixed
*/
public function index(Content $content)
{
return $content
->header('报名列表')
->body($this->grid());
}
/**
* Show interface.
*
* @param mixed $id
* @param Content $content
* @return mixed
*/
public function show($id, Content $content)
{
return $content
->header('Detail')
->description('description')
->body($this->detail($id));
}
/**
* Edit interface.
*
* @param mixed $id
* @param Content $content
* @return Content
*/
public function edit($id, Content $content)
{
return $content
->header('Edit')
->description('description')
->body($this->form()->edit($id));
}
/**
* Create interface.
*
* @param Content $content
* @return Content
*/
public function create(Content $content)
{
return $content
->header('Create')
->description('description')
->body($this->form());
}
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
return Admin::Grid(new Enrollment, function ($grid) {
$grid->model()->orderBy('id', 'desc');
$grid->id('Id');
$grid->column('activity.title', '活动');
$grid->name('姓名');
$grid->mobile('电话');
$grid->company('公司');
$grid->recommender('推荐人');
$grid->pay_status('支付状态')->display(function ($value){return $value?'已支付':'未支付';});
$grid->created_at('报名时间');
$grid->disableCreateButton();
$grid->enableExport();
$grid->exporter(new EnrollmentsExporter());
$grid->enableFilter();
$grid->filter(function($filter){
// 去掉默认的id过滤器
$filter->disableIdFilter();
$filter->equal('activity_id', '活动')->select(Activity::pluck('title', 'id'));
$filter->equal('pay_status', '支付状态')->select(['未支付','已支付']);
$filter->equal('name', '姓名');
$filter->equal('mobile', '手机号');
});
$grid->actions(function ($actions){
$actions->disableEdit();
$actions->disableView();
});
});
}
/**
* Make a show builder.
*
* @param mixed $id
* @return Show
*/
protected function detail($id)
{
$show = new Show(Enrollment::findOrFail($id));
$show->id('Id');
$show->user_id('User id');
$show->activity_id('Activity id');
$show->name('Name');
$show->mobile('Mobile');
$show->company('Company');
$show->recommender('Recommender');
$show->pay_status('Pay status');
$show->created_at('Created at');
$show->updated_at('Updated at');
return $show;
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
$form = new Form(new Enrollment);
$form->number('user_id', 'User id');
$form->number('activity_id', 'Activity id');
$form->text('name', 'Name');
$form->mobile('mobile', 'Mobile');
$form->text('company', 'Company');
$form->text('recommender', 'Recommender');
$form->switch('pay_status', 'Pay status');
return $form;
}
}
<?php
namespace Modules\Base\Http\Controllers\Admin;
use Encore\Admin\Grid\Exporters\AbstractExporter;
class EnrollmentsExporter extends AbstractExporter
{
/**
* {@inheritdoc}
*/
public function export()
{
$filename = $this->getTable().'.csv';
$headers = [
'Content-Encoding' => 'UTF-8',
'Content-Type' => 'text/csv;charset=gbk',
'Content-Disposition' => "attachment; filename=\"$filename\"",
];
response()->stream(function () {
$handle = fopen('php://output', 'w');
//echo chr(0xEF).chr(0xBB).chr(0xBF);
fwrite($handle, chr(0xEF).chr(0xBB).chr(0xBF));
$titles = $this->convert_array(['ID', '活动', '姓名', '电话', '公司', '推荐人', '支付状态', '报名时间']);
fputcsv($handle, $titles);
$this->chunk(function ($records) use ($handle, &$titles) {
foreach ($records as $record) {
$data = $this->getFormattedRecord($record,[
'id',
'activity.title',
'name',
'mobile',
'company',
'recommender',
function($record) {
return $record->pay_status?'已支付':'未支付';
},
'created_at'
]);
fputcsv($handle, $data);
}
});
// Close the output stream
fclose($handle);
}, 200, $headers)->send();
exit;
}
public function getFormattedRecord($record, $columns=[])
{
$data = [];
foreach ($columns as $column)
{
if (is_callable($column)) {
$data[]= $column($record);
} else {
$keys = explode('.', $column);
$data[] = array_reduce($keys, function($v,$key){ return $v->$key; }, $record);
}
}
return $this->convert_array($data);
}
public function convert_array($strs) {
return array_map(function ($str){return iconv("UTF-8","gbk//TRANSLIT",(string)$str);}, $strs);
}
}
<?php
namespace Modules\Base\Http\Controllers\Admin;
use Modules\Base\Entities\Openid;
use App\Http\Controllers\Controller;
use SMG\Admin\Controllers\HasResourceActions;
use SMG\Admin\Facades\Admin;
use SMG\Admin\Form;
use SMG\Admin\Grid;
use SMG\Admin\Layout\Content;
use SMG\Admin\Show;
class OpenidsController extends Controller
{
use HasResourceActions;
/**
* Index interface.
*
* @param Content $content
* @return mixed
*/
public function index(Content $content)
{
return $content
->header('openid列表')
->body($this->grid());
}
/**
* Show interface.
*
* @param mixed $id
* @param Content $content
* @return mixed
*/
public function show($id, Content $content)
{
return $content
->header('详情')
->body($this->detail($id));
}
/**
* Edit interface.
*
* @param mixed $id
* @param Content $content
* @return mixed
*/
public function edit($id, Content $content)
{
return $content
->header('编辑')
->description('description')
->body($this->form()->edit($id));
}
/**
* Create interface.
*
* @param Content $content
* @return mixed
*/
public function create(Content $content)
{
return $content
->header('新增')
->body($this->form());
}
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
return Admin::Grid(new Openid(), function($grid) {
$grid->model()->withCount('user')->orderBy('id', 'desc');
$grid->id('Id');
$grid->user_id('用户id');
$grid->user()->name('用户名');
$grid->user()->sex('性别?')->display(function ($sex) {
return $sex ? $sex ==1?'男':'女' : '未知';
});
$grid->type('类型');
$grid->openid('openid');
$grid->created_at('添加时间');
});
}
/**
* Make a show builder.
*
* @param mixed $id
* @return Show
*/
protected function detail($id)
{
$show = new Show(Openid::findOrFail($id));
$show->id('Id');
$show->type('类型');
$show->openid('openid');
$show->user_id('用户id');
$show->created_at('创建时间');
return $show;
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
$form = new Form(new Openid);
$form->number('type', '类型')->rules('required');
$form->text('openid', 'openid')->rules('required');
$form->number('user_id', '用户id')->rules('required');
$form->text('extra', '额外信息');
return $form;
}
}
<?php
namespace Modules\Base\Http\Controllers\Admin;
use Modules\Base\Entities\User;
use App\Http\Controllers\Controller;
use SMG\Admin\Controllers\HasResourceActions;
use SMG\Admin\Facades\Admin;
use SMG\Admin\Form;
use SMG\Admin\Grid;
use SMG\Admin\Layout\Content;
use SMG\Admin\Show;
class UsersController extends Controller
{
use HasResourceActions;
/**
* Index interface.
*
* @param Content $content
* @return mixed
*/
public function index(Content $content)
{
return $content
->header('会员')
->body($this->grid());
}
/**
* Show interface.
*
* @param mixed $id
* @param Content $content
* @return mixed
*/
public function show($id, Content $content)
{
return $content
->header('详情')
->body($this->detail($id));
}
/**
* Edit interface.
*
* @param mixed $id
* @param Content $content
* @return mixed
*/
public function edit($id, Content $content)
{
return $content
->header('编辑')
->description('description')
->body($this->form()->edit($id));
}
/**
* Create interface.
*
* @param Content $content
* @return mixed
*/
public function create(Content $content)
{
return $content
->header('新增')
->body($this->form());
}
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
return Admin::Grid(new User(), function($grid) {
$grid->id('id')->sortable();
$grid->id('Id');
$grid->name('姓名');
$grid->phone('手机号');
$grid->avatar()->image('',60,60);
$grid->email('邮箱');
$grid->sex('性别')->display(function ($sex) {
return $sex ? $sex ==1?'男':'女' : '未知';
});
$grid->company('公司名');
$grid->enableFilter();
$grid->enableFilter();
$grid->disableExport();
$grid->disableCreateButton();
$grid->actions(function ($actions) {
$actions->disableEdit();
$actions->disableDelete();
});
$grid->filter(function ($filter) {
// 去掉默认的id过滤器
$filter->disableIdFilter();
// 在这里添加字段过滤器
$filter->like('name', '姓名');
$filter->like('phone', '手机号');
});
$grid->created_at('添加时间');
});
}
/**
* Make a show builder.
*
* @param mixed $id
* @return Show
*/
protected function detail($id)
{
$show = new Show(User::findOrFail($id));
$show->id('Id');
$show->name('姓名');
$show->phone('手机号');
$show->email('邮箱');
$show->avatar('头像')->image();
$show->panel()->tools(function ($tools) {
$tools->disableEdit();
$tools->disableDelete();
});
$show->sex('性别')->using(['0' => '未知', 1 => '男' ,1 => '女' ]);
$show->company('公司名');
$show->created_at('创建时间');
return $show;
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
$form = new Form(new User);
$form->text('name', '姓名')->rules('required');
$form->mobile('phone', '手机号')->rules('required');
$form->email('email', '邮箱')->rules(null);
$form->saving(function (Form $form) {
if ($form->password && $form->model()->password != $form->password) {
$form->password = bcrypt($form->password);
}
});
$form->password('password', '用户密码');
$form->file('avatar', '头像')->rules('required');
$form->radio('sex', '性别')->options([0=>'未知',1=>'男',2=>'女']);
return $form;
}
}
<?php
namespace Modules\Base\Http\Controllers\Api;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Modules\Base\Entities\Activity;
use Modules\Base\Transformers\ActivityTransformer;
class ActivityController extends ApiController
{
/**
* 已报名用户信息列表
* @return \Dingo\Api\Http\Response
*
* @OA\Get(
* tags={"活动"},
* summary="活动信息",
* path="/api/activities/{activity_id}",
* @OA\Parameter(
* name="activity_id",
* in="path",
* description="活动ID",
* required=true,
* @OA\Schema(
* type="integer",
* )
* ),
* @OA\Response(
* response="200",
* description="成功",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property="data",
* type="array",
* @OA\Items(ref="#/components/schemas/Activity"),
* description="列表"
* ),
* )
* )
* )
* )
*/
public function detail(Activity $activity)
{
return $this->response->item($activity, new ActivityTransformer());
}
/**
* @param Activity $activity
* @return \Dingo\Api\Http\Response
*
*
* @OA\Get(
* tags={"活动"},
* summary="活动列表",
* path="/api/activities",
* @OA\Parameter(
* name="type",
* in="query",
* description="类型 往期-wangqi 预展期-yuzhanqi 进行中-jinxingzhong",
* required=false,
* @OA\Schema(
* type="string"
* )
* ),
* @OA\Response(
* response="200",
* description="成功",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property="data",
* type="array",
* @OA\Items(ref="#/components/schemas/Activity"),
* description="列表"
* ),
* )
* )
* )
* )
*/
public function index(Activity $activity)
{
$activity = $activity->when(request('type', false), function ($query, $type) {
if($type == 'wangqi'){
$query->where('enroll_end','<',date('Y-m-d'));
}else if($type == 'yuzhanqi'){
$query->where('enroll_start','>',date('Y-m-d'));
}else{
$query->where('enroll_start','<',date('Y-m-d'));
$query->where('enroll_end','>',date('Y-m-d'));
}
});
return $this->response->paginator($activity->paginate(20), new ActivityTransformer());
}
}
<?php
namespace Modules\Base\Http\Controllers\Api;
use Modules\Base\Http\Controllers\BaseController;
class ApiController extends BaseController
{
use \Dingo\Api\Routing\Helpers;
}
<?php
namespace Modules\Base\Http\Controllers\Api;
use Illuminate\Support\Facades\Auth;
use Modules\Base\Http\Requests\AuthorizationRequest;
use Modules\Base\Http\Requests\OpenloginRequest;
use Modules\Base\Services\OpenloginService;
use Modules\Base\Transformers\AccessTokenTransformer;
use Modules\Base\Transformers\UserTransformer;
class AuthorizationsController extends ApiController
{
/**
* 登陆
*
* @param AuthorizationRequest $request
*
* @return mixed
*
* @OA\Post(
* tags={"用户"},
* summary="用户登陆",
* path="/api/base/authorizations",
* @OA\RequestBody(
* @OA\MediaType(
* mediaType="application/x-www-form-urlencoded",
* @OA\Schema(
* type="object",
* required={"phone","password"},
* @OA\Property(
* property="phone",
* ref="#/components/schemas/phone"
* ),
* @OA\Property(
* property="password",
* ref="#/components/schemas/password"
* ),
* )
* )
* ),
* @OA\Response(
* response="201",
* description="登陆成功",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(property="data", type="object", ref="#/components/schemas/Token")
* )
* )
* )
* )
*/
public function store(AuthorizationRequest $request)
{
if (!$token = Auth::guard('api')->attempt($request->only(['phone', 'password']))) {
return $this->response->errorUnauthorized('手机号或密码错误');
}
return $this->response->item(auth('api')->user(), new AccessTokenTransformer())->setStatusCode(201);
}
/**
* 第三方登陆
*
* @param $type
* @param OpenloginRequest $request
* @param OpenloginService $openlogin
*
* @return $token
*
* @OA\Post(
* tags={"用户"},
* summary="第三方账号登陆",
* path="/api/base/authorizations/openlogin/{type}",
* @OA\Parameter(
* name="type",
* in="path",
* description="第三方登陆类型",
* required=true,
* @OA\Schema(
* type="string",
* )
* ),
* @OA\RequestBody(
* @OA\MediaType(
* mediaType="application/x-www-form-urlencoded",
* @OA\Schema(
* type="object",
* @OA\Property(
* property="code",
* type="string"
* )
* )
* )
* ),
* @OA\Response(
* response="201",
* description="登陆成功",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(property="data", type="object", ref="#/components/schemas/Token")
* )
* )
* )
* )
*/
public function openlogin($type, OpenloginRequest $request, OpenloginService $openlogin)
{
$user = $openlogin->login($type, $request->all());
return $this->response->item($user, new AccessTokenTransformer())->setStatusCode(201);
}
/**
* @return mixed
*
* @OA\Put(
* tags={"用户"},
* summary="刷新TOKEN",
* path="/api/base/authorizations/current",
* security={
* {"jwt_auth": {}}
* },
* @OA\Response(
* response="200",
* description="刷新成功",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(property="data", type="object", ref="#/components/schemas/Token")
* )
* )
* )
* )
*/
public function update()
{
$token = \Auth::guard('api')->refresh();
return $this->respondWithToken($token);
}
/**
* @return mixed
*
* @OA\Delete(
* tags={"用户"},
* summary="用户登出",
* path="/api/base/authorizations/current",
* security={
* {"jwt_auth": {}}
* },
* @OA\Response(
* response="204",
* description="登出成功"
* )
* )
*/
public function destroy()
{
\Auth::logout();
return $this->response->noContent()->setStatusCode(200);
}
}
<?php
namespace Modules\Base\Http\Controllers\Api;
use Illuminate\Support\Facades\Event;
use Modules\Base\Entities\Activity;
use Modules\Base\Entities\Enrollment;
use Modules\Base\Events\EnrollmentCreated;
use Modules\Base\Http\Requests\EnrollmentRequest;
use Modules\Base\Transformers\EnrollmentTransformer;
class EnrollmentController extends ApiController
{
/**
* 已报名用户信息列表
* @return \Dingo\Api\Http\Response
*
* @OA\Get(
* tags={"报名"},
* summary="报名信息",
* path="/api/enrollments",
* @OA\Parameter(
* name="activity_id",
* in="query",
* description="活动ID",
* required=true,
* explode=true,
* @OA\Schema(
* type="number"
* )
* ),
* @OA\Response(
* response="200",
* description="成功",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property="data",
* type="array",
* @OA\Items(ref="#/components/schemas/Enrollment"),
* description="列表"
* ),
* )
* )
* )
* )
*/
public function index()
{
//$list = Enrollment::with('user')->latest()->paginate();
$activity = Activity::findOrFail(request()->activity_id);
return $this->response->paginator($activity->enrollments()->paginate(), new EnrollmentTransformer());
}
/**
* 个人报名信息
* @return \Dingo\Api\Http\Response
*
* @OA\Get(
* tags={"报名"},
* summary="个人报名信息",
* path="/api/user/enrollment",
* @OA\Parameter(
* name="activity_id",
* in="path",
* description="活动ID",
* required=true,
* @OA\Schema(
* type="integer",
* )
* ),
* security={
* {"jwt_auth": {}}
* },
* @OA\Response(
* response="200",
* description="成功",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(type="object",
* @OA\Property(property="data", type="object", ref="#/components/schemas/Enrollment")
* )
* )
* )
* )
*/
public function me()
{
return $this->response->item($this->user()->enrollment, new EnrollmentTransformer(true));
}
/**
* 个人报名信息
* @return \Dingo\Api\Http\Response
*
* @OA\Get(
* tags={"报名"},
* summary="已报名列表",
* path="/api/user/enrollment",
* security={
* {"jwt_auth": {}}
* },
* @OA\Response(
* response="200",
* description="成功",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(type="object",
* @OA\Property(property="data", type="object", ref="#/components/schemas/Enrollment")
* )
* )
* )
* )
*/
public function meEnrollments()
{
return $this->response->paginator($this->user()->enrollments()->paginate(20), new EnrollmentTransformer(true));
}
/**
* 报名
* @param EnrollmentRequest $request
* @return \Dingo\Api\Http\Response
*
* @OA\Post(
* tags={"报名"},
* summary="提交报名信息",
* path="/api/enrollments",
* security={
* {"jwt_auth": {}}
* },
* @OA\RequestBody(
* required=true,
* @OA\MediaType(
* mediaType="application/x-www-form-urlencoded",
* @OA\Schema(
* type="object",
* required={"name","mobile", "company","activity_id"},
* @OA\Property(
* property="activity_id",
* type="number",
* description="活动ID"
* ),
* @OA\Property(
* property="name",
* type="string",
* description="姓名"
* ),
* @OA\Property(
* property="mobile",
* type="number",
* description="手机号"
* ),
* @OA\Property(
* property="company",
* type="string",
* description="公司"
* ),
* @OA\Property(
* property="recommender",
* type="string",
* description="推荐人姓名"
* ),
* )
* )
* ),
* @OA\Response(
* response="201",
* description="成功"
* )
* )
*/
public function store(EnrollmentRequest $request)
{
$enrollment = $this->user()->enrollment()->create($request->all());
event(new EnrollmentCreated($enrollment));
return $this->response->created();
}
}
<?php
namespace Modules\Base\Http\Controllers\Api;
use Modules\Base\Http\Requests\FileRequest;
use Modules\Base\Services\FileService;
use Modules\Base\Transformers\FileTransformer;
class FilesController extends ApiController
{
/**
* Store a newly created resource in storage.
*
* @param FileRequest $request
* @param FileService $file
*
* @return \Dingo\Api\Http\Response $response
*
* @OA\Post(
* tags={"基础接口"},
* summary="上传文件",
* path="/api/base/files",
* security={
* {"jwt_auth": {}}
* },
* @OA\RequestBody(
* required=true,
* @OA\MediaType(
* mediaType="multipart/form-data",
* @OA\Schema(
* type="object",
* required={"type","file"},
* @OA\Property(
* property="type",
* type="string",
* enum={"avatar"}
* ),
* @OA\Property(
* property="file",
* type="string",
* format="binary"
* ),
* )
* )
* ),
* @OA\Response(
* response="201",
* description="成功",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(type="object",
* @OA\Property(property="data", type="object", ref="#/components/schemas/File")
* )
* )
* )
* )
*/
public function store(FileRequest $request, FileService $file)
{
$info = $file->process($request->file, $request->input('type'));
return $this->response->item($info, new FileTransformer())
->setStatusCode(201);
}
}
<?php
namespace Modules\Base\Http\Controllers\Api;
use Illuminate\Notifications\DatabaseNotification;
use Modules\Base\Notifications\TestNotify;
use Modules\Base\Transformers\NotificationTransformer;
class NotificationsController extends ApiController
{
/**
* @return mixed
*
* @OA\Get(
* tags={"用户"},
* summary="通知列表",
* path="/api/base/user/notifications",
* security={{"jwt_auth":{}}},
* @OA\Response(
* response="200",
* description="成功",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property="data",
* type="array",
* @OA\Items(ref="#/components/schemas/Notification"),
* description="列表"
* ),
* )
* )
* )
* )
*/
public function index()
{
$notifications = $this->user->notifications()->paginate(20);
return $this->response->paginator($notifications, new NotificationTransformer());
}
/**
* @return mixed
*
* @OA\Get(
* tags={"用户"},
* summary="查看通知",
* path="/api/base/user/notifications/{notification_id}",
* security={{"jwt_auth":{}}},
* @OA\Parameter(
* name="notification_id",
* in="path",
* description="通知ID",
* required=true,
* @OA\Schema(
* type="string",
* )
* ),
* @OA\Response(
* response="200",
* description="成功",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property="data",
* type="array",
* @OA\Items(ref="#/components/schemas/Notification"),
* description="列表"
* ),
* )
* )
* )
* )
*/
public function show($notification_id)
{
$notification = DatabaseNotification::where('notifiable_id', $this->user->id)->findOrFail($notification_id);
return $this->response->item($notification, new NotificationTransformer());
}
/**
* @return mixed
*
* @OA\Get(
* tags={"用户"},
* summary="通知数据统计",
* path="/api/base/user/notifications/stats",
* security={{"jwt_auth":{}}},
* @OA\Response(
* response="200",
* description="成功",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(property="count", type="integer", description="消息数量"),
* @OA\Property(property="unread_count", type="integer", description="未读数量")
* )
* )
* )
* )
*/
public function stats()
{
$user = $this->user();
return $this->response->array([
'count' => $user->notifications()->count(),
'unread_count' => $user->unreadNotifications()->count(),
//'group_count' => $user->notifications()->groupBy('notifiable_type')->count(),
//'unread_unread_count' => $user->unreadNotifications()->groupBy('notifiable_type')->count(),
]);
}
/**
* @return \Dingo\Api\Http\Response
*
* @OA\Post(
* tags={"用户"},
* path="/api/base/user/notifications",
* summary="向登陆用户发送一条测试消息",
* security={
* {"jwt_auth": {}}
* },
* @OA\Response(response="201", description="成功")
* )
*/
public function test()
{
$this->user()->notify(new TestNotify(['id' => 111,'content' => '这里是内容', 'subject' => '这里是标题']));
$notification->markAsRead();
return $this->response->created();
}
/**
* @return mixed
*
* @OA\Put(
* tags={"用户"},
* summary="所有通知标记为已读",
* path="/api/base/user/read/notifications",
* security={{"jwt_auth":{}}},
* @OA\Response(
* response="204",
* description="成功"
* )
* )
*/
public function read()
{
$this->user()->unreadNotifications()->update(['read_at' => now()]);
return $this->response->noContent();
}
}
<?php
namespace Modules\Base\Http\Controllers\Api;
use Modules\Base\Http\Requests\SmsRequest;
use Modules\Base\Services\SmsService;
class SmsController extends ApiController
{
/**
* @OA\Post(
* tags={"基础接口"},
* summary="发送短信验证码",
* path="/api/base/sms",
* description="type:手机验证码类型:1:注册,2:找回密码,3:更换手机号",
* @OA\RequestBody(
* required=true,
* description="xxxyy",
* @OA\MediaType(
* mediaType="application/x-www-form-urlencoded",
* @OA\Schema(
* type="object",
* required={"captcha_key"},
* @OA\Property(
* property="captcha_key",
* type="string",
* description="验证码KEY",
* ),
* @OA\Property(
* property="captcha_code",
* type="string",
* ),
* @OA\Property(
* property="phone",
* type="string",
* ),
* @OA\Property(
* type="integer",
* property="type",
* description="手机短信类型",
* enum={1,2,3}
* ),
* )
* )
* ),
* @OA\Response(response="201", description="发送成功")
* )
*/
public function store(SmsRequest $request, SmsService $sms)
{
$sms->send($request->phone, $request->type);
return $this->response->noContent()->setStatusCode(201);
}
}
<?php
namespace Modules\Base\Http\Controllers\Api;
use Modules\Base\Http\Requests\UserRequest;
use Modules\Base\Services\SmsService;
use Modules\Base\Services\UserService;
use Modules\Base\Transformers\UserTransformer;
class UsersController extends ApiController
{
/**
* Store a newly created resource in storage.
*
* @param UserRequest $request
* @param SmsService $sms
* @param UserService $userService
*
* @return \Dingo\Api\Http\Response $response
*
* @OA\Post(
* tags={"用户"},
* summary="用户注册接口",
* path="/api/base/users",
* @OA\RequestBody(
* @OA\MediaType(
* mediaType="application/x-www-form-urlencoded",
* @OA\Schema(
* type="object",
* required={"phone","password", "code"},
* @OA\Property(
* property="phone",
* ref="#/components/schemas/phone"
* ),
* @OA\Property(
* property="code",
* ref="#/components/schemas/phone_code"
* ),
* @OA\Property(
* property="password",
* ref="#/components/schemas/password"
* ),
* )
* )
* ),
* @OA\Response(
* response="201",
* description="成功",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(type="object",
* @OA\Property(property="data", type="object", ref="#/components/schemas/User")
* )
* )
* )
* )
*/
public function store(UserRequest $request, SmsService $sms, UserService $userService)
{
$sms->verifyCode($request->code, $sms::REGISTER, $request->phone);
$request['password'] = \Hash::make($request->password);
$userService->create($request->all());
return $this->response->item($userService->model, new UserTransformer())
->setStatusCode(201);
}
/**
* @return \Dingo\Api\Http\Response
*
* @OA\Get(
* tags={"用户"},
* summary="当前登陆用户信息",
* path="/api/base/user",
* security={
* {"jwt_auth": {}}
* },
* @OA\Response(
* response="200",
* description="成功",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(property="data", type="object", ref="#/components/schemas/User")
* )
* )
* )
* )
*/
public function me()
{
return $this->response->item($this->user(), new UserTransformer());
}
/**
* Update resource in storage.
*
* @param UserRequest $request
*
* @return \Dingo\Api\Http\Response
*
* @OA\Put(
* tags={"用户"},
* summary="更新用户信息",
* path="/api/base/user",
* security={
* {"jwt_auth": {}}
* },
* @OA\RequestBody(
* @OA\MediaType(
* mediaType="application/x-www-form-urlencoded",
* @OA\Schema(
* type="object",
* @OA\Property(
* property="name",
* type="string",
* ),
* @OA\Property(
* property="email",
* ref="#/components/schemas/email"
* ),
* @OA\Property(
* property="file_id",
* type="integer",
* description="文件ID"
* ),
* @OA\Property(
* property="password",
* ref="#/components/schemas/password"
* ),
* @OA\Property(
* property="oldpassword",
* ref="#/components/schemas/password"
* ),
* @OA\Property(
* property="phone",
* ref="#/components/schemas/phone",
* description="手机号",
* ),
* @OA\Property(
* property="code",
* ref="#/components/schemas/phone_code",
* description="手机验证码,修改修改号时必须",
* ),
* )
* )
* ),
* @OA\Response(
* response="200",
* description="成功",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(type="object",
* @OA\Property(property="data", type="object", ref="#/components/schemas/User")
* )
* )
* )
* )
*/
public function update(UserRequest $request, UserService $user)
{
if ($request->phone) {
$sms = app(SmsService::class);
$sms->verifyCode($request->code, $sms::CHANGE_PHONE, $request->phone);
}
$user->update(\Auth::id(), $request->all());
return $this->response->item($user->model, new UserTransformer());
}
/**
* Update resource in storage.
*
* @param UserRequest $request
*
* @return \Dingo\Api\Http\Response
*
* @OA\Put(
* tags={"用户"},
* summary="重设密码",
* path="/api/base/user/password",
* @OA\RequestBody(
* @OA\MediaType(
* mediaType="application/x-www-form-urlencoded",
* @OA\Schema(
* type="object",
* @OA\Property(
* property="phone",
* ref="#/components/schemas/phone"
* ),
* @OA\Property(
* property="code",
* ref="#/components/schemas/phone_code"
* ),
* @OA\Property(
* property="password",
* ref="#/components/schemas/password"
* ),
* )
* )
* ),
* @OA\Response(
* response="204",
* description="成功"
* )
* )
*/
public function password(UserRequest $request, UserService $userService, SmsService $sms)
{
$sms->verifyCode($request->code, $sms::FIND_PASSWORD, $request->phone);
$user = $userService->model->where('phone', $request->phone)->firstOrFail();
$userService->update($user->id, $request->only('password'));
return $this->response->noContent();
}
/**
* Remove the specified resource from storage.
*
* @param int $id
*
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}
<?php
namespace Modules\Base\Http\Controllers;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller;
class BaseController extends Controller
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}
<?php
namespace Modules\Base\Http\Middleware;
use Closure;
use Illuminate\Contracts\Session\Session;
use Illuminate\Http\Request;
use Illuminate\Session\SessionManager;
use Illuminate\Support\Carbon;
use Symfony\Component\HttpFoundation\Response;
class StartSession
{
/**
* The session manager.
*
* @var \Illuminate\Session\SessionManager
*/
protected $manager;
/**
* Indicates if the session was handled for the current request.
*
* @var bool
*/
protected $sessionHandled = false;
/**
* Create a new session middleware.
*
* @param \Illuminate\Session\SessionManager $manager
*
* @return void
*/
public function __construct(SessionManager $manager)
{
$this->manager = $manager;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
$this->sessionHandled = true;
// If a session driver has been configured, we will need to start the session here
// so that the data is ready for an application. Note that the Laravel sessions
// do not make use of PHP "native" sessions in any way since they are crappy.
if ($this->sessionConfigured() && auth('api')->user()) {
$request->setLaravelSession(
$session = $this->startSession($request)
);
$this->collectGarbage($session);
}
$response = $next($request);
// Again, if the session has been configured we will need to close out the session
// so that the attributes may be persisted to some storage medium. We will also
// add the session identifier cookie to the application response headers now.
if ($this->sessionConfigured()) {
$this->storeCurrentUrl($request, $session);
$this->addCookieToResponse($response, $session);
}
return $response;
}
/**
* Perform any final actions for the request lifecycle.
*
* @param \Illuminate\Http\Request $request
* @param \Symfony\Component\HttpFoundation\Response $response
*
* @return void
*/
public function terminate($request, $response)
{
if ($this->sessionHandled && $this->sessionConfigured() && auth('api')->user()) {
$this->manager->driver()->save();
}
}
/**
* Start the session for the given request.
*
* @param \Illuminate\Http\Request $request
*
* @return \Illuminate\Contracts\Session\Session
*/
protected function startSession(Request $request)
{
return tap($this->getSession($request), function ($session) use ($request) {
$session->setRequestOnHandler($request);
$session->start();
});
}
/**
* Get the session implementation from the manager.
*
* @param \Illuminate\Http\Request $request
*
* @return \Illuminate\Contracts\Session\Session
*/
public function getSession(Request $request)
{
return tap($this->manager->driver(), function ($session) use ($request) {
$session_id = 'apiseesion'.auth('api')->id();
$session_id = str_pad($session_id, 40, '0', STR_PAD_LEFT);
$session->setId($session_id);
});
}
/**
* Remove the garbage from the session if necessary.
*
* @param \Illuminate\Contracts\Session\Session $session
*
* @return void
*/
protected function collectGarbage(Session $session)
{
$config = $this->manager->getSessionConfig();
// Here we will see if this request hits the garbage collection lottery by hitting
// the odds needed to perform garbage collection on any given request. If we do
// hit it, we'll call this handler to let it delete all the expired sessions.
if ($this->configHitsLottery($config)) {
$session->getHandler()->gc($this->getSessionLifetimeInSeconds());
}
}
/**
* Determine if the configuration odds hit the lottery.
*
* @param array $config
*
* @return bool
*/
protected function configHitsLottery(array $config)
{
return random_int(1, $config['lottery'][1]) <= $config['lottery'][0];
}
/**
* Store the current URL for the request if necessary.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Contracts\Session\Session $session
*
* @return void
*/
protected function storeCurrentUrl(Request $request, $session)
{
if ($request->method() === 'GET' && $request->route() && !$request->ajax()) {
$session->setPreviousUrl($request->fullUrl());
}
}
/**
* Add the session cookie to the application response.
*
* @param \Symfony\Component\HttpFoundation\Response $response
* @param \Illuminate\Contracts\Session\Session $session
*
* @return void
*/
protected function addCookieToResponse(Response $response, Session $session)
{
$this->manager->driver()->save();
}
/**
* Get the session lifetime in seconds.
*
* @return int
*/
protected function getSessionLifetimeInSeconds()
{
return ($this->manager->getSessionConfig()['lifetime'] ?? null) * 60;
}
/**
* Get the cookie lifetime in seconds.
*
* @return \DateTimeInterface
*/
protected function getCookieExpirationDate()
{
$config = $this->manager->getSessionConfig();
return $config['expire_on_close'] ? 0 : Carbon::now()->addMinutes($config['lifetime']);
}
/**
* Determine if a session driver has been configured.
*
* @return bool
*/
protected function sessionConfigured()
{
return !is_null($this->manager->getSessionConfig()['driver'] ?? null);
}
/**
* Determine if the configured session driver is persistent.
*
* @param array|null $config
*
* @return bool
*/
protected function sessionIsPersistent(array $config = null)
{
$config = $config ?: $this->manager->getSessionConfig();
return !in_array($config['driver'], [null, 'array']);
}
/**
* Determine if the session is using cookie sessions.
*
* @return bool
*/
protected function usingCookieSessions()
{
return false;
}
}
<?php
namespace Modules\Base\Http\Requests;
class AuthorizationRequest extends BaseRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'phone' => 'bail|required|regex:/^1[345789][0-9]{9}$/|exists:users',
'password' => 'required|string|min:6',
];
}
}
<?php
namespace Modules\Base\Http\Requests;
use Dingo\Api\Http\FormRequest;
use Dingo\Api\Http\Request;
class BaseRequest extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
//
];
}
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* @return bool
*
*/
public function isApi()
{
if ($this->container['request'] instanceof Request) {
return true;
}
return false;
}
}
<?php
namespace Modules\Base\Http\Requests;
use Carbon\Carbon;
use Illuminate\Validation\Rule;
use Modules\Base\Entities\Activity;
use SMG\Support\Rules\Mobile;
class EnrollmentRequest extends BaseRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
$user_id = $this->user() ? $this->user()->id : 0;
return [
'activity_id' => ['bail', 'required',
Rule::exists('activities', 'id')->where(function ($query) {
$query->where('enroll_end', '>', Carbon::now());
}),
Rule::unique('enrollments')->where(function ($query) use ($user_id) {
$query->where('user_id', $user_id);
}),
function ($attribute, $value, $fail) {
$active = Activity::where('id', $value)->withCount('enrollments')->first();
if ($active && $active->limit > 0 && $active->enrollments_count >= $active->limit) {
return $fail('报名人数已满,不可以再报名!');
}
},
],
'name' => 'required',
'mobile' => ['required', new Mobile()],
'company' => 'required',
];
}
/**
* @return array
*/
public function messages()
{
return [
'activity_id.unique' => '已报过名,不能再次报名',
];
}
}
<?php
namespace Modules\Base\Http\Requests;
class FileRequest extends BaseRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
$upload = config('upload', []);
$types = implode(',', array_keys($upload));
$validate = isset($upload[$this->type]) ? 'required|file|'.$upload[$this->type]['validate'] : 'required|file';
$rules = [
'type' => 'required|in:'.$types,
'file' => $validate,
];
return $rules;
}
public function messages()
{
return config('upload.'.$this->type.'.validate_msg', []);
}
}
<?php
namespace Modules\Base\Http\Requests;
class OpenloginRequest extends BaseRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
$type = $this->route('type');
switch ($type) {
case 'test':
case 'wx_mini':
return [
'code' => 'bail|required',
];
}
return [];
}
}
<?php
namespace Modules\Base\Http\Requests;
use Modules\Base\Services\Exception\PhoneNullException;
use Modules\Base\Services\SmsService;
class SmsRequest extends BaseRequest
{
/**
* @throws \Throwable
*
* @return array
*/
public function rules()
{
$types = SmsService::getTypes();
$guard = $this->isApi() ? 'api' : null;
if (SmsService::needAuth($this->type)) {
abort_if(auth($guard)->guest(), 401, '需要登陆');
$user = auth($guard)->user();
if (SmsService::needUserPhone($this->type)) {
$phone = $user->phone;
throw_unless($phone, new PhoneNullException());
$this->request->add(['phone' => $phone]);
}
}
$rules = [
'type' => 'required|in:'.implode(',', $types),
'captcha_key' => 'required|string',
'captcha_code' => 'bail|required|captcha_api:'.$this->captcha_key,
//'phone' => 'bail|required|regex:/^1[345789][0-9]{9}$/',
];
if (!SmsService::needUserPhone($this->type)) {
$rules['phone'] = 'bail|required|regex:/^1[345789][0-9]{9}$/'.SmsService::appendPhoneValidateRule($this->type);
}
return $rules;
}
public function attributes()
{
return [
'captcha_key' => '图片验证码 key',
'captcha_code' => '图片验证码',
'phone' => '手机号',
];
}
public function messages()
{
return [
'captcha_code.captcha_api' => '图片验证码错误或已过期',
];
}
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
}
<?php
namespace Modules\Base\Http\Requests;
use Modules\Base\Services\OpenloginService;
class UserRequest extends BaseRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
switch ($this->method()) {
case 'POST':
return [
'phone' => 'bail|required|regex:/^1[345789][0-9]{9}$/|unique:users',
'password' => 'required|string|min:6',
'code' => 'required|string',
];
break;
case 'PUT':
//找回密码
if (strpos($this->path(), 'password') > 0) {
return [
'phone' => 'bail|required|regex:/^1[345789][0-9]{9}$/|exists:users',
'password' => 'required|string|min:6',
'code' => 'required|string',
];
}
//更新资料
$user = \Auth::user();
$userId = $user->id;
$needVerifyPhone = $user->phone ? '|required_with:phone' : '';
//当用户手机号为空,且传了encryptedData 和 iv 参数 ,试图解析手机号
if (!$user->phone && $this->encryptedData && $this->iv) {
$data = app(OpenloginService::class)->decryptData($this->iv, $this->encryptData, $userId);
if ($data && $data['purePhoneNumber']) {
$this->request->add(['phone' => $data['purePhoneNumber']]);
}
}
return [
'name' => 'between:1,25',
'email' => 'email|unique:users,email,'.$userId,
//'introduction' => 'max:80',
'file_id' => 'exists:files,id,type,avatar,user_id,'.$userId,
'ext' => 'array',
'old_password' => 'bail|required_with:password|string|min:6|check_password:'.$user->getAuthPassword(),
'password' => 'string|min:6',
'phone' => 'bail|regex:/^1[345789][0-9]{9}$/|unique:users',
'sex' => 'in:0,1,2',
'code' => 'nullable'.$needVerifyPhone.'|string',
];
break;
}
}
public function attributes()
{
return [
'old_password' => '旧密码',
];
}
public function messages()
{
return [
'old_password.required_with' => '旧密码不能为空',
];
}
}
<?php
$api = app('Dingo\Api\Routing\Router');
$api->version(
'v1',
array_merge(
[
'namespace' => 'Modules\Base\Http\Controllers\Api',
'prefix' => 'api/base',
],
config('api.defaultSetting', [])
),
function ($api) {
$api->get('/', 'ApiController@index')->name('api.base.home');
// 短信验证码
$api->post('sms', 'SmsController@store')
->name('api.base.sms.store');
// 用户注册
$api->post('users', 'UsersController@store')
->name('api.base.users.store');
// 登录
$api->post('authorizations', 'AuthorizationsController@store')
->name('api.base.authorizations.store');
// 第三方账号登录
$api->post('authorizations/openlogin/{type}', 'AuthorizationsController@openlogin')
->name('api.base.authorizations.openlogin');
//短信重置密码
$api->put('user/password', 'UsersController@password')
->name('api.base.user.password');
// 需要 token 验证的接口
$api->group(['middleware' => 'api.auth'], function ($api) {
// 刷新token
$api->put('authorizations/current', 'AuthorizationsController@update')
->name('api.base.authorizations.update');
// 删除token
$api->delete('authorizations/current', 'AuthorizationsController@destroy')
->name('api.base.authorizations.destroy');
// 文件上传
$api->post('files', 'FilesController@store')
->name('api.base.files.store');
// 当前登录用户信息
$api->get('user', 'UsersController@me')
->name('api.base.user.show');
// 编辑登录用户信息
$api->put('user', 'UsersController@update')
->name('api.base.user.update');
// 通知列表
$api->get('user/notifications', 'NotificationsController@index')
->name('api.base.user.notifications.index');
// 查看某一条通知
$api->get('user/notifications/{notification_id}', 'NotificationsController@show')
->name('api.base.user.notifications.show');
//发送一个测试的通知消息
$api->post('user/notifications', 'NotificationsController@test')
->name('api.base.user.notifications.test');
// 通知统计
$api->get('user/notifications/stats', 'NotificationsController@stats')
->name('api.base.user.notifications.stats');
// 标记消息通知为已读
$api->put('user/read/notifications', 'NotificationsController@read')
->name('api.base.user.notifications.read');
});
}
);
$api->version(
'v1',
array_merge(
[
'namespace' => 'Modules\Base\Http\Controllers\Api',
'prefix' => 'api',
],
config('api.defaultSetting', [])
),
function ($api) {
$api->get('/', 'ApiController@index')->name('api.base.home');
// 最近报名用户信息
$api->get('activities/{activity}', 'ActivityController@detail')
->name('api.activities.detail');
// 最近报名用户信息
$api->get('activities', 'ActivityController@index')
->name('api.activities.index');
// 最近报名用户信息
$api->get('enrollments', 'EnrollmentController@index')
->name('api.enrollments.index');
// 需要 token 验证的接口
$api->group(['middleware' => 'api.auth'], function ($api) {
// 我的报名信息
$api->get('user/enrollment', 'EnrollmentController@me')
->name('api.user.enrollment');
// 我的报名信息
$api->get('user/enrollments', 'EnrollmentController@meEnrollments')
->name('api.user.enrollments');
// 报名
$api->post('enrollments', 'EnrollmentController@store')
->name('api.enrollments.store');
});
}
);
Route::group([
'prefix' => config('admin.route.prefix'),
'middleware' => config('admin.route.middleware'),
'namespace' => 'Modules\Base\Http\Controllers\Admin',
], function ($router) {
//活动
$router->resource('/activity', 'ActivityController');
//报名
$router->resource('/enrollment', 'EnrollmentController');
$router->resource('/files', 'FilesController');
$router->resource('/openids', 'OpenidsController');
$router->resource('/users', 'UsersController');
});
<?php
namespace Modules\Base\Listeners;
class ProcessUploadImage
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param object $event
*
* @return void
*/
public function handle($event)
{
$file = $event->file;
$config = config('upload.'.$file->type, []);
if (!isset($config['image_processor']) || !$config['image_processor']) {
return;
}
$root = config('filesystems.disks.'.$config['filesystem'].'.root', false);
$img_file = $root ? $root.'/'.$file->path : get_file_url($file->path, $file->type);
$img = \Image::make($img_file);
$processors = explode('|', $config['image_processor']);
foreach ($processors as $processor) {
$info = explode(':', $processor);
list($method, $args) = count($info) > 1 ? [$info[0], explode(',', $info[1])] : [$info[0], []];
array_walk($args, function (&$val) {
if ($val == 'null') {
$val = null;
}
if (substr($val, 0, 11) == 'constraint=') {
$param = substr($val, 11);
$val = function ($constraint) use ($param) {
$funcs = explode('&', $param);
foreach ($funcs as $func) {
call_user_func([$constraint, $func]);
}
};
}
});
call_user_func_array([$img, $method], $args);
}
$img->save();
clearstatcache();
$file->size = filesize($img_file);
$file->save();
}
}
<?php
namespace Modules\Base\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class TestNotify extends Notification
{
use Queueable;
public $info;
/**
* Create a new notification instance.
*
* @return void
*/
public function __construct($info)
{
$this->info = $info;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
*
* @return array
*/
public function via($notifiable)
{
return ['database'];
//如果用数据库通知记得在.env里面配置好邮件相关参数
//return ['mail', 'database'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
*
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->line('The introduction to the notification.')
->action('Notification Action', url('/'))
->line('Thank you for using our application!');
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
*
* @return array
*/
public function toArray($notifiable)
{
return [
'id' => $this->info['id'],
'subject' => $this->info['subject'],
'content' => $this->info['content'],
];
}
}
<?php
namespace Modules\Base\Providers;
use Illuminate\Database\Eloquent\Factory;
use Illuminate\Support\ServiceProvider;
use Modules\Base\Events\FileUploaded;
use Modules\Base\Listeners\ProcessUploadImage;
use Modules\Base\Services\SmsService;
class BaseServiceProvider extends ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = false;
/**
* Boot the application events.
*
* @return void
*/
public function boot()
{
$this->registerTranslations();
$this->registerConfig();
$this->registerViews();
$this->registerFactories();
$this->loadMigrationsFrom(__DIR__.'/../Database/Migrations');
//密码验证
\Validator::extend('check_password', function ($attribute, $value, $parameters, $validator) {
$hashed_password = empty($parameters) ? \Auth::user()->getAuthPassword() : $parameters[0];
return \Hash::check($value, $hashed_password);
});
\Validator::replacer('check_password', function ($message, $attribute, $rule, $parameters) {
return '密码验证失败';
});
//密码验证
\Validator::extend('check_sms', function ($attribute, $value, $parameters, $validator) {
$data = $validator->getData();
$phone = $parameters[0] ?? array_get($data, 'phone');
$type = $parameters[1] ?? array_get($data, 'type');
if (!$type || !$phone) {
return false;
}
return app(SmsService::class)->verifyCode($value, $type, $phone, true);
});
\Validator::replacer('check_sms', function ($message, $attribute, $rule, $parameters) {
return '手机验证码错误或已过期,请重试';
});
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
//
// API 模型找不到时返回404
\API::error(function (\Illuminate\Database\Eloquent\ModelNotFoundException $exception) {
abort(404);
});
//API没有权限返回403
\API::error(function (\Illuminate\Auth\Access\AuthorizationException $exception) {
abort(403, $exception->getMessage());
});
//API请求验证错误
\API::error(function (\Illuminate\Validation\ValidationException $exception) {
throw new \Dingo\Api\Exception\ValidationHttpException($exception->errors());
});
//图片上传事件
$this->app['events']->listen(FileUploaded::class, ProcessUploadImage::class);
}
/**
* Register config.
*
* @return void
*/
protected function registerConfig()
{
$this->publishes([
__DIR__.'/../Config/config.php' => config_path('base.php'),
], 'config');
$this->mergeConfigFrom(
__DIR__.'/../Config/config.php',
'base'
);
}
/**
* Register views.
*
* @return void
*/
public function registerViews()
{
$viewPath = resource_path('views/modules/base');
$sourcePath = __DIR__.'/../Resources/views';
$this->publishes([
$sourcePath => $viewPath,
], 'views');
$this->loadViewsFrom(array_merge(array_map(function ($path) {
return $path.'/modules/base';
}, \Config::get('view.paths')), [$sourcePath]), 'base');
}
/**
* Register translations.
*
* @return void
*/
public function registerTranslations()
{
$langPath = resource_path('lang/modules/base');
if (is_dir($langPath)) {
$this->loadTranslationsFrom($langPath, 'base');
} else {
$this->loadTranslationsFrom(__DIR__.'/../Resources/lang', 'base');
}
}
/**
* Register an additional directory of factories.
*
* @return void
*/
public function registerFactories()
{
if (!app()->environment('production')) {
app(Factory::class)->load(__DIR__.'/../Database/factories');
}
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return [];
}
}
基础模块
\ No newline at end of file
@extends('base::layouts.master')
@section('content')
<h1>Hello World</h1>
<p>
This view is loaded from module: {!! config('base.name') !!}
</p>
@stop
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Module Base</title>
{{-- Laravel Mix - CSS File --}}
{{-- <link rel="stylesheet" href="{{ mix('css/base.css') }}"> --}}
</head>
<body>
@yield('content')
{{-- Laravel Mix - JS File --}}
{{-- <script src="{{ mix('js/base.js') }}"></script> --}}
</body>
</html>
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/6/13
* Time: 9:52
*/
namespace Modules\Base\Services;
class BaseService
{
public $model;
public function create($data)
{
return $this->model = $this->model->create($data);
}
public function update($id, $data)
{
$this->model = $this->model->find($id);
return $this->model->update($data);
}
}
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/8/22
* Time: 10:42
*/
namespace Modules\Base\Services\Exception;
use Throwable;
class PhoneNullException extends \Exception
{
public function __construct(string $message = "", int $code = 0, Throwable $previous = null)
{
$message = $message ?: '您还没有设置手机号';
parent::__construct($message, 102, $previous);
}
public static function make($message = '')
{
return new static($message);
}
}
\ No newline at end of file
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/6/14
* Time: 14:47
*/
namespace Modules\Base\Services;
use Modules\Base\Entities\File;
use Modules\Base\Events\FileUploaded;
class FileService extends BaseService
{
public function __construct(File $file)
{
$this->model = $file;
}
public function process($file, $type)
{
$config = config('upload', []);
$folder = $config[$type]['folder'];
$folder_name = "$folder/".date('Ym', time()).'/'.date('d', time());
$path = $file->store($folder_name, $config[$type]['filesystem']);
$info = [];
$info['user_id'] = \Auth::id();
$info['type'] = $type;
$info['path'] = $path;
$info['size'] = $file->getSize();
$info['mime'] = $file->getMimeType();
$info['name'] = $file->getClientOriginalName();
$this->create($info);
event(new FileUploaded($this->model));
return $this->model;
}
}
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/6/13
* Time: 9:53
*/
namespace Modules\Base\Services;
use Modules\Base\Entities\Openid;
use Modules\Base\Entities\User;
use SMG\Support\Traits\HasHttpRequest;
class OpenloginService extends BaseService
{
use HasHttpRequest;
public function __construct(Openid $openid, UserService $userService)
{
$this->model = $openid;
$this->userService = $userService;
}
public static function getTypes()
{
return ['wx_mini', 'test'];
}
/**
* @param $type
* @param array $data
*
* @throws \Throwable
*
* @return \Modules\Base\Entities\User
*/
public function login($type, $data = [])
{
throw_unless(
in_array($type, self::getTypes()),
\Illuminate\Validation\ValidationException::withMessages([
'type' => ['错误的登陆类型'],
])
);
$openid_data = [];
$openid = $this->getOpenid($type, $data, $openid_data);
$account_type = $type == 'wx_mini' ? 'weixin' : $type;
return $this->userService->openUser($account_type, $openid, $data, $openid_data);
}
/**
* @param $type
* @param $data
* @param $openid_data
*
* @throws \Throwable
*
* @return mixed
*/
public function getOpenid($type, &$data, &$openid_data)
{
if ($type == 'wx_mini') {
$app = app('wechat.mini_program');
$result = $app->auth->session($data['code']);
if (isset($result['errcode'])) {
throw \Illuminate\Validation\ValidationException::withMessages([
'code' => [$result['errmsg']],
]);
}
if (isset($result['unionid'])) {
$result['origin_openid'] = $result['openid'];
}
$openid_data['session_key'] = $result['session_key'];
return $result['unionid'] ?? $result['openid'];
} elseif ($type == 'test') {
return $data['code'];
}
}
/**
* 小程序解密数据
*
* @param $iv
* @param $encryptData
* @param int $user_id
*
* @return bool|array
*/
public function decryptData($iv, $encryptData, $user_id = 0)
{
$user_id || $user_id = auth()->id();
if (!$user_id) {
return false;
}
$openid = $this->model->where('user_id', $user_id)->where('type', 'weixin')->first();
$session_key = array_get($openid, 'session_key');
if (!$session_key) {
return false;
}
$app = app('wechat.mini_program');
$decryptedData = $app->encryptor->decryptData($session_key, $iv, $encryptData);
if ($decryptedData && isset($decryptedData)) {
return $decryptedData;
}
return false;
}
public function userOpenid($user_id = null, $errthrow = true)
{
$user = $user_id ? (($user_id instanceof User) ? $user_id : User::find($user_id)) : auth()->user();
//暂时从用户 ext.openid获取
$openid = array_get($user, 'ext.openid', false);
throw_if(!$openid && $errthrow, new \Exception('用户OPENID不存在'));
return $openid;
}
}
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/6/12
* Time: 17:35
*/
namespace Modules\Base\Services;
class SmsService extends BaseService
{
const REGISTER = 1;
const FIND_PASSWORD = 2;
const CHANGE_PHONE = 3;
const ADD_CARD = 4;
const SET_PAY_PASSWORD = 5;
/**
* 检查要发送的类型是应该向新手机号发还是已经存在的手机号发
*
* @param $type
*
* @return bool
*/
public static function needNewPhone($type)
{
return in_array($type, [self::REGISTER, self::CHANGE_PHONE]);
}
/**
* 短信验证时附加检查规则
*
* @param $type
*
* @return string
*/
public static function appendPhoneValidateRule($type)
{
switch ($type) {
case self::REGISTER:
case self::CHANGE_PHONE:
return '|unique:users';
case self::FIND_PASSWORD:
case self::SET_PAY_PASSWORD:
return '|exists:users';
default:
return '';
}
}
/**
* 发送该类型短信是否需要登陆
*
* @param $type
*
* @return string
*/
public static function needAuth($type)
{
switch ($type) {
case self::CHANGE_PHONE:
case self::SET_PAY_PASSWORD:
return true;
default:
return false;
}
}
/**
* 发送该类型短信是否需要检查手机号信息
*
* @param $type
*
* @return string
*/
public static function needUserPhone($type)
{
switch ($type) {
case self::SET_PAY_PASSWORD:
return true;
default:
return false;
}
}
public static function getTypes()
{
$oClass = new \ReflectionClass(__CLASS__);
return array_values($oClass->getConstants());
}
public function send($phone, $type, $args = [])
{
$code = $this->generateCode($phone, $type);
return true;
}
public function generateCode($phone, $type)
{
$code = 1234;
$key = 'sms_'.$type.'_'.$phone;
\Cache::put($key, $code, 5);
return $code;
}
public function verifyCode($code, $type, $phone, $return = false)
{
$key = 'sms_'.$type.'_'.$phone;
if (\Cache::get($key) == $code) {
//\Cache::forget($key);
return true;
} else {
if ($return) {
return false;
}
$error = \Illuminate\Validation\ValidationException::withMessages([
'code' => ['手机验证码错误或已过期,请重试'],
]);
throw $error;
}
}
}
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/6/13
* Time: 9:53
*/
namespace Modules\Base\Services;
use Modules\Base\Entities\File;
use Modules\Base\Entities\Openid;
use Modules\Base\Entities\User;
class UserService extends BaseService
{
public function __construct(User $user)
{
$this->model = $user;
}
public function update($id, $data)
{
if (isset($data['file_id']) && $file = File::find($data['file_id'])) {
$data['avatar'] = $file['path'];
}
if (isset($data['password'])) {
$data['password'] = \Hash::make($data['password']);
}
return parent::update($id, $data); // TODO: Change the autogenerated stub
}
/**
* 根据OPENID获取用户
*
* @param $type
* @param $openid
* @param array $data
* @param User|null $assocUser
*
* @return User
*/
public function openUser($type, $openid, $data = [], $openid_data = [], User $assocUser = null)
{
$openUser = Openid::firstOrNew(['type' => $type, 'openid' => $openid]);
$create =false;
if (!$openUser->user_id) {
if (!$assocUser) {
$data = ['password' => 'temp', 'ext' => ['type' => $type, 'openid' => $openid]] + $data;
$data['password'] = \Hash::make($data['password']);
$assocUser = $this->model->create($data);
}
$create = true;
$openUser->user_id = $assocUser->id;
$openUser->extra = $data + $openid_data;
$openUser->save();
}
if (!$create && !empty($openid_data)) {
$openUser->extra = array_merge((array) $openUser->extra , (array) $openid_data);
$openUser->save();
}
return $openUser->user;
}
}
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/6/15
* Time: 9:47
*/
namespace Modules\Base\Transformers;
use Illuminate\Support\Traits\Macroable;
class AccessTokenTransformer extends BaseTransformer
{
use Macroable;
public $availableIncludes = ['user'];
/**
* @OA\Schema(
* description="Token信息",
* type="object",
* schema="Token",
* @OA\Property(property="access_token", type="string", description="Token"),
* @OA\Property(property="token_type", type="string", description="Token类型"),
* @OA\Property(property="expires_in", type="integer", description="过期时间"),
* @OA\Property(property="user", type="object", description="用户", @OA\Property(property="data", type="object", ref="#/components/schemas/User"))
* )
*/
public function transform($user)
{
return [
'access_token' => \Auth::guard('api')->login($user),
'token_type' => 'Bearer',
'expires_in' => \Auth::guard('api')->factory()->getTTL() * 60,
];
}
public function includeUser($user)
{
return $this->item($user, new UserTransformer());
}
}
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/6/15
* Time: 9:47
*/
namespace Modules\Base\Transformers;
use Modules\Base\Entities\Activity;
use Modules\Base\Entities\Enrollment;
class ActivityTransformer extends BaseTransformer
{
public $availableIncludes=['enrollments','enrollment'];
/**
* @param Activity $activity
* @return array
*
* @OA\Schema(
* description="活动信息",
* type="object",
* schema="Activity",
* @OA\Property(property="id", type="integer", description="ID"),
* @OA\Property(property="start", type="string", description="开始时间"),
* @OA\Property(property="end", type="string", description="开始时间"),
* @OA\Property(property="enroll_start", type="string", description="报名开始时间"),
* @OA\Property(property="enroll_end", type="string", description="报名结束时间"),
* @OA\Property(property="cover", type="string", description="封面图"),
* @OA\Property(property="price", type="string", description="价格"),
* @OA\Property(property="sponsor", type="string", description="主办人"),
* @OA\Property(property="address", type="string", description="地址"),
* @OA\Property(property="contact", type="string", description="联系方式"),
* @OA\Property(property="introduction", type="string", description="简介"),
* @OA\Property(property="content", type="string", description="内容"),
* @OA\Property(property="limit", type="number", description="数量限制"),
* @OA\Property(property="enrolledCount", type="number", description="报名数量"),
* @OA\Property(property="enrollment", type="number", description="当前用户报名信息"),
* @OA\Property(property="enrollments", type="number", description="最近报名信息"),
* )
*/
public function transform(Activity $activity)
{
return map_attr($activity, ['id','title', 'start', 'end', 'enroll_start', 'enroll_end', 'cover', 'price', 'sponsor', 'address', 'contact', 'content', 'limit', 'enrolledCount','introduction']);
}
public function includeEnrollments($activity)
{
return $this->collection($activity->enrollments()->orderBy('id', 'desc')->limit(15)->get(), new EnrollmentTransformer());
}
public function includeEnrollment($activity)
{
$user_id = \Auth::guard('api')->id();
if (!$user_id) return null;
$enrollment = $activity->enrollments()->where('user_id', $user_id)->first();
if (!$enrollment) return null;
return $this->item($enrollment, new EnrollmentTransformer(true));
}
}
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/6/27
* Time: 17:44
*/
namespace Modules\Base\Transformers;
use League\Fractal\TransformerAbstract;
class BaseTransformer extends TransformerAbstract
{
static $extraIncludes = [];
static $extraDefaultIncludes = [];
public function __construct()
{
if (!isset(static::$extraIncludes[static::class])) {
static::$extraIncludes[static::class]=[];
}
if (!isset(static::$extraDefaultIncludes[static::class])) {
static::$extraDefaultIncludes[static::class]=[];
}
$this->availableIncludes += static::$extraIncludes[static::class];
$this->defaultIncludes +=static::$extraDefaultIncludes[static::class];
}
public static function addIncludes($name)
{
if (!isset(static::$extraIncludes[static::class])) {
static::$extraIncludes[static::class]=[];
}
static::$extraIncludes[static::class] += (array)$name;
}
public static function addDefaultIncludes($name)
{
if (!isset(static::$extraDefaultIncludes[static::class])) {
static::$extraDefaultIncludes[static::class]=[];
}
static::$extraDefaultIncludes[static::class] += (array)$name;
}
}
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/6/15
* Time: 9:47
*/
namespace Modules\Base\Transformers;
use League\Fractal\TransformerAbstract;
class CommonTransformer extends TransformerAbstract
{
public function transform($data)
{
return (array)$data;
}
}
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/6/15
* Time: 9:47
*/
namespace Modules\Base\Transformers;
use Modules\Base\Entities\Enrollment;
class EnrollmentTransformer extends BaseTransformer
{
protected $defaultIncludes = ['user'];
public $availableIncludes=['activity'];
protected $isMe = false;
public function __construct($isMe = false)
{
parent::__construct();
$this->isMe = $isMe;
}
/**
* @OA\Schema(
* description="报名信息",
* type="object",
* schema="Enrollment",
* @OA\Property(property="id", type="integer", description="ID"),
* )
*/
public function transform(Enrollment $enrollment)
{
if ($this->isMe) {
return map_attr($enrollment, ['id', 'mobile', 'name', 'company', 'pay_status', 'recommender', 'created_at']);
}
return map_attr($enrollment, ['id', 'created_at']);
}
public function includeUser($enrollment)
{
return $this->item($enrollment->user, new UserBaseTransformer());
}
public function includeActivity($enrollment)
{
return $this->item($enrollment->activity, new ActivityTransformer());
}
}
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/6/15
* Time: 9:47
*/
namespace Modules\Base\Transformers;
use Modules\Base\Entities\File;
class FileTransformer extends BaseTransformer
{
/**
* @OA\Schema(
* description="文件信息",
* type="object",
* schema="File",
* @OA\Property(property="id", type="integer", description="ID"),
* @OA\Property(property="name", type="string", description="文件名"),
* @OA\Property(property="path", type="string", description="文件路径"),
* @OA\Property(property="mime", type="string", description="MIME类型"),
* @OA\Property(property="type", type="string", description="文件类型"),
* @OA\Property(property="url", type="string", description="访问URL"),
* @OA\Property(property="created_at", type="string", description="注册时间"),
* @OA\Property(property="updated_at", type="string", description="更新时间")
* )
*/
public function transform(File $file)
{
return map_attr($file, [
'id', 'name', 'path', 'type', 'mime', 'created_at', 'updated_at',
'url' => get_file_url($file->path, $file->type),
]);
}
}
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/6/8
* Time: 12:20
*/
namespace Modules\Base\Transformers;
use Illuminate\Notifications\DatabaseNotification;
class NotificationTransformer extends BaseTransformer
{
/**
* @OA\Schema(
* description="通知信息",
* type="object",
* schema="Notification",
* @OA\Property(property="id", type="integer", description="ID"),
* @OA\Property(property="type", type="string", description="通知类型"),
* @OA\Property(property="data", type="object", description="通知数据"),
* @OA\Property(property="read_at", type="string", description="查看时间"),
* @OA\Property(property="created_at", type="string", description="注册时间"),
* @OA\Property(property="updated_at", type="string", description="更新时间")
* )
*/
public function transform(DatabaseNotification $notification)
{
return map_attr($notification, ['id', 'type', 'data', 'read_at', 'created_at', 'updated_at']);
}
}
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/6/13
* Time: 11:12
*/
namespace Modules\Base\Transformers;
use Illuminate\Support\Traits\Macroable;
use Modules\Base\Entities\User;
class UserBaseTransformer extends BaseTransformer
{
use Macroable;
/**
* @param User $user
* @return array
*
* @OA\Schema(
* description="基本用户信息",
* type="object",
* schema="UserBase",
* @OA\Property(property="id", type="integer", description="用户ID"),
* @OA\Property(property="name", type="string", description="用户名"),
* @OA\Property(property="avatar", type="string", description="头像")
* )
*/
public function transform(User $user)
{
return map_attr($user, ['id', 'name', 'avatar']);
}
}
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/6/13
* Time: 11:12
*/
namespace Modules\Base\Transformers;
use Illuminate\Support\Traits\Macroable;
use Modules\Base\Entities\User;
class UserTransformer extends BaseTransformer
{
use Macroable;
/**
* @OA\Schema(
* description="用户信息",
* type="object",
* schema="User",
* @OA\Property(property="id", type="integer", description="用户ID"),
* @OA\Property(property="name", type="string", description="用户名"),
* @OA\Property(property="email", type="string", description="邮箱"),
* @OA\Property(property="phone", type="string", description="手机号"),
* @OA\Property(property="created_at", type="string", description="注册时间"),
* @OA\Property(property="updated_at", type="string", description="更新时间")
* )
*/
public function transform(User $user)
{
return map_attr($user, ['id', 'name', 'email', 'avatar', 'phone', 'company', 'created_at', 'updated_at']);
}
}
<?php
/**
*
* @OA\Get(
* tags={"收货地址"},
* summary="用户地址列表",
* path="/api/package/user/addresses",
* security={
* {"jwt_auth": {}}
* },
* @OA\Response(
* response="200",
* description="成功",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property="data",
* type="array",
* @OA\Items(ref="#/components/schemas/Address"),
* description="列表"
* ),
* )
* )
* )
* )
*/
/**
*
* @OA\Get(
* tags={"收货地址"},
* summary="用户默认地址",
* path="/api/package/user/address",
* security={
* {"jwt_auth": {}}
* },
* @OA\Response(
* response="200",
* description="成功",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(type="object",
* @OA\Property(property="data", type="object", ref="#/components/schemas/Address")
* )
* )
* )
* )
*/
/**
* @OA\Post(
* tags={"收货地址"},
* summary="用户创建地址",
* path="/api/package/user/addresses",
* security={
* {"jwt_auth": {}}
* },
* @OA\RequestBody(
* required=true,
* @OA\MediaType(
* mediaType="application/x-www-form-urlencoded",
* @OA\Schema(
* type="object",
* required={"type","file"},
* @OA\Property(
* property="name",
* type="string",
* ),
* @OA\Property(
* property="mobile",
* ref="#/components/schemas/phone"
* ),
* @OA\Property(
* property="area_id",
* type="integer",
* ),
* @OA\Property(
* property="detail",
* type="string",
* ),
* @OA\Property(
* property="is_default",
* type="integer",
* enum={0,1}
* ),
* @OA\Property(
* property="other",
* type="string",
* ),
* @OA\Property(
* property="lat",
* type="number",
* ),
* @OA\Property(
* property="lng",
* type="number",
* ),
* )
* )
* ),
* @OA\Response(
* response="201",
* description="成功",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(type="object",
* @OA\Property(property="data", type="object", ref="#/components/schemas/Address")
* )
* )
* )
* )
*/
/**
* @OA\Put(
* tags={"收货地址"},
* summary="更新地址",
* path="/api/package/user/addresses/{address_id}",
* security={
* {"jwt_auth": {}}
* },
* @OA\Parameter(
* name="address_id",
* in="path",
* description="地址ID",
* required=true,
* @OA\Schema(
* type="integer",
* )
* ),
* @OA\RequestBody(
* required=true,
* @OA\MediaType(
* mediaType="application/x-www-form-urlencoded",
* @OA\Schema(
* type="object",
* required={"type","file"},
* @OA\Property(
* property="name",
* type="string",
* ),
* @OA\Property(
* property="mobile",
* ref="#/components/schemas/phone"
* ),
* @OA\Property(
* property="area_id",
* type="integer",
* ),
* @OA\Property(
* property="detail",
* type="string",
* ),
* @OA\Property(
* property="is_default",
* type="integer",
* enum={0,1}
* ),
* @OA\Property(
* property="other",
* type="string",
* ),
* @OA\Property(
* property="lat",
* type="number",
* ),
* @OA\Property(
* property="lng",
* type="number",
* ),
* )
* )
* ),
* @OA\Response(
* response="200",
* description="成功",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(type="object",
* @OA\Property(property="data", type="object", ref="#/components/schemas/Address")
* )
* )
* )
* )
*/
/**
* @OA\Delete(
* tags={"收货地址"},
* summary="用户删除地址",
* path="/api/package/user/addresses/{address_id}",
* security={
* {"jwt_auth": {}}
* },
* @OA\Parameter(
* name="address_id",
* in="path",
* description="地址ID",
* required=true,
* @OA\Schema(
* type="integer",
* )
* ),
* @OA\Response(
* response="200",
* description="成功"
* )
* )
*/
/**
*
* @OA\Schema(
* description="地址信息",
* type="object",
* schema="Address",
* @OA\Property(property="id", type="integer", description="ID"),
* @OA\Property(property="name", type="string", description="姓名"),
* @OA\Property(property="mobile", type="string", description="电话"),
* @OA\Property(property="area", type="string", description="地区"),
* @OA\Property(property="area_ids", type="string", description="地区ID列表"),
* @OA\Property(property="detail", type="string", description="地址详情"),
* @OA\Property(property="is_default", type="string", description="是否是默认地址"),
* )
*/
\ No newline at end of file
<?php
/**
* API START!
*
* @author syw
*
* @OA\OpenApi(
* @OA\Info(
* version="1.0.0",
* title="接口",
* description="<b>通用状态码</b>:
* 200 成功
* 201 成功创建
* 204 执行成功,没有返回内容
*
* 401 没有登陆
* 403 没有权限
* 404 要操作的资源不存在
* 405 操作方法不允许
* 422 参数验证错误
* 500 程序出现错误
*",
* )
* )
*/
/**
* @OA\SecurityScheme(
* securityScheme="jwt_auth",
* type="http",
* scheme="bearer",
* bearerFormat="JWT",
* )
*
* @OA\Get(
* tags={"基础接口"},
* summary="获取验证码",
* path="/captcha/api",
* @OA\Response(
* response="200",
* description="验证码信息",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(property="data", type="object", ref="#/components/schemas/Verify")
* )
* )
* )
* )
*
*
* @OA\Get(
* tags={"基础接口"},
* summary="缩略图",
* path="/imagecache/{template}/{image_path}",
* @OA\Parameter(
* name="template",
* in="path",
* description="图片处理模板,默认有 small,medium,large三种",
* required=true,
* @OA\Schema(
* type="string",
* )
* ),
* @OA\Parameter(
* name="image_path",
* in="path",
* description="储存的文件名,程序保存时的路径",
* required=true,
* @OA\Schema(
* type="string",
* )
* ),
* @OA\Response(
* response="200",
* description="处理后的图片",
* @OA\MediaType(
* mediaType="image/png",
* @OA\Schema(
* type="string",
* format="binary",
* )
* ),
* @OA\MediaType(
* mediaType="image/jpg",
* @OA\Schema(
* type="string",
* format="binary",
* )
* ),
* @OA\MediaType(
* mediaType="image/jpeg",
* @OA\Schema(
* type="string",
* format="binary",
* )
* ),
* @OA\MediaType(
* mediaType="image/gif",
* @OA\Schema(
* type="string",
* format="binary",
* )
* )
* )
* )
*
* @OA\Schema(
* description="请求验证错误422",
* type="object",
* schema="error422",
* @OA\Property(property="message", type="string", description="422 Unprocessable Entity"),
* @OA\Property(property="error", type="object", description="错误",
* @OA\Property(property="key", type="array", description="请求键值",
* @OA\Items(type="string", description="具体错误"),
* ),
* ),
* @OA\Property(property="status_code", type="integer", description="状态码422", example=422),
* @OA\Property(property="debug", type="object", description="错误调试信息")
* )
*
*
*
* @OA\Schema(
* description="验证码信息",
* type="object",
* schema="Verify",
* @OA\Property(property="sensitive", type="boolean", description="验证码是否大小写敏感"),
* @OA\Property(property="key", type="string", description="验证码KEY"),
* @OA\Property(property="img", type="string", description="验证码图片(base64图片编码)")
* )
*
* @OA\Schema(
* description="手机号",
* type="string",
* schema="phone",
* minLength=11
* )
*
* @OA\Schema(
* description="密码",
* type="string",
* schema="password",
* minLength=6
* )
*
* @OA\Schema(
* description="手机短信验证码",
* type="string",
* schema="phone_code",
* minLength=4
* )
*
* @OA\Schema(
* description="邮箱",
* type="string",
* schema="email"
* )
*
* @OA\Schema(
* description="1为是,0为否",
* type="integer",
* enum={0,1},
* schema="yesno"
* )
*
* @OA\Schema(
* description="验证码KEY",
* type="string",
* schema="captcha_key"
* )
*
* @OA\Schema(
* description="验证码",
* type="string",
* schema="captcha_code"
* )
*/
\ No newline at end of file
<?php
/**
*
* @OA\Get(
* tags={"幻灯片"},
* summary="获取指定位置幻灯片",
* path="/api/package/sliders",
* description="id需要到后台查看",
* @OA\Parameter(
* name="position_id",
* in="query",
* description="位置id",
* required=true,
* @OA\Schema(
* type="integer"
* )
* ),
* @OA\Response(
* response="200",
* description="成功",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property="data",
* type="array",
* @OA\Items(ref="#/components/schemas/Slider"),
* description="列表"
* ),
* )
* )
* )
* )
*/
/**
*
* @OA\Schema(
* description="幻灯片图片信息",
* type="object",
* schema="Slider",
* @OA\Property(property="id", type="integer", description="ID"),
* @OA\Property(property="path", type="string", description="文件地址"),
* @OA\Property(property="click_event_type", type="string", description="事件类型"),
* @OA\Property(property="click_event_value", type="string", description="事件具体值"),
* @OA\Property(property="description", type="string", description="描述"),
* @OA\Property(property="position_id", type="integer", description="位置id"),
* @OA\Property(property="sort", type="integer", description="排序值"),
* )
*/
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment