update
This commit is contained in:
1 parent
70066f3086
commit
0348f84255
4 files changed
+260
-36
No files matched your search
+47
-20
@@ -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) => {
|
||||||
apiKey = ''
|
if (!r) {
|
||||||
setApiKey()
|
apiKey = ''
|
||||||
|
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()
|
||||||
@@ -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>
|
||||||
@@ -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
@@ -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,
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user