first commit

This commit is contained in:
2026-01-18 09:52:48 +08:00
commit 836bdc9409
584 changed files with 40891 additions and 0 deletions

View File

@@ -0,0 +1,84 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Ads\Controllers\Admin;
use Illuminate\Http\Request;
use App\Http\Controllers\BaseController;
use Modules\Ads\Services\AdsService;
class Ads extends BaseController {
/**
* @title 广告列表
*
* @param Request $request
* @param AdsService $service
* @return void
*/
public function index(Request $request, AdsService $service) {
try {
$this->data['data'] = $service->getDataList($request);
} catch (\Exception $e) {
$this->data['code'] = 0;
$this->data['message'] = $e->getMessage();
}
return response()->json($this->data);
}
/**
* @title 添加广告
*
* @param Request $request
* @param AdsService $service
* @return void
*/
public function add(Request $request, AdsService $service) {
try {
$this->data['data'] = $service->create($request);
} catch (\Exception $e) {
$this->data['code'] = 0;
$this->data['message'] = $e->getMessage();
}
return response()->json($this->data);
}
/**
* @title 编辑广告
*
* @param Request $request
* @param AdsService $service
* @return void
*/
public function edit(Request $request, AdsService $service) {
try {
$this->data['data'] = $service->update($request);
} catch (\Exception $e) {
$this->data['code'] = 0;
$this->data['message'] = $e->getMessage();
}
return response()->json($this->data);
}
/**
* @title 删除广告
*
* @param Request $request
* @param AdsService $service
* @return void
*/
public function delete(Request $request, AdsService $service) {
try {
$this->data['data'] = $service->delete($request);
} catch (\Exception $e) {
$this->data['code'] = 0;
$this->data['message'] = $e->getMessage();
}
return response()->json($this->data);
}
}

View File

@@ -0,0 +1,35 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Ads\Controllers\Api;
use Illuminate\Http\Request;
use App\Http\Controllers\BaseController;
use Modules\Ads\Services\AdsService;
class Ads extends BaseController {
/**
* @title 广告列表
*
* @param Request $request
* @param AdsService $service
* @return void
*/
public function index(Request $request, AdsService $service){
try {
$request->mergeIfMissing(['status' => 1]);
$this->data['data'] = $service->getDataList($request);
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return response()->json($this->data);
}
}

View File

@@ -0,0 +1,28 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Ads\Models;
use Illuminate\Database\Eloquent\Builder;
use App\Models\BaseModel;
class Ads extends BaseModel {
protected $table = 'ads';
protected $fillable = ['title', 'description', 'logo', 'sort','status'];
// protected $hidden = ['deleted_at'];
protected function casts(): array {
return [
'sort' => 'integer',
'status' => 'integer',
'created_at' => 'datetime:Y-m-d H:i:s',
'updated_at' => 'datetime:Y-m-d H:i:s',
];
}
}

View File

View File

@@ -0,0 +1,120 @@
<?php
namespace Modules\Ads\Providers;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
class AdsServiceProvider extends ServiceProvider
{
protected string $moduleName = 'Ads';
protected string $moduleNameLower = 'ads';
/**
* Boot the application events.
*/
public function boot(): void
{
$this->registerCommands();
$this->registerCommandSchedules();
$this->registerTranslations();
$this->registerConfig();
$this->registerViews();
$this->loadMigrationsFrom(module_path($this->moduleName, 'database/migrations'));
}
/**
* Register the service provider.
*/
public function register(): void
{
$this->app->register(EventServiceProvider::class);
$this->app->register(RouteServiceProvider::class);
}
/**
* Register commands in the format of Command::class
*/
protected function registerCommands(): void
{
// $this->commands([]);
}
/**
* Register command Schedules.
*/
protected function registerCommandSchedules(): void
{
// $this->app->booted(function () {
// $schedule = $this->app->make(Schedule::class);
// $schedule->command('inspire')->hourly();
// });
}
/**
* Register translations.
*/
public function registerTranslations(): void
{
$langPath = resource_path('lang/modules/'.$this->moduleNameLower);
if (is_dir($langPath)) {
$this->loadTranslationsFrom($langPath, $this->moduleNameLower);
$this->loadJsonTranslationsFrom($langPath);
} else {
$this->loadTranslationsFrom(module_path($this->moduleName, 'lang'), $this->moduleNameLower);
$this->loadJsonTranslationsFrom(module_path($this->moduleName, 'lang'));
}
}
/**
* Register config.
*/
protected function registerConfig(): void
{
$this->publishes([module_path($this->moduleName, 'config/config.php') => config_path($this->moduleNameLower.'.php')], 'config');
$this->mergeConfigFrom(module_path($this->moduleName, 'config/config.php'), $this->moduleNameLower);
}
/**
* Register views.
*/
public function registerViews(): void
{
$viewPath = resource_path('views/modules/'.$this->moduleNameLower);
$sourcePath = module_path($this->moduleName, 'resources/views');
$this->publishes([$sourcePath => $viewPath], ['views', $this->moduleNameLower.'-module-views']);
$this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), $this->moduleNameLower);
$componentNamespace = str_replace('/', '\\', config('modules.namespace').'\\'.$this->moduleName.'\\'.ltrim(config('modules.paths.generator.component-class.path'), config('modules.paths.app_folder', '')));
Blade::componentNamespace($componentNamespace, $this->moduleNameLower);
}
/**
* Get the services provided by the provider.
*
* @return array<string>
*/
public function provides(): array
{
return [];
}
/**
* @return array<string>
*/
private function getPublishableViewPaths(): array
{
$paths = [];
foreach (config('view.paths') as $path) {
if (is_dir($path.'/modules/'.$this->moduleNameLower)) {
$paths[] = $path.'/modules/'.$this->moduleNameLower;
}
}
return $paths;
}
}

View File

@@ -0,0 +1,38 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Ads\Providers;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event handler mappings for the application.
*
* @var array<string, array<int, string>>
*/
protected $listen = [];
/**
* Indicates if events should be discovered.
*
* @var bool
*/
protected static $shouldDiscoverEvents = true;
/**
* Configure the proper event listeners for email verification.
*
* @return void
*/
protected function configureEmailVerification(): void
{
}
}

View File

@@ -0,0 +1,67 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Ads\Providers;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class RouteServiceProvider extends ServiceProvider
{
/**
* Called before routes are registered.
*
* Register any model bindings or pattern based filters.
*/
public function boot(): void
{
parent::boot();
}
/**
* Define the routes for the application.
*/
public function map(): void
{
$this->mapApiRoutes();
$this->mapWebRoutes();
$this->mapAdminRoutes();
}
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*/
protected function mapWebRoutes(): void
{
Route::middleware('web')->group(module_path('Ads', '/routes/web.php'));
}
/**
* Define the "api" routes for the application.
*
* These routes are typically stateless.
*/
protected function mapApiRoutes(): void
{
Route::middleware('api')->prefix('api')->name('api.')->group(module_path('Ads', '/routes/api.php'));
}
/**
* Define the "api" routes for the application.
*
* These routes are typically stateless.
*/
protected function mapAdminRoutes(): void
{
Route::middleware('api')->prefix('admin')->name('admin.')->group(module_path('Ads', '/routes/admin.php'));
}
}

View File

@@ -0,0 +1,124 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Ads\Services;
use Modules\Ads\Models\Ads;
class AdsService {
/**
* @title 广告列表
*
* @param [type] $request
* @return void
*/
public function getDataList($request){
$map = [];
if($request->filled('title')){
$map[] = ['title', 'like', '%'.$request->input('title').'%'];
}
if($request->filled('client_id')){
$map[] = ['client_id', '=', $request->input('client_id')];
}
if($request->filled('code')){
$map[] = ['code', '=', $request->input('code')];
}
if($request->filled('group')){
$map[] = ['group', '=', $request->input('group')];
}
if($request->filled('status')){
$map[] = ['status', '=', $request->input('status')];
}
$query = Ads::where($map);
$query->orderBy($request->input('order', 'sort'), $request->input('sort', 'desc'));
if($request->filled('page')){
$data = [
'total' => $query->count(),
'page' => $request->input('page', 1),
'data' => $query->offset($request->input('offset', 0))->limit($request->input('limit', 10))->get(),
];
}else{
$data = $query->get();
}
return $data;
}
/**
* @title 添加广告
*
* @param [type] $request
* @return void
*/
public function create($request){
$request->validate([
'title' => 'required',
'group' => 'required'
], [
'title.required' => '请输入广告名称',
'group.required' => '请输入广告位标识'
]);
$ads = new Ads;
foreach ($ads->setFilterFields($request->all()) as $key => $value) {
$ads->$key = $value;
}
$ads->save();
return $ads;
}
/**
* @title 更新广告
*
* @param [type] $request
* @return void
*/
public function update($request){
$request->validate([
'title' => 'required',
'group' => 'required'
], [
'title.required' => '请输入广告名称',
'group.required' => '请输入广告位标识'
]);
$ads = Ads::findOrFail($request->input('id'));
foreach ($ads->setFilterFields($request->all()) as $key => $value) {
$ads->$key = $value;
}
$ads->save();
return $ads;
}
public function delete($request){
if($request->filled('id')){
try {
$ads = Ads::findOrFail($request->input('id'));
} catch (\Throwable $th) {
throw new \Exception("广告不存在!", 1);
}
$ads->delete();
}
if($request->filled('ids')){
try {
$ads = Ads::whereIn('id', $request->input('ids'));
$ads->delete();
} catch (\Throwable $th) {
throw new \Exception($th->getMessage(), 1);
}
}
return $ads;
}
}

30
modules/Ads/composer.json Normal file
View File

@@ -0,0 +1,30 @@
{
"name": "tensent/ads",
"description": "",
"authors": [
{
"name": "molong",
"email": "molong@tensent.cn"
}
],
"extra": {
"laravel": {
"providers": [],
"aliases": {
}
}
},
"autoload": {
"psr-4": {
"Modules\\Ads\\": "app/",
"Modules\\Ads\\Database\\Factories\\": "database/factories/",
"Modules\\Ads\\Database\\Seeders\\": "database/seeders/"
}
},
"autoload-dev": {
"psr-4": {
"Modules\\Ads\\Tests\\": "tests/"
}
}
}

View File

View File

@@ -0,0 +1,5 @@
<?php
return [
'name' => 'Ads',
];

View File

View File

View File

