昨天在寫Code的時候一不注意時間就超過了
其實我本來是很懶惰容易放棄的人
在之前的參賽中我也是寫了幾篇就放棄了
但是這次希望可以堅持完成
完成一件事情不只是技術磨練及進步
而是對一個自我認同跟堅持的展現!!
真的很感謝IT邦跟永豐的機會
在我參賽的期間
我除了學習到了金流系統的交易(從未碰過)
我也加深了對Laravel的技能
之前我也是看教學影片而已
但是在實際做系統時才會發現許多細節要調整~
(Laravel 的MVC還有資料庫設計)
好啦我的心得分享差不多就到此結束了我們來完成最後的部分吧!
雖然有許多遺珠之憾
不過這個系統是我有興趣的
我希望以後可以把這個side project完成!!
今天的目標有點多!
我們來把它完成吧
我在寫文章的時候也會遇到失敗的地方
我希望可以把這些紀錄忠實呈現
除了可以提醒自我需要加強的地方外
也想跟大家分享
工程師沒有一開始就做出完美的系統
隨者patch的update我們才會與生活的改變進步!!
先上成果給大家看吧
我們首先要先製作修改首頁
在這之前我們先製作一個名為layout的樣板
也就是我們上方的navbar為主要樣式
其他的組件都可以套用上方列表
這樣我們就不用在每頁都製作導覽列(這也是許多現代前端框架會用的方法)
Layout.blade.php
<head>
<!-- Scripts -->
<script src="{{ asset('js/app.js') }}" defer></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"> </script>
<!-- Styles -->
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<div class="container">
<ul class="nav justify-content-center">
<li class="nav-item">
<a class="nav-link active" href="{{ url('/') }}">
<H2>首頁</H2>
</a>
</li>
<li class="nav-item">
<a class="nav-link active" href="{{ url('/skills') }}">
<H2>全技能列表</H2>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url('profile') }}">
<H2>個人檔案</H2>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url('/points')}}">
<h2>評分系統</h2>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url('/trades/record')}}">
<h2>訂單編號</h2>
</a>
</li>
<li class=" nav-item">
<a class="nav-link" href="{{ url('/skills/tree')}}">
<h2>技能樹</h2>
</a>
</li>
</ul>
<div class="container">
@yield('content')
</div>
</div>
這邊的樣板代表我可以把導覽列建立好作為我系統的主要樣板
yeild函數就是可以給其他blade填充的頁面
裡面的變數就是要填聰在哪個相對應的變數裡 -> 我這邊叫做content
再來大家看我簡單的首頁吧就會比較理解我說什麼了
Home.blade.php
@extends('layout')
@section('content')
<div class="jumbotron jumbotron-fluid">
<div class="container">
<h1 class="display-4">技能交換平台</h1>
<p class="lead">交換你的技能是放潛能吧!!</p>
</div>
</div>
@endsection
@extend 是代表我要延伸哪個樣板 我這邊選擇的是名叫layout的樣板
layout是我的 Layout.blade.php的名字喔 blade.php可以不加上去
接者使用 @section 跟@endsection包起來 變數就使用contnent包進去
聰民的你應該發現了!這樣的作法 我們可以用不同變數包在不同區域
比如說footer或是sidebar等等~~~
有了這樣的概念後我們把其他葉面都補上這個layout搂
user/profile.blade.php
@extends('layout')
<head>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"> </script>
<!-- Styles -->
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
<style>
.box {
display: flex;
/* align-items: center; */
justify-content: center;
height: 100%;
}
</style>
</head>
@section('content')
<div class="box">
<div>
<table class="table">
<thead class="thead-dark">
<tr>
<th scope="col">id</th>
<th scope="col">姓名</th>
<th scope="col">email</th>
<th scope="col">會員建立時間</th>
</tr>
</thead>
<tbody>
<tr>
<td>
{{$user->id}}
</td>
<td>
{{$user->name}}
</td>
<td>
{{$user->email}}
</td>
<td>
{{$user->created_at}}
</td>
</tr>
</tbody>
</table>
</div>
</div>
@endsection
以此類推
依照我前面的習慣
我們先建立Model跟migration吧
php artisan make:Trade -m
create_trades_table.php
接者在mirgration裡面增加這些欄位
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateTradesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('trades', function (Blueprint $table) {
$table->id();
$table->string('target_user_id'); // 交換者的User ID
$table->integer('skill_id'); // 對方的技能ID
$table->integer('user_id'); // 自己的User ID
$table->string('my_skill_id'); // 自己的技能ID
$table->string('shopNo'); // 建立訂單的編號
$table->integer('amount'); // 價錢 (前方說的技能相減分數*1000)
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('trades');
}
}
建立這些欄位的解釋麻煩幫我看註解喔
接者我們定義route吧!
Route::resource('trades', 'TradeController');
Trade Model fillable也要修改一下喔
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Trade extends Model
{
use HasFactory;
protected $fillable = [
'target_user_id',
'user_id', 'skill_id',
'my_skill_id', 'shopNo', 'amount'
];
}
為了讓大家了解我的系統流程
先讓大家看圖吧!
在評分表裡我們除了秀出個人對該技能的評分以外
我們也多了交易的按鈕
我們來看一下接下來會跳到哪個畫面喽!
接者跳到這畫面
說明 我現在是admin的使用者 我目標是roni的微積分作技能交換
那們作為交換我目前只有化學可以選
點擊過去就可以做交換搂!!
@extends('layout')
@section('content')
<div>
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>標題</th>
<th>使用者ID</th>
<th>技能評分</th>
<th>分數</th>
<th>交換技能</th>
</tr>
</thead>
<tbody>
@foreach($skills as $skill )
<tr>
<td>{{$skill->id}}</td>
<td>{{$skill->title}}</td>
<td>{{$skill->user_id}}</td>
<td><button type="button" class="btn btn-primary" onclick="myFunction('{{$skill->id}}','{{$skill->user_id}}')">進入評分</button></td>
<td>{{$skill->point}}</td>
<td><button class="btn btn-primary" onclick="goTrade('{{$skill->id}}','{{$skill->user_id}}','{{$my_id}}')">進行技能交換</button></td>
</tr>
@endforeach
</tbody>
</table>
<!-- {{$skills}} -->
<!-- {{$my_id}} -->
</div>
<script>
function myFunction(skill_id, user_id) {
var data = {
skill_id,
user_id
}
$.ajax({
method: "POST",
url: "/points",
dataType: 'json',
data
})
.done(function(msg) {
console.log(msg)
});
}
function goTrade(skill_id, user_id, my_id) {
var data = {
skill_id,
user_id: my_id,
target_user_id: user_id
}
window.location.replace(`/trades?skill_id=${data.skill_id}&user_id=${data.user_id}&target_user_id=${data.target_user_id}`)
}
</script>
@endsection
我們在評分上面goTrade function上動手角
把一些使用者參數跟技能ID
對方ID帶過去
那麼為了要帶到
交換的選擇頁面我們參數可以用query string的方式導向別的頁面
query string就是網址後面? 接變數然後用&接起來
像是youtube影片 可以接?t=10m20s 這些參數可以讓頁面讀取到指定的參數做api請求
或是js操作
在Controller/TradeController.php裡的index function
public function index(Request $request)
{
//
$data = $request->all();
$user = Auth::user();
$skill_id = $request->query('skill_id');
$user_id = $request->query('user_id');
$target_user_id = $request->query('target_user_id');
$myskills = Skill::where('user_id', $user->id)->get();
// dd($myskills);
return view('trade.index', [
'skill_id' => $skill_id,
'user_id' => $user_id,
'target_user_id' => $target_user_id,
'myskills' => $myskills
]);
}
我們可以用Auth::user先把登入者也就是自己抓出來
然後把query()抓取query string的參數
然後我們要把自己的技能抓出來
在丟回去
自己的技能丟回去是要給作為交換的技能
才會有我們看到的這個畫面
對了這邊有小提醒!我們在開發時php可以用dd()把變數印出來
前端也可以找個位置用{{}}花括號印在旁邊來參考
接者我們有了這些參數後
選擇化學跟roni的微積分進行技能交換吧
在看code之前我要提醒大家一件事
我們除了存進資料庫外還有一些是要做
比如說我們要新建一筆訂單
那麼我們要先跟nodejs的服務溝通
在跟永豐API 溝通完建立完成後
如果有成功我們再把這筆交易存進資料庫裡
為了溝通我們先使用這個Class吧
use Illuminate\Support\Facades\Http;
Controller/TradeController.php
public function store(Request $request)
{
$targetPoint = Point::find($request->point_id);
$myskillsPoint = Point::query()->where('skill_id', $request->my_skill_id)->get()->first();
$ScoreGap = abs($myskillsPoint->point - $targetPoint['point']);
// 這邊是要 計算分數差
$datenow = date('YmdHis');
$OrderNo = "A$datenow" . "1";
$Amount = $ScoreGap * 1000;
// 這邊data是php內建函數 可以抓現在時間 我把這當作訂單編號
// 最後前面補上A字串最後加上1防止訂單錯誤 (永豐尾數是9會模擬交易失敗)
// . 點 是php在接字串的方法 跟javascript + 一樣
// amount 的分數差 乘上 一千代表要交易的錢
$result = Http::post('http://localhost:8888/createOrder', [
'OrderNo' => $OrderNo,
'Amount' => $Amount * 100,
]);
// 對了這邊補上100是因為永豐會把尾數去掉兩個0
// 我們這邊把 可以在laravel做post
// 這個是我們nodejs的建立訂單的api
// 最後我們簡單判斷如果result有回傳version == 1.0.0代表我們有建立訂單成功
// 接者再把訂單存進資料庫的動作
if ($result['Version'] == "1.0.0") {
$trade = Trade::create([
'target_user_id' => $targetPoint['user_id'],
'user_id' => $myskillsPoint->user_id,
'skill_id' => $targetPoint['skill_id'],
'my_skill_id' => $myskillsPoint->skill_id, 'shopNo' => $OrderNo, 'amount' => $Amount
]);
return response(['trade' => $trade, 'nonce' => $result['Nonce'], 'msg' => $result['Message']]);
// return response($response);
}
// dd($response);
return "交易失敗";
}
補充
我們可以觀察這個表
透過這兩個分數表的技能分數相減
可以得到2喔
(roni 的微積分 跟admin的化學)
好啦我們來看結果吧!!
畫面有點長XD
但是為了表現有成功
把network教出來給大家看
小提醒: Chrome開發工具打開network可以幫助我們看APi 是否有叫成功喔!!
接者使用者就可以進到付款畫面喽
我們先新建一個紀錄個人所有交易的路由
Route::get('trades/record', 'TradeController@record');
接者去調整controller
public function record(Request $request)
{
if (!Auth::check()) {
return view('user.login');
}
$user = Auth::user();
$myresult = DB::table('trades')
->join('users', 'trades.target_user_id', '=', 'users.id')
->join('skills', 'skills.id', '=', 'trades.skill_id')
->where('trades.user_id', $user->id)->select('trades')
->select(
'users.name as target_user_name',
'skills.title as tatget_skill_title',
'ShopNo',
'amount',
'trades.created_at'
)
->get();
// $target_user_id = $myresult['target_user_id'];
// $target_user = User::find($target_user_id);
return view('trade.record', ['result' => $myresult]);
}
這邊用query builder的功能把sql串在一起
我們要把對方使用者名稱跟技能做聯表查詢
回傳的名稱可以用as就可以變更名稱
最後再把訂單編號、價錢、訂單日期回傳回來
我們可以先用dd來看回傳資料
給大家看對照比較好懂
接者我們就把index畫面補上吧
@extends('layout')
@section('content')
<div>
<table class="table table-bordered">
<thead>
<tr>
<th>交易對象</th>
<th>交易技能名稱</th>
<th>訂單編號</th>
<th>價錢</th>
<th>交易時間</th>
</tr>
</thead>
<tbody>
@foreach($result as $res)
<tr>
<td>{{$res->target_user_name}}</td>
<td>{{$res->tatget_skill_title}}</td>
<td>{{$res->ShopNo}}</td>
<td>{{$res->amount}}</td>
<td>{{$res->created_at}}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@endsection
接者就是成果拉
接者讓大家看一下
我本來是希望可以把自己有的技能以技能樹呈現出來給跟別人交換
但是案於時間關係沒有把它串完
可以讓大家看一下用d3js做的圖
使用d3js可以把既能呈現成這種形狀並且無限延伸
好啦
今天總結突然爆了一堆程式碼
相信大家也看得頭昏眼花了
先給大家程式碼聯結有興趣的可以玩看看喔
Laravel 的程式碼
這邊有一些地方可以跟大家分享
今天你得主服務可能是laravel可能是spring
但是其他小的服務比如說machine用python我們使用flask接
或是使用nodejs來串
那這些小型的微服務好處是把耦合性分離
不會因為一個service壞了整個系統
也很好把邏輯分開
但缺點是需要有人去維護處理
還有溝通之間的資安風險喔!!
最後如果要看每一天的篇章可以回到首篇來參考喔感謝大家!!
感謝這幾天有follow我的觀眾們!
看完我整包專案
應該可以對以下概念有所了解
我把一些重點篇章整理出來可以
由下方參考找到篇章喔
最後真的很感謝大家觀看
最後一篇章1萬5千多字的超長文XD
有興趣陪我一起技術可以透過我github找我信箱寫信喔!
如果喜歡我的分享可以幫我按讚喔XD