mirror of
https://github.com/rubickCenter/rubick
synced 2025-12-16 23:54:19 +08:00
✨ 支持 webdav 数据多端同步
This commit is contained in:
@@ -36,4 +36,11 @@ window.market = {
|
||||
removeLocalStartPlugin(plugin) {
|
||||
ipcSend('removeLocalStartPlugin', { plugin });
|
||||
},
|
||||
dbDump(target) {
|
||||
ipcSend('dbDump', { target });
|
||||
},
|
||||
|
||||
dbImport(target) {
|
||||
ipcSend('dbImport', { target });
|
||||
},
|
||||
};
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 3.2 KiB |
@@ -99,6 +99,9 @@ export default {
|
||||
localstart: {
|
||||
title: 'Local Start',
|
||||
},
|
||||
database: {
|
||||
title: 'Data Synchronization',
|
||||
},
|
||||
},
|
||||
dev: {
|
||||
title: 'Developer',
|
||||
|
||||
@@ -97,6 +97,9 @@ export default {
|
||||
localstart: {
|
||||
title: '本地启动',
|
||||
},
|
||||
database: {
|
||||
title: '多端数据同步',
|
||||
},
|
||||
},
|
||||
dev: {
|
||||
title: '开发者',
|
||||
|
||||
241
feature/src/views/settings/database.vue
Normal file
241
feature/src/views/settings/database.vue
Normal file
@@ -0,0 +1,241 @@
|
||||
<template>
|
||||
<div class="export-header">
|
||||
<a-button @click="exportData" size="small" type="primary" style="margin-right: 10px;">
|
||||
导出数据
|
||||
<template #icon>
|
||||
<ExportOutlined />
|
||||
</template>
|
||||
</a-button>
|
||||
<a-button @click="importData" danger size="small" style="margin-right: 10px;">
|
||||
导入数据
|
||||
<template #icon>
|
||||
<ImportOutlined />
|
||||
</template>
|
||||
</a-button>
|
||||
<a-button type="link" size="small" @click="showSetting = true">
|
||||
<template #icon>
|
||||
<SettingOutlined />
|
||||
</template>
|
||||
</a-button>
|
||||
</div>
|
||||
<a-list item-layout="horizontal" :data-source="dataPlugins">
|
||||
<template #renderItem="{ item }">
|
||||
<a-list-item>
|
||||
<template #actions>
|
||||
<a v-if="!item.plugin.isdownload && !item.plugin.isloading" key="list-loadmore-edit"
|
||||
@click="() => downloadPlugin(item.plugin)">
|
||||
<CloudDownloadOutlined style="font-size: 18px;"/>
|
||||
</a>
|
||||
<a v-if="item.plugin.isloading" key="list-loadmore-edit">
|
||||
<LoadingOutlined style="font-size: 18px;"/>
|
||||
</a>
|
||||
<a key="list-loadmore-edit" @click="() => showKeys(item)">
|
||||
<DatabaseOutlined style="font-size: 18px;"/>
|
||||
</a>
|
||||
</template>
|
||||
<a-list-item-meta :description="`${item.keys.length} 份文档`">
|
||||
<template #title>
|
||||
<div>
|
||||
<span>{{ item.plugin.pluginName }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #avatar>
|
||||
<a-avatar shape="square" :src="item.plugin.logo"/>
|
||||
</template>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
</template>
|
||||
</a-list>
|
||||
<a-drawer
|
||||
v-model:visible="open"
|
||||
width="400"
|
||||
:closable="false"
|
||||
:title="currentSelect.plugin.pluginName"
|
||||
placement="right"
|
||||
>
|
||||
<p
|
||||
class="key-item"
|
||||
:key="key"
|
||||
@click="() => showDetail(key)"
|
||||
v-for="key in currentSelect.keys"
|
||||
>
|
||||
{{ key }}
|
||||
</p>
|
||||
</a-drawer>
|
||||
<a-modal
|
||||
centered
|
||||
bodyStyle="max-height: 500px; overflow: auto"
|
||||
:footer="null"
|
||||
:closable="false"
|
||||
v-model:visible="show"
|
||||
>
|
||||
<pre>{{ JSON.stringify(detail, null, 2) }}</pre>
|
||||
</a-modal>
|
||||
<a-modal
|
||||
v-model:visible="showSetting"
|
||||
title="坚果云 webdav 配置"
|
||||
:footer="null"
|
||||
>
|
||||
<a-alert style="margin-bottom: 20px;" type="info" show-icon>
|
||||
<template #message>
|
||||
<div
|
||||
@click="openHelp"
|
||||
class="openHelp">
|
||||
点击查看如何获取坚果云账号密码
|
||||
</div>
|
||||
</template>
|
||||
</a-alert>
|
||||
<a-form
|
||||
:model="formState"
|
||||
name="basic"
|
||||
:label-col="{ span: 8 }"
|
||||
:wrapper-col="{ span: 16 }"
|
||||
autocomplete="off"
|
||||
@finish="handleOk"
|
||||
>
|
||||
<a-form-item
|
||||
label="username"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: '请填写 username!' }]"
|
||||
>
|
||||
<a-input v-model:value="formState.username" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="password"
|
||||
name="password"
|
||||
:rules="[{ required: true, message: '请填写 password!' }]"
|
||||
>
|
||||
<a-input-password v-model:value="formState.password" />
|
||||
</a-form-item>
|
||||
<a-form-item :wrapper-col="{ offset: 8, span: 16 }">
|
||||
<a-button type="primary" html-type="submit">保存设置</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
<script setup>
|
||||
import { useStore } from 'vuex';
|
||||
import { computed, ref, reactive } from 'vue';
|
||||
import {
|
||||
DatabaseOutlined,
|
||||
CloudDownloadOutlined,
|
||||
LoadingOutlined,
|
||||
ExportOutlined,
|
||||
ImportOutlined,
|
||||
SettingOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const open = ref(false);
|
||||
const show = ref(false);
|
||||
const showSetting = ref(false);
|
||||
const currentSelect = ref({ plugin: {} });
|
||||
const detail = ref({});
|
||||
|
||||
const defaultConfig = window.rubick.dbStorage.getItem('rubick-db-jg-webdav') || {
|
||||
url: 'https://dav.jianguoyun.com/dav/',
|
||||
username: '',
|
||||
password: '',
|
||||
};
|
||||
const formState = reactive(defaultConfig);
|
||||
|
||||
const showKeys = (item) => {
|
||||
open.value = true;
|
||||
currentSelect.value = item;
|
||||
};
|
||||
|
||||
const handleOk = () => {
|
||||
window.rubick.dbStorage.setItem('rubick-db-jg-webdav', JSON.parse(JSON.stringify(formState)));
|
||||
message.success('保存成功');
|
||||
showSetting.value = false;
|
||||
};
|
||||
|
||||
const showDetail = (key) => {
|
||||
show.value = true;
|
||||
detail.value = window.rubick.db.get(key);
|
||||
};
|
||||
|
||||
const exportData = () => {
|
||||
if (!formState.password || !formState.username) {
|
||||
return showSetting.value = true;
|
||||
}
|
||||
window.market.dbDump(JSON.parse(JSON.stringify(formState)));
|
||||
};
|
||||
|
||||
const importData = () => {
|
||||
if (!formState.password || !formState.username) {
|
||||
return showSetting.value = true;
|
||||
}
|
||||
Modal.confirm({
|
||||
title: '导入确认',
|
||||
content: '导入坚果云数据将会覆盖本地数据,是否确认导入?',
|
||||
onOk() {
|
||||
window.market.dbImport(JSON.parse(JSON.stringify(formState)));
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const openHelp = () => {
|
||||
window.rubick.shellOpenExternal('https://help.jianguoyun.com/?p=2064')
|
||||
};
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const pluginsData = window.rubick.db.get('RUBICK_PLUGIN_INFO');
|
||||
|
||||
const totalPlugins = computed(() => store.state.totalPlugins);
|
||||
|
||||
const dataPlugins = computed(() => {
|
||||
if (!pluginsData) return [];
|
||||
return pluginsData.data.map((item) => {
|
||||
let plugin = null;
|
||||
if (['rubick-system-feature'].includes(item.name)) {
|
||||
plugin = {
|
||||
pluginName: '主程序',
|
||||
isdownload: true,
|
||||
logo: require('../../assets/logo.png'),
|
||||
};
|
||||
} else {
|
||||
plugin = totalPlugins.value.find((p) => p.name === item.name);
|
||||
}
|
||||
const data = item.keys.map((key) => window.rubick.db.get(key));
|
||||
return {
|
||||
...item,
|
||||
plugin,
|
||||
data,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const startDownload = (name) => store.dispatch('startDownload', name);
|
||||
const successDownload = (name) => store.dispatch('successDownload', name);
|
||||
|
||||
const downloadPlugin = async (plugin) => {
|
||||
startDownload(plugin.name);
|
||||
await window.market.downloadPlugin(plugin);
|
||||
message.success(t('feature.dev.installSuccess', { pluginName: plugin.name }));
|
||||
successDownload(plugin.name);
|
||||
};
|
||||
</script>
|
||||
<style lang="less">
|
||||
.openHelp {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.export-header {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
border-bottom: 1px solid #eee;
|
||||
text-align: right;
|
||||
}
|
||||
.key-item {
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: var(--ant-primary-color);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -32,10 +32,16 @@
|
||||
<!-- </template>-->
|
||||
<!-- {{ $t('feature.settings.superPanel.title') }}-->
|
||||
<!-- </a-menu-item>-->
|
||||
<a-menu-item key="localhost">
|
||||
<a-menu-item key="database">
|
||||
<template #icon>
|
||||
<DatabaseOutlined />
|
||||
</template>
|
||||
{{ $t('feature.settings.database.title') }}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="localhost">
|
||||
<template #icon>
|
||||
<SafetyOutlined />
|
||||
</template>
|
||||
{{ $t('feature.settings.intranet.title') }}
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
@@ -227,6 +233,7 @@
|
||||
<SuperPanel v-if="currentSelect[0] === 'superpanel'" />
|
||||
<Localhost v-if="currentSelect[0] === 'localhost'" />
|
||||
<LocalStart v-if="currentSelect[0] === 'localstart'" />
|
||||
<DataBase v-if="currentSelect[0] === 'database'" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -240,6 +247,7 @@ import {
|
||||
PlusCircleOutlined,
|
||||
UserOutlined,
|
||||
FolderOpenOutlined,
|
||||
SafetyOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import debounce from 'lodash.debounce';
|
||||
import { ref, reactive, watch, toRefs, computed } from 'vue';
|
||||
@@ -248,6 +256,7 @@ import Localhost from './localhost.vue';
|
||||
import SuperPanel from './super-panel.vue';
|
||||
import UserInfo from './user-info';
|
||||
import LocalStart from './local-start';
|
||||
import DataBase from './database';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import localConfig from '@/confOp';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user