Rework skin library filter

This commit is contained in:
Pig Fang 2019-03-26 17:42:27 +08:00
parent 0876d41421
commit a1e38eec1f
7 changed files with 123 additions and 134 deletions

View File

@ -1,4 +1,6 @@
@import '~element-theme-chalk/src/button.scss'; @import '~element-theme-chalk/src/button.scss';
@import '~element-theme-chalk/src/button-group.scss';
@import '~element-theme-chalk/src/input.scss';
@import '~element-theme-chalk/src/message.scss'; @import '~element-theme-chalk/src/message.scss';
@import '~element-theme-chalk/src/message-box.scss'; @import '~element-theme-chalk/src/message-box.scss';
@import '~element-theme-chalk/src/progress.scss'; @import '~element-theme-chalk/src/progress.scss';

View File

@ -1,9 +1,13 @@
import Vue from 'vue' import Vue from 'vue'
import Button from 'element-ui/lib/button' import Button from 'element-ui/lib/button'
import ButtonGroup from 'element-ui/lib/button-group'
import Input from 'element-ui/lib/input'
import Message from 'element-ui/lib/message' import Message from 'element-ui/lib/message'
import MessageBox from 'element-ui/lib/message-box' import MessageBox from 'element-ui/lib/message-box'
Vue.use(Button) Vue.use(Button)
Vue.use(ButtonGroup)
Vue.use(Input)
Vue.prototype.$message = Message Vue.prototype.$message = Message
Vue.prototype.$msgbox = MessageBox Vue.prototype.$msgbox = MessageBox

View File

