Use server side table

This commit is contained in:
Pig Fang 2018-08-13 11:08:14 +08:00
parent f71a9b3dd8
commit 7e4ae5381b
7 changed files with 202 additions and 28 deletions

View File

@ -238,37 +238,72 @@ class AdminController extends Controller
public function getUserData(Request $request)
{
$users = collect();
$isSingleUser = $request->has('uid');
if ($request->has('uid')) {
if ($isSingleUser) {
$users = User::select(['uid', 'email', 'nickname', 'score', 'permission', 'register_at'])
->where('uid', intval($request->input('uid')));
->where('uid', intval($request->input('uid')))
->get();
} else {
$users = User::select(['uid', 'email', 'nickname', 'score', 'permission', 'register_at']);
$search = $request->input('search', '');
$sortField = $request->input('sortField', 'uid');
$sortType = $request->input('sortType', 'asc');
$page = $request->input('page', 1);
$perPage = $request->input('perPage', 10);
$users = User::select(['uid', 'email', 'nickname', 'score', 'permission', 'register_at'])
->where('uid', 'like', '%' . $search . '%')
->orWhere('email', 'like', '%' . $search . '%')
->orWhere('nickname', 'like', '%' . $search . '%')
->orWhere('score', 'like', '%' . $search . '%')
->orderBy($sortField, $sortType)
->offset(($page - 1) * $perPage)
->limit($perPage)
->get();
}
return Datatables::of($users)->editColumn('email', function ($user) {
return $user->email ?: 'EMPTY';
})
->setRowId('uid')
->addColumn('operations', Auth::user()->permission)
->addColumn('players_count', function ($user) {
return $user->players->count();
})
->make(true);
$users->transform(function ($user) {
$user->operations = auth()->user()->permission;
$user->players_count = $user->players->count();
return $user;
});
return [
'totalRecords' => $isSingleUser ? 1 : User::count(),
'data' => $users
];
}
public function getPlayerData(Request $request)
{
$players = collect();
if ($request->has('uid')) {
$isSpecifiedUser = $request->has('uid');
if ($isSpecifiedUser) {
$players = Player::select(['pid', 'uid', 'player_name', 'preference', 'tid_steve', 'tid_alex', 'tid_cape', 'last_modified'])
->where('uid', intval($request->input('uid')));
->where('uid', intval($request->input('uid')))
->get();
} else {
$players = Player::select(['pid', 'uid', 'player_name', 'preference', 'tid_steve', 'tid_alex', 'tid_cape', 'last_modified']);
$search = $request->input('search', '');
$sortField = $request->input('sortField', 'pid');
$sortType = $request->input('sortType', 'asc');
$page = $request->input('page', 1);
$perPage = $request->input('perPage', 10);
$players = Player::select(['pid', 'uid', 'player_name', 'preference', 'tid_steve', 'tid_alex', 'tid_cape', 'last_modified'])
->where('pid', 'like', '%' . $search . '%')
->orWhere('uid', 'like', '%' . $search . '%')
->orWhere('player_name', 'like', '%' . $search . '%')
->orWhere('preference', 'like', '%' . $search . '%')
->orderBy($sortField, $sortType)
->offset(($page - 1) * $perPage)
->limit($perPage)
->get();
}
return Datatables::of($players)->setRowId('pid')->make(true);
return [
'totalRecords' => $isSpecifiedUser ? 1 : Player::count(),
'data' => $players
];
}
/**

View File

@ -1,10 +1,16 @@
<template>
<section class="content">
<vue-good-table
mode="remote"
:rows="players"
:totalRows="totalRecords || players.length"
:columns="columns"
:search-options="tableOptions.search"
:pagination-options="tableOptions.pagination"
@on-page-change="onPageChange"
@on-sort-change="onSortChange"
@on-search="onSearch"
@on-per-page-change="onPerPageChange"
styleClass="vgt-table striped"
>
<template slot="table-row" slot-scope="props">
@ -94,6 +100,7 @@ export default {
data() {
return {
players: [],
totalRecords: 0,
columns: [
{ field: 'pid', label: 'PID', type: 'number' },
{ field: 'player_name', label: this.$t('general.player.player-name') },
@ -103,6 +110,13 @@ export default {
{ field: 'last_modified', label: this.$t('general.player.last-modified') },
{ field: 'operations', label: this.$t('admin.operationsTitle'), globalSearchDisabled: true, sortable: false },
],
serverParams: {
sortField: 'pid',
sortType: 'asc',
page: 1,
perPage: 10,
search: '',
},
tableOptions: {
search: {
enabled: true,
@ -124,7 +138,29 @@ export default {
},
methods: {
async fetchData() {
this.players = (await this.$http.get(`/admin/player-data${location.search}`)).data;
const { data, totalRecords } = await this.$http.get(
`/admin/player-data${location.search}`,
!location.search && this.serverParams
);
this.totalRecords = totalRecords;
this.players = data;
},
onPageChange(params) {
this.serverParams.page = params.currentPage;
this.fetchData();
},
onPerPageChange(params) {
this.serverParams.perPage = params.currentPerPage;
this.fetchData();
},
onSortChange(params) {
this.serverParams.sortType = params.sortType;
this.serverParams.sortField = this.columns[params.columnIndex].field;
this.fetchData();
},
onSearch(params) {
this.serverParams.search = params.searchTerm;
this.fetchData();
},
async changeTexture(player, model) {
const { dismiss, value } = await swal({

View File

@ -1,10 +1,16 @@
<template>
<section class="content">
<vue-good-table
mode="remote"
:rows="users"
:totalRows="totalRecords || users.length"
:columns="columns"
:search-options="tableOptions.search"
:pagination-options="tableOptions.pagination"
@on-page-change="onPageChange"
@on-sort-change="onSortChange"
@on-search="onSearch"
@on-per-page-change="onPerPageChange"
styleClass="vgt-table striped"
>
<template slot="table-row" slot-scope="props">
@ -96,6 +102,7 @@ export default {
data() {
return {
users: [],
totalRecords: 0,
columns: [
{ field: 'uid', label: 'UID', type: 'number' },
{ field: 'email', label: this.$t('general.user.email') },
@ -106,6 +113,13 @@ export default {
{ field: 'register_at', label: this.$t('general.user.register-at') },
{ field: 'operations', label: this.$t('admin.operationsTitle'), sortable: false, globalSearchDisabled: true }
],
serverParams: {
sortField: 'uid',
sortType: 'asc',
page: 1,
perPage: 10,
search: '',
},
tableOptions: {
search: {
enabled: true,
@ -127,9 +141,30 @@ export default {
},
methods: {
async fetchData() {
const { data } = await this.$http.get(`/admin/user-data${location.search}`);
const { data, totalRecords } = await this.$http.get(
`/admin/user-data${location.search}`,
!location.search && this.serverParams
);
this.totalRecords = totalRecords;
this.users = data;
},
onPageChange(params) {
this.serverParams.page = params.currentPage;
this.fetchData();
},
onPerPageChange(params) {
this.serverParams.perPage = params.currentPerPage;
this.fetchData();
},
onSortChange(params) {
this.serverParams.sortType = params.sortType;
this.serverParams.sortField = this.columns[params.columnIndex].field;
this.fetchData();
},
onSearch(params) {
this.serverParams.search = params.searchTerm;
this.fetchData();
},
async changeEmail(user) {
const { dismiss, value } = await swal({
text: this.$t('admin.newUserEmail'),

View File

@ -9,7 +9,41 @@ jest.mock('@/js/notify');
test('fetch data after initializing', () => {
Vue.prototype.$http.get.mockResolvedValue({ data: [] });
mount(Players);
expect(Vue.prototype.$http.get).toBeCalledWith('/admin/player-data');
expect(Vue.prototype.$http.get).toBeCalledWith(
'/admin/player-data',
{ page: 1, perPage: 10, search: '', sortField: 'pid', sortType: 'asc' }
);
});
test('update tables', async () => {
Vue.prototype.$http.get.mockResolvedValue({
data: Array.from({ length: 20 }).map((item, pid) => ({ pid }))
});
const wrapper = mount(Players);
wrapper.find('.vgt-input').setValue('abc');
expect(Vue.prototype.$http.get).toBeCalledWith(
'/admin/player-data',
{ page: 1, perPage: 10, search: 'abc', sortField: 'pid', sortType: 'asc' }
);
wrapper.vm.onPageChange({ currentPage: 2 });
expect(Vue.prototype.$http.get).toBeCalledWith(
'/admin/player-data',
{ page: 2, perPage: 10, search: 'abc', sortField: 'pid', sortType: 'asc' }
);
wrapper.vm.onPerPageChange({ currentPerPage: 5 });
expect(Vue.prototype.$http.get).toBeCalledWith(
'/admin/player-data',
{ page: 2, perPage: 5, search: 'abc', sortField: 'pid', sortType: 'asc' }
);
wrapper.vm.onSortChange({ sortType: 'desc', columnIndex: 0 });
expect(Vue.prototype.$http.get).toBeCalledWith(
'/admin/player-data',
{ page: 2, perPage: 5, search: 'abc', sortField: 'pid', sortType: 'desc' }
);
});
test('change texture', async () => {

View File

@ -14,7 +14,41 @@ jest.mock('@/js/i18n', () => ({
test('fetch data after initializing', () => {
Vue.prototype.$http.get.mockResolvedValue({ data: [] });
mount(Users);
expect(Vue.prototype.$http.get).toBeCalledWith('/admin/user-data');
expect(Vue.prototype.$http.get).toBeCalledWith(
'/admin/user-data',
{ page: 1, perPage: 10, search: '', sortField: 'uid', sortType: 'asc' }
);
});
test('update tables', () => {
Vue.prototype.$http.get.mockResolvedValue({
data: Array.from({ length: 20 }).map((item, uid) => ({ uid }))
});
const wrapper = mount(Users);
wrapper.find('.vgt-input').setValue('abc');
expect(Vue.prototype.$http.get).toBeCalledWith(
'/admin/user-data',
{ page: 1, perPage: 10, search: 'abc', sortField: 'uid', sortType: 'asc' }
);
wrapper.vm.onPageChange({ currentPage: 2 });
expect(Vue.prototype.$http.get).toBeCalledWith(
'/admin/user-data',
{ page: 2, perPage: 10, search: 'abc', sortField: 'uid', sortType: 'asc' }
);
wrapper.vm.onPerPageChange({ currentPerPage: 5 });
expect(Vue.prototype.$http.get).toBeCalledWith(
'/admin/user-data',
{ page: 2, perPage: 5, search: 'abc', sortField: 'uid', sortType: 'asc' }
);
wrapper.vm.onSortChange({ sortType: 'desc', columnIndex: 0 });
expect(Vue.prototype.$http.get).toBeCalledWith(
'/admin/user-data',
{ page: 2, perPage: 5, search: 'abc', sortField: 'uid', sortType: 'desc' }
);
});
test('humanize permission', async () => {

View File

@ -105,10 +105,10 @@ Route::group(['middleware' => ['auth', 'admin'], 'prefix' => 'admin'], function
Route::any('/options', 'AdminController@options');
Route::view('/users', 'admin.users');
Route::get ('/user-data', 'AdminController@getUserData');
Route::any ('/user-data', 'AdminController@getUserData');
Route::view('/players', 'admin.players');
Route::get ('/player-data', 'AdminController@getPlayerData');
Route::any ('/player-data', 'AdminController@getPlayerData');
Route::get ('/user/{uid}', 'AdminController@getOneUser');
// ajax handlers

View File

@ -153,7 +153,7 @@ class AdminControllerTest extends BrowserKitTestCase
public function testGetUserData()
{
$this->visit('/admin/user-data')
$this->getJson('/admin/user-data')
->seeJsonStructure([
'data' => [[
'uid',
@ -168,7 +168,7 @@ class AdminControllerTest extends BrowserKitTestCase
]);
$user = factory(User::class)->create();
$this->visit('/admin/user-data?uid='.$user->uid)
$this->getJson('/admin/user-data?uid='.$user->uid)
->seeJsonSubset([
'data' => [[
'uid' => $user->uid,
@ -191,7 +191,7 @@ class AdminControllerTest extends BrowserKitTestCase
$player = factory(Player::class)->create();
$user = $player->user;
$this->visit('/admin/player-data')
$this->getJson('/admin/player-data')
->seeJsonStructure([
'data' => [[
'pid',
@ -205,7 +205,7 @@ class AdminControllerTest extends BrowserKitTestCase
]]
]);
$this->visit('/admin/player-data?uid='.$user->uid)
$this->getJson('/admin/player-data?uid='.$user->uid)
->seeJsonSubset([
'data' => [[
'pid' => $player->pid,