|
|
@@ -1,6 +1,6 @@
|
|
|
<script>
|
|
|
import {getBook, getBookContent, getBookListOfRecommend, setBookStatus} from '@/api/knowledge.js';
|
|
|
-import {numberToChinese} from '@/utils/format';
|
|
|
+
|
|
|
|
|
|
export default {
|
|
|
name: 'KnowledgeBookDetail',
|
|
|
@@ -11,6 +11,8 @@ export default {
|
|
|
recommend: [],
|
|
|
|
|
|
containerHeight: 0,
|
|
|
+
|
|
|
+ selected: {},
|
|
|
};
|
|
|
},
|
|
|
computed: {
|
|
|
@@ -28,34 +30,45 @@ export default {
|
|
|
}, 200);
|
|
|
},
|
|
|
methods: {
|
|
|
- async getBook() {
|
|
|
- this.book = await getBook(this.book.id);
|
|
|
- let index = 1;
|
|
|
- const section = [];
|
|
|
- for (const {catalogueName: name, catalogueId: id} of this.book.catalogueList) {
|
|
|
- section.push({
|
|
|
- id,
|
|
|
- name: name === '序' ? name : `第${numberToChinese(index)}章 ${name}`,
|
|
|
- content: '',
|
|
|
- dirty: false,
|
|
|
- });
|
|
|
- if (name !== '序') { index += 1;}
|
|
|
- }
|
|
|
- this.section = section;
|
|
|
- },
|
|
|
async getRecommend() {
|
|
|
try {
|
|
|
this.recommend = await getBookListOfRecommend(this.book.id);
|
|
|
} catch (e) {}
|
|
|
},
|
|
|
- async getContent(data, index, section) {
|
|
|
- try {
|
|
|
- let content = await getBookContent({bookId: this.book.id, catalogueId: data.id});
|
|
|
- content = `  ${(content || '').replace(/\n|\r/g, '<br>  ')}`;
|
|
|
- this.$set(this.section, index, Object.assign(data, {dirty: true, error: '', content}));
|
|
|
- } catch (e) {
|
|
|
- this.$set(this.section, index, Object.assign(data, {dirty: true, error: `出错了(${e})`}));
|
|
|
+ async getBook() {
|
|
|
+ this.book = await getBook(this.book.id);
|
|
|
+ let selected;
|
|
|
+ const get = (list, level = 1) => list.map(item => {
|
|
|
+ const children = Array.isArray(item.children) ? get(item.children, level + 1) : [];
|
|
|
+ const isLeaf = !children.length;
|
|
|
+ const section = {
|
|
|
+ id: item.catalogueId,
|
|
|
+ name: item.catalogueName,
|
|
|
+ children, isLeaf, level,
|
|
|
+ content: isLeaf ? '' : void 0,
|
|
|
+ dirty: !isLeaf,
|
|
|
+ }
|
|
|
+ if (section.isLeaf && !selected) selected = section;
|
|
|
+ return section;
|
|
|
+ });
|
|
|
+ this.section = get(this.book.catalogueList);
|
|
|
+ await this.load(selected);
|
|
|
+ },
|
|
|
+ async load(section) {
|
|
|
+ if (!section.isLeaf) return;
|
|
|
+
|
|
|
+ this.selected = {...section};
|
|
|
+ if (!section.dirty) {
|
|
|
+ try {
|
|
|
+ section.content = await getBookContent({bookId: this.book.id, catalogueId: section.id});
|
|
|
+ section.dirty = true;
|
|
|
+ this.$set(this.selected, 'content', section.content);
|
|
|
+ this.$set(this.selected, 'dirty', section.dirty);
|
|
|
+ } catch (e) {}
|
|
|
}
|
|
|
+ this.$nextTick(() => {
|
|
|
+ document.querySelector(`#scrolling`).scrollTo({top: 0, behavior: 'smooth'});
|
|
|
+ });
|
|
|
},
|
|
|
async collected() {
|
|
|
try {
|
|
|
@@ -67,16 +80,6 @@ export default {
|
|
|
|
|
|
}
|
|
|
},
|
|
|
- load(ids) {
|
|
|
- if (ids && !Array.isArray(ids)) {ids = [ids];}
|
|
|
- for (const id of ids) {
|
|
|
- const index = this.section.findIndex(item => item.id === id);
|
|
|
- const data = this.section[index];
|
|
|
- if (data.dirty || data.content) continue;
|
|
|
- this.$set(this.section, index, Object.assign(data, {dirty: true, error: ''}));
|
|
|
- this.getContent(data, index, this.section);
|
|
|
- }
|
|
|
- },
|
|
|
async onPreview(book) {
|
|
|
if (book) {
|
|
|
await this.$router.push({path: `/index/knowledge/book/detail?id=${book.id}`});
|
|
|
@@ -118,14 +121,22 @@ export default {
|
|
|
</div>
|
|
|
<el-divider content-position="left">阅读<span v-if="book.readProgress">:{{ book.readProgress }}%</span>
|
|
|
</el-divider>
|
|
|
- <el-collapse style="margin: 0 12px;" @change="load">
|
|
|
- <el-collapse-item v-for="item in section" :key="item.id" :title="item.name" :name="item.id">
|
|
|
- <div class="book-content-container" v-loading="!item.content">
|
|
|
- <div v-html="item.content"></div>
|
|
|
+ <div class="book-content-container" :style="{maxHeight: containerHeight}" :class="{scrollable: true}">
|
|
|
+ <div class="catalogue">
|
|
|
+ <div v-for="item in section" :key="item.id"
|
|
|
+ :class="['level-' + item.level, item.isLeaf ? 'section' : 'title']">
|
|
|
+ <span :class="{active: item.id === selected.id}" @click="load(item)">{{ item.name }}</span>
|
|
|
+ <div v-for="item in item.children" :key="item.id"
|
|
|
+ :class="['level-' + item.level, item.isLeaf ? 'section' : 'title']">
|
|
|
+ <span :class="{active: item.id === selected.id}" @click="load(item)">{{ item.name }}</span>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </el-collapse-item>
|
|
|
- </el-collapse>
|
|
|
- <el-backtop style="right: 300px;" target=".detail-wrapper"></el-backtop>
|
|
|
+ </div>
|
|
|
+ <div class="content" id="scrolling" :style="{height: containerHeight}" v-loading="!selected.dirty">
|
|
|
+ <div class="text" v-html="selected.content"></div>
|
|
|
+ <el-backtop style="right: 300px;" target="#scrolling"></el-backtop>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
<el-card header="相关医书">
|
|
|
<div class="book-wrapper" style="margin-bottom: 24px;" v-for="book in recommend" :key="book.id"
|
|
|
@@ -151,6 +162,7 @@ export default {
|
|
|
.detail-wrapper {
|
|
|
flex: auto;
|
|
|
overflow-y: auto;
|
|
|
+ height: 100%;
|
|
|
padding: 0 24px;
|
|
|
|
|
|
.header {
|
|
|
@@ -214,7 +226,49 @@ export default {
|
|
|
}
|
|
|
|
|
|
.book-content-container {
|
|
|
- min-height: 80px;
|
|
|
+ display: flex;
|
|
|
+
|
|
|
+ &.scrollable > div {
|
|
|
+ overflow-y: auto;
|
|
|
+ }
|
|
|
+
|
|
|
+ .catalogue {
|
|
|
+ flex: 1 0;
|
|
|
+ user-select: none;
|
|
|
+
|
|
|
+
|
|
|
+ .title {
|
|
|
+ margin: 24px 0;
|
|
|
+ color: #213547;
|
|
|
+ > span {
|
|
|
+ pointer-events: none;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .section {
|
|
|
+ margin: 6px 0;
|
|
|
+ color: #3c3c3cb3;
|
|
|
+
|
|
|
+ &:hover, .active {
|
|
|
+ cursor: pointer;
|
|
|
+ color: #5386f6;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .content {
|
|
|
+ flex: 4 4;
|
|
|
+
|
|
|
+ > .text {
|
|
|
+ padding: 24px;
|
|
|
+ line-height: 2.5;
|
|
|
+ white-space: pre-wrap;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ::v-deep.el-loading-mask {
|
|
|
+ background-color: transparent;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
.book-wrapper {
|