Merge pull request #173 from zyronon/dev
feat:add feedback link & migrate notice
This commit is contained in:
@@ -82,7 +82,6 @@ async function transfer() {
|
||||
Toast.success('迁移完成')
|
||||
model.value = false
|
||||
emit('ok')
|
||||
|
||||
} catch (e) {
|
||||
Toast.error('迁移失败:' + e)
|
||||
console.error('迁移失败', e);
|
||||
@@ -91,21 +90,21 @@ async function transfer() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog v-model="model" title="迁移数据">
|
||||
<div class="px-4 flex-col center text-align-center w-100">
|
||||
<h2>
|
||||
<Dialog v-model="model"
|
||||
:footer="true"
|
||||
@ok="transfer"
|
||||
confirmButtonText="迁移数据"
|
||||
title="迁移数据">
|
||||
<div class="px-4 flex-col center w-100">
|
||||
<h2 class="text-align-center">
|
||||
本网站已启用新域名 <span class="color-blue">{{ Origin }}</span>
|
||||
</h2>
|
||||
<h3>
|
||||
老域名即将停用,由于浏览器安全限制,新老网站数据无法互通,需要您手动点击转移数据
|
||||
</h3>
|
||||
<h3>
|
||||
<BaseButton
|
||||
size="large"
|
||||
@click="transfer">
|
||||
转移数据
|
||||
</BaseButton>
|
||||
</h3>
|
||||
<div>
|
||||
如果您不想此时迁移,关闭弹窗后,您可随时在“设置” -> “数据管理” 里面再次进行
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
@@ -18,7 +18,7 @@ import dayjs from "dayjs";
|
||||
import isBetween from "dayjs/plugin/isBetween";
|
||||
import isoWeek from 'dayjs/plugin/isoWeek'
|
||||
import { useFetch } from "@vueuse/core";
|
||||
import { AppEnv, DICT_LIST, PracticeSaveArticleKey } from "@/config/env.ts";
|
||||
import {AppEnv, DICT_LIST, Host, PracticeSaveArticleKey} from "@/config/env.ts";
|
||||
import { myDictList } from "@/apis";
|
||||
|
||||
dayjs.extend(isoWeek)
|
||||
@@ -162,11 +162,16 @@ const weekList = $computed(() => {
|
||||
|
||||
const {data: recommendBookList, isFetching} = useFetch(resourceWrap(DICT_LIST.ARTICLE.RECOMMENDED)).json()
|
||||
|
||||
let isNewHost = $ref(window.location.host === Host)
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasePage>
|
||||
<div class="mb-4" v-if="!isNewHost">
|
||||
新域名已启用,后续请访问 <a href="https://typewords.cc/words?from_old_site=1">https://typewords.cc</a>。当前 2study.top 域名将在不久后停止使用
|
||||
</div>
|
||||
|
||||
<div class="card flex flex-col md:flex-row justify-between gap-space p-4 md:p-6">
|
||||
<div class="">
|
||||
<Book
|
||||
|
||||
@@ -17,6 +17,9 @@ const {toggleTheme, getTheme} = useTheme()
|
||||
function goHome() {
|
||||
window.location.href = '/';
|
||||
}
|
||||
function goFeedback() {
|
||||
window.open('https://v.wjx.cn/vm/ev0W7fv.aspx#', '_blank');
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -44,6 +47,10 @@ function goHome() {
|
||||
<span v-if="settingStore.sideExpand">设置</span>
|
||||
<div class="red-point" :class="!settingStore.sideExpand && 'top-1 right-0'" v-if="runtimeStore.isNew"></div>
|
||||
</div>
|
||||
<div class="row" @click="goFeedback">
|
||||
<IconFluentCommentEdit20Regular/>
|
||||
<span v-if="settingStore.sideExpand">建议反馈</span>
|
||||
</div>
|
||||
<!-- <div class="row" @click="router.push('/user')">-->
|
||||
<!-- <IconFluentPerson20Regular/>-->
|
||||
<!-- <span v-if="settingStore.sideExpand">用户</span>-->
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
import { nextTick, ref, watch } from "vue";
|
||||
import { useSettingStore } from "@/stores/setting.ts";
|
||||
import { getAudioFileUrl, usePlayAudio } from "@/hooks/sound.ts";
|
||||
import { getShortcutKey, useEventListener } from "@/hooks/event.ts";
|
||||
import { checkAndUpgradeSaveDict, checkAndUpgradeSaveSetting, cloneDeep, loadJsLib, shakeCommonDict } from "@/utils";
|
||||
import { DefaultShortcutKeyMap, ShortcutKey, WordPracticeMode } from "@/types/types.ts";
|
||||
import {nextTick, onMounted, ref, watch} from "vue";
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import {getAudioFileUrl, usePlayAudio} from "@/hooks/sound.ts";
|
||||
import {getShortcutKey, useEventListener} from "@/hooks/event.ts";
|
||||
import {checkAndUpgradeSaveDict, checkAndUpgradeSaveSetting, cloneDeep, loadJsLib, shakeCommonDict} from "@/utils";
|
||||
import {DefaultShortcutKeyMap, ShortcutKey, WordPracticeMode} from "@/types/types.ts";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import VolumeIcon from "@/components/icon/VolumeIcon.vue";
|
||||
import { useBaseStore } from "@/stores/base.ts";
|
||||
import { saveAs } from "file-saver";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
import {saveAs} from "file-saver";
|
||||
import {
|
||||
APP_NAME, APP_VERSION, EMAIL,
|
||||
EXPORT_DATA_KEY, GITHUB,
|
||||
EXPORT_DATA_KEY, GITHUB, Host,
|
||||
LOCAL_FILE_KEY,
|
||||
Origin,
|
||||
PracticeSaveArticleKey,
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
import dayjs from "dayjs";
|
||||
import BasePage from "@/components/BasePage.vue";
|
||||
import Toast from '@/components/base/toast/Toast.ts'
|
||||
import { Option, Select } from "@/components/base/select";
|
||||
import {Option, Select} from "@/components/base/select";
|
||||
import Switch from "@/components/base/Switch.vue";
|
||||
import Slider from "@/components/base/Slider.vue";
|
||||
import RadioGroup from "@/components/base/radio/RadioGroup.vue";
|
||||
@@ -29,10 +29,11 @@ import InputNumber from "@/components/base/InputNumber.vue";
|
||||
import PopConfirm from "@/components/PopConfirm.vue";
|
||||
import Textarea from "@/components/base/Textarea.vue";
|
||||
import SettingItem from "@/pages/setting/SettingItem.vue";
|
||||
import { get, set } from "idb-keyval";
|
||||
import { useRuntimeStore } from "@/stores/runtime.ts";
|
||||
import { useUserStore } from "@/stores/user.ts";
|
||||
import { useExport } from "@/hooks/export.ts";
|
||||
import {get, set} from "idb-keyval";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import {useUserStore} from "@/stores/user.ts";
|
||||
import {useExport} from "@/hooks/export.ts";
|
||||
import MigrateDialog from "@/components/MigrateDialog.vue";
|
||||
|
||||
const emit = defineEmits<{
|
||||
toggleDisabledDialogEscKey: [val: boolean]
|
||||
@@ -42,7 +43,6 @@ const tabIndex = $ref(0)
|
||||
const settingStore = useSettingStore()
|
||||
const runtimeStore = useRuntimeStore()
|
||||
const store = useBaseStore()
|
||||
const userStore = useUserStore()
|
||||
|
||||
//@ts-ignore
|
||||
const gitLastCommitHash = ref(LATEST_COMMIT_HASH);
|
||||
@@ -99,7 +99,7 @@ useEventListener('keydown', (e: KeyboardEvent) => {
|
||||
} else {
|
||||
// 忽略单独的修饰键
|
||||
if (shortcutKey === 'Ctrl+' || shortcutKey === 'Alt+' || shortcutKey === 'Shift+' ||
|
||||
e.key === 'Control' || e.key === 'Alt' || e.key === 'Shift') {
|
||||
e.key === 'Control' || e.key === 'Alt' || e.key === 'Shift') {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -300,6 +300,15 @@ function importOldData() {
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
let isNewHost = $ref(window.location.host === Host)
|
||||
|
||||
let showTransfer = $ref(false)
|
||||
function transferOk() {
|
||||
setTimeout(() => {
|
||||
window.location.href = '/words'
|
||||
}, 1500)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -372,8 +381,8 @@ function importOldData() {
|
||||
v-if="settingStore.ignoreSimpleWord"
|
||||
>
|
||||
<Textarea
|
||||
placeholder="多个单词用英文逗号隔号"
|
||||
v-model="simpleWords" :autosize="{minRows: 6, maxRows: 10}"/>
|
||||
placeholder="多个单词用英文逗号隔号"
|
||||
v-model="simpleWords" :autosize="{minRows: 6, maxRows: 10}"/>
|
||||
</SettingItem>
|
||||
|
||||
<!-- 音效-->
|
||||
@@ -401,16 +410,16 @@ function importOldData() {
|
||||
class="w-50!"
|
||||
>
|
||||
<Option
|
||||
v-for="item in SoundFileOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
v-for="item in SoundFileOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
>
|
||||
<div class="flex justify-between items-center w-full">
|
||||
<span>{{ item.label }}</span>
|
||||
<VolumeIcon
|
||||
:time="100"
|
||||
@click="usePlayAudio(getAudioFileUrl(item.value)[0])"/>
|
||||
:time="100"
|
||||
@click="usePlayAudio(getAudioFileUrl(item.value)[0])"/>
|
||||
</div>
|
||||
</Option>
|
||||
</Select>
|
||||
@@ -528,16 +537,16 @@ function importOldData() {
|
||||
<SettingItem mainTitle="字体设置"/>
|
||||
<SettingItem title="外语字体">
|
||||
<Slider
|
||||
:min="10"
|
||||
:max="100"
|
||||
v-model="settingStore.fontSize.wordForeignFontSize"/>
|
||||
:min="10"
|
||||
:max="100"
|
||||
v-model="settingStore.fontSize.wordForeignFontSize"/>
|
||||
<span class="w-10 pl-5">{{ settingStore.fontSize.wordForeignFontSize }}px</span>
|
||||
</SettingItem>
|
||||
<SettingItem title="中文字体">
|
||||
<Slider
|
||||
:min="10"
|
||||
:max="100"
|
||||
v-model="settingStore.fontSize.wordTranslateFontSize"/>
|
||||
:min="10"
|
||||
:max="100"
|
||||
v-model="settingStore.fontSize.wordTranslateFontSize"/>
|
||||
<span class="w-10 pl-5">{{ settingStore.fontSize.wordTranslateFontSize }}px</span>
|
||||
</SettingItem>
|
||||
</div>
|
||||
@@ -550,7 +559,6 @@ function importOldData() {
|
||||
<!-- 发音-->
|
||||
<!-- 发音-->
|
||||
<!-- 发音-->
|
||||
<div class="line"></div>
|
||||
<SettingItem mainTitle="音效"/>
|
||||
<SettingItem title="自动播放句子">
|
||||
<Switch v-model="settingStore.articleSound"/>
|
||||
@@ -586,7 +594,7 @@ function importOldData() {
|
||||
<input ref="shortcutInput" :value="item[1]?item[1]:'未设置快捷键'" readonly type="text"
|
||||
@blur="handleInputBlur">
|
||||
<span @click.stop="editShortcutKey = ''">按键盘进行设置,<span
|
||||
class="text-red!">设置完成点击这里</span></span>
|
||||
class="text-red!">设置完成点击这里</span></span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div v-if="item[1]">{{ item[1] }}</div>
|
||||
@@ -623,11 +631,20 @@ function importOldData() {
|
||||
@change="importData">
|
||||
</div>
|
||||
<PopConfirm
|
||||
title="导入老版本数据前,请先备份当前数据,确定要导入老版本数据吗?"
|
||||
@confirm="importOldData">
|
||||
title="导入老版本数据前,请先备份当前数据,确定要导入老版本数据吗?"
|
||||
@confirm="importOldData">
|
||||
<BaseButton>老版本数据导入</BaseButton>
|
||||
</PopConfirm>
|
||||
</div>
|
||||
|
||||
<template v-if="!isNewHost">
|
||||
<div class="line my-3"></div>
|
||||
<div>请注意,如果本地已有使用记录,请先备份当前数据,迁移数据后将<b class="text-red"> 完全覆盖 </b>当前所有数据,请谨慎操作。
|
||||
</div>
|
||||
<div class="flex gap-space mt-3">
|
||||
<BaseButton @click="showTransfer = true">迁移 2study.top 网站数据</BaseButton>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div v-if="tabIndex === 5">
|
||||
@@ -798,29 +815,6 @@ function importOldData() {
|
||||
|
||||
<div v-if="tabIndex === 6" class="center flex-col">
|
||||
<h1>Type Words</h1>
|
||||
|
||||
<!-- 用户信息部分 -->
|
||||
<div v-if="userStore.isLoggedIn && userStore.user" class="user-info-section mb-6">
|
||||
<div class="user-avatar mb-4">
|
||||
<img v-if="userStore.user.avatar" :src="userStore.user.avatar" alt="头像" class="avatar-img"/>
|
||||
<div v-else class="avatar-placeholder">
|
||||
{{ userStore.user.nickname?.charAt(0) || 'U' }}
|
||||
</div>
|
||||
</div>
|
||||
<h3 class="mb-2">{{ userStore.user.nickname || '用户' }}</h3>
|
||||
<p v-if="userStore.user.email" class="text-sm color-gray mb-1">{{ userStore.user.email }}</p>
|
||||
<p v-if="userStore.user.phone" class="text-sm color-gray">{{ userStore.user.phone }}</p>
|
||||
|
||||
<BaseButton
|
||||
@click="userStore.logout"
|
||||
type="info"
|
||||
class="mt-4"
|
||||
:loading="userStore.isLoading"
|
||||
>
|
||||
退出登录
|
||||
</BaseButton>
|
||||
</div>
|
||||
|
||||
<p class="w-100 text-xl">
|
||||
感谢使用本项目!本项目是开源项目,如果觉得有帮助,请在 GitHub 点个 Star,您的支持是我持续改进的动力。
|
||||
</p>
|
||||
@@ -837,10 +831,14 @@ function importOldData() {
|
||||
Build {{ gitLastCommitHash }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</BasePage>
|
||||
|
||||
<MigrateDialog
|
||||
v-model="showTransfer"
|
||||
@ok="transferOk"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@@ -1054,85 +1052,85 @@ function importOldData() {
|
||||
@media (max-width: 768px) {
|
||||
.setting {
|
||||
flex-direction: column;
|
||||
|
||||
|
||||
.left {
|
||||
width: 100%;
|
||||
border-right: none;
|
||||
border-bottom: 2px solid gainsboro;
|
||||
|
||||
|
||||
.tabs {
|
||||
flex-direction: row;
|
||||
overflow-x: auto;
|
||||
padding: 0.5rem;
|
||||
gap: 0.3rem;
|
||||
|
||||
|
||||
.tab {
|
||||
white-space: nowrap;
|
||||
padding: 0.4rem 0.6rem;
|
||||
font-size: 0.9rem;
|
||||
|
||||
|
||||
span {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.content {
|
||||
padding: 0 1rem;
|
||||
|
||||
|
||||
.row {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 0.5rem;
|
||||
min-height: auto;
|
||||
padding: 0.5rem 0;
|
||||
|
||||
|
||||
.wrapper {
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
|
||||
|
||||
.set-key {
|
||||
width: 100%;
|
||||
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
max-width: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 补充:选择器和输入框优化
|
||||
.base-select, .base-input {
|
||||
width: 100% !important;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
|
||||
// 单选按钮组优化
|
||||
.radio-group {
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
|
||||
|
||||
.radio {
|
||||
min-height: 44px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 滑块优化
|
||||
.slider {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.main-title {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
|
||||
.item-title {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.body {
|
||||
height: auto;
|
||||
max-height: 60vh;
|
||||
|
||||
@@ -19,7 +19,7 @@ import PracticeSettingDialog from "@/pages/word/components/PracticeSettingDialog
|
||||
import ChangeLastPracticeIndexDialog from "@/pages/word/components/ChangeLastPracticeIndexDialog.vue";
|
||||
import { useSettingStore } from "@/stores/setting.ts";
|
||||
import { useFetch } from "@vueuse/core";
|
||||
import { AppEnv, DICT_LIST, PracticeSaveWordKey } from "@/config/env.ts";
|
||||
import {AppEnv, DICT_LIST, Host, PracticeSaveWordKey} from "@/config/env.ts";
|
||||
import { myDictList } from "@/apis";
|
||||
import PracticeWordListDialog from "@/pages/word/components/PracticeWordListDialog.vue";
|
||||
import ShufflePracticeSettingDialog from "@/pages/word/components/ShufflePracticeSettingDialog.vue";
|
||||
@@ -32,6 +32,7 @@ const {nav} = useNav()
|
||||
const runtimeStore = useRuntimeStore()
|
||||
let loading = $ref(true)
|
||||
let isSaveData = $ref(false)
|
||||
|
||||
let currentStudy = $ref({
|
||||
new: [],
|
||||
review: [],
|
||||
@@ -196,11 +197,15 @@ const {
|
||||
isFetching
|
||||
} = useFetch(resourceWrap(DICT_LIST.WORD.RECOMMENDED)).json()
|
||||
|
||||
|
||||
let isNewHost = $ref(window.location.host === Host)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasePage>
|
||||
<div class="mb-4" v-if="!isNewHost">
|
||||
新域名已启用,后续请访问 <a href="https://typewords.cc/words?from_old_site=1">https://typewords.cc</a>。当前 2study.top 域名将在不久后停止使用
|
||||
</div>
|
||||
|
||||
<div class="card flex flex-col md:flex-row gap-8">
|
||||
<div class="flex-1 w-full flex flex-col justify-between">
|
||||
<div class="flex gap-3">
|
||||
|
||||
Reference in New Issue
Block a user