增加全局设置页,增加百度云登录
parent
e7cc311253
commit
7dabb90df1
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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']
|
||||
|
|
|
|||
|
|
@ -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 = [
|
||||
'使用“快速移动”, 可以直接到到达图生图,文生图等文件夹',
|
||||
"你可以通过拖拽调整两边区域的大小",
|
||||
"使用ctrl,shift可以很方便的进行多选",
|
||||
"从百度云向本地拖拽是下载,本地向百度云拖拽是上传",
|
||||
"可以多尝试更多里面的功能",
|
||||
"鼠标在文件上右键可以打开上下文菜单",
|
||||
"提醒任务完成后,你需要手动刷新下才能看到新文件"]
|
||||
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>
|
||||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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 = [{
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
Loading…
Reference in New Issue