您将要創造的
本教程是 Envato Tuts +上的“ 使用PHP建構啟動”系列 的一部分。 在本系列文章中,我 将以 我的 Meeting Planner 應用程式作為真實示例 ,指導您完成從概念到現實的啟動 。 在此過程的每一步中,我都會将Meeting Planner代碼作為開放源代碼示例釋出,您可以從中學習。 我還将解決與啟動相關的業務問題。
小組會議簡介
與多個參與者安排會議始終是我計劃的一部分,但不屬于最早的最低可行産品(MVP)的一部分。 Meeting Planner的Alpha版本僅以1:1的計劃啟動。 支援小組日程安排的目标像登上珠穆朗瑪峰一樣位于任務清單上,目标是針對七個峰會的登山者(我什至都不是戶外登山者)。
安排多個參與者會議是最具挑戰性的,是以對于會議計劃器産品而言非常有價值。 當Beta任務清單達到可以開始從事此工作的程度時,我感到很興奮。
我從一開始就一直在計劃,設計和編碼小組會議。 我希望為此功能更新站點将不需要進行大量的UX更改或編碼更新。 事實證明,這需要一條中間路線,需要7到10天的重點工作和測試,而無需進行重大重新架構。
實際上,事實證明,測試是建構此功能最困難的方面。 它還有助于揭示早期代碼中的缺點。 隻是這并不容易...發送到多個電子郵件位址,檢查每個電子郵件位址都收到所有正确的通知,但沒有收到錯誤的通知-并檢視整個站點中所有正确的菜單選項。
在今天的教程中,我将介紹啟用多個參與者,更新組的UX,任命組織者,删除參與者,以及根據參與者的受歡迎程度對日期,時間和地點選項進行排序。
在下一個教程中,我将描述其餘的工作:複查受多個參與者會議影響的站點的所有區域,處理并智能顯示各種狀态的收件人清單,适當地管理組的通知和通知過濾,最後更新最近啟動的請求會議更改功能 。
嘗試安排小組會議
請今天安排一個小組會議 ! 在下面的評論中分享您的想法和回報。
我确實參與了讨論,但是您也可以在Twitter上與我聯系@reifman 。 我總是樂于接受Meeting Planner的新功能建議以及有關未來系列劇集的建議。
提醒一下,Meeting Planner的所有代碼都是開源提供的,并使用PHP的Yii2架構編寫。 如果您想了解有關Yii2的更多資訊,請檢視我的平行系列“ 使用Yii2程式設計” 。 我聽說過有關Laravel的很棒的事情,但是Yii2總是可以輕松快捷地滿足我的需求。
回頭看
當我第一次設計Meeting Planner計劃界面時 ,它在其自己的列中顯示了其他參與者的目前可用性。 由于存在禁用的控件,這有點令人困惑。
當時,我擔心如何騰出空間來顯示群組的可用性。
幸運的是,當我重建UX以獲得更好的響應體驗時 ,我用一個小的文本摘要替換了參與者的可用性列:
可用性的文本摘要恰好适合小組會議。
通過首先針對移動裝置進行重新設計,我解決了多次參加會議的最大使用者體驗障礙!
小組會議的編碼
讓我們開始周遊所有代碼并測試多個參與者會議所需的内容。
允許多個參與者
小組會議最有趣的方面是激活會議很簡單。 我隻需要在計劃階段關閉“ 誰”面闆上的加号圖示按鈕的禁用功能即可:
<div class="col-lg-2 col-md-2 col-xs-2">
<div style="float:right;">
<?= Html::a(Yii::t('frontend', ''), ['/participant/create', 'meeting_id' => $model->id], ['class' => 'btn btn-primary '.($model->status>=$model::STATUS_CONFIRMED?'disabled':'').' glyphicon glyphicon-plus']) ?>
</div>
</div>
然後,我開始建立一個 參與者模型中的
MEETING_LIMIT
:
class Participant extends \yii\db\ActiveRecord
{
...
const MEETING_LIMIT = 15;
它在送出時用于
ParticipantController::actionCreate()
中:
public function actionCreate($meeting_id)
{
if (!Participant::withinLimit($meeting_id)) {
Yii::$app->getSession()->setFlash('error', Yii::t('frontend','Sorry, you have reached the maximum number of participants per meeting. Contact support if you need additional help or want to offer feedback.'));
return $this->redirect(['/meeting/view', 'id' => $meeting_id]);
}
推進使用者體驗和相關功能
很長一段時間以來,我一直希望允許會議組織者删除參與者,地點和日期時間,而又不會使使用者界面混亂。 同樣,我意識到可能會有多個指令要對參與者執行。
在“ 進階指令”教程的緊湊型Bootstrap下拉按鈕中找到了很多實用程式之後,我決定将其用于顯示會議與會者:
組織者以星号表示。 拒絕參加會議的與會者以橙色顯示。 組織者删除的與會者以紅色顯示。
這是我新的部分/frontend/views/participant/_buttons.php中的代碼:
<div class="btn-group btn-participant">
<button type="button" class="btn btn-default btn-sm dropdown-toggle " data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="glyphicon glyphicon-star red-star aria-hidden="true"></span>
<?= MiscHelpers::getDisplayName($model->owner_id) ?>
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><?= Html::a(Yii::t('frontend','Send a message'),Url::to('mailto:'.$model->owner->email))?></li>
</ul>
</div>
現在任何人都可以向任何參與者發送消息(會議記錄功能目前已分發給所有會議參與者)。
組織者看到了更深的下拉菜單,這使他們可以任命其他組織者,即Make Organer 。 現在,這是一個非常酷的功能。 組織者将在整個計劃階段收到更完整的通知,并擁有更多權力。 他們還可以删除參與者 。
将AJAX功能建構到參與者按鈕中
我一時興起就決定将所有這些菜單選項都AJAXify。 事實證明,這需要幾個小時的編碼。
這是定義初始按鈕菜單并準備JavaScript的代碼:
<?php
if (count($model->participants)>0) {
foreach ($model->participants as $p) {
if ($p->participant->id==Yii::$app->user->getId()) {
continue;
}
$btn_color = 'btn-default';
if ($p->status == Participant::STATUS_DECLINED) {
$btn_color = 'btn-warning';
} else if ($p->status == Participant::STATUS_REMOVED || $p->status == Participant::STATUS_DECLINED_REMOVED) {
$btn_color = 'btn-danger';
}
?>
<div class="btn-group btn-participant">
<button id="btn_<?= $p->id ?>" type="button" class="btn <?= $btn_color ?> btn-sm dropdown-toggle " data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span id="star_<?= $p->id ?>" class="glyphicon glyphicon-star red-star <?= (!$p->isOrganizer())?'hidden':''?>" aria-hidden="true"></span>
<?= MiscHelpers::getDisplayName($p->participant->id) ?>
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><?= Html::a(Yii::t('frontend','Send a message'),Url::to('mailto:'.$p->participant->email))?></li>
<?php if ($model->isOrganizer()) {
?>
<li role="separator" class="divider"></li>
<li id="mo_<?= $p->id ?>" class="<?= ($p->isOrganizer())?'hidden':''?>"><?= Html::a(Yii::t('frontend','Make organizer'),'javascript:void(0);',['onclick' => "toggleOrganizer($p->id,true);return false;"]); ?></li>
<li id="ro_<?= $p->id ?>" class="<?= (!$p->isOrganizer())?'hidden':''?>"><?= Html::a(Yii::t('frontend','Revoke organizer role'),'javascript:void(0);',['onclick' => "toggleOrganizer($p->id,false);return false;"]); ?></li>
<li id="rp_<?= $p->id ?>" class="<?= ($p->status == Participant::STATUS_REMOVED || $p->status == Participant::STATUS_DECLINED_REMOVED)?'hidden':''?>"><?= Html::a(Yii::t('frontend','Remove participant'),'javascript:void(0);',['onclick' => "toggleParticipant($p->id,false,$p->status);return false;"]); ?></li>
<li id="rstp_<?= $p->id ?>" class="<?= ($p->status != Participant::STATUS_REMOVED && $p->status != Participant::STATUS_DECLINED_REMOVED)?'hidden':''?>"><?= Html::a(Yii::t('frontend','Restore participant'),'javascript:void(0);',['onclick' => "toggleParticipant($p->id,true,$p->status);return false;"]); ?></li>
<?php
}
?>
</ul>
</div>
當頁面上以互動方式進行更改時,要更新的按鈕狀态,顔色和星号太多,是以代碼變得相當複雜。 我将功能添加到
toggleOrganizer()
JavaScript檔案中的
toggleOrganizer()
,即make / unset
toggleParticipant()
和
toggleParticipant()
, 即删除/恢複參與者作為參與者。
function toggleOrganizer(id, val) {
if (val === true) {
arg2 = 1;
} else {
arg2 =0;
}
$.ajax({
url: $('#url_prefix').val()+'/participant/toggleorganizer',
data: {id: id, val: arg2},
success: function(data) {
if (data) {
if (val===false) {
$('#star_'+id).addClass("hidden");
$('#ro_'+id).addClass("hidden");
$('#mo_'+id).removeClass("hidden");
} else {
$('#star_'+id).removeClass("hidden");
$('#ro_'+id).removeClass("hidden");
$('#mo_'+id).addClass("hidden");
}
}
return true;
}
});
}
function toggleParticipant(id, val, original_status) {
if (val === true) {
arg2 = 1;
} else {
arg2 =0;
}
$.ajax({
url: $('#url_prefix').val()+'/participant/toggleparticipant',
data: {id: id, val: arg2, original_status: original_status},
success: function(data) {
if (data) {
if (val===false) {
$('#rp_'+id).addClass("hidden");
$('#rstp_'+id).removeClass("hidden");
$('#btn_'+id).addClass("btn-danger");
$('#btn_'+id).removeClass("btn-default");
} else {
$('#rp_'+id).removeClass("hidden");
$('#rstp_'+id).addClass("hidden");
if (original_status==100) {
$('#btn_'+id).addClass("btn-warning");
$('#btn_'+id).removeClass("btn-danger");
} else {
$('#btn_'+id).addClass("btn-default");
$('#btn_'+id).removeClass("btn-danger");
}
}
}
return true;
}
});
}
這些在ParticipantController.php中需要随附的JSON控制器方法來處理切換請求和更新資料庫:
public function actionToggleorganizer($id,$val) {
Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
// change setting
$p=Participant::findOne($id);
if ($p->meeting->isOrganizer()) {
$p->email = $p->participant->email;
if ($val==1) {
$p->participant_type=Participant::TYPE_ORGANIZER;
} else {
$p->participant_type=Participant::TYPE_DEFAULT;
}
$p->update();
return true;
} else {
return false;
}
}
public function actionToggleparticipant($id,$val) {
Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
// change setting
$p=Participant::findOne($id);
if ($p->meeting->isOrganizer()) {
$p->email = $p->participant->email;
if ($val==0) {
if ($p->status == Participant::STATUS_DECLINED) {
$p->status=Participant::STATUS_DECLINED_REMOVED;
} else {
$p->status=Participant::STATUS_REMOVED;
}
} else {
if ($p->status == Participant::STATUS_DECLINED_REMOVED) {
$p->status=Participant::STATUS_DECLINED;
} else {
$p->status=Participant::STATUS_DEFAULT;
}
}
$p->update();
return true;
} else {
return false;
}
}
在面闆上激活手風琴功能
這時,我還意識到,随着會議計劃的複雜性增加,接收者和選項的增加,滾動的内容也會越來越多。 我決定為會議視圖上的所有面闆實施Bootstrap手風琴功能 。
換句話說,您現在可以單擊标題以折疊或打開每個和/或所有面闆。
這是對聚會場所_panel.php的局部的更改:
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading" role="tab" id="headingWhere">
<div class="row">
<div class="col-lg-10 col-md-10 col-xs-10" ><h4 class="meeting-place">
<a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapseWhere" target="_blank" rel="external nofollow" aria-expanded="true" aria-controls="collapseWhere"><?= Yii::t('frontend','Where') ?></a>
</h4><p>
<div class="hint-text heading-pad">
<?php if ($placeProvider->count<=1) { ?>
<?= Yii::t('frontend','add places for participants or switch to \'virtual\'') ?>
<?php } elseif ($placeProvider->count>1) { ?>
<?= Yii::t('frontend','are listed places okay? ') ?>
<?php
}
?>
...
<div id="collapseWhere" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingWhere">
<div class="panel-body">
<?php
$style = ($model->switchVirtual==$model::SWITCH_VIRTUAL?'none':'block');
?>
<div id ="meeting-place-list" style="display:<?php echo $style; ?>">
<?php
if ($placeProvider->count>0):
?>
<table class="table">
<?= ListView::widget([
'dataProvider' => $placeProvider,
'itemOptions' => ['class' => 'item'],
'layout' => '{items}',
'itemView' => '_list',
'viewParams' => ['placeCount'=>$placeProvider->count,'isOwner'=>$isOwner,'participant_choose_place'=>$model->meetingSettings['participant_choose_place'],'whereStatus'=>$whereStatus],
]) ?>
</table>
注意上面
panel-heading
上的設定,然後注意後面的
panel-body
周圍的div。 這些控制每個面闆的打開和折疊。
這導緻了一些小的外觀問題,例如在項目清單周圍出現不必要的填充,我将來需要清理這些問題。
小組會議的模型基礎架構
盡管我幾乎從一開始就計劃有多個參與者,但在基礎設施方面有一些次要的改進以支援他們。
雖然
MeetingTimeChoice
和
MeetingPlaceChoice
模型跟蹤參與者是否喜歡特定的日期時間和地點,但我想跟蹤每個日期和地點所有參與者的總體可用性。 這将使我能夠根據地點和時間的受歡迎程度對其進行排序,并在面闆頂部顯示最受歡迎的設定。
首先,我建立了一個遷移,以将其添加到兩個模型中。 我的遷移很少會影響多個模型,這使得這種特殊情況變得如此:
<?php
use yii\db\Schema;
use yii\db\Migration;
class m160824_235517_extend_meeting_place_and_time extends Migration
{
public function up()
{
$tableOptions = null;
if ($this->db->driverName === 'mysql') {
$tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
}
$this->addColumn('{{%meeting_time}}','availability',Schema::TYPE_SMALLINT.' NOT NULL DEFAULT 0');
$this->addColumn('{{%meeting_place}}','availability',Schema::TYPE_SMALLINT.' NOT NULL DEFAULT 0');
}
public function down()
{
$this->dropColumn('{{%meeting_time}}','availability');
$this->dropColumn('{{%meeting_place}}','availability');
}
}
有了這種能力,我就可以從
MeetingController::actionView()
開始顯示可能的會議日期時間和地點,
MeetingController::actionView()
參加者的受歡迎程度排序:
$timeProvider = new ActiveDataProvider([
'query' => MeetingTime::find()->where(['meeting_id'=>$id]),
'sort' => [
'defaultOrder' => [
'availability'=>SORT_DESC
]
],
]);
$placeProvider = new ActiveDataProvider([
'query' => MeetingPlace::find()->where(['meeting_id'=>$id]),
'sort' => [
'defaultOrder' => [
'availability'=>SORT_DESC
]
],
]);
您可以在下面的計劃螢幕截圖中看到這一點:
為了跟蹤參與者是否是組織者,并允許将來退出特定會議的通知,我為“參與者”表添加了此遷移:
<?php
use yii\db\Schema;
use yii\db\Migration;
class m160825_074740_extend_participant_add_type extends Migration
{
public function up()
{
$tableOptions = null;
if ($this->db->driverName === 'mysql') {
$tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
}
$this->addColumn('{{%participant}}','participant_type',Schema::TYPE_SMALLINT.' NOT NULL DEFAULT 0');
$this->addColumn('{{%participant}}','notify',Schema::TYPE_SMALLINT.' NOT NULL DEFAULT 0');
}
public function down()
{
$this->dropColumn('{{%participant}}','participant_type');
$this->dropColumn('{{%participant}}','notify');
}
}
我還在Participant.php中添加了一些常量以使用這些屬性:
class Participant extends \yii\db\ActiveRecord
{
const TYPE_DEFAULT = 0;
const TYPE_ORGANIZER = 10;
const NOTIFY_ON = 0;
const NOTIFY_OFF = 1;
const STATUS_DEFAULT = 0;
const STATUS_REMOVED = 90;
const STATUS_DECLINED = 100;
const STATUS_DECLINED_REMOVED = 110;
我知道在大型會議模型中具有一些輔助功能會很有幫助。 例如,
IsOrganizer()
告訴我目前檢視者是否是會議組織者:
public function isOrganizer() {
$user_id = Yii::$app->user->getId();
if ($user_id == $this->owner_id) {
return true;
} else {
foreach ($this->participants as $p) {
if ($user_id == $p->participant_id) {
if ($p->participant_type == Participant::TYPE_ORGANIZER) {
return true;
} else {
return false;
}
}
}
}
return false;
}
等等,還有嗎?
如您所見,建構此功能有很多基礎。 在下一個情節中,我将介紹啟動多個參與者會議所需的開發和測試的後半部分:收件人字元串,通知,請求以及對請求的響應。
如果還沒有,請安排與Meeting Planner的第一次會議,然後嘗試所有這些。 請在下面的評論中分享您的回報。
有關衆籌的教程也正在編寫中 ,是以請關注我們的WeFunder Meeting Planner頁面 。
您也可以與我聯系@reifman 。 我總是樂于接受新功能的想法和主題建議,以供将來的教程使用。
請閱讀“ 用PHP建構您的啟動”系列,繼續關注所有這些以及以後的教程。
相關連結
- 會議策劃人
- 關注會議計劃者的資金概況
- 使用Yii2系列進行程式設計(Envato Tuts +)
翻譯自: https://code.tutsplus.com/tutorials/building-your-startup-meetings-with-multiple-participants--cms-27132