This commit is contained in:
polv committed 2021-10-24 23:49:09 +07:00
1 parent 70066f3086
commit 0348f84255
4 files changed
+258 -34

No files matched your search

+45 -18
View File
@@ -1,6 +1,20 @@
import _axios, { AxiosInstance } from 'axios' import _axios, { AxiosInstance } from 'axios'
export type IType = 'character' | 'vocabulary' | 'sentence' export type ITypeLevel = 'character' | 'vocabulary'
export type IType = ITypeLevel | 'sentence'
export interface ILevelBrowserByType {
whatToShow: string[]
}
export type ILevelBrowser = Record<ITypeLevel, ILevelBrowserByType>
export interface IUserSettings {
identifier: string
level: number
levelMin?: number
level_browser?: ILevelBrowser
}
export interface IEntry { export interface IEntry {
id: string id: string
@@ -41,18 +55,19 @@ class Api {
} }
setApiKey() setApiKey()
const r = await this.user_getSettings()
if (r) return r return await this.isAuthorized().then((r) => {
if (!r) {
apiKey = '' apiKey = ''
setApiKey() setApiKey()
}
return null return r
})
} }
async isAuthorized(): Promise<boolean> { async isAuthorized(): Promise<boolean> {
if (this._isAuthorized && !this._user) { if (this._isAuthorized && !this._user) {
const r = await this.user_getSettings() const r = await this.user_getSettings({ select: ['identifier'] })
if (r) { if (r) {
this._user = r.identifier this._user = r.identifier
this._isAuthorized = true this._isAuthorized = true
@@ -62,21 +77,15 @@ class Api {
return this._isAuthorized return this._isAuthorized
} }
async user_getSettings() { async user_getSettings(params: { select: (keyof IUserSettings)[] }) {
const r = await this.axios const r = await this.axios
.get('/api/user', { .get('/api/user', {
params: { params: {
select: 'level,levelMin,identifier', ...params,
select: params.select.join(','),
}, },
}) })
.then( .then((r) => r.data as IUserSettings)
(r) =>
r.data as {
level: number
levelMin?: number
identifier: string
}
)
.then((r) => ({ .then((r) => ({
...r, ...r,
levelMin: r.levelMin || 1, levelMin: r.levelMin || 1,
@@ -84,13 +93,16 @@ class Api {
.catch(() => null) .catch(() => null)
if (!r) { if (!r) {
return return null
} }
return r return r
} }
async user_updateSettings(u: { levelMin: number }) { async user_updateSettings(u: {
levelMin?: number
level_browser?: ILevelBrowser
}) {
return await this.axios.patch('/api/user', u) return await this.axios.patch('/api/user', u)
} }
@@ -258,6 +270,21 @@ class Api {
} }
) )
} }
async library_getLevelList(payload: {
type: ITypeLevel
settings: ILevelBrowserByType
}) {
return await this.axios.post('/api/library/getLevelList', payload).then(
(r) =>
r.data as {
result: {
entry: string
level: number
}[]
}
)
}
} }
export const api = new Api() export const api = new Api()
+146
View File
@@ -0,0 +1,146 @@
<template>
<section>
<div class="LevelPage container">
<div class="field">
<label class="label">Filter</label>
<b-field>
<b-radio-button
v-model="whatToShow"
native-value="all"
type="is-success"
>
Show all
</b-radio-button>
<b-radio-button
v-model="whatToShow"
native-value="learning"
type="is-warning"
>
Learning
</b-radio-button>
<b-radio-button
v-model="whatToShow"
native-value="all-quiz"
type="is-info"
>
All quiz
</b-radio-button>
</b-field>
</div>
<section class="card">
<div class="card-content">
<LibraryCard
v-for="{ level, entries } in sublist"
:key="level"
:title="`Level ${level}`"
:entries="entries.map((entry) => ({ entry }))"
:type="type"
:open="true"
/>
<b-pagination
class="mt-4"
v-if="list.length > perPage"
v-model="page"
:total="list.length"
:per-page="perPage"
icon-prev="angle-left"
icon-next="angle-right"
@change="(p) => (page = p)"
/>
</div>
</section>
</div>
</section>
</template>
<script lang="ts">
import { Component, Prop, Vue, Watch } from 'vue-property-decorator'
import { api, ILevelBrowser, ITypeLevel } from '~/assets/api'
@Component<LevelCard>({
created() {
this.init()
},
})
export default class LevelCard extends Vue {
@Prop() type!: ITypeLevel
isLoading = true
list: {
level: number
entries: string[]
}[] = []
settings: ILevelBrowser = {
character: {
whatToShow: ['all'],
},
vocabulary: {
whatToShow: ['all'],
},
}
page = 1
perPage = 5
get sublist() {
return this.list.slice(
(this.page - 1) * this.perPage,
this.page * this.perPage
)
}
async init() {
const r = await api.user_getSettings({
select: ['level_browser'],
})
if (r?.level_browser) {
this.settings = r.level_browser
}
await this.setCurrentData()
this.isLoading = false
}
async setCurrentData() {
const { result } = await api.library_getLevelList({
type: this.type,
settings: this.settings[this.type],
})
const allData = new Map<number, string[]>()
result.map(({ entry, level }) => {
const levelData = allData.get(level) || []
levelData.push(entry)
allData.set(level, levelData)
})
this.list = Array.from(allData)
.sort(([lv1], [lv2]) => lv1 - lv2)
.map(([level, entries]) => ({ level, entries }))
}
@Watch('settings')
async onSettingsChanged() {
this.page = 1
this.setCurrentData()
await api.user_updateSettings({
level_browser: this.settings,
})
}
}
</script>
<style scoped>
.tag {
margin-right: 0.5rem;
}
.b-table {
margin-bottom: 2rem;
}
</style>
+25
View File
@@ -0,0 +1,25 @@
<template>
<b-tabs :value="1">
<b-tab-item label="Character">
<level-card type="character" />
</b-tab-item>
<b-tab-item label="Vocabulary">
<level-card type="vocabulary" />
</b-tab-item>
</b-tabs>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import LevelCard from '../cards/LevelCard.vue'
@Component<LevelTab>({
components: {
LevelCard,
},
created() {
this.$emit('title', 'Level')
},
})
export default class LevelTab extends Vue {}
</script>
+42 -16
View File
@@ -1,11 +1,19 @@
import { actionTree, getAccessorType, mutationTree } from 'typed-vuex' import { actionTree, getAccessorType, mutationTree } from 'typed-vuex'
import { api } from '~/assets/api' import { api } from '~/assets/api'
import { jsonClone } from '~/assets/util'
const TAB_SETTINGS = 'TABS_SETTINGS'
interface ISettings { interface ISettings {
level: number | null level: number | null
levelMin: number | null levelMin: number | null
sentenceMin: number | null }
sentenceMax: number | null
interface ITab {
title: string
component: string
permanent?: boolean
query: Record<string, string>
} }
export const state = () => ({ export const state = () => ({
@@ -16,12 +24,7 @@ export const state = () => ({
sentenceMax: null, sentenceMax: null,
} as ISettings, } as ISettings,
isApp: false, isApp: false,
tabs: [] as { tabs: [] as ITab[],
title: string
component: string
permanent?: boolean
query: Record<string, string>
}[],
activeTab: 0, activeTab: 0,
identifier: '', identifier: '',
}) })
@@ -33,9 +36,26 @@ export const mutations = mutationTree(state, {
SET_IS_APP(state, isApp: boolean) { SET_IS_APP(state, isApp: boolean) {
state.isApp = isApp state.isApp = isApp
}, },
SET_ALL_TABS(
state,
o: {
tabs: ITab[]
activeTab: number
} = state
) {
localStorage.setItem(
TAB_SETTINGS,
JSON.stringify({
tabs: o.tabs,
activeTabs: o.activeTab,
})
)
state.tabs = jsonClone(o.tabs)
state.activeTab = jsonClone(o.activeTab)
},
SET_TAB_TITLE(state, { i, title }: { i: number; title: string }) { SET_TAB_TITLE(state, { i, title }: { i: number; title: string }) {
state.tabs[i].title = title state.tabs[i].title = title
state.tabs = JSON.parse(JSON.stringify(state.tabs)) this.SET_ALL_TABS(state)
}, },
ADD_TAB( ADD_TAB(
state, state,
@@ -70,6 +90,7 @@ export const mutations = mutationTree(state, {
} }
state.activeTab = state.tabs.length - 1 state.activeTab = state.tabs.length - 1
this.SET_ALL_TABS(state)
}, },
DELETE_TAB(state, { i }: { i: number }) { DELETE_TAB(state, { i }: { i: number }) {
state.tabs.splice(i, 1) state.tabs.splice(i, 1)
@@ -78,16 +99,15 @@ export const mutations = mutationTree(state, {
state.activeTab = state.tabs.length - 1 state.activeTab = state.tabs.length - 1
} }
state.tabs = JSON.parse(JSON.stringify(state.tabs)) this.SET_ALL_TABS(state)
}, },
SET_TAB_COMPONENT(state, { i, component }: { i: number; component: string }) { SET_TAB_COMPONENT(state, { i, component }: { i: number; component: string }) {
state.tabs[i].component = component state.tabs[i].component = component
this.SET_ALL_TABS(state)
state.tabs = JSON.parse(JSON.stringify(state.tabs))
state.activeTab = i
}, },
SET_TAB_CURRENT(state, { i }: { i: number }) { SET_TAB_CURRENT(state, { i }: { i: number }) {
state.activeTab = i state.activeTab = i
this.SET_ALL_TABS(state)
}, },
SET_IDENTIFIER(state, name: string) { SET_IDENTIFIER(state, name: string) {
state.identifier = name state.identifier = name
@@ -97,8 +117,16 @@ export const mutations = mutationTree(state, {
export const actions = actionTree( export const actions = actionTree(
{ state, mutations }, { state, mutations },
{ {
async nuxtServerInit({ dispatch, commit }) {
await dispatch('updateSetings')
const settings = localStorage.getItem(TAB_SETTINGS)
if (settings) commit('SET_ALL_TABS', JSON.parse(settings))
},
async updateSettings({ commit }) { async updateSettings({ commit }) {
const r = await api.user_getSettings() const r = await api.user_getSettings({
select: ['identifier', 'levelMin', 'level'],
})
commit('SET_IS_APP', !!r) commit('SET_IS_APP', !!r)
commit('SET_IDENTIFIER', r?.identifier || '') commit('SET_IDENTIFIER', r?.identifier || '')
@@ -115,8 +143,6 @@ export const actions = actionTree(
commit('SET_SETTINGS', { commit('SET_SETTINGS', {
level: r?.level || null, level: r?.level || null,
levelMin: r?.levelMin || null, levelMin: r?.levelMin || null,
sentenceMin: null,
sentenceMax: null,
}) })
}, },
} }