Commit e2a8da32 by 杨树贤

完成兑换配置的增删改查

parent f0ebf966
<?php
namespace App\Http\Controllers\Api;
use App\Http\Requests\ExchangeSettingApiRequest;
use App\Http\Services\ExchangeSettingService;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class ExchangeSettingsApiController extends Controller
{
protected $service;
public function __construct(ExchangeSettingService $service) {
$this->service = $service;
}
public function exchangeSettingListApi(Request $request, ExchangeSettingService $service)
{
$data = $service->getExchangeSettingList('/exchange_settings?' . urldecode(http_build_query($request->all())));
$data = $this->transformer($data);
return $this->apiReturn(0, 'ok', [
'data' => $data['data'],
'count' => $data['count'],
]);
}
private function transformer($data)
{
foreach ($data['data'] as &$item) {
$item['status'] = $item['status'] ? '使用中' : '已停用';
$item['add_time'] = date('Y-m-d H:i:s', $item['add_time']);
$item['update_time'] = $item['update_time'] ? date('Y-m-d H:i:s', $item['update_time']) : '暂无更新';
}
unset($item);
return $data;
}
public function storeExchangeSettingApi(ExchangeSettingApiRequest $request, ExchangeSettingService $service)
{
$result = $service->storeExchangeSetting('/exchange_settings', $request->all());
return $result;
}
public function updateExchangeSettingApi(ExchangeSettingApiRequest $request, ExchangeSettingService $service)
{
$result = $service->updateExchangeSetting('/exchange_settings/' . $request->id, $request->all());
return $result;
}
public function deleteExchangeSettingApi(Request $request, ExchangeSettingService $service)
{
$result = $service->deleteExchangeSetting('/exchange_settings/' . $request->id);
return $result;
}
public function changeExchangeSettingStatusApi(Request $request)
{
$id = $request->id;
$status = $request->status;
$path = '/exchange_settings/' . $id;
$result = $this->service->changeExchangeSettingStatus($path, ['status' => $status]);
return $result;
}
public function batchUpdateStatusApi(Request $request)
{
$path = '/exchange_settings/batchUpdateStatus';
$result = $this->service->batchUpdateStatus($path, $request->all());
return $result;
}
}
<?php
namespace App\Http\Controllers;
use App\Http\Services\ExchangeSettingService;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class ExchangeSettingsController extends Controller
{
protected $service;
public function __construct(ExchangeSettingService $service) {
$this->service = $service;
}
//
public function Entrance(Request $request, $id = 'index')
{
if ($request->path() == '/') {
$path = 'web/index';
} else {
$path = $request->path();
}
$this->data = [
'menus' => $request->menus,
'header' => $request->user->header,
'username' => $request->user->email,
'useremail' => $request->user->email,
'uri' => '/' . $path,
'id' => $id,
];
return $this->$id($request);
}
public function __call($method, $parameters)
{
return $this->errhtml('NotFind', '没有这个页面');
}
public function exchangeSettingList()
{
$this->data['title'] = '兑换红包配置';
return $this->view();
}
public function createExchangeSetting()
{
$this->data['title'] = '新增红包配置';
return $this->view();
}
public function updateExchangeSetting(Request $request)
{
$this->data['title'] = '修改红包配置';
$exchangeSetting = $this->service->getExchangeSetting('/exchange_settings/' . $request->id);
$this->data['exchangeSetting'] = $exchangeSetting['data'];
return $this->view();
}
public function storeExchangeSetting(Request $request)
{
// $result = $this->service->storeExchangeSetting('/integrals', $request->all());
// if ($result['errno'] === 0) {
// return redirect('/integrals/integralList');
// }
}
}
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ExchangeSettingApiRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
//
];
}
}
<?php
namespace App\Http\Services;
class ExchangeSettingService extends BaseService
{
public function getExchangeSetting($path)
{
return $this->apiGet($path);
}
public function getExchangeSettingList($path)
{
return $this->apiGet($path);
}
public function deleteExchangeSetting($path)
{
return $this->apiDelete($path);
}
public function storeExchangeSetting($path, $data)
{
return $this->apiPost($path, $data);
}
public function updateExchangeSetting($path, $data)
{
return $this->apiPatch($path, $data);
}
public function changeExchangeSettingStatus($path, $data = [])
{
return $this->apiPatch($path, $data);
}
public function batchUpdateStatus($path, $data = [])
{
return $this->apiPost($path, $data);
}
}
\ No newline at end of file
......@@ -22,17 +22,15 @@ class UserIntegralService extends BaseService
return $this->apiGet($path);
}
public function getUserMobilesFromRedis($userIds = [])
public function getUsersFromRedis($userIds = [])
{
$redis = new RedisModel();
$users = $redis->hmget('ic_user', $userIds);
$userMobiles = [];
foreach ($users as $user) {
$user = json_decode($user, true);
$userMobiles[$user['user_id']] = $user['mobile'];
foreach ($users as $key => $user) {
$users[$key] = json_decode($user, true);
}
return $userMobiles;
return $users;
}
public function getUserIdByMobile($mobile)
......
......@@ -20,7 +20,10 @@ class IntegralBillTransformer
{
foreach ($data['data'] as &$item) {
$userId = \request()->user_id;
$mobile = $this->service->getUserMobilesFromRedis($userId);
$users = $this->service->getUsersFromRedis($userId);
foreach ($users as $user) {
$mobile[$user['user_id']] = $user['mobile'];
}
$item['mobile'] = array_get($mobile, $userId);
$item['integral_name'] = array_get($item, 'integral.name');
$item['status'] = $item['status'] ? '成功' : '失败';
......
......@@ -10,22 +10,39 @@ class UserIntegralTransformer
{
protected $service;
public function __construct(UserIntegralService $service) {
public function __construct(UserIntegralService $service)
{
$this->service = $service;
}
public function transform($data)
{
$userIds = array_column($data['data'], 'user_id');
$userMobiles = [];
$certifications = [];
if ($userIds) {
$userMobiles = $this->service->getUserMobilesFromRedis($userIds);
if ($userIds) {
$users = $this->service->getUsersFromRedis($userIds);
foreach ($users as $user) {
$userMobiles[$user['user_id']] = $user['mobile'];
$certifications[$user['user_id']] = array_get($user, 'company_type', 0);
}
}
}
foreach ($data['data'] as &$item) {
$item['status'] = $item['status'] ? '正常' : '禁用';
$mobile = array_get($userMobiles, $item['user_id'], '无');
$item['mobile'] = $mobile;
$item['certification_status'] = array_get($certifications, $item['user_id'], 0);
if ($item['certification_status'] === 1) {
$item['certification_status'] = '企业认证';
} elseif ($item['certification_status'] === 2) {
$item['certification_status'] = '个人认证';
} else {
$item['certification_status'] = '暂无认证';
}
}
unset($item);
......
......@@ -16,7 +16,6 @@ class StatusPresenter
</select>
</div>
EOF;
return $html;
}
......
layui.use('form', function () {
var form = layui.form;
form.on('switch(switchStatus)', function (data) {
this.value = this.checked ? 1 : 0;
});
form.on('submit(CreateExchangeSetting)', function (data) {
let url = '/exchange/settings/api/storeExchangeSettingApi';
$.ajax({
type: 'POST',
url: url,
data: data.field,
success: function (result) {
if (result.errcode === 0) {
layer.msg('新增配置成功');
window.location = '/exchange/settings/exchangeSettingList';
}
}
});
});
});
function getRequestParams() {
var url = location.search;
var theRequest = new Object();
if (url.indexOf("?") != -1) {
var str = url.substr(1);
strs = str.split("&");
for (var i = 0; i < strs.length; i++) {
theRequest[strs[i].split("=")[0]] = decodeURI(strs[i].split("=")[1]);
}
}
return theRequest;
}
layui.use(['table', 'form', 'laydate', 'layer'], function () {
var table = layui.table;
var form = layui.form;
table.render({
elem: '#list'
, skin: 'line'
, url: '/exchange/settings/api/exchangeSettingListApi'
, method: 'post'
, request: {
pageName: 'page'
, limitName: 'page_size'
}
, where: getRequestParams()
, toolbar: '#toolbarLeft'
, defaultToolbar: ['filter']
, loading: true
, cols: [[
{type: 'checkbox'}
, {field: 'id', title: '序号'}
, {field: 'name', title: '商品名称'}
, {field: 'type', title: '商品类型'}
, {field: 'amount', title: '兑换所需金额'}
, {field: 'status', title: '配置状态', templet: '#status'}
, {field: 'update_time', title: '配置更新时间', templet: '#update_time'}
, {field: 'experience', title: '操作', templet: '#operate', fixed: 'right'}
]]
, id: 'ExchangeSetting'
, page: {
// layout: ['prev', 'page', 'next', 'count', 'skip'] //自定义分页布局
}
});
function changeStatus(checkStatus, status, table) {
var data = checkStatus.data;
var ids = [];
for (var key in data) {
ids.push(data[key].id);
}
var operateText = status ? '恢复' : '禁用';
layer.confirm('确定要批量' + operateText + '?', function (index) {
$.ajax({
url: '/exchange/settings/api/batchUpdateStatusApi',
type: 'post',
data: {ids: ids, status: status},
dataType: 'json',
timeout: 10000,
success: function (res) {
if (!res) return layer.msg('网络错误,请重试', {icon: 5});
if (res.errcode === 0) {
var msg = status ? '批量恢复成功' : '批量禁用成功';
layer.msg('批量' + operateText + '成功');
table.reload('ExchangeSetting');
}
},
error: function () {
return layer.msg('网络错误,请重试', {icon: 5});
}
})
})
}
//监听行工具事件
table.on('tool(ExchangeSetting)', function (obj) { //注:tool 是工具条事件名,test 是 table 原始容器的属性 lay-filter="对应的值"
var data = obj.data //获得当前行数据
, layEvent = obj.event; //获得 lay-event 对应的值
switch (layEvent) {
case 'disable':
layer.confirm('确定要禁用该条配置?', function (index) {
//向服务端发送禁用指令
$.get('/exchange/settings/api/changeExchangeSettingStatusApi', {
id: obj.data.id,
status: 0
}, function (result) {
if (result.errcode === 0) {
layer.msg('禁用成功!');
layer.close(index);
table.reload('ExchangeSetting');
}
});
});
break;
case 'recover':
layer.confirm('确定要恢复该条配置?', function (index) {
$.get('/exchange/settings/api/changeExchangeSettingStatusApi', {
id: obj.data.id,
status: 1
}, function (result) {
if (result.errcode === 0) {
layer.msg('恢复成功!');
layer.close(index);
table.reload('ExchangeSetting');
}
});
});
break;
case 'edit':
window.location = '/exchange/settings/updateExchangeSetting?id=' + obj.data.id;
break;
}
});
form.on('submit(load)', function (data) {
//执行重载
table.reload('ExchangeSetting', {
page: {
curr: 1 //重新从第 1 页开始
}
, where: data.field
});
return false;
});
//头工具栏事件
table.on('toolbar(ExchangeSetting)', function (obj) {
var checkStatus = table.checkStatus(obj.config.id);
switch (obj.event) {
case 'batchDisableStatus':
changeStatus(checkStatus, 0, table);
break;
case 'batchRecoverStatus':
changeStatus(checkStatus, 1, table);
break;
case 'isAll':
layer.msg(checkStatus.isAll ? '全选' : '未全选');
break;
}
});
});
\ No newline at end of file
......@@ -29,8 +29,7 @@ layui.use(['table', 'form', 'laydate', 'layer', 'element'], function () {
, defaultToolbar: ['filter']
, loading: true
, cols: [[
{type: 'checkbox'}
, {field: 'mobile', title: '账号'}
{field: 'mobile', title: '账号'}
, {field: 'integral_name', title: '事件'}
, {field: 'status', title: '执行结果'}
, {field: 'add_time', title: '操作时间',templet:'#add_time'}
......
layui.use('form', function () {
var form = layui.form;
form.on('switch(switchStatus)', function (data) {
this.value = this.checked ? 1 : 0;
});
form.on('submit(UpdateExchangeSetting)', function (data) {
let url = '/exchange/settings/api/updateExchangeSettingApi';
$.ajax({
type: 'POST',
url: url,
data: data.field,
success: function (result) {
if (result.errcode === 0) {
layer.msg('修改配置成功');
window.location = '/exchange/settings/exchangeSettingList';
}
}
});
});
});
......@@ -17,24 +17,27 @@ function changeStatus(checkStatus, status, table) {
for (var key in data) {
ids.push(data[key].id);
}
$.ajax({
url: '/user_integrals/api/batchUpdateStatusApi',
type: 'post',
data: {ids: ids, status: status},
dataType: 'json',
timeout: 10000,
success: function (res) {
if (!res) return layer.msg('网络错误,请重试', {icon: 5});
if (res.errcode === 0) {
var msg = status ? '批量恢复成功' : '批量禁用成功';
layer.msg(msg);
table.reload('UserIntegral');
var operateText = status ? '恢复' : '禁用';
layer.confirm('确定要批量' + operateText + '? 禁用之后你所选择的用户都将无法进行红包兑换!', function (index) {
$.ajax({
url: '/user_integrals/api/batchUpdateStatusApi',
type: 'post',
data: {ids: ids, status: status},
dataType: 'json',
timeout: 10000,
success: function (res) {
if (!res) return layer.msg('网络错误,请重试', {icon: 5});
if (res.errcode === 0) {
var msg = status ? '批量恢复成功' : '批量禁用成功';
layer.msg(msg);
table.reload('UserIntegral');
}
},
error: function () {
return layer.msg('网络错误,请重试', {icon: 5});
}
},
error: function () {
return layer.msg('网络错误,请重试', {icon: 5});
}
})
})
}
......@@ -93,7 +96,7 @@ layui.use(['table', 'form', 'laydate', 'layer'], function () {
, layEvent = obj.event;
switch (layEvent) {
case 'disable':
layer.confirm('确定要禁用户兑换红包?', function (index) {
layer.confirm('确定要禁用户兑换红包?', function (index) {
//向服务端发送禁用指令
$.get('/user_integrals/api/changeUserIntegralStatus', {
id: obj.data.id,
......
<div class="layui-card">
<div class="layui-card-body" style="padding-top: 20px">
<div class="layui-form">
<input type="hidden" name="id">
<div class="layui-form-item">
<label class="layui-form-label">红包名称</label>
<div class="layui-input-block">
<input type="text" name="name" lay-verify="required"
autocomplete="off" placeholder="请输入红包名称"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
@inject('statusPresenter','App\Presenters\StatusPresenter')
{!! $statusPresenter->render('type','商品类型',0,[0=>'无',1=>'类型1',2=>'类型2']) !!}
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">兑换所需金额</label>
<div class="layui-input-inline">
<input type="text" name="amount""
lay-verify="required|number"
autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">每日库存</label>
<div class="layui-input-inline">
<input type="text" name="stock"
lay-verify="required|number"
autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
@inject('statusPresenter','App\Presenters\StatusPresenter')
{!! $statusPresenter->render('status','配置状态',1,[0=>'已停用',1=>'使用中']) !!}
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit="" lay-filter="CreateExchangeSetting">立即提交</button>
{{-- <button type="reset" class="layui-btn layui-btn-primary">重置</button>--}}
</div>
</div>
</div>
</div>
</div>
\ No newline at end of file
<div class="layui-card">
<div class="layui-form layui-card-header layuiadmin-card-header-auto">
<form class="layui-form" action="">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">商品名称</label>
<div class="layui-input-inline">
<input type="text" name="name" value="{{request()->get('name')}}"
class="layui-input">
</div>
</div>
<div class="layui-inline">
@inject('statusPresenter','App\Presenters\StatusPresenter')
{!! $statusPresenter->render('type','商品类型',request()->get('type'),[0=>'无',1=>'类型1',2=>'类型2']) !!}
</div>
<div class="layui-inline">
@inject('statusPresenter','App\Presenters\StatusPresenter')
{!! $statusPresenter->render('status','配置状态',request()->get('status'),[0=>'已停用',1=>'使用中']) !!}
</div>
<div class="layui-inline">
<button type="submit" class="layui-btn">
<i class="layui-icon layui-icon-search layuiadmin-button-btn"></i>
</button>
<a type="button" class="layui-btn" href="/exchange/settings/exchangeSettingList">
<i class="layui-icon layui-icon-refresh-3 layuiadmin-button-btn" title="重置搜索"></i>
</a>
</div>
</div>
</form>
</div>
<div class="layui-card-body" style="padding-top: 20px">
<div style="padding-bottom: 10px;">
{{-- <button class="layui-btn layui-btn-danger layuiadmin-btn-list" data-type="batchdel">禁用</button>--}}
<a href="/exchange/settings/createExchangeSetting" class="layui-btn layuiadmin-btn-list"
data-type="add">添加</a>
</div>
<table class="layui-table" id="list" lay-filter="ExchangeSetting"></table>
</div>
</div>
<script type="text/html" id="operate">
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="edit">编辑</a>
@{{# if(d.status == '使用中'){ }}
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="disable">禁用</a>
@{{# } else { }}
<a class="layui-btn layui-btn-green layui-btn-xs" lay-event="recover">恢复</a>
@{{# } }}
</script>
<script type="text/html" id="status">
@{{# if(d.status == '使用中'){ }}
<span class="layui-badge-dot layui-bg-blue"></span>
@{{# } else { }}
<span class="layui-badge-dot layui-bg-gray"></span>
@{{# } }}
@{{d.status}}
</script>
<script type="text/html" id="toolbarLeft">
<div class="layui-btn-container">
<button class="layui-btn layui-btn-danger layui-btn-sm" lay-event="batchDisableStatus">禁用所选中行</button>
<button class="layui-btn layui-btn-green layui-btn-sm" lay-event="batchRecoverStatus">恢复所选中行</button>
</div>
</script>
\ No newline at end of file
<div class="layui-card">
<div class="layui-card-body" style="padding-top: 20px">
<div class="layui-form">
<input type="hidden" name="id" value="{{$exchangeSetting['id']}}">
<div class="layui-form-item">
<label class="layui-form-label">红包名称</label>
<div class="layui-input-block">
<input type="text" name="name" value="{{$exchangeSetting['name']}}" lay-verify="required"
autocomplete="off" placeholder="请输入红包名称"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
@inject('statusPresenter','App\Presenters\StatusPresenter')
{!! $statusPresenter->render('type','商品类型',$exchangeSetting['type'],[0=>'无',1=>'类型1',2=>'类型2']) !!}
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">兑换所需金额</label>
<div class="layui-input-inline">
<input type="text" name="amount" value="{{$exchangeSetting['amount']}}"
lay-verify="required|number"
autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">每日库存</label>
<div class="layui-input-inline">
<input type="text" name="stock" value="{{$exchangeSetting['stock']}}"
lay-verify="required|number"
autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form-item">
@inject('statusPresenter','App\Presenters\StatusPresenter')
{!! $statusPresenter->render('status','配置状态',$exchangeSetting['status'],[0=>'已停用',1=>'使用中']) !!}
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit="" lay-filter="UpdateExchangeSetting">立即提交</button>
{{-- <button type="reset" class="layui-btn layui-btn-primary">重置</button>--}}
</div>
</div>
</div>
</div>
</div>
\ No newline at end of file
<div class="layui-card">
<div class="layui-card-body" style="padding-top: 20px">
<div class="layui-form layui-card-header layuiadmin-card-header-auto">
<form class="layui-form" action="">
<div class="layui-form-item">
<div class="layui-inline">
......@@ -9,22 +9,23 @@
autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-inline">
@inject('statusPresenter','App\Presenters\StatusPresenter')
{!! $statusPresenter->render('status','兑换状态',request()->get('status')) !!}
</div>
<div class="layui-inline">
<button type="submit" class="layui-btn layui-btn-sm">
<button type="submit" class="layui-btn">
<i class="layui-icon layui-icon-search layuiadmin-button-btn"></i>
</button>
<a type="button" href="/user_integrals/userIntegralList"
class="layui-btn layui-btn-primary layui-btn-sm">
<i class="layui-icon layui-icon-refresh-3" title="重置搜索"></i>
<a type="button" class="layui-btn" href="/user_integrals/userIntegralList">
<i class="layui-icon layui-icon-refresh-3 layuiadmin-button-btn" title="重置搜索"></i>
</a>
</div>
</div>
</form>
</div>
<div class="layui-card-body" style="padding-top: 20px">
<table class="layui-table" id="UserIntegral" lay-filter="UserIntegral"></table>
</div>
......
......@@ -26,6 +26,7 @@ Route::group(['middleware' => 'web'], function () {
Route::match(['get', 'post'], '/integrals/{key}', 'IntegralsController@Entrance');
Route::match(['get', 'post'], '/user_integrals/{key}', 'UserIntegralsController@Entrance');
Route::match(['get', 'post'], '/integral_bills/{key}', 'IntegralBillsController@Entrance');
Route::match(['get', 'post'], '/exchange/settings/{key}', 'ExchangeSettingsController@Entrance');
});
Route::get('/time', function () {
......@@ -39,9 +40,25 @@ Route::namespace('Api')->group(function () {
Route::match(['get', 'post'], '/integrals/api/updateIntegralApi', 'IntegralsApiController@updateIntegralApi');
//用户积分
Route::match(['get', 'post'], '/user_integrals/api/userIntegralList', 'UserIntegralsApiController@userIntegralListApi');
Route::match(['get', 'post'], '/user_integrals/api/changeUserIntegralStatus', 'UserIntegralsApiController@changeUserIntegralStatusApi');
Route::match(['get', 'post'], '/integral_bills/api/integralBillList', 'IntegralBillsApiController@integralBillListApi');
Route::match(['get', 'post'], '/user_integrals/api/batchUpdateStatusApi', 'UserIntegralsApiController@batchUpdateStatusApi');
Route::match(['get', 'post'], '/user_integrals/api/userIntegralList',
'UserIntegralsApiController@userIntegralListApi');
Route::match(['get', 'post'], '/user_integrals/api/changeUserIntegralStatus',
'UserIntegralsApiController@changeUserIntegralStatusApi');
Route::match(['get', 'post'], '/integral_bills/api/integralBillList',
'IntegralBillsApiController@integralBillListApi');
Route::match(['get', 'post'], '/user_integrals/api/batchUpdateStatusApi',
'UserIntegralsApiController@batchUpdateStatusApi');
//积分兑换配置
Route::match(['get', 'post'], '/exchange/settings/api/exchangeSettingListApi',
'ExchangeSettingsApiController@exchangeSettingListApi');
Route::match(['get', 'post'], '/exchange/settings/api/storeExchangeSettingApi',
'ExchangeSettingsApiController@storeExchangeSettingApi');
Route::match(['get', 'post'], '/exchange/settings/api/updateExchangeSettingApi',
'ExchangeSettingsApiController@updateExchangeSettingApi');
Route::match(['get', 'post'], '/exchange/settings/api/changeExchangeSettingStatusApi',
'ExchangeSettingsApiController@changeExchangeSettingStatusApi');
Route::match(['get', 'post'], '/exchange/settings/api/batchUpdateStatusApi',
'ExchangeSettingsApiController@batchUpdateStatusApi');
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment