mirror of
https://github.com/CzBiX/qb-web.git
synced 2026-04-13 18:01:17 +08:00
270 lines
5.6 KiB
Vue
270 lines
5.6 KiB
Vue
<template>
|
|
<v-app ref="app">
|
|
<v-navigation-drawer
|
|
app
|
|
:clipped="$vuetify.breakpoint.lgAndUp"
|
|
v-model="drawer"
|
|
v-class:phone-layout="phoneLayout"
|
|
width="300"
|
|
>
|
|
<drawer v-model="drawerOptions" />
|
|
<template v-if="phoneLayout">
|
|
<v-spacer />
|
|
<v-divider />
|
|
<v-expansion-panels
|
|
class="drawer-footer"
|
|
>
|
|
<v-expansion-panel
|
|
lazy
|
|
@input="drawerFooterOpen"
|
|
>
|
|
<v-expansion-panel-header>
|
|
<div class="d-flex align-center">
|
|
<v-icon class="footer-icon shrink">
|
|
mdi-information-outline
|
|
</v-icon>
|
|
<span class="footer-title">
|
|
Status info
|
|
</span>
|
|
</div>
|
|
</v-expansion-panel-header>
|
|
<v-expansion-panel-content>
|
|
<app-footer phone-layout />
|
|
</v-expansion-panel-content>
|
|
</v-expansion-panel>
|
|
<div ref="end" />
|
|
</v-expansion-panels>
|
|
</template>
|
|
</v-navigation-drawer>
|
|
<main-toolbar v-model="drawer" />
|
|
|
|
<v-content>
|
|
<torrents />
|
|
</v-content>
|
|
|
|
<add-form v-if="preferences" />
|
|
<login-form
|
|
v-if="needAuth"
|
|
v-model="needAuth"
|
|
/>
|
|
<logs-dialog
|
|
v-if="drawerOptions.showLogs"
|
|
v-model="drawerOptions.showLogs"
|
|
/>
|
|
<RssDialog
|
|
v-if="drawerOptions.showRss"
|
|
v-model="drawerOptions.showRss"
|
|
@download-torrent="setPasteUrl({url: $event})"
|
|
/>
|
|
|
|
<v-footer
|
|
app
|
|
class="elevation-4"
|
|
padless
|
|
v-if="$vuetify.breakpoint.smAndUp"
|
|
>
|
|
<app-footer />
|
|
</v-footer>
|
|
|
|
<GlobalDialog />
|
|
<GlobalSnackBar />
|
|
</v-app>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import Vue from 'vue';
|
|
import { mapGetters, mapState, mapMutations } from 'vuex';
|
|
import { registerProtocolHandler, checkDownloadUrl } from './protocolHandler';
|
|
|
|
import GlobalDialog from './components/GlobalDialog.vue';
|
|
import GlobalSnackBar from './components/GlobalSnackBar.vue';
|
|
|
|
import AddForm from './components/AddForm.vue';
|
|
import Drawer from './components/Drawer.vue';
|
|
import LoginForm from './components/LoginForm.vue';
|
|
import MainToolbar from './components/MainToolbar.vue';
|
|
import Torrents from './components/Torrents.vue';
|
|
import AppFooter from './components/Footer.vue';
|
|
import LogsDialog from './components/dialogs/LogsDialog.vue';
|
|
import RssDialog from './components/dialogs/RssDialog.vue';
|
|
|
|
import api from './Api';
|
|
import { timeout } from './utils';
|
|
import Component from 'vue-class-component';
|
|
import { Watch } from 'vue-property-decorator';
|
|
import { MainData } from './types';
|
|
|
|
let appWrapEl: HTMLElement;
|
|
|
|
@Component({
|
|
components: {
|
|
AddForm,
|
|
Drawer,
|
|
LoginForm,
|
|
Torrents,
|
|
AppFooter,
|
|
LogsDialog,
|
|
MainToolbar,
|
|
GlobalDialog,
|
|
GlobalSnackBar,
|
|
RssDialog,
|
|
},
|
|
computed: {
|
|
...mapState([
|
|
'mainData',
|
|
'rid',
|
|
'preferences',
|
|
]),
|
|
...mapGetters(['config']),
|
|
},
|
|
methods: {
|
|
...mapMutations([
|
|
'updateMainData',
|
|
'updatePreferences',
|
|
'setPasteUrl',
|
|
]),
|
|
}
|
|
})
|
|
export default class App extends Vue {
|
|
needAuth = false
|
|
drawer = true
|
|
drawerOptions = {
|
|
showLogs: false,
|
|
showRss: false,
|
|
}
|
|
task = 0
|
|
|
|
mainData!: MainData
|
|
rid!: number
|
|
preferences!: any
|
|
config!: any
|
|
|
|
updateMainData!: (_: any) => void
|
|
updatePreferences!: (_: any) => void
|
|
setPasteUrl!: (_: any) => void
|
|
|
|
get phoneLayout() {
|
|
return this.$vuetify.breakpoint.xsOnly;
|
|
}
|
|
|
|
initProtocolHandler() {
|
|
registerProtocolHandler();
|
|
const url = checkDownloadUrl();
|
|
|
|
if (url) {
|
|
this.setPasteUrl({
|
|
url,
|
|
});
|
|
}
|
|
}
|
|
|
|
async created() {
|
|
this.initProtocolHandler();
|
|
|
|
await this.getInitData();
|
|
appWrapEl = (this.$refs.app as any).$el.querySelector('.v-application--wrap');
|
|
appWrapEl.addEventListener('paste', this.onPaste);
|
|
}
|
|
|
|
beforeDestroy() {
|
|
if (this.task) {
|
|
clearTimeout(this.task);
|
|
}
|
|
appWrapEl.removeEventListener('paste', this.onPaste);
|
|
}
|
|
|
|
async getInitData() {
|
|
try {
|
|
await this.getMainData();
|
|
} catch (e) {
|
|
if (e.response.status === 403) {
|
|
this.needAuth = true;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
await this.getPreferences();
|
|
}
|
|
|
|
async getPreferences() {
|
|
const resp = await api.getAppPreferences();
|
|
|
|
this.updatePreferences(resp.data);
|
|
}
|
|
|
|
async getMainData() {
|
|
const rid = this.rid ? this.rid : undefined;
|
|
const resp = await api.getMainData(rid);
|
|
const mainData = resp.data;
|
|
|
|
this.updateMainData(mainData);
|
|
|
|
this.task = setTimeout(this.getMainData, this.config.updateInterval);
|
|
}
|
|
|
|
async drawerFooterOpen(v: boolean) {
|
|
if (!v) {
|
|
return;
|
|
}
|
|
|
|
await timeout(3000);
|
|
|
|
(this.$refs.end as HTMLElement).scrollIntoView({
|
|
behavior: 'smooth',
|
|
});
|
|
}
|
|
|
|
onPaste(e: ClipboardEvent) {
|
|
if ((e.target as HTMLElement).tagName === 'INPUT') {
|
|
return;
|
|
}
|
|
|
|
const text = e.clipboardData!.getData('text');
|
|
if (text) {
|
|
this.setPasteUrl({
|
|
url: text,
|
|
});
|
|
}
|
|
}
|
|
|
|
@Watch('needAuth')
|
|
onNeedAuth(v: boolean) {
|
|
if (!v) {
|
|
this.getInitData();
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.phone-layout ::v-deep .v-navigation-drawer__content {
|
|
display: flex;
|
|
flex-direction: column;
|
|
|
|
.drawer-footer .v-expansion-panel-header {
|
|
padding: 12px 16px 12px 16px;
|
|
|
|
.footer-icon {
|
|
font-size: 22px;
|
|
margin-left: 10px;
|
|
margin-right: 34px;
|
|
}
|
|
|
|
.footer-title {
|
|
font-size: 13px;
|
|
font-weight: 500;
|
|
}
|
|
}
|
|
}
|
|
|
|
.v-footer {
|
|
min-height: 36px;
|
|
}
|
|
</style>
|
|
|
|
<style lang="scss">
|
|
html {
|
|
overflow-y: hidden;
|
|
}
|
|
</style> |