update vue3.3

web编辑 修正筛选删除导出逻辑
This commit is contained in:
Xwite 2023-05-14 19:36:52 +08:00
parent 152dc4e3b8
commit 5efc367bc6
12 changed files with 130 additions and 100 deletions

View File

@ -4,7 +4,6 @@
"ComponentPublicInstance": true,
"ComputedRef": true,
"EffectScope": true,
"ElLoading": true,
"ElMessage": true,
"InjectionKey": true,
"PropType": true,

View File

@ -15,26 +15,26 @@
"dependencies": {
"@element-plus/icons-svg": "^2.1.0",
"@element-plus/icons-vue": "^2.1.0",
"@vueuse/shared": "^10.0.2",
"axios": "^1.3.5",
"element-plus": "^2.3.3",
"@vueuse/shared": "^10.1.2",
"axios": "^1.4.0",
"element-plus": "^2.3.4",
"hotkeys-js": "^3.10.2",
"pinia": "^2.0.34",
"vue": "^3.2.47",
"vue-router": "^4.1.6",
"pinia": "^2.0.36",
"vue": "^3.3.2",
"vue-router": "^4.2.0",
"vue3-virtual-scroll-list": "^0.2.1"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.1.0",
"eslint": "^8.38.0",
"@vitejs/plugin-vue": "^4.2.3",
"eslint": "^8.40.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "^9.11.0",
"prettier": "^2.8.7",
"sass": "^1.62.0",
"eslint-plugin-vue": "^9.12.0",
"prettier": "^2.8.8",
"sass": "^1.62.1",
"unplugin-auto-import": "^0.15.3",
"unplugin-icons": "^0.16.1",
"unplugin-vue-components": "^0.24.1",
"vite": "^4.2.1"
"vite": "^4.3.5"
}
}

View File

