diff --git a/package.json b/package.json index 03b14ce80..2489a0e1d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sub-store-front-end", - "version": "2.14.228", + "version": "2.14.229", "private": true, "scripts": { "dev": "vite --host", diff --git a/src/components/SubListItem.vue b/src/components/SubListItem.vue index 7fdbdf5f6..082977306 100644 --- a/src/components/SubListItem.vue +++ b/src/components/SubListItem.vue @@ -175,11 +175,11 @@ - +
+ + + +
{ showNotify({ title: t("subPage.copyConfigNotify.succeed") }); swipe.value.close(); }; +// const onClickExport = async () => { +// swipeController() +// let data: Sub | Collection; +// switch (props.type) { +// case "sub": +// data = JSON.parse(JSON.stringify(toRaw(props.sub))); +// break; +// case "collection": +// data = JSON.parse(JSON.stringify(toRaw(props.collection))); +// break; +// } +// data.name += `-exportedAt${new Date().toLocaleDateString()} ${new Date().toLocaleTimeString()}`; + +// Toast.loading(t("subPage.copyConfigNotify.loading"), { id: "exportConfig" }); +// // await subsApi.createSub(props.type + "s", data); +// // await subsStore.fetchSubsData(); +// Toast.hide("exportConfig"); +// showNotify({ title: t("subPage.copyConfigNotify.succeed") }); +// swipe.value.close(); +// }; const onClickEdit = () => { router.push(`/edit/${props.type}s/${encodeURIComponent(name)}`); diff --git a/src/locales/en.ts b/src/locales/en.ts index 44df03db4..57e4711e9 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -9,6 +9,7 @@ export default { unknown: 'Unknown', all: 'All', untagged: 'Untagged', + or: 'or', }, globalNotify: { refresh: { @@ -99,6 +100,11 @@ export default { }, // subscription management page subPage: { + import: { + label: 'Import', + succeed: 'Successfully imported!', + failed: 'Failed to import!\n{e}', + }, addSubTitle: 'Which type you want to create?', previewTitle: 'Copy/Preview a subscription', @@ -152,6 +158,11 @@ export default { succeed: 'Successfully cloned config!', failed: 'Failed to clone config!\n{e}', }, + exportConfigNotify: { + loading: 'Exporting...', + succeed: 'Successfully exported config!', + failed: 'Failed to exporte config!\n{e}', + }, panel: { general: 'General', tips: { diff --git a/src/locales/zh.ts b/src/locales/zh.ts index 8d0d36e4a..e13cca2fe 100644 --- a/src/locales/zh.ts +++ b/src/locales/zh.ts @@ -9,6 +9,7 @@ export default { unknown: '未知', all: '全部', untagged: '未分组', + or: '或', }, globalNotify: { refresh: { @@ -99,6 +100,11 @@ export default { }, // 订阅管理页 subPage: { + import: { + label: '导入', + succeed: '导入成功', + failed: '导入失败\n{e}', + }, addSubTitle: '选择要创建的订阅类型', previewTitle: '预览/拷贝订阅', @@ -151,6 +157,11 @@ export default { succeed: '配置克隆成功!', failed: '配置克隆失败!\n{e}', }, + exportConfigNotify: { + loading: '导出配置中...', + succeed: '导出成功!', + failed: '导出失败!\n{e}', + }, panel: { general: '通用订阅', tips: { diff --git a/src/plugin/awesomeIcon.ts b/src/plugin/awesomeIcon.ts index 7ff2beb50..08880cbb5 100644 --- a/src/plugin/awesomeIcon.ts +++ b/src/plugin/awesomeIcon.ts @@ -28,8 +28,12 @@ import { faEraser, faT, faICursor, + faFileImport, + faFileExport, } from '@fortawesome/free-solid-svg-icons'; +library.add(faFileImport); +library.add(faFileExport); library.add(faToggleOn); library.add(faToggleOff); library.add(faLanguage); diff --git a/src/views/Sub.vue b/src/views/Sub.vue index 0d93c5382..5f47593ac 100644 --- a/src/views/Sub.vue +++ b/src/views/Sub.vue @@ -21,7 +21,27 @@ closeable round > -

{{ $t(`subPage.addSubTitle`) }}

+
+

{{ $t(`subPage.addSubTitle`) }}

+

{{ $t(`specificWord.or`) }}

+ + + + {{ $t(`subPage.import.label`) }} + + +
  • @@ -225,7 +245,7 @@ import { ref, toRaw, computed } from "vue"; import draggable from "vuedraggable"; import { useAppNotifyStore } from "@/store/appNotify"; -// import { Dialog, Toast } from '@nutui/nutui'; +import { Dialog, Toast } from '@nutui/nutui'; import { useSubsApi } from "@/api/subs"; import SubListItem from "@/components/SubListItem.vue"; @@ -240,7 +260,9 @@ const { env } = useBackend(); const { showNotify } = useAppNotifyStore(); const subsApi = useSubsApi(); const { t } = useI18n(); - +const fileInput = ref(null); +const uploadIsLoading = ref(false); +const restoreIsLoading = ref(false); const addSubBtnIsVisible = ref(false); // const isSubFold = ref(localStorage.getItem('sub-fold') === '1'); // const isColFold = ref(localStorage.getItem('col-fold') === '1'); @@ -453,6 +475,69 @@ const shouldShowElement = (element) => { if(tag.value === 'untagged') return !Array.isArray(element.tag) || element.tag.length === 0 return element.tag.includes(tag.value) }; +const upload = async() => { + try { + fileInput.value.click() + } catch (e) { + console.error(e); + } +} + +const fileChange = async (event) => { + const file = event.target.files[0]; + if(!file) return + try { + restoreIsLoading.value = true; + const reader = new FileReader(); + reader.readAsText(file); + reader.onload = async () => { + const item = JSON.parse(String(reader.result)) + const suffix = new Date().getTime() + item.name += `_${suffix}` + item.displayName += `_${suffix}` + item['display-name'] = item.displayName + const res = await subsApi.createSub('subs', item); + // await subsStore.fetchSubsData(); + + // const res = await useSettingsApi().restoreSettings({ content: String(reader.result) }); + if (res?.data?.status === "success") { + await initStores(false, true, true); + showNotify({ + type: "success", + title: t(`subPage.import.succeed`), + }); + addSubBtnIsVisible.value = false + } else { + throw new Error('restore failed') + } + } + + reader.onerror = e => { + throw e + } + + } catch (e) { + showNotify({ + type: "danger", + title: t(`subPage.import.failed`, { e: e.message ?? e }), + }); + console.error(e); + } finally { + restoreIsLoading.value = false; + } +}; +const importTips = () => { + addSubBtnIsVisible.value = false + Dialog({ + title: '仅支持 Sub-Store 单条订阅数据', + content: '订阅管理页面, 在某个单条订阅左滑/右滑的更多项中, 点击导出图标按钮', + popClass: 'auto-dialog', + okText: 'OK', + noCancelBtn: true, + closeOnPopstate: true, + lockScroll: false, + }); +};