123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- <template>
- <Drawer v-model:visible="show" title="书签" @close="emits('close')">
- <div class="bookmark">
- <el-button class="bookmark__add" :icon="Plus" @click="addBookmark" />
- <p class="bookmark__title">总数:{{ list.length }}</p>
- <div v-loading="loading" class="bookmark-list">
- <div v-for="(item, idx) in list" :key="item.id" class="bookmark-item">
- <div class="bookmark-item__inner" @click="goToDetail(item)">
- <p>书签</p>
- <p>{{ item.createTime }}</p>
- </div>
- <svg-icon
- class="bookmark-item__close"
- name="icon_delete"
- width="24px"
- height="24px"
- color="var(--el-color-primary)"
- @click="handleDelete(item, idx)"
- />
- </div>
- <el-empty v-if="!list.length && !loading" description="暂无数据" />
- </div>
- </div>
- </Drawer>
- </template>
- <script setup>
- import { computed, ref, watch } from "vue";
- import { Plus } from "@element-plus/icons-vue";
- import { saveLabelApi, getLabelListApi, deleteLabelApi } from "@/api";
- import { useEpubStore, useDetailStore } from "@/stores";
- import Drawer from "./Drawer.vue";
- const props = defineProps(["visible"]);
- const emits = defineEmits(["update:visible", "close"]);
- const epubStore = useEpubStore();
- const detailStore = useDetailStore();
- const list = ref([]);
- const loading = ref(false);
- const show = computed({
- get() {
- return props.visible;
- },
- set(v) {
- emits("update:visible", v);
- },
- });
- const addBookmark = async () => {
- const { startCfi, page } = await epubStore.refreshLocation();
- const data = await saveLabelApi({
- type: "label",
- bookId: detailStore.detail.id,
- content: JSON.stringify({
- location: startCfi,
- page,
- }),
- });
- list.value.push({ ...data, content: JSON.parse(data.content) });
- };
- const getLabelList = async () => {
- try {
- loading.value = true;
- const data = await getLabelListApi(detailStore.detail.id, "label");
- list.value = data.map((i) => ({
- ...i,
- content: JSON.parse(i.content),
- }));
- } finally {
- loading.value = false;
- }
- };
- const goToDetail = (item) => {
- epubStore.goToChapter(item.content.location, item.content.page);
- };
- const handleDelete = (item, idx) => {
- list.value.splice(idx, 1);
- deleteLabelApi(item.id);
- };
- watch(show, (v) => {
- if (v && !list.value.length) {
- getLabelList();
- }
- });
- </script>
- <style lang="scss" scoped>
- .bookmark {
- position: relative;
- padding: 0 30px;
- &__add {
- position: absolute;
- top: -15px;
- right: 30px;
- }
- &__title {
- padding-bottom: 3px;
- border-bottom: 1px solid #d9d9d9;
- }
- &-list {
- padding: 7.5px 0;
- min-height: 300px;
- }
- &-item {
- position: relative;
- margin: 7.5px 0;
- padding-left: 17px;
- display: flex;
- align-items: center;
- &__inner {
- flex: 1;
- cursor: pointer;
- p:last-child {
- color: var(--text-color-placeholder);
- }
- }
- &__close {
- cursor: pointer;
- }
- &::before {
- content: "";
- position: absolute;
- top: 50%;
- left: 0;
- width: 5px;
- height: 31px;
- background: var(--el-color-primary);
- transform: translateY(-50%);
- }
- }
- }
- </style>
|