@@ -0,0 +1,39 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration{
/**
* Run the migrations.
*/
public function up(): void {
Schema::create('ads', function (Blueprint $table) {
$table->id()->uniqid()->comment('主键id');
$table->unsignedBigInteger('client_id')->default(0)->comment('站点ID');
$table->string('title')->comment('广告标题');
$table->string('name')->nullable()->comment('广告标识');
$table->string('group')->nullable()->comment('广告所属板块标识');
$table->string('description')->nullable()->comment('广告描述');
$table->string('cover')->nullable()->comment('广告封面');
$table->string('link')->nullable()->comment('广告链接');
$table->string('sort')->default(0)->comment('排序');
$table->tinyInteger('status')->default(1)->comment('状态 1正常 2禁用');
$table->timestamp('created_at')->nullable()->comment('创建时间');
$table->timestamp('updated_at')->nullable()->comment('更新时间');
$table->engine = 'InnoDB';
$table->charset = 'utf8mb4';
$table->collation = 'utf8mb4_unicode_ci';
$table->comment('广告表');
});
}
/**
* Reverse the migrations.
*/
public function down(): void {
Schema::dropIfExists('ads');
}
};

View File

View File

@@ -0,0 +1,42 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Ads\Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use App\Services\Auth\MenuService;
class AdsDatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
$this->initMenu();
}
public function initMenu(){
$menuService = app(MenuService::class);
$operate = DB::table('auth_permissions')->where('name', 'operate')->first();
if (!$operate) {
$menu = [
['title' => '营销', 'name' => 'operate', 'path' => '/operate', 'component' => '', 'type' => 'menu', 'sort' => 5, 'children' => [
['title' => '广告管理', 'name' => 'operate.ads', 'path' => '/operate/ads', 'component' => 'operate/ads', 'type' => 'menu']
]]
];
$menuService->importMenu($menu, 0);
}else{
$menuService->importMenu([
['title' => '广告管理', 'name' => 'operate.ads', 'path' => '/operate/ads', 'component' => 'operate/ads', 'type' => 'menu']
], $operate->id);
}
}
}

11
modules/Ads/module.json Normal file
View File

@@ -0,0 +1,11 @@
{
"name": "Ads",
"alias": "ads",
"description": "",
"keywords": [],
"priority": 0,
"providers": [
"Modules\\Ads\\Providers\\AdsServiceProvider"
],
"files": []
}

15
modules/Ads/package.json Normal file
View File

@@ -0,0 +1,15 @@
{
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build"
},
"devDependencies": {
"axios": "^1.1.2",
"laravel-vite-plugin": "^0.7.5",
"sass": "^1.69.5",
"postcss": "^8.3.7",
"vite": "^4.0.0"
}
}

View File

View File

@@ -0,0 +1,7 @@
@extends('ads::layouts.master')
@section('content')
<h1>Hello World</h1>
<p>Module: {!! config('ads.name') !!}</p>
@endsection

View File

@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Ads Module - {{ config('app.name', 'Laravel') }}</title>
<meta name="description" content="{{ $description ?? '' }}">
<meta name="keywords" content="{{ $keywords ?? '' }}">
<meta name="author" content="{{ $author ?? '' }}">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
{{-- Vite CSS --}}
{{-- {{ module_vite('build-ads', 'resources/assets/sass/app.scss') }} --}}
</head>
<body>
@yield('content')
{{-- Vite JS --}}
{{-- {{ module_vite('build-ads', 'resources/assets/js/app.js') }} --}}
</body>

View File

View File

@@ -0,0 +1,16 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
use Illuminate\Support\Facades\Route;
Route::controller(Modules\Ads\Controllers\Admin\Ads::class)->prefix('ads')->name('ads.')->group(function () {
Route::get('/index', 'index')->name('index');
Route::post('/add', 'add')->name('add');
Route::put('/edit', 'edit')->name('edit');
Route::delete('/delete', 'delete')->name('delete');
});

View File

@@ -0,0 +1,13 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
use Illuminate\Support\Facades\Route;
Route::controller(Modules\Ads\Controllers\Api\Ads::class)->prefix('ads')->name('ads.')->group(function () {
Route::get('/index', 'index')->name('index');
});

View File

@@ -0,0 +1,9 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
use Illuminate\Support\Facades\Route;

View File

@@ -0,0 +1,26 @@
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
export default defineConfig({
build: {
outDir: '../../public/build-ads',
emptyOutDir: true,
manifest: true,
},
plugins: [
laravel({
publicDirectory: '../../public',
buildDirectory: 'build-ads',
input: [
__dirname + '/resources/assets/sass/app.scss',
__dirname + '/resources/assets/js/app.js'
],
refresh: true,
}),
],
});
//export const paths = [
// 'Modules/Ads/resources/assets/sass/app.scss',
// 'Modules/Ads/resources/assets/js/app.js',
//];

View File

View File

