├── static ├── .gitkeep └── qr_code.png ├── src ├── assets │ ├── font │ │ └── .gitkeep │ ├── image │ │ ├── p2.gif │ │ ├── book.jpg │ │ ├── bruin.jpeg │ │ ├── girl1.jpeg │ │ ├── icon_t01.png │ │ ├── icon_t03.png │ │ ├── icon_t05.png │ │ ├── icon_t06.png │ │ ├── icon_t09.png │ │ ├── icon_t10.png │ │ ├── icon_t12.png │ │ ├── pic_back.png │ │ ├── progress.gif │ │ ├── touxiang.jpg │ │ ├── biaoqing2.png │ │ ├── loading_1.gif │ │ ├── pic_share.png │ │ ├── progress2.gif │ │ ├── Circle_book.jpg │ │ ├── detail-book.jpg │ │ ├── loading_read.gif │ │ ├── search_back.png │ │ ├── bookimg_loading.png │ │ ├── tongtian_book.jpeg │ │ ├── book_search_icon.png │ │ ├── detail_more_icon.png │ │ ├── fan_score_level16.png │ │ ├── listen_time_icon.png │ │ ├── pic_right_arrows.png │ │ ├── pic_search_newer.png │ │ ├── reply_comment_icon.png │ │ ├── upload_fail_icon.png │ │ ├── batch_download_back.png │ │ ├── batch_download_close.png │ │ ├── pic_header_loading_0.png │ │ ├── pic_shelf_pop_batch.png │ │ ├── pic_shelf_title_logo.png │ │ ├── pic_shelf_title_more.png │ │ ├── default_user_head_photo.png │ │ ├── pic_book_cover_catalog.png │ │ ├── pic_book_cover_download.png │ │ ├── pic_book_cover_fans_1.png │ │ ├── pic_book_cover_fans_2.png │ │ ├── pic_book_cover_fans_3.png │ │ ├── pic_book_cover_newer_1.png │ │ ├── pic_default_head_image.png │ │ ├── pic_shelf_pop_list_mode.png │ │ ├── pic_shelf_title_search.png │ │ ├── read_set_chapter_next.png │ │ ├── speech_menu_next_normal.png │ │ ├── pic_book_cover_add_shelf.png │ │ ├── pic_main_personal_account.png │ │ ├── pic_main_personal_setting.png │ │ ├── pic_main_tab_shelf_normal.png │ │ ├── pic_main_tab_store_normal.png │ │ ├── pic_shelf_item_menu_share.png │ │ ├── pic_shelf_pop_collection.png │ │ ├── pic_shelf_pop_cover_mode.png │ │ ├── reply_item_praise_normal.png │ │ ├── pic_main_personal_about_us.png │ │ ├── pic_main_personal_fan_score.png │ │ ├── pic_main_personal_my_coupon.png │ │ ├── pic_main_personal_my_dynamic.png │ │ ├── pic_main_personal_my_message.png │ │ ├── pic_main_tab_circle_normal.png │ │ ├── pic_main_tab_circle_selected.png │ │ ├── pic_main_tab_personal_normal.png │ │ ├── pic_main_tab_shelf_selected.png │ │ ├── pic_main_tab_store_selected.png │ │ ├── pic_shelf_item_menu_add_top.png │ │ ├── pic_shelf_item_menu_circle.png │ │ ├── pic_shelf_item_menu_delete.png │ │ ├── pic_shelf_item_menu_detail.png │ │ ├── pic_shelf_item_menu_download.png │ │ ├── pic_book_cover_add_shelf_done.png │ │ ├── pic_main_personal_gift_center.png │ │ ├── pic_main_tab_personal_selected.png │ │ ├── reader_menu_chenjin_unchecked.png │ │ ├── pic_main_personal_author_center.png │ │ ├── pic_main_personal_listen_center.png │ │ ├── pic_main_personal_my_collection.png │ │ ├── pic_shelf_item_menu_month_ticket.png │ │ └── pic_shelf_item_menu_recommend_ticket.png │ ├── js │ │ ├── validat.js │ │ └── utils.js │ └── css │ │ ├── public.styl │ │ ├── login_register.styl │ │ └── reset.styl ├── api │ ├── config.js │ └── index.js ├── base │ ├── Arrows.vue │ ├── Chapter.vue │ ├── Banner.vue │ ├── Loading.vue │ ├── Tips.vue │ ├── Time.vue │ ├── Bottom.vue │ └── Scroll.vue ├── main.js ├── App.vue ├── components │ ├── chapter.vue │ ├── Login.vue │ ├── Store.vue │ ├── store │ │ ├── Classify.vue │ │ ├── Queue.vue │ │ ├── Theme.vue │ │ ├── End.vue │ │ ├── Charge.vue │ │ └── Woman.vue │ ├── Register.vue │ ├── Circle.vue │ ├── Mine.vue │ ├── Reack.vue │ └── Read.vue └── router │ └── index.js ├── server ├── config.js ├── lib │ └── utils.js ├── mock │ ├── banner.json │ ├── overBook.json │ ├── user.json │ ├── defaultBook.json │ ├── 1.json │ ├── rank.json │ └── hot.json ├── middleware │ └── index.js ├── api │ ├── url.js │ └── index.js ├── app.js └── route │ ├── view.js │ ├── book.js │ └── user.js ├── qr_code.png ├── config ├── prod.env.js ├── dev.env.js └── index.js ├── .editorconfig ├── .gitignore ├── .babelrc ├── .postcssrc.js ├── pm2.prod.config.js ├── package.json ├── README.md └── index.html /static/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/font/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | PORT: 4000, 3 | } 4 | -------------------------------------------------------------------------------- /qr_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/qr_code.png -------------------------------------------------------------------------------- /static/qr_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/static/qr_code.png -------------------------------------------------------------------------------- /src/assets/image/p2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/p2.gif -------------------------------------------------------------------------------- /src/assets/image/book.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/book.jpg -------------------------------------------------------------------------------- /src/assets/image/bruin.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/bruin.jpeg -------------------------------------------------------------------------------- /src/assets/image/girl1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/girl1.jpeg -------------------------------------------------------------------------------- /src/assets/image/icon_t01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/icon_t01.png -------------------------------------------------------------------------------- /src/assets/image/icon_t03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/icon_t03.png -------------------------------------------------------------------------------- /src/assets/image/icon_t05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/icon_t05.png -------------------------------------------------------------------------------- /src/assets/image/icon_t06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/icon_t06.png -------------------------------------------------------------------------------- /src/assets/image/icon_t09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/icon_t09.png -------------------------------------------------------------------------------- /src/assets/image/icon_t10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/icon_t10.png -------------------------------------------------------------------------------- /src/assets/image/icon_t12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/icon_t12.png -------------------------------------------------------------------------------- /src/assets/image/pic_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_back.png -------------------------------------------------------------------------------- /src/assets/image/progress.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/progress.gif -------------------------------------------------------------------------------- /src/assets/image/touxiang.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/touxiang.jpg -------------------------------------------------------------------------------- /src/assets/image/biaoqing2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/biaoqing2.png -------------------------------------------------------------------------------- /src/assets/image/loading_1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/loading_1.gif -------------------------------------------------------------------------------- /src/assets/image/pic_share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_share.png -------------------------------------------------------------------------------- /src/assets/image/progress2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/progress2.gif -------------------------------------------------------------------------------- /src/assets/image/Circle_book.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/Circle_book.jpg -------------------------------------------------------------------------------- /src/assets/image/detail-book.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/detail-book.jpg -------------------------------------------------------------------------------- /src/assets/image/loading_read.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/loading_read.gif -------------------------------------------------------------------------------- /src/assets/image/search_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/search_back.png -------------------------------------------------------------------------------- /src/assets/image/bookimg_loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/bookimg_loading.png -------------------------------------------------------------------------------- /src/assets/image/tongtian_book.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/tongtian_book.jpeg -------------------------------------------------------------------------------- /src/assets/image/book_search_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/book_search_icon.png -------------------------------------------------------------------------------- /src/assets/image/detail_more_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/detail_more_icon.png -------------------------------------------------------------------------------- /src/assets/image/fan_score_level16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/fan_score_level16.png -------------------------------------------------------------------------------- /src/assets/image/listen_time_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/listen_time_icon.png -------------------------------------------------------------------------------- /src/assets/image/pic_right_arrows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_right_arrows.png -------------------------------------------------------------------------------- /src/assets/image/pic_search_newer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_search_newer.png -------------------------------------------------------------------------------- /src/assets/image/reply_comment_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/reply_comment_icon.png -------------------------------------------------------------------------------- /src/assets/image/upload_fail_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/upload_fail_icon.png -------------------------------------------------------------------------------- /src/assets/image/batch_download_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/batch_download_back.png -------------------------------------------------------------------------------- /src/assets/image/batch_download_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/batch_download_close.png -------------------------------------------------------------------------------- /src/assets/image/pic_header_loading_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_header_loading_0.png -------------------------------------------------------------------------------- /src/assets/image/pic_shelf_pop_batch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_shelf_pop_batch.png -------------------------------------------------------------------------------- /src/assets/image/pic_shelf_title_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_shelf_title_logo.png -------------------------------------------------------------------------------- /src/assets/image/pic_shelf_title_more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_shelf_title_more.png -------------------------------------------------------------------------------- /src/assets/image/default_user_head_photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/default_user_head_photo.png -------------------------------------------------------------------------------- /src/assets/image/pic_book_cover_catalog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_book_cover_catalog.png -------------------------------------------------------------------------------- /src/assets/image/pic_book_cover_download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_book_cover_download.png -------------------------------------------------------------------------------- /src/assets/image/pic_book_cover_fans_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_book_cover_fans_1.png -------------------------------------------------------------------------------- /src/assets/image/pic_book_cover_fans_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_book_cover_fans_2.png -------------------------------------------------------------------------------- /src/assets/image/pic_book_cover_fans_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_book_cover_fans_3.png -------------------------------------------------------------------------------- /src/assets/image/pic_book_cover_newer_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_book_cover_newer_1.png -------------------------------------------------------------------------------- /src/assets/image/pic_default_head_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_default_head_image.png -------------------------------------------------------------------------------- /src/assets/image/pic_shelf_pop_list_mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_shelf_pop_list_mode.png -------------------------------------------------------------------------------- /src/assets/image/pic_shelf_title_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_shelf_title_search.png -------------------------------------------------------------------------------- /src/assets/image/read_set_chapter_next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/read_set_chapter_next.png -------------------------------------------------------------------------------- /src/assets/image/speech_menu_next_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/speech_menu_next_normal.png -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"', 4 | REQUEST_PREFIX: '"http://zh.zeebin.top"' 5 | } 6 | -------------------------------------------------------------------------------- /src/assets/image/pic_book_cover_add_shelf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_book_cover_add_shelf.png -------------------------------------------------------------------------------- /src/assets/image/pic_main_personal_account.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_main_personal_account.png -------------------------------------------------------------------------------- /src/assets/image/pic_main_personal_setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_main_personal_setting.png -------------------------------------------------------------------------------- /src/assets/image/pic_main_tab_shelf_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_main_tab_shelf_normal.png -------------------------------------------------------------------------------- /src/assets/image/pic_main_tab_store_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_main_tab_store_normal.png -------------------------------------------------------------------------------- /src/assets/image/pic_shelf_item_menu_share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_shelf_item_menu_share.png -------------------------------------------------------------------------------- /src/assets/image/pic_shelf_pop_collection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_shelf_pop_collection.png -------------------------------------------------------------------------------- /src/assets/image/pic_shelf_pop_cover_mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_shelf_pop_cover_mode.png -------------------------------------------------------------------------------- /src/assets/image/reply_item_praise_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/reply_item_praise_normal.png -------------------------------------------------------------------------------- /src/assets/image/pic_main_personal_about_us.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_main_personal_about_us.png -------------------------------------------------------------------------------- /src/assets/image/pic_main_personal_fan_score.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_main_personal_fan_score.png -------------------------------------------------------------------------------- /src/assets/image/pic_main_personal_my_coupon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_main_personal_my_coupon.png -------------------------------------------------------------------------------- /src/assets/image/pic_main_personal_my_dynamic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_main_personal_my_dynamic.png -------------------------------------------------------------------------------- /src/assets/image/pic_main_personal_my_message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_main_personal_my_message.png -------------------------------------------------------------------------------- /src/assets/image/pic_main_tab_circle_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_main_tab_circle_normal.png -------------------------------------------------------------------------------- /src/assets/image/pic_main_tab_circle_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_main_tab_circle_selected.png -------------------------------------------------------------------------------- /src/assets/image/pic_main_tab_personal_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_main_tab_personal_normal.png -------------------------------------------------------------------------------- /src/assets/image/pic_main_tab_shelf_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_main_tab_shelf_selected.png -------------------------------------------------------------------------------- /src/assets/image/pic_main_tab_store_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_main_tab_store_selected.png -------------------------------------------------------------------------------- /src/assets/image/pic_shelf_item_menu_add_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_shelf_item_menu_add_top.png -------------------------------------------------------------------------------- /src/assets/image/pic_shelf_item_menu_circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_shelf_item_menu_circle.png -------------------------------------------------------------------------------- /src/assets/image/pic_shelf_item_menu_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_shelf_item_menu_delete.png -------------------------------------------------------------------------------- /src/assets/image/pic_shelf_item_menu_detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_shelf_item_menu_detail.png -------------------------------------------------------------------------------- /src/assets/image/pic_shelf_item_menu_download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_shelf_item_menu_download.png -------------------------------------------------------------------------------- /src/assets/image/pic_book_cover_add_shelf_done.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_book_cover_add_shelf_done.png -------------------------------------------------------------------------------- /src/assets/image/pic_main_personal_gift_center.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_main_personal_gift_center.png -------------------------------------------------------------------------------- /src/assets/image/pic_main_tab_personal_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_main_tab_personal_selected.png -------------------------------------------------------------------------------- /src/assets/image/reader_menu_chenjin_unchecked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/reader_menu_chenjin_unchecked.png -------------------------------------------------------------------------------- /src/assets/image/pic_main_personal_author_center.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_main_personal_author_center.png -------------------------------------------------------------------------------- /src/assets/image/pic_main_personal_listen_center.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_main_personal_listen_center.png -------------------------------------------------------------------------------- /src/assets/image/pic_main_personal_my_collection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_main_personal_my_collection.png -------------------------------------------------------------------------------- /src/assets/image/pic_shelf_item_menu_month_ticket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_shelf_item_menu_month_ticket.png -------------------------------------------------------------------------------- /src/assets/image/pic_shelf_item_menu_recommend_ticket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lzbabd/zh-book/HEAD/src/assets/image/pic_shelf_item_menu_recommend_ticket.png -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Editor directories and files 9 | .idea 10 | .vscode 11 | *.suo 12 | *.ntvs* 13 | *.njsproj 14 | *.sln 15 | -------------------------------------------------------------------------------- /src/api/config.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | axios.defaults.baseURL = process.env.REQUEST_PREFIX; 4 | axios.defaults.withCredentials = true; 5 | axios.interceptors.response.use(res => res.data); 6 | 7 | export default axios; 8 | -------------------------------------------------------------------------------- /config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"', 7 | REQUEST_PREFIX: '"http://localhost:4000"' 8 | }) 9 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false, 5 | "targets": { 6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] 7 | } 8 | }], 9 | "stage-2" 10 | ], 11 | "plugins": ["transform-vue-jsx", "transform-runtime"] 12 | } 13 | -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | "postcss-import": {}, 6 | "postcss-url": {}, 7 | // to edit target browsers: use "browserslist" field in package.json 8 | "autoprefixer": {} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /pm2.prod.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | /** 3 | * Application configuration section 4 | * http://pm2.keymetrics.io/docs/usage/application-declaration/ 5 | */ 6 | apps : [ 7 | { 8 | name : 'zongheng', 9 | script : 'server/app.js', 10 | env_production : { 11 | NODE_ENV: 'production' 12 | } 13 | } 14 | ] 15 | }; 16 | -------------------------------------------------------------------------------- /src/base/Arrows.vue: -------------------------------------------------------------------------------- 1 | 6 | 15 | 29 | -------------------------------------------------------------------------------- /src/assets/js/validat.js: -------------------------------------------------------------------------------- 1 | export let validatUsername = (u) => { 2 | if (typeof u === "string") { 3 | let reg = /^[a-zA-Z0-9_]{6,16}$/i; 4 | return {valida: reg.test(u), msg: '6到16位数字字母下划线'} 5 | } 6 | return {} 7 | } 8 | export let validatPassword = (p) => { 9 | if (typeof p === "string") { 10 | let reg = /^([a-zA-Z]){6,16}$|^(\d){6,16}$|^((?=[\x21-\x7e]+)[^A-Za-z0-9]){6,16}$|^(?!\2+$)(?!\1+$)[\2\1]{6,7}$|^(?!\3+$)(?!\1+$)[\3\1]{6,7}$|^(?!\3+$)(?!\2+$)[\2\3]{6,7}$|^(?=.*\3)(?=.*\1)(?=.*\2)[a-zA-Z\x21-\x7e\d]{6,7}$/; 11 | return {valida: reg.test(p), msg: '6到16位数字字母特殊字符'} 12 | } 13 | return {} 14 | } 15 | -------------------------------------------------------------------------------- /src/base/Chapter.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 29 | 30 | 36 | -------------------------------------------------------------------------------- /server/lib/utils.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | module.exports = { 5 | /** 6 | * 读取文件 7 | */ 8 | readFile(filename) { 9 | let _path = path.join(__dirname, '../mock', filename); 10 | return new Promise((resolve, reject) => { 11 | fs.readFile(_path, 'utf-8', (err, val) => { 12 | if (err) return reject(err.message) 13 | resolve(JSON.parse(val)) 14 | }) 15 | }) 16 | }, 17 | writeFile(filename, data) { 18 | let _path = path.join(__dirname, '../mock', filename); 19 | data = typeof data === 'string' ? data : JSON.stringify(data) 20 | return new Promise((resolve, reject) => { 21 | fs.writeFile(_path, data, 'utf-8', err => { 22 | if (err) return reject(err.message) 23 | resolve() 24 | }) 25 | }) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/base/Banner.vue: -------------------------------------------------------------------------------- 1 | 9 | 31 | 36 | -------------------------------------------------------------------------------- /server/mock/banner.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 1, 4 | "title": "花语", 5 | "link": "http://news.zongheng.com/subject/422.html?zong_heng_share_bool=1", 6 | "img": "//static.zongheng.com/upload/recommend/59/1c/591ce0df7cadb330af33833dec2eeca3.jpeg" 7 | }, 8 | { 9 | "id": 2, 10 | "title": "帝道独尊", 11 | "link": "http://book.zongheng.com/book/735577.html", 12 | "img": "//static.zongheng.com/upload/recommend/5c/31/5c316a48397e574cb4422f353898f9a9.jpeg" 13 | }, 14 | { 15 | "id": 3, 16 | "title": "这么多小说网站里,只有纵横看书爽", 17 | "link": "", 18 | "img": "//static.zongheng.com/upload/recommend/cc/91/cc917016d06ffe4125cd40094898b389.jpeg" 19 | }, 20 | { 21 | "id": 4, 22 | "title": "万界仙王", 23 | "link": "http://book.zongheng.com/book/711996.html", 24 | "img": "//static.zongheng.com/upload/recommend/ac/87/ac874aeb7845d6ac9dbe243c5da9a191.jpeg" 25 | } 26 | ] 27 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App' 3 | import router from './router' 4 | import VueLazyload from 'vue-lazyload' 5 | 6 | 7 | Vue.use(VueLazyload, { 8 | preLoad: 1.3, 9 | error: require('./assets/image/p2.gif'), 10 | loading: require('./assets/image/p2.gif'), 11 | attempt: 1 12 | }) 13 | 14 | import '@/assets/css/public.styl' 15 | import '@/assets/css/reset.styl' 16 | 17 | import Loading from '@/base/Loading.vue' 18 | import Tips from '@/base/Tips.vue' 19 | import Scroll from '@/base/Scroll.vue' 20 | 21 | //导入轮播组件 22 | import Swiper from "vue-awesome-swiper" 23 | Vue.use(Swiper); 24 | import 'swiper/dist/css/swiper.css' 25 | 26 | 27 | Vue.config.productionTip = false; 28 | // 全局 组件 29 | Vue.component('Loading', Loading) 30 | Vue.component('Tips', Tips) 31 | Vue.component('Scroll', Scroll) 32 | 33 | Vue.filter('countWan',val => { 34 | return (Math.round(val/10000) || 1) + '万字' 35 | }) 36 | 37 | // 38 | 39 | new Vue({ 40 | el: '#app', 41 | router, 42 | components: { App }, 43 | template: '' 44 | }); 45 | -------------------------------------------------------------------------------- /src/base/Loading.vue: -------------------------------------------------------------------------------- 1 | 9 | 13 | 43 | -------------------------------------------------------------------------------- /src/base/Tips.vue: -------------------------------------------------------------------------------- 1 | 10 | 23 | 46 | -------------------------------------------------------------------------------- /server/middleware/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | setCORS(host = []) { 3 | return (req, res, next) => { 4 | res.header("Access-Control-Allow-Origin", req.headers.origin); 5 | res.header("Access-Control-Allow-Credentials", true); 6 | res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With"); 7 | res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS"); 8 | // res.header("X-Powered-By", '3.2.1'); 9 | if (req.method === 'OPTIONS') { 10 | return res.send('support CORS') 11 | } 12 | next(); 13 | } 14 | }, 15 | // 初始化 登录/非登录 数据 16 | isLogin() { 17 | return (req, res, next) => { 18 | if (req.session.userId > 0) { 19 | // 用户已登录 20 | req.isLogin = true; 21 | req.userInfo = req.userList.find(item => parseInt(item.id) === parseInt(req.session.userId)) || {} 22 | req.bookshelf = req.userInfo['bookshelf'] || []; 23 | } else { 24 | req.isLogin = false; 25 | req.userInfo = {}; 26 | // 用户没有登录 27 | if (!('bookshelf' in req.session)) { 28 | // 书架未初始化 29 | req.session.bookshelf = req.userList[0].bookshelf || []; 30 | } 31 | req.bookshelf = req.session.bookshelf 32 | } 33 | next() 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /server/mock/overBook.json: -------------------------------------------------------------------------------- 1 | { 2 | "_id": "5a9e4da7a5ee611ea424b033", 3 | "title": "从姑获鸟开始", 4 | "author": "活儿该", 5 | "longIntro": "身如鸿毛,命如野草。见过最黑的夜,所以心中炽烈明亮的火焰,从不动摇。", 6 | "majorCate": "科幻", 7 | "minorCate": "未来世界", 8 | "cover": "/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2236150%2F2236150_d70a33199a5246bea4e76c9e23f81a51_default_cover.png%2F", 9 | "hiddenPackage": [ 10 | "mangguo" 11 | ], 12 | "apptype": [ 13 | 0, 14 | 1 15 | ], 16 | "rating": { 17 | "count": 115, 18 | "score": 8.348, 19 | "isEffect": true 20 | }, 21 | "hasCopyright": true, 22 | "buytype": 0, 23 | "sizetype": -1, 24 | "superscript": "", 25 | "currency": 0, 26 | "contentType": "txt", 27 | "_le": true, 28 | "allowMonthly": false, 29 | "allowVoucher": true, 30 | "allowBeanVoucher": true, 31 | "hasCp": true, 32 | "postCount": 42, 33 | "latelyFollower": 15220, 34 | "followerCount": 0, 35 | "wordCount": 135998, 36 | "serializeWordCount": 4300, 37 | "retentionRatio": "34.27", 38 | "updated": "2018-03-26T15:33:00.788Z", 39 | "isSerial": true, 40 | "chaptersCount": 52, 41 | "lastChapter": "第51章 山中有鬼", 42 | "gender": [ 43 | "male" 44 | ], 45 | "tags": [], 46 | "advertRead": true, 47 | "cat": "未来世界", 48 | "donate": false, 49 | "_gg": false, 50 | "discount": null, 51 | "limit": false 52 | } 53 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 15 | 29 | 53 | -------------------------------------------------------------------------------- /src/assets/js/utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 公用JS方法资源库 3 | */ 4 | 5 | let class2type = {}; 6 | "Boolean Number String Function Array Date RegExp Object Error".split(" ").forEach(name => { 7 | class2type["[object " + name + "]"] = name.toLowerCase(); 8 | }); 9 | 10 | 11 | 12 | function formatNumber(n) { 13 | n = n.toString(); 14 | return n[1] ? n : '0' + n 15 | } 16 | 17 | 18 | /** 19 | * 时间格式化 20 | * @param time 标准时间格式/时间字符串 21 | * @param template 22 | */ 23 | export function formatTime(time, template = '{0}-{1}-{2}') { 24 | if (typeof time === 'object') { 25 | time = time.toLocaleString() 26 | } 27 | // 匹配字符串中的数字 ['2018','11','3'] 28 | let reg = /\d+/g, 29 | ary = time.match(reg); 30 | ary = ary.map(item => item < 10 ? `0${item}` : item); 31 | 32 | reg = /{(\d+)}/g; 33 | template = template.replace(reg, (...arg) => { 34 | return ary[arg[1]] || '00' 35 | }); 36 | return template 37 | } 38 | 39 | /** 40 | * 判断数据类型 41 | * @param obj 需要检测的对象 42 | * @returns {string} 数据类型 e.g:'number','string' 43 | */ 44 | export function type(obj) { 45 | if (obj == null) { 46 | return obj + ""; 47 | } 48 | // Support: Android<4.0, iOS<6 (functionish RegExp) 49 | return typeof obj === "object" || typeof obj === "function" ? 50 | class2type[toString.call(obj)] || "object" : 51 | typeof obj; 52 | } 53 | 54 | export function px2rem (px, designWidth = 720) { 55 | return parseInt(px, 10) * 320 / designWidth / 20; 56 | } 57 | export function rem2px (rem, designWidth = 720) { 58 | return rem * 20 * designWidth / 320; 59 | } 60 | export default {formatTime, type} 61 | -------------------------------------------------------------------------------- /server/api/url.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | staticHost: 'http://statics.zhuishushenqi.com', 3 | category: { 4 | // 带书籍数量的父分类 5 | categoryWithBookCount: '/cats/lv2/statistics', 6 | // 带子分类的父分类 7 | categoryWithSubCategories: '/cats/lv2', 8 | // 分类详情: 带着书籍 9 | categoryInfo: '/book/by-categories' 10 | }, 11 | book: { 12 | // 书籍详情 13 | bookInfo: '/book', // id 书籍id 14 | // 书籍最新章节 15 | bookUpdate: '/book', //query ?view=updated&id=id,id(可以查询多条) 16 | // 相关推荐 17 | relatedRecommendedBooks: '/book', // /book/56d0b60dfb51235c3a7a2739/recommend 18 | // 作者名下的书籍 19 | authorBooks: '/book/accurate-search', // query ?author=忘语 20 | // 书籍章节列表(根据书源id) 21 | bookChaptersBySourcesId: '/atoc', // :sourcesId?view=chapters 22 | // 书籍章节列表(根据书id) 23 | bookChaptersByBookId: '/mix-atoc', // :bookId?view=chapters 24 | // 书源 25 | bookSources: '/atoc', // query ?view=summary&book=5779b38d3b433dd647d95da2 26 | // 章节内容:id 单章id 27 | chapterContent: 'http://chapter2.zhuishushenqi.com/chapter', //id: chapter id 28 | // 书籍搜索 可以搜索作者但是不精确 29 | bookSearch: '/book/fuzzy-search', //query ?query=凡人修仙传 30 | // 搜索自动补充 31 | searchKeyWord: '/book/auto-complete' //query ?query=凡 32 | }, 33 | rank: { 34 | // 排名分类 35 | rankCategory: '/ranking/gender', 36 | // 排名详情(起点月票榜) 37 | rankInfo: '/ranking/54d4306c321052167dfb75e4' // id: rank id 38 | }, 39 | comment: { 40 | // 讨论 41 | discussions: '/post/by-book', 42 | // 短评 43 | shortReviews: '/post/short-review', 44 | //长评 45 | bookReviews: '/post/review/by-book' 46 | }, 47 | bookList: { 48 | // 书单 49 | lists: '/book-list', 50 | // 列表 51 | detail: '/book-list' // bookId 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/assets/css/public.styl: -------------------------------------------------------------------------------- 1 | // 设计尺寸 2 | $designWidth = 720 3 | 4 | // 单位转换函数 5 | px2rem(px) 6 | return unit(px * 320 / $designWidth / 20, 'rem') 7 | // 公共颜色 8 | $fontColorBlack = #333 9 | $fontColorGray6 = #666 10 | $bgGray1 = #ededed 11 | $mainColor = #dc151e 12 | 13 | bs() { 14 | background-size 100% 100% 15 | } 16 | .fl 17 | float left 18 | .fr 19 | float right 20 | .clearfix 21 | display block 22 | zoom 1 23 | &::after 24 | display block 25 | content '' 26 | font-size 0 27 | height 0 28 | clear both 29 | visibility hidden 30 | .fade-enter-active, .fade-leave-active { 31 | transition: opacity .2s; 32 | } 33 | .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ { 34 | opacity: 0; 35 | } 36 | .read-setting-enter-active, .read-setting-leave-active { 37 | transition: opacity .3s; 38 | } 39 | .read-setting-enter-to, .read-setting-leave { 40 | opacity: .9!important 41 | } 42 | .read-setting-enter, .read-setting-leave-to { 43 | opacity: 0!important 44 | } 45 | [class*='fs-']{ 46 | line-height 1.5 47 | h2{ 48 | padding-bottom: px2rem(12) 49 | } 50 | p{ 51 | text-indent 2em 52 | padding-bottom: px2rem(12) 53 | } 54 | } 55 | .fs-5 { 56 | h2 { 57 | font-size px2rem(56) 58 | } 59 | p { 60 | font-size px2rem(48) 61 | } 62 | } 63 | .fs-4 { 64 | h2 { 65 | font-size px2rem(52) 66 | } 67 | p { 68 | font-size px2rem(44) 69 | } 70 | } 71 | .fs-3 { 72 | h2 { 73 | font-size px2rem(48) 74 | } 75 | p { 76 | font-size px2rem(40) 77 | } 78 | } 79 | .fs-2 { 80 | h2 { 81 | font-size px2rem(44) 82 | } 83 | p { 84 | font-size px2rem(38) 85 | } 86 | } 87 | 88 | .fs-1 { 89 | h2 { 90 | font-size px2rem(40) 91 | } 92 | p { 93 | font-size px2rem(34) 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/components/chapter.vue: -------------------------------------------------------------------------------- 1 | 16 | 25 | 73 | -------------------------------------------------------------------------------- /server/app.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const express = require('express'); 3 | const bodyParser = require('body-parser'); 4 | const app = express(); 5 | const session = require('express-session'); 6 | const compression = require('compression'); 7 | const config = require('./config') 8 | const {setCORS, isLogin} = require('./middleware/index') 9 | const {readFile} = require('./lib/utils'); 10 | 11 | /** 12 | * Create Server 13 | */ 14 | app.listen(config.PORT, () => { 15 | console.log(`server is running at port to ${config.PORT}...`); 16 | }); 17 | 18 | /** 19 | * Public Middleware 20 | */ 21 | // CORS 22 | app.use(setCORS()); 23 | 24 | // SESSION 25 | app.use(session({ 26 | secret: 'zh',//=>用来对SESSION-ID相关的COOKIE进行签名 27 | saveUninitialized: false, //=>是否自动保存未初始化的会话,建议FALSE 28 | resave: false, //=>是否每次都重新保存会话,建议FALSE 29 | cookie: { 30 | maxAge: 1000 * 60 * 60 * 24 * 30 //=>有效期,单位是毫秒 31 | } 32 | })); 33 | 34 | // BODY-PARSER 35 | app.use(bodyParser.urlencoded({extended: true})); 36 | app.use(bodyParser.json()); 37 | 38 | // COMPRESSION GZIP 39 | app.use(compression({filter: shouldCompress})) 40 | 41 | function shouldCompress(req, res) { 42 | if (req.headers['x-no-compression']) { 43 | // 不压缩此响应头的请求 44 | return false 45 | } 46 | // 标准压缩 47 | return compression.filter(req, res) 48 | } 49 | 50 | // USER DATA (必须在登录验证之前注入) 51 | app.use(async (req, res, next) => { 52 | let result = await readFile('user.json') 53 | req.userList = result.userList 54 | req.userCount = result.num 55 | next() 56 | }); 57 | 58 | // INIT LOGIN 59 | app.use(isLogin()) 60 | 61 | // 62 | app.get('/', (req, res) => { 63 | res.redirect('/index.html') 64 | }); 65 | 66 | /** 67 | * Handle Route API 68 | */ 69 | app.use('/book', require('./route/book')); 70 | app.use('/view', require('./route/view')) 71 | app.use('/user', require('./route/user')) 72 | 73 | 74 | /** 75 | * Handle Static Resource 76 | */ 77 | app.use(express.static(path.join(__dirname, '../dist'))); 78 | 79 | /** 80 | * Handle Other 81 | */ 82 | app.use((req, res) => { 83 | res.status(404); 84 | res.send('NOT FOUND!') 85 | }); 86 | -------------------------------------------------------------------------------- /src/base/Time.vue: -------------------------------------------------------------------------------- 1 | 11 | 65 | 84 | -------------------------------------------------------------------------------- /src/api/index.js: -------------------------------------------------------------------------------- 1 | import axios from './config' 2 | 3 | // 请求方法 4 | export let getX = () => axios.get('/X'); 5 | 6 | export let getBoutique = () => axios.get('/view/boutique'); 7 | export let getRanking = () => axios.get('/book/ranking'); 8 | export let getCategory = () => axios.get('/book/category'); 9 | export let getTheme = o => axios.get('/book/categoryBooks', {params: o}); 10 | 11 | 12 | // user 方法 13 | export let isLogin = () => axios.get('/user/isLogin'); 14 | export let register = (username, password) => axios.post('/user/register', { 15 | username, password 16 | }); 17 | export let logout = () => axios.get('/user/logout'); 18 | export let login = (username, password) => axios.post('/user/login', { 19 | username, password 20 | }); 21 | export let getUserInfo = () => axios.get('/user/userInfo'); 22 | 23 | export let getBanner = () => { 24 | return axios.get('/view/banner') 25 | }; 26 | 27 | 28 | export let getBook = (id) => { 29 | return axios.get('/user/hasBookInBookshelf/:bid') 30 | }; 31 | export let getDetail = id => { 32 | return axios.get('/book/detail/' + id) 33 | }; 34 | 35 | export let bookRack = () => { 36 | return axios.get('/user/bookshelf') 37 | }; 38 | 39 | 40 | export let getCircle = () => { 41 | return axios.get('/user/forums') 42 | }; 43 | 44 | export let getRead = bid => { 45 | return axios.get('/book/chapters/' + bid) 46 | }; 47 | export let getChapter = _id => { 48 | return axios.get('/book/chapters/' + _id) 49 | }; 50 | export let getReadContent = link => { 51 | return axios.get('/book/chapter/content', { 52 | params: { 53 | link 54 | } 55 | }) 56 | }; 57 | 58 | export let getSearch = () => { 59 | return axios.get('/book/search') 60 | }; 61 | 62 | 63 | export let deleteBook = id => { 64 | return axios.delete('/user/bookshelf/' + id); 65 | }; 66 | 67 | 68 | // 自动补全关键词 69 | export let getKeyword = val => axios.get('/view/keyCom?val=' + val,); 70 | export let search = ({query, start, limit}) => axios.get('/book/search', { 71 | params: { 72 | query, start, limit 73 | } 74 | }); 75 | 76 | // 判断书籍是否已存入书架 77 | export let isCollect = bid => axios.get('/user/hasBookInBookshelf/' + bid,); 78 | 79 | 80 | // 收藏书籍(加入书架) 81 | export let collectBook = id => axios.post('/user/bookshelf', {id}) 82 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // Template version: 1.3.1 3 | // see http://vuejs-templates.github.io/webpack for documentation. 4 | 5 | const path = require('path') 6 | 7 | module.exports = { 8 | dev: { 9 | 10 | // Paths 11 | assetsSubDirectory: 'static', 12 | assetsPublicPath: '/', 13 | proxyTable: {}, 14 | 15 | // Various Dev Server settings 16 | host: 'localhost', // can be overwritten by process.env.HOST 17 | port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined 18 | autoOpenBrowser: false, 19 | errorOverlay: true, 20 | notifyOnErrors: true, 21 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- 22 | 23 | 24 | /** 25 | * Source Maps 26 | */ 27 | 28 | // https://webpack.js.org/configuration/devtool/#development 29 | devtool: 'cheap-module-eval-source-map', 30 | 31 | // If you have problems debugging vue-files in devtools, 32 | // set this to false - it *may* help 33 | // https://vue-loader.vuejs.org/en/options.html#cachebusting 34 | cacheBusting: true, 35 | 36 | cssSourceMap: true 37 | }, 38 | 39 | build: { 40 | // Template for index.html 41 | index: path.resolve(__dirname, '../dist/index.html'), 42 | 43 | // Paths 44 | assetsRoot: path.resolve(__dirname, '../dist'), 45 | assetsSubDirectory: 'static', 46 | assetsPublicPath: '/', 47 | 48 | /** 49 | * Source Maps 50 | */ 51 | 52 | productionSourceMap: true, 53 | // https://webpack.js.org/configuration/devtool/#production 54 | devtool: '#source-map', 55 | 56 | // Gzip off by default as many popular static hosts such as 57 | // Surge or Netlify already gzip all static assets for you. 58 | // Before setting to `true`, make sure to: 59 | // npm install --save-dev compression-webpack-plugin 60 | productionGzip: false, 61 | productionGzipExtensions: ['js', 'css'], 62 | 63 | // Run the build command with an extra argument to 64 | // View the bundle analyzer report after build finishes: 65 | // `npm run build --report` 66 | // Set to `true` or `false` to always turn it on or off 67 | bundleAnalyzerReport: process.env.npm_config_report 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | 4 | // 路由按需加载 const Reack = () => import('') 5 | 6 | const Reack = () => import('@/components/Reack'); 7 | const Circle = () => import('@/components/Circle'); 8 | const Store = () => import('@/components/Store.vue'); 9 | const Man = () => import('@/components/store/Man.vue'); 10 | const Classify = () => import('@/components/store/Classify.vue'); 11 | const Woman = () => import('@/components/store/Woman.vue'); 12 | const Charge = () => import('@/components/store/Charge.vue'); 13 | const Queue = () => import('@/components/store/Queue.vue'); 14 | const End = () => import('@/components/store/End.vue'); 15 | const Home = () => import('@/components/store/Home.vue'); 16 | 17 | const Search = () => import('../base/Search'); 18 | const Theme = () => import('../components/store/Theme'); 19 | const Read = () => import ('@/components/Read'); 20 | const Chapter=()=>import('../base/Chapter'); 21 | 22 | const Details =()=> import ('@/components/Details'); 23 | 24 | 25 | // Mine 用户 26 | const Mine = () => import('../components/Mine.vue'); 27 | const Login = () => import('../components/Login.vue'); 28 | const Register = () => import('../components/Register.vue'); 29 | 30 | 31 | 32 | Vue.use(Router); 33 | let routes = [ 34 | {path: '/reack', component: Reack}, 35 | {path: '/details/:bid',component: Details}, 36 | {path: '/circle', component: Circle}, 37 | {path: '/search', component: Search}, 38 | {path: '/read/:bid', name:'read', component: Read}, 39 | {path: "/classify", component: Classify}, 40 | {path: "/theme/:major", component: Theme}, 41 | { 42 | path: '/store', component: Store, 43 | children: [ //二级路由 44 | {path: "", redirect: 'home'}, 45 | {path: "home", component: Home}, 46 | {path: "woman", component: Woman}, 47 | {path: "man", component: Man}, 48 | {path: "charge", component: Charge}, 49 | {path: "queue", component: Queue}, 50 | {path: "end", component: End}, 51 | {path: "*", component: Home}, 52 | ] 53 | }, 54 | {path: '/mine', component: Mine}, 55 | {path: '/login', component: Login}, 56 | {path: '/register', component: Register}, 57 | {path: '*', redirect: '/store'}, 58 | ]; 59 | 60 | export default new Router({routes}) 61 | -------------------------------------------------------------------------------- /server/api/index.js: -------------------------------------------------------------------------------- 1 | const {category, book, rank, comment, bookList} = require('./url'); 2 | const axios = require('axios'); 3 | 4 | // axios 请求配置 5 | axios.defaults.baseURL = 'http://api.zhuishushenqi.com'; 6 | axios.interceptors.response.use(res => res.data); 7 | 8 | // 获取分类 9 | let getCategory = () => axios.get(category.categoryWithBookCount) 10 | 11 | // 获取书籍列表 12 | let getBooks = aryId => aryId.map(id => axios.get(`${book.bookInfo}/${id}`)) 13 | 14 | // 获取书籍详情 15 | let getBookDetail = id => axios.get(`${book.bookInfo}/${id}`) 16 | 17 | // 搜索书籍/作者 18 | let searchBookAndAuthor = ({query = '', start = 0, limit = 10}) => axios.get(book.bookSearch, { 19 | params: {query, start, limit} 20 | }) 21 | 22 | /** 23 | * 获取分类书籍 24 | * @query {} 25 | * gender: 'male' // 性别 (female,male,press) 26 | * type: 'reputation' // 按照不同的类型获取分类下的书籍(hot, new, reputation, over) 27 | * minor: '东方玄幻' // 子分类 28 | * start: 0 // 起始位置 29 | * limit: 20 //每页数量 30 | */ 31 | let getCategoryBooks = query => axios.get(category.categoryInfo, { 32 | params: query 33 | }) 34 | 35 | // 获取全部书源 36 | let getSources = bookId => axios.get(book.bookSources, { 37 | params: {view: 'summary', book: bookId} 38 | }) 39 | 40 | let getRecommend = bookId => { 41 | return axios.get(`/book/${bookId}/recommend`) 42 | } 43 | 44 | // 获取章节列表(根据书籍id) 45 | let getChapters = bookId => axios.get(`${book.bookChaptersByBookId}/${bookId}?view=chapters`) 46 | 47 | // 获取章节内容(根据link) 48 | let getChapterContent = link => axios.get(`${book.chapterContent}/${link}`) 49 | 50 | // 关键词补充 51 | let keyComplete = word => axios.get(`${book.searchKeyWord}`, { 52 | params: {query: word} 53 | }) 54 | 55 | // 获取书籍最新更新信息 56 | let getBookUpdate = id => axios.get(book.bookUpdate, { 57 | params: {view: 'updated', id: id} 58 | }) 59 | 60 | // 获取圈子信息 app.zongheng.com/app/forum/v1/ajax/hotForums 61 | let getHotForums = page => axios.post('http://app.zongheng.com/app/forum/v1/ajax/hotForums', { 62 | pageNum: page 63 | }) 64 | 65 | 66 | let getRank = () => axios.get(rank.rankInfo) 67 | module.exports = { 68 | getCategory, 69 | getBooks, 70 | getBookDetail, 71 | searchBookAndAuthor, 72 | getCategoryBooks, 73 | getChapters, 74 | getChapterContent, 75 | keyComplete, 76 | getBookUpdate, 77 | getHotForums, 78 | getRank, 79 | getRecommend 80 | } 81 | -------------------------------------------------------------------------------- /src/base/Bottom.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 31 | 32 | 81 | -------------------------------------------------------------------------------- /src/components/Login.vue: -------------------------------------------------------------------------------- 1 | 37 | 88 | 91 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zongheng", 3 | "version": "1.0.0", 4 | "description": "1403纵横中文项目", 5 | "author": "1403 lzb ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --open", 9 | "start": "npm run dev", 10 | "dev-server": "cross-env NODE_ENV=develop nodemon server/app.js", 11 | "build": "node build/build.js", 12 | "server": "pm2 startOrRestart pm2.prod.config.js" 13 | }, 14 | "dependencies": { 15 | "axios": "^0.18.0", 16 | "better-scroll": "^1.9.1", 17 | "blueimp-md5": "^2.10.0", 18 | "body-parser": "^1.18.2", 19 | "compression": "^1.7.2", 20 | "express": "^4.16.3", 21 | "express-session": "^1.15.6", 22 | "npm": "^5.8.0", 23 | "pm2": "^2.10.1", 24 | "vue": "^2.5.2", 25 | "vue-awesome-swiper": "^3.1.3", 26 | "vue-lazyload": "^1.2.2", 27 | "vue-router": "^3.0.1" 28 | }, 29 | "devDependencies": { 30 | "autoprefixer": "^7.1.2", 31 | "babel-core": "^6.22.1", 32 | "babel-helper-vue-jsx-merge-props": "^2.0.3", 33 | "babel-loader": "^7.1.1", 34 | "babel-plugin-syntax-jsx": "^6.18.0", 35 | "babel-plugin-transform-runtime": "^6.22.0", 36 | "babel-plugin-transform-vue-jsx": "^3.5.0", 37 | "babel-preset-env": "^1.3.2", 38 | "babel-preset-stage-2": "^6.22.0", 39 | "chalk": "^2.0.1", 40 | "copy-webpack-plugin": "^4.0.1", 41 | "cross-env": "^5.1.4", 42 | "css-loader": "^0.28.0", 43 | "extract-text-webpack-plugin": "^3.0.0", 44 | "file-loader": "^1.1.4", 45 | "friendly-errors-webpack-plugin": "^1.6.1", 46 | "html-webpack-plugin": "^2.30.1", 47 | "node-notifier": "^5.1.2", 48 | "nodemon": "^1.17.2", 49 | "optimize-css-assets-webpack-plugin": "^3.2.0", 50 | "ora": "^1.2.0", 51 | "portfinder": "^1.0.13", 52 | "postcss-import": "^11.0.0", 53 | "postcss-loader": "^2.0.8", 54 | "postcss-url": "^7.2.1", 55 | "rimraf": "^2.6.0", 56 | "semver": "^5.3.0", 57 | "shelljs": "^0.7.6", 58 | "stylus": "^0.54.5", 59 | "stylus-loader": "^3.0.2", 60 | "uglifyjs-webpack-plugin": "^1.1.1", 61 | "url-loader": "^0.5.8", 62 | "vue-loader": "^13.3.0", 63 | "vue-style-loader": "^3.0.1", 64 | "vue-template-compiler": "^2.5.2", 65 | "webpack": "^3.6.0", 66 | "webpack-bundle-analyzer": "^2.9.0", 67 | "webpack-dev-server": "^2.9.1", 68 | "webpack-merge": "^4.1.0" 69 | }, 70 | "engines": { 71 | "node": ">= 6.0.0", 72 | "npm": ">= 3.0.0" 73 | }, 74 | "browserslist": [ 75 | "> 1%", 76 | "last 2 versions", 77 | "not ie <= 8" 78 | ], 79 | "main": "server/app.js", 80 | "repository": { 81 | "type": "git", 82 | "url": "https://git.coding.net/zeebin/base-test.git" 83 | }, 84 | "keywords": [], 85 | "license": "ISC" 86 | } 87 | -------------------------------------------------------------------------------- /src/assets/css/login_register.styl: -------------------------------------------------------------------------------- 1 | @import "./public.styl"; 2 | button 3 | border: none 4 | -webkit-appearance:none; 5 | background: none 6 | .register-page,.login-page 7 | position absolute 8 | left: 0 9 | right: 0 10 | top: 0 11 | bottom: 0 12 | background: #fff; 13 | .header 14 | display: flex 15 | box-sizing border-box 16 | padding px2rem(24) 17 | width 100% 18 | background: #fff 19 | align-items center 20 | .close-btn 21 | padding px2rem(24) 22 | img 23 | display: block 24 | margin-right: auto 25 | width px2rem(46) 26 | height px2rem(46) 27 | 28 | .register-btn 29 | margin-left auto 30 | color $mainColor 31 | padding: px2rem(24) 32 | font-size px2rem(32) 33 | .main 34 | margin: 0 auto 35 | width px2rem(570) 36 | h2 37 | font-size px2rem(38) 38 | font-weight: 500 39 | color #333 40 | line-height: px2rem(100) 41 | .form 42 | .input-box 43 | width 100% 44 | height px2rem(108) 45 | line-height: px2rem(108) 46 | border-bottom: px2rem(1) solid #dedede 47 | input 48 | box-sizing border-box 49 | border: none 50 | font-size px2rem(30) 51 | width 100% 52 | padding-right: px2rem(10) 53 | &:last-child 54 | display: flex 55 | width 100% 56 | font-size px2rem(30) 57 | align-items center 58 | .code 59 | line-height px2rem(42) 60 | height px2rem(42) 61 | color $mainColor 62 | width px2rem(220) 63 | text-align: center 64 | border-left: px2rem(1) solid #ccc 65 | &:disabled 66 | color #999 67 | input 68 | flex:1 69 | 70 | .tips 71 | color $mainColor 72 | margin-top px2rem(24) 73 | height px2rem(40) 74 | line-height: px2rem(40) 75 | font-size px2rem(28) 76 | .btn-box 77 | width 100% 78 | margin-top px2rem(24) 79 | button 80 | display: block 81 | width 100% 82 | height px2rem(88) 83 | background: $mainColor 84 | font-size px2rem(36) 85 | border-radius: px2rem(7); 86 | border: px2rem(1) solid darken($mainColor, 6) 87 | color white 88 | &:disabled 89 | background-color: #D8D8D8 90 | border-color:darken(#D8D8D8, 6) 91 | small 92 | display: block 93 | font-size px2rem(26) 94 | margin-top: px2rem(26) 95 | color #888 96 | .footer 97 | width 100% 98 | position: absolute 99 | bottom: px2rem(80) 100 | text-align: center 101 | color #777 102 | font-size px2rem(26) 103 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 纵横阅读 2 | 3 | > 基于vue + 追书api实现的小说阅读应用(UI仿纵横小说) 4 | 5 | 6 | ## 概述 7 | 8 | 这个项目后端使用express,前端使用了vue。 9 | 10 | 前端技术栈为: 11 | - vue 12 | - vue-router 13 | - vuex ... 14 | - hotcss 15 | - stylus + postcss 16 | - axios 17 | 18 | 后端技术栈为: 19 | - express 20 | - body-parser 21 | - express-session 22 | - compression 23 | - compression 24 | - nginx + pm2 25 | 26 | ## 运行方式 27 | ### 安装nodejs8.9+ 28 | Mac:安装nvm,使用nvm安装相应版本Nodejs Windows:Node.js官方安装最新版本 29 | 30 | ``` bash 31 | # 安装依赖 32 | npm install 33 | ``` 34 | 35 | ### 开发环境 36 | ``` bash 37 | # Node.js端运行在 localhost:4000 38 | npm run dev-server 39 | 40 | # Borwser端运行在 localhost:8080 41 | npm start 42 | ``` 43 | 44 | 45 | ### 生产环境 46 | ``` bash 47 | # Node.js服务器 48 | npm run server 49 | 50 | # 编译代码 51 | npm run build 52 | ``` 53 | 54 | ## 项目前端目录 */src* 55 | ``` bash 56 | . 57 | ├── App.vue # 根组件 58 | ├── api # 数据请求文件夹 59 | │   ├── config.js # axios配置 60 | │   └── index.js # 请求方法 61 | ├── assets # 静态资源文件夹(被编译处理) 62 | │   ├── css # css 63 | │   │   ├── reset.styl 64 | │   │   ├── public.styl 65 | │   │   └── ... 66 | │   ├── font # 字体文件 67 | │   ├── image # 图片文件 68 | │   │   └── ... 69 | │   └── js # js文件 70 | │   ├── utils.js 71 | │   └── ... 72 | ├── base # 基础组件 73 | │   ├── Tips.vue 74 | │   └── ... 75 | ├── components # 页面级组件 76 | │   └── ... 77 | ├── main.js # 入口JS文件 78 | ├── router # 路由配置 79 | │   └── index.js # 导出路由 80 | └── vuex # vuex文件夹 81 | ``` 82 | 83 | ## 项目后端目录 */server* 84 | ``` bash 85 | . 86 | ├── api # 请求文件夹 87 | │   ├── README.md 88 | │   ├── index.js 89 | │   └── url.js # 接口地址 90 | ├── app.js # 入口文件 91 | ├── config.js # 配置文件 92 | ├── lib # 工具库 93 | │   └── utils.js # 工具 94 | ├── middleware # 中间件 95 | │   └── index.js 96 | ├── mock # mock数据 97 | │   ├── 1.json 98 | │   ├── banner.json 99 | │   ├── bookList.json 100 | │   ├── defaultBook.json 101 | │   ├── hot.json 102 | │   ├── overBook.json 103 | │   ├── rank.json 104 | │   └── user.json 105 | └── route # 路由文件夹 106 | ├── book.js # 书籍模块 107 | ├── user.js # 用户模块 108 | └── view.js # 视图模块 109 | 110 | ``` 111 | 112 | ## 项目预览地址 113 | 114 | ![链接](http://note.zeebin.top/public/img/qr_code.png) 115 | 116 | ## 辅助开发资源 117 | 118 | 追书API: 119 | https://github.com/zimplexing/vue-nReader/blob/master/doc/zhuishushenqi.md 120 | 121 | hotcss: 122 | http://imochen.github.io/hotcss/ 123 | 124 | ## 功能完成进度 125 | 126 | - [x] 书籍分类 127 | - [x] 书籍列表 128 | - [x] 搜索书籍 129 | - [x] 登录注册 130 | - [x] 书架功能 131 | - [x] 书籍阅读 132 | - [x] 主题切换 133 | - [ ] 书架目录 134 | 135 | 136 | -------------------------------------------------------------------------------- /server/route/view.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const route = express.Router(); 3 | const utils = require('../lib/utils'); 4 | const {keyComplete, getBooks} = require('../api') 5 | 6 | 7 | // banner 请求接口 8 | route.get('/banner', (req, res) => { 9 | utils.readFile('banner.json').then(result => { 10 | res.send({ 11 | code: 200, 12 | result: result, 13 | message: 'ok' 14 | }) 15 | }).catch(err => { 16 | res.status(404) 17 | res.send({ 18 | code: 404, 19 | result: [], 20 | message: 'error' 21 | }) 22 | }) 23 | }) 24 | 25 | // 关键词补充 query ? val= 26 | route.get('/keyCom', async (req, res) => { 27 | keyComplete(req.query['val']).then(result => { 28 | return res.send(result) 29 | }).catch(e => { 30 | console.log(e.message); 31 | res.send({code: 404, message: 'error'}) 32 | }) 33 | }) 34 | 35 | // 书城列表 boutique 36 | route.get('/boutique', async (req, res) => { 37 | let recommend = [ 38 | '5816b415b06d1d32157790b1', 39 | '56928442c49f3bce42b7f521', 40 | '548d9c17eb0337ee6df738f5', 41 | '53e56ee335f79bb626a496c9', 42 | '57ceb2069acafda7326052ae' 43 | ] 44 | let free = [ 45 | '53026961b2c50edb7c080482', 46 | '58f825bb30a95f25565a3d02', 47 | '54a9edf9a8b9b8c35d8a983f', 48 | '520a230cff0b5cf74400277e', 49 | '595b8ee3a54f31975a09c9bd', 50 | '57a981def7c11139427720eb', 51 | ] 52 | let sell = [ 53 | '573d655d608bed412452b999', 54 | '520b6093a9d7038825000344', 55 | '591e62e8c6212c3b4318faff', 56 | '582c5dfd75f1c8ab7a44a94c', 57 | '5710a23e44993b5a22ae36ad', 58 | '59dda2bf19be019161eb4bc9', 59 | ] 60 | let Male = [ 61 | '56928442c49f3bce42b7f521', 62 | '5816b415b06d1d32157790b1', 63 | '582d9b14772890d404ee4bf1', 64 | '54262d86198ede733cfe3d48', 65 | '56de87cbadc279664982afd9', 66 | '5763cb49512c38e3082db209', 67 | ] 68 | let female = [ 69 | '5a95120d4351da46cd34a271', 70 | '599ba0e19a5314622b8f353c', 71 | '5833ed3a45eb4e9f0352ab45', 72 | '57a3744b32a39aa8471d7800', 73 | '569a333316ef9be07f6260bc', 74 | '5532dd5ba155a7a57e70c1e3', 75 | ] 76 | let newBook = [ 77 | '5aa0ff50df01ca1e8fe384d2', 78 | '54dc32e999322a3e7d946659', 79 | '51060bbfbb1c67cf28000026', 80 | '5667b5c224aafd4f3abe7c3f', 81 | '5836323138bcc1c615e5832b', 82 | '56e3cfeb4ee9d70763a24a8d', 83 | ] 84 | let data = { 85 | recommend: await Promise.all(getBooks(recommend)), 86 | free: await Promise.all(getBooks(free)), 87 | sell: await Promise.all(getBooks(sell)), 88 | Male: await Promise.all(getBooks(Male)), 89 | female: await Promise.all(getBooks(female)), 90 | newBook: await Promise.all(getBooks(newBook)) 91 | } 92 | let result = { 93 | code: 200, 94 | success: 'ok', 95 | result: data 96 | } 97 | res.send(result); 98 | }) 99 | 100 | 101 | module.exports = route; 102 | -------------------------------------------------------------------------------- /src/assets/css/reset.styl: -------------------------------------------------------------------------------- 1 | @import "./public.styl" 2 | body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, dl, dt, dd, ul, ol, li, button, input, textarea, th, td 3 | margin: 0; 4 | padding: 0 5 | body 6 | font-size: px2rem(28); 7 | font-style: normal; 8 | font-family: "\5FAE\8F6F\96C5\9ED1", Helvetica, sans-serif 9 | small 10 | font-size: px2rem(24) 11 | h1 12 | font-size: px2rem(36) 13 | h2 14 | font-size: px2rem(38) 15 | h3 16 | font-size: px2rem(28) 17 | h4, h5, h6 18 | font-size: 100% 19 | ul, ol 20 | list-style: none 21 | a 22 | text-decoration: none; 23 | background-color: transparent 24 | color: #000 25 | a:hover, a:active 26 | outline-width: 0; 27 | text-decoration: none 28 | table 29 | border-collapse: collapse; 30 | border-spacing: 0 31 | hr 32 | border: 0; 33 | height: px2rem(1) 34 | img 35 | border-style: none 36 | img:not([src]) 37 | display: none 38 | svg:not(:root) 39 | overflow: hidden 40 | html 41 | -webkit-touch-callout: none; 42 | -webkit-text-size-adjust: 100% 43 | input, textarea, button, a 44 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0) 45 | outline none 46 | article, aside, details, figcaption, figure, footer, header, main, menu, nav, section, summary 47 | display: block 48 | audio, canvas, progress, video 49 | display: inline-block 50 | audio:not([controls]), video:not([controls]) 51 | display: none; 52 | height: 0 53 | progress 54 | vertical-align: baseline 55 | mark 56 | background-color: #ff0; 57 | color: #000 58 | sub, sup 59 | position: relative; 60 | font-size: 75%; 61 | line-height: 0; 62 | vertical-align: baseline 63 | sub 64 | bottom: -0.25em 65 | sup 66 | top: -0.5em 67 | button, input, select, textarea 68 | font-size: 100%; 69 | outline: 0 70 | button, input 71 | overflow: visible 72 | button, select 73 | text-transform: none 74 | textarea 75 | overflow: auto 76 | button, html [type="button"], [type="reset"], [type="submit"] 77 | -webkit-appearance: button 78 | button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, [type="submit"]::-moz-focus-inner 79 | border-style: none; 80 | padding: 0 81 | button:-moz-focusring, [type="button"]:-moz-focusring, [type="reset"]:-moz-focusring, [type="submit"]:-moz-focusring 82 | outline: px2rem(1) dotted ButtonText 83 | [type="checkbox"], [type="radio"] 84 | box-sizing: border-box; 85 | padding: 0 86 | [type="number"]::-webkit-inner-spin-button, [type="number"]::-webkit-outer-spin-button 87 | height: auto 88 | [type="search"] 89 | -webkit-appearance: textfield; 90 | outline-offset: px2rem(-2) 91 | [type="search"]::-webkit-search-cancel-button, [type="search"]::-webkit-search-decoration 92 | -webkit-appearance: none 93 | ::-webkit-input-placeholder 94 | color: inherit; 95 | opacity: .54 96 | ::-webkit-file-upload-button 97 | -webkit-appearance: button; 98 | font: inherit 99 | 100 | // custom 101 | html, body 102 | overflow-x: hidden 103 | background: #f4f4f4 104 | width 100% 105 | height 100% 106 | 107 | -------------------------------------------------------------------------------- /server/mock/user.json: -------------------------------------------------------------------------------- 1 | { 2 | "num": 12, 3 | "userList": [ 4 | { 5 | "id": -1, 6 | "username": "traveler", 7 | "password": "", 8 | "bookshelf": [ 9 | { 10 | "bid": "5a5577e59b2420ef3fda94f2" 11 | }, 12 | { 13 | "bid": "5a780680acaa077a60c2f3b3" 14 | }, 15 | { 16 | "bid": "50bef0732033d09b2f00007f" 17 | } 18 | ], 19 | "forums": [] 20 | }, 21 | { 22 | "id": 1, 23 | "username": "lzbabd", 24 | "password": "d3a99072b2aef542dbe18f3190ef9344", 25 | "bookshelf": [ 26 | { 27 | "bid": "5816b415b06d1d32157790b1" 28 | }, 29 | { 30 | "bid": "50874f79f98e8f7446000017" 31 | }, 32 | { 33 | "bid": "5a780680acaa077a60c2f3b3" 34 | }, 35 | { 36 | "bid": "50bef0732033d09b2f00007f" 37 | } 38 | ], 39 | "forums": [ 40 | 68490, 41 | 189788, 42 | 185282, 43 | 160116 44 | ] 45 | }, 46 | { 47 | "id": 2, 48 | "username": "fgg", 49 | "password": "a8bb12dd523ac5b5d2892920de6e9a9e", 50 | "bookshelf": [], 51 | "forums": [] 52 | }, 53 | { 54 | "id": 3, 55 | "username": "asdasdsa", 56 | "password": "bb53574afac7923a1c0c325727d55f45", 57 | "bookshelf": [], 58 | "forums": [] 59 | }, 60 | { 61 | "id": 4, 62 | "username": "ddddddd", 63 | "password": "989b89f49864543d0feb22c9b7026550", 64 | "bookshelf": [], 65 | "forums": [] 66 | }, 67 | { 68 | "id": 5, 69 | "username": "asdadddd", 70 | "password": "5fe7b99450053aa42ad8ed7c864945ba", 71 | "bookshelf": [], 72 | "forums": [] 73 | }, 74 | { 75 | "id": 6, 76 | "username": "asdasdas", 77 | "password": "44648a46cff74c8cf75cbd53ff681a9d", 78 | "bookshelf": [], 79 | "forums": [] 80 | }, 81 | { 82 | "id": 7, 83 | "username": "sdsdassa", 84 | "password": "2a2993fc197bbb86bdd106efd4f65aba", 85 | "bookshelf": [], 86 | "forums": [] 87 | }, 88 | { 89 | "id": 8, 90 | "username": "asdasdasd", 91 | "password": "0d5f5fc07943f9d30fdf21e4c4a40e20", 92 | "bookshelf": [], 93 | "forums": [] 94 | }, 95 | { 96 | "id": 9, 97 | "username": "asdasdasdas", 98 | "password": "c4319a985c3bdb672da97612d9ad8461", 99 | "bookshelf": [], 100 | "forums": [] 101 | }, 102 | { 103 | "id": 10, 104 | "username": "lkdsbb", 105 | "password": "a8bb12dd523ac5b5d2892920de6e9a9e", 106 | "bookshelf": [], 107 | "forums": [] 108 | }, 109 | { 110 | "id": 11, 111 | "username": "lk1234", 112 | "password": "d3a99072b2aef542dbe18f3190ef9344", 113 | "bookshelf": [], 114 | "forums": [] 115 | }, 116 | { 117 | "id": 12, 118 | "username": "122222", 119 | "password": "31b4be8dc8fb50fc3b253157334ebd9c", 120 | "bookshelf": [], 121 | "forums": [] 122 | } 123 | ] 124 | } 125 | -------------------------------------------------------------------------------- /server/route/book.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const route = express.Router(); 3 | const utils = require('../lib/utils'); 4 | const { 5 | getCategory, 6 | getBooks, 7 | getBookDetail, 8 | getCategoryBooks, 9 | getChapters, 10 | getChapterContent, 11 | searchBookAndAuthor, 12 | getRank, 13 | getRecommend 14 | } = require('../api/index') 15 | 16 | 17 | // 获取分类 18 | route.get('/category', async (req, res) => { 19 | let result = await getCategory(); 20 | for (let key in result) { 21 | if (!result.hasOwnProperty(key) || !Array.isArray(result[key])) continue; 22 | result[key] = result[key].map(item => { 23 | delete item['icon'] 24 | delete item['bookCover'] 25 | delete item['monthlyCount'] 26 | return item 27 | }) 28 | } 29 | res.send(result) 30 | }) 31 | 32 | // todo 获取书籍列表 33 | route.get('/list', async (req, res) => { 34 | let arr = [ 35 | '5a9e4da7a5ee611ea424b033', 36 | '222', 37 | '5a5577e59b2420ef3fda94f2', 38 | '5a5577e59b2420ef3fda94f2', 39 | '5a780680acaa077a60c2f3b3', 40 | ] 41 | let result = await Promise.all(getBooks(arr)) 42 | result = result.filter(book => book['_id']) 43 | res.send(result); 44 | 45 | }) 46 | 47 | // 查看书籍详情 (id:xxx) 48 | route.get('/detail/:id', async (req, res) => { 49 | let result = await getBookDetail(req.params['id']); 50 | if (result['_id']) { 51 | return res.send({ 52 | code: 200, 53 | message: 'ok', 54 | result 55 | }) 56 | } 57 | res.send({ 58 | code: 404, 59 | message: result.msg, 60 | }) 61 | 62 | }) 63 | // 获取相关书籍 64 | route.get('/recommend/:id', async (req, res) => { 65 | let result = await getRecommend(req.params['id']); 66 | res.send({ 67 | code: 200, 68 | message: 'ok', 69 | books: result.books || [], 70 | }) 71 | 72 | }) 73 | 74 | // 获取分类书籍 (query: {}) 75 | route.get('/categoryBooks', async (req, res) => { 76 | let { 77 | gender = 'male', 78 | type = 'reputation', 79 | major = '玄幻', 80 | minor = '', 81 | start = 0, 82 | limit = 10 83 | } = req.query; 84 | let query = { 85 | gender, 86 | type, 87 | major, 88 | minor, 89 | start, 90 | limit, 91 | } 92 | let result = await getCategoryBooks(query); 93 | res.send(result); 94 | 95 | }) 96 | 97 | // 获取章节列表 98 | route.get('/chapters/:id', async (req, res) => { 99 | let result = await getChapters(req.params['id']); 100 | res.send(result); 101 | 102 | }) 103 | 104 | // 获取章节内容 query ?link必须转码 encodeURIComponent 105 | route.get('/chapter/content', async (req, res) => { 106 | let link = encodeURIComponent(req.query['link']) 107 | let result = await getChapterContent(link); 108 | res.send(result); 109 | 110 | }) 111 | 112 | // 搜索书籍 query ?keyword = {} 113 | route.get('/search', async (req, res) => { 114 | let result = await searchBookAndAuthor(req.query) 115 | res.send(result); 116 | 117 | }) 118 | 119 | // 获取排行榜信息 120 | route.get('/ranking', async (req, res) => { 121 | let result = await getRank() 122 | res.send({code: 200, message: 'ok', result: result['ranking']}); 123 | 124 | }) 125 | 126 | module.exports = route; 127 | -------------------------------------------------------------------------------- /src/components/Store.vue: -------------------------------------------------------------------------------- 1 | 39 | 40 | 46 | 47 | 48 | 112 | -------------------------------------------------------------------------------- /server/mock/defaultBook.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "enable": true, 4 | "bookType": 1, 5 | "coverUrl": "https://static.zongheng.com/upload/s_image/cover/2016/12/1482306024388.jpg", 6 | "authorization": 4, 7 | "serialStatus": 0, 8 | "bookId": 578824, 9 | "bookName": "儒武争锋", 10 | "chapterCount": 1569, 11 | "female": 0, 12 | "lastChapterId": 40844654, 13 | "lastChapterName": "第一千五百四十三节:血祭妖尊大圆满!", 14 | "chapterModifyTime": 1522053350000 15 | }, 16 | { 17 | "enable": true, 18 | "bookType": 1, 19 | "coverUrl": "https://static.zongheng.com/upload/s_image/cover/32/0b/320ba84fa6300b68e34df5921a0635b6.jpeg", 20 | "authorization": 4, 21 | "serialStatus": 0, 22 | "bookId": 591243, 23 | "bookName": "超级医生在都市", 24 | "chapterCount": 1353, 25 | "female": 0, 26 | "lastChapterId": 40844756, 27 | "lastChapterName": "第一千三百五十一章 惊喜的迈克尔", 28 | "chapterModifyTime": 1522055227000 29 | }, 30 | { 31 | "enable": true, 32 | "bookType": 1, 33 | "coverUrl": "https://static.zongheng.com/upload/s_image/cover/2017/06/1496383089659.jpg", 34 | "authorization": 4, 35 | "serialStatus": 0, 36 | "bookId": 673214, 37 | "bookName": "娇妻在上:完美宠婚一百招", 38 | "chapterCount": 425, 39 | "female": 1, 40 | "lastChapterId": 40818337, 41 | "lastChapterName": "423一个神奇的男人", 42 | "chapterModifyTime": 1522029553000 43 | }, 44 | { 45 | "enable": true, 46 | "bookType": 1, 47 | "coverUrl": "https://static.zongheng.com/upload/s_image/cover/2015/09/1441699844976.jpg", 48 | "authorization": 4, 49 | "serialStatus": 0, 50 | "bookId": 499738, 51 | "bookName": "天刑纪", 52 | "chapterCount": 923, 53 | "female": 0, 54 | "lastChapterId": 40816166, 55 | "lastChapterName": "第九百二十章 拿人手短", 56 | "chapterModifyTime": 1521989630000 57 | }, 58 | { 59 | "enable": true, 60 | "bookType": 1, 61 | "coverUrl": "https://static.zongheng.com/upload/s_image/cover/2016/10/1476174410510.jpg", 62 | "authorization": 4, 63 | "serialStatus": 0, 64 | "bookId": 611561, 65 | "bookName": "绝品小神医", 66 | "chapterCount": 1976, 67 | "female": 0, 68 | "lastChapterId": 40815121, 69 | "lastChapterName": "第1770章:带你飞(2更)", 70 | "chapterModifyTime": 1521978471000 71 | }, 72 | { 73 | "enable": true, 74 | "bookType": 1, 75 | "coverUrl": "https://static.zongheng.com/upload/s_image/cover/be/5d/be5d65825626035a7e02eb6784f3765d.jpeg", 76 | "authorization": 4, 77 | "serialStatus": 0, 78 | "bookId": 628887, 79 | "bookName": "无敌剑魂", 80 | "chapterCount": 1024, 81 | "female": 0, 82 | "lastChapterId": 40823148, 83 | "lastChapterName": "第一千零二十三章 七佛塔", 84 | "chapterModifyTime": 1522039900000 85 | }, 86 | { 87 | "enable": true, 88 | "bookType": 1, 89 | "coverUrl": "https://static.zongheng.com/upload/s_image/cover/shucheng/44/1194150.jpg", 90 | "authorization": 4, 91 | "serialStatus": 0, 92 | "bookId": 564846, 93 | "bookName": "天才道士", 94 | "chapterCount": 962, 95 | "female": 0, 96 | "lastChapterId": 39971701, 97 | "lastChapterName": "正文_第九百六十二章 轮回,注定的劫(终章)", 98 | "chapterModifyTime": 1514571225000 99 | } 100 | ] 101 | -------------------------------------------------------------------------------- /src/components/store/Classify.vue: -------------------------------------------------------------------------------- 1 | 34 | 57 | 118 | -------------------------------------------------------------------------------- /src/components/Register.vue: -------------------------------------------------------------------------------- 1 | 39 | 107 | 110 | -------------------------------------------------------------------------------- /src/components/store/Queue.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 44 | 45 | 131 | -------------------------------------------------------------------------------- /src/base/Scroll.vue: -------------------------------------------------------------------------------- 1 | 6 | 160 | 162 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 纵横中文 9 | 10 | 11 | 12 | 137 |
138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /server/mock/1.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "_id": "568fef99adb27bfb4b3a58dc", 4 | "source": "zhuishuvip", 5 | "name": "优质书源", 6 | "link": "http://vip.zhuishushenqi.com/toc/568fef99adb27bfb4b3a58dc", 7 | "lastChapter": "正文 第2812章 你会寂寞吗?", 8 | "isCharge": false, 9 | "chaptersCount": 2812, 10 | "updated": "2018-03-27T07:03:32.053Z", 11 | "starting": true, 12 | "host": "vip.zhuishushenqi.com" 13 | }, 14 | { 15 | "_id": "57541d0771fb7acf339bbb37", 16 | "lastChapter": "正文 第2812章 你会寂寞吗?", 17 | "link": "http://book.my716.com/getBooks.aspx?method=chapterList&bookId=683354", 18 | "source": "my176", 19 | "name": "176小说", 20 | "isCharge": false, 21 | "chaptersCount": 2812, 22 | "updated": "2018-03-27T07:05:27.026Z", 23 | "starting": false, 24 | "host": "book.my716.com" 25 | }, 26 | { 27 | "_id": "577b6c81ccb7bf00499d036c", 28 | "lastChapter": "第2708章 回去讨个说法吧!", 29 | "link": "http://www.biquge.la/book/5210/", 30 | "source": "biquge", 31 | "name": "笔趣阁", 32 | "isCharge": false, 33 | "chaptersCount": 2649, 34 | "updated": "2018-02-05T03:21:41.359Z", 35 | "starting": false, 36 | "host": "biquge.la" 37 | }, 38 | { 39 | "_id": "5883c4ed1f4e61f21b3a3920", 40 | "lastChapter": "第2681章 误打误撞!", 41 | "link": "http://www.sanjiangge.com/book/30/30662/index.html", 42 | "source": "sanjiangge", 43 | "name": "三江阁", 44 | "isCharge": false, 45 | "chaptersCount": 2880, 46 | "updated": "2018-01-22T15:51:48.599Z", 47 | "starting": false, 48 | "host": "sanjiangge.com" 49 | }, 50 | { 51 | "_id": "57a192c13b252f673a656db8", 52 | "lastChapter": "第2650章 两支特种部队!5烈焰滔滔", 53 | "link": "http://www.xiaoxiaoshuwu.com/modules/article/reader.php?aid=63480", 54 | "source": "xiaoxiaoshuwu", 55 | "name": "小小书屋", 56 | "isCharge": false, 57 | "chaptersCount": 4440, 58 | "updated": "2018-01-11T15:59:14.441Z", 59 | "starting": false, 60 | "host": "xiaoxiaoshuwu.com" 61 | }, 62 | { 63 | "_id": "57541d0871fb7acf339bbb3b", 64 | "lastChapter": "第2596章 一个人的四面楚歌!", 65 | "link": "http://www.snwx.com/book/99/99818/", 66 | "source": "snwx", 67 | "name": "少年文学网", 68 | "isCharge": false, 69 | "chaptersCount": 2594, 70 | "updated": "2017-12-21T23:00:12.251Z", 71 | "starting": false, 72 | "host": "snwx.com" 73 | }, 74 | { 75 | "_id": "57541d0871fb7acf339bbb3c", 76 | "lastChapter": "第2594章 幸灾乐祸!", 77 | "link": "http://www.2yt.net/17960/", 78 | "source": "w2yt", 79 | "name": "2月天", 80 | "isCharge": false, 81 | "chaptersCount": 2757, 82 | "updated": "2017-12-21T05:28:17.754Z", 83 | "starting": false, 84 | "host": "2yt.net" 85 | }, 86 | { 87 | "_id": "57541d0771fb7acf339bbb38", 88 | "lastChapter": "第2578章 玩大了!", 89 | "link": "http://leduwo.com/book/50/50621/index.html", 90 | "source": "tianyibook", 91 | "name": "乐读窝", 92 | "isCharge": false, 93 | "chaptersCount": 2590, 94 | "updated": "2017-12-10T09:47:07.377Z", 95 | "starting": false, 96 | "host": "leduwo.com" 97 | }, 98 | { 99 | "_id": "57541d0771fb7acf339bbb39", 100 | "lastChapter": "第2368章 他最重要!", 101 | "link": "http://www.hunhun520.com/book/zuiqiangkuangbing/", 102 | "source": "hunhun", 103 | "name": "混混小说网", 104 | "isCharge": false, 105 | "chaptersCount": 3560, 106 | "updated": "2017-09-07T00:28:03.575Z", 107 | "starting": false, 108 | "host": "hunhun520.com" 109 | }, 110 | { 111 | "_id": "57541d0871fb7acf339bbb3d", 112 | "lastChapter": "第2211章 我还真不关心你是谁!", 113 | "link": "http://www.69shu.com/20001/", 114 | "source": "w69shu", 115 | "name": "69书吧", 116 | "isCharge": false, 117 | "chaptersCount": 2204, 118 | "updated": "2017-06-23T16:53:36.837Z", 119 | "starting": false, 120 | "host": "69shu.com" 121 | }, 122 | { 123 | "_id": "57541d0771fb7acf339bbb3a", 124 | "lastChapter": "第2161章 蛮不讲理的火力覆盖!", 125 | "link": "http://www.qingkan.net/book/zuiqiangkuangbing/", 126 | "source": "qingkan", 127 | "name": "请看小说网", 128 | "isCharge": false, 129 | "chaptersCount": 2263, 130 | "updated": "2017-06-02T09:50:26.680Z", 131 | "starting": false, 132 | "host": "qingkan.net" 133 | }, 134 | { 135 | "_id": "585994fae48a78bc2a8c571e", 136 | "lastChapter": "正文 第1028章 埋伏!", 137 | "link": "http://www.79xs.com/Html/Book/91/91054/Index.html", 138 | "source": "shuhaha", 139 | "name": "79小说网", 140 | "isCharge": false, 141 | "chaptersCount": 1720, 142 | "updated": "2016-12-20T20:30:52.082Z", 143 | "starting": false, 144 | "host": "79xs.com" 145 | }, 146 | { 147 | "_id": "579b93af561763dd2d2382e7", 148 | "lastChapter": "第1779章 心不在焉的大少爷!", 149 | "link": "http://www.luoqiu.com/read/9170/", 150 | "source": "luoqiu", 151 | "name": "落秋中文", 152 | "isCharge": false, 153 | "chaptersCount": 1827, 154 | "updated": "2016-12-15T15:17:45.051Z", 155 | "starting": false, 156 | "host": "luoqiu.com" 157 | } 158 | ] 159 | -------------------------------------------------------------------------------- /server/mock/rank.json: -------------------------------------------------------------------------------- 1 | { 2 | "message": "OK", 3 | "result": [ 4 | { 5 | "number": 38983, 6 | "description": "大千世界,无奇不有。我陈平安,唯有一剑,可搬山,倒海,降妖,镇魔,敕神,摘星,断江,摧城,开天!", 7 | "authorName": "烽火戏诸侯", 8 | "coverUrl": "https://static.zongheng.com/upload/s_image/cover/2017/05/1496234539057.JPG", 9 | "serialStatus": 0, 10 | "bookId": 672340, 11 | "bookName": "剑来", 12 | "cateName": "古典仙侠", 13 | "rankNo": null, 14 | "totalWords": "155万" 15 | }, 16 | { 17 | "number": 8942, 18 | "description": "2017年夏天,位于紫薇星域的武道宗门,要修筑一座史无前例的大型传送阵法,以方便他们对于银河系南部星域的开发,而这座阵法的仙力脉冲正好要经过地球,所以,地球要被强拆了。而地球人对此,一无所知。\n请关注公众号【乱世狂刀】。", 19 | "authorName": "乱世狂刀", 20 | "coverUrl": "https://static.zongheng.com/upload/s_image/cover/a7/1a/a71a535fd8ad36ff597e432076b760a2.jpeg", 21 | "serialStatus": 0, 22 | "bookId": 682920, 23 | "bookName": "圣武星辰", 24 | "cateName": "东方玄幻", 25 | "rankNo": null, 26 | "totalWords": "177万" 27 | }, 28 | { 29 | "number": 8880, 30 | "description": "功夫究竟是什么?花架子还是杀人技?三千年冷兵器战争和无数民间私斗酝酿出来的把式,究竟是不是骗局?国术流开创者,功夫小说第一人梦入神机,在本书中为您揭秘。止戈为武,点到为止。“你若无敌,将会如何?”“得饶人处且饶人。”", 31 | "authorName": "梦入神机", 32 | "coverUrl": "https://static.zongheng.com/upload/s_image/cover/2c/1f/2c1fe294306eea58638e7d07a12a7628.jpeg", 33 | "serialStatus": 0, 34 | "bookId": 730066, 35 | "bookName": "点道为止", 36 | "cateName": "都市生活", 37 | "rankNo": null, 38 | "totalWords": "36万" 39 | }, 40 | { 41 | "number": 7777, 42 | "description": "修仙归来成奶爸,建山头,开餐厅,写写歌,泡泡孩她妈......且看修仙奶爸如何玩转都市。 ps:正版读者微信群:加微信1334725041验证入群(积分500以上)。普通读者Q群:162099227。ps2:推荐师道力作:《重生之商业大亨》。", 43 | "authorName": "单王张", 44 | "coverUrl": "https://static.zongheng.com/upload/s_image/cover/de/3c/de3ccb25c9283d485dd0485e763752eb.jpeg", 45 | "serialStatus": 0, 46 | "bookId": 719827, 47 | "bookName": "神级奶爸", 48 | "cateName": "都市重生", 49 | "rankNo": null, 50 | "totalWords": "87万" 51 | }, 52 | { 53 | "number": 7254, 54 | "description": "天地初始,宇宙洪荒;奇门九遁,布道星空。\n当地球尘封万古的雪山龙棺移位时刻,诛天大道临世,神魔文明到来,宇宙如同撕裂枷锁的神魔,演化着一个精彩绝伦的修行世界。\n仙命少年从弱小中崛起,一步步踏向宇宙星海,战万界,伐仙穹......\n作者微信公众号“一叶青天”,VIP订阅群:434739889", 55 | "authorName": "一叶青天", 56 | "coverUrl": "https://static.zongheng.com/upload/s_image/cover/ff/83/ff835851b6c6c44d8199839e770447c0.jpeg", 57 | "serialStatus": 0, 58 | "bookId": 735577, 59 | "bookName": "帝道独尊", 60 | "cateName": "东方玄幻", 61 | "rankNo": null, 62 | "totalWords": "18万" 63 | }, 64 | { 65 | "number": 5424, 66 | "description": "【蜻蜓FM有声书千万点击原著,繁体出版,读者群89798139】千年前穿越异世,成就一代儒圣,却遭武帝暗算身陨。千年后再世重生,武帝屠灭儒道传承,独尊天下,飞升天外之天。\n三世轮回,秦枫面对武帝神像,握紧手中剑:“天外天重逢之日,便是你血债血偿,身死道消之时!”", 67 | "authorName": "情殇孤月", 68 | "coverUrl": "https://static.zongheng.com/upload/s_image/cover/2016/12/1482306024388.jpg", 69 | "serialStatus": 0, 70 | "bookId": 578824, 71 | "bookName": "儒武争锋", 72 | "cateName": "东方玄幻", 73 | "rankNo": null, 74 | "totalWords": "355万" 75 | }, 76 | { 77 | "number": 5290, 78 | "description": "一个现代商人回到明末的山西能做什么?他将成为晋商领袖?他将富可敌国?他将掌握人心,成立理事会,最终将大明变成一个庞大的股份制公司?他将成立商团,用利益驱使士兵,最终获得无上权力?一切尽在大明1617,这是一本以商人角度切入明朝的作品,期待与您共同穿越时空,打造我们共同的新大明。", 79 | "authorName": "淡墨青衫", 80 | "coverUrl": "https://static.zongheng.com/upload/s_image/cover/2015/08/1438797020681.jpg", 81 | "serialStatus": 0, 82 | "bookId": 490607, 83 | "bookName": "大明1617", 84 | "cateName": "架空历史", 85 | "rankNo": null, 86 | "totalWords": "483万" 87 | }, 88 | { 89 | "number": 4075, 90 | "description": "他曾是仙门弃徒,遭人陷害,千年后重生醒来,凭不灭神魂,盖世神功,令八方风云乱,夺天地造化,掌生死之权,叱咤九境,昔日诸神为惧。\n(悬疑仙侠剧情流,书友千人群:76089602。微信公众号:神出古异)", 91 | "authorName": "神出古异", 92 | "coverUrl": "https://static.zongheng.com/upload/s_image/cover/2016/07/1468835876117.jpg", 93 | "serialStatus": 0, 94 | "bookId": 513438, 95 | "bookName": "九界仙尊", 96 | "cateName": "奇幻修真", 97 | "rankNo": null, 98 | "totalWords": "503万" 99 | }, 100 | { 101 | "number": 4056, 102 | "description": "今朝修仙不为仙,只为春色花满园;来日九星冲牛斗,且看天刑开纪元。——光明阁vip群:423807160光明阁聊天群:209710200", 103 | "authorName": "曳光", 104 | "coverUrl": "https://static.zongheng.com/upload/s_image/cover/2015/09/1441699844976.jpg", 105 | "serialStatus": 0, 106 | "bookId": 499738, 107 | "bookName": "天刑纪", 108 | "cateName": "奇幻修真", 109 | "rankNo": null, 110 | "totalWords": "298万" 111 | }, 112 | { 113 | "number": 3923, 114 | "description": "山中少年孟凡,意外得修大帝观想图,观想上古大帝,碾压异族,武极巅峰,人道称尊! 人道帝路,自其而始,万古不朽!\n(书友群:460768905,欢迎各位加入)", 115 | "authorName": "笑面虎难画骨", 116 | "coverUrl": "https://static.zongheng.com/upload/s_image/cover/5e/9d/5e9d2fafba58b9b1a360a4d798ca3bd4.jpeg", 117 | "serialStatus": 0, 118 | "bookId": 678554, 119 | "bookName": "人道帝尊", 120 | "cateName": "东方玄幻", 121 | "rankNo": null, 122 | "totalWords": "144万" 123 | } 124 | ], 125 | "code": 200 126 | } 127 | -------------------------------------------------------------------------------- /server/route/user.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const route = express.Router(); 3 | const {writeFile} = require('../lib/utils'); 4 | const {getBooks, getHotForums} = require('../api/index') 5 | 6 | // 判断是书籍是否已经存入书架 7 | let hasInBookshelf = (req, bid) => req.bookshelf.some(item => item['bid'] === bid); 8 | 9 | 10 | // 请求书架列表 11 | route.get('/bookshelf', (req, res) => { 12 | 13 | let bookshelf = req.bookshelf || []; 14 | 15 | // 生成请求bid数组 16 | bookshelf = bookshelf.map(item => item.bid) 17 | 18 | Promise.all(getBooks(bookshelf)).then(result => { 19 | res.send({code: 200, result: result, message: 'ok'}) 20 | }).catch(err => { 21 | console.log(err); 22 | res.send({code: 404, result: [], message: 'error'}) 23 | }) 24 | 25 | }) 26 | 27 | // 添加到书架列表 post {id:bookid} 28 | route.post('/bookshelf', async (req, res) => { 29 | let bookId = req.body.id; 30 | // 判断是否已经存入书架 31 | if (hasInBookshelf(req, bookId)) { 32 | // 这本书已经在书架了 33 | return res.send({code: 404, message: 'Have it already'}) 34 | } 35 | let newBook = {bid: bookId} 36 | if (req.isLogin) { 37 | // 用户已登录 存入user文件 38 | let userId = req.session.userId; 39 | let user = req.userList.find(item => parseInt(item.id) === parseInt(userId)) 40 | user['bookshelf'].unshift(newBook) 41 | writeFile('user.json', { 42 | num: req.userCount, 43 | userList: req.userList 44 | }).then(() => { 45 | return res.send({code: 200, message: 'ok'}) 46 | }) 47 | } else { 48 | // 用户没有登录 存入session书架 49 | req.session.bookshelf.unshift(newBook) 50 | res.send({code: 200, message: 'ok'}) 51 | } 52 | }) 53 | 54 | // 从书架列表移除 post {id:bookid} 55 | route.delete('/bookshelf/:id', async (req, res) => { 56 | let bookId = req.params.id; 57 | // 判断是否存在 58 | if (!hasInBookshelf(req, bookId)) { 59 | // 这本书不存在 60 | return res.send({code: 404, message: 'Invalid id'}) 61 | } 62 | 63 | if (req.isLogin) { 64 | // 用户已登录 从user文件删除 65 | let userId = req.session.userId; 66 | let user = req.userList.find(item => parseInt(item.id) === parseInt(userId)) 67 | let n = user['bookshelf'].findIndex(item => item['bid'] === bookId) || 0; 68 | user['bookshelf'].splice(n, 1) 69 | writeFile('user.json', { 70 | num: req.userCount, 71 | userList: req.userList 72 | }).then(() => { 73 | return res.send({code: 200, message: 'ok'}) 74 | }) 75 | } else { 76 | // 用户没有登录 从session中删除 77 | let n = req.session.bookshelf.findIndex(item => item['bid'] === bookId) || 0; 78 | req.session.bookshelf.splice(n, 1) 79 | res.send({code: 200, message: 'ok'}) 80 | } 81 | }) 82 | 83 | // 判断是书籍是否已经存入书架 84 | route.get('/hasBookInBookshelf/:bid', (req, res) => { 85 | let bid = req.params['bid'] 86 | if (hasInBookshelf(req, bid)) { 87 | return res.send({code: 404, includes: true, message: '书籍已收藏'}) 88 | } 89 | res.send({code: 200, includes: false, message: '书籍未收藏'}) 90 | }) 91 | 92 | // 获取圈子信息 query ? page= 93 | route.get('/forums', async (req, res) => { 94 | let {result} = await getHotForums(req.query['page']) 95 | // 判断是否关注了 96 | result = result.map(item => { 97 | item['isFollow'] = req.isLogin ? req.userInfo['forums'].includes(item['forumId']) : false 98 | return item 99 | }) 100 | res.send({code: 200, result, message: 'ok'}) 101 | }) 102 | 103 | 104 | // 用户登录 {username, password} 105 | route.post('/login', (req, res) => { 106 | if (req.isLogin) return res.send({ 107 | code: 401, 108 | message: '用户已登录', 109 | id: req.session.userId 110 | }) 111 | let {username, password} = req.body; 112 | if (!username || !password) { 113 | return res.send({code: 404, message: 'Invalid params'}) 114 | } 115 | let user = req.userList.find(item => item.username === username); 116 | 117 | if (user) { 118 | if (user.password === password) { 119 | req.session.userId = user.id; 120 | req.session.bookshelf = null; 121 | return res.send({code: 200, message: 'ok', id: user.id}); 122 | } 123 | return res.send({code: 400, message: '用户名或密码错误'}) 124 | } 125 | res.send({code: 402, message: '用户名未注册'}) 126 | }) 127 | 128 | // 退出登录 129 | route.get('/logout', (req, res) => { 130 | if (!req.isLogin) return res.send({ 131 | code: 401, 132 | message: '用户未登录' 133 | }) 134 | 135 | req.session.userId = null; 136 | req.session.bookshelf = null; 137 | res.send({code: 200, message: 'ok'}) 138 | }) 139 | 140 | // 用户注册 {username, password} 141 | route.post('/register', async (req, res) => { 142 | let {username, password} = req.body; 143 | if (!username || !password) { 144 | return res.send({code: 404, message: 'Invalid params'}) 145 | } 146 | let user = req.userList.find(item => item.username === username); 147 | 148 | if (user) { 149 | return res.send({code: 400, message: '用户名已存在'}) 150 | } 151 | 152 | let newUser = { 153 | "id": ++req.userCount, 154 | "username": username.toString(), 155 | "password": password.toString(), 156 | "bookshelf": [], 157 | "forums": [] 158 | } 159 | req.userList.push(newUser) 160 | writeFile('user.json', { 161 | num: req.userCount, 162 | userList: req.userList 163 | }).then(() => { 164 | return res.send({code: 200, message: 'ok', id: newUser.id}) 165 | }).catch(e => { 166 | console.log(e); 167 | return res.send({code: 404, message: 'error'}) 168 | }) 169 | }) 170 | 171 | // 验证是否登录 172 | route.get('/isLogin', (req, res) => { 173 | if (req.isLogin) { 174 | res.send({ 175 | code: 200, 176 | isLogin: true, 177 | message: '用户已登录', 178 | id: req.session.userId 179 | }) 180 | return 181 | } 182 | res.send({code: 404, isLogin: false, message: '用户未登录'}) 183 | }) 184 | 185 | // 请求用户信息 186 | route.get('/userInfo', async (req, res) => { 187 | if (!req.isLogin) return res.send({ 188 | code: 401, 189 | message: '用户未登录' 190 | }) 191 | let info = req.userInfo || {}; 192 | res.send({ 193 | code: 200, 194 | result: info, 195 | id: req.session.userId 196 | }) 197 | }) 198 | 199 | 200 | module.exports = route; 201 | -------------------------------------------------------------------------------- /src/components/Circle.vue: -------------------------------------------------------------------------------- 1 | 51 | 52 | 79 | 80 | 81 | 270 | -------------------------------------------------------------------------------- /src/components/store/Theme.vue: -------------------------------------------------------------------------------- 1 | 33 | 127 | 249 | -------------------------------------------------------------------------------- /server/mock/hot.json: -------------------------------------------------------------------------------- 1 | { 2 | "message": "ok", 3 | "result": [ 4 | { 5 | "contentType": 1, 6 | "threadId": 15437043, 7 | "bookId": 672340, 8 | "threadTitle": "《剑来》第二百六十一章 有剑从云海来 看点", 9 | "imgUrl": "https://static.zongheng.com/upload/s_image/cover/2017/05/1496234539057.JPG", 10 | "threadNum": 336639, 11 | "rawThreadImgUrls": [], 12 | "recommendBookTitles": "", 13 | "threadThumbnailUrls": [], 14 | "forumId": 160116, 15 | "followerNum": 15277, 16 | "forumTitle": "剑来", 17 | "threadContent": "1.在骊珠洞天小庙内曾有已经陨落的外乡剑仙说过有关女子和云海半仙兵的传闻,但未必属实。\n\r2.范峻茂与郑大风首次见面时为洞府境,如今为金丹境,境界攀升之快骇人听闻\n\r3.绿袍儿范峻茂疑似可以看破天机。\n\r4.范俊茂使用云海仙兵的方式,类似于投掷枪矛成剑\n\r5.初一与绿袍疑似旧识。\n\r6.范二在范家会..." 18 | }, 19 | { 20 | "contentType": 1, 21 | "threadId": 15438951, 22 | "bookId": 0, 23 | "threadTitle": "你经历过最尴尬的事情是什么?", 24 | "imgUrl": "https://static.zongheng.com/upload/bbs/35/e7/35e750d81476564e11e5a47bca1f46ce.jpeg", 25 | "threadNum": 33040, 26 | "rawThreadImgUrls": [ 27 | "https://static.zongheng.com/upload/bbs/8d/c5/8dc584021eb1c5c7ca1be85101613bf6.jpeg", 28 | "https://static.zongheng.com/upload/bbs/31/81/3181b1a3bec096e8538dd5862ef5476e.jpeg", 29 | "https://static.zongheng.com/upload/bbs/a9/3f/a93fdbeb26ca3b279f4c6aeb45711ddc.jpeg", 30 | "https://static.zongheng.com/upload/bbs/58/8a/588a9fbd72a9a8ee4ad87b946694ddea.jpeg", 31 | "https://static.zongheng.com/upload/bbs/da/fb/dafbb551b0150715557d3d07f18687ae.jpeg", 32 | "https://static.zongheng.com/upload/bbs/92/f1/92f1c521d68b7acb05a926605cb2d6f0.jpeg", 33 | "https://static.zongheng.com/upload/bbs/0f/77/0f77c0da3ffcdce9c218e814fd2a07b4.jpeg" 34 | ], 35 | "recommendBookTitles": "", 36 | "threadThumbnailUrls": [ 37 | "https://static.zongheng.com/upload/thumb/bbs/8d/c5/216/216/92cf64b702e3d7036789c44ae7c0ab54/8dc584021eb1c5c7ca1be85101613bf6.jpeg", 38 | "https://static.zongheng.com/upload/thumb/bbs/31/81/216/216/6ee819f9a32da51d9cb908cc1ad50b28/3181b1a3bec096e8538dd5862ef5476e.jpeg", 39 | "https://static.zongheng.com/upload/thumb/bbs/a9/3f/216/216/b95ae5f59817208acccea42f432376c6/a93fdbeb26ca3b279f4c6aeb45711ddc.jpeg", 40 | "https://static.zongheng.com/upload/thumb/bbs/58/8a/216/216/c1f923fdd285cdda55f6fc71e8675b2f/588a9fbd72a9a8ee4ad87b946694ddea.jpeg", 41 | "https://static.zongheng.com/upload/thumb/bbs/da/fb/216/216/7b0b086ed7ec3bf59a5c9c2302e0d0a1/dafbb551b0150715557d3d07f18687ae.jpeg", 42 | "https://static.zongheng.com/upload/thumb/bbs/92/f1/216/216/c3c58186fd5c27457b879cb2e62caf46/92f1c521d68b7acb05a926605cb2d6f0.jpeg", 43 | "https://static.zongheng.com/upload/thumb/bbs/0f/77/216/216/da9560642fc0c5830426ea5e3e6b9a3a/0f77c0da3ffcdce9c218e814fd2a07b4.jpeg" 44 | ], 45 | "forumId": 116320, 46 | "followerNum": 6741, 47 | "forumTitle": "大话纵横", 48 | "threadContent": "知乎上有一个这样的话题:\n你经历过的最尴尬的事情是什么?\n底下一个同学的回答拿到了最高赞!\n然后他的事迹就被人画出来了…" 49 | }, 50 | { 51 | "contentType": 1, 52 | "threadId": 15439309, 53 | "bookId": 685640, 54 | "imgUrl": "https://static.zongheng.com/upload/s_image/cover/fe/98/fe98b68f0627ee2b1fef1b478a9835cc.jpeg", 55 | "threadNum": 40468, 56 | "rawThreadImgUrls": [], 57 | "recommendBookTitles": "", 58 | "threadThumbnailUrls": [], 59 | "forumId": 166796, 60 | "followerNum": 5350, 61 | "forumTitle": "元尊", 62 | "threadContent": "哼,看样子晚上能分出胜负" 63 | }, 64 | { 65 | "contentType": 1, 66 | "threadId": 15435277, 67 | "bookId": 0, 68 | "threadTitle": "联盟出了一个母老虎", 69 | "imgUrl": "https://static.zongheng.com/upload/bbs/8c/28/8c282a90aeda6606169164ef943fb914.jpeg", 70 | "threadNum": 12714, 71 | "rawThreadImgUrls": [], 72 | "recommendBookTitles": "", 73 | "threadThumbnailUrls": [], 74 | "forumId": 135093, 75 | "followerNum": 5737, 76 | "forumTitle": "书荒互助", 77 | "threadContent": "路人:女强人人挡杀人 佛挡杀佛 凶神恶煞的嘞~\n女主:(微笑)你说什么?\n——重返地球:星际女上校" 78 | }, 79 | { 80 | "contentType": 1, 81 | "threadId": 15430549, 82 | "bookId": 408586, 83 | "imgUrl": "https://static.zongheng.com/upload/s_image/cover/2014/11/1416425191645.jpg", 84 | "threadNum": 102798, 85 | "rawThreadImgUrls": [], 86 | "recommendBookTitles": "", 87 | "threadThumbnailUrls": [], 88 | "forumId": 41327, 89 | "followerNum": 7553, 90 | "forumTitle": "逆天邪神", 91 | "threadContent": "你们都忘了吗?最开始去找茉莉的那个人,把猪脚差点弄死的那个。" 92 | }, 93 | { 94 | "contentType": 1, 95 | "threadId": 15438841, 96 | "bookId": 0, 97 | "threadTitle": "现在的微商小伙伴是越来越厉害了,跪了跪了!", 98 | "imgUrl": "https://static.zongheng.com/upload/bbs/bb/16/bb166d33d839537c59bdb1de621bfbb7.jpeg", 99 | "threadNum": 6995, 100 | "rawThreadImgUrls": [ 101 | "https://static.zongheng.com/upload/bbs/c9/16/c916a850675a229a4c428bd4fa696819.jpeg", 102 | "https://static.zongheng.com/upload/bbs/fb/1e/fb1e288cf19adb0f69fcf1a384522f1b.jpeg", 103 | "https://static.zongheng.com/upload/bbs/31/ba/31ba464d9c3771843d4161ac9b5836b1.jpeg", 104 | "https://static.zongheng.com/upload/bbs/13/8b/138b2de61c28fb45709bc3f9012ebbde.jpeg", 105 | "https://static.zongheng.com/upload/bbs/bc/a1/bca1db731e5e5eabde26c8026a4e105e.jpeg", 106 | "https://static.zongheng.com/upload/bbs/53/6d/536dc8cedce8fc20d3979d3dc6886da3.jpeg", 107 | "https://static.zongheng.com/upload/bbs/75/9e/759e253c28a7f902baf0e33aa5740e97.jpeg", 108 | "https://static.zongheng.com/upload/bbs/0a/a0/0aa0226f7f6dcc64ea17f5f972da7589.jpeg", 109 | "https://static.zongheng.com/upload/bbs/bf/87/bf87072375aeb878fe1e0c5216b69beb.jpeg" 110 | ], 111 | "recommendBookTitles": "", 112 | "threadThumbnailUrls": [ 113 | "https://static.zongheng.com/upload/thumb/bbs/c9/16/216/216/d310f352b3819d3610a877f1e62972b4/c916a850675a229a4c428bd4fa696819.jpeg", 114 | "https://static.zongheng.com/upload/thumb/bbs/fb/1e/216/216/2b69561a466c6f8cd1bc82de04132bf9/fb1e288cf19adb0f69fcf1a384522f1b.jpeg", 115 | "https://static.zongheng.com/upload/thumb/bbs/31/ba/216/216/25f1fd5947f58a702671dfddf5a6f9f7/31ba464d9c3771843d4161ac9b5836b1.jpeg", 116 | "https://static.zongheng.com/upload/thumb/bbs/13/8b/216/216/cd3a2c18cac9e53ae496aeefc59e4ac2/138b2de61c28fb45709bc3f9012ebbde.jpeg", 117 | "https://static.zongheng.com/upload/thumb/bbs/bc/a1/216/216/791ea3ef1910c055579f8470a619049e/bca1db731e5e5eabde26c8026a4e105e.jpeg", 118 | "https://static.zongheng.com/upload/thumb/bbs/53/6d/216/216/8069ebb8adf735d993648862df76e90a/536dc8cedce8fc20d3979d3dc6886da3.jpeg", 119 | "https://static.zongheng.com/upload/thumb/bbs/75/9e/216/216/e914f359aef0727a63f2d3cef4c98c64/759e253c28a7f902baf0e33aa5740e97.jpeg", 120 | "https://static.zongheng.com/upload/thumb/bbs/0a/a0/216/216/8b14b4b272d2c5fdcf60c177dcdd9cd8/0aa0226f7f6dcc64ea17f5f972da7589.jpeg", 121 | "https://static.zongheng.com/upload/thumb/bbs/bf/87/216/216/37ab6d8ab1d75aa554231ea6a7d22e7e/bf87072375aeb878fe1e0c5216b69beb.jpeg" 122 | ], 123 | "forumId": 148876, 124 | "followerNum": 1519, 125 | "forumTitle": "奇葩吐槽", 126 | "threadContent": "你们知道现在的微商有多厉害吗?\n你们都看好了,别吓得腿软我告诉你!!!" 127 | }, 128 | { 129 | "contentType": 1, 130 | "threadId": 1990593, 131 | "bookId": 342974, 132 | "threadTitle": "来自 章四十二 宁静生活 的评论", 133 | "imgUrl": "https://static.zongheng.com/upload/s_image/cover/2016/01/1453257564712.jpg", 134 | "threadNum": 207779, 135 | "rawThreadImgUrls": [], 136 | "recommendBookTitles": "", 137 | "threadThumbnailUrls": [], 138 | "forumId": 16899, 139 | "followerNum": 4698, 140 | "forumTitle": "永夜君王", 141 | "threadContent": "不得不承认大大刻画人物的功力深厚,但是我真得特别讨厌这种牛皮癣一般的人,千夜的从开头的垃圾场就被这货坑,到后来这货莫名其妙被白家败家女T给养着,继续努力给别人制造麻烦。这种精神套句老一辈人的话就是,要是用到建设社会主义上去的话估计已经可以奔大康啦。嗯,千夜也在某些方面有些欠缺,不是说不努力啊,也不是..." 142 | }, 143 | { 144 | "contentType": 1, 145 | "threadId": 15438525, 146 | "bookId": 0, 147 | "threadTitle": "原来这些名言都有后半句", 148 | "imgUrl": "https://static.zongheng.com/upload/bbs/d6/64/d664fcaaf9e8b0db4ced0d74b91fe67f.jpeg", 149 | "threadNum": 5886, 150 | "rawThreadImgUrls": [ 151 | "https://static.zongheng.com/upload/bbs/4d/48/4d48c8681bd674545a0d2fb343411b97.jpeg" 152 | ], 153 | "recommendBookTitles": "", 154 | "threadThumbnailUrls": [ 155 | "https://static.zongheng.com/upload/thumb/bbs/4d/48/690/270/85ec1c9f79d28dfe07b25cdc08de9aa7/4d48c8681bd674545a0d2fb343411b97.jpeg" 156 | ], 157 | "forumId": 165892, 158 | "followerNum": 920, 159 | "forumTitle": "读者之家", 160 | "threadContent": "父母在,不远游?\n\n你知道几个呢?" 161 | }, 162 | { 163 | "contentType": 1, 164 | "threadId": 15438714, 165 | "bookId": 0, 166 | "threadTitle": "【作者专栏】蛮杏出墙来:写作不易,且行且珍惜", 167 | "imgUrl": "https://static.zongheng.com/upload/bbs/54/6c/546cb0a3a0f8b57861eacdeea8c5aea2.jpeg", 168 | "threadNum": 8398, 169 | "rawThreadImgUrls": [ 170 | "https://static.zongheng.com/upload/bbs/8b/c6/8bc6c2b456434de75030c2d87bb24750.jpeg" 171 | ], 172 | "recommendBookTitles": "", 173 | "threadThumbnailUrls": [ 174 | "https://static.zongheng.com/upload/thumb/bbs/8b/c6/690/270/40dd4fbe82f0d4da1ce2996433584b92/8bc6c2b456434de75030c2d87bb24750.jpeg" 175 | ], 176 | "forumId": 177692, 177 | "followerNum": 521, 178 | "forumTitle": "女神集中营", 179 | "threadContent": "女神集中营【作者专栏】开栏啦~~~\n欢迎广大作者来投稿~~\n投稿路径:\n来女神集中营交流群联系——【作者专栏】美少女\n与大家分享你的经验、见解\n \n作者简介:\n蛮杏出墙来,花语女生网A级签约作者,目前小说《说案谈情》《以庶为贵》正在花语女生网连载,另著有《妃祸天下:战神认栽吧》《医等邪妃》等完结作品..." 180 | }, 181 | { 182 | "contentType": 1, 183 | "threadId": 15439259, 184 | "bookId": 673218, 185 | "threadTitle": "来自 第三百八十五章、逃生 的评论", 186 | "imgUrl": "https://static.zongheng.com/upload/s_image/cover/dc/52/dc52975b76b1392fa6e40ee80a62cb82.jpeg", 187 | "threadNum": 7209, 188 | "rawThreadImgUrls": [], 189 | "recommendBookTitles": "", 190 | "threadThumbnailUrls": [], 191 | "forumId": 160131, 192 | "followerNum": 75, 193 | "forumTitle": "末日崛起", 194 | "threadContent": "订阅追书,支持大大!" 195 | } 196 | ], 197 | "code": 200 198 | } 199 | -------------------------------------------------------------------------------- /src/components/Mine.vue: -------------------------------------------------------------------------------- 1 | 142 | 195 | 310 | -------------------------------------------------------------------------------- /src/components/Reack.vue: -------------------------------------------------------------------------------- 1 | 113 | 163 | 391 | 392 | -------------------------------------------------------------------------------- /src/components/Read.vue: -------------------------------------------------------------------------------- 1 | 52 | 219 | 397 | -------------------------------------------------------------------------------- /src/components/store/End.vue: -------------------------------------------------------------------------------- 1 | 120 | 121 | 150 | 151 | 344 | -------------------------------------------------------------------------------- /src/components/store/Charge.vue: -------------------------------------------------------------------------------- 1 | 122 | 123 | 152 | 153 | 346 | -------------------------------------------------------------------------------- /src/components/store/Woman.vue: -------------------------------------------------------------------------------- 1 | 123 | 124 | 153 | 154 | 347 | --------------------------------------------------------------------------------