增加全局设置页,增加百度云登录

pull/10/head
zanllp 2023-04-05 17:23:41 +08:00
parent e7cc311253
commit 7dabb90df1
10 changed files with 129 additions and 168 deletions

View File

@ -1,12 +1,6 @@
from fastapi import FastAPI
from scripts.api import baidu_netdisk_api, send_img_path, AutoUpload
from modules import script_callbacks, generation_parameters_copypaste as send, extras
from scripts.bin import (
bin_file_name,
get_matched_summary,
check_bin_exists,
download_bin_file,
)
from scripts.tool import cwd, debounce
from PIL import Image
from scripts.logger import logger
@ -16,28 +10,12 @@ from scripts.logger import logger
api函数声明和启动分离方便另外一边被外部调用
"""
not_exists_msg = (
f"找不到{bin_file_name},尝试手动从 {get_matched_summary()[1]} 或者 {get_matched_summary()[2]} 下载,下载后放到 {cwd} 文件夹下,重启界面"
)
def on_ui_tabs():
import gradio as gr
exists = check_bin_exists()
if not exists:
try:
print("缺少必要的二进制文件,开始下载")
download_bin_file()
print("done")
except Exception as e:
print("下载二进制文件时出错:", str(e))
exists = check_bin_exists()
if not exists:
print(f"\033[31m{not_exists_msg}\033[0m")
with gr.Blocks(analytics_enabled=False) as baidu_netdisk:
gr.Textbox(not_exists_msg, visible=not exists)
with gr.Row(visible=bool(exists)):
with gr.Row():
with gr.Column():
gr.HTML(
"如果你看到这个那说明此项那说明出现了问题", elem_id="baidu_netdisk_container_wrapper"

2
vue/components.d.ts vendored
View File

@ -18,6 +18,7 @@ declare module '@vue/runtime-core' {
AFormItem: typeof import('ant-design-vue/es')['FormItem']
AImage: typeof import('ant-design-vue/es')['Image']
AInput: typeof import('ant-design-vue/es')['Input']
AInputNumber: typeof import('ant-design-vue/es')['InputNumber']
AMenu: typeof import('ant-design-vue/es')['Menu']
AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
AModal: typeof import('ant-design-vue/es')['Modal']
@ -26,6 +27,7 @@ declare module '@vue/runtime-core' {
ASelect: typeof import('ant-design-vue/es')['Select']
ASkeleton: typeof import('ant-design-vue/es')['Skeleton']
AStatistic: typeof import('ant-design-vue/es')['Statistic']
ASwitch: typeof import('ant-design-vue/es')['Switch']
ATabPane: typeof import('ant-design-vue/es')['TabPane']
ATabs: typeof import('ant-design-vue/es')['Tabs']
ATag: typeof import('ant-design-vue/es')['Tag']

View File

@ -1,123 +1,32 @@
<!-- eslint-disable no-empty -->
<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue'
import { onMounted, reactive } from 'vue'
import { FetchQueue } from 'vue3-ts-util'
import { getUserInfo, type UserInfo, logout, loginByBduss } from './api/user'
import { message } from 'ant-design-vue'
import { isAxiosError } from 'axios'
import { getUserInfo } from './api/user'
import { getGlobalSetting } from './api'
import { useGlobalStore } from './store/useGlobalStore'
import { getAutoCompletedTagList } from './taskRecord/autoComplete'
import { useTaskListStore } from './store/useTaskListStore'
import { useIntervalFn } from '@vueuse/core'
import SplitViewTab from './SplitViewTab/SplitViewTab.vue'
const user = ref<UserInfo>()
const bduss = ref('')
const queue = reactive(new FetchQueue(-1, 0, 0, 'throw'))
const globalStore = useGlobalStore()
const taskStore = useTaskListStore()
const queue = reactive(new FetchQueue(-1, 0, 0, 'throw'))
onMounted(async () => {
getGlobalSetting().then(async (resp) => {
globalStore.conf = resp
const r = await getAutoCompletedTagList(resp)
globalStore.autoCompletedDirList = r.filter(v => v?.dir?.trim?.())
})
user.value = await queue.pushAction(getUserInfo).res
globalStore.user = await queue.pushAction(getUserInfo).res
})
const onLogoutBtnClick = async () => {
await queue.pushAction(logout).res
user.value = undefined
}
const onLoginBtnClick = async () => {
try {
user.value = await queue.pushAction(() => loginByBduss(bduss.value)).res
} catch (error) {
console.error(error)
message.error(isAxiosError(error) ? error.response?.data?.detail ?? '未知错误' : '未知错误')
}
}
const tips = ref('')
const msgs = [
'使用“快速移动”, 可以直接到到达图生图,文生图等文件夹',
"你可以通过拖拽调整两边区域的大小",
"使用ctrlshift可以很方便的进行多选",
"从百度云向本地拖拽是下载,本地向百度云拖拽是上传",
"可以多尝试更多里面的功能",
"鼠标在文件上右键可以打开上下文菜单",
"提醒任务完成后,你需要手动刷新下才能看到新文件"]
useIntervalFn(() => {
tips.value = msgs[~~(Math.random() * msgs.length)]
}, 3000)
</script>
<template>
<a-skeleton :loading="!queue.isIdle">
<!--div class="panel">
<template v-if="user">
<div>
已登录用户{{ user.username }}
</div>
<div class="flex-placeholder" /><a-alert :message="tips" type="info" show-icon />
<a-form layout="inline">
<a-form-item label="使用缩略图预览">
<a-switch v-model:checked="globalStore.enableThumbnail" />
</a-form-item>
<a-form-item>
<a-button @click="onLogoutBtnClick">
<template #icon>
<logout-outlined />
</template>
登出
</a-button>
</a-form-item>
</a-form>
</template>
<a-form layout="inline" v-else>
<a-form-item label="bduss">
<a-input v-model:value="bduss" style="width:300px"></a-input>
</a-form-item>
<a-form-item>
<a-button @click="onLoginBtnClick" type="primary">
<template #icon>
<login-outlined />
</template>
登录
</a-button>
</a-form-item>
</a-form>
</div-->
<split-view-tab />
</a-skeleton>
</template>
<style scoped lang="scss">
.panel {
padding: 8px;
margin: 16px;
border-radius: 8px;
background: var(--zp-primary-background);
display: flex;
justify-content: space-between;
&> :not(:first-child) {
margin-left: 16px;
}
}
.opreation-container {
display: flex;
flex-direction: column;
.split-view {
height: var(--scroll-container-max-height);
}
}
</style>

View File

@ -15,7 +15,8 @@ const compMap: Record<TabPane['type'], ReturnType<typeof defineAsyncComponent>>
netdisk: defineAsyncComponent(() => import('@/fileTransfer/stackView.vue')),
"task-record": defineAsyncComponent(() => import('@/taskRecord/taskRecord.vue')),
empty: defineAsyncComponent(() => import('./emptyStartup.vue')),
"log-detail": defineAsyncComponent(() => import('@/taskRecord/logDetail.vue'))
"log-detail": defineAsyncComponent(() => import('@/taskRecord/logDetail.vue')),
"global-setting": defineAsyncComponent(() => import('@/page/globalSetting.vue'))
}
const onEdit = (idx: number, targetKey: any, action: string) => {
const tab = global.tabList[idx]

View File

@ -12,7 +12,8 @@ const compCnMap: Partial<Record<TabPane['type'], string>> = {
"auto-upload": '自动上传',
local: '本地文件',
netdisk: '百度云',
"task-record": '任务记录'
"task-record": '任务记录',
'global-setting': '全局设置'
}
const openInCurrentTab = (type: TabPane['type'], path?: string, walkMode = false) => {
let pane: TabPane
@ -23,6 +24,7 @@ const openInCurrentTab = (type: TabPane['type'], path?: string, walkMode = false
case 'auto-upload':
case 'task-record':
case 'log-detail':
case 'global-setting':
case 'empty':
pane = { type, name: compCnMap[type]!, key: Date.now() + uniqueId() }
break
@ -182,4 +184,7 @@ const openInNewWindow = () => window.parent.open('/baidu_netdisk')
flex: 1;
font-size: 16px;
}
.quick-start__icon {
margin-right: 8px;
}
</style>

View File

@ -17,6 +17,7 @@ import NProgress from 'multi-nprogress'
import { Modal, message } from 'ant-design-vue'
import type { MenuInfo } from 'ant-design-vue/lib/menu/src/interface'
import { nextTick } from 'vue'
import { loginByBduss } from '@/api/user'
const global = useGlobalStore()
export const toRawFileUrl = (file: FileNodeInfo, download = false) => `/baidu_netdisk/file?filename=${encodeURIComponent(file.fullpath)}${download ? `&disposition=${encodeURIComponent(file.name)}` : ''}`
@ -87,6 +88,8 @@ export type ViewMode = 'line' | 'grid' | 'large-size-grid'
export const useBaiduyun = () => {
const taskListStore = useTaskListStore()
const bduss = ref('')
const installedBaiduyun = computedAsync(taskListStore.checkBaiduyunInstalled, false)
const baiduyunLoading = ref(false)
const failedHint = ref('')
@ -105,11 +108,29 @@ export const useBaiduyun = () => {
baiduyunLoading.value = false
}
}
const onLoginBtnClick = async () => {
if (baiduyunLoading.value) {
return
}
try {
baiduyunLoading.value = true
global.user = await loginByBduss(bduss.value)
} catch (error) {
console.error(error)
message.error(isAxiosError(error) ? error.response?.data?.detail ?? '未知错误' : '未知错误')
} finally {
baiduyunLoading.value = false
}
}
return {
installBaiduyunBin,
installedBaiduyun,
failedHint,
baiduyunLoading
baiduyunLoading,
bduss,
onLoginBtnClick
}
}
@ -218,7 +239,7 @@ export function useLocation (props: Props) {
watch(() => stack.value.length, debounce((v, lv) => {
if (v !== lv) {
scroller.value!.scrollToItem(0)
scroller.value?.scrollToItem(0)
}
}, 300))
@ -251,7 +272,7 @@ export function useLocation (props: Props) {
/**
*
*/
watch(() => props.target === 'netdisk' && installedBaiduyun.value, async (v, last) => {
watch(() => props.target === 'netdisk' && installedBaiduyun.value && global.user, async (v, last) => {
if (v && !last) {
const resp = await getTargetFolderFiles(props.target, '/')
stack.value = [{

View File

@ -22,7 +22,9 @@ const props = defineProps<{
path?: string,
walkMode?: boolean
}>()
const { installBaiduyunBin, installedBaiduyun, failedHint, baiduyunLoading, scroller, stackViewEl, props: _props } = useHookShareState().toRefs()
const { installBaiduyunBin, installedBaiduyun, failedHint, baiduyunLoading,
scroller, stackViewEl, props: _props, bduss, onLoginBtnClick
} = useHookShareState().toRefs()
watch(() => props, () => {
_props.value = props
}, { immediate: true })
@ -41,18 +43,36 @@ const { previewIdx, onPreviewVisibleChange, previewing, previewImgMove, canPrevi
</script>
<template>
<ASelect style="display: none;"></ASelect>
<div v-if="props.target === 'netdisk' && !installedBaiduyun" class="uninstalled-hint">
<div>尚未安装依赖当前不可用</div>
<AButton type="primary" :loading="baiduyunLoading" @click="installBaiduyunBin"></AButton>
<p v-if="failedHint">{{ failedHint }}</p>
<div v-if="props.target === 'netdisk' && (!installedBaiduyun || !global.user)" class="uninstalled-hint">
<template v-if="!installedBaiduyun">
<div>尚未安装依赖当前不可用</div>
<AButton type="primary" :loading="baiduyunLoading" @click="installBaiduyunBin"></AButton>
<p v-if="failedHint">{{ failedHint }}</p>
</template>
<template v-else>
<a-form layout="inline">
<a-form-item label="bduss">
<a-input v-model:value="bduss" style="width:300px"></a-input>
</a-form-item>
<a-form-item>
<a-button @click="onLoginBtnClick" type="primary" :loading="baiduyunLoading">
<template #icon>
<login-outlined />
</template>
登录
</a-button>
</a-form-item>
</a-form>
</template>
</div>
<div ref="stackViewEl" @dragover.prevent @drop.prevent="onDrop($event)" class="container" v-else>
<AModal v-model:visible="showGenInfo" width="50vw">
<ASkeleton active :loading="!q.isIdle">
<pre style="width: 100%; word-break: break-all;white-space: pre-line;" @dblclick="copy2clipboard(imageGenInfo)">
双击复制
{{ imageGenInfo }}
</pre>
双击复制
{{ imageGenInfo }}
</pre>
</ASkeleton>
</AModal>
<div class="location-bar">

View File

@ -0,0 +1,57 @@
<script setup lang="ts">
import { logout } from '@/api/user'
import { useGlobalStore } from '@/store/useGlobalStore'
import { useTaskListStore } from '@/store/useTaskListStore'
import { message } from 'ant-design-vue'
import { storeToRefs } from 'pinia'
import { reactive } from 'vue'
import { FetchQueue } from 'vue3-ts-util'
const queue = reactive(new FetchQueue(-1, 0, 0, 'throw'))
const globalStore = useGlobalStore()
const taskStore = useTaskListStore()
const { user } = storeToRefs(globalStore)
const onLogoutBtnClick = async () => {
await queue.pushAction(logout).res
user.value = undefined
message.info('登出成功')
}
</script>
<template>
<div class="panel">
<a-form>
<a-form-item label="使用缩略图预览">
<a-switch v-model:checked="globalStore.enableThumbnail" />
</a-form-item>
<a-form-item label="轮询间隔">
<a-input-number v-model:value="taskStore.pollInterval" :min="0.5" :disabled="!taskStore.queue.isIdle" /> (s)
<sub>越小对网络压力越大</sub>
</a-form-item>
<template v-if="user">
<a-form-item label="百度云已登录用户">
{{ user.username }}
<a-button @click="onLogoutBtnClick" :loading="!queue.isIdle">
<template #icon>
<logout-outlined />
</template>
登出
</a-button>
</a-form-item>
</template>
</a-form>
</div>
</template>
<style lang="scss" scoped>
.panel {
padding: 8px;
margin: 16px;
border-radius: 8px;
background: var(--zp-primary-background);
&> :not(:first-child) {
margin-left: 16px;
}
}
</style>

View File

@ -1,4 +1,5 @@
import type { GlobalConf, UploadTaskSummary } from '@/api'
import type { UserInfo } from '@/api/user'
import type { getAutoCompletedTagList } from '@/taskRecord/autoComplete'
import type { ReturnTypeAsync } from '@/util'
import { uniqueId } from 'lodash'
@ -8,7 +9,7 @@ import { ref } from 'vue'
import { typedEventEmitter, type UniqueId, ID } from 'vue3-ts-util'
interface OtherTabPane {
type: 'auto-upload' | 'task-record' | 'empty' | 'log-detail'
type: 'auto-upload' | 'task-record' | 'empty' | 'log-detail' | 'global-setting'
name: string
readonly key: string
}
@ -39,6 +40,7 @@ export interface Tab extends UniqueId {
export const useGlobalStore = defineStore('useGlobalStore', () => {
const conf = ref<GlobalConf>()
const user = ref<UserInfo>()
const autoCompletedDirList = ref([] as ReturnTypeAsync<typeof getAutoCompletedTagList>)
const enableThumbnail = ref(true)
const stackViewSplit = ref(50)
@ -76,12 +78,13 @@ export const useGlobalStore = defineStore('useGlobalStore', () => {
tabList.value.push(ID({ panes: [log], key: log.key }))
} else {
tab.key = log.key
tab.panes.push(log)
tab.panes.push(log)
}
}
return {
user,
tabList,
conf,
autoCompletedDirList,

View File

@ -1,35 +0,0 @@
<!-- eslint-disable no-empty -->
<script setup lang="ts">
import { computed, onMounted } from 'vue'
import { copy2clipboard, SplitView } from 'vue3-ts-util'
import { useTaskListStore } from '../store/useTaskListStore'
import LogDetail from './logDetail.vue'
import TaskList from './taskRecord.vue'
const store = useTaskListStore()
</script>
<template>
<div class="opreation-container">
<div class="panel">
<a-form layout="inline">
<a-form-item label="轮询间隔">
<a-input-number v-model:value="store.pollInterval" :min="0.5" :disabled="!store.queue.isIdle" /> (s)
<sub>越小对网络压力越大</sub>
</a-form-item>
</a-form>
</div>
</div>
</template>
<style scoped lang="scss">
.opreation-container {
display: flex;
flex-direction: column;
.split-view {
height: var(--scroll-container-max-height);
}
}
</style>