@ -64,7 +64,6 @@ const getCover = (coverUrl) => {
const subJustify = computed(() =>
props.isSearch ? "space-between" : "flex-start"
);
</script>
<style lang="scss" scoped>

View File

@ -12,7 +12,12 @@
</div>
</template>
<script setup>
const props = defineProps(["index", "source", "gotoChapter", "currentChapterIndex"]);
const props = defineProps([
"index",
"source",
"gotoChapter",
"currentChapterIndex",
]);
const isSelected = (idx) => {
return idx == props.currentChapterIndex;

View File

@ -27,9 +27,12 @@ const store = useSourceStore();
const printDebug = ref("");
const searchKey = ref("");
watch(() => store.isDebuging, () => {
if (store.isDebuging) startDebug();
});
watch(
() => store.isDebuging,
() => {
if (store.isDebuging) startDebug();
}
);
const appendDebugMsg = (msg) => {
let debugDom = document.querySelector("#debug-text");

View File

@ -15,11 +15,12 @@
<script setup>
import { Edit } from "@element-plus/icons-vue";
import { getSourceUniqueKey } from "@/utils/souce";
const props = defineProps(["source"]);
const store = useSourceStore();
const { savedSourcesMap, currentSourceUrl, sourceUrlKey } = storeToRefs(store);
const sourceUrl = computed(() => props.source[sourceUrlKey.value]);
const { savedSourcesMap, currentSourceUrl } = storeToRefs(store);
const sourceUrl = computed(() => getSourceUniqueKey(props.source));
const handleSourceClick = (source) => {
store.changeCurrentSource(source);
};

View File

@ -18,7 +18,7 @@
type="danger"
:icon="Delete"
@click="deleteSelectSources"
:disabled="sourceUrlSelect.length === 0"
:disabled="sourceSelect.length === 0"
>删除</el-button
>
<el-button
@ -43,7 +43,11 @@
<script setup>
import API from "@api";
import { Folder, Delete, Download, Search } from "@element-plus/icons-vue";
import { isSourceContains } from "@utils/souce";
import {
isSourceMatches,
getSourceUniqueKey,
convertSourcesToMap,
} from "@utils/souce";
import VirtualList from "vue3-virtual-scroll-list";
import SourceItem from "./SourceItem.vue";
@ -52,35 +56,50 @@ const sourceUrlSelect = ref([]);
const searchKey = ref("");
const { sources, sourcesMap } = storeToRefs(store);
//
/** @type Ref<import('@/source').Source[]> */
const sourcesFiltered = computed(() => {
const key = searchKey.value;
if (key === "") return sources.value;
return (
sources.value
// @ts-ignore
.filter((source) => isSourceMatches(source, key))
);
});
//
/** @type Ref<import('@/source').Source[]> */
const sourceSelect = computed(() => {
const urls = sourceUrlSelect.value;
if (urls.length == 0) return [];
return urls.map(
(sourceUrl) => sourcesMap.value.get(sourceUrl) ?? {}
);
const sourcesFilteredMap =
searchKey.value == ""
? sourcesMap.value
: convertSourcesToMap(sourcesFiltered.value);
return urls.reduce((sources, sourceUrl) => {
const source = sourcesFilteredMap.get(sourceUrl);
if (source) sources.push(source);
return sources;
}, []);
});
const deleteSelectSources = () => {
const sourceSelectValue = sourceSelect.value;
API.deleteSource(sourceSelectValue).then(({ data }) => {
if (!data.isSuccess) return ElMessage.error(data.errorMsg);
store.deleteSources(sourceSelectValue);
sourceUrlSelect.value = [];
const sourceUrlSelectRawValue = toRaw(sourceUrlSelect.value);
sourceSelectValue.forEach((source) => {
const index = sourceUrlSelectRawValue.indexOf(getSourceUniqueKey(source));
if (index > -1) sourceUrlSelectRawValue.splice(index, 1);
});
sourceUrlSelect.value = sourceUrlSelectRawValue;
});
};
const clearAllSources = () => {
store.clearAllSource();
sourceUrlSelect.value = [];
};
//
const sourcesFiltered = computed(() => {
let key = searchKey.value;
if (key === "") return sources.value;
return (
sources.value
// @ts-ignore
.filter((source) => isSourceContains(source, key))
);
});
//
const importSourceFile = () => {

View File

@ -6,10 +6,10 @@
:name="tab[0]"
:label="tab[1]"
>
<source-json v-show="index == 0" />
<source-debug v-show="index == 1" />
<source-list v-show="index == 2" />
<source-help v-show="index == 3" />
<source-json v-if="index == 0" />
<source-debug v-if="index == 1" />
<source-list v-if="index == 2" />
<source-help v-if="index == 3" />
</el-tab-pane>
</el-tabs>
</template>

View File

@ -1,5 +1,10 @@
import { defineStore } from "pinia";
import { emptyBookSource, emptyRssSource } from "@utils/souce";
import {
emptyBookSource,
emptyRssSource,
getSourceUniqueKey,
convertSourcesToMap,
} from "@utils/souce";
const isBookSource = /bookSource/i.test(location.href);
const emptySource = isBookSource ? emptyBookSource : emptyRssSource;
@ -22,21 +27,9 @@ export const useSourceStore = defineStore("source", {
},
getters: {
sources: (state) => (isBookSource ? state.bookSources : state.rssSources),
sourceUrlKey: () => (isBookSource ? "bookSourceUrl" : "sourceUrl"),
sourcesMap: (state) => {
let map = new Map();
state.sources.forEach((source) =>
map.set(source[state.sourceUrlKey], source)
);
return map;
},
savedSourcesMap: (state) => {
let map = new Map();
state.savedSources.forEach((source) =>
map.set(source[state.sourceUrlKey], source)
);
return map;
},
// @ts-ignore
sourcesMap: (state) => convertSourcesToMap(state.sources),
savedSourcesMap: (state) => convertSourcesToMap(state.savedSources),
currentSourceUrl: (state) =>
isBookSource
? state.currentSource.bookSourceUrl
@ -79,10 +72,10 @@ export const useSourceStore = defineStore("source", {
saveCurrentSource() {
let source = this.currentSource,
map = this.sourcesMap;
map.set(source[this.sourceUrlKey], source);
map.set(getSourceUniqueKey(source), Object.create(source));
this.saveSources(Array.from(map.values()));
},
// 更改当前编辑的源
// 更改当前编辑的源qq
changeCurrentSource(source) {
this.currentSource = JSON.parse(JSON.stringify(source));
},

View File

@ -1,38 +1,49 @@
import { Source } from '../source'
const isNullOrBlank = (string: string | null | undefined | number) => string == null || (string as string).length === 0 || /^\s+$/.test(string as string)
const isBookSource = (source: Source) => "bookSourceName" in source
export const isInvaildSource: (source: Source) => boolean = (source) => {
if (isBookSource(source)) {
return !isNullOrBlank(source.bookSourceName) &&
!isNullOrBlank(source.bookSourceUrl) &&
!isNullOrBlank(source.bookSourceType)
}
return !isNullOrBlank(source.sourceName) &&
!isNullOrBlank(source.sourceName)
}
export const isSourceContains: (source: Source, searchKey: string) => boolean = (source, searchKey) => {
if (isBookSource(source)) {
return (source.bookSourceName?.includes(searchKey) ||
source.bookSourceUrl?.includes(searchKey) ||
source.bookSourceGroup?.includes(searchKey) ||
source.bookSourceComment?.includes(searchKey)) ?? false
}
return (source.sourceName?.includes(searchKey) ||
source.sourceUrl?.includes(searchKey) ||
source.sourceGroup?.includes(searchKey) ||
source.sourceComment?.includes(searchKey)) ?? false
}
export const emptyBookSource = {
ruleSearch: {},
ruleBookInfo: {},
ruleToc: {},
ruleContent: {},
ruleReview: {},
ruleExplore: {}
}
export const emptyRssSource = {}
import { Source } from '../source'
const isNullOrBlank = (string: string | null | undefined | number) => string == null || (string as string).length === 0 || /^\s+$/.test(string as string)
const isBookSource = (source: Source) => "bookSourceName" in source
export const isInvaildSource: (source: Source) => boolean = (source) => {
if (isBookSource(source)) {
return !isNullOrBlank(source.bookSourceName) &&
!isNullOrBlank(source.bookSourceUrl) &&
!isNullOrBlank(source.bookSourceType)
}
return !isNullOrBlank(source.sourceName) &&
!isNullOrBlank(source.sourceName)
}
export const getSourceUniqueKey = (source: Source) => isBookSource(source) ? source.bookSourceUrl : source.sourceUrl;
export const isSourceMatches: (source: Source, searchKey: string) => boolean = (source, searchKey) => {
// TODO: 正则和普通字符串识别 识别 * . \ [ ] <= <! != = ?: () \d\w\s\...
if (isBookSource(source)) {
return (source.bookSourceName?.includes(searchKey) ||
source.bookSourceUrl?.includes(searchKey) ||
source.bookSourceGroup?.includes(searchKey) ||
source.bookSourceComment?.includes(searchKey)) ?? false
}
return (source.sourceName?.includes(searchKey) ||
source.sourceUrl?.includes(searchKey) ||
source.sourceGroup?.includes(searchKey) ||
source.sourceComment?.includes(searchKey)) ?? false
}
export const convertSourcesToMap = (sources: Source[]): Map<string, Source> => {
const map = new Map();
sources.forEach((source) =>
map.set(getSourceUniqueKey(source), source)
);
return map;
}
export const emptyBookSource = {
ruleSearch: {},
ruleBookInfo: {},
ruleToc: {},
ruleContent: {},
ruleReview: {},
ruleExplore: {}
}
export const emptyRssSource = {}

View File

@ -318,7 +318,7 @@ const saveReadingBookProgressToBrowser = (index, pos) => {
* VisibilityChange https://developer.mozilla.org/zh-CN/docs/Web/API/Document/visibilitychange_event
* 监听关闭页面 切换tab 返回桌面 等操作
* 注意不用监听点击链接导航变化 不对Safari<14.5兼容处理
**/
**/
const onVisibilityChange = () => {
if (document.visibilityState == "hidden") {
API.saveBookProgressWithBeacon(bookProgress.value);

View File

@ -10,13 +10,13 @@ import bookSourceConfig from "@/utils/bookSourceEditConfig.js";
import rssSourceConfig from "@/utils/rssSourceEditConfig.js";
import "@/assets/main.css";
const config = ref({});
let config;
if (/bookSource/i.test(location.href)) {
config.value = bookSourceConfig;
config = bookSourceConfig;
document.title = "书源管理";
} else {
config.value = rssSourceConfig;
config = rssSourceConfig;
document.title = "订阅源管理";
}
</script>