├── .browserslistrc
├── .editorconfig
├── .env.development
├── .eslintrc.js
├── .gitignore
├── README.md
├── babel.config.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
├── favicon.ico
├── fonts
│ ├── cabin.css
│ ├── cabin.woff2
│ ├── daysOne.css
│ ├── daysOne.woff2
│ ├── montserrat.css
│ ├── montserrat.woff2
│ ├── tangerine.css
│ └── tangerine.woff2
└── index.html
├── src
├── App.vue
├── api
│ └── store.js
├── assets
│ ├── fonts
│ │ ├── cabin.css
│ │ ├── cabin.woff2
│ │ ├── daysOne.css
│ │ ├── daysOne.woff2
│ │ ├── montserrat.css
│ │ ├── montserrat.woff2
│ │ ├── tangerine.css
│ │ └── tangerine.woff2
│ ├── images
│ │ ├── compass-left.png
│ │ ├── compass-right.png
│ │ ├── crown-left.png
│ │ ├── crown-right.png
│ │ ├── gift-left.png
│ │ ├── gift-right.png
│ │ ├── heart-left.png
│ │ ├── heart-right.png
│ │ ├── star-left.png
│ │ └── star-right.png
│ ├── logo.png
│ └── styles
│ │ ├── flapCard.scss
│ │ ├── fonts
│ │ ├── icomoon.eot
│ │ ├── icomoon.svg
│ │ ├── icomoon.ttf
│ │ └── icomoon.woff
│ │ ├── global.scss
│ │ ├── home.scss
│ │ ├── icon.css
│ │ ├── mixin.scss
│ │ ├── reset.scss
│ │ └── transition.scss
├── components
│ ├── common
│ │ ├── Dialog.vue
│ │ ├── Popup.vue
│ │ ├── Scroll.vue
│ │ ├── Toast.vue
│ │ └── bookmark.vue
│ ├── detail
│ │ ├── BookInfo.vue
│ │ └── DetaiTitle.vue
│ ├── ebook
│ │ ├── EbookBookmark.vue
│ │ ├── EbookFooter.vue
│ │ ├── EbookHeader.vue
│ │ ├── EbookLoading.vue
│ │ ├── EbookMenu.vue
│ │ ├── EbookReader.vue
│ │ ├── EbookSettingFont.vue
│ │ ├── EbookSettingFontPopup.vue
│ │ ├── EbookSettingProgess.vue
│ │ ├── EbookSettingTheme.vue
│ │ ├── EbookSlide.vue
│ │ ├── EbookSlideBookmark.vue
│ │ ├── EbookSlideContents.vue
│ │ └── EbookTitle.vue
│ ├── home
│ │ ├── Category.vue
│ │ ├── CategoryBook.vue
│ │ ├── Featured.vue
│ │ ├── FlapCard.vue
│ │ ├── GuessYouLike.vue
│ │ ├── HotSearch.vue
│ │ ├── HotSearchList.vue
│ │ ├── Recommend.vue
│ │ ├── SearchBar.vue
│ │ └── Title.vue
│ ├── shelf
│ │ ├── A.vue
│ │ ├── ShelfGroupDialog.vue
│ │ ├── ShelfItem.vue
│ │ ├── ShelfItemAdd.vue
│ │ ├── ShelfItemBook.vue
│ │ ├── ShelfItemCategory.vue
│ │ ├── ShelfList.vue
│ │ ├── ShelfSearch.vue
│ │ ├── ShelfTitle.vue
│ │ └── shelfFooter.vue
│ └── speak
│ │ ├── SpeakBottom.vue
│ │ ├── SpeakMask.vue
│ │ └── SpeakPlaying.vue
├── lang
│ ├── cn.js
│ ├── en.js
│ └── index.js
├── main.js
├── mock
│ ├── bookCategoryList.js
│ ├── bookFlatList.js
│ ├── bookHome.js
│ ├── bookList.js
│ ├── bookShelf.js
│ └── index.js
├── router.js
├── store
│ ├── actions.js
│ ├── getters.js
│ ├── index.js
│ └── modules
│ │ ├── book.js
│ │ └── store.js
├── utils
│ ├── book.js
│ ├── boost.js
│ ├── create-api.js
│ ├── localForage.js
│ ├── localstorage.js
│ ├── mixin.js
│ ├── store.js
│ └── utils.js
└── views
│ ├── ebook
│ └── index.vue
│ └── store
│ ├── StoreCategory.vue
│ ├── StoreDetail.vue
│ ├── StoreHome.vue
│ ├── StoreList.vue
│ ├── StoreShelf.vue
│ ├── StoreSpeaking.vue
│ └── index.vue
├── vue.config.js
└── 项目总结.md
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 | not ie <= 8
4 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{js,jsx,ts,tsx,vue}]
2 | indent_style = space
3 | indent_size = 2
4 | trim_trailing_whitespace = true
5 | insert_final_newline = true
6 |
--------------------------------------------------------------------------------
/.env.development:
--------------------------------------------------------------------------------
1 | VUE_APP_RES_URL=http://192.168.0.174:9000
2 | VUE_APP_EPUB_URL=http://47.99.166.157/epub
3 | VUE_APP_BASE_URL=http://192.168.0.174:8080
4 | VUE_APP_BOOK_URL=//47.99.166.157:3000
5 | VUE_APP_EPUB_OPF_URL=http://47.99.166.157/epub2
6 | VUE_APP_VOICE_URL=http://47.99.166.157:3000
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true
5 | },
6 | 'extends': [
7 | 'plugin:vue/essential',
8 | '@vue/standard'
9 | ],
10 | rules: {
11 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
12 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
13 | 'indent': 'off',
14 | 'space-before-function-paren': 'off'
15 | },
16 | parserOptions: {
17 | parser: 'babel-eslint'
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw*
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue-ebook
2 |
3 | ## Project setup
4 | ```
5 | npm install
6 | ```
7 |
8 | ### Compiles and hot-reloads for development
9 | ```
10 | npm run serve
11 | ```
12 |
13 | ### Compiles and minifies for production
14 | ```
15 | npm run build
16 | ```
17 |
18 | ### Run your tests
19 | ```
20 | npm run test
21 | ```
22 |
23 | ### Lints and fixes files
24 | ```
25 | npm run lint
26 | ```
27 |
28 | ### Customize configuration
29 | See [Configuration Reference](https://cli.vuejs.org/config/).
30 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/app'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-ebook",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint"
9 | },
10 | "dependencies": {
11 | "axios": "^0.18.0",
12 | "epubjs": "^0.3.81",
13 | "localforage": "^1.7.3",
14 | "vue": "^2.5.17",
15 | "vue-create-api": "^0.2.0",
16 | "vue-i18n": "^8.4.0",
17 | "vue-router": "^3.0.1",
18 | "vuex": "^3.0.1",
19 | "web-storage-cache": "^1.0.3"
20 | },
21 | "devDependencies": {
22 | "@vue/cli-plugin-babel": "^3.2.0",
23 | "@vue/cli-plugin-eslint": "^3.2.0",
24 | "@vue/cli-service": "^3.2.0",
25 | "@vue/eslint-config-standard": "^4.0.0",
26 | "babel-eslint": "^10.0.1",
27 | "eslint": "^5.8.0",
28 | "eslint-plugin-vue": "^5.0.0-0",
29 | "mockjs": "^1.0.1-beta3",
30 | "node-sass": "^4.10.0",
31 | "sass-loader": "^7.1.0",
32 | "vue-template-compiler": "^2.5.17"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {}
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jack97github/Ebook/4415489bc0a607071b20652277e5e0eed14f648a/public/favicon.ico
--------------------------------------------------------------------------------
/public/fonts/cabin.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'Cabin';
3 | font-style: normal;
4 | font-weight: 400;
5 | src: url('cabin.woff2') format('woff2');
6 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
7 | }
8 |
--------------------------------------------------------------------------------
/public/fonts/cabin.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jack97github/Ebook/4415489bc0a607071b20652277e5e0eed14f648a/public/fonts/cabin.woff2
--------------------------------------------------------------------------------
/public/fonts/daysOne.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'Days One';
3 | font-style: normal;
4 | font-weight: 400;
5 | src: url('daysOne.woff2') format('woff2');
6 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
7 | }
8 |
--------------------------------------------------------------------------------
/public/fonts/daysOne.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jack97github/Ebook/4415489bc0a607071b20652277e5e0eed14f648a/public/fonts/daysOne.woff2
--------------------------------------------------------------------------------
/public/fonts/montserrat.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'Montserrat';
3 | font-style: normal;
4 | font-weight: 400;
5 | src: url('montserrat.woff2') format('woff2');
6 | unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
7 | }
8 |
--------------------------------------------------------------------------------
/public/fonts/montserrat.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jack97github/Ebook/4415489bc0a607071b20652277e5e0eed14f648a/public/fonts/montserrat.woff2
--------------------------------------------------------------------------------
/public/fonts/tangerine.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'Tangerine';
3 | font-style: normal;
4 | font-weight: 400;
5 | src: url('tangerine.woff2') format('woff2');
6 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
7 | }
8 |
--------------------------------------------------------------------------------
/public/fonts/tangerine.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jack97github/Ebook/4415489bc0a607071b20652277e5e0eed14f648a/public/fonts/tangerine.woff2
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | vue-ebook
10 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
16 |
17 |
25 |
--------------------------------------------------------------------------------
/src/api/store.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import { setLocalForage } from '../utils/localForage'
3 |
4 | export function flatList() {
5 | return axios({
6 | method: 'get',
7 | url: `${process.env.VUE_APP_BOOK_URL}/book/flat-list`
8 | })
9 | }
10 |
11 | export function shelf() {
12 | return axios({
13 | method: 'get',
14 | url: `${process.env.VUE_APP_BASE_URL}/book/shelf`
15 | })
16 | }
17 |
18 | export function home() {
19 | return axios({
20 | method: 'get',
21 | url: `${process.env.VUE_APP_BASE_URL}/book/home`
22 | })
23 | }
24 |
25 | export function detail(book) {
26 | return axios({
27 | method: 'get',
28 | url: `${process.env.VUE_APP_BOOK_URL}/book/detail`,
29 | params: {
30 | fileName: book.fileName
31 | }
32 | })
33 | }
34 |
35 | export function list() {
36 | return axios({
37 | method: 'get',
38 | url: `${process.env.VUE_APP_BASE_URL}/book/list`
39 | })
40 | }
41 |
42 | export function download(book, onSucess, onError, onProgress) {
43 | if (onProgress == null) {
44 | onProgress = onError
45 | onError = null
46 | }
47 | return axios.create({
48 | baseURL: process.env.VUE_APP_EPUB_URL,
49 | method: 'get',
50 | responseType: 'blob',
51 | timeout: 180 * 1000,
52 | onDownloadProgress: progressEvent => {
53 | if (onProgress) onProgress(progressEvent)
54 | }
55 | }).get(`${book.categoryText}/${book.fileName}.epub`)
56 | .then(res => {
57 | const blob = new Blob([res.data])
58 | setLocalForage(book.fileName, blob,
59 | () => onSucess(book),
60 | err => onError(err))
61 | }).catch(err => {
62 | if (onError) onError(err)
63 | })
64 | }
65 |
--------------------------------------------------------------------------------
/src/assets/fonts/cabin.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'Cabin';
3 | font-style: normal;
4 | font-weight: 400;
5 | src: url('cabin.woff2') format('woff2');
6 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
7 | }
8 |
--------------------------------------------------------------------------------
/src/assets/fonts/cabin.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jack97github/Ebook/4415489bc0a607071b20652277e5e0eed14f648a/src/assets/fonts/cabin.woff2
--------------------------------------------------------------------------------
/src/assets/fonts/daysOne.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'Days One';
3 | font-style: normal;
4 | font-weight: 400;
5 | src: url('daysOne.woff2') format('woff2');
6 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
7 | }
8 |
--------------------------------------------------------------------------------
/src/assets/fonts/daysOne.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jack97github/Ebook/4415489bc0a607071b20652277e5e0eed14f648a/src/assets/fonts/daysOne.woff2
--------------------------------------------------------------------------------
/src/assets/fonts/montserrat.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'Montserrat';
3 | font-style: normal;
4 | font-weight: 400;
5 | src: url('montserrat.woff2') format('woff2');
6 | unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
7 | }
8 |
--------------------------------------------------------------------------------
/src/assets/fonts/montserrat.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jack97github/Ebook/4415489bc0a607071b20652277e5e0eed14f648a/src/assets/fonts/montserrat.woff2
--------------------------------------------------------------------------------
/src/assets/fonts/tangerine.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'Tangerine';
3 | font-style: normal;
4 | font-weight: 400;
5 | src: url('tangerine.woff2') format('woff2');
6 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
7 | }
8 |
--------------------------------------------------------------------------------
/src/assets/fonts/tangerine.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jack97github/Ebook/4415489bc0a607071b20652277e5e0eed14f648a/src/assets/fonts/tangerine.woff2
--------------------------------------------------------------------------------
/src/assets/images/compass-left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jack97github/Ebook/4415489bc0a607071b20652277e5e0eed14f648a/src/assets/images/compass-left.png
--------------------------------------------------------------------------------
/src/assets/images/compass-right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jack97github/Ebook/4415489bc0a607071b20652277e5e0eed14f648a/src/assets/images/compass-right.png
--------------------------------------------------------------------------------
/src/assets/images/crown-left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jack97github/Ebook/4415489bc0a607071b20652277e5e0eed14f648a/src/assets/images/crown-left.png
--------------------------------------------------------------------------------
/src/assets/images/crown-right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jack97github/Ebook/4415489bc0a607071b20652277e5e0eed14f648a/src/assets/images/crown-right.png
--------------------------------------------------------------------------------
/src/assets/images/gift-left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jack97github/Ebook/4415489bc0a607071b20652277e5e0eed14f648a/src/assets/images/gift-left.png
--------------------------------------------------------------------------------
/src/assets/images/gift-right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jack97github/Ebook/4415489bc0a607071b20652277e5e0eed14f648a/src/assets/images/gift-right.png
--------------------------------------------------------------------------------
/src/assets/images/heart-left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jack97github/Ebook/4415489bc0a607071b20652277e5e0eed14f648a/src/assets/images/heart-left.png
--------------------------------------------------------------------------------
/src/assets/images/heart-right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jack97github/Ebook/4415489bc0a607071b20652277e5e0eed14f648a/src/assets/images/heart-right.png
--------------------------------------------------------------------------------
/src/assets/images/star-left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jack97github/Ebook/4415489bc0a607071b20652277e5e0eed14f648a/src/assets/images/star-left.png
--------------------------------------------------------------------------------
/src/assets/images/star-right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jack97github/Ebook/4415489bc0a607071b20652277e5e0eed14f648a/src/assets/images/star-right.png
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jack97github/Ebook/4415489bc0a607071b20652277e5e0eed14f648a/src/assets/logo.png
--------------------------------------------------------------------------------
/src/assets/styles/flapCard.scss:
--------------------------------------------------------------------------------
1 | @import "mixin";
2 |
3 | $color-green: rgb(59, 201, 22);
4 | $color-pink: rgb(255, 102, 159);
5 | $color-blue: rgb(74, 171, 255);
6 | $color-yellow: rgb(255, 198, 102);
7 | $color-green-transparent: rgba(59, 201, 22, .5);
8 | $color-pink-transparent: rgba(255, 102, 159, .5);
9 | $color-blue-transparent: rgba(74, 171, 255, .5);
10 | $color-yellow-transparent: rgba(255, 198, 102, .5);
11 |
12 | $moves: (
13 | (startX: 0, startY: 0, endX: 0, endY: 55, width: 6, height: 6, background: $color-green),
14 | (startX: 0, startY: 0, endX: 15, endY: 60, width: 4, height: 4, background: $color-pink-transparent),
15 | (startX: 0, startY: 0, endX: 35, endY: 45, width: 4, height: 4, background: $color-blue-transparent),
16 | (startX: 0, startY: 0, endX: 50, endY: 25, width: 6, height: 6, background: $color-yellow),
17 | (startX: 0, startY: 0, endX: 60, endY: 0, width: 2, height: 2, background: $color-pink-transparent),
18 | (startX: 0, startY: 0, endX: 50, endY: -25, width: 6, height: 6, background: $color-blue),
19 | (startX: 0, startY: 0, endX: 40, endY: -30, width: 3, height: 3, background: $color-green-transparent),
20 | (startX: 0, startY: 0, endX: 20, endY: -55, width: 5, height: 5, background: $color-pink),
21 | (startX: 0, startY: 0, endX: 5, endY: -45, width: 4, height: 4, background: $color-green-transparent),
22 | (startX: 0, startY: 0, endX: -20, endY: -50, width: 2, height: 2, background: $color-pink-transparent),
23 | (startX: 0, startY: 0, endX: -40, endY: -50, width: 2, height: 2, background: $color-green-transparent),
24 | (startX: 0, startY: 0, endX: -55, endY: -30, width: 4, height: 4, background: $color-blue),
25 | (startX: 0, startY: 0, endX: -55, endY: -10, width: 3, height: 3, background: $color-yellow-transparent),
26 | (startX: 0, startY: 0, endX: -55, endY: -5, width: 3, height: 3, background: $color-green-transparent),
27 | (startX: 0, startY: 0, endX: -35, endY: -7, width: 2, height: 2, background: $color-pink-transparent),
28 | (startX: 0, startY: 0, endX: -45, endY: 10, width: 4, height: 4, background: $color-yellow-transparent),
29 | (startX: 0, startY: 0, endX: -50, endY: 25, width: 6, height: 6, background: $color-pink),
30 | (startX: 0, startY: 0, endX: -40, endY: 35, width: 4, height: 4, background: $color-green-transparent)
31 | );
32 |
33 | @mixin move($index) {
34 | $item: nth($moves, $index);
35 | $keyframesName: "move" + $index;
36 | $animationTime: .5s;
37 | $animationType: linear;
38 | $animationIterator: 1;
39 | $width: map-get($item, width);
40 | $height: map-get($item, height);
41 | $backgroud: map-get($item, background);
42 | $startX: map-get($item, startX);
43 | $startY: map-get($item, startY);
44 | $endX: map-get($item, endX);
45 | $endY: map-get($item, endY);
46 |
47 | width: px2rem($width);
48 | height: px2rem($height);
49 | background: $backgroud;
50 | animation: #{$keyframesName} $animationTime $animationType $animationIterator;
51 | @keyframes #{$keyframesName} {
52 | 0% {
53 | transform: translate3d(px2rem($startX), px2rem($startY), 0) scale(0);
54 | opacity: 0;
55 | }
56 | 50% {
57 | transform: translate3d(px2rem($endX * 0.5), px2rem($endY * 0.5), 0) scale(.5);
58 | opacity: 1;
59 | }
60 | 90% {
61 | transform: translate3d(px2rem($endX), px2rem($endY), 0) scale(1);
62 | opacity: 1;
63 | }
64 | 100% {
65 | transform: translate3d(px2rem($endX * 1.05), px2rem($endY * 1.05), 0) scale(1);
66 | opacity: 0;
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/assets/styles/fonts/icomoon.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jack97github/Ebook/4415489bc0a607071b20652277e5e0eed14f648a/src/assets/styles/fonts/icomoon.eot
--------------------------------------------------------------------------------
/src/assets/styles/fonts/icomoon.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jack97github/Ebook/4415489bc0a607071b20652277e5e0eed14f648a/src/assets/styles/fonts/icomoon.ttf
--------------------------------------------------------------------------------
/src/assets/styles/fonts/icomoon.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jack97github/Ebook/4415489bc0a607071b20652277e5e0eed14f648a/src/assets/styles/fonts/icomoon.woff
--------------------------------------------------------------------------------
/src/assets/styles/global.scss:
--------------------------------------------------------------------------------
1 | @import "./reset";
2 | @import "./mixin";
3 | @import "./transition";
4 | @import "./home";
5 | @import "./flapCard"
--------------------------------------------------------------------------------
/src/assets/styles/home.scss:
--------------------------------------------------------------------------------
1 | @import "./mixin";
2 |
3 | $text-large: px2rem(18);
4 | $text-big: px2rem(16);
5 | $text-medium: px2rem(14);
6 | $text-small: px2rem(12);
7 | $text-tiny: px2rem(10);
8 |
9 | $text-large-lh: px2rem(20);
10 | $text-big-lh: px2rem(18);
11 | $text-medium-lh: px2rem(16);
12 | $text-small-lh: px2rem(15);
13 | $text-tiny-lh: px2rem(12);
14 |
15 | $text-big-max-height3: px2rem(54);
16 | $text-medium-max-height3: px2rem(48);
17 | $text-samll-max-height3: px2rem(42);
18 | $text-big-max-height2: px2rem(36);
19 | $text-medium-max-height2: px2rem(32);
20 | $text-medium-max-height: px2rem(16);
21 | $text-small-max-height2: px2rem(30);
22 | $text-small-max-height: px2rem(15);
23 | $text-tiny-max-height: px2rem(12);
24 |
25 | .title-big {
26 | line-height: $text-big-lh;
27 | font-size: $text-big;
28 | max-height: $text-big-max-height2;
29 | color: #444;
30 | font-weight: bold;
31 | @include ellipsis2(3);
32 | }
33 | .title-medium {
34 | font-size: $text-medium;
35 | line-height: $text-medium-lh;
36 | max-height: $text-medium-max-height2;
37 | color: #444;
38 | font-weight: bold;
39 | @include ellipsis2(3);
40 | }
41 | .title-small {
42 | font-size: $text-small;
43 | line-height: $text-small-lh;
44 | max-height: $text-small-max-height2;
45 | color: #444;
46 | font-weight: bold;
47 | @include ellipsis2(2);
48 | }
49 | .sub-title-medium {
50 | line-height: $text-medium-lh;
51 | font-size: $text-medium;
52 | max-height: $text-medium-max-height2;
53 | color: #666;
54 | @include ellipsis2(2);
55 | }
56 | .sub-title {
57 | line-height: $text-small-lh;
58 | font-size: $text-small;
59 | max-height: $text-small-max-height;
60 | color: #666;
61 | @include ellipsis2(1);
62 | }
63 | .sub-title-tiny {
64 | line-height: $text-tiny-lh;
65 | font-size: $text-tiny;
66 | max-height: $text-tiny-max-height;
67 | color: #666;
68 | @include ellipsis2(1);
69 | }
70 | .third-title {
71 | line-height: $text-small-lh;
72 | font-size: $text-small;
73 | max-height: $text-small-max-height;
74 | color: #999;
75 | @include ellipsis2(1);
76 | }
77 | .third-title-tiny {
78 | line-height: $text-tiny-lh;
79 | font-size: $text-tiny;
80 | max-height: $text-tiny-max-height;
81 | color: #999;
82 | @include ellipsis2(1);
83 | }
84 |
--------------------------------------------------------------------------------
/src/assets/styles/icon.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'icomoon';
3 | src: url('fonts/icomoon.eot?eu5z6r');
4 | src: url('fonts/icomoon.eot?eu5z6r#iefix') format('embedded-opentype'),
5 | url('fonts/icomoon.ttf?eu5z6r') format('truetype'),
6 | url('fonts/icomoon.woff?eu5z6r') format('woff'),
7 | url('fonts/icomoon.svg?eu5z6r#icomoon') format('svg');
8 | font-weight: normal;
9 | font-style: normal;
10 | }
11 |
12 | [class^="icon-"], [class*=" icon-"] {
13 | /* use !important to prevent issues with browser extensions that change fonts */
14 | font-family: 'icomoon' !important;
15 | speak: none;
16 | font-style: normal;
17 | font-weight: normal;
18 | font-variant: normal;
19 | text-transform: none;
20 | line-height: 1;
21 |
22 | /* Better Font Rendering =========== */
23 | -webkit-font-smoothing: antialiased;
24 | -moz-osx-font-smoothing: grayscale;
25 | }
26 |
27 | .icon-A:before {
28 | content: "\e900";
29 | }
30 | .icon-add:before {
31 | content: "\e901";
32 | }
33 | .icon-back:before {
34 | content: "\e902";
35 | }
36 | .icon-book:before {
37 | content: "\e903";
38 | }
39 | .icon-book2:before {
40 | content: "\e904";
41 | }
42 | .icon-bookmark:before {
43 | content: "\e905";
44 | }
45 | .icon-bright:before {
46 | content: "\e906";
47 | }
48 | .icon-cart:before {
49 | content: "\e907";
50 | }
51 | .icon-check:before {
52 | content: "\e908";
53 | }
54 | .icon-clock:before {
55 | content: "\e909";
56 | }
57 | .icon-close-circle-fill:before {
58 | content: "\e90a";
59 | }
60 | .icon-close:before {
61 | content: "\e90b";
62 | }
63 | .icon-cn:before {
64 | content: "\e90c";
65 | }
66 | .icon-down:before {
67 | content: "\e90d";
68 | }
69 | .icon-down2:before {
70 | content: "\e90e";
71 | }
72 | .icon-download-remove:before {
73 | content: "\e90f";
74 | }
75 | .icon-download:before {
76 | content: "\e910";
77 | }
78 | .icon-en:before {
79 | content: "\e911";
80 | }
81 | .icon-forward:before {
82 | content: "\e912";
83 | }
84 | .icon-headphone:before {
85 | content: "\e913";
86 | }
87 | .icon-menu:before {
88 | content: "\e914";
89 | }
90 | .icon-more:before {
91 | content: "\e915";
92 | }
93 | .icon-move:before {
94 | content: "\e916";
95 | }
96 | .icon-person:before {
97 | content: "\e917";
98 | }
99 | .icon-play_backward:before {
100 | content: "\e918";
101 | }
102 | .icon-play_forward:before {
103 | content: "\e919";
104 | }
105 | .icon-play_go:before {
106 | content: "\e91a";
107 | }
108 | .icon-play_pause:before {
109 | content: "\e91b";
110 | }
111 | .icon-private-see:before {
112 | content: "\e91c";
113 | }
114 | .icon-private:before {
115 | content: "\e91d";
116 | }
117 | .icon-progress:before {
118 | content: "\e91e";
119 | }
120 | .icon-pull_down:before {
121 | content: "\e91f";
122 | }
123 | .icon-search:before {
124 | content: "\e920";
125 | }
126 | .icon-selected:before {
127 | content: "\e921";
128 | }
129 | .icon-settings:before {
130 | content: "\e922";
131 | }
132 | .icon-shake:before {
133 | content: "\e923";
134 | }
135 | .icon-share:before {
136 | content: "\e924";
137 | }
138 | .icon-shelf:before {
139 | content: "\e925";
140 | }
141 | .icon-speak:before {
142 | content: "\e926";
143 | }
144 | .icon-up:before {
145 | content: "\e927";
146 | }
147 |
--------------------------------------------------------------------------------
/src/assets/styles/mixin.scss:
--------------------------------------------------------------------------------
1 | $ratio: 375 / 10;
2 | $animationTime: .3s;
3 | $animationType: linear;
4 |
5 | @function px2rem ($px) {
6 | @return $px / $ratio + rem;
7 | }
8 |
9 | @mixin center {
10 | display: flex;
11 | justify-content: center;
12 | align-items: center;
13 | }
14 |
15 | @mixin left {
16 | display: flex;
17 | justify-content: flex-start;
18 | align-items: center;
19 | }
20 |
21 | @mixin right {
22 | display: flex;
23 | justify-content: flex-end;
24 | align-items: center;
25 | }
26 |
27 | @mixin ellipsis {
28 | text-overflow: ellipsis;
29 | overflow: hidden;
30 | white-space: nowrap;
31 | }
32 |
33 | @mixin ellipsis2($line) {
34 | display: -webkit-box;
35 | -webkit-box-orient: vertical;
36 | -webkit-line-clamp: $line;
37 | white-space: normal;
38 | overflow: hidden;
39 | text-overflow: ellipsis;
40 | word-break: keep-all;
41 | }
42 |
43 | @mixin scroll {
44 | overflow-x: hidden;
45 | overflow-y: scroll;
46 | -webkit-overflow-scrolling: touch;
47 | &::-webkit-scrollbar {
48 | display: none;
49 | }
50 | }
51 |
52 | @mixin leftBottom {
53 | display: flex;
54 | justify-content: flex-start;
55 | align-items: flex-end;
56 | }
57 |
58 | @mixin columnLeft {
59 | display: flex;
60 | flex-direction: column;
61 | justify-content: center;
62 | align-items: flex-start;
63 | }
64 |
65 | @mixin absCenter {
66 | position: absolute;
67 | top: 0;
68 | left: 0;
69 | right: 0;
70 | bottom: 0;
71 | margin: auto;
72 | }
73 |
74 | @mixin columnTop {
75 | display: flex;
76 | flex-direction: column;
77 | justify-content: flex-start;
78 | align-items: center;
79 | }
80 |
81 | @mixin columnCenter {
82 | display: flex;
83 | flex-direction: column;
84 | justify-content: center;
85 | align-items: center;
86 | }
87 |
88 | @mixin top {
89 | display: flex;
90 | justify-content: center;
91 | align-items: flex-start;
92 | }
93 |
94 | .icon {
95 | color: #666;
96 | font-size: px2rem(16);
97 | }
98 |
99 | .title {
100 | color: #666;
101 | font-size: px2rem(16);
102 | font-weight: bold;
103 | }
104 |
--------------------------------------------------------------------------------
/src/assets/styles/reset.scss:
--------------------------------------------------------------------------------
1 | /* http://meyerweb.com/eric/tools/css/reset/
2 | v2.0 | 20110126
3 | License: none (public domain)
4 | */
5 |
6 | html, body, div, span, applet, object, iframe,
7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
8 | a, abbr, acronym, address, big, cite, code,
9 | del, dfn, em, img, ins, kbd, q, s, samp,
10 | small, strike, strong, sub, sup, tt, var,
11 | b, u, i, center,
12 | dl, dt, dd, ol, ul, li,
13 | fieldset, form, label, legend,
14 | table, caption, tbody, tfoot, thead, tr, th, td,
15 | article, aside, canvas, details, embed,
16 | figure, figcaption, footer, header, hgroup,
17 | menu, nav, output, ruby, section, summary,
18 | time, mark, audio, video {
19 | margin: 0;
20 | padding: 0;
21 | border: 0;
22 | font-size: 100%;
23 | font: inherit;
24 | vertical-align: baseline;
25 | }
26 |
27 | /* HTML5 display-role reset for older browsers */
28 | article, aside, details, figcaption, figure,
29 | footer, header, hgroup, menu, nav, section {
30 | display: block;
31 | }
32 |
33 | body {
34 | line-height: 1;
35 | }
36 |
37 | ol, ul {
38 | list-style: none;
39 | }
40 |
41 | blockquote, q {
42 | quotes: none;
43 | }
44 |
45 | blockquote:before, blockquote:after,
46 | q:before, q:after {
47 | content: '';
48 | content: none;
49 | }
50 |
51 | table {
52 | border-collapse: collapse;
53 | border-spacing: 0;
54 | }
55 |
56 | html, body {
57 | width: 100%;
58 | height: 100%;
59 | user-select: none;
60 | overflow: hidden;
61 | font-family: 'PingFangSC-Light', 'PingFang SC', 'STHeitiSC-Light', 'Helvetica-Light', 'Arial', 'sans-serif';
62 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
63 | }
--------------------------------------------------------------------------------
/src/assets/styles/transition.scss:
--------------------------------------------------------------------------------
1 | @import "mixin";
2 | .slide-down-enter, .slide-down-leave-to {
3 | transform: translate3d(0, -100%, 0)
4 | }
5 | .slide-down-enter-to, .slide-down-leave, .slide-up-enter-to, .slide-up-leave {
6 | transform: translate3d(0, 0, 0)
7 | }
8 | .slide-down-enter-active,
9 | .slide-down-leave-active,
10 | .slide-up-enter-active,
11 | .slide-up-leave-active,
12 | .fade-enter-active,
13 | .fade-leave-active,
14 | .slide-right-enter-active,
15 | .slide-right-leave-active,
16 | .popup-slide-up-enter-active,
17 | .popup-slide-up-leave-active,
18 | .fade-slide-right-enter-active,
19 | .fade-slide-right-leave-active,
20 | .title-move-enter-active, .title-move-leave-active,
21 | .hot-search-move-enter-active, .hot-search-move-leave-active {
22 | transition: all $animationTime linear;
23 | }
24 | .slide-up-enter, .slide-up-leave-to {
25 | transform: translate3d(0, px2rem(138), 0)
26 | }
27 | .fade-enter, .fade-leave-to {
28 | opacity: 0;
29 | }
30 | .fade-enter-to, .fade-leave {
31 | opacity: 1;
32 | }
33 | .slide-right-enter, .slide-right-leave-to {
34 | transform: translate3d(-100%, 0, 0);
35 | }
36 | .popup-slide-up-enter, .popup-slide-up-leave-to {
37 | transform: translate3d(0, 100%, 0);
38 | opacity: 0;
39 | }
40 | .popup-slide-up-enter-to, .popup-slide-up-leave,
41 | .fade-slide-right-enter-to, .fade-slide-right-leave,
42 | .title-move-enter-to, .title-move-leave,
43 | .hot-search-move-enter-to, .hot-search-move-leave {
44 | transform: translate3d(0, 0, 0);
45 | opacity: 1;
46 | }
47 | .fade-slide-right-enter, .fade-slide-right-leave-to {
48 | transform: translate3d(-100%, 0, 0);
49 | opacity: 0;
50 | }
51 | .title-move-enter, .title-move-leave-to {
52 | transform: translate3d(0, px2rem(10), 0);
53 | opacity: 0;
54 | }
55 | .hot-search-move-enter, .hot-search-move-leave-to {
56 | transform: translate3d(0, px2rem(30), 0);
57 | opacity: 0;
58 | }
--------------------------------------------------------------------------------
/src/components/common/Dialog.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{title}}
7 |
8 |
9 |
10 |
11 |
12 | {{$t('shelf.cancel')}}
13 | {{$t('shelf.confirm')}}
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
41 |
42 |
96 |
--------------------------------------------------------------------------------
/src/components/common/Popup.vue:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
22 |
51 |
52 |
101 |
--------------------------------------------------------------------------------
/src/components/common/Scroll.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
52 |
53 |
70 |
--------------------------------------------------------------------------------
/src/components/common/Toast.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 |
13 |
53 |
54 |
89 |
--------------------------------------------------------------------------------
/src/components/common/bookmark.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
36 |
37 |
47 |
--------------------------------------------------------------------------------
/src/components/detail/BookInfo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
![]()
5 |
6 |
17 |
18 |
19 |
20 |
30 |
31 |
85 |
--------------------------------------------------------------------------------
/src/components/detail/DetaiTitle.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | {{title}}
12 |
13 |
14 |
15 |
16 |
46 |
47 |
87 |
--------------------------------------------------------------------------------
/src/components/ebook/EbookBookmark.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
{{text}}
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
161 |
162 |
195 |
--------------------------------------------------------------------------------
/src/components/ebook/EbookFooter.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
15 |
16 |
35 |
--------------------------------------------------------------------------------
/src/components/ebook/EbookHeader.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
14 |
15 |
34 |
--------------------------------------------------------------------------------
/src/components/ebook/EbookLoading.vue:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 |
99 |
100 |
149 |
--------------------------------------------------------------------------------
/src/components/ebook/EbookMenu.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
54 |
55 |
83 |
--------------------------------------------------------------------------------
/src/components/ebook/EbookSettingFont.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
27 |
28 |
29 | {{defaultFontFamily}}
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
62 |
63 |
155 |
--------------------------------------------------------------------------------
/src/components/ebook/EbookSettingFontPopup.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
19 |
20 |
21 |
22 |
52 |
53 |
109 |
--------------------------------------------------------------------------------
/src/components/ebook/EbookSettingProgess.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{getReadText()}}
7 |
8 |
9 |
10 |
11 |
12 |
13 |
25 |
26 |
27 |
28 |
29 |
30 | {{getSectionName}}
31 | {{bookAvailable ? progress + '%' : '加载中...'}}
32 |
33 |
34 |
35 |
36 |
37 |
38 |
94 |
95 |
164 |
--------------------------------------------------------------------------------
/src/components/ebook/EbookSettingTheme.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
11 |
16 |
{{item.alias}}
17 |
18 |
19 |
20 |
21 |
22 |
23 |
40 |
41 |
82 |
--------------------------------------------------------------------------------
/src/components/ebook/EbookSlide.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
{{$t('book.navigation')}}
12 |
{{$t('book.bookmark')}}
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
50 |
51 |
100 |
--------------------------------------------------------------------------------
/src/components/ebook/EbookSlideBookmark.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{$t('book.bookmark')}} · {{bookmark ? bookmark.length : 0}}
4 |
5 |
6 |
9 |
{{item.text}}
10 |
11 |
12 |
13 |
14 |
15 |
42 |
43 |
85 |
--------------------------------------------------------------------------------
/src/components/ebook/EbookSlideContents.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
{{$t('book.cancel')}}
22 |
23 |
24 |
25 |
![]()
26 |
27 |
28 |
29 | {{metadata.title}}
30 |
31 |
32 | {{metadata.creator}}
33 |
34 |
35 |
36 |
37 | {{progress + '%'}}
38 | {{$t('book.haveRead2')}}
39 |
40 |
{{getReadText()}}
41 |
42 |
43 |
48 |
49 | {{item.label}}
53 | {{item.page}}
54 |
55 |
56 |
60 |
66 | {{item.excerpt}}
67 |
68 |
69 |
70 |
71 |
72 |
143 |
144 |
270 |
--------------------------------------------------------------------------------
/src/components/ebook/EbookTitle.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
34 |
35 |
70 |
--------------------------------------------------------------------------------
/src/components/home/Category.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
{{categoryText(item.category)}}
9 |
{{item.num + ' ' + $t('home.books')}}
10 |
11 |
12 |
13 |
![]()
14 |
![]()
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
53 |
54 |
122 |
--------------------------------------------------------------------------------
/src/components/home/CategoryBook.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
![]()
8 |
9 |
10 |
{{item.title}}
11 |
{{item.author}}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
47 |
48 |
79 |
--------------------------------------------------------------------------------
/src/components/home/Featured.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
![]()
9 |
10 |
11 |
{{item.title}}
12 |
{{item.author}}
13 |
{{categoryText(item.category)}}
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
70 |
71 |
116 |
--------------------------------------------------------------------------------
/src/components/home/GuessYouLike.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
![]()
8 |
9 |
10 |
{{item.title}}
11 |
{{item.author}}
12 |
{{resultText(item)}}
13 |
14 |
15 |
16 |
17 |
18 |
19 |
95 |
96 |
133 |
--------------------------------------------------------------------------------
/src/components/home/HotSearch.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{label}}
5 | {{btn}}
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
{{item.text}}
15 |
{{item.num}}人搜索
16 |
17 |
18 |
19 |
20 |
21 |
22 |
38 |
39 |
100 |
--------------------------------------------------------------------------------
/src/components/home/HotSearchList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
12 |
13 |
17 |
18 |
19 |
20 |
21 |
141 |
142 |
157 |
--------------------------------------------------------------------------------
/src/components/home/Recommend.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
![]()
8 |
9 |
10 |
{{item.title}}
11 |
{{$t('home.readers').replace('$1', item.readers)}}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
32 |
33 |
68 |
--------------------------------------------------------------------------------
/src/components/home/SearchBar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{$t('home.title')}}
8 |
9 |
10 |
11 |
12 |
13 |
14 |
17 |
18 |
19 |
32 |
33 |
34 |
35 |
36 |
37 |
129 |
130 |
228 |
--------------------------------------------------------------------------------
/src/components/home/Title.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{label}}
4 |
{{btn}}
5 |
6 |
7 |
8 |
21 |
22 |
44 |
--------------------------------------------------------------------------------
/src/components/shelf/A.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
12 |
--------------------------------------------------------------------------------
/src/components/shelf/ShelfGroupDialog.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
{{item.title}}
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | {{$t('shelf.groupName')}}
19 |
20 |
28 |
29 |
30 |
33 | {{$t('shelf.cancel')}}
34 |
35 |
{{$t('shelf.confirm')}}
40 |
41 |
42 |
43 |
44 |
45 |
173 |
174 |
261 |
--------------------------------------------------------------------------------
/src/components/shelf/ShelfItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 |
69 |
70 |
97 |
--------------------------------------------------------------------------------
/src/components/shelf/ShelfItemAdd.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
11 |
25 |
--------------------------------------------------------------------------------
/src/components/shelf/ShelfItemBook.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
![]()
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
18 |
19 |
54 |
--------------------------------------------------------------------------------
/src/components/shelf/ShelfItemCategory.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
![]()
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
21 |
22 |
65 |
--------------------------------------------------------------------------------
/src/components/shelf/ShelfList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 | {{item.title}}
11 |
12 |
13 |
14 |
15 |
16 |
17 |
43 |
44 |
75 |
--------------------------------------------------------------------------------
/src/components/shelf/ShelfSearch.vue:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | {{$t('shelf.cancel')}}
28 |
29 |
30 |
31 |
32 |
36 |
38 | {{item.text}}
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
115 |
116 |
226 |
--------------------------------------------------------------------------------
/src/components/shelf/ShelfTitle.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{title}}
6 | {{selectedText}}
7 |
8 |
9 | {{$t('shelf.clearCache')}}
10 |
11 |
12 | {{isEditMode ? $t('shelf.cancel') : $t('shelf.edit')}}
16 |
17 |
18 |
19 |
20 |
25 | {{$t('shelf.editGroup')}}
26 |
27 |
28 |
29 |
30 |
31 |
180 |
181 |
236 |
--------------------------------------------------------------------------------
/src/components/speak/SpeakBottom.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 | {{chapter ? chapter.label : ''}}
13 | ( {{currentSectionIndex}} / {{currentSectionTotal}} )
14 |
15 |
{{playInfo ? playInfo.currentMinute : '00'}}:{{playInfo ? playInfo.currentSecond : '00'}} / {{playInfo ? playInfo.totalMinute : '00'}}:{{playInfo ? playInfo.totalSecond : '00'}}
16 |
17 |
18 |
19 | {{$t('detail.addOrRemoveShelf')}}
20 |
21 |
22 |
23 |
24 |
44 |
45 |
117 |
--------------------------------------------------------------------------------
/src/components/speak/SpeakPlaying.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
44 |
45 |
63 |
--------------------------------------------------------------------------------
/src/lang/cn.js:
--------------------------------------------------------------------------------
1 | const messages = {
2 | home: {
3 | title: '书城',
4 | hint: '计算机科学和软件工程',
5 | guessYouLike: '猜你喜欢',
6 | change: '换一批',
7 | clear: '清空',
8 | hotSearch: '热门搜索',
9 | historySearch: '搜索历史',
10 | sameAuthor: '与$1同作者',
11 | sameReader: '对$1感兴趣的人也在读',
12 | readPercent: '阅读$2的人,$1都在读',
13 | recommend: '热门推荐',
14 | seeAll: '查看全部',
15 | readers: '$1人同时在读',
16 | featured: '精选',
17 | category: '分类',
18 | books: '本书',
19 | readNow: '立即阅读',
20 | allBook: '共 $1 本图书'
21 | },
22 | category: {
23 | computerScience: '计算机科学',
24 | socialSciences: '社会科学',
25 | economics: '经济学',
26 | education: '教育学',
27 | engineering: '工程学',
28 | environment: '环境学',
29 | geography: '地理学',
30 | history: '历史学',
31 | laws: '法学',
32 | lifeSciences: '生命科学',
33 | literature: '文学',
34 | biomedicine: '生物医学',
35 | businessandManagement: '工商管理',
36 | earthSciences: '地球科学',
37 | materialsScience: '材料科学',
38 | mathematics: '数学',
39 | medicineAndPublicHealth: '公共卫生',
40 | philosophy: '哲学',
41 | physics: '物理',
42 | politicalScienceAndInternationalRelations: '国际关系',
43 | psychology: '心理学',
44 | statistics: '统计学'
45 | },
46 | shelf: {
47 | title: '书架',
48 | edit: '编辑',
49 | cancel: '取消',
50 | search: '搜索',
51 | private: '私密阅读',
52 | noPrivate: '关闭私密阅读',
53 | download: '开启离线',
54 | move: '移动到...',
55 | remove: '移出书架',
56 | setPrivateTitle: '开启后,所选书籍的阅读记录将不会对外公开',
57 | open: '开启',
58 | closePrivateTitle: '是否关闭所选书籍的私密阅读?',
59 | close: '关闭',
60 | setPrivateSuccess: '已开启私密阅读
阅读记录将不再公开',
61 | closePrivateSuccess: '已关闭私密阅读',
62 | setDownloadTitle: '开启后,将自动缓存所选书籍内容',
63 | setDownloadSuccess: '已开启,将自动离线已购内容',
64 | setDownloadError: '离线下载异常,请重新尝试',
65 | removeDownloadTitle: '确认后,将删除所选书籍的离线内容',
66 | removeDownloadSuccess: '已选书籍的离线内容已删除',
67 | delete: '删除',
68 | clearCache: '清除缓存',
69 | clearCacheSuccess: '缓存已清空',
70 | removeBookTitle: '是否将$1移出书架?',
71 | removeBook: '移出',
72 | selectedBooks: '所选书籍',
73 | default: '默认',
74 | progress: '按进度',
75 | purchase: '按购买',
76 | bought: '已购买',
77 | notPurchased: '未购买',
78 | selectBook: '选择书籍',
79 | haveSelectedBook: '已选择$1本',
80 | haveSelectedBooks: '已选择$1本',
81 | moveBook: '移动书籍',
82 | newGroup: '新建分组',
83 | groupOut: '移出分组',
84 | editGroup: '修改分组',
85 | editGroupName: '修改分组名',
86 | deleteGroup: '删除分组',
87 | deleteGroupTitle: '删除分组后,分组内的书籍将会自动移出分组',
88 | groupNone: '当前分组暂无书籍',
89 | groupName: '分组名',
90 | confirm: '确定',
91 | moveBookInSuccess: '成功移入$1',
92 | moveBookOutSuccess: '成功移出分组',
93 | statistic: '$1本公开阅读 • $2本私密阅读',
94 | startDownload: '开始下载...',
95 | progressDownload: '正在下载:$1',
96 | downloadFirst: '请先缓存图书',
97 | welcome: '欢迎访问慕课网
学习《实战微信读书——媲美原生APP的企业级Web书城》
-------- 作者:Sam --------',
98 | find: '去找书',
99 | changeLanguage: '切换语言',
100 | studyNow: '去慕课网学习'
101 | },
102 | detail: {
103 | copyright: '版权',
104 | navigation: '目录',
105 | publisher: '出版社',
106 | category: '分类',
107 | ISBN: 'ISBN',
108 | trial: '试读',
109 | lang: '语言',
110 | loading: '加载中...',
111 | read: '阅读',
112 | listen: '听书',
113 | addOrRemoveShelf: '加入书架',
114 | isAddedToShelf: '已加入书架'
115 | },
116 | speak: {
117 | voice: '语音朗读',
118 | read: '查看原文',
119 | settings: '设置',
120 | timing: '定时',
121 | current: '当前章节',
122 | requestFailed: '请求失败!',
123 | apply: '语义解析核心技术由科大讯飞提供'
124 | },
125 | book: {
126 | pulldownAddMark: '下拉添加书签',
127 | releaseAddMark: '松手添加书签',
128 | pulldownDeleteMark: '下拉删除书签',
129 | releaseDeleteMark: '松手删除书签',
130 | selectFont: '选择字体',
131 | haveRead: '已读$1分钟',
132 | themeDefault: '默认',
133 | themeGold: '雅致',
134 | themeEye: '护眼',
135 | themeNight: '夜间',
136 | loading: '加载中...',
137 | navigation: '目录',
138 | bookmark: '书签',
139 | searchHint: '搜索全书内容',
140 | haveRead2: '已读',
141 | minutes: '分钟',
142 | cancel: '取消'
143 | }
144 | }
145 |
146 | export default messages
147 |
--------------------------------------------------------------------------------
/src/lang/en.js:
--------------------------------------------------------------------------------
1 | const messages = {
2 | home: {
3 | title: 'Book Store',
4 | hint: 'Computer Science And Software Engineering',
5 | guessYouLike: 'Guess You Like',
6 | change: 'Change',
7 | clear: 'Clear',
8 | hotSearch: 'Hot Search',
9 | historySearch: 'History Search',
10 | sameAuthor: 'Same author with $1',
11 | sameReader: 'Same reader with $1',
12 | readPercent: '$1 is reading $2',
13 | recommend: 'Recommend',
14 | seeAll: 'See all',
15 | readers: '$1 is reading',
16 | featured: 'Featured',
17 | category: 'Category',
18 | books: 'books',
19 | readNow: 'Read Now',
20 | allBook: '$1 books'
21 | },
22 | category: {
23 | computerScience: 'Computer Science',
24 | socialSciences: 'Social Sciences',
25 | economics: 'Economics',
26 | education: 'Eductation',
27 | engineering: 'Engineering',
28 | environment: 'Environment',
29 | geography: 'Geography',
30 | history: 'History',
31 | laws: 'Laws',
32 | lifeSciences: 'LifeSciences',
33 | literature: 'Literature',
34 | biomedicine: 'Biomedicine',
35 | businessandManagement: 'Business and Management',
36 | earthSciences: 'Earth Sciences',
37 | materialsScience: 'Materials Science',
38 | mathematics: 'Mathematics',
39 | medicineAndPublicHealth: 'Medicine And Public Health',
40 | philosophy: 'Philosophy',
41 | physics: 'Physics',
42 | politicalScienceAndInternationalRelations: 'Political Science And International Relations',
43 | psychology: 'Psychology',
44 | statistics: 'Statistics'
45 | },
46 | shelf: {
47 | title: 'Book Shelf',
48 | edit: 'Edit',
49 | cancel: 'Cancel',
50 | search: 'Search',
51 | private: 'Private',
52 | noPrivate: 'Close Private',
53 | download: 'Download',
54 | move: 'Move...',
55 | remove: 'Remove',
56 | setPrivateTitle: 'When opened, the reading history of selected books will not be made public',
57 | open: 'Open',
58 | closePrivateTitle: 'Whether to close the private reading of selected books?',
59 | close: 'Close',
60 | setPrivateSuccess: 'Private reading has been open and reading history will no longer be published',
61 | closePrivateSuccess: 'Private reading has been closed',
62 | setDownloadTitle: 'When opened, selected books will automatically download',
63 | setDownloadSuccess: 'Opened, will automatically download purchased books',
64 | setDownloadError: 'Offline download exception, please try again',
65 | removeDownloadTitle: 'Once confirmed, the offline books of selected will be remove',
66 | removeDownloadSuccess: 'Offline books of selected has been remove',
67 | delete: 'Remove',
68 | clearCache: 'Clear Cache',
69 | clearCacheSuccess: 'Clear cache successfully, cache is empty',
70 | removeBookTitle: 'Whether to remove $1 out of the bookshelf?',
71 | removeBook: 'Remove',
72 | selectedBooks: 'selected books',
73 | default: 'Default',
74 | progress: 'By Progress',
75 | purchase: 'By Purchase',
76 | bought: 'Bought',
77 | notPurchased: 'Not Purchased',
78 | selectBook: 'Select Book',
79 | haveSelectedBook: '$1 book has been selected',
80 | haveSelectedBooks: '$1 books have been selected',
81 | moveBook: 'Move Book',
82 | newGroup: 'New Group',
83 | groupOut: 'Move Out of Group',
84 | editGroup: 'Edit Group',
85 | editGroupName: 'Edit Group Name',
86 | deleteGroup: 'Delete Group',
87 | deleteGroupTitle: 'After deleting a group, the books in the group will be automatically moved out of the group',
88 | groupNone: 'There are no books in the current group',
89 | groupName: 'Group Name',
90 | confirm: 'Confirm',
91 | moveBookInSuccess: 'Move book(s) into $1 successfully',
92 | moveBookOutSuccess: 'Move book(s) out of the group successfully',
93 | statistic: '$1 public reading • $2 private reading',
94 | startDownload: 'Start download...',
95 | progressDownload: 'Downloading:$1',
96 | downloadFirst: 'Please download book first',
97 | welcome: 'Welcome to visit iMooc
Learning "Practical WeChat Reading - Enterprise Web Book Store of Amami Native APP"
-------- Author: Sam --------',
98 | find: 'Go to book store',
99 | changeLanguage: 'Change Language',
100 | studyNow: 'Learn on imooc.com'
101 | },
102 | detail: {
103 | copyright: 'Copyright',
104 | navigation: 'Table of Contents',
105 | publisher: 'Publisher',
106 | category: 'Category',
107 | ISBN: 'ISBN',
108 | trial: 'Trial Reading',
109 | lang: 'Language',
110 | loading: 'Loading...',
111 | read: 'Read',
112 | listen: 'Listen',
113 | addOrRemoveShelf: 'Add to Book Shelf',
114 | isAddedToShelf: 'Added to BookShelf'
115 | },
116 | speak: {
117 | voice: 'Voice Reading',
118 | read: 'Read Originial',
119 | settings: 'Settings',
120 | timing: 'Timing',
121 | current: 'Current Section',
122 | requestFailed: 'Request failed!',
123 | apply: 'The core technology of semantic analysis is provided by iFLY TEK'
124 | },
125 | book: {
126 | pulldownAddMark: 'Pull down to add bookmark',
127 | releaseAddMark: 'Release to add bookmark',
128 | pulldownDeleteMark: 'Pull down to delete bookmark',
129 | releaseDeleteMark: 'Release to add bookmark',
130 | selectFont: 'Select Font',
131 | haveRead: 'Already read $1 minutes',
132 | themeDefault: 'Default',
133 | themeGold: 'Grace',
134 | themeEye: 'Eye',
135 | themeNight: 'Night',
136 | loading: 'Loading...',
137 | navigation: 'Contents',
138 | bookmark: 'Bookmark',
139 | searchHint: 'Search from the entire book',
140 | haveRead2: 'already read',
141 | minutes: 'minutes',
142 | cancel: 'Cancel'
143 | }
144 | }
145 |
146 | export default messages
147 |
--------------------------------------------------------------------------------
/src/lang/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueI18n from 'vue-i18n'
3 | import en from './en'
4 | import cn from './cn'
5 | import { getLocale, saveLocale } from '../utils/localstorage'
6 |
7 | Vue.use(VueI18n)
8 |
9 | const messages = {
10 | en,
11 | cn
12 | }
13 |
14 | let locale = getLocale()
15 | if (!locale) {
16 | locale = 'cn'
17 | saveLocale(locale)
18 | }
19 |
20 | const i18n = new VueI18n({
21 | locale,
22 | messages
23 | })
24 |
25 | export default i18n
26 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | import router from './router'
4 | import store from './store/index'
5 | import i18n from './lang'
6 | import './assets/styles/icon.css'
7 | import './assets/styles/global.scss'
8 | // import './mock'
9 | import './utils/boost'
10 | import './utils/create-api'
11 |
12 | Vue.config.productionTip = false
13 |
14 | new Vue({
15 | router,
16 | store,
17 | i18n,
18 | render: h => h(App)
19 | }).$mount('#app')
20 |
--------------------------------------------------------------------------------
/src/mock/index.js:
--------------------------------------------------------------------------------
1 | import Mock from 'mockjs'
2 | import home from './bookHome'
3 | import shelf from './bookShelf'
4 | import list from './bookList'
5 | import flatList from './bookFlatList'
6 |
7 | Mock.mock(/\/book\/home/, 'get', home)
8 | Mock.mock(/\/book\/shelf/, 'get', shelf)
9 | Mock.mock(/\/book\/list/, 'get', list)
10 | Mock.mock(/\/book\/flat-list/, 'get', flatList)
11 |
--------------------------------------------------------------------------------
/src/router.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 |
4 | Vue.use(Router)
5 |
6 | export default new Router({
7 | routes: [
8 | {
9 | path: '/',
10 | redirect: '/store'
11 | },
12 | {
13 | path: '/ebook',
14 | component: () => import('./views/ebook/index.vue'),
15 | children: [
16 | {
17 | path: ':fileName',
18 | component: () => import('./components/ebook/EbookReader.vue')
19 | }
20 | ]
21 | },
22 | {
23 | path: '/store',
24 | component: () => import('./views/store/index.vue'),
25 | redirect: '/store/shelf',
26 | children: [
27 | {
28 | path: 'home',
29 | component: () => import('./views/store/StoreHome.vue')
30 | },
31 | {
32 | path: 'list',
33 | component: () => import('./views/store/StoreList.vue')
34 | },
35 | {
36 | path: 'detail',
37 | component: () => import('./views/store/StoreDetail.vue')
38 | },
39 | {
40 | path: 'category',
41 | component: () => import('./views/store/StoreCategory.vue')
42 | },
43 | {
44 | path: 'shelf',
45 | component: () => import('./views/store/StoreShelf.vue')
46 | },
47 | {
48 | path: 'speaking',
49 | component: () => import('./views/store/StoreSpeaking.vue')
50 | }
51 | ]
52 | }
53 | ]
54 | })
55 |
--------------------------------------------------------------------------------
/src/store/actions.js:
--------------------------------------------------------------------------------
1 | const actions = {
2 | setFontFamilyVisible: ({ commit }, visible) => {
3 | return commit('SET_FONT_FAMILY_VISIBLE', visible)
4 | },
5 | setDefaultFontFamily: ({ commit }, font) => {
6 | return commit('SET_DEFAULT_FONT_FAMILY', font)
7 | },
8 | setDefaultFontSize: ({ commit }, fontSize) => {
9 | return commit('SET_DEFAULT_FONT_SIZE', fontSize)
10 | },
11 | setSettingVisible: ({ commit }, visible) => {
12 | return commit('SET_SETTING_VISIBLE', visible)
13 | },
14 | setMenuVisible: ({ commit }, visible) => {
15 | return commit('SET_MENU_VISIBLE', visible)
16 | },
17 | setFileName: ({ commit }, fileName) => {
18 | return commit('SET_FILENAME', fileName)
19 | },
20 | setDefaultTheme: ({ commit }, theme) => {
21 | return commit('SET_DEFAULT_THEME', theme)
22 | },
23 | setBookAvailable: ({ commit }, bookAvailable) => {
24 | return commit('SET_BOOK_AVAILABLE', bookAvailable)
25 | },
26 | setProgress: ({ commit }, progress) => {
27 | return commit('SET_PROGRESS', progress)
28 | },
29 | setSection: ({ commit }, section) => {
30 | return commit('SET_SECTION', section)
31 | },
32 | setIsPaginating: ({ commit }, isPaginating) => {
33 | return commit('SET_IS_PAGINATING', isPaginating)
34 | },
35 | setCurrentBook: ({ commit }, book) => {
36 | return commit('SET_CURRENT_BOOK', book)
37 | },
38 | setNavigation: ({ commit }, navigation) => {
39 | return commit('SET_NAVIGATION', navigation)
40 | },
41 | setCover: ({ commit }, cover) => {
42 | return commit('SET_COVER', cover)
43 | },
44 | setMetadata: ({ commit }, metadata) => {
45 | return commit('SET_METADATA', metadata)
46 | },
47 | setPaginate: ({ commit }, paginate) => {
48 | return commit('SET_PAGINATE', paginate)
49 | },
50 | setPageList: ({ commit }, pagelist) => {
51 | return commit('SET_PAGELIST', pagelist)
52 | },
53 | setIsBookmark({ commit }, isBookmark) {
54 | return commit('SET_IS_BOOKMARK', isBookmark)
55 | },
56 | setOffsetY({ commit }, offsetY) {
57 | return commit('SET_OFFSETY', offsetY)
58 | },
59 | setHotSearchOffsetY({ commit }, offsetY) {
60 | return commit('SET_HOT_SEARCH_OFFSETY', offsetY)
61 | },
62 | setFlapCardVisible({ commit }, visible) {
63 | return commit('SET_FLAP_CARD_VISIBLE', visible)
64 | },
65 | setIsEditMode({ commit }, isEditMode) {
66 | return commit('SET_IS_EDIT_MODE', isEditMode)
67 | },
68 | setShelfList({ commit }, list) {
69 | return commit('SET_SHELF_LIST', list)
70 | },
71 | setShelfSelected({ commit }, selected) {
72 | return commit('SET_SHELF_SELECTED', selected)
73 | },
74 | setShelfTitleVisible({ commit }, visible) {
75 | return commit('SET_SHELF_TITLE_VISIBLE', visible)
76 | },
77 | setShelfCategory({ commit }, category) {
78 | return commit('SET_SHELF_CATEGORY', category)
79 | },
80 | setCurrentType({ commit }, type) {
81 | return commit('SET_CURRENT_TYPE', type)
82 | }
83 | }
84 |
85 | export default actions
86 |
--------------------------------------------------------------------------------
/src/store/getters.js:
--------------------------------------------------------------------------------
1 | const book = {
2 | fileName: state => state.book.fileName,
3 | menuVisible: state => state.book.menuVisible,
4 | settingVisible: state => state.book.settingVisible,
5 | defaultFontSize: state => state.book.defaultFontSize,
6 | defaultFontFamily: state => state.book.defaultFontFamily,
7 | fontFamilyVisible: state => state.book.fontFamilyVisible,
8 | defaultTheme: state => state.book.defaultTheme,
9 | bookAvailable: state => state.book.bookAvailable,
10 | progress: state => state.book.progress,
11 | section: state => state.book.section,
12 | isPaginating: state => state.book.isPaginating,
13 | currentBook: state => state.book.currentBook,
14 | navigation: state => state.book.navigation,
15 | cover: state => state.book.cover,
16 | metadata: state => state.book.metadata,
17 | paginate: state => state.book.paginate,
18 | pagelist: state => state.book.pagelist,
19 | offsetY: state => state.book.offsetY,
20 | isBookmark: state => state.book.isBookmark,
21 | hotSearchOffsetY: state => state.store.hotSearchOffsetY,
22 | flapCardVisible: state => state.store.flapCardVisible,
23 | isEditMode: state => state.store.isEditMode,
24 | shelfList: state => state.store.shelfList,
25 | shelfSelected: state => state.store.shelfSelected,
26 | shelfTitleVisible: state => state.store.shelfTitleVisible,
27 | shelfCategory: state => state.store.shelfCategory,
28 | currentType: state => state.store.currentType
29 | }
30 |
31 | export default book
32 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 | import book from './modules/book'
4 | import getters from './getters'
5 | import actions from './actions'
6 | import store from './modules/store'
7 |
8 | Vue.use(Vuex)
9 |
10 | export default new Vuex.Store({
11 | modules: {
12 | book,
13 | store
14 | },
15 | getters,
16 | actions
17 | })
18 |
--------------------------------------------------------------------------------
/src/store/modules/book.js:
--------------------------------------------------------------------------------
1 | const book = {
2 | state: {
3 | fileName: '',
4 | menuVisible: false,
5 | settingVisible: -1,
6 | defaultFontSize: 16,
7 | defaultFontFamily: 'Default',
8 | fontFamilyVisible: false,
9 | defaultTheme: 'default',
10 | bookAvailable: false,
11 | progress: 0,
12 | section: 0,
13 | isPaginating: true,
14 | currentBook: null,
15 | navigation: null,
16 | cover: null,
17 | metadata: null,
18 | paginate: '',
19 | pagelist: null,
20 | offsetY: 0,
21 | isBookmark: null
22 | },
23 | mutations: {
24 | 'SET_FILENAME': (state, fileName) => {
25 | state.fileName = fileName
26 | },
27 | 'SET_MENU_VISIBLE': (state, visible) => {
28 | state.menuVisible = visible
29 | },
30 | 'SET_SETTING_VISIBLE': (state, visible) => {
31 | state.settingVisible = visible
32 | },
33 | 'SET_DEFAULT_FONT_SIZE': (state, fontSize) => {
34 | state.defaultFontSize = fontSize
35 | },
36 | 'SET_DEFAULT_FONT_FAMILY': (state, font) => {
37 | state.defaultFontFamily = font
38 | },
39 | 'SET_FONT_FAMILY_VISIBLE': (state, visible) => {
40 | state.fontFamilyVisible = visible
41 | },
42 | 'SET_DEFAULT_THEME': (state, theme) => {
43 | state.defaultTheme = theme
44 | },
45 | 'SET_BOOK_AVAILABLE': (state, bookAvailable) => {
46 | state.bookAvailable = bookAvailable
47 | },
48 | 'SET_PROGRESS': (state, progress) => {
49 | state.progress = progress
50 | },
51 | 'SET_SECTION': (state, section) => {
52 | state.section = section
53 | },
54 | 'SET_IS_PAGINATING': (state, isPaginating) => {
55 | state.isPaginating = isPaginating
56 | },
57 | 'SET_CURRENT_BOOK': (state, currentBook) => {
58 | state.currentBook = currentBook
59 | },
60 | 'SET_NAVIGATION': (state, navigation) => {
61 | state.navigation = navigation
62 | },
63 | 'SET_COVER': (state, cover) => {
64 | state.cover = cover
65 | },
66 | 'SET_METADATA': (state, metadata) => {
67 | state.metadata = metadata
68 | },
69 | 'SET_PAGINATE': (state, paginate) => {
70 | state.paginate = paginate
71 | },
72 | 'SET_PAGELIST': (state, pagelist) => {
73 | state.pagelist = pagelist
74 | },
75 | 'SET_OFFSETY': (state, offsetY) => {
76 | state.offsetY = offsetY
77 | },
78 | 'SET_IS_BOOKMARK': (state, isBookmark) => {
79 | state.isBookmark = isBookmark
80 | }
81 | }
82 | }
83 |
84 | export default book
85 |
--------------------------------------------------------------------------------
/src/store/modules/store.js:
--------------------------------------------------------------------------------
1 | const store = {
2 | state: {
3 | hotSearchOffsetY: 0,
4 | flapCardVisible: false,
5 | isEditMode: false,
6 | shelfList: [],
7 | shelfSelected: [],
8 | shelfTitleVisible: true,
9 | shelfCategory: [],
10 | currentType: 1
11 | },
12 | mutations: {
13 | SET_HOT_SEARCH_OFFSETY(state, offsetY) {
14 | state.hotSearchOffsetY = offsetY
15 | },
16 | SET_FLAP_CARD_VISIBLE(state, visible) {
17 | state.flapCardVisible = visible
18 | },
19 | SET_IS_EDIT_MODE(state, isEditMode) {
20 | state.isEditMode = isEditMode
21 | },
22 | SET_SHELF_LIST(state, list) {
23 | state.shelfList = list
24 | },
25 | SET_SHELF_SELECTED(state, selected) {
26 | state.shelfSelected = selected
27 | },
28 | SET_SHELF_TITLE_VISIBLE(state, visible) {
29 | state.shelfTitleVisible = visible
30 | },
31 | SET_SHELF_CATEGORY(state, category) {
32 | state.shelfCategory = category
33 | },
34 | SET_CURRENT_TYPE(state, type) {
35 | state.currentType = type
36 | }
37 | }
38 | }
39 |
40 | export default store
41 |
--------------------------------------------------------------------------------
/src/utils/book.js:
--------------------------------------------------------------------------------
1 | import { getReadTime } from './localstorage'
2 | import { realPx } from './utils'
3 |
4 | export const FONT_SIZE_LIST = [
5 | { fontSize: 12 },
6 | { fontSize: 14 },
7 | { fontSize: 16 },
8 | { fontSize: 18 },
9 | { fontSize: 20 },
10 | { fontSize: 22 },
11 | { fontSize: 24 }
12 | ]
13 |
14 | export const FONT_FAMILY = [
15 | { font: 'Default' },
16 | { font: 'Cabin' },
17 | { font: 'Days One' },
18 | { font: 'Montserrat' },
19 | { font: 'Tangerine' }
20 | ]
21 |
22 | export function themeList(vue) {
23 | return [
24 | {
25 | alias: vue.$t('book.themeDefault'),
26 | name: 'Default',
27 | style: {
28 | body: {
29 | 'color': '#4c5059',
30 | 'background': '#cecece',
31 | 'padding-top': `${realPx(48)}px!important`,
32 | 'padding-bottom': `${realPx(48)}px!important`
33 | }
34 | }
35 | },
36 | {
37 | alias: vue.$t('book.themeGold'),
38 | name: 'Gold',
39 | style: {
40 | body: {
41 | 'color': '#5c5b56',
42 | 'background': '#c6c2b6',
43 | 'padding-top': `${realPx(48)}px!important`,
44 | 'padding-bottom': `${realPx(48)}px!important`
45 | }
46 | }
47 | },
48 | {
49 | alias: vue.$t('book.themeEye'),
50 | name: 'Eye',
51 | style: {
52 | body: {
53 | 'color': '#404c42',
54 | 'background': '#a9c1a9',
55 | 'padding-top': `${realPx(48)}px!important`,
56 | 'padding-bottom': `${realPx(48)}px!important`
57 | }
58 | }
59 | },
60 | {
61 | alias: vue.$t('book.themeNight'),
62 | name: 'Night',
63 | style: {
64 | body: {
65 | 'color': '#cecece',
66 | 'background': '#000000',
67 | 'padding-top': `${realPx(48)}px!important`,
68 | 'padding-bottom': `${realPx(48)}px!important`
69 | }
70 | }
71 | }
72 | ]
73 | }
74 |
75 | export function addCss(href) {
76 | const link = document.createElement('link')
77 | link.setAttribute('rel', 'stylesheet')
78 | link.setAttribute('type', 'text/css')
79 | link.setAttribute('href', href)
80 | document.getElementsByTagName('head')[0].appendChild(link)
81 | }
82 |
83 | export function removeCss(href) {
84 | const links = document.getElementsByTagName('link')
85 | for (let i = links.length; i >= 0; i--) {
86 | const link = links[i]
87 | if (link && link.getAttribute('href') && link.getAttribute('href') === href) {
88 | link.parentNode.removeChild(link)
89 | }
90 | }
91 | }
92 |
93 | export function removeAllCss () {
94 | removeCss(`${process.env.VUE_APP_RES_URL}/theme/theme_default.css`)
95 | removeCss(`${process.env.VUE_APP_RES_URL}/theme/theme_eye.css`)
96 | removeCss(`${process.env.VUE_APP_RES_URL}/theme/theme_gold.css`)
97 | removeCss(`${process.env.VUE_APP_RES_URL}/theme/theme_night.css`)
98 | }
99 |
100 | export function getReadTimeByMinute (fileName) {
101 | const readTime = getReadTime(fileName)
102 | if (!readTime) {
103 | return 0
104 | } else {
105 | return Math.ceil(readTime / 60)
106 | }
107 | }
108 |
109 | export function flatten (arr) {
110 | return [].concat(...arr.map(item => [].concat(item, ...flatten(item.subitems))))
111 | }
112 |
--------------------------------------------------------------------------------
/src/utils/boost.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-extend-native */
2 | Array.prototype.pushWithoutDuplicate = function () {
3 | for (let i = 0; i < arguments.length; i++) {
4 | const arg = arguments[i]
5 | if (this.indexOf(arg) === -1) {
6 | this.push(arg)
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/utils/create-api.js:
--------------------------------------------------------------------------------
1 | import CreateAPI from 'vue-create-api'
2 | import Vue from 'vue'
3 | import Toast from '../components/common/Toast'
4 | import Popup from '../components/common/Popup'
5 | import GroupDoalog from '../components/shelf/ShelfGroupDialog'
6 |
7 | Vue.use(CreateAPI)
8 | Vue.createAPI(Toast, true)
9 | Vue.createAPI(Popup, true)
10 | Vue.createAPI(GroupDoalog, true)
11 | Vue.mixin({
12 | methods: {
13 | toast(settings) {
14 | return this.$createToast({
15 | $props: settings
16 | })
17 | },
18 | popup(settings) {
19 | return this.$createPopup({
20 | $props: settings
21 | })
22 | },
23 | simpleToast(text) {
24 | const toast = this.toast({
25 | text: text
26 | })
27 | toast.show()
28 | toast.updateText(text)
29 | },
30 | dialog (settings) {
31 | return this.$createGroupDialog({
32 | $props: settings
33 | })
34 | }
35 | }
36 | })
37 |
--------------------------------------------------------------------------------
/src/utils/localForage.js:
--------------------------------------------------------------------------------
1 | import localForage from 'localforage'
2 |
3 | export function setLocalForage(key, data, cb, cb2) {
4 | localForage.setItem(key, data).then((value) => {
5 | if (cb) cb(value)
6 | }).catch(function(err) {
7 | if (cb2) cb2(err)
8 | })
9 | }
10 |
11 | export function getLocalForage(key, cb) {
12 | localForage.getItem(key, (err, value) => {
13 | cb(err, value)
14 | })
15 | }
16 |
17 | export function removeLocalForage(key, cb, cb2) {
18 | localForage.removeItem(key).then(function() {
19 | if (cb) cb()
20 | }).catch(function(err) {
21 | if (cb2) cb2(err)
22 | })
23 | }
24 |
25 | export function clearLocalForage(cb, cb2) {
26 | localForage.clear().then(function() {
27 | if (cb) cb()
28 | }).catch(function(err) {
29 | if (cb2) cb2(err)
30 | })
31 | }
32 |
33 | export function lengthLocalForage(cb) {
34 | localForage.length().then(
35 | numberOfKeys => {
36 | if (cb) cb(numberOfKeys)
37 | console.log(numberOfKeys)
38 | }).catch(function(err) {
39 | console.log(err)
40 | })
41 | }
42 |
43 | export function iteratorLocalForage() {
44 | localForage.iterate(function(value, key, iterationNumber) {
45 | console.log([key, value])
46 | }).then(function() {
47 | console.log('Iteration has completed')
48 | }).catch(function(err) {
49 | console.log(err)
50 | })
51 | }
52 |
53 | export function support() {
54 | const indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || null
55 | if (indexedDB) {
56 | return true
57 | } else {
58 | return false
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/utils/localstorage.js:
--------------------------------------------------------------------------------
1 | import Storage from 'web-storage-cache'
2 |
3 | const localstorage = new Storage()
4 |
5 | export function setLocalStorage(key, value) {
6 | return localstorage.set(key, value)
7 | }
8 |
9 | export function getLocalStorage(key) {
10 | return localstorage.get(key)
11 | }
12 |
13 | export function removeLocalStorage(key) {
14 | return localstorage.delete(key)
15 | }
16 |
17 | export function clearLocalStorage() {
18 | return localstorage.clear()
19 | }
20 |
21 | export function saveBookShelf(shelf) {
22 | return setLocalStorage('shelf', shelf)
23 | }
24 |
25 | export function getBookShelf() {
26 | return getLocalStorage('shelf')
27 | }
28 |
29 | export function setBookObject(fileName, key, value) {
30 | let book = getLocalStorage(`${fileName}-info`)
31 | if (!book) {
32 | book = {}
33 | }
34 | book[key] = value
35 | setLocalStorage(`${fileName}-info`, book)
36 | }
37 |
38 | export function getBookObject(fileName, key) {
39 | let book = getLocalStorage(`${fileName}-info`)
40 | if (book) {
41 | return book[key]
42 | } else {
43 | return null
44 | }
45 | }
46 |
47 | export function getLocale() {
48 | return getLocalStorage('locale')
49 | }
50 |
51 | export function saveLocale(locale) {
52 | return setLocalStorage('locale', locale)
53 | }
54 |
55 | export function getLocation(fileName) {
56 | return getBookObject(fileName, 'location')
57 | }
58 |
59 | export function saveLocation(fileName, location) {
60 | setBookObject(fileName, 'location', location)
61 | }
62 |
63 | export function getBookmark(fileName) {
64 | return getBookObject(fileName, 'bookmark')
65 | }
66 |
67 | export function saveBookmark(fileName, bookmark) {
68 | setBookObject(fileName, 'bookmark', bookmark)
69 | }
70 |
71 | export function getReadTime(fileName) {
72 | return getBookObject(fileName, 'time')
73 | }
74 |
75 | export function saveReadTime(fileName, theme) {
76 | setBookObject(fileName, 'time', theme)
77 | }
78 |
79 | export function getProgress(fileName) {
80 | return getBookObject(fileName, 'progress')
81 | }
82 |
83 | export function saveProgress(fileName, progress) {
84 | setBookObject(fileName, 'progress', progress)
85 | }
86 |
87 | export function getNavigation(fileName) {
88 | return getBookObject(fileName, 'navigation')
89 | }
90 |
91 | export function saveNavigation(fileName, navigation) {
92 | setBookObject(fileName, 'navigation', navigation)
93 | }
94 |
95 | export function getMetadata(fileName) {
96 | return getBookObject(fileName, 'metadata')
97 | }
98 |
99 | export function saveMetadata(fileName, metadata) {
100 | setBookObject(fileName, 'metadata', metadata)
101 | }
102 |
103 | export function getCover(fileName) {
104 | return getBookObject(fileName, 'cover')
105 | }
106 |
107 | export function saveCover(fileName, cover) {
108 | setBookObject(fileName, 'cover', cover)
109 | }
110 |
111 | export function getFontFamily(fileName) {
112 | return getBookObject(fileName, 'fontFamily')
113 | }
114 |
115 | export function saveFontFamily(fileName, font) {
116 | return setBookObject(fileName, 'fontFamily', font)
117 | }
118 |
119 | export function getTheme(fileName) {
120 | return getBookObject(fileName, 'theme')
121 | }
122 |
123 | export function saveTheme(fileName, theme) {
124 | setBookObject(fileName, 'theme', theme)
125 | }
126 |
127 | export function getFontSize(fileName) {
128 | return getBookObject(fileName, 'fontSize')
129 | }
130 |
131 | export function saveFontSize(fileName, fontSize) {
132 | setBookObject(fileName, 'fontSize', fontSize)
133 | }
134 |
--------------------------------------------------------------------------------
/src/utils/mixin.js:
--------------------------------------------------------------------------------
1 | import {
2 | mapGetters,
3 | mapActions
4 | } from 'vuex'
5 | import {
6 | themeList,
7 | addCss,
8 | removeAllCss,
9 | getReadTimeByMinute
10 | } from '../utils/book'
11 | import {
12 | getBookmark,
13 | saveLocation,
14 | getBookShelf,
15 | saveBookShelf
16 | } from './localstorage'
17 | import {
18 | gotoBookDetail,
19 | appendAddToShelf,
20 | computeId,
21 | removeAddFromShelf
22 | } from './store'
23 | import {
24 | shelf
25 | } from '../api/store'
26 |
27 | export const storeShelfMixin = {
28 | computed: {
29 | ...mapGetters([
30 | 'isEditMode',
31 | 'shelfList',
32 | 'shelfSelected',
33 | 'shelfTitleVisible',
34 | 'offsetY',
35 | 'shelfCategory',
36 | 'currentType'
37 | ])
38 | },
39 | methods: {
40 | ...mapActions([
41 | 'setIsEditMode',
42 | 'setShelfList',
43 | 'setShelfSelected',
44 | 'setShelfTitleVisible',
45 | 'setOffsetY',
46 | 'setShelfCategory',
47 | 'setCurrentType'
48 | ]),
49 | showBookDetail(book) {
50 | gotoBookDetail(this, book)
51 | },
52 | getCategoryList(title) {
53 | this.getShelfList().then(() => {
54 | const categoryList = this.shelfList.filter(book => book.type === 2 && book.title === title)[0]
55 | this.setShelfCategory(categoryList)
56 | })
57 | },
58 | getShelfList() {
59 | let shelfList = getBookShelf()
60 | if (!shelfList) {
61 | shelf().then(response => {
62 | if (response.status === 200 && response.data && response.data.bookList) {
63 | shelfList = appendAddToShelf(response.data.bookList)
64 | saveBookShelf(shelfList)
65 | return this.setShelfList(shelfList)
66 | }
67 | })
68 | } else {
69 | return this.setShelfList(shelfList)
70 | }
71 | },
72 | moveOutOfGroup(f) {
73 | this.setShelfList(this.shelfList.map(book => {
74 | if (book.type === 2 && book.itemList) {
75 | book.itemList = book.itemList.filter(subBook => !subBook.selected)
76 | }
77 | return book
78 | })).then(() => {
79 | const list = computeId(appendAddToShelf([].concat(removeAddFromShelf(this.shelfList), ...this.shelfSelected)))
80 | this.setShelfList(list).then(() => {
81 | this.simpleToast(this.$t('shelf.moveBookOutSuccess'))
82 | if (f) f()
83 | })
84 | })
85 | }
86 | }
87 | }
88 |
89 | export const storeHomeMixin = {
90 | computed: {
91 | ...mapGetters([
92 | 'offsetY',
93 | 'hotSearchOffsetY',
94 | 'flapCardVisible'
95 | ])
96 | },
97 | methods: {
98 | ...mapActions([
99 | 'setOffsetY',
100 | 'setHotSearchOffsetY',
101 | 'setFlapCardVisible'
102 | ]),
103 | showBookDetail(book) {
104 | gotoBookDetail(this, book)
105 | }
106 | }
107 | }
108 |
109 | export const ebookMixin = {
110 | computed: {
111 | ...mapGetters([
112 | 'fileName',
113 | 'menuVisible',
114 | 'settingVisible',
115 | 'defaultFontSize',
116 | 'defaultFontFamily',
117 | 'fontFamilyVisible',
118 | 'defaultTheme',
119 | 'bookAvailable',
120 | 'progress',
121 | 'section',
122 | 'isPaginating',
123 | 'currentBook',
124 | 'navigation',
125 | 'cover',
126 | 'metadata',
127 | 'paginate',
128 | 'pagelist',
129 | 'offsetY',
130 | 'isBookmark'
131 | ]),
132 | themeList() {
133 | return themeList(this)
134 | },
135 | getSectionName() {
136 | return this.section ? this.navigation[this.section].label : ''
137 | }
138 | },
139 | methods: {
140 | ...mapActions([
141 | 'setFileName',
142 | 'setMenuVisible',
143 | 'setSettingVisible',
144 | 'setDefaultFontSize',
145 | 'setDefaultFontFamily',
146 | 'setFontFamilyVisible',
147 | 'setDefaultTheme',
148 | 'setBookAvailable',
149 | 'setProgress',
150 | 'setSection',
151 | 'setIsPaginating',
152 | 'setCurrentBook',
153 | 'setNavigation',
154 | 'setCover',
155 | 'setMetadata',
156 | 'setPaginate',
157 | 'setPageList',
158 | 'setOffsetY',
159 | 'setIsBookmark'
160 | ]),
161 | initGlobalStyle() {
162 | removeAllCss()
163 | switch (this.defaultTheme) {
164 | case 'Default':
165 | addCss(`${process.env.VUE_APP_RES_URL}/theme/theme_default.css`)
166 | break
167 | case 'Eye':
168 | addCss(`${process.env.VUE_APP_RES_URL}/theme/theme_eye.css`)
169 | break
170 | case 'Gold':
171 | addCss(`${process.env.VUE_APP_RES_URL}/theme/theme_gold.css`)
172 | break
173 | case 'Night':
174 | addCss(`${process.env.VUE_APP_RES_URL}/theme/theme_night.css`)
175 | break
176 | default:
177 | addCss(`${process.env.VUE_APP_RES_URL}/theme/theme_default.css`)
178 | }
179 | },
180 | refreshLocation() {
181 | const currentLocation = this.currentBook.rendition.currentLocation()
182 | if (currentLocation && currentLocation.start) {
183 | const startCfi = currentLocation.start.cfi
184 | const progress = this.currentBook.locations.percentageFromCfi(startCfi)
185 | this.setProgress(Math.floor(progress * 100))
186 | this.setSection(currentLocation.start.index)
187 | saveLocation(this.fileName, startCfi)
188 | const bookmark = getBookmark(this.fileName)
189 | if (bookmark) {
190 | if (bookmark.some(item => item.cfi === startCfi)) {
191 | this.setIsBookmark(true)
192 | } else {
193 | this.setIsBookmark(false)
194 | }
195 | } else {
196 | this.setIsBookmark(false)
197 | }
198 | if (this.pagelist) {
199 | const totalPage = this.pagelist.length
200 | const currentPage = currentLocation.start.location
201 | if (currentPage && currentPage > 0) {
202 | this.setPaginate(currentPage + '/' + totalPage)
203 | } else {
204 | this.setPaginate('')
205 | }
206 | } else {
207 | this.setPaginate('')
208 | }
209 | }
210 | },
211 | display(target, cb) {
212 | if (target) {
213 | this.currentBook.rendition.display(target).then(() => {
214 | this.refreshLocation()
215 | if (cb) cb()
216 | })
217 | } else {
218 | this.currentBook.rendition.display().then(() => {
219 | this.refreshLocation()
220 | if (cb) cb()
221 | })
222 | }
223 | },
224 | hideTitleAndMenu() {
225 | this.setMenuVisible(false)
226 | this.setSettingVisible(-1)
227 | this.setFontFamilyVisible(false)
228 | },
229 | getReadText() {
230 | return this.$t('book.haveRead').replace('$1', getReadTimeByMinute(this.fileName))
231 | }
232 | }
233 | }
234 |
--------------------------------------------------------------------------------
/src/utils/store.js:
--------------------------------------------------------------------------------
1 | import { getLocalStorage, getBookShelf, saveBookShelf } from './localstorage'
2 |
3 | export function addToShelf(book) {
4 | let shelfList = getBookShelf()
5 | shelfList = removeAddFromShelf(shelfList)
6 | book.type = 1
7 | shelfList.push(book)
8 | shelfList = computeId(shelfList)
9 | shelfList = appendAddToShelf(shelfList)
10 | saveBookShelf(shelfList)
11 | }
12 |
13 | export function removeFromBookShelf(book) {
14 | return getBookShelf().filter(item => {
15 | if (item.itemList) {
16 | item.itemList = removeAddFromShelf(item.itemList)
17 | }
18 | return item.fileName !== book.fileName
19 | })
20 | }
21 |
22 | export function flatBookList(bookList) {
23 | if (bookList) {
24 | let orgBookList = bookList.filter(item => {
25 | return item.type !== 3
26 | })
27 | const categoryList = bookList.filter(item => {
28 | return item.type === 2
29 | })
30 | categoryList.forEach(item => {
31 | const index = orgBookList.findIndex(v => {
32 | return v.id === item.id
33 | })
34 | if (item.itemList) {
35 | item.itemList.forEach(subItem => {
36 | orgBookList.splice(index, 0, subItem)
37 | })
38 | }
39 | })
40 | orgBookList.forEach((item, index) => {
41 | item.id = index + 1
42 | })
43 | orgBookList = orgBookList.filter(item => item.type !== 2)
44 | return orgBookList
45 | } else {
46 | return []
47 | }
48 | }
49 |
50 | export function findBook(fileName) {
51 | const bookList = getLocalStorage('shelf')
52 | return flatBookList(bookList).find(item => item.fileName === fileName)
53 | }
54 |
55 | export function computeId(list) {
56 | return list.map((book, index) => {
57 | if (book.type !== 3) {
58 | book.id = index + 1
59 | if (book.itemList) {
60 | book.itemList = computeId(book.itemList)
61 | }
62 | }
63 | return book
64 | })
65 | }
66 |
67 | export function gotoBookDetail(vue, book) {
68 | vue.$router.push({
69 | path: '/store/detail',
70 | query: {
71 | fileName: book.fileName,
72 | category: book.categoryText
73 | }
74 | })
75 | }
76 |
77 | export function gotoStoreHome(vue) {
78 | vue.$router.push({
79 | path: '/store/home'
80 | })
81 | }
82 |
83 | export function appendAddToShelf(list) {
84 | list.push({
85 | id: -1,
86 | type: 3
87 | })
88 | return list
89 | }
90 |
91 | export function removeAddFromShelf(list) {
92 | return list.filter(item => item.type !== 3)
93 | }
94 |
95 | export const flapCardList = [
96 | {
97 | r: 255,
98 | g: 102,
99 | _g: 102,
100 | b: 159,
101 | imgLeft: 'url(' + require('@/assets/images/gift-left.png') + ')',
102 | imgRight: 'url(' + require('@/assets/images/gift-right.png') + ')',
103 | backgroundSize: '50% 50%',
104 | zIndex: 100,
105 | rotateDegree: 0
106 | },
107 | {
108 | r: 74,
109 | g: 171,
110 | _g: 171,
111 | b: 255,
112 | imgLeft: 'url(' + require('@/assets/images/compass-left.png') + ')',
113 | imgRight: 'url(' + require('@/assets/images/compass-right.png') + ')',
114 | backgroundSize: '50% 50%',
115 | zIndex: 99,
116 | rotateDegree: 0
117 | },
118 | {
119 | r: 255,
120 | g: 198,
121 | _g: 198,
122 | b: 102,
123 | imgLeft: 'url(' + require('@/assets/images/star-left.png') + ')',
124 | imgRight: 'url(' + require('@/assets/images/star-right.png') + ')',
125 | backgroundSize: '50% 50%',
126 | zIndex: 98,
127 | rotateDegree: 0
128 | },
129 | {
130 | r: 255,
131 | g: 102,
132 | _g: 102,
133 | b: 159,
134 | imgLeft: 'url(' + require('@/assets/images/heart-left.png') + ')',
135 | imgRight: 'url(' + require('@/assets/images/heart-right.png') + ')',
136 | backgroundSize: '50% 50%',
137 | zIndex: 97,
138 | rotateDegree: 0
139 | },
140 | {
141 | r: 59,
142 | g: 201,
143 | _g: 201,
144 | b: 22,
145 | imgLeft: 'url(' + require('@/assets/images/crown-left.png') + ')',
146 | imgRight: 'url(' + require('@/assets/images/crown-right.png') + ')',
147 | backgroundSize: '50% 50%',
148 | zIndex: 96,
149 | rotateDegree: 0
150 | }
151 | ]
152 |
153 | export const categoryList = {
154 | 'ComputerScience': 1,
155 | 'SocialSciences': 2,
156 | 'Economics': 3,
157 | 'Education': 4,
158 | 'Engineering': 5,
159 | 'Environment': 6,
160 | 'Geography': 7,
161 | 'History': 8,
162 | 'Laws': 9,
163 | 'LifeSciences': 10,
164 | 'Literature': 11,
165 | 'Biomedicine': 12,
166 | 'BusinessandManagement': 13,
167 | 'EarthSciences': 14,
168 | 'MaterialsScience': 15,
169 | 'Mathematics': 16,
170 | 'MedicineAndPublicHealth': 17,
171 | 'Philosophy': 18,
172 | 'Physics': 19,
173 | 'PoliticalScienceAndInternationalRelations': 20,
174 | 'Psychology': 21,
175 | 'Statistics': 22
176 | }
177 |
178 | export function getCategoryName(id) {
179 | switch (id) {
180 | case 1:
181 | return 'ComputerScience'
182 | case 2:
183 | return 'SocialSciences'
184 | case 3:
185 | return 'Economics'
186 | case 4:
187 | return 'Education'
188 | case 5:
189 | return 'Engineering'
190 | case 6:
191 | return 'Environment'
192 | case 7:
193 | return 'Geography'
194 | case 8:
195 | return 'History'
196 | case 9:
197 | return 'Laws'
198 | case 10:
199 | return 'LifeSciences'
200 | case 11:
201 | return 'Literature'
202 | case 12:
203 | return 'Biomedicine'
204 | case 13:
205 | return 'BusinessandManagement'
206 | case 14:
207 | return 'EarthSciences'
208 | case 15:
209 | return 'MaterialsScience'
210 | case 16:
211 | return 'Mathematics'
212 | case 17:
213 | return 'MedicineAndPublicHealth'
214 | case 18:
215 | return 'Philosophy'
216 | case 19:
217 | return 'Physics'
218 | case 20:
219 | return 'PoliticalScienceAndInternationalRelations'
220 | case 21:
221 | return 'Psychology'
222 | case 22:
223 | return 'Statistics'
224 | }
225 | }
226 |
227 | export function categoryText(category, vue) {
228 | switch (category) {
229 | case 1:
230 | return vue.$t('category.computerScience')
231 | case 2:
232 | return vue.$t('category.socialSciences')
233 | case 3:
234 | return vue.$t('category.economics')
235 | case 4:
236 | return vue.$t('category.education')
237 | case 5:
238 | return vue.$t('category.engineering')
239 | case 6:
240 | return vue.$t('category.environment')
241 | case 7:
242 | return vue.$t('category.geography')
243 | case 8:
244 | return vue.$t('category.history')
245 | case 9:
246 | return vue.$t('category.laws')
247 | case 10:
248 | return vue.$t('category.lifeSciences')
249 | case 11:
250 | return vue.$t('category.literature')
251 | case 12:
252 | return vue.$t('category.biomedicine')
253 | case 13:
254 | return vue.$t('category.businessandManagement')
255 | case 14:
256 | return vue.$t('category.earthSciences')
257 | case 15:
258 | return vue.$t('category.materialsScience')
259 | case 16:
260 | return vue.$t('category.mathematics')
261 | case 17:
262 | return vue.$t('category.medicineAndPublicHealth')
263 | case 18:
264 | return vue.$t('category.philosophy')
265 | case 19:
266 | return vue.$t('category.physics')
267 | case 20:
268 | return vue.$t('category.politicalScienceAndInternationalRelations')
269 | case 21:
270 | return vue.$t('category.psychology')
271 | case 22:
272 | return vue.$t('category.statistics')
273 | }
274 | }
275 |
--------------------------------------------------------------------------------
/src/utils/utils.js:
--------------------------------------------------------------------------------
1 | export function px2rem(px) {
2 | const ratio = 375 / 10
3 | return px / ratio
4 | }
5 |
6 | export function realPx(px) {
7 | const maxWidth = window.innerWidth > 500 ? 500 : window.innerWidth
8 | return px * (maxWidth / 375)
9 | }
10 |
--------------------------------------------------------------------------------
/src/views/ebook/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
79 |
80 |
90 |
--------------------------------------------------------------------------------
/src/views/store/StoreCategory.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
12 |
15 |
16 |
17 | {{$t('shelf.groupNone')}}
18 |
19 |
20 |
21 |
22 |
23 |
66 |
67 |
93 |
--------------------------------------------------------------------------------
/src/views/store/StoreHome.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
![]()
8 |
9 |
10 |
11 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
87 |
88 |
118 |
--------------------------------------------------------------------------------
/src/views/store/StoreList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
11 |
13 |
14 |
15 |
16 |
17 |
93 |
94 |
103 |
--------------------------------------------------------------------------------
/src/views/store/StoreShelf.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
57 |
58 |
74 |
--------------------------------------------------------------------------------
/src/views/store/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
11 |
19 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | function mock(app, url, data) {
2 | app.get(url, (request, response) => {
3 | response.json(data)
4 | })
5 | }
6 |
7 | const homeData = require('./src/mock/bookHome')
8 | const shelfData = require('./src/mock/bookShelf')
9 | const listData = require('./src/mock/bookList')
10 | const flatListData = require('./src/mock/bookFlatList')
11 |
12 | module.exports = {
13 | baseUrl: process.env.NODE_ENV === 'production'
14 | ? './'
15 | : '/',
16 | devServer: {
17 | before (app) {
18 | mock(app, '/book/home', homeData)
19 | mock(app, '/book/shelf', shelfData)
20 | mock(app, '/book/list', listData)
21 | mock(app, '/book/flat-list', flatListData)
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------