@@ -0,0 +1,39 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Controllers\Admin;
use Illuminate\Http\Request;
use App\Http\Controllers\BaseController;
use Modules\Member\Services\ExtendService;
class Extend extends BaseController {
public function index(Request $request, ExtendService $service){
try {
$this->data['data'] = $service->getDataList($request);
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return $this->data;
}
public function audit(Request $request, ExtendService $service){
try {
$this->data['data'] = $service->audit($request);
$this->data['message'] = '审核完成!';
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return $this->data;
}
}

View File

@@ -0,0 +1,130 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Controllers\Admin;
use Illuminate\Http\Request;
use App\Http\Controllers\BaseController;
use Modules\Member\Services\FieldsService;
class Field extends BaseController {
/**
* @title 获取字段列表
*
* @param Request $request
* @param FieldsService $service
* @return void
*/
public function index(Request $request, FieldsService $service) {
try {
$this->data['data'] = $service->getDataList($request);
$this->data['message'] = '获取成功';
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return $this->data;
}
/**
* @title 添加字段
*
* @param Request $request
* @param FieldsService $service
* @return void
*/
public function add(Request $request, FieldsService $service) {
try {
$this->data['data'] = $service->create($request);
$this->data['message'] = '添加成功';
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return $this->data;
}
/**
* @title 编辑字段
*
* @param Request $request
* @param FieldsService $service
* @return void
*/
public function edit(Request $request, FieldsService $service) {
try {
$this->data['data'] = $service->update($request);
$this->data['message'] = '编辑成功';
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return $this->data;
}
/**
* @title 删除字段
*
* @param Request $request
* @param FieldsService $service
* @return void
*/
public function delete(Request $request, FieldsService $service) {
try {
$this->data['data'] = $service->delete($request);
$this->data['message'] = '删除成功';
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return $this->data;
}
/**
* @title 字段列表
*
* @param Request $request
* @param FieldsService $service
* @return void
*/
public function lists(Request $request, FieldsService $service){
try {
$this->data['data'] = $service->getFieldList($request);
$this->data['message'] = '获取成功';
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return $this->data;
}
/**
* @title 列表字段配置
*
* @param Request $request
* @param FieldsService $service
* @return void
*/
public function setting(Request $request, FieldsService $service){
try {
$this->data['data'] = $service->getFieldSetting($request);
$this->data['message'] = '获取成功';
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return $this->data;
}
}

View File

@@ -0,0 +1,124 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Controllers\Admin;
use Illuminate\Http\Request;
use App\Http\Controllers\BaseController;
use Modules\Member\Services\MemberService;
class Index extends BaseController{
/**
* @title 会员列表
*
* @param Request $request
* @param MemberService $service
* @return void
*/
public function index(Request $request, MemberService $service){
try {
$this->data['data'] = $service->getDataList($request);
} catch (\Exception $e) {
$this->data['code'] = 0;
$this->data['message'] = $e->getMessage();
}
return response()->json($this->data);
}
/**
* @title 添加会员
*
* @param Request $request
* @param MemberService $service
* @return void
*/
public function add(Request $request, MemberService $service){
try {
$this->data['data'] = $service->create($request);
} catch (\Exception $e) {
$this->data['code'] = 0;
$this->data['message'] = $e->getMessage();
}
return response()->json($this->data);
}
/**
* @title 修改会员
*
* @param Request $request
* @param MemberService $service
* @return void
*/
public function edit(Request $request, MemberService $service){
try {
$this->data['data'] = $service->update($request);
} catch (\Exception $e) {
$this->data['code'] = 0;
$this->data['message'] = $e->getMessage();
}
return response()->json($this->data);
}
/**
* @title 删除会员
*
* @param Request $request
* @param MemberService $service
* @return void
*/
public function delete(Request $request, MemberService $service){
try {
$this->data['data'] = $service->delete($request);
} catch (\Exception $e) {
$this->data['code'] = 0;
$this->data['message'] = $e->getMessage();
}
return response()->json($this->data);
}
/**
* @title 导入会员
*
* @param Request $request
* @param MemberService $service
* @return void
*/
public function import(Request $request, MemberService $service){
try {
$this->data['data'] = $service->import($request);
} catch (\Exception $e) {
$this->data['code'] = 0;
$this->data['message'] = $e->getMessage();
}
return response()->json($this->data);
}
/**
* @title 导出会员
*
* @param Request $request
* @param MemberService $service
* @return void
*/
public function export(Request $request, MemberService $service){
try {
$this->data['data'] = $service->export($request);
} catch (\Exception $e) {
$this->data['code'] = 0;
$this->data['message'] = $e->getMessage();
}
return response()->json($this->data);
}
}

View File

@@ -0,0 +1,88 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Controllers\Admin;
use Illuminate\Http\Request;
use App\Http\Controllers\BaseController;
use Modules\Member\Services\LevelService;
class Level extends BaseController{
/**
* @title 会员列表
*
* @param Request $request
* @param LevelService $service
* @return void
*/
public function index(Request $request, LevelService $service){
try {
$this->data['data'] = $service->getDataList($request);
} catch (\Exception $e) {
$this->data['code'] = 0;
$this->data['message'] = $e->getMessage();
}
return response()->json($this->data);
}
/**
* @title 添加会员
*
* @param Request $request
* @param LevelService $service
* @return void
*/
public function add(Request $request, LevelService $service){
try {
$this->data['data'] = $service->create($request);
} catch (\Exception $e) {
$this->data['code'] = 0;
$this->data['message'] = $e->getMessage();
}
return response()->json($this->data);
}
/**
* @title 修改会员
*
* @param Request $request
* @param LevelService $service
* @return void
*/
public function edit(Request $request, LevelService $service){
try {
$this->data['data'] = $service->update($request);
} catch (\Exception $e) {
$this->data['code'] = 0;
$this->data['message'] = $e->getMessage();
}
return response()->json($this->data);
}
/**
* @title 删除会员
*
* @param Request $request
* @param LevelService $service
* @return void
*/
public function delete(Request $request, LevelService $service){
try {
$this->data['data'] = $service->delete($request);
} catch (\Exception $e) {
$this->data['code'] = 0;
$this->data['message'] = $e->getMessage();
}
return response()->json($this->data);
}
}

View File

@@ -0,0 +1,82 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Controllers\Api;
use Illuminate\Http\Request;
use App\Http\Controllers\BaseController;
use Modules\Member\Services\LevelService;
use Modules\Member\Services\FieldsService;
use Modules\Member\Services\ExtendService;
class Extend extends BaseController {
/**
* title 会员扩展列表
*
* @param Request $request
* @param ExtendService $service
* @return void
*/
public function index(Request $request, ExtendService $service){
try {
$request->mergeIfMissing(['status' => 1]);
$this->data['data'] = $service->getDataList($request);
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return response()->json($this->data);
}
public function detail(Request $request, ExtendService $service){
try {
$this->data['data'] = $service->getDetail($request);
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return response()->json($this->data);
}
public function field(Request $request, FieldsService $service){
try {
$request->mergeIfMissing(['status' => 1]);
$this->data['data'] = $service->getDataList($request);
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return response()->json($this->data);
}
public function level(Request $request, LevelService $service){
try {
$this->data['data'] = $service->getDataList($request);
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return response()->json($this->data);
}
public function save(Request $request, ExtendService $service){
try {
$this->data['data'] = $service->update($request);
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return response()->json($this->data);
}
}

View File

@@ -0,0 +1,100 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Controllers\Api;
use Illuminate\Http\Request;
use App\Http\Controllers\BaseController;
use Modules\Member\Services\MemberService;
class Index extends BaseController {
/**
* @title 用户列表
*
* @param Request $request
* @param MemberService $service
* @return void
*/
public function index(Request $request, MemberService $service){
try {
$this->data['data'] = $service->getDataList($request);
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return response()->json($this->data);
}
/**
* @title 手机号绑定
*
* @param MemberService $service
* @return void
*/
public function mobile(MemberService $service){
try {
$this->data['data'] = $service->bindMobile($this->request->param());
} catch (\think\Exception $e) {
$this->data['code'] = 0;
$this->data['message'] = $e->getMessage();
}
return $this->data;
}
/**
* @title 微信绑定
*
* @param MemberService $service
* @return void
*/
public function upwechat(MemberService $service){
try {
$this->data['data'] = $service->updateWechatInfo($this->request->param());
} catch (\think\Exception $e) {
$this->data['code'] = 0;
$this->data['message'] = $e->getMessage();
}
return $this->data;
}
public function edit(Request $request, MemberService $service){
try {
$request->mergeIfMissing(['uid' => auth('api')->user()['uid']]);
$this->data['data'] = $service->update($request);
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return $this->data;
}
public function editpasswd(Request $request, MemberService $service){
try {
$request->mergeIfMissing(['uid' => auth('api')->user()['uid']]);
$this->data['data'] = $service->updatePasswd($request);
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return $this->data;
}
public function card(Request $request, MemberService $service){
try {
$this->data['data'] = $service->getDetail($request);
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return $this->data;
}
}

View File

@@ -0,0 +1,87 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Controllers\Api;
use Illuminate\Http\Request;
use App\Http\Controllers\BaseController;
use Modules\Member\Services\AuthService;
class Login extends BaseController {
/**
* @title 登录
*
* @param Request $request
* @param AuthService $service
* @return void
*/
public function index(Request $request, AuthService $service){
try {
$this->data['data'] = $service->userLogin($request);
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return response()->json($this->data);
}
/**
* @title 退出
*
* @param Request $request
* @param AuthService $service
* @return void
*/
public function logout(Request $request, AuthService $service){
try {
$this->data['data'] = $service->userLogout($request);
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return response()->json($this->data);
}
/**
* @title 注册
*
* @param Request $request
* @param AuthService $service
* @return void
*/
public function register(Request $request, AuthService $service){
try {
$this->data['data'] = $service->userRegister($request);
} catch (\Throwable $th) {
$this->data['code'] = 0;
$this->data['message'] = $th->getMessage();
}
return response()->json($this->data);
}
/**
* @title 获取当前登录用户信息
*
* @return void
*/
public function user(){
$type = request('type', 'wechat');
$user = auth('api')->user();
$user->level = $user->level()->first();
$user->social = $user->social()->where('type', $type)->first();
$user->store = $user->store()->first();
$user->pm = $user->pm()->where('status', 1)->first();
$this->data['data'] = $user;
return response()->json($this->data);
}
}

View File

@@ -0,0 +1,60 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Controllers\Api;
use Illuminate\Http\Request;
use App\Services\Social\Wechat\OauthService;
use Modules\Member\Services\AuthService;
use App\Http\Controllers\BaseController;
class Social extends BaseController{
public function wechat(Request $request, OauthService $service){
if($request->filled('code')){
if($request->filled('url')){
return redirect($request->input('url') . '?code=' . $request->input('code', ''));
}
}else{
$res = $service->oauth($request);
return redirect($res);
}
}
public function login(Request $request, OauthService $service){
$type = $request->input('type', 'wechat');
if($request->filled('code')){
switch ($type) {
case 'wechat':
try {
$wechatInfo = $service->wechatLogin($request->input('code', ''));
$request->merge([
'username' => $wechatInfo['openid'],
'nickname' => $wechatInfo['nickname'],
'password' => uniqid()
]);
$member = app(AuthService::class)->userRegister($request, $wechatInfo, 'wechat');
$token = auth('api')->login($member);
$this->data['data'] = [
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => auth('api')->factory()->getTTL() * 60
];
} catch (\Throwable $th) {
$this->data['message'] = $th->getMessage();
$this->data['code'] = 0;
}
break;
}
}else{
$this->data['message'] = "非法操作!";
$this->data['code'] = 0;
}
return response()->json($this->data);
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace Modules\Member\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class LoginBefore {
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(public $username = '', public $password = ''){
//
}
/**
* Get the channels the event should broadcast on.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array {
return [
new PrivateChannel('channel-name'),
];
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace Modules\Member\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Modules\Member\Models\Member;
class LoginEvent {
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(public Member $member, public $openid = '', public $type = ''){
//
}
/**
* Get the channels the event should broadcast on.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array {
return [
new PrivateChannel('channel-name'),
];
}
}

View File

@@ -0,0 +1,40 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Modules\Member\Models\Member;
class MemberUpdate {
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(public Member $member){
//
}
/**
* Get the channels the event should broadcast on.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array{
return [
new PrivateChannel('channel-name'),
];
}
}

View File

@@ -0,0 +1,40 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Modules\Member\Models\Member;
class Registered {
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(public Member $member, public $openid = '', public $type = ''){
//
}
/**
* Get the channels the event should broadcast on.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array{
return [
new PrivateChannel('channel-name'),
];
}
}

View File

@@ -0,0 +1,77 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Modules\Member\Models\Member;
use Modules\Member\Models\Fields;
use Modules\System\Models\Tasks;
use Illuminate\Support\Facades\Storage;
use Dcat\EasyExcel\Excel;
use Dcat\EasyExcel\Contracts\Sheet as SheetInterface;
use Dcat\EasyExcel\Support\SheetCollection;
class MemberExport implements ShouldQueue {
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $params;
protected $tasks;
/**
* Create a new job instance.
*/
public function __construct($params, Tasks $tasks) {
$this->params = $params;
$this->tasks = $tasks;
}
/**
* Execute the job.
*/
public function handle(): void {
$file = $this->params['fileName'] ? 'export/' . $this->params['fileName'] : 'member_' . date('YmdHis') . '.xlsx';
//扩展字段
$fields = Fields::all();
Excel::export()->chunk(function(int $page) use($fields){
$chunkSize = 1000;
$query = Member::with(['extend', 'level'])->forPage($page, $chunkSize);
logger($query->toSql());
if ($query->count() == 0) {
$this->tasks->status = 1;
$this->tasks->save();
return;
}
$data = $query->get();
$exportData = [];
foreach ($data as $key => $value) {
$item = [
'用户名' => $value->username,
'昵称' => $value->nickname,
'手机号' => $value->mobile,
'邮箱' => $value->email,
];
foreach ($fields as $field) {
$item[$field->title] = $value->extend ? $value->extend->{$field->name} : '';
}
$item['等级'] = $value->level ? $value->level->title : '未设置等级';
$item['等级到期时间'] = $value->level_expire_time;
$item['登录次数'] = $value->login_count;
$item['注册时间'] = $value->created_at;
$exportData[] = $item;
}
return $exportData;
})->disk(Storage::disk('public'))->store($file);
}
}

View File

@@ -0,0 +1,79 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Modules\Member\Models\Member;
use Modules\Member\Models\Fields;
use Modules\Member\Models\MemberExtend;
use Modules\System\Models\Tasks;
use Illuminate\Support\Facades\Storage;
use Dcat\EasyExcel\Excel;
use Dcat\EasyExcel\Contracts\Sheet as SheetInterface;
use Dcat\EasyExcel\Support\SheetCollection;
class MemberImport implements ShouldQueue {
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $file;
protected $tasks;
/**
* Create a new job instance.
*/
public function __construct($file, Tasks $tasks) {
$this->file = Storage::disk('public')->path($file);
$this->tasks = $tasks;
}
/**
* Execute the job.
*/
public function handle(): void {
//扩展字段
$fields = Fields::all();
Excel::import($this->file)->each(function (SheetInterface $sheet) use($fields) {
$chunkSize = 100;
$sheet->chunk($chunkSize, function (SheetCollection $collection) {
$collection->each(function ($row) {
if (empty($row)){
$this->tasks->status = 1;
$this->tasks->save();
return true;
}
$member = Member::updateOrCreate([
'username' => $row['用户名'],
'mobile' => $row['手机号'],
'email' => $row['邮箱']
], [
'nickname' => $row['昵称'],
'password' => $row['手机号'],
]);
if ($member->id) {
if($member->extend()->exists()){
$extend = $member->extend()->first();
}else{
$extend = new MemberExtend();
$extend->member_id = $member->id;
}
foreach ($fields as $field) {
$extend->{$field->name} = $row[$field->title];
}
}
});
});
});
}
}

View File

@@ -0,0 +1,36 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Listeners;
use Modules\Member\Events\LoginBefore;
use Modules\Member\Models\Member;
class UpMemberPaswd {
/**
* @title 会员登录后更新用户信息
*
* @param LoginEvent $event
* @return void
*/
public function handle(LoginBefore $event) {
$username = $event->username;
$password = $event->password;
$member = Member::where('username', '=', $username)->whereNotNull('old_password')->first();
if($member){
if(md5($password . $member->salt) === $member->old_password){
$member->password = $password;
$member->old_password = '';
$member->salt = '';
$member->save();
}
}
}
}

View File

@@ -0,0 +1,27 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Listeners;
use Modules\Member\Events\Registered;
use Modules\Member\Models\Member;
class UpdateMember {
/**
* @title 会员登录后更新用户信息
*
* @param LoginEvent $event
* @return void
*/
public function handle(Registered $event) {
$member = $event->member;
$openid = $event->openid;
$type = $event->type;
}
}

View File

@@ -0,0 +1,21 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Models;
use App\Models\BaseModel;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Modules\Member\Observers\FieldObserver;
#[ObservedBy([FieldObserver::class])]
class Fields extends BaseModel {
protected $table = 'member_extends_fields';
protected $fillable = [];
// protected $hidden = ['deleted_at'];
}

View File

@@ -0,0 +1,97 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Models;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Notifications\Notifiable;
use Illuminate\Notifications\Notification;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Support\Facades\Hash;
class Member extends Authenticatable implements JWTSubject {
use Notifiable;
protected $table = 'member';
protected $primaryKey = 'uid';
protected $fillable = ['username', 'nickname', 'email', 'mobile', 'password', 'status'];
protected $hidden = ['password', 'deleted_at'];
protected $dateFormat = 'Y-m-d H:i:s';
protected $with = ['invite:uid,nickname,username,level_id', 'extend', 'level', 'store', 'social', 'pm'];
/**
* 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 [];
}
protected function casts(): array {
return [
'created_at' => 'datetime:Y-m-d H:i:s',
'updated_at' => 'datetime:Y-m-d H:i:s',
'deleted_at' => 'datetime:Y-m-d H:i:s',
];
}
public function password() : Attribute {
return new Attribute(
set: fn ($value) => Hash::make($value),
);
}
public function avatar(): Attribute {
return new Attribute(
get: fn ($value) => $value ?? request()->root() . '/storage/avatar/default_avatar.jpg',
);
}
public function routeNotificationForMail(Notification $notification): array|string{
return [$this->email => $this->nickname];
}
public function invite(){
return $this->hasOne(Member::class, 'uid', 'invite_uid');
}
public function extend(){
return $this->hasOne(MemberExtends::class, 'member_id', 'uid');
}
public function social(){
return $this->hasMany(\Modules\Wechat\Models\MemberSocial::class, 'member_id', 'uid');
}
public function level(){
return $this->hasOne(MemberLevel::class, 'id', 'level_id');
}
public function address(){
return $this->hasMany(MemberAddress::class, 'member_id', 'id');
}
public function pm(){
return $this->hasOne(Pm::class, 'member_id', 'pm_uid');
}
public function store(){
return $this->hasOne(Store::class, 'member_id', 'store_uid');
}
}

View File

@@ -0,0 +1,18 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Models;
use App\Models\BaseModel;
class MemberAccount extends BaseModel {
protected $table = 'member_account';
protected $fillable = [];
// protected $hidden = ['deleted_at'];
}

View File

@@ -0,0 +1,18 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Models;
use App\Models\BaseModel;
class MemberAddress extends BaseModel {
protected $table = 'member_address';
protected $fillable = [];
// protected $hidden = ['deleted_at'];
}

View File

@@ -0,0 +1,18 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Models;
use App\Models\BaseModel;
class MemberBank extends BaseModel {
protected $table = 'member_bank';
protected $fillable = [];
// protected $hidden = ['deleted_at'];
}

View File

@@ -0,0 +1,18 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Models;
use App\Models\BaseModel;
class MemberCoupon extends BaseModel {
protected $table = 'member_coupon';
protected $fillable = [];
// protected $hidden = ['deleted_at'];
}

View File

@@ -0,0 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Models;
use App\Models\BaseModel;
class MemberExtends extends BaseModel {
protected $table = 'member_extends';
protected $fillable = [];
// protected $hidden = ['deleted_at'];
public function member(){
return $this->belongsTo(Member::class, 'member_id', 'uid');
}
}

View File

@@ -0,0 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Models;
use App\Models\BaseModel;
class MemberLevel extends BaseModel {
protected $table = 'member_level';
protected $fillable = ['title', 'name', 'icon', 'sort', 'status', 'remark', 'created_at', 'updated_at'];
// protected $hidden = ['deleted_at'];
public function members(){
return $this->belongsToMany(Member::class, 'member_has_level', 'level_id', 'member_id');
}
}

View File

@@ -0,0 +1,18 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Models;
use App\Models\BaseModel;
class MemberScore extends BaseModel {
protected $table = 'member_score';
protected $fillable = [];
// protected $hidden = ['deleted_at'];
}

View File

@@ -0,0 +1,18 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Models;
use App\Models\BaseModel;
class MemberStore extends BaseModel {
protected $table = 'member_store';
protected $fillable = [];
// protected $hidden = ['deleted_at'];
}

View File

@@ -0,0 +1,18 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Models;
use App\Models\BaseModel;
class MemberWallet extends BaseModel {
protected $table = 'member_wallet';
protected $fillable = [];
// protected $hidden = ['deleted_at'];
}

View File

@@ -0,0 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Models;
use App\Models\BaseModel;
class Pm extends BaseModel {
protected $table = 'member_pm';
protected $fillable = [];
// protected $hidden = ['deleted_at'];
public function members(){
return $this->belongsTo(Member::class, 'member_id', 'uid');
}
}

View File

@@ -0,0 +1,22 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Models;
use App\Models\BaseModel;
class Store extends BaseModel {
protected $table = 'member_store';
protected $fillable = [];
// protected $hidden = ['deleted_at'];
public function members(){
return $this->belongsTo(Member::class, 'member_id', 'uid');
}
}

View File

@@ -0,0 +1,57 @@
<?php
namespace Modules\Member\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class Member extends Notification
{
use Queueable;
/**
* Create a new notification instance.
*/
public function __construct()
{
//
}
/**
* Get the notification's delivery channels.
*/
public function via($notifiable): array
{
$via = [];
if ($notifiable->email) {
$via[] = 'mail';
}
if ($notifiable->mobile) {
$via[] = 'sms';
}
return $via;
}
/**
* Get the mail representation of the notification.
*/
public function toMail($notifiable): MailMessage
{
return (new MailMessage)
->subject('通知主题')
->greeting('你好!')
->line('The introduction to the notification.')
->action('Notification Action', 'https://laravel.com')
->line('Thank you for using our application!');
}
/**
* Get the array representation of the notification.
*/
public function toArray($notifiable): array
{
return [];
}
}

View File

@@ -0,0 +1,107 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Observers;
use Modules\Member\Models\Fields;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class FieldObserver {
public $type = [
'string' => 'string',
'audio' => 'string',
'video' => 'string',
'editor' => 'longText',
'text' => 'text',
'image' => 'string',
'images' => 'text',
'file' => 'string',
'files' => 'text',
'number' => 'integer',
'bool' => 'boolean',
'date' => 'date',
'datetime' => 'dateTime',
'select' => 'string',
'radio' => 'string',
'checkbox' => 'text'
];
/**
* 处理 "created" 事件。
*/
public function created(Fields $fields): void {
$table = 'member_extends';
if(Schema::hasTable($table)){
Schema::table($table, function (Blueprint $table) use ($fields) {
$type = $this->type[$fields->type] ? $this->type[$fields->type] : 'string';
if($fields->length){
$field = $table->{$type}($fields->name, length: $fields->length);
}else{
$field = $table->{$type}($fields->name);
}
if($fields->default_value){
$field = $field->default($fields->default_value);
}
if($fields->type == 'required'){
$field = $field->nullable();
}
$field = $field->comment($fields->title)->after($fields->after);
});
}
}
/**
* 处理 "updated" 事件。
*/
public function updated(Fields $fields): void {
$table = 'member_extends';
if (!Schema::hasTable($table) && !Schema::hasColumn($table, $fields->name)) {
return;
}
if($fields->isDirty('name') && Schema::hasColumn($table, $fields->getOriginal('name'))){
Schema::table($table, function (Blueprint $table) use ($fields) {
$table->renameColumn($fields->getOriginal('name'), $fields->name);
});
}
if($fields->isDirty()){
Schema::table($table, function (Blueprint $table) use ($fields) {
$type = $this->type[$fields->type] ? $this->type[$fields->type] : 'string';
if($fields->length){
$field = $table->{$type}($fields->name, length: $fields->length);
}else{
$field = $table->{$type}($fields->name);
}
if($fields->default_value){
$field = $table->default($fields->default_value);
}else{
if($fields->type == 'required'){
$field = $field->nullable(false);
}else{
$field = $field->nullable();
}
}
$field->after($fields->after)->comment($fields->title)->change();
});
}
}
public function deleted(Fields $fields): void {
if($fields->status == 1){
$table = 'member_extends';
if (Schema::hasTable($table) && Schema::hasColumn($table, $fields->name)) {
Schema::table($table, function (Blueprint $table) use ($fields) {
$table->dropColumn($fields->name);
});
}
}
}
}

View File

View File

@@ -0,0 +1,42 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Providers;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event handler mappings for the application.
*
* @var array<string, array<int, string>>
*/
protected $listen = [
\Modules\Member\Events\LoginBefore::class => [
\Modules\Member\Listeners\UpMemberPaswd::class,
],
];
/**
* Indicates if events should be discovered.
*
* @var bool
*/
protected static $shouldDiscoverEvents = true;
/**
* Configure the proper event listeners for email verification.
*
* @return void
*/
protected function configureEmailVerification(): void
{
}
}

View File

@@ -0,0 +1,120 @@
<?php
namespace Modules\Member\Providers;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
class MemberServiceProvider extends ServiceProvider
{
protected string $moduleName = 'Member';
protected string $moduleNameLower = 'member';
/**
* Boot the application events.
*/
public function boot(): void
{
$this->registerCommands();
$this->registerCommandSchedules();
$this->registerTranslations();
$this->registerConfig();
$this->registerViews();
$this->loadMigrationsFrom(module_path($this->moduleName, 'database/migrations'));
}
/**
* Register the service provider.
*/
public function register(): void
{
$this->app->register(EventServiceProvider::class);
$this->app->register(RouteServiceProvider::class);
}
/**
* Register commands in the format of Command::class
*/
protected function registerCommands(): void
{
// $this->commands([]);
}
/**
* Register command Schedules.
*/
protected function registerCommandSchedules(): void
{
// $this->app->booted(function () {
// $schedule = $this->app->make(Schedule::class);
// $schedule->command('inspire')->hourly();
// });
}
/**
* Register translations.
*/
public function registerTranslations(): void
{
$langPath = resource_path('lang/modules/'.$this->moduleNameLower);
if (is_dir($langPath)) {
$this->loadTranslationsFrom($langPath, $this->moduleNameLower);
$this->loadJsonTranslationsFrom($langPath);
} else {
$this->loadTranslationsFrom(module_path($this->moduleName, 'lang'), $this->moduleNameLower);
$this->loadJsonTranslationsFrom(module_path($this->moduleName, 'lang'));
}
}
/**
* Register config.
*/
protected function registerConfig(): void
{
$this->publishes([module_path($this->moduleName, 'config/config.php') => config_path($this->moduleNameLower.'.php')], 'config');
$this->mergeConfigFrom(module_path($this->moduleName, 'config/config.php'), $this->moduleNameLower);
}
/**
* Register views.
*/
public function registerViews(): void
{
$viewPath = resource_path('views/modules/'.$this->moduleNameLower);
$sourcePath = module_path($this->moduleName, 'resources/views');
$this->publishes([$sourcePath => $viewPath], ['views', $this->moduleNameLower.'-module-views']);
$this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), $this->moduleNameLower);
$componentNamespace = str_replace('/', '\\', config('modules.namespace').'\\'.$this->moduleName.'\\'.ltrim(config('modules.paths.generator.component-class.path'), config('modules.paths.app_folder', '')));
Blade::componentNamespace($componentNamespace, $this->moduleNameLower);
}
/**
* Get the services provided by the provider.
*
* @return array<string>
*/
public function provides(): array
{
return [];
}
/**
* @return array<string>
*/
private function getPublishableViewPaths(): array
{
$paths = [];
foreach (config('view.paths') as $path) {
if (is_dir($path.'/modules/'.$this->moduleNameLower)) {
$paths[] = $path.'/modules/'.$this->moduleNameLower;
}
}
return $paths;
}
}

View File

@@ -0,0 +1,67 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Providers;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class RouteServiceProvider extends ServiceProvider
{
/**
* Called before routes are registered.
*
* Register any model bindings or pattern based filters.
*/
public function boot(): void
{
parent::boot();
}
/**
* Define the routes for the application.
*/
public function map(): void
{
$this->mapApiRoutes();
$this->mapWebRoutes();
$this->mapAdminRoutes();
}
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*/
protected function mapWebRoutes(): void
{
Route::middleware('web')->group(module_path('Member', '/routes/web.php'));
}
/**
* Define the "api" routes for the application.
*
* These routes are typically stateless.
*/
protected function mapApiRoutes(): void
{
Route::middleware('api')->prefix('api')->name('api.')->group(module_path('Member', '/routes/api.php'));
}
/**
* Define the "api" routes for the application.
*
* These routes are typically stateless.
*/
protected function mapAdminRoutes(): void
{
Route::middleware('api')->prefix('admin')->name('admin.')->group(module_path('Member', '/routes/admin.php'));
}
}

View File

@@ -0,0 +1,134 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Services;
use Modules\Member\Models\Member;
use Modules\Member\Events\LoginBefore;
use Modules\Member\Events\LoginEvent;
use Modules\Member\Events\Registered;
class AuthService {
/**
* @title 会员登录
*
* @param [type] $request
* @return void
*/
public function userLogin($request){
$request->validate([
'username' => 'required',
'password' => 'required',
]);
$username = $request->input('username');
$password = $request->input('password');
LoginBefore::dispatch($username, $password);
$token = auth('api')->attempt(['mobile' => $username, 'password' => $password]);
if (!$token) {
throw new \Exception("登錄失敗!", 1000);
}else{
LoginEvent::dispatch(auth('api')->user(), $request->input('openid', ''), $request->input('type'));
// 判断是否到期
$user = auth('api')->user();
if(isset($user['level_expire_time']) && $user['level_expire_time'] != ''){
$level_expire_time = strtotime($user['level_expire_time']);
if($level_expire_time < time()){
throw new \Exception("您的會員已到期,請聯系管理員!", 1004);
}
}
return [
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => auth('api')->factory()->getTTL() * 60
];
}
}
/**
* @title UID登录
* @description 提供给第三方登录接口
*
* @param [type] $uid
* @param array $params 第三方登录参数
* @param string $type 第三方登录类型
* @return void
*/
public function userLoginByUid($uid, $params = [], $type = 'wechat'){
$member = Member::find($uid);
if(!$member){
throw new \Exception("用户不存在!", 1000);
}
$token = auth('api')->login($member);
if (!$token) {
throw new \Exception("登录失败!", 1000);
}else{
LoginEvent::dispatch(auth('api')->user(), $params, $type);
return [
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => auth('api')->factory()->getTTL() * 60
];
}
}
/**
* @title 会员注册
*
* @param [type] $request
* @return void
*/
public function userRegister($request){
$request->validate([
'username' => 'required|unique:member,username',
'password' => 'required',
'mobile' => 'nullable|unique:member,mobile',
], [
'username.unique' => '用户名已存在!',
'mobile.unique' => '手机号已存在!',
'username.required' => '用户名不能为空!',
'password.required' => '密码不能为空!'
]);
$member = Member::where('username', '=', $request->input('username'))->first();
if(!$member){
$data = [
'username' => $request->input('username'),
'password' => $request->input('password'),
'nickname' => $request->input('nickname', ''),
'avatar' => $request->input('avatar', ''),
'mobile' => $request->input('mobile', 0),
];
$member = Member::updateOrCreate($data);
}
Registered::dispatch($member, $request->input('openid', ''), $request->input('type', ''));
$token = auth('api')->login($member);
return [
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => auth('api')->factory()->getTTL() * 60
];
}
/**
* @title 会员退出
*
* @param [type] $request
* @return void
*/
public function userLogout($request){
auth('api')->logout();
}
}

View File

@@ -0,0 +1,146 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Services;
use Modules\Member\Models\Fields;
use Modules\Member\Models\MemberExtends;
class ExtendService {
public function getDataList($request){
$map = [];
$query = MemberExtends::with('member:uid,username,nickname,avatar,level_id,level_expire_time');
if ($request->filled('member_id')){
$query->where('member_id', $request->input('member_id'));
}
if ($request->filled('keyword')){
$map[] = ['name', 'like', '%' . $request->input('keyword') . '%'];
}
if ($request->filled('name')){
$map[] = ['name', 'like', '%' . $request->input('name') . '%'];
}
if ($request->filled('status')){
$map[] = ['status', '=', $request->input('status')];
}
$query->where($map);
$query->orderBy($request->input('order', 'id'), $request->input('sort', 'desc'));
if ($request->filled('page')){
$data = [
'total' => $query->count(),
'page' => (int) $request->input('page', 1),
'data' => $query->offset($request->input('offset', 0))->limit($request->input('limit', 30))->get(),
];
}else{
$data = $query->limit($request->input('limit', 10))->get();
}
return $data;
}
public function getDetail($request){
if ($request->filled('member_id')){
$member_id = $request->input('member_id');
} else {
$member_id = auth('api')->user()['uid'];
}
$extends = MemberExtends::with('member:uid,username,nickname,avatar,level_id,level_expire_time', 'member.level')->where('member_id', $member_id)->first();
if (!$extends){
throw new \Exception('用户数据不存在');
}
if ($extends->status == 0){
throw new \Exception('用户数据审核中');
}
if ($extends->status == 2){
throw new \Exception('用户数据审核未通过');
}
return $extends ?? [];
}
public function update($request){
$field = Fields::all();
if ($request->filled('member_id')){
$member_id = $request->input('member_id');
} else {
$member_id = auth('api')->user()['uid'];
}
$extends = MemberExtends::where('member_id', $member_id)->first();
if (!$extends){
$extends = new MemberExtends();
$extends->member_id = $member_id;
}
foreach ($field as $key => $value) {
if ($request->filled($value['name']) && $request->input($value['name']) != ''){
$extends->{$value['name']} = $request->input($value['name']);
}
}
$extends->status = 0;
$extends->save();
return $extends;
}
public function audit($request){
$request->validate([
'id' => 'required',
'member_id' => 'required',
'level_id' => 'required',
'status' => 'required|integer|in:0,1,2',
'level_expire_time' => 'required|date',
], [
'id.required' => 'ID不能为空',
'member_id.required' => '用户ID不能为空',
'level_id.required' => '等级ID不能为空',
'status.required' => '审核状态不能为空',
'status.integer' => '审核状态必须为数字',
'status.in' => '审核状态值错误',
'level_expire_time.required' => '等级过期时间不能为空',
'level_expire_time.date' => '等级过期时间格式错误',
]);
$extends = MemberExtends::where('id', $request->input('id'))->first();
if (!$extends){
throw new \Exception('审核数据不存在');
}
$extends->status = $request->input('status');
$extends->card_number = 'NF9' . str_pad($extends->member_id, 6, '0', STR_PAD_LEFT);
$extends->save();
if ($request->input('status') == 1){
$member = $extends->member()->first();
$member->level_id = $request->input('level_id');
$member->level_expire_time = $request->input('level_expire_time');
if ($extends->name){
$member->nickname = $extends->name;
}
if ($extends->mobile){
$member->mobile = $extends->mobile;
}
if ($extends->email){
$member->email = $extends->email;
}
$member->save();
}
return $extends;
}
}

View File

@@ -0,0 +1,140 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Services;
use Modules\Member\Models\Fields;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Str;
class FieldsService {
/**
* @title 字段列表
*
* @param [type] $request
* @return void
*/
public function getDataList($request) {
$map = [];
if ($request->filled('status')) {
$map[] = ['status', '=', $request->input('status')];
}
$query = Fields::where($map);
if($request->filled('page')){
$data = [
'total' => $query->count(),
'page' => $request->input('page', 1),
'data' => $query->offset($request->input('offset', 0))->limit($request->input('limit', 10))->get(),
];
}else{
$data = $query->limit($request->input('limit', 10))->get();
}
return $data;
}
/**
* @title 创建字段
*
* @param [type] $request
* @return void
*/
public function create($request) {
$request->validate([
'name' => 'required|unique:cms_model_field',
'title' => 'required',
'type' => 'required',
]);
$field = new Fields();
foreach ($field->setFilterFields($request->all()) as $key => $value) {
$field->$key = $value;
}
$field->save();
return $field;
}
/**
* @title 更新字段
*
* @param [type] $request
* @return void
*/
public function update($request) {
$request->validate([
'name' => 'required|unique:cms_model_field,name,' . $request->input('id'),
'title' => 'required',
'type' => 'required',
]);
$field = Fields::find($request->input('id'));
foreach ($field->setFilterFields($request->all()) as $key => $value){
$field->$key = $value;
}
$field->save();
return $field;
}
/**
* @title 删除字段
*
* @param [type] $request
* @return void
*/
public function delete($request) {
if($request->filled('id')){
try {
$field = Fields::findOrFail($request->input('id'));
} catch (\Throwable $th) {
throw new \Exception("模型不存在!", 1);
}
$field->delete();
}
if($request->filled('ids')){
try {
$field = Fields::whereIn('id', $request->input('ids'));
$field->delete();
} catch (\Throwable $th) {
throw new \Exception($th->getMessage(), 1);
}
}
return $field;
}
public function getFieldList($request){
$fields = Schema::getColumnListing('member_extends');
$data = [];
foreach ($fields as $value) {
if ($value !== $request->input('name'))
$data[] = ['title' => $value, 'values' => $value];
}
return $data;
}
public function getFieldSetting($request){
$map = [];
$query = Fields::with('model:id,title,name,icon');
if ($request->filled('model')) {
$query->whereHas('model', function($q) use($request) {
$q->where('name', $request->input('model'));
});
}
$data = $query->get();
return $data;
}
}

View File

@@ -0,0 +1,124 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Services;
use Modules\Member\Models\MemberLevel;
class LevelService {
/**
* @title 获取会员列表
*
* @param [type] $request
* @return void
*/
public function getDataList($request){
$map = [];
if ($request->filled('title')) {
$map[] = ['title', 'like', '%' . $request->input('title') . '%'];
}
if ($request->filled('name')) {
$map[] = ['name', 'like', '%' . $request->input('name') . '%'];
}
$query = MemberLevel::where($map)->orderBy('id', 'desc');
if ($request->filled('page')) {
$data = [
'total' => $query->count(),
'page' => $request->input('page', 1),
'data' => $query->offset($request->input('offset', 0))->limit($request->input('limit', 30))->get(),
];
}else{
$data = $query->limit($request->input('limit', 30))->get();
}
return $data;
}
/**
* @title 添加会员
*
* @param Request $request
* @param MemberService $service
* @return void
*/
public function create($request){
$request->validate([
'title' => 'required|max:255',
'name' => 'required|max:255|alpha_dash:ascii|unique:member_level,name',
]);
$data = [
'title' => $request->input('title', ''),
'name' => $request->input('name', ''),
'icon' => $request->input('icon', ''),
'sort' => $request->input('sort', 0),
'status' => $request->input('status', 1),
'remark' => $request->input('remark', ''),
];
$level = MemberLevel::create($data);
}
/**
* @title 修改会员
*
* @param Request $request
* @param MemberService $service
* @return void
*/
public function update($request){
$request->validate([
'title' => 'required|max:255',
'name' => 'required|max:255|alpha_dash:ascii|unique:member_level,name,' . $request->input('id'),
]);
try {
$level = MemberLevel::findOrFail($request->input('id'));
} catch (\Throwable $th) {
throw new \Exception("会员不存在!", 1);
}
$data = [
'title'=> $request->input('title', ''),
'name' => $request->input('name', ''),
'icon' => $request->input('icon', ''),
'sort' => $request->input('sort', 0),
'status' => $request->input('status', 1),
'remark' => $request->input('remark', ''),
];
$level->update($data);
return $level;
}
public function delete($request){
if($request->filled('id')){
try {
$level = MemberLevel::findOrFail($request->input('id'));
} catch (\Throwable $th) {
throw new \Exception("会员等级不存在!", 1);
}
$level->members()->detach();
$level->delete();
}
if($request->filled('ids')){
try {
$level = MemberLevel::whereIn('id', $request->input('ids'));
foreach ($level->get() as $item) {
$item->members()->detach(); //删除关联
}
$level->delete();
} catch (\Throwable $th) {
throw new \Exception($th->getMessage(), 1);
}
}
return $level;
}
}

View File

@@ -0,0 +1,299 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Services;
use Modules\Member\Models\Member;
use Modules\Member\Events\MemberUpdate;
class MemberService {
/**
* @title 获取会员列表
*
* @param [type] $request
* @return void
*/
public function getDataList($request){
$map = [];
if ($request->filled('username')) {
$map[] = ['username', 'like', '%' . $request->input('username') . '%'];
}
if ($request->filled('mobile')) {
$map[] = ['mobile', 'like', '%' . $request->input('mobile') . '%'];
}
if ($request->filled('email')) {
$map[] = ['email', 'like', '%' . $request->input('email') . '%'];
}
$query = Member::with(['social', 'level'])->where($map)->orderBy('uid', 'desc');
if ($request->filled('title')) {
$query->whereAny(['nickname', 'username'], 'like', '%' . $request->input('title') . '%');
}
$data = [
'total' => $query->count(),
'page' => $request->input('page', 1),
'data' => $query->offset($request->input('offset', 0))->limit($request->input('limit', 10))->get(),
];
return $data;
}
public function getDetail($request){
$request->validate([
'id_card' => 'required',
], [
'id_card.required' => '身份证号不能为空!',
]);
$query = Member::with(['level', 'extend']);
if ($request->filled('id_card')) {
$query->whereHas('extend', function ($query) use ($request) {
$query->where('id_card', $request->input('id_card'));
});
}
if ($request->is('api/*')) {
$query->select(['nickname', 'uid', 'level_id']);
}
if ($query->exists()) {
return $query->first();
} else {
throw new \Exception("会员不存在!", 1);
}
}
/**
* @title 创建用户
*
* @param [type] $request
* @return void
*/
public function create($request){
$request->validate([
'username' => 'required|unique:member',
'nickname' => 'required',
'mobile' => 'required|unique:member',
'password' => 'required|min:6|max:16'
], [
'username.required' => '用户名不能为空!',
'username.unique' => '用户名已存在!',
'nickname.required' => '昵称不能为空!',
'mobile.required' => '手机号不能为空!',
'mobile.unique' => '手机号已存在!',
'password.required' => '密码不能为空!',
'password.min' => '密码长度不能小于6位',
'password.max' => '密码长度不能大于16位'
]);
$member = new Member;
if ($request->filled('username')) {
$member->username = $request->input('username');
}
if ($request->filled('nickname')) {
$member->nickname = $request->input('nickname');
}
if ($request->filled('avatar')) {
$member->avatar = $request->input('avatar');
}
if ($request->filled('email')) {
$member->email = $request->input('email');
}
if ($request->filled('gender')) {
$member->gender = $request->input('gender');
}
if ($request->filled('birthday')) {
$member->birthday = $request->input('birthday');
}
if ($request->filled('date_type')) {
$member->date_type = $request->input('date_type');
}
if ($request->filled('mobile')) {
$member->mobile = $request->input('mobile');
}
if ($request->filled('level_expire_time')) {
$member->level_expire_time = $request->input('level_expire_time');
}
if ($request->filled('password')) {
$member->password = $request->input('password');
}
if ($request->filled('status')) {
$member->status = $request->input('status');
}
$member->invite_uid = $request->input('invite_uid', '1890000001');
$member->pm_uid = $request->input('pm_uid', '1890000001');
$member->store_uid = $request->input('store_uid', '1890000001');
$member->level_id = $request->input('level_id', '1');
$member->save();
return $member;
}
/**
* @title 更新用户
*
* @param [type] $request
* @return void
*/
public function update($request){
$request->validate([
'username' => 'unique:member,username,'.$request->input('uid').',uid',
'mobile' => 'unique:member,mobile,'.$request->input('uid').',uid',
],[
'username.unique' => '用户名已存在!',
'mobile.unique' => '手机号已存在!',
]);
if ($request->filled('uid')) {
$members = Member::where('uid', $request->input('uid'))->first();
}
if ($request->is('api/*') && auth('api')->user()) {
$members = Member::where('uid', auth('api')->user()['uid'])->first();
}
if ($request->filled('username')) {
$members->username = $request->input('username');
}
if ($request->filled('nickname')) {
$members->nickname = $request->input('nickname');
}
if ($request->filled('avatar')) {
$members->avatar = $request->input('avatar');
}
if ($request->filled('email')) {
$members->email = $request->input('email');
}
if ($request->filled('gender')) {
$members->gender = $request->input('gender');
}
if ($request->filled('birthday')) {
$members->birthday = $request->input('birthday');
}
if ($request->filled('date_type')) {
$members->date_type = $request->input('date_type');
}
if ($request->filled('mobile')) {
$members->mobile = $request->input('mobile');
}
if ($request->filled('password')) {
$members->password = $request->input('password');
}
if ($request->filled('level_expire_time')) {
$members->level_expire_time = $request->input('level_expire_time');
}
$members->save();
MemberUpdate::dispatch($members);
return $members;
}
public function delete($request){
if(!$request->filled('uid')){
throw new \Exception("非法操作!", 1);
}
if (is_array($request->input('uid'))) {
// 批量删除
$mebers = Member::whereIn('uid', $request->input('uid'))->get();
if ($mebers->isEmpty()) {
throw new \Exception("会员不存在!", 1);
}
$member = Member::destroy(request()->input('uid'));
return $member;
}else{
// 单个删除
try {
$mebers = Member::findOrFail($request->input('uid'));
} catch (\Throwable $th) {
throw new \Exception("会员不存在!", 1);
}
$mebers->delete();
return $mebers;
}
}
public function updatePasswd($request){
$request->validate([
'password' => 'required|min:6|max:16'
], [
'password.required' => '密码不能为空!',
'password.min' => '密码长度不能小于6位',
'password.max' => '密码长度不能大于16位'
]);
if ($request->is('api/*')) {
$request->validate([
'old_password' => 'required',
'password' => 'confirmed'
], [
'old_password.required' => '旧密码不能为空!',
'password.confirmed' => '两次密码不一致!'
]);
}
if(!$request->filled('uid')){
throw new \Exception("非法操作!", 1);
}
try {
$mebers = Member::findOrFail($request->input('uid'));
} catch (\Throwable $th) {
throw new \Exception("会员不存在!", 1);
}
if(!$request->filled('password')){
throw new \Exception("密码不能为空!", 1);
}
$mebers->password = $request->input('password');
$mebers->save();
return $mebers;
}
public function import($request){
$file = $request->file('file');
if ($file->isValid()) {
$ext = $file->extension();
if (in_array($ext, ['csv', 'xlsx']) === false) {
throw new \Exception("请上传csv文件");
}
$path = $file->store('import/'.date('Ymd'), 'public');
$tasks = app()->tasks->create([
'title' => '会员数据导入',
'type' => 'import',
'file' => $path,
'params' => $request->except('file'),
'status' => 0,
]);
if ($tasks->id) {
\Modules\Member\Jobs\MemberImport::dispatch($path, $tasks);
}
}
}
public function export($request){
$tasks = app()->tasks->create([
'title' => '会员数据导出',
'type' => 'export',
'file' => 'export/' . $request->input('fileName', time().'xlsx'),
'status' => 0,
]);
if ($tasks->id) {
\Modules\Member\Jobs\MemberExport::dispatch($request->all(), $tasks);
}
}
}

View File

@@ -0,0 +1,30 @@
{
"name": "tensent/member",
"description": "",
"authors": [
{
"name": "molong",
"email": "molong@tensent.cn"
}
],
"extra": {
"laravel": {
"providers": [],
"aliases": {
}
}
},
"autoload": {
"psr-4": {
"Modules\\Member\\": "app/",
"Modules\\Member\\Database\\Factories\\": "database/factories/",
"Modules\\Member\\Database\\Seeders\\": "database/seeders/"
}
},
"autoload-dev": {
"psr-4": {
"Modules\\Member\\Tests\\": "tests/"
}
}
}

View File

View File

@@ -0,0 +1,5 @@
<?php
return [
'name' => 'Member',
];

View File

@@ -0,0 +1,72 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void {
Schema::create('member', function (Blueprint $table) {
$table->id('uid')->unique()->comment('用户ID');
$table->string('username')->comment('用户名');
$table->string('password')->comment('密码');
$table->string('nickname')->comment('昵称');
$table->string('mobile')->nullable()->comment('手机号');
$table->string('email')->nullable()->comment('邮箱');
$table->string('avatar')->nullable()->comment('头像');
$table->tinyInteger('gender')->default(0)->comment('性别');
$table->date('birthday')->nullable()->comment('生日');
$table->unsignedBigInteger('invite_uid')->default(0)->comment('邀请人UID');
$table->unsignedBigInteger('level_id')->default(0)->comment('会员等级ID');
$table->string('last_login_ip')->nullable()->comment('最后登录IP');
$table->timestamp('last_login_time')->nullable()->comment('最后登录时间');
$table->integer('login_count')->default(0)->comment('登录次数');
$table->tinyInteger('status')->default(1)->comment('状态 1正常 2禁用');
$table->timestamp('created_at')->nullable()->comment('创建时间');
$table->timestamp('updated_at')->nullable()->comment('更新时间');
$table->engine = 'InnoDB';
$table->charset = 'utf8mb4';
$table->collation = 'utf8mb4_unicode_ci';
$table->comment('会员表');
});
Schema::create('member_level', function (Blueprint $table) {
$table->id()->uniqid()->comment('主键id');
$table->string('title')->comment('会员等级名称');
$table->string('name')->comment('会员等级标识');
$table->string('icon')->nullable()->comment('会员等级图标');
$table->string('remark')->nullable()->comment('会员等级备注');
$table->string('sort')->default(0)->comment('排序');
$table->tinyInteger('status')->default(1)->comment('状态');
$table->timestamp('created_at')->nullable()->comment('创建时间');
$table->timestamp('updated_at')->nullable()->comment('更新时间');
$table->engine = 'InnoDB';
$table->charset = 'utf8mb4';
$table->collation = 'utf8mb4_unicode_ci';
$table->comment('会员等级表');
});
Schema::create('member_has_level', function (Blueprint $table) {
$table->unsignedBigInteger('level_id')->comment('等级id');
$table->unsignedBigInteger('member_id')->comment('用户id');
$table->primary(['level_id', 'member_id']);
$table->engine = 'InnoDB';
$table->charset = 'utf8mb4';
$table->collation = 'utf8mb4_unicode_ci';
$table->comment('会员等级关联表');
});
}
/**
* Reverse the migrations.
*/
public function down(): void {
Schema::dropIfExists('member');
Schema::dropIfExists('member_level');
Schema::dropIfExists('member_has_level');
}
};

View File

@@ -0,0 +1,71 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void {
Schema::create('member_extends', function (Blueprint $table) {
$table->id()->uniqid()->comment('主键id');
$table->unsignedBigInteger('member_id')->comment('用户id');
$table->tinyInteger('status')->default(1)->comment('状态');
$table->timestamp('created_at')->nullable()->comment('创建时间');
$table->timestamp('updated_at')->nullable()->comment('更新时间');
$table->engine = 'InnoDB';
$table->charset = 'utf8mb4';
$table->collation = 'utf8mb4_unicode_ci';
$table->comment('会员扩展表');
});
Schema::create('member_extends_fields', function (Blueprint $table) {
$table->id()->uniqid()->comment('主键id');
$table->string('title')->comment('字段名称');
$table->string('name')->comment('字段标识');
$table->string('type')->comment('字段类型');
$table->string('length')->nullable()->comment('字段长度');
$table->string('default_value')->nullable()->comment('默认值');
$table->string('after')->nullable()->comment('在字段后');
$table->string('remark')->nullable()->comment('字段备注');
$table->tinyInteger('required')->default(0)->comment('是否必填');
$table->string('sort')->default(0)->comment('排序');
$table->tinyInteger('status')->default(1)->comment('状态 1正常 2禁用');
$table->timestamp('created_at')->nullable()->comment('创建时间');
$table->timestamp('updated_at')->nullable()->comment('更新时间');
$table->engine = 'InnoDB';
$table->charset = 'utf8mb4';
$table->collation = 'utf8mb4_unicode_ci';
$table->comment('会员扩展字段表');
});
Schema::create('member_extends_log', function (Blueprint $table) {
$table->id()->uniqid()->comment('主键id');
$table->unsignedBigInteger('member_id')->comment('用户id');
$table->string('field')->comment('修改的字段');
$table->string('old_value')->nullable()->comment('旧值');
$table->string('new_value')->nullable()->comment('新值');
$table->timestamp('created_at')->nullable()->comment('创建时间');
$table->timestamp('updated_at')->nullable()->comment('更新时间');
$table->engine = 'InnoDB';
$table->charset = 'utf8mb4';
$table->collation = 'utf8mb4_unicode_ci';
$table->comment('会员扩展日志表');
});
}
/**
* Reverse the migrations.
*/
public function down(): void {
Schema::dropIfExists('member_extends');
Schema::dropIfExists('member_extends_fields');
Schema::dropIfExists('member_extends_log');
}
};

View File

@@ -0,0 +1,23 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void {
Schema::table('member_has_level', function (Blueprint $table) {
$table->timestamp('level_expire_time')->nullable()->after('level_id')->comment('等级到期时间');
});
}
/**
* Reverse the migrations.
*/
public function down(): void {
}
};

View File

@@ -0,0 +1,72 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void {
Schema::table('member', function (Blueprint $table) {
$table->string('invite_code')->nullable()->after('login_count')->comment('推荐码');
$table->string('old_password')->nullable()->after('password')->comment('旧密码');
$table->string('salt')->nullable()->after('old_password')->comment('密码盐值');
$table->unsignedBigInteger('pm_uid')->nullable()->after('invite_code')->comment('健康管理师id');
$table->unsignedBigInteger('store_id')->nullable()->after('pm_uid')->comment('所属综合服务体');
});
Schema::create('member_pm', function (Blueprint $table) {
$table->id()->uniqid()->comment('主键id');
$table->unsignedBigInteger('member_id')->comment('用户id');
$table->tinyInteger('level')->default(1)->comment('等级');
$table->string('name')->nullable()->comment('名称');
$table->integer('sex')->default(0)->comment('内容');
$table->string('mobile')->nullable()->comment('电话');
$table->string('area')->nullable()->comment('区域');
$table->tinyInteger('store_id')->default(0)->comment('所属综合服务体');
$table->tinyInteger('status')->default(1)->comment('状态');
$table->bigInteger('end_time')->nullable()->comment('到期时间');
$table->timestamp('created_at')->nullable()->comment('创建时间');
$table->timestamp('updated_at')->nullable()->comment('更新时间');
$table->engine = 'InnoDB';
$table->charset = 'utf8mb4';
$table->collation = 'utf8mb4_unicode_ci';
$table->comment('会员工作室表');
});
Schema::create('member_store', function (Blueprint $table) {
$table->id()->uniqid()->comment('主键id');
$table->unsignedBigInteger('member_id')->comment('用户id');
$table->string('name')->nullable()->comment('名称');
$table->string('logo')->nullable()->comment('logo');
$table->string('mobile')->nullable()->comment('电话');
$table->string('area')->nullable()->comment('区域');
$table->string('address')->nullable()->comment('地址');
$table->string('map')->nullable()->comment('地图坐标');
$table->string('license')->nullable()->comment('营业执照');
$table->tinyInteger('status')->default(1)->comment('状态');
$table->timestamp('created_at')->nullable()->comment('创建时间');
$table->timestamp('updated_at')->nullable()->comment('更新时间');
$table->engine = 'InnoDB';
$table->charset = 'utf8mb4';
$table->collation = 'utf8mb4_unicode_ci';
$table->comment('会员综合服务体表');
});
}
/**
* Reverse the migrations.
*/
public function down(): void {
Schema::table('member', function (Blueprint $table) {
$table->dropColumn('invite_code');
$table->dropColumn('old_password');
$table->dropColumn('salt');
});
Schema::dropIfExists('member_pm');
Schema::dropIfExists('member_store');
}
};

View File

@@ -0,0 +1,26 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('member', function (Blueprint $table) {
$table->string('date_type', 10)->default('lunar')->comment('会员生日类型')->after('birthday');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
//
}
};

View File

View File

@@ -0,0 +1,24 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Member\Database\Seeders;
use Illuminate\Database\Seeder;
class MemberDatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
$this->call([
MemberSeeder::class
]);
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace Modules\Member\Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use App\Services\Auth\MenuService;
class MemberSeeder extends Seeder {
/**
* Run the database seeds.
*/
public function run(): void {
$this->addMemberMenu();
}
/**
* @title 商品菜单导入
*
* @return void
*/
public function addMemberMenu(){
$permissions = [
['title' => '会员', 'name' => 'member', 'path' => '/member', 'component' => '', 'type' => 'menu', 'sort' => 1, 'children' => [
['title' => '会员列表', 'name' => 'member.lists', 'path' => '/member/lists', 'component' => 'member/lists', 'type' => 'menu'],
['title' => '会员等级', 'name' => 'member.level', 'path' => '/member/level', 'component' => 'member/level', 'type' => 'menu'],
['title' => '会员字段', 'name' => 'member.field', 'path' => '/member/field', 'component' => 'member/field', 'type' => 'menu'],
]],
];
return app(MenuService::class)->importMenu($permissions, 0);
}
}

View File

@@ -0,0 +1,11 @@
{
"name": "Member",
"alias": "member",
"description": "",
"keywords": [],
"priority": 0,
"providers": [
"Modules\\Member\\Providers\\MemberServiceProvider"
],
"files": []
}

View File

@@ -0,0 +1,15 @@
{
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build"
},
"devDependencies": {
"axios": "^1.1.2",
"laravel-vite-plugin": "^0.7.5",
"sass": "^1.69.5",
"postcss": "^8.3.7",
"vite": "^4.0.0"
}
}

View File

View File

View File

@@ -0,0 +1,7 @@
@extends('member::layouts.master')
@section('content')
<h1>Hello World</h1>
<p>Module: {!! config('member.name') !!}</p>
@endsection

View File

@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Member Module - {{ config('app.name', 'Laravel') }}</title>
<meta name="description" content="{{ $description ?? '' }}">
<meta name="keywords" content="{{ $keywords ?? '' }}">
<meta name="author" content="{{ $author ?? '' }}">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
{{-- Vite CSS --}}
{{-- {{ module_vite('build-member', 'resources/assets/sass/app.scss') }} --}}
</head>
<body>
@yield('content')
{{-- Vite JS --}}
{{-- {{ module_vite('build-member', 'resources/assets/js/app.js') }} --}}
</body>

View File

View File

@@ -0,0 +1,49 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
use Illuminate\Support\Facades\Route;
use Modules\Member\Controllers\MemberController;
// 会员管理路由配置
Route::name('member.')->prefix('member')->middleware(['auth.check:admin'])->group(function () {
Route::controller(Modules\Member\Controllers\Admin\Index::class)->prefix('index')->name('index.')->group(function () {
Route::get('/index', 'index')->name('index');
Route::post('/add', 'add')->name('add');
Route::put('/edit', 'edit')->name('edit');
Route::delete('/delete', 'delete')->name('delete');
Route::get('/export', 'export')->name('export');
Route::post('/import', 'import')->name('import');
});
Route::controller(Modules\Member\Controllers\Admin\Level::class)->prefix('level')->name('level.')->group(function () {
Route::get('/index', 'index')->name('index');
Route::post('/add', 'add')->name('add');
Route::put('/edit', 'edit')->name('edit');
Route::delete('/delete', 'delete')->name('delete');
});
Route::controller(Modules\Member\Controllers\Admin\Account::class)->prefix('account')->name('account.')->group(function () {
Route::get('/index', 'index')->name('index');
Route::post('/add', 'add')->name('add');
Route::put('/edit', 'edit')->name('edit');
Route::delete('/delete', 'delete')->name('delete');
});
Route::controller(Modules\Member\Controllers\Admin\Field::class)->prefix('field')->name('field.')->group(function () {
Route::get('/index', 'index')->name('index');
Route::post('/add', 'add')->name('add');
Route::put('/edit', 'edit')->name('edit');
Route::delete('/delete', 'delete')->name('delete');
Route::get('/fields', 'lists')->name('fields');
Route::get('/setting', 'setting')->name('setting');
});
Route::controller(Modules\Member\Controllers\Admin\Extend::class)->prefix('extend')->name('extend.')->group(function () {
Route::get('/index', 'index')->name('index');
Route::put('/audit', 'audit')->name('audit');
Route::delete('/delete', 'delete')->name('delete');
});
});

View File

@@ -0,0 +1,32 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
use Illuminate\Support\Facades\Route;
use Modules\Member\Controllers\MemberController;
Route::post('/member/login', [Modules\Member\Controllers\Api\Login::class, 'index'])->name('member.login');
Route::post('/member/register', [Modules\Member\Controllers\Api\Login::class, 'register'])->name('member.register');
Route::name('member.')->prefix('member')->middleware(['auth.check:api'])->group(function () {
Route::get('/user', [Modules\Member\Controllers\Api\Login::class, 'user'])->name('user');
Route::post('/logout', [Modules\Member\Controllers\Api\Login::class, 'logout'])->name('logout');
Route::controller(Modules\Member\Controllers\Api\Index::class)->prefix('member')->name('member.')->group(function () {
Route::get('/index', 'index')->name('index');
Route::put('/edit', 'edit')->name('edit');
Route::put('/editpasswd', 'editpasswd')->name('editpasswd');
});
Route::controller(Modules\Member\Controllers\Api\Extend::class)->prefix('extend')->name('extend.')->group(function () {
Route::get('/index', 'index')->name('index');
Route::get('/detail', 'detail')->name('detail');
Route::get('/field', 'field')->name('field');
Route::get('/level', 'level')->name('level');
Route::post('/save', 'save')->name('save');
});
});

View File

@@ -0,0 +1,9 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
use Illuminate\Support\Facades\Route;

View File

View File

View File

@@ -0,0 +1,26 @@
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
export default defineConfig({
build: {
outDir: '../../public/build-member',
emptyOutDir: true,
manifest: true,
},
plugins: [
laravel({
publicDirectory: '../../public',
buildDirectory: 'build-member',
input: [
__dirname + '/resources/assets/sass/app.scss',
__dirname + '/resources/assets/js/app.js'
],
refresh: true,
}),
],
});
//export const paths = [
// 'Modules/Member/resources/assets/sass/app.scss',
// 'Modules/Member/resources/assets/js/app.js',
//];

View File

@@ -0,0 +1,150 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Wechat\Controllers\Api;
use Illuminate\Http\Request;
use App\Http\Controllers\BaseController;
use Modules\Wechat\Services\OauthService;
use Modules\Wechat\Services\WechatService;
class Index extends BaseController {
/**
* 获取微信用户授权跳转
*/
public function oauth(Request $request, OauthService $service){
if($request->filled('code')){
if($request->filled('url')){
return redirect($request->input('url') . '?code=' . $request->input('code', ''));
}
}else{
$res = $service->oauth($request);
return redirect($res);
}
}
/**
* @title 微信登录
*
* @param Request $request
* @param OauthService $service
* @return void
*/
public function login(Request $request, OauthService $service){
$type = $request->input('type', 'wechat');
if($request->filled('code')){
$info = [];
switch ($type) {
case 'wechat':
try {
$info = $service->wechatLogin($request->input('code', ''));
} catch (\Throwable $th) {
$this->data['message'] = $th->getMessage();
$this->data['code'] = 0;
return $this->data;
}
break;
case 'miniapp':
try {
$info = $service->miniappLogin($request);
} catch (\Throwable $th) {
$this->data['message'] = $th->getMessage();
$this->data['code'] = 0;
return $this->data;
}
break;
default:
$this->data['message'] = "非法操作!";
$this->data['code'] = 0;
break;
}
if(isset($info['member_id']) && $info['member_id']){
$token = auth('api')->tokenById($info['member_id']);
if($token){
$this->data['data'] = [
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => auth('api')->factory()->getTTL() * 60
];
}elseif(isset($info['openid']) && $info['openid']){
$this->data['data'] = $info;
$this->data['message'] = "初次登录未绑定用户,请先绑定用户,或注册新用户绑定!";
$this->data['code'] = 100;
}else{
$this->data['message'] = "登录失败!";
$this->data['code'] = 0;
}
}else{
if(isset($info['openid']) && $info['openid']){
$this->data['data'] = $info;
$this->data['message'] = "初次登录未绑定用户,请先绑定用户,或注册新用户绑定!";
$this->data['code'] = 100;
}else{
$this->data['message'] = "登录失败!";
$this->data['code'] = 0;
}
}
}else{
$this->data['message'] = "非法操作!";
$this->data['code'] = 0;
}
return response()->json($this->data);
}
/**
* @title 微信公众号验证
*
* @param OauthService $service
* @return void
*/
public function serve(OauthService $service){
return $service->WechatServe();
}
/**
* @title 获取微信jssdk配置
*
* @param WechatService $service
* @return void
*/
public function jssdk(OauthService $service){
try {
$this->data['data'] = $service->getJsSdk($this->request);
} catch (\think\Exception $e) {
$this->data['message'] = $e->getMessage();
$this->data['code'] = 0;
}
return $this->data;
}
public function invitecode(Request $request, WechatService $service){
try {
$this->data['data'] = $service->getInviteCode($request);
} catch (\think\Exception $e) {
$this->data['message'] = $e->getMessage();
$this->data['code'] = 0;
}
return $this->data;
}
public function qrcode(Request $request, WechatService $service){
try {
$request->mergeIfMissing([
'doctor_id' => auth('doctor')->id(),
]);
$this->data['data'] = $service->getSingleQrcode($request);
} catch (\think\Exception $e) {
$this->data['message'] = $e->getMessage();
$this->data['code'] = 0;
}
return $this->data;
}
}

View File

@@ -0,0 +1,33 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Wechat\Listeners;
use Modules\Member\Events\LoginEvent;
use Modules\Wechat\Models\MemberSocial;
class LoginBind {
/**
* @title 会员登录后更新用户信息
*
* @param LoginEvent $event
* @return void
*/
public function handle(LoginEvent $event) {
$member = $event->member;
$openid = $event->openid;
$type = $event->type;
$social = MemberSocial::where('openid', $openid)->where('type', $type)->first();
if ($social && $social->member_id == 0) {
$social->member_id = $member->uid;
$social->save();
}
}
}

View File

@@ -0,0 +1,33 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Wechat\Listeners;
use Modules\Member\Events\Registered;
use Modules\Wechat\Models\MemberSocial;
class RegisterBind {
/**
* @title 会员登录后更新用户信息
*
* @param LoginEvent $event
* @return void
*/
public function handle(Registered $event) {
$member = $event->member;
$openid = $event->openid;
$type = $event->type;
$social = MemberSocial::where('openid', $openid)->where('type', $type)->first();
if ($social && $social->member_id == 0) {
$social->member_id = $member->uid;
$social->save();
}
}
}

View File

@@ -0,0 +1,18 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace Modules\Wechat\Models;
use App\Models\BaseModel;
class MemberSocial extends BaseModel {
protected $table = 'member_social';
protected $fillable = ['nickname', 'member_id', 'type', 'gender', 'openid', 'avatar', 'county', 'province', 'city', 'language', 'unionid'];
// protected $hidden = ['deleted_at'];
}

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