SourceList.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. <template>
  2. <el-input
  3. v-model="searchKey"
  4. class="search"
  5. :prefix-icon="Search"
  6. placeholder="筛选源"
  7. />
  8. <div class="tool">
  9. <el-button @click="importSourceFile" :icon="Folder">打开</el-button>
  10. <el-button
  11. :disabled="sourcesFiltered.length === 0"
  12. @click="outExport"
  13. :icon="Download"
  14. >
  15. 导出</el-button
  16. >
  17. <el-button
  18. type="danger"
  19. :icon="Delete"
  20. @click="deleteSelectSources"
  21. :disabled="sourceSelect.length === 0"
  22. >删除</el-button
  23. >
  24. <el-button
  25. type="danger"
  26. :icon="Delete"
  27. @click="clearAllSources"
  28. :disabled="sources.length === 0"
  29. >清空</el-button
  30. >
  31. </div>
  32. <el-checkbox-group id="source-list" v-model="sourceSelect">
  33. <virtual-list
  34. style="height: 100%; overflow-y: auto; overflow-x: hidden"
  35. :data-key="(source) => source.bookSourceUrl || source.sourceUrl"
  36. :data-sources="sourcesFiltered"
  37. :data-component="SourceItem"
  38. :estimate-size="45"
  39. />
  40. </el-checkbox-group>
  41. </template>
  42. <script setup>
  43. import API from "@api";
  44. import { Folder, Delete, Download, Search } from "@element-plus/icons-vue";
  45. import { isSourceContains } from "@utils/souce";
  46. import VirtualList from "vue3-virtual-scroll-list";
  47. import SourceItem from "./SourceItem.vue";
  48. const store = useSourceStore();
  49. const sourceSelect = ref([]);
  50. const searchKey = ref("");
  51. const { sources } = storeToRefs(store);
  52. const isBookSource = computed(() => {
  53. return /bookSource/.test(window.location.href);
  54. });
  55. const deleteSelectSources = () => {
  56. API.deleteSource(sourceSelect.value).then(({ data }) => {
  57. if (!data.isSuccess) return ElMessage.error(data.errorMsg);
  58. store.deleteSources(sourceSelect.value);
  59. sourceSelect.value = [];
  60. });
  61. };
  62. const clearAllSources = () => {
  63. store.clearAllSource();
  64. sourceSelect.value = [];
  65. };
  66. //筛选源
  67. const sourcesFiltered = computed(() => {
  68. let key = searchKey.value;
  69. if (key === "") return sources.value;
  70. return (
  71. sources.value
  72. // @ts-ignore
  73. .filter((source) => isSourceContains(source, key))
  74. );
  75. });
  76. //导入本地文件
  77. const importSourceFile = () => {
  78. const input = document.createElement("input");
  79. input.type = "file";
  80. input.accept = ".json,.txt";
  81. input.addEventListener("change", (e) => {
  82. // @ts-ignore
  83. const file = e.target.files[0];
  84. var reader = new FileReader();
  85. reader.readAsText(file);
  86. reader.onload = () => {
  87. try {
  88. // @ts-ignore
  89. const jsonData = JSON.parse(reader.result);
  90. store.saveSources(jsonData);
  91. } catch {
  92. ElMessage({
  93. message: "上传的源格式错误",
  94. type: "error",
  95. });
  96. }
  97. };
  98. });
  99. input.click();
  100. };
  101. const outExport = () => {
  102. const exportFile = document.createElement("a");
  103. let sources =
  104. sourceSelect.value.length === 0
  105. ? sourcesFiltered.value
  106. : sourceSelect.value,
  107. sourceType = isBookSource.value ? "BookSource" : "RssSource";
  108. exportFile.download = `${sourceType}_${Date()
  109. .replace(/.*?\s(\d+)\s(\d+)\s(\d+:\d+:\d+).*/, "$2$1$3")
  110. .replace(/:/g, "")}.json`;
  111. let myBlob = new Blob([JSON.stringify(sources, null, 4)], {
  112. type: "application/json",
  113. });
  114. exportFile.href = window.URL.createObjectURL(myBlob);
  115. exportFile.click();
  116. };
  117. </script>
  118. <style lang="scss" scoped>
  119. .tool {
  120. display: flex;
  121. margin: 4px 0;
  122. justify-content: center;
  123. }
  124. #source-list {
  125. margin-top: 6px;
  126. height: calc(100vh - 112px - 7px);
  127. :deep(.el-checkbox) {
  128. margin-bottom: 4px;
  129. width: 100%;
  130. }
  131. }
  132. </style>