Laravel9+FullCalendar+Livewire:模态框增改日程数据求助
Laravel 9 + Livewire + FullCalendar 5 实现日程新增与修改功能
我已经在Laravel 9项目中完成了FullCalendar 5与Livewire组件的集成,实现了以下功能:
- 点击日历空白日期触发
select函数弹出模态框 - 点击已有日程触发
eventClick函数弹出同一模态框,且能将数据库中的日程数据填充到模态框输入框内
现在需要实现模态框中保存按钮的逻辑,分别通过updateEvent和addEvent函数完成日程的修改与新增操作。
一、统一模态框(livewire/eventmodal.blade.php)
将原有的两个模态框合并为一个,新增隐藏的event_id字段用于区分新增/修改操作:
<div class="modal fade" id="eventModal" tabindex="-1" aria-labelledby="eventModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="eventModalLabel">@if($event_id) 修改日程 @else 新增日程 @endif</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <form wire:submit.prevent="@if($event_id) updateEvent @else saveEvent @endif"> <div class="modal-body"> <input type="hidden" wire:model="event_id"> <div class="mb-3"> <label for="title" class="form-label">标题</label> <input type="text" class="form-control" id="title" wire:model="title"> @error('title') <span class="text-danger">{{ $message }}</span> @enderror </div> <div class="mb-3"> <label for="acronym" class="form-label">缩写</label> <input type="text" class="form-control" id="acronym" wire:model="acronym"> </div> <div class="mb-3"> <label for="city" class="form-label">城市</label> <input type="text" class="form-control" id="city" wire:model="city"> </div> <div class="mb-3"> <label for="venue" class="form-label">地点</label> <input type="text" class="form-control" id="venue" wire:model="venue"> </div> <div class="mb-3"> <label for="value" class="form-label">值</label> <input type="text" class="form-control" id="value" wire:model="value"> </div> <div class="mb-3"> <label for="start" class="form-label">开始时间</label> <input type="datetime-local" class="form-control" id="start" wire:model="start"> @error('start') <span class="text-danger">{{ $message }}</span> @enderror </div> <div class="mb-3"> <label for="end" class="form-label">结束时间</label> <input type="datetime-local" class="form-control" id="end" wire:model="end"> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button> <button type="submit" class="btn btn-primary">保存</button> </div> </form> </div> </div> </div>
二、修改Livewire Calendar组件
添加必要属性、验证规则、updateEvent方法,完善日期处理逻辑:
<?php namespace App\Http\Livewire; use Livewire\Component; use App\Models\Event; use App\Models\Resource; use Illuminate\Support\Arr; use Carbon\Carbon; class Calendar extends Component { public $events, $resources; public $event_id, $title, $acronym, $city, $venue, $value, $start, $end; // 验证规则 protected $rules = [ 'title' => 'required|string|max:255', 'start' => 'required|date', ]; public function resetInput() { $this->event_id = null; $this->title = ''; $this->acronym = ''; $this->city = ''; $this->venue = ''; $this->value = ''; $this->start = ''; $this->end = ''; } public function saveEvent() { $this->validate(); $eventData = [ 'title' => $this->title, 'start' => Carbon::parse($this->start)->toIso8601String(), 'extendedProps' => [ 'acronym' => $this->acronym, 'city' => $this->city, 'venue' => $this->venue, 'value' => $this->value ] ]; if ($this->end) { $eventData['end'] = Carbon::parse($this->end)->toIso8601String(); } Event::create($eventData); session()->flash('message', '日程新增成功'); $this->resetInput(); $this->dispatchBrowserEvent('close-modal'); } public function updateEvent() { $this->validate(); $event = Event::find($this->event_id); if (!$event) { session()->flash('error', '日程不存在'); return; } $eventData = [ 'title' => $this->title, 'start' => Carbon::parse($this->start)->toIso8601String(), 'extendedProps' => [ 'acronym' => $this->acronym, 'city' => $this->city, 'venue' => $this->venue, 'value' => $this->value ] ]; if ($this->end) { $eventData['end'] = Carbon::parse($this->end)->toIso8601String(); } $event->update($eventData); session()->flash('message', '日程修改成功'); $this->resetInput(); $this->dispatchBrowserEvent('close-modal'); $this->events = json_encode(Event::all()); } public function eventChange($event) { $e = Event::find($event['id']); if (!$e) return; $e->start = $event['start']; if (Arr::exists($event, 'end')) { $e->end = $event['end']; } $e->save(); } public function eventAdd($event) { Event::create($event); } public function eventRemove($id) { Event::destroy($id); } public function resourceAdd($resources) { Resource::create($resources); } public function resourceRemove($id) { Resource::destroy($id); } public function render() { $this->events = json_encode(Event::all()); $this->resources = json_encode(Resource::all()); return view('livewire.calendar'); } }
三、修改FullCalendar的JS逻辑
统一模态框调用逻辑,实现Livewire数据同步,添加日历刷新逻辑:
@push('scripts') <script src='https://cdn.jsdelivr.net/npm/fullcalendar-scheduler@5.10.1/main.min.js'></script> <script> create_UUID = () => { let dt = new Date().getTime(); const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { let r = (dt + Math.random() * 16) % 16 | 0; dt = Math.floor(dt / 16); return (c == 'x' ? r :(r&0x3|0x8)).toString(16); }); return uuid; } document.addEventListener('livewire:load', function () { const Calendar = FullCalendar.Calendar; const calendarEl = document.getElementById('calendar'); const Draggable = FullCalendar.Draggable; new Draggable(document.getElementById('events'), { itemSelector: '.dropEvent' }); const calendar = new Calendar(calendarEl, { headerToolbar: { left: 'promptResource prev,next today', center: 'title', right: 'resourceMonth,dayGridMonth,timeGridWeek,timeGridDay,listMonth' }, views: { resourceMonth: { type: 'resourceTimelineMonth', buttonText: '人员' } }, customButtons: { promptResource: { text: "+ 人员", click: function() { var title = prompt("姓名"); if (title) { calendar.addResource({ title: title }); fetch("add_resources.php", { method: "POST", headers: { Accept: "application/json" }, body: new URLSearchParams({ title: title }) }) .then(response => console.log(response)) .catch(error => console.log(error)); } } } }, initialView: 'resourceTimelineMonth', locale: '{{ config('app.locale') }}', events: JSON.parse(@this.events), resourceAreaHeaderContent: '人员', resources: JSON.parse(@this.resources), editable: true, eventResize: info => @this.eventChange(info.event), eventDrop: info => @this.eventChange(info.event), eventReceive: info => { const id = create_UUID(); info.event.setProp('id', id); @this.eventAdd(info.event); }, selectable: true, select: function(info) { @this.resetInput(); @this.set('start', info.startStr); if (info.endStr) { @this.set('end', info.endStr); } $('#eventModal').modal('show'); }, eventClick: function(info) { @this.set('event_id', info.event.id); @this.set('title', info.event.title); @this.set('acronym', info.event.extendedProps.acronym); @this.set('city', info.event.extendedProps.city); @this.set('venue', info.event.extendedProps.venue); @this.set('value', info.event.extendedProps.value); @this.set('start', info.event.startStr); if (info.event.endStr) { @this.set('end', info.event.endStr); } $('#eventModal').modal('show'); }, }); calendar.render(); document.addEventListener('close-modal', function() { $('#eventModal').modal('hide'); calendar.refetchEvents(); }); }); </script> <link href='https://cdn.jsdelivr.net/npm/fullcalendar-scheduler@5.11.3/main.min.css' rel='stylesheet' /> @endpush
功能说明
- 模态框区分操作:通过
event_id字段自动判断调用新增/修改方法 - 数据双向同步:使用
wire:model绑定表单字段,实现Livewire与视图的数据同步 - 日期格式兼容:将用户输入的日期转换为ISO8601格式,确保FullCalendar正确解析
- 实时刷新日历:保存完成后通过
refetchEvents()刷新日历,展示最新日程
内容的提问来源于stack exchange,提问作者Steve Adams
相关产品推荐
相关产品推荐