@ -23,84 +23,39 @@
<div class="box box-default"> <div class="box box-default">
<div class="box-header"> <div class="box-header">
<div class="form-group row"> <div class="form-group row">
<div class="col-md-4"> <form class="col-md-6" @submit.prevent="fetchData">
<label> <el-input
<input v-model="keyword"
v-model="filter" :placeholder="$t('vendor.datatable.search')"
type="radio" clearable
name="filter" >
value="skin" <el-select slot="prepend" v-model="filter" class="texture-type-select">
> <el-option :label="$t('general.skin')" value="skin" />
{{ $t('skinlib.anyModels') }} <el-option label="Steve" value="steve" />
</label>&nbsp; <el-option label="Alex" value="alex" />
<label> <el-option :label="$t('general.cape')" value="cape" />
<input </el-select>
v-model="filter" <el-button slot="append" data-test="btn-search" @click="fetchData">
type="radio" {{ $t('general.submit') }}
name="filter" </el-button>
value="steve" </el-input>
>
Steve
</label>&nbsp;
<label>
<input
v-model="filter"
type="radio"
name="filter"
value="alex"
>
Alex
</label>&nbsp;
<label>
<input
v-model="filter"
type="radio"
name="filter"
value="cape"
>
{{ $t('general.cape') }}
</label>
</div>
<form class="col-md-4" @submit.prevent="fetchData">
<div class="input-group">
<input
v-model="keyword"
type="text"
:placeholder="$t('vendor.datatable.search')"
class="form-control"
>
<span class="input-group-btn">
<button class="btn btn-success" @click="fetchData">
{{ $t('general.submit') }}
</button>
</span>
</div>
</form> </form>
<div class="col-md-4"> <div class="col-md-6 advanced-filter">
<div class="btn-group filter-btn"> <el-button-group class="pull-right">
<button <el-button plain @click="sort = 'likes'">
class="btn btn-primary dropdown-toggle" {{ $t('skinlib.sort.likes') }}
data-toggle="dropdown" </el-button>
aria-haspopup="true" <el-button plain @click="sort = 'time'">
aria-expanded="false" {{ $t('skinlib.sort.time') }}
> </el-button>
{{ $t('skinlib.sort.title') }} <span class="caret" /> <el-button plain @click="uploader = currentUid">
</button> {{ $t('skinlib.seeMyUpload') }}
<ul class="dropdown-menu"> </el-button>
<li><a v-t="'skinlib.sort.likes'" href="#" @click="sort = 'likes'" /></li> <el-button type="info" plain @click="reset">
<li><a v-t="'skinlib.sort.time'" href="#" @click="sort = 'time'" /></li> {{ $t('skinlib.reset') }}
</ul> </el-button>
</div> </el-button-group>
<a
v-if="currentUid"
class="btn btn-default btn-tail"
@click="uploader = currentUid"
>{{ $t('skinlib.seeMyUpload') }}</a>
<button class="btn btn-warning btn-tail" @click="reset">
{{ $t('skinlib.reset') }}
</button>
</div> </div>
</div> </div>
</div> </div>
@ -154,10 +109,17 @@
</template> </template>
<script> <script>
import Vue from 'vue'
import Paginate from 'vuejs-paginate' import Paginate from 'vuejs-paginate'
import 'element-ui/lib/theme-chalk/select.css'
import Select from 'element-ui/lib/select'
import Option from 'element-ui/lib/option'
import { queryString } from '../../js/utils' import { queryString } from '../../js/utils'
import SkinLibItem from '../../components/SkinLibItem.vue' import SkinLibItem from '../../components/SkinLibItem.vue'
Vue.use(Select)
Vue.use(Option)
export default { export default {
name: 'SkinLibrary', name: 'SkinLibrary',
components: { components: {
@ -191,8 +153,7 @@ export default {
}, },
}, },
watch: { watch: {
filter(value) { filter() {
$(`[value="${value}"]`).iCheck('check')
this.fetchData() this.fetchData()
}, },
uploader() { uploader() {
@ -202,17 +163,6 @@ export default {
this.fetchData() this.fetchData()
}, },
}, },
created() {
let available = true
const origin = this.fetchData
this.fetchData = () => {
if (available) {
available = false
setTimeout(() => (available = true), 50)
origin()
}
}
},
beforeMount() { beforeMount() {
this.fetchData() this.fetchData()
}, },
@ -265,9 +215,12 @@ export default {
color #000 color #000
font-size 20px font-size 20px
@media (min-width: 768px) .texture-type-select
.filter-btn width 90px
margin-left 25px
.advanced-filter
@media (max-width 850px)
display none
.btn-tail .btn-tail
margin-left 6px margin-left 6px

View File

@ -1,7 +1,10 @@
/* eslint-disable import/no-extraneous-dependencies */ /* eslint-disable import/no-extraneous-dependencies */
import 'jest-extended' import 'jest-extended'
import Vue from 'vue' import Vue from 'vue'
import { Button } from 'element-ui' import {
Button,
Input,
} from 'element-ui'
window.blessing = { window.blessing = {
base_url: '', base_url: '',
@ -37,6 +40,7 @@ Vue.prototype.$http = {
} }
Vue.use(Button) Vue.use(Button)
Vue.use(Input)
Vue.prototype.$message = { Vue.prototype.$message = {
info: jest.fn(), info: jest.fn(),
success: jest.fn(), success: jest.fn(),

View File

@ -1,7 +1,48 @@
import Vue from 'vue' import Vue from 'vue'
import { mount } from '@vue/test-utils' import { mount } from '@vue/test-utils'
import { Button } from 'element-ui'
import List from '@/views/skinlib/List.vue' import List from '@/views/skinlib/List.vue'
jest.mock('element-ui/lib/select', () => ({
install(vue: typeof Vue) {
vue.component('ElSelect', {
render(h) {
return h('select', {
on: {
change: (event: Event) => this.$emit(
'change',
(event.target as HTMLSelectElement).value
),
},
attrs: {
value: this.value,
},
}, this.$slots.default)
},
props: {
value: String,
},
model: {
prop: 'value',
event: 'change',
},
})
},
}))
jest.mock('element-ui/lib/option', () => ({
install(vue: typeof Vue) {
vue.component('ElOption', {
render(h) {
return h('option', { attrs: { value: this.value } }, this.label)
},
props: {
label: String,
value: String,
},
})
},
}))
test('fetch data before mounting', () => { test('fetch data before mounting', () => {
Vue.prototype.$http.get.mockResolvedValue({ Vue.prototype.$http.get.mockResolvedValue({
items: [], total_pages: 0, current_uid: 0, items: [], total_pages: 0, current_uid: 0,
@ -27,17 +68,13 @@ test('toggle texture type', () => {
Vue.prototype.$http.get.mockResolvedValue({ Vue.prototype.$http.get.mockResolvedValue({
items: [], total_pages: 0, current_uid: 0, items: [], total_pages: 0, current_uid: 0,
}) })
window.$ = jest.fn(() => ({
iCheck() {},
}))
const wrapper = mount(List) const wrapper = mount(List)
const select = wrapper.find({ name: 'ElSelect' })
const breadcrumb = wrapper.find('.breadcrumb') const breadcrumb = wrapper.find('.breadcrumb')
jest.runAllTimers()
expect(breadcrumb.text()).toContain('skinlib.filter.skin') expect(breadcrumb.text()).toContain('skinlib.filter.skin')
wrapper.find('[value=steve]').setChecked() select.setValue('steve')
jest.runAllTimers() select.trigger('change')
expect(breadcrumb.text()).toContain('skinlib.filter.steve') expect(breadcrumb.text()).toContain('skinlib.filter.steve')
expect(Vue.prototype.$http.get).toBeCalledWith( expect(Vue.prototype.$http.get).toBeCalledWith(
'/skinlib/data', '/skinlib/data',
@ -45,8 +82,8 @@ test('toggle texture type', () => {
filter: 'steve', uploader: 0, sort: 'time', keyword: '', page: 1, filter: 'steve', uploader: 0, sort: 'time', keyword: '', page: 1,
} }
) )
wrapper.find('[value=alex]').setChecked() select.setValue('alex')
jest.runAllTimers() select.trigger('change')
expect(breadcrumb.text()).toContain('skinlib.filter.alex') expect(breadcrumb.text()).toContain('skinlib.filter.alex')
expect(Vue.prototype.$http.get).toBeCalledWith( expect(Vue.prototype.$http.get).toBeCalledWith(
'/skinlib/data', '/skinlib/data',
@ -54,8 +91,8 @@ test('toggle texture type', () => {
filter: 'alex', uploader: 0, sort: 'time', keyword: '', page: 1, filter: 'alex', uploader: 0, sort: 'time', keyword: '', page: 1,
} }
) )
wrapper.find('[value=cape]').setChecked() select.setValue('cape')
jest.runAllTimers() select.trigger('change')
expect(breadcrumb.text()).toContain('general.cape') expect(breadcrumb.text()).toContain('general.cape')
expect(Vue.prototype.$http.get).toBeCalledWith( expect(Vue.prototype.$http.get).toBeCalledWith(
'/skinlib/data', '/skinlib/data',
@ -72,9 +109,10 @@ test('check specified uploader', async () => {
const wrapper = mount(List) const wrapper = mount(List)
await wrapper.vm.$nextTick() await wrapper.vm.$nextTick()
const breadcrumb = wrapper.find('.breadcrumb') const breadcrumb = wrapper.find('.breadcrumb')
const button = wrapper.find('.btn-default') const button = wrapper
.find('.advanced-filter')
jest.runAllTimers() .findAll(Button)
.at(2)
expect(breadcrumb.text()).toContain('skinlib.filter.allUsers') expect(breadcrumb.text()).toContain('skinlib.filter.allUsers')
button.trigger('click') button.trigger('click')
@ -92,9 +130,9 @@ test('sort items', () => {
items: [], total_pages: 0, current_uid: 0, items: [], total_pages: 0, current_uid: 0,
}) })
const wrapper = mount(List) const wrapper = mount(List)
const sortByLikes = wrapper.find('.dropdown-menu > li:nth-child(1) > a') const buttons = wrapper.find('.advanced-filter').findAll(Button)
const sortByTime = wrapper.find('.dropdown-menu > li:nth-child(2) > a') const sortByLikes = buttons.at(0)
jest.runAllTimers() const sortByTime = buttons.at(1)
sortByLikes.trigger('click') sortByLikes.trigger('click')
expect(Vue.prototype.$http.get).toBeCalledWith( expect(Vue.prototype.$http.get).toBeCalledWith(
@ -104,7 +142,6 @@ test('sort items', () => {
} }
) )
expect(wrapper.text()).toContain('skinlib.sort.likes') expect(wrapper.text()).toContain('skinlib.sort.likes')
jest.runAllTimers()
sortByTime.trigger('click') sortByTime.trigger('click')
expect(Vue.prototype.$http.get).toBeCalledWith( expect(Vue.prototype.$http.get).toBeCalledWith(
@ -121,10 +158,8 @@ test('search by keyword', () => {
items: [], total_pages: 0, current_uid: 0, items: [], total_pages: 0, current_uid: 0,
}) })
const wrapper = mount(List) const wrapper = mount(List)
const searchBox = wrapper.find('input[type=text]')
jest.runAllTimers()
searchBox.setValue('a') wrapper.setData({ keyword: 'a' })
wrapper.find('form').trigger('submit') wrapper.find('form').trigger('submit')
expect(Vue.prototype.$http.get).toBeCalledWith( expect(Vue.prototype.$http.get).toBeCalledWith(
'/skinlib/data', '/skinlib/data',
@ -132,10 +167,9 @@ test('search by keyword', () => {
filter: 'skin', uploader: 0, sort: 'time', keyword: 'a', page: 1, filter: 'skin', uploader: 0, sort: 'time', keyword: 'a', page: 1,
} }
) )
jest.runAllTimers()
searchBox.setValue('b') wrapper.setData({ keyword: 'b' })
wrapper.find('.input-group-btn > button').trigger('click') wrapper.find('[data-test="btn-search"]').trigger('click')
expect(Vue.prototype.$http.get).toBeCalledWith( expect(Vue.prototype.$http.get).toBeCalledWith(
'/skinlib/data', '/skinlib/data',
{ {
@ -145,23 +179,18 @@ test('search by keyword', () => {
}) })
test('reset all filters', () => { test('reset all filters', () => {
window.$ = jest.fn(() => ({
iCheck() {},
}))
Vue.prototype.$http.get.mockResolvedValue({ Vue.prototype.$http.get.mockResolvedValue({
items: [], total_pages: 0, current_uid: 0, items: [], total_pages: 0, current_uid: 0,
}) })
const wrapper = mount(List) const wrapper = mount(List)
jest.runAllTimers() wrapper.findAll('option').at(3)
wrapper.find('input[value=cape]').setChecked() .setSelected()
jest.runAllTimers() wrapper.setData({ keyword: 'abc' })
wrapper.find('input[type=text]').setValue('abc') const buttons = wrapper.find('.advanced-filter').findAll(Button)
jest.runAllTimers() buttons.at(1).trigger('click')
wrapper.find('.dropdown-menu > li:nth-child(1) > a').trigger('click')
jest.runAllTimers()
Vue.prototype.$http.get.mockClear() Vue.prototype.$http.get.mockClear()
wrapper.find('.btn-warning').trigger('click') buttons.at(3).trigger('click')
expect(Vue.prototype.$http.get).toBeCalledTimes(1) expect(Vue.prototype.$http.get).toBeCalledTimes(1)
}) })
@ -178,7 +207,6 @@ test('on page changed', () => {
items: [], total_pages: 0, current_uid: 0, items: [], total_pages: 0, current_uid: 0,
}) })
const wrapper = mount<Vue & { pageChanged(page: number): void }>(List) const wrapper = mount<Vue & { pageChanged(page: number): void }>(List)
jest.runAllTimers()
wrapper.vm.pageChanged(2) wrapper.vm.pageChanged(2)
expect(Vue.prototype.$http.get).toBeCalledWith( expect(Vue.prototype.$http.get).toBeCalledWith(
'/skinlib/data', '/skinlib/data',

View File

@ -47,8 +47,7 @@ skinlib:
emptyItemName: Empty texture name. emptyItemName: Empty texture name.
setNewTextureName: 'Please enter the new texture name:' setNewTextureName: 'Please enter the new texture name:'
emptyNewTextureName: Empty new texture name. emptyNewTextureName: Empty new texture name.
anyModels: Any Models seeMyUpload: My Uploads
seeMyUpload: Check My Upload
apply: Quick Apply apply: Quick Apply
filter: filter:
skin: (Any Model) skin: (Any Model)
@ -59,7 +58,7 @@ skinlib:
allUsers: All Users allUsers: All Users
sort: sort:
title: Sort title: Sort
time: Newestly Uploaded time: Latest
likes: Most Likes likes: Most Likes
badSkinSize: The size of selected skin file is not valid badSkinSize: The size of selected skin file is not valid
badCapeSize: The size of selected cape file is not valid badCapeSize: The size of selected cape file is not valid

View File

@ -47,8 +47,7 @@ skinlib:
emptyItemName: 你还没有填写要收藏的材质名称啊 emptyItemName: 你还没有填写要收藏的材质名称啊
anonymous: 请先登录 anonymous: 请先登录
private: 私密 private: 私密
anyModels: 任意模型 seeMyUpload: 我上传的
seeMyUpload: 查看我上传的
apply: 立即使用 apply: 立即使用
filter: filter:
skin: (任意模型) skin: (任意模型)