安装Jetstream
bash
composer require laravel/jetstream
使用Livewire安装Jetstream
php artisan jetstream:install livewire
首页控制器
go
php artisan make:controller HomeController --invokable
php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class HomeController extends Controller
{
/**
* Handle the incoming request.
*/
public function __invoke(Request $request)
{
return view('home');
}
}
路由
rust
use App\Http\Controllers\HomeController;
// 首页
Route::get('/',HomeController::class)->name('home');
添加迁移文件
Database\Migrations\2014_10_12_000000_create_users_table.php
scss
public function up(): void
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('username')->unique();
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->foreignId('current_team_id')->nullable();
$table->string('profile_photo_path', 2048)->nullable();
$table->string('banner_image')->nullable();
$table->string('channel_description')->nullable();
$table->timestamps();
});
}
执行迁移命令
php artisan migrate
安装Livewire:在你的项目中,使用Composer安装Livewire库。可以通过运行以下命令来完成安装:
bash
composer require livewire/livewire
安装MaryUI
css
composer require robsontenorio/mary
npm i -D tailwindcss daisyui@latest postcss autoprefixer && npx tailwindcss init -p
tailwind.config.js 编写
less
content: [
"./vendor/robsontenorio/mary/src/View/Components/**/*.php"
],
plugins: [
require("daisyui")
],
User模型设置白名单
ini
protected $fillable = [
...
...
'username',
'banner_image',
'channel_description'
];
前端模版
添加登记和注册按钮
resources/views/navigation-menu.blade.php
xml
<!-- Navigation Links -->
<div class="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
<x-nav-link href="{{ route('dashboard') }}" :active="request()->routeIs('dashboard')">
{{ __('Dashboard') }}
</x-nav-link>
</div>
</div>
<!-- 登录注册 -->
@guest
<div class="hidden sm:flex sm:items-center sm:ms-6">
<x-nav-link href="{{ route('login') }}" :active="request()->routeIs('dengl')">
{{ __('登录') }}
</x-nav-link>
<x-nav-link href="{{ route('register') }}" :active="request()->routeIs('register')">
{{ __('注册') }}
</x-nav-link>
</div>
@endguest
效果图:
删除MaryUI 组件
input.bide.php、welcome.blagg.php、dropdown.biade.php、dropdown-link.biade.php
删除欢迎界面 <x-welcome / >
resources/views/dashboard.blade.php
xml
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Dashboard') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
<x-welcome / > // 删除
</div>
</div>
</div>
</x-app-layout>
启动个人资料图片
config/Jetstream,开启Features::profilePhotos()
ini
'features' => [
Features::profilePhotos(),
],
账户设置添加控制器
App\Actions\Fortify\UpdateUserProfileInformation.php
php
public function update(User $user, array $input): void
{
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'username' => ['required', 'string', 'max:255', Rule::unique('users')->ignore($user->id)],
'email' => ['required', 'email', 'max:255', Rule::unique('users')->ignore($user->id)],
'photo' => ['nullable', 'mimes:jpg,jpeg,png', 'max:1024'],
])->validateWithBag('updateProfileInformation');
if (isset($input['photo'])) {
$user->updateProfilePhoto($input['photo']);
}
if ($input['email'] !== $user->email &&
$user instanceof MustVerifyEmail) {
$this->updateVerifiedUser($user, $input);
} else {
$user->forceFill([
'name' => $input['name'],
'username' => $input['username'],
'email' => $input['email'],
])->save();
}
}
'username' => ['required', 'string', 'max:255', Rule::unique('users')->ignore($user->id)],
, 为自己添加的
账号设置页面
resources/views/profile/update-profile-information-form.blade.php 添加username 字段
xml
<!-- Name -->
<div class="col-span-6 sm:col-span-4">
<x-input label="Name" id="name" type="text" class="mt-1 block w-full" wire:model="state.name" required autocomplete="name" />
<x-input-error for="name" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-4">
<x-input label="Username" id="username" type="text" class="mt-1 block w-full" wire:model="state.username" required autocomplete="username" />
<x-input-error for="username" class="mt-2" />
</div>
<!-- Email -->
<div class="col-span-6 sm:col-span-4">
<x-input label="Email" id="email" type="email" class="mt-1 block w-full" wire:model="state.email" required autocomplete="username" />
<x-input-error for="email" class="mt-2" />
<x-button type="sybmit" wire:loading.attr="disabled" wire:target="photo">
{{ __('Save') }}
</x-button>
type="sybmit"
此为按钮
修改密码页面
resources/views/profile/update-password-form.blade.php
ini
<x-slot name="form">
<div class="col-span-6 sm:col-span-4">
<x-input lable="Current password" id="current_password" type="password" class="mt-1 block w-full" wire:model="state.current_password" autocomplete="current-password" />
<x-input-error for="current_password" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-4">
<x-input lable="Password" id="password" type="password" class="mt-1 block w-full" wire:model="state.password" autocomplete="new-password" />
<x-input-error for="password" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-4">
<x-input lable="Confirm password" id="password_confirmation" type="password" class="mt-1 block w-full" wire:model="state.password_confirmation" autocomplete="new-password" />
<x-input-error for="password_confirmation" class="mt-2" />
</div>
</x-slot>
<x-button type="sybmit">
{{ __('Save') }}
</x-button>
resources/views/profile/two-factor-authentication-form.blade.php
less
@if ($showingConfirmation)
<div class="mt-4">
<x-input label="code" id="code" type="text" name="code" class="block mt-1 w-1/2" inputmode="numeric" autofocus autocomplete="one-time-code"
wire:model="code"
wire:keydown.enter="confirmTwoFactorAuthentication" />
<x-input-error for="code" class="mt-2" />
</div>
@endif
注册页面
resources/views/auth/login.blade.php
xml
<x-guest-layout>
<x-authentication-card>
<x-slot name="logo">
<x-authentication-card-logo />
</x-slot>
<x-validation-errors class="mb-4" />
<form method="POST" action="{{ route('register') }}">
@csrf
<div>
<x-input label="昵称" id="name" class="block mt-1 w-full" type="text" name="name" :value="old('name')" required autofocus autocomplete="name" />
</div>
<div class="mt-4">
<x-input label="用户名" id="username" class="block mt-1 w-full" type="text" name="username" :value="old('username')" required autofocus autocomplete="username" />
</div>
<div class="mt-4">
<x-input label="电子邮箱" id="email" class="block mt-1 w-full" type="email" name="email" :value="old('email')" required autocomplete="username" />
</div>
<div class="mt-4">
<x-input label="密码" id="password" class="block mt-1 w-full" type="password" name="password" required autocomplete="new-password" />
</div>
<div class="mt-4">
<x-input label="确认密码" id="password_confirmation" class="block mt-1 w-full" type="password" name="password_confirmation" required autocomplete="new-password" />
</div>
@if (Laravel\Jetstream\Jetstream::hasTermsAndPrivacyPolicyFeature())
<div class="mt-4">
<x-label for="terms">
<div class="flex items-center">
<x-checkbox name="terms" id="terms" required />
<div class="ms-2">
{!! __('I agree to the :terms_of_service and :privacy_policy', [
'terms_of_service' => '<a target="_blank" href="'.route('terms.show').'" class="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">'.__('Terms of Service').'</a>',
'privacy_policy' => '<a target="_blank" href="'.route('policy.show').'" class="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">'.__('Privacy Policy').'</a>',
]) !!}
</div>
</div>
</x-label>
</div>
@endif
<div class="flex items-center justify-end mt-4">
<a class="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" href="{{ route('login') }}">
{{ __('已经注册?') }}
</a>
<x-button class="ms-4" type="submit">
{{ __('注册') }}
</x-button>
</div>
</form>
</x-authentication-card>
</x-guest-layout>
效果图:
config\fortify.php 修改成 identity
ini
'username' => 'identity',
'email' => 'identity',
登录控制器验证改造
App\Providers\FortifyServiceProvider
php
public function boot(): void
{
Fortify::authenticateUsing(function (LoginRequest $request) {
$user = User::where('email', $request->identity)
->orWhere('username', $request->identity)->first();
if (
$user &&
Hash::check($request->password, $user->password)
) {
return $user;
}
});
}
登录页面
resources/views/auth/login.blade.php
xml
<x-guest-layout>
<x-authentication-card>
<x-slot name="logo">
<x-authentication-card-logo />
</x-slot>
<x-validation-errors class="mb-4" />
@if (session('status'))
<div class="mb-4 font-medium text-sm text-green-600">
{{ session('status') }}
</div>
@endif
<form method="POST" action="{{ route('login') }}">
@csrf
<div>
<x-input label="电子邮箱/用户名" id="identity" class="block mt-1 w-full" type="text" name="identity" :value="old('identity')" required autofocus autocomplete="identity" />
</div>
<div class="mt-4">
<x-input label="密码" id="password" class="block mt-1 w-full" type="password" name="password" required autocomplete="current-password" />
</div>
<div class="block mt-4">
<label for="remember_me" class="flex items-center">
<x-checkbox id="remember_me" name="remember" />
<span class="ms-2 text-sm text-gray-600">{{ __('记住我') }}</span>
</label>
</div>
<div class="flex items-center justify-end mt-4">
@if (Route::has('password.request'))
<a class="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" href="{{ route('password.request') }}">
{{ __('忘记密码?') }}
</a>
@endif
<x-button type="submit" class="ms-4">
{{ __('登录') }}
</x-button>
</div>
</form>
</x-authentication-card>
</x-guest-layout>
identity
为用户名和电子邮箱登录