├── .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 | 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 | 20 | 21 | 41 | 42 | 96 | -------------------------------------------------------------------------------- /src/components/common/Popup.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 51 | 52 | 101 | -------------------------------------------------------------------------------- /src/components/common/Scroll.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 52 | 53 | 70 | -------------------------------------------------------------------------------- /src/components/common/Toast.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 53 | 54 | 89 | -------------------------------------------------------------------------------- /src/components/common/bookmark.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 36 | 37 | 47 | -------------------------------------------------------------------------------- /src/components/detail/BookInfo.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 30 | 31 | 85 | -------------------------------------------------------------------------------- /src/components/detail/DetaiTitle.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 46 | 47 | 87 | -------------------------------------------------------------------------------- /src/components/ebook/EbookBookmark.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 161 | 162 | 195 | -------------------------------------------------------------------------------- /src/components/ebook/EbookFooter.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 15 | 16 | 35 | -------------------------------------------------------------------------------- /src/components/ebook/EbookHeader.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | 34 | -------------------------------------------------------------------------------- /src/components/ebook/EbookLoading.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 99 | 100 | 149 | -------------------------------------------------------------------------------- /src/components/ebook/EbookMenu.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 54 | 55 | 83 | -------------------------------------------------------------------------------- /src/components/ebook/EbookSettingFont.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 62 | 63 | 155 | -------------------------------------------------------------------------------- /src/components/ebook/EbookSettingFontPopup.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 52 | 53 | 109 | -------------------------------------------------------------------------------- /src/components/ebook/EbookSettingProgess.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 94 | 95 | 164 | -------------------------------------------------------------------------------- /src/components/ebook/EbookSettingTheme.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 40 | 41 | 82 | -------------------------------------------------------------------------------- /src/components/ebook/EbookSlide.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 50 | 51 | 100 | -------------------------------------------------------------------------------- /src/components/ebook/EbookSlideBookmark.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 42 | 43 | 85 | -------------------------------------------------------------------------------- /src/components/ebook/EbookSlideContents.vue: -------------------------------------------------------------------------------- 1 | 71 | 72 | 143 | 144 | 270 | -------------------------------------------------------------------------------- /src/components/ebook/EbookTitle.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 34 | 35 | 70 | -------------------------------------------------------------------------------- /src/components/home/Category.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 53 | 54 | 122 | -------------------------------------------------------------------------------- /src/components/home/CategoryBook.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 47 | 48 | 79 | -------------------------------------------------------------------------------- /src/components/home/Featured.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 70 | 71 | 116 | -------------------------------------------------------------------------------- /src/components/home/GuessYouLike.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 95 | 96 | 133 | -------------------------------------------------------------------------------- /src/components/home/HotSearch.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 38 | 39 | 100 | -------------------------------------------------------------------------------- /src/components/home/HotSearchList.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 141 | 142 | 157 | -------------------------------------------------------------------------------- /src/components/home/Recommend.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 32 | 33 | 68 | -------------------------------------------------------------------------------- /src/components/home/SearchBar.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 129 | 130 | 228 | -------------------------------------------------------------------------------- /src/components/home/Title.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 21 | 22 | 44 | -------------------------------------------------------------------------------- /src/components/shelf/A.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /src/components/shelf/ShelfGroupDialog.vue: -------------------------------------------------------------------------------- 1 | 44 | 45 | 173 | 174 | 261 | -------------------------------------------------------------------------------- /src/components/shelf/ShelfItem.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 69 | 70 | 97 | -------------------------------------------------------------------------------- /src/components/shelf/ShelfItemAdd.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | 11 | 25 | -------------------------------------------------------------------------------- /src/components/shelf/ShelfItemBook.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 18 | 19 | 54 | -------------------------------------------------------------------------------- /src/components/shelf/ShelfItemCategory.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 21 | 22 | 65 | -------------------------------------------------------------------------------- /src/components/shelf/ShelfList.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 43 | 44 | 75 | -------------------------------------------------------------------------------- /src/components/shelf/ShelfSearch.vue: -------------------------------------------------------------------------------- 1 | 45 | 46 | 115 | 116 | 226 | -------------------------------------------------------------------------------- /src/components/shelf/ShelfTitle.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 180 | 181 | 236 | -------------------------------------------------------------------------------- /src/components/speak/SpeakBottom.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 44 | 45 | 117 | -------------------------------------------------------------------------------- /src/components/speak/SpeakPlaying.vue: -------------------------------------------------------------------------------- 1 | 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 | 11 | 12 | 79 | 80 | 90 | -------------------------------------------------------------------------------- /src/views/store/StoreCategory.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 66 | 67 | 93 | -------------------------------------------------------------------------------- /src/views/store/StoreHome.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 87 | 88 | 118 | -------------------------------------------------------------------------------- /src/views/store/StoreList.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 93 | 94 | 103 | -------------------------------------------------------------------------------- /src/views/store/StoreShelf.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 57 | 58 | 74 | -------------------------------------------------------------------------------- /src/views/store/index.vue: -------------------------------------------------------------------------------- 1 | 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 | --------------------------------------------------------------------------------