├── .gitignore ├── API.md ├── README.md ├── app.js ├── app.json ├── app.wxss ├── components ├── behaviors │ └── pagination.js ├── book │ ├── index.js │ ├── index.json │ ├── index.wxml │ └── index.wxss ├── classic │ ├── classic-beh.js │ ├── common.wxss │ ├── essay │ │ ├── images │ │ │ └── essay@tag.png │ │ ├── index.js │ │ ├── index.json │ │ ├── index.wxml │ │ └── index.wxss │ ├── movie │ │ ├── images │ │ │ └── movie@tag.png │ │ ├── index.js │ │ ├── index.json │ │ ├── index.wxml │ │ └── index.wxss │ └── music │ │ ├── images │ │ ├── music@tag.png │ │ ├── player@playing.png │ │ └── player@waitting.png │ │ ├── index.js │ │ ├── index.json │ │ ├── index.wxml │ │ └── index.wxss ├── epsoide │ ├── index.js │ ├── index.json │ ├── index.wxml │ └── index.wxss ├── image-button │ ├── index.js │ ├── index.json │ ├── index.wxml │ └── index.wxss ├── like │ ├── images │ │ ├── like.png │ │ └── like@dis.png │ ├── index.js │ ├── index.json │ ├── index.wxml │ ├── index.wxss │ └── like-beh.js ├── loading │ ├── index.js │ ├── index.json │ ├── index.wxml │ └── index.wxss ├── mask │ ├── index.js │ ├── index.json │ ├── index.wxml │ └── index.wxss ├── navi │ ├── images │ │ ├── triangle.dis@left.png │ │ ├── triangle.dis@right.png │ │ ├── triangle@left.png │ │ └── triangle@right.png │ ├── index.js │ ├── index.json │ ├── index.wxml │ └── index.wxss ├── preview │ ├── index.js │ ├── index.json │ ├── index.wxml │ └── index.wxss ├── search │ ├── images │ │ ├── cancel.png │ │ └── search.png │ ├── index.js │ ├── index.json │ ├── index.wxml │ └── index.wxss └── tag │ ├── index.js │ ├── index.json │ ├── index.wxml │ └── index.wxss ├── config.js ├── images ├── book │ ├── quality.png │ └── tip.png ├── icon │ ├── search.png │ └── share.png ├── my │ ├── about.png │ ├── course.png │ ├── like.png │ ├── my.png │ ├── my@bg.png │ ├── study.png │ └── vendor.png └── tab │ ├── book.png │ ├── book@highlight.png │ ├── classic.png │ ├── classic@highlight.png │ ├── my.png │ └── my@highlight.png ├── models ├── book.js ├── classic.js ├── comment.js ├── keyword.js └── like.js ├── pages ├── about │ ├── about.js │ ├── about.json │ ├── about.wxml │ └── about.wxss ├── book-detail │ ├── book-detail.js │ ├── book-detail.json │ ├── book-detail.wxml │ └── book-detail.wxss ├── book │ ├── book.js │ ├── book.json │ ├── book.wxml │ └── book.wxss ├── classic-detail │ ├── classic-detail.js │ ├── classic-detail.json │ ├── classic-detail.wxml │ └── classic-detail.wxss ├── classic │ ├── classic.js │ ├── classic.json │ ├── classic.wxml │ └── classic.wxss ├── course │ ├── course.js │ ├── course.json │ ├── course.wxml │ └── course.wxss └── my │ ├── my.js │ ├── my.json │ ├── my.wxml │ └── my.wxss ├── project.config.json ├── promise.md ├── sitemap.json ├── utils ├── filter.wxs ├── http-p.js ├── http.js └── util.js └── 纯正商业级应用-微信小程序开发实战.mmap /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | .vscode 3 | .idea/ 4 | Pipfile.lock 5 | project.config.json 6 | node_modules 7 | -------------------------------------------------------------------------------- /API.md: -------------------------------------------------------------------------------- 1 | # old-land-flask-api 2 | ## API说明 3 | * 点赞和取消点赞接口需要携带token 4 | * token必须通过小程序的code换取 5 | * 无论是提交数据还是返回数据只支持json 6 | * API遵从严格的HTTP动作并采用标准的 Http Status Code 作为响应状态,建议采用HTTP状态码作为Api调用是否成功的标识,具体异常请通过错误码判断 7 | 8 | - [返回码](README.md#返回码) 9 | * [HTTP 状态码](README.md#HTTP状态码) 10 | * [错误码(error_code)](README.md#错误码) 11 | 12 | - [期刊](README.md#期刊) 13 | * [获取最新一期](README.md#获取最新一期) 14 | * [获取当前一期的下一期](README.md#获取当前一期的下一期) 15 | * [获取某一期详细信息](README.md#获取某一期详细信息) 16 | * [获取当前一期的上一期](README.md#获取当前一期的上一期) 17 | * [获取点赞信息](README.md#获取点赞信息) 18 | * [获取我喜欢的期刊](README.md#获取我喜欢的期刊) 19 | 20 | - [书籍](README.md#书籍) 21 | * [获取热门书籍](README.md#获取热门书籍) 22 | * [获取书籍短评](README.md#获取书籍短评) 23 | * [获取喜欢书籍数量](README.md#获取喜欢书籍数量) 24 | * [获取书籍点赞情况](README.md#获取书籍点赞情况) 25 | * [新增短评](README.md#新增短评) 26 | * [获取热搜关键字](README.md#获取热搜关键字) 27 | * [书籍搜索](README.md#书籍搜索) 28 | * [获取书籍详细信息](README.md#获取书籍详细信息) 29 | 30 | - [点赞](README.md#点赞) 31 | * [进行点赞](README.md#进行点赞) 32 | * [取消点赞](README.md#取消点赞) 33 | 34 | - [小程序登录](README.md#小程序登录) 35 | * [获取token](README.md#获取token) 36 | * [验证token](README.md#验证token) 37 | 38 | 39 | # 返回码 40 | ## HTTP状态码 41 | 42 | | 状态码 | 含义 | 说明 | 43 | | ------ | ------------------------- | -------------------- | 44 | | 200 | OK | 请求成功 | 45 | | 201 | CREATED | 创建成功 | 46 | | 202 | ACCEPTED | 更新成功 | 47 | | 204 | NO CONTENT | 删除成功 | 48 | | 301 | MOVED PERMANENTLY | 永久重定向 | 49 | | 400 | BAD REQUEST | 请求包含不支持的参数 | 50 | | 401 | UNAUTHORIZED | 未授权 | 51 | | 403 | FORBIDDEN | 被禁止访问 | 52 | | 404 | NOT FOUND | 请求的资源不存在 | 53 | | 413 | REQUIRED LENGTH TOO LARGE | 上传的File体积太大 | 54 | | 500 | INTERNAL SERVER ERROR | 内部错误 | 55 | 56 | 57 | ## 错误码 58 | 59 | 请以错误码来判断具体的错误,不要以文字描述作为判断的依据 60 | 61 | >100x 通用类型: 62 | 63 | | 错误码 | 含义 | 64 | | ------ | -------------------- | 65 | | 0 | OK, 成功 | 66 | | 1000 | 输入参数错误 | 67 | | 1001 | 输入的json格式不正确 | 68 | | 1002 | 找不到资源 | 69 | | 1003 | 未知错误 | 70 | | 1004 | 禁止访问 | 71 | | 1005 | 不正确的开发者key | 72 | | 1006 | 服务器内部错误 | 73 | 74 | 75 | >200x 点赞类型 76 | 77 | | 错误码 | 含义 | 78 | | ------ | -------------- | 79 | | 2000 | 你已经点过赞了 | 80 | | 2001 | 你还没点过赞 | 81 | 82 | 83 | >300x 期刊类型 84 | 85 | | 错误码 | 含义 | 86 | | ------ | -------------- | 87 | | 3000 | 该期内容不存在 | 88 | 89 | 90 | # 期刊 91 | 92 | ## 获取最新一期 93 | URL: 94 | >GET /classic/latest 95 | 96 | Response 200: 97 | ```json 98 | { 99 | "content": "人生不能像做菜,把所有的材料准备好才下锅", 100 | "fav_nums": 2, 101 | "id": 8, 102 | "image": "http://127.0.0.1:5000/v1/movie.2.png", 103 | "index": 8, 104 | "like_status": 0, 105 | "pubdate": "2018-08-14", 106 | "title": "李安《饮食男女》", 107 | "type": 100 108 | } 109 | ``` 110 | 111 | Response_description: 112 | * content:期刊内容 113 | * fav_nums: 点赞次数 114 | * image: 图片 115 | * index: 期号 116 | * like_status: 是否点赞 117 | * pubdate: 发布日期 118 | * title: 期刊题目 119 | * type: 期刊类型,这里的类型分为:100 电影 200 音乐 300 句子 120 | * id: 期刊在数据中序号,供点赞使用 121 | * 返回期刊的详细信息 122 | 123 | ## 获取当前一期的下一期 124 | URL: 125 | >GET /classic//next 126 | 127 | >demo /classic/2/next 128 | 129 | Parameters: 130 | 131 | * id:id号,必填,必须是正整数 132 | 133 | Response 200: 134 | ```json 135 | { 136 | "content": "你陪我不如蝉夏 越过城市喧嚣", 137 | "fav_nums": 0, 138 | "id": 3, 139 | "image": "http://127.0.0.1:5000/v1/music.2.png", 140 | "index": 3, 141 | "like_status": 0, 142 | "pubdate": "2018-08-14", 143 | "title": "花弼《纸短情长》", 144 | "type": 200, 145 | "url": "http://music.163.com/song/media/outer/url?id=557581284.mp3" 146 | } 147 | ``` 148 | 149 | ## 获取某一期详细信息 150 | URL: 151 | >GET /classic// 152 | 153 | >demo /classic/200/1 154 | 155 | Parameters: 156 | 157 | * id:id号,必填,必须是正整数 158 | * type: 类型号,必填,为100,200,300的一种,分别表示电影,音乐,句子 159 | 160 | Response 200: 161 | ```json 162 | { 163 | "content": "岁月长,衣裳薄", 164 | "fav_nums": 0, 165 | "id": 1, 166 | "image": "http://127.0.0.1:5000/v1/music.1.png", 167 | "index": 1, 168 | "like_status": 0, 169 | "pubdate": "2018-08-14", 170 | "title": "杨千嬅《再见二丁目》", 171 | "type": 200, 172 | "url": "http://music.163.com/song/media/outer/url?id=557581284.mp3" 173 | } 174 | ``` 175 | 176 | ## 获取当前一期的上一期 177 | URL: 178 | >GET /classic//next 179 | 180 | >demo /classic/5/next 181 | 182 | Parameters: 183 | * id:id号,必填,必须是正整数 184 | 185 | Response 200: 186 | ```json 187 | { 188 | "content": "在变换的生命里,岁月原来是最大的小偷", 189 | "fav_nums": 0, 190 | "id": 4, 191 | "image": "http://127.0.0.1:5000/v1/movie.1.png", 192 | "index": 4, 193 | "like_status": 0, 194 | "pubdate": "2018-08-14", 195 | "title": "罗启锐《岁月神偷》", 196 | "type": 100 197 | } 198 | ``` 199 | 200 | ## 获取点赞信息 201 | 202 | URL: 203 | >GET /classic///favor 204 | 205 | >demo /classic/200/7/favor 206 | 207 | Parameters: 208 | 209 | * id:id号,必填,必须是正整数 210 | * type: 类型号,必填,为100,200,300的一种,分别表示电影,音乐,句子 211 | * token: 通过 Basic Auth方式传递 username: eyJhbGciOiJIUzI1NiIsImlhdCI6MTUzNDUxODQ0MCwiZXhwIjoxNTM3MTEwNDQwfQ.eyJ1aWQiOjEsInR5cGUiOjIwMCwic2NvcGUiOiJVc2VyU2NvcGUifQ.S1YoU30kgUIwYRgyCVeDgL2VvYcTlmeGph6P9Vd2irg, password: '' 212 | 213 | Response 200: 214 | 215 | ```json 216 | { 217 | "fav_nums": 2, 218 | "id": 7, 219 | "like_status": 1 220 | } 221 | ``` 222 | 223 | ## 获取我喜欢的期刊 224 | URL: 225 | >GET /classic/favor 226 | 227 | Parameters: 228 | * token 229 | 230 | Response 200: 231 | 232 | ```json 233 | [ 234 | { 235 | "content": "人生不能像做菜,把所有的材料准备好才下锅", 236 | "fav_nums": 2, 237 | "id": 8, 238 | "image": "http://127.0.0.1:5000/v1/movie.2.png", 239 | "index": 8, 240 | "like_status": 1, 241 | "pubdate": "2018-08-14", 242 | "title": "李安《饮食男女》", 243 | "type": 100 244 | }, 245 | { 246 | "content": "谁念过 千字文章 秋收冬已藏", 247 | "fav_nums": 2, 248 | "id": 7, 249 | "image": "http://127.0.0.1:5000/v1/music.4.png", 250 | "index": 7, 251 | "like_status": 1, 252 | "pubdate": "2018-08-14", 253 | "title": "不才《参商》", 254 | "type": 200, 255 | "url": "http://music.163.com/song/media/outer/url?id=557581284.mp3" 256 | }, 257 | { 258 | "content": "谁念过 千字文章 秋收冬已藏", 259 | "fav_nums": 2, 260 | "id": 7, 261 | "image": "http://127.0.0.1:5000/v1/music.4.png", 262 | "index": 7, 263 | "like_status": 1, 264 | "pubdate": "2018-08-14", 265 | "title": "不才《参商》", 266 | "type": 200, 267 | "url": "http://music.163.com/song/media/outer/url?id=557581284.mp3" 268 | } 269 | ] 270 | ``` 271 | 272 | 273 | 274 | 275 | ## 获取热门书籍 276 | 277 | URL: 278 | 279 | >GET /book/hot_list 280 | 281 | Response 200: 282 | 283 | ```json 284 | [ 285 | { 286 | "author": [ 287 | "Vamei" 288 | ], 289 | "fav_nums": 3, 290 | "id": 13, 291 | "image": "https://img1.doubanio.com/lpic/s29166309.jpg", 292 | "like_status": 0, 293 | "title": "从Python开始学编程" 294 | }, 295 | { 296 | "author": [ 297 | "MarkPilgrim" 298 | ], 299 | "fav_nums": 2, 300 | "id": 5, 301 | "image": "https://img3.doubanio.com/lpic/s4059293.jpg", 302 | "like_status": 0, 303 | "title": "Dive Into Python 3" 304 | } 305 | ] 306 | ``` 307 | 308 | 309 | ## 获取书籍短评 310 | 311 | URL: 312 | 313 | >GET /book//shot_comment 314 | 315 | Parameters: 316 | 317 | * book_id:书籍的id,必填,必须为正整数 318 | * Response 200: 319 | 320 | ```json 321 | { 322 | "book_id": 1, 323 | "comment": [ 324 | { 325 | "book_id": 1, 326 | "content": "这个书不错", 327 | "nums": 1 328 | }, 329 | { 330 | "book_id": 1, 331 | "content": "而是的回忆!七龙珠", 332 | "nums": 9 333 | }, 334 | { 335 | "book_id": 1, 336 | "content": "回忆杀!", 337 | "nums": 19 338 | } 339 | ] 340 | } 341 | ``` 342 | 343 | Response_description: 344 | 345 | * comment: 一个评论的列表,包含用户对书籍的评论及对应数量的字典 346 | * book_id: 书籍id 347 | 348 | 349 | 350 | Parameters: 351 | 352 | 353 | response_description: 354 | 355 | * fav_nums:点赞数 356 | * id: 书籍id 357 | * like_status: 是否点赞 358 | * author: 作者 359 | * title: 书籍题目 360 | * image: 书籍图片 361 | * 返回一个列表,包含所有热门书籍的概要信息 362 | 363 | 364 | ## 获取喜欢书籍数量 365 | 366 | URL: 367 | 368 | >GET /book/favor/count 369 | 370 | Parameters: 371 | * token 372 | ```json 373 | { 374 | "count": 1 375 | } 376 | ``` 377 | Response_description: 378 | 379 | * count: 返回我喜欢的书籍数量 380 | 381 | 382 | ## 获取书籍点赞情况 383 | 384 | URL: 385 | 386 | >GET /book//favor 387 | 388 | Parameters: 389 | 390 | * book_id:书籍的id,必填,必须为正整数 391 | 392 | Response 200: 393 | 394 | ```json 395 | { 396 | "fav_nums": 0, 397 | "id": 1, 398 | "like_status": 0 399 | } 400 | ``` 401 | 402 | 403 | ## 新增短评 404 | 405 | URL: 406 | 407 | >POST /book/add/comment 408 | 409 | Parameters: 410 | 411 | * book_id:书籍id 412 | * content:评论内容,我们可允许的评论内容范围为12字以内 413 | 414 | Response 201: 415 | ```json 416 | { 417 | "error_code": 0, 418 | "msg": "OK", 419 | "request": "POST /v1/book/add/short_comment" 420 | } 421 | ``` 422 | 423 | ## 获取热搜关键字 424 | 425 | URL: 426 | >GET /json 427 | 428 | Response 200: 429 | ```json 430 | { 431 | "hot": [ 432 | "鸟山明", 433 | "龙珠", 434 | "http", 435 | "PHP", 436 | "周", 437 | "阿", 438 | "火箭", 439 | "阿斯达", 440 | "\bphp", 441 | "\bpython3", 442 | "鲁迅", 443 | "python" 444 | ] 445 | } 446 | ``` 447 | 448 | ## 书籍搜索 449 | 450 | URL: 451 | >GET /book/search 452 | 453 | > demo1 /book/search?q=七龙珠 454 | 455 | > demo2 /book/search?q=七龙珠&summary=1 456 | 457 | Parameters: 458 | 459 | * start: 开始记录数,默认为0 460 | * count: 记录条数,默认为20,超过依然按照20条计算 461 | * summary: 返回完整或简介,默认为0,0为完整内容,1为简介 462 | * q:搜索内容 463 | 464 | Response 200: 465 | 466 | 当summary=0,返回详细数据: 467 | 468 | 469 | ```json 470 | { 471 | "books": [ 472 | { 473 | "author": [ 474 | "[日]鸟山明" 475 | ], 476 | "category": "日本漫画", 477 | "id": 17699, 478 | "image": "https://img1.doubanio.com/lpic/s28671937.jpg", 479 | "isbn": "9787600100354", 480 | "pages": "全42册", 481 | "price": "367.6", 482 | "pubdate": "2005-7-1", 483 | "publisher": "中国少年儿童出版社", 484 | "subtitle": "", 485 | "summary": "《DRAGON BALL》译名《龙珠》(又名:七龙珠)是日本著名漫画家鸟山明的得意作品,1984年登场,1992年又推出『龙珠』续集。这部长篇巨作在『少年跳跃』上连载7年。\\n故事讲述了孙悟空(当然不是我们神化中的那个齐天大圣喽)父子和那7颗能满足人们心愿的龙珠,把读者从山村引到城市,从地球引到外星,又从现在引到未来。\\n根据《龙珠》的漫画故事,还推出了《龙珠》的系列动画片,无论是TV版还是剧场版,都吸引了无数的龙珠迷,掀起了一股股“龙珠”的热潮。\\n龙珠的舞台,虽说是带有中国色彩的,但是也并非就限定在中国;时代也一样,并没有把它固定在某一个具体时间。整个故事架构很简单,至于一些细节和结局,我想任其自由发展。这么一来,连我自己也会想[故事下一步会怎么发展啊],并为之捏了一把汗。因为无论怎么发挥都可以,所以乐在其中。\\n传说中,地球四处散落着7颗龙珠。如果谁将他们收集起来就可以实现自己的愿望,人们为了得到它而不断的你争我夺……每年都会有一场以龙珠为奖品的《天下第一武道大会》……在地球的一个角落,生活着孙悟空这个茁壮的孩子,他的身份其实是赛亚人卡卡罗特。因为婴儿时的变身能力不够而被派往地球,其实是为了毁灭地球生物而变成殖民地,但他生来和平,丝毫不知自己的身世……这种战斗力超强的种族“赛亚人”与宇宙中另一些种族“那美克星人”等等间发生了无数惊险有趣又富有教育意义的故事……这就是日本著名漫画家“鸟山明”创造的《七龙珠》世界。", 486 | "title": "龙珠(全42册)", 487 | "translator": [ 488 | "牟琳" 489 | ] 490 | }, 491 | { 492 | "author": [ 493 | "[日]鸟山明" 494 | ], 495 | "category": "日本漫画", 496 | "id": 18569, 497 | "image": "https://img3.doubanio.com/lpic/s11231433.jpg", 498 | "isbn": "9787500774860", 499 | "pages": "175", 500 | "price": "6.9", 501 | "pubdate": "2005-7", 502 | "publisher": "中国少年儿童出版社", 503 | "subtitle": "孙悟空和伙伴们", 504 | "summary": "《龙珠(套装共42册)》是日本著名漫画家鸟山明的得意作品。相传,有七颗龙珠散落在世界的各个角落,当它们被聚集到一起时神龙就会出现,能够实现你的任何一个愿望。这个一个美丽的的传说引出了小悟空和他的朋友们寻找龙珠的故事。", 505 | "title": "龙珠1", 506 | "translator": [ 507 | "牟琳" 508 | ] 509 | } 510 | ], 511 | "count": 20, 512 | "start": 0, 513 | "total": 2 514 | } 515 | ``` 516 | 517 | 当summary=1,返回概要数据: 518 | 519 | ```json 520 | { 521 | "books": [ 522 | { 523 | "author": [ 524 | "[日]鸟山明" 525 | ], 526 | "id": 17699, 527 | "image": "https://img1.doubanio.com/lpic/s28671937.jpg", 528 | "isbn": "9787600100354", 529 | "price": "367.6", 530 | "title": "龙珠(全42册)" 531 | }, 532 | { 533 | "author": [ 534 | "[日]鸟山明" 535 | ], 536 | "id": 18569, 537 | "image": "https://img3.doubanio.com/lpic/s11231433.jpg", 538 | "isbn": "9787500774860", 539 | "price": "6.9", 540 | "title": "龙珠1" 541 | } 542 | ], 543 | "count": 20, 544 | "start": 0, 545 | "total": 2 546 | } 547 | ``` 548 | 549 | 550 | ## 获取书籍详细信息 551 | 552 | URL: 553 | 554 | >GET /book//detail 555 | 556 | >demo /book/6548683/detail 557 | 558 | Parameters: 559 | 560 | id: 书籍的id号,从豆瓣API获取 561 | 562 | Response 200: 563 | 564 | ```json 565 | { 566 | "author": [ 567 | "申音" 568 | ], 569 | "category": "", 570 | "id": "6548683", 571 | "image": "https://img1.doubanio.com/view/subject/m/public/s6569607.jpg", 572 | "isbn": "9787807674030", 573 | "pages": "262", 574 | "price": "35.00元", 575 | "pubdate": "2011-7-1", 576 | "publisher": "山西经济出版社", 577 | "subtitle": "为何普世商业价值在中国行不通", 578 | "summary": "★为什么美国没有史玉柱,中国没有乔布斯?\n★什么是“对的行业”、“错的行业”?\n★我们需要什么样的营销?\n★老板为什么要读商学院?\n★山寨公司还需要管理吗?\n★资源问题是个“伪问题”?\n★别把商业模式当成葵花宝典\n★给海归技术创业兄弟的九个忠告\n★在一个不伟大的行业里,做一个伟大的公司\n★是什么让互联网遭遇了有史以来最鸡犬不宁的一战?", 579 | "title": "商业的常识", 580 | "translator": "" 581 | } 582 | ``` 583 | 584 | # 点赞 585 | 586 | ## 进行点赞 587 | URL: 588 | 589 | >POST /like 590 | 591 | Parameters: 592 | 593 | * art_id: 点赞对象,例如你想对电影进行点赞,那这个参数就是电影的id号 594 | * type:点赞类型分为四种:100 电影 200 音乐 300 句子 400 书籍 595 | 596 | Response Status 201: 597 | 598 | ```json 599 | { 600 | "error_code": 0, 601 | "msg": "OK", 602 | "request": "POST /v1/like" 603 | } 604 | ``` 605 | 606 | ## 取消点赞 607 | URL: 608 | >POST /like/cancel 609 | 610 | Parameters: 611 | 612 | * art_id: 点赞对象id 613 | * type:点赞类型 614 | 615 | Response Status 201: 616 | ```json 617 | { 618 | "error_code": 0, 619 | "msg": "OK", 620 | "request": "POST /v1/like" 621 | } 622 | ``` 623 | 624 | 625 | # 小程序登录 626 | 627 | ## 获取token 628 | 629 | URL: 630 | >POST /token/mina 631 | 632 | Parameters: 633 | * code: wx.login API获取的code值。 634 | 635 | Response Status 200: 636 | ```json 637 | { 638 | "token" : "eyJhbGciOiJIUzI1NiIsImlhdCI6MTUzNDUxODQ0MCwiZXhwIjoxNTM3MTEwNDQwfQ.eyJ1aWQiOjEsInR5cGUiOjIwMCwic2NvcGUiOiJVc2VyU2NvcGUifQ.S1YoU30kgUIwYRgyCVeDgL2VvYcTlmeGph6P9Vd2irg" 639 | } 640 | ``` 641 | 642 | Response_description: 643 | 644 | * token: 供需要权限认证的接口请使用 645 | 646 | ## 验证token 647 | 648 | Parameters: 649 | * token: 需要权限认证的接口请使用HTTP BASIC方式在header头中传递token,headers中的键名为 Authorization, 键值为 base64(basic token:'') 650 | 651 | Response Status 200: 652 | ```json 653 | { 654 | "error_code": 1008, 655 | "msg": "token is invalid", 656 | "request": "POST /v1/like/cancel" 657 | } 658 | ``` 659 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # imooc-pure 2 | 3 | > 纯正商业级应用-微信小程序开发实战 appkey 4 | 5 | - RdshydjBvcYZhMZC 6 | - GgRhTjUNUYn1fHke 7 | 8 | ## 运行 9 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | // app.js 2 | App({ 3 | onLaunch: function() { 4 | // 展示本地存储能力 5 | var logs = wx.getStorageSync('logs') || [] 6 | logs.unshift(Date.now()) 7 | wx.setStorageSync('logs', logs) 8 | // 登录 9 | wx.login({ 10 | success: res => { 11 | // 发送 res.code 到后台换取 openId, sessionKey, unionId 12 | } 13 | }) 14 | // 获取用户信息 15 | wx.getSetting({ 16 | success: res => { 17 | if (res.authSetting['scope.userInfo']) { 18 | // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框 19 | wx.getUserInfo({ 20 | success: res => { 21 | // 可以将 res 发送给后台解码出 unionId 22 | this.globalData.userInfo = res.userInfo 23 | // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 24 | // 所以此处加入 callback 以防止这种情况 25 | if (this.userInfoReadyCallback) { 26 | this.userInfoReadyCallback(res) 27 | } 28 | } 29 | }) 30 | } 31 | } 32 | }) 33 | }, 34 | globalData: { 35 | userInfo: null 36 | } 37 | }) 38 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": [ 3 | "pages/book/book", 4 | "pages/classic/classic", 5 | "pages/my/my", 6 | "pages/book-detail/book-detail", 7 | "pages/about/about", 8 | "pages/course/course", 9 | "pages/classic-detail/classic-detail" 10 | ], 11 | "window": { 12 | "backgroundTextStyle": "light", 13 | "navigationBarBackgroundColor": "#fff", 14 | "navigationBarTitleText": "旧岛小样", 15 | "navigationBarTextStyle": "black", 16 | "navigationStyle": "default" 17 | }, 18 | "tabBar": { 19 | "borderStyle": "black", 20 | "selectedColor": "#000", 21 | "backgroundColor": "#fff", 22 | "color": "#c7c7c7", 23 | "list": [ 24 | { 25 | "pagePath": "pages/classic/classic", 26 | "selectedIconPath": "/images/tab/classic@highlight.png", 27 | "iconPath": "/images/tab/classic.png", 28 | "text": "流行" 29 | }, 30 | { 31 | "pagePath": "pages/book/book", 32 | "selectedIconPath": "/images/tab/book@highlight.png", 33 | "iconPath": "/images/tab/book.png", 34 | "text": "书单" 35 | }, 36 | { 37 | "pagePath": "pages/my/my", 38 | "selectedIconPath": "/images/tab/my@highlight.png", 39 | "iconPath": "/images/tab/my.png", 40 | "text": "喜欢" 41 | } 42 | ] 43 | }, 44 | "sitemapLocation": "sitemap.json" 45 | } -------------------------------------------------------------------------------- /app.wxss: -------------------------------------------------------------------------------- 1 | /* 组件会自动被 page 包裹 */ 2 | page { 3 | font-family: PingFangSC-Thin; 4 | font-size: 16px; 5 | } 6 | -------------------------------------------------------------------------------- /components/behaviors/pagination.js: -------------------------------------------------------------------------------- 1 | let paginationBev = Behavior({ 2 | properties: {}, 3 | data: { 4 | count: 20, 5 | empty: false, 6 | dataArray: [], 7 | total: null, 8 | noneResult: false, 9 | loading: false 10 | }, 11 | methods: { 12 | setMoreData: function(dataArray) { 13 | if (dataArray == false) { 14 | this.data.ending = true 15 | if (this.data.dataArray === false) { 16 | this.setData({ 17 | empty: true 18 | }) 19 | } 20 | } 21 | let temp = this.data.dataArray.concat(dataArray) 22 | this.data.start += this.data.count 23 | this.setData({ 24 | dataArray: temp 25 | }) 26 | return true 27 | }, 28 | setTotal(total) { 29 | this.data.total = total 30 | if (total == 0) { 31 | this.setData({ 32 | noneResult: true 33 | }) 34 | } 35 | }, 36 | hasMore: function() { 37 | if (this.data.dataArray.length >= this.data.total) { 38 | return false 39 | } else { 40 | return true 41 | } 42 | }, 43 | getCurrentStart: function() { 44 | return this.data.dataArray.length 45 | }, 46 | initPagination: function() { 47 | this.data.total = null 48 | this.setData({ 49 | dataArray: [], 50 | noneResult: false, 51 | loading: false 52 | }) 53 | }, 54 | isLocked() { 55 | return this.data.loading ? true : false 56 | }, 57 | locked() { 58 | this.setData({ 59 | loading: true 60 | }) 61 | }, 62 | unLocked() { 63 | this.setData({ 64 | loading: false 65 | }) 66 | } 67 | } 68 | }) 69 | 70 | export { paginationBev } 71 | -------------------------------------------------------------------------------- /components/book/index.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | properties: { 3 | book: Object, 4 | showLike: { 5 | type: Boolean, 6 | value: true 7 | } 8 | }, 9 | data: { 10 | title: String, 11 | author: String, 12 | img: String 13 | }, 14 | methods: { 15 | onTap: function(event) { 16 | const bid = this.properties.book.id 17 | this.triggerEvent( 18 | 'booktap', 19 | { 20 | bid: this.properties.book.id 21 | }, 22 | {} 23 | ) 24 | wx.navigateTo({ 25 | url: `/pages/book-detail/book-detail?bid=${bid}` 26 | }) 27 | } 28 | } 29 | }) 30 | -------------------------------------------------------------------------------- /components/book/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } 5 | -------------------------------------------------------------------------------- /components/book/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{book.title}} 5 | {{book.author}} 6 | 7 | {{book.fav_nums}} 喜欢 8 | 9 | 10 | -------------------------------------------------------------------------------- /components/book/index.wxss: -------------------------------------------------------------------------------- 1 | .container { 2 | display: flex; 3 | flex-direction: column; 4 | /* 使其不为 static, 参考 */ 5 | position: relative; 6 | margin: 30rpx 0 0 0; 7 | width: 240rpx; 8 | height: 360rpx; 9 | box-shadow: 4rpx 4rpx 6rpx #e3e3e3; 10 | } 11 | 12 | .container image { 13 | border-radius: 4rpx; 14 | width: 100%; 15 | height: 100%; 16 | } 17 | 18 | .description { 19 | display: flex; 20 | flex-direction: column; 21 | /* 覆盖 位置重叠, 参照元素为 relative 的元素, 不参考 static */ 22 | position: absolute; 23 | bottom: 0; 24 | padding: 5rpx 10rpx 8rpx 15rpx; 25 | border-bottom-right-radius: 4rpx; 26 | border-bottom-left-radius: 4rpx; 27 | /* 真正宽度要加上 panding border */ 28 | /* 240rpx - 10prx - 15rpx = 215rpx, 不取奇数, 216rpx */ 29 | width: 216rpx; 30 | font-size: 24rpx; 31 | background-color: #fff; 32 | } 33 | 34 | .title { 35 | margin: 10rpx 0 0 0; 36 | text-overflow: ellipsis; 37 | white-space: nowrap; 38 | overflow: hidden; 39 | } 40 | 41 | .author { 42 | margin: -5rpx 0 10rpx 0; 43 | font-size: 20rpx; 44 | color: #999; 45 | text-overflow: ellipsis; 46 | white-space: nowrap; 47 | overflow: hidden; 48 | } 49 | 50 | .foot { 51 | display: flex; 52 | flex-direction: row; 53 | justify-content: flex-end; 54 | font-size: 20rpx; 55 | } 56 | 57 | .footer { 58 | color: #666; 59 | } 60 | -------------------------------------------------------------------------------- /components/classic/classic-beh.js: -------------------------------------------------------------------------------- 1 | let classicBehavior = Behavior({ 2 | properties: { 3 | type: String, 4 | img: String, 5 | content: String, 6 | hidden: Boolean 7 | } 8 | }) 9 | 10 | export { classicBehavior } 11 | -------------------------------------------------------------------------------- /components/classic/common.wxss: -------------------------------------------------------------------------------- 1 | .classic-container { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | } 6 | 7 | .classic-img { 8 | width: 750rpx; 9 | height: 500rpx; 10 | } 11 | 12 | .tag { 13 | position: relative; 14 | bottom: 58rpx; 15 | right: 310rpx; 16 | width: 46rpx; 17 | height: 142rpx; 18 | } 19 | 20 | .content { 21 | max-width: 550rpx; 22 | font-size: 36rpx; 23 | } -------------------------------------------------------------------------------- /components/classic/essay/images/essay@tag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/components/classic/essay/images/essay@tag.png -------------------------------------------------------------------------------- /components/classic/essay/index.js: -------------------------------------------------------------------------------- 1 | import { classicBehavior } from '../classic-beh.js' 2 | 3 | Component({ 4 | // 组件的属性列表 5 | behaviors: [classicBehavior] 6 | }) 7 | -------------------------------------------------------------------------------- /components/classic/essay/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } 5 | -------------------------------------------------------------------------------- /components/classic/essay/index.wxml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /components/classic/essay/index.wxss: -------------------------------------------------------------------------------- 1 | @import "../common.wxss"; -------------------------------------------------------------------------------- /components/classic/movie/images/movie@tag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/components/classic/movie/images/movie@tag.png -------------------------------------------------------------------------------- /components/classic/movie/index.js: -------------------------------------------------------------------------------- 1 | import { classicBehavior } from '../classic-beh.js' 2 | 3 | Component({ 4 | behaviors: [classicBehavior] // 组件的属性列表 5 | }) 6 | -------------------------------------------------------------------------------- /components/classic/movie/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } 5 | -------------------------------------------------------------------------------- /components/classic/movie/index.wxml: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /components/classic/movie/index.wxss: -------------------------------------------------------------------------------- 1 | @import "../common.wxss"; -------------------------------------------------------------------------------- /components/classic/music/images/music@tag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/components/classic/music/images/music@tag.png -------------------------------------------------------------------------------- /components/classic/music/images/player@playing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/components/classic/music/images/player@playing.png -------------------------------------------------------------------------------- /components/classic/music/images/player@waitting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/components/classic/music/images/player@waitting.png -------------------------------------------------------------------------------- /components/classic/music/index.js: -------------------------------------------------------------------------------- 1 | import { classicBehavior } from '../classic-beh.js' 2 | 3 | let mMgr = wx.getBackgroundAudioManager() // 音乐对象 4 | 5 | Component({ 6 | behaviors: [classicBehavior], // 组件的属性列表 7 | properties: { 8 | src: String, 9 | title: String 10 | }, 11 | data: { 12 | playing: false, 13 | waittingUrl: 'images/player@waitting.png', 14 | playingUrl: 'images/player@playing.png' 15 | }, 16 | attached: function() { // 微信生命周期, 组件进入界面节点树时执行 17 | this._recoverPlaying() 18 | this._monitorSwitch() 19 | }, 20 | // hidden 不会触发完整生命周期, 适用于频繁切换; wx:if 会触发完整生命周期, 不大可能改变 21 | // detached: function() { // 微信生命周期, 组件退出界面节点树时执行 22 | // wx.pauseBackgroundAudio() 23 | // }, 24 | methods: { 25 | onPlay: function(event) { 26 | if (!this.data.playing) { 27 | this.setData({ 28 | playing: true 29 | }) 30 | if (mMgr.src === this.properties.src) { 31 | mMgr.play() 32 | } else { 33 | mMgr.src = this.properties.src 34 | } 35 | mMgr.title = this.properties.title 36 | } else { 37 | this.setData({ 38 | playing: false 39 | }) 40 | mMgr.pause() 41 | } 42 | }, 43 | _recoverPlaying: function() { 44 | if (mMgr.paused) { 45 | this.setData({ 46 | playing: false 47 | }) 48 | return 49 | } 50 | if (mMgr.src === this.properties.src) { 51 | if (!mMgr.paused) { 52 | this.setData({ 53 | playing: true 54 | }) 55 | } 56 | } 57 | }, 58 | _monitorSwitch: function() { 59 | mMgr.onPlay(() => { 60 | this._recoverPlaying() 61 | }) 62 | mMgr.onPause(() => { 63 | this._recoverPlaying() 64 | }) 65 | mMgr.onStop(() => { 66 | this._recoverPlaying() 67 | }) 68 | mMgr.onEnded(() => { 69 | this._recoverPlaying() 70 | }) 71 | } 72 | } 73 | }) 74 | -------------------------------------------------------------------------------- /components/classic/music/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } 5 | -------------------------------------------------------------------------------- /components/classic/music/index.wxml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /components/classic/music/index.wxss: -------------------------------------------------------------------------------- 1 | @keyframes rotation { 2 | from { 3 | -webkit-transform: rotate(0deg); 4 | } 5 | to { 6 | -webkit-transform: rotate(360deg); 7 | } 8 | } 9 | 10 | .rotation { 11 | transform: rotate(360deg); 12 | animation: rotation 12s linear infinite; 13 | -moz-animation: rotation 12s linear infinite; 14 | -webkit-animation: rotation 12s linear infinite; 15 | -o-animation: rotation 12s linear infinite; 16 | } 17 | 18 | .classic-container { 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | } 23 | 24 | .classic-img { 25 | margin-top: 60rpx; 26 | border-radius: 70%; 27 | width: 422rpx; 28 | height: 422rpx; 29 | overflow: hidden; 30 | } 31 | 32 | .player-img { 33 | position: relative; 34 | bottom: 271rpx; 35 | width: 120rpx; 36 | height: 120rpx; 37 | } 38 | 39 | .tag { 40 | position: relative; 41 | bottom: 160rpx; 42 | right: 310rpx; 43 | width: 44rpx; 44 | height: 127rpx; 45 | } 46 | 47 | .content { 48 | display: block; 49 | margin-top: -90rpx; 50 | max-width: 550rpx; 51 | font-size: 36rpx; 52 | } 53 | -------------------------------------------------------------------------------- /components/epsoide/index.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | properties: { 3 | index: { 4 | type: Number, 5 | observer: function(newVal, oldVal, changedPath) { // 数据改变时调用 observer changedPath 属性被改变时执行的函数(可选),也可以写成在 methods 段中定义的方法名字符串, 如:'_propertyChange' 通常 newVal 就是新设置的数据, oldVal 是旧数据 6 | let val = newVal < 10 ? '0' + newVal : newVal 7 | this.setData({ 8 | _index: val // 不要修改本身数据 index, 容易无限循环 9 | }) 10 | } 11 | } 12 | }, 13 | // 组件的初始数据, data 的值也会被页面绑定, data 的值不可以从组件外部设置 用 text 组件会出现双文字的情况 14 | data: { 15 | months: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'], 16 | year: Number, 17 | month: String, 18 | _index: String 19 | }, 20 | ready: function() { // 组件生命周期函数, 组件布局完成后执行 21 | let date = new Date() 22 | let month = date.getMonth() 23 | let year = date.getFullYear() 24 | this.setData({ 25 | month: this.data.months[month], 26 | year: year 27 | }) 28 | } 29 | }) 30 | -------------------------------------------------------------------------------- /components/epsoide/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } 5 | -------------------------------------------------------------------------------- /components/epsoide/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | No. 4 | {{_index}} 5 | 6 | 7 | 8 | {{month}} 9 | {{year}} 10 | 11 | 12 | -------------------------------------------------------------------------------- /components/epsoide/index.wxss: -------------------------------------------------------------------------------- 1 | .container { 2 | display: inline-flex; 3 | flex-direction: row; 4 | height: 60rpx; /* 根据最高元素 08 font-size 设置 */ 5 | } 6 | 7 | .index-container { 8 | display: flex; 9 | flex-direction: row; 10 | align-items: baseline; /* No 08 | 基于底部对齐 */ 11 | } 12 | 13 | .plain { 14 | font-size: 32rpx; 15 | } 16 | 17 | .index { 18 | margin: 0 14rpx 0 0; 19 | line-height: 60rpx; /* 取消字体上下间距 */ 20 | font-size: 60rpx; /* 取消字体上下间距 */ 21 | font-weight: 800; 22 | } 23 | 24 | .vertical-line { 25 | margin: 0 14rpx 0 0; 26 | border-left: 1rpx solid #000; 27 | height: 44rpx; 28 | } 29 | 30 | .date-container { 31 | display: flex; 32 | flex-direction: column; 33 | margin: 5rpx 0 0 0; 34 | } 35 | 36 | .month { 37 | line-height: 24rpx; 38 | font-size: 24rpx; 39 | } 40 | 41 | .year { 42 | font-size: 20rpx; 43 | } 44 | -------------------------------------------------------------------------------- /components/image-button/index.js: -------------------------------------------------------------------------------- 1 | // components/image-button/index.html.js 2 | Component({ 3 | options: { 4 | multipleSlots: true // 在组件定义时的选项中启用多 slot 支持 5 | }, 6 | properties: { 7 | openType: { 8 | type: String 9 | }, 10 | imageSrc: { 11 | type: String 12 | }, 13 | bindgetuserinfo: { 14 | type: String 15 | } 16 | }, 17 | methods: { 18 | onGetUserInfo(event) { 19 | this.triggerEvent('getuserinfo', event.detail, {}) 20 | } 21 | } 22 | }) 23 | -------------------------------------------------------------------------------- /components/image-button/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } 5 | -------------------------------------------------------------------------------- /components/image-button/index.wxml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /components/image-button/index.wxss: -------------------------------------------------------------------------------- 1 | .container { 2 | /* display: flex; 3 | flex-direction: row; 4 | justify-content: center; */ 5 | /* display: flex; */ 6 | padding: 0 !important; 7 | border: none !important; 8 | /* display: inline !important; */ 9 | } 10 | 11 | /* .img{ 12 | width:100%; 13 | height:100%; 14 | } */ 15 | -------------------------------------------------------------------------------- /components/like/images/like.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/components/like/images/like.png -------------------------------------------------------------------------------- /components/like/images/like@dis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/components/like/images/like@dis.png -------------------------------------------------------------------------------- /components/like/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Description: 3 | * @version: 4 | * @Author: GanEhank 5 | * @Date: 2018-07-07 19:53:30 6 | * @LastEditors: GanEhank 7 | * @LastEditTime: 2019-08-20 01:32:33 8 | */ 9 | Component({ 10 | properties: { // 组件的属性列表, 需要开放出来的数据 11 | like: { 12 | type: Boolean 13 | }, 14 | count: { 15 | type: Number 16 | }, 17 | readOnly: { 18 | type: Boolean 19 | } 20 | // myProperty: { 21 | // [properties](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/component.html) 22 | // type: String, // 类型(必填),目前接受的类型包括:String, Number, Boolean, Object, Array, null(表示任意类型) 23 | // value: '', // 属性初始值(可选),如果未指定则会根据类型选择一个 24 | // observer: function(newVal, oldVal, changedPath) { 25 | // 属性被改变时执行的函数(可选),也可以写成在methods段中定义的方法名字符串, 如:'_propertyChange' 26 | // 通常 newVal 就是新设置的数据, oldVal 是旧数据 27 | // } 28 | // } 29 | }, 30 | data: { 31 | yes_url: 'images/like.png', 32 | no_url: 'images/like@dis.png' 33 | }, 34 | methods: { 35 | onLike: function(event) { 36 | if (this.properties.readOnly) { 37 | return 38 | } 39 | let like = this.properties.like 40 | let count = this.properties.count 41 | count = like ? count - 1 : count + 1 42 | this.setData({ // setData: modify data inside data, data upgrate 43 | count: count, 44 | like: !like 45 | }) 46 | let behavior = this.properties.like ? 'like' : 'cancel' 47 | this.triggerEvent( // triggerEvent: 自定义事件 like: 事件名称 { behavior: behavior }: 传递参数, 设置 detail 48 | 'like', 49 | { 50 | behavior: behavior 51 | }, 52 | {} 53 | ) 54 | } 55 | } 56 | }) 57 | -------------------------------------------------------------------------------- /components/like/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } 5 | -------------------------------------------------------------------------------- /components/like/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{count}} 5 | 6 | -------------------------------------------------------------------------------- /components/like/index.wxss: -------------------------------------------------------------------------------- 1 | .container { 2 | display: inline-flex; 3 | flex-direction: row; 4 | /* 指定宽度,否则会出现移动, 数字显示使用 10k */ 5 | width: 120rpx; 6 | padding: 10rpx; 7 | } 8 | 9 | .container image { 10 | width: 32rpx; 11 | height: 28rpx; 12 | } 13 | 14 | .container text { 15 | position: relative; 16 | bottom: 10rpx; 17 | left: 6rpx; 18 | /* 取消字体上下间距 */ 19 | line-height: 24rpx; 20 | font-size: 24rpx; 21 | color: #bbb; 22 | } 23 | -------------------------------------------------------------------------------- /components/like/like-beh.js: -------------------------------------------------------------------------------- 1 | let likeBehavior = Behavior({ 2 | properties: { 3 | like: Boolean, 4 | count: Number 5 | }, 6 | data: { 7 | yes_url: '../images/like.png', 8 | no_url: '../images/like@dis.png' 9 | }, 10 | attached: function() {}, 11 | methods: { 12 | onLike: function(event) { 13 | let count = this.properties.count 14 | count = this.properties.like ? count - 1 : count + 1 15 | this.setData({ 16 | count: count, 17 | like: !this.properties.like 18 | }) 19 | let behavior = this.properties.like ? 'like' : 'cancel' 20 | this.triggerEvent( 21 | 'like', 22 | { 23 | behavior: behavior 24 | }, 25 | {} 26 | ) 27 | } 28 | } 29 | }) 30 | 31 | export { likeBehavior } 32 | -------------------------------------------------------------------------------- /components/loading/index.js: -------------------------------------------------------------------------------- 1 | Component({}) 2 | -------------------------------------------------------------------------------- /components/loading/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } 5 | -------------------------------------------------------------------------------- /components/loading/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /components/loading/index.wxss: -------------------------------------------------------------------------------- 1 | .spinner { 2 | width: 40rpx; 3 | height: 40rpx; 4 | position: relative; 5 | /* margin: 100px auto; */ 6 | } 7 | 8 | .double-bounce1, 9 | .double-bounce2 { 10 | width: 100%; 11 | height: 100%; 12 | border-radius: 50%; 13 | background-color: #3063b2; 14 | opacity: 0.6; 15 | position: absolute; 16 | top: 0; 17 | left: 0; 18 | 19 | -webkit-animation: bounce 2s infinite ease-in-out; 20 | animation: bounce 2s infinite ease-in-out; 21 | } 22 | 23 | .double-bounce2 { 24 | -webkit-animation-delay: -1s; 25 | animation-delay: -1s; 26 | } 27 | 28 | @-webkit-keyframes bounce { 29 | 0%, 30 | 100% { 31 | -webkit-transform: scale(0); 32 | } 33 | 50% { 34 | -webkit-transform: scale(1); 35 | } 36 | } 37 | 38 | @keyframes bounce { 39 | 0%, 40 | 100% { 41 | transform: scale(0); 42 | -webkit-transform: scale(0); 43 | } 44 | 50% { 45 | transform: scale(1); 46 | -webkit-transform: scale(1); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /components/mask/index.js: -------------------------------------------------------------------------------- 1 | // components/mask/index.js 2 | Component({ 3 | options: { 4 | multipleSlots: true // 在组件定义时的选项中启用多slot支持 5 | } 6 | }) 7 | -------------------------------------------------------------------------------- /components/mask/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } 5 | -------------------------------------------------------------------------------- /components/mask/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /components/mask/index.wxss: -------------------------------------------------------------------------------- 1 | /* components/mask/index.wxss */ 2 | .container { 3 | z-index: 99; 4 | position: fixed; 5 | top: 0; 6 | width: 100%; 7 | height: 100%; 8 | background-color: #000; 9 | opacity: 0.6; 10 | } 11 | -------------------------------------------------------------------------------- /components/navi/images/triangle.dis@left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/components/navi/images/triangle.dis@left.png -------------------------------------------------------------------------------- /components/navi/images/triangle.dis@right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/components/navi/images/triangle.dis@right.png -------------------------------------------------------------------------------- /components/navi/images/triangle@left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/components/navi/images/triangle@left.png -------------------------------------------------------------------------------- /components/navi/images/triangle@right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/components/navi/images/triangle@right.png -------------------------------------------------------------------------------- /components/navi/index.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | properties: { 3 | title: { 4 | type: String, 5 | value: '...' 6 | }, 7 | latest: { // 最后一期期刊, 是最新一期期刊 8 | type: Boolean, 9 | value: false, 10 | observer: function() {} 11 | }, 12 | first: { // 第一期期刊 13 | type: Boolean, 14 | value: false, 15 | observer: function() {} 16 | } 17 | }, 18 | data: { 19 | disLeftSrc: 'images/triangle.dis@left.png', 20 | highLeftSrc: 'images/triangle@left.png', 21 | disRightSrc: 'images/triangle.dis@right.png', 22 | highRightSrc: 'images/triangle@right.png' 23 | }, 24 | methods: { 25 | onLeft: function() { 26 | if (!this.properties.latest) { 27 | this.triggerEvent('left', {}, {}) 28 | } 29 | }, 30 | onRight: function() { 31 | if (!this.properties.first) { 32 | this.triggerEvent('right', {}, {}) 33 | } 34 | } 35 | } 36 | }) 37 | -------------------------------------------------------------------------------- /components/navi/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } 5 | -------------------------------------------------------------------------------- /components/navi/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | {{title}} 10 | 16 | -------------------------------------------------------------------------------- /components/navi/index.wxss: -------------------------------------------------------------------------------- 1 | .container { 2 | display: inline-flex; 3 | flex-direction: row; 4 | justify-content: space-between; 5 | align-items: center; 6 | border-radius: 4rpx; 7 | width: 600rpx; 8 | height: 80rpx; 9 | background-color: #f7f7f7; 10 | } 11 | 12 | .navi-icon { 13 | width: 80rpx; 14 | height: 80rpx; 15 | } 16 | 17 | .title { 18 | font-size: 28rpx; 19 | } 20 | -------------------------------------------------------------------------------- /components/preview/index.js: -------------------------------------------------------------------------------- 1 | // components/preview/index.js 2 | Component({ 3 | properties: { 4 | classic: { 5 | type: Object, 6 | observer: function(newVal) { 7 | if (newVal) { 8 | var typeText = { 9 | 100: '电影', 10 | 200: '音乐', 11 | 300: '句子' 12 | }[newVal.type] 13 | } 14 | this.setData({ 15 | typeText: typeText 16 | }) 17 | } 18 | } 19 | }, 20 | data: { 21 | typeText: String 22 | }, 23 | methods: { 24 | onTap: function() { 25 | this.triggerEvent( // 注意 catchtap 与 bindtap 的区别 26 | 'tap', 27 | { 28 | cid: this.properties.classic.id, 29 | type: this.properties.classic.type 30 | }, 31 | {} 32 | ) 33 | } 34 | } 35 | }) 36 | -------------------------------------------------------------------------------- /components/preview/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": { 4 | "tag-cmp": "/components/tag/index", 5 | "like-cmp": "/components/like/index" 6 | } 7 | } 8 | 9 | -------------------------------------------------------------------------------- /components/preview/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | {{classic.content}} 8 | -------------------------------------------------------------------------------- /components/preview/index.wxss: -------------------------------------------------------------------------------- 1 | .container { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | width: 330rpx; 6 | background-color: #ffffff; 7 | } 8 | 9 | .head { 10 | display: flex; 11 | width: 100%; 12 | flex-direction: row; 13 | align-items: center; 14 | justify-content: space-between; 15 | height: 80rpx; 16 | } 17 | 18 | .tag { 19 | margin-left: 20rpx; 20 | margin-top: -2rpx; 21 | height: 40rpx; 22 | width: 72rpx; 23 | font-size: 24rpx; 24 | background-color: #f7f7f7 !important; 25 | } 26 | 27 | .like { 28 | margin-top: 4rpx; 29 | margin-right: 4rpx; 30 | } 31 | 32 | .other-img { 33 | width: 100%; 34 | height: 240rpx; 35 | } 36 | 37 | .music-img { 38 | border-radius: 50%; 39 | width: 240rpx; 40 | height: 240rpx; 41 | } 42 | 43 | .text { 44 | padding: 30rpx; 45 | font-size: 28rpx; 46 | height: 130rpx; 47 | color: #666666; 48 | overflow: hidden; 49 | } 50 | -------------------------------------------------------------------------------- /components/search/images/cancel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/components/search/images/cancel.png -------------------------------------------------------------------------------- /components/search/images/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/components/search/images/search.png -------------------------------------------------------------------------------- /components/search/index.js: -------------------------------------------------------------------------------- 1 | // import { HTTP } from '../../utils/http' 2 | import { KeywordModel } from '../../models/keyword' 3 | import { BookModel } from '../../models/book' 4 | import { paginationBev } from '../behaviors/pagination.js' 5 | 6 | // let http = new HTTP() 7 | const keyModel = new KeywordModel() 8 | const bookModel = new BookModel() 9 | 10 | Component({ 11 | behaviors: [paginationBev], 12 | properties: { 13 | more: { 14 | type: String, 15 | observer: 'loadMore' 16 | } 17 | }, 18 | data: { 19 | historyWords: [], 20 | hotKeys: [], 21 | q: '', 22 | loading: false, // 锁, 防止多次无用的加载 23 | loadingCenter: false, 24 | // dataArray: [], 25 | searching: false 26 | }, 27 | attached: function() { // 组件进入界面 节点树时执行 28 | this.setData({ 29 | historyWords: keyModel.getHistory() 30 | }) 31 | keyModel 32 | .getHot() 33 | .then(res => { 34 | this.setData({ 35 | hotKeys: res.hot 36 | }) 37 | }) 38 | }, 39 | methods: { 40 | loadMore: function() { 41 | if (!this.data.q) { 42 | return 43 | } 44 | if (this.isLocked()) { 45 | return 46 | } 47 | let hasMore = this.hasMore() 48 | if (!hasMore) { 49 | return 50 | } 51 | if (this.hasMore()) { 52 | this.locked() 53 | // const length = this.data.dataArray.length 54 | bookModel 55 | .search(this.getCurrentStart(), this.data.q) 56 | .then(res => { 57 | // const tempArray = this.data.dataArray.concat(res.books) 58 | this.setMoreData(res.books) 59 | this.unLocked() 60 | }, 61 | () => { 62 | this.unLocked() // 断网后避免死锁 63 | } 64 | ) 65 | } 66 | // http.request({ 67 | // url: 'book/search?summary=1', 68 | // data: { 69 | // q: this.data.q, 70 | // start: this.getCurrentStart() 71 | // }, 72 | // success: data => { 73 | // this.setMoreData(data.books) 74 | // this.setData({ 75 | // loading: false 76 | // }) 77 | // } 78 | // }) 79 | }, 80 | _closeResult() { 81 | this.setData({ 82 | searching: false, 83 | q: '' 84 | }) 85 | }, 86 | onCancel: function() { 87 | this.initPagination() 88 | this.triggerEvent('cancel', {}, {}) 89 | }, 90 | onDelete: function() { 91 | this.initPagination() 92 | this._closeResult() 93 | }, 94 | onConfirm: function(event) { 95 | this._showResult() 96 | this._showLoadingCenter() 97 | const q = event.detail.value || event.detail.text // event.detail.value: input 输入的值, event.detail.text: 事件触发定义的值 98 | this.setData({ 99 | q: q 100 | }) 101 | bookModel 102 | .search(0, q) 103 | .then(res => { 104 | this.setMoreData(res.books) 105 | this.setTotal(res.total) 106 | keyModel.addToHistory(q) 107 | this._hideLoadingCenter() 108 | }) 109 | // http.request({ 110 | // url: 'book/search?summary=1', 111 | // data: { 112 | // q: q, 113 | // start: this.getCurrentStart() 114 | // }, 115 | // success: data => { 116 | // if (!(data.books == false)) { 117 | // keyModel.addToHistory(q) 118 | // } 119 | // this.setMoreData(data.books) 120 | // this.setData({ 121 | // q: q, 122 | // loadingCenter: false 123 | // }) 124 | // } 125 | // }) 126 | }, 127 | _showResult() { 128 | this.setData({ 129 | searching: true 130 | }) 131 | }, 132 | _showLoadingCenter() { 133 | this.setData({ 134 | loadingCenter: true 135 | }) 136 | }, 137 | _hideLoadingCenter() { 138 | this.setData({ 139 | loadingCenter: false 140 | }) 141 | } 142 | } 143 | }) 144 | -------------------------------------------------------------------------------- /components/search/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": { 4 | "tag-cmp": "../tag/index", 5 | "book-cmp": "../book/index", 6 | "loading-cmp": "../loading/index" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /components/search/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 取消 9 | 10 | 11 | 12 | 13 | 14 | 历史搜索 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 热门搜索 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 没有搜索到书籍 42 | -------------------------------------------------------------------------------- /components/search/index.wxss: -------------------------------------------------------------------------------- 1 | .container { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | width: 100%; 6 | /* padding-left:15px; */ /* padding-right:15px; */ 7 | } 8 | 9 | .history { 10 | width: 690rpx; 11 | margin: 40rpx 0 20rpx 0; 12 | display: flex; 13 | font-size: 14px; 14 | margin-top: 160rpx; 15 | flex-direction: column; 16 | } 17 | 18 | .hot-search { 19 | margin-top: 70rpx; 20 | } 21 | 22 | .title { 23 | line-height: 15px; 24 | display: flex; 25 | flex-direction: row; 26 | align-items: center; 27 | /* margin-left:100px; */ 28 | } 29 | 30 | .search-container { 31 | display: inline-flex; 32 | flex-direction: row; 33 | align-items: center; 34 | background-color: #f5f5f5; 35 | border-radius: 50px; 36 | margin-left: 20rpx; 37 | /* margin-left: */ 38 | } 39 | 40 | .books-container book-cmp { 41 | margin-bottom: 25rpx; 42 | } 43 | 44 | .cancel-img { 45 | width: 14px; 46 | height: 14px; 47 | margin-right: 10px; 48 | } 49 | 50 | .books-container { 51 | width: 570rpx; 52 | margin-top: 100rpx; 53 | display: flex; 54 | flex-direction: row; 55 | flex-wrap: wrap; 56 | padding: 0 90rpx 0 90rpx; 57 | justify-content: space-between; 58 | } 59 | 60 | .loading { 61 | margin: 50rpx 0 50rpx 0; 62 | } 63 | 64 | .loading-center { 65 | position: absolute; 66 | top: 50%; 67 | left: 50%; 68 | } 69 | 70 | .empty-tip { 71 | display: inline-block; 72 | width: 100%; 73 | text-align: center; 74 | position: absolute; 75 | top: 50%; 76 | /* left: 275rpx; */ 77 | } 78 | 79 | .icon { 80 | width: 14px; 81 | height: 14px; 82 | margin-left: 12px; 83 | margin-right: 8px; 84 | } 85 | 86 | .in-bar { 87 | color: #999; 88 | } 89 | 90 | .cancel { 91 | line-height: 34px; 92 | width: 60px; 93 | /* margin-left:10px; */ 94 | text-align: center; 95 | display: inline-block; 96 | border: none; 97 | } 98 | 99 | .chunk { 100 | height: 15px; 101 | width: 5px; 102 | background-color: #000; 103 | display: inline-block; 104 | margin-right: 10px; 105 | } 106 | 107 | .tags { 108 | /* padding-left:15px; */ 109 | display: flex; 110 | flex-direction: row; 111 | flex-wrap: wrap; 112 | /* justify-content: flex-start; */ 113 | margin-top: 24rpx; 114 | padding-left: 15px; 115 | width: 630rpx; 116 | } 117 | 118 | .tags tag-cmp { 119 | margin-right: 10px; 120 | margin-bottom: 10px; 121 | /* padding-bottom: 10px; */ /* margin-right:6px; */ 122 | } 123 | 124 | .header { 125 | background-color: #ffffff; 126 | position: fixed; 127 | height: 100rpx; 128 | border-top: 1px solid #f5f5f5; 129 | border-bottom: 1px solid #f5f5f5; 130 | display: flex; 131 | flex-direction: row; 132 | width: 750rpx; 133 | align-items: center; 134 | z-index: 99; 135 | /* padding-left:15px; */ /* padding-right:5px; */ 136 | } 137 | 138 | .bar { 139 | border-top-right-radius: 15px; 140 | border-bottom-right-radius: 15px; 141 | display: inline-block; 142 | height: 34px; 143 | /* width:100%; */ 144 | width: 500rpx; 145 | font-size: 14px; 146 | } 147 | 148 | .test { 149 | background-color: #000; 150 | } 151 | -------------------------------------------------------------------------------- /components/tag/index.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | options: { 3 | multipleSlots: true // 在组件定义时的选项中启用多 slot 支持 4 | }, 5 | externalClasses: ['tag-class'], // 组件外部传入的样式 6 | properties: { 7 | text: String 8 | }, 9 | methods: { 10 | onTap: function(event) { 11 | this.triggerEvent('tapping', { 12 | text: this.properties.text 13 | }) 14 | } 15 | } 16 | }) 17 | -------------------------------------------------------------------------------- /components/tag/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } 5 | -------------------------------------------------------------------------------- /components/tag/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{text}} 5 | 6 | -------------------------------------------------------------------------------- /components/tag/index.wxss: -------------------------------------------------------------------------------- 1 | /* components/tag/index.wxss */ 2 | .container { 3 | flex-direction: row; 4 | justify-content: center; 5 | align-items: center; 6 | display: inline-flex; 7 | padding: 4rpx 12rpx; 8 | border-radius: 2px; 9 | font-size: 28rpx; 10 | color: #666666; 11 | background-color: #f5f5f5; 12 | } 13 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | api_blink_url: 'http://bl.7yue.pro/v1/', 3 | appkey: 'RdshydjBvcYZhMZC' 4 | // appkey: 'GgRhTjUNUYn1fHke' 5 | } 6 | 7 | export { config } 8 | -------------------------------------------------------------------------------- /images/book/quality.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/images/book/quality.png -------------------------------------------------------------------------------- /images/book/tip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/images/book/tip.png -------------------------------------------------------------------------------- /images/icon/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/images/icon/search.png -------------------------------------------------------------------------------- /images/icon/share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/images/icon/share.png -------------------------------------------------------------------------------- /images/my/about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/images/my/about.png -------------------------------------------------------------------------------- /images/my/course.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/images/my/course.png -------------------------------------------------------------------------------- /images/my/like.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/images/my/like.png -------------------------------------------------------------------------------- /images/my/my.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/images/my/my.png -------------------------------------------------------------------------------- /images/my/my@bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/images/my/my@bg.png -------------------------------------------------------------------------------- /images/my/study.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/images/my/study.png -------------------------------------------------------------------------------- /images/my/vendor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/images/my/vendor.png -------------------------------------------------------------------------------- /images/tab/book.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/images/tab/book.png -------------------------------------------------------------------------------- /images/tab/book@highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/images/tab/book@highlight.png -------------------------------------------------------------------------------- /images/tab/classic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/images/tab/classic.png -------------------------------------------------------------------------------- /images/tab/classic@highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/images/tab/classic@highlight.png -------------------------------------------------------------------------------- /images/tab/my.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/images/tab/my.png -------------------------------------------------------------------------------- /images/tab/my@highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/images/tab/my@highlight.png -------------------------------------------------------------------------------- /models/book.js: -------------------------------------------------------------------------------- 1 | import { HTTP } from '../utils/http-p.js' 2 | 3 | class BookModel extends HTTP { 4 | constructor() { 5 | super() 6 | } 7 | getHotList() { 8 | // return this.request({ // http-p.js/request({}), 里面写了 {}, 导致能传递对象, (解构赋值) 9 | // url: 'book/hot_list', 10 | // data: { 11 | // name: '1', 12 | // age: 18 13 | // }, 14 | // method: 'POST' 15 | // }) 16 | return this.request({ 17 | url: 'book/hot_list' 18 | }) 19 | } 20 | search(start, q) { 21 | return this.request({ 22 | url: 'book/search?summary=1', 23 | data: { 24 | q: q, 25 | start: start 26 | } 27 | }) 28 | } 29 | getMyBookCount(success) { 30 | let params = { 31 | url: '/book/favor/count', 32 | success: success 33 | } 34 | this.request(params) 35 | } 36 | getDetail(bid) { 37 | return this.request({ 38 | url: `book/${bid}/detail` 39 | }) 40 | } 41 | getLikeStatus(bid) { 42 | return this.request({ 43 | url: `book/${bid}/favor` 44 | }) 45 | } 46 | getComments(bid) { 47 | return this.request({ 48 | url: `book/${bid}/short_comment` 49 | }) 50 | } 51 | } 52 | 53 | export { BookModel } 54 | -------------------------------------------------------------------------------- /models/classic.js: -------------------------------------------------------------------------------- 1 | import { HTTP } from '../utils/http.js' 2 | 3 | class ClassicModel extends HTTP { 4 | prefix = 'classic' 5 | constructor() { 6 | super() 7 | } 8 | getLatest(sCallback) { // 获取最新的期刊, 也就是最大的期刊号,可看作是最后一期期刊 9 | // this.request() is async, can't return res, invoked HTTP request() 10 | this.request({ 11 | url: 'classic/latest', 12 | success: res => { 13 | let key = this._fullKey(res.index) // key 值加盐,用来定义名字 14 | wx.setStorageSync(key, res) // 缓存内容 15 | this._setLatestIndex(res.index) // 缓存刊号,用来判断是否是最后一期期刊 16 | sCallback(res) // 回调函数回传回去 17 | } 18 | }) 19 | } 20 | getById(cid, type, success) { 21 | let params = { 22 | url: 'classic/' + type + '/' + cid, 23 | success: success 24 | } 25 | this.request(params) 26 | } 27 | getClassic(index, next_or_previous, sCallback) { // 获取下一期或者上一期期刊 28 | let key = next_or_previous === 'next' ? this._fullKey(index + 1) : this._fullKey(index - 1) 29 | let classic = wx.getStorageSync(key) 30 | if (!classic) { 31 | this.request({ 32 | url: `classic/${index}/${next_or_previous}`, 33 | success: res => { 34 | let key = this._fullKey(res.index) 35 | wx.setStorageSync(key, res) 36 | sCallback(res) 37 | } 38 | }) 39 | } else { 40 | sCallback(classic) 41 | } 42 | } 43 | getMyFavor(success) { 44 | let params = { 45 | url: 'classic/favor', 46 | success: success 47 | } 48 | this.request(params) 49 | } 50 | isFirst(index) { // 是否是最新一期期刊 51 | return index === 1 ? true : false 52 | } 53 | isLatest(index) { // 是否是最后一期期刊 54 | let latestIndex = this._getLastIndex(index) 55 | return latestIndex === index ? true : false 56 | } 57 | _fullKey(partKey) { // key 值加盐,用来定义名字 58 | let key = this.prefix + '-' + partKey 59 | return key 60 | } 61 | _setLatestIndex(index) { // 缓存 latest 刊号 62 | let key = this._fullKey('latest-' + index) 63 | wx.setStorageSync(key, index) 64 | } 65 | _getLastIndex(index) { // 读取 latest 刊号缓存, 获取刊号 66 | let key = this._fullKey('latest-' + index) 67 | let latestIndex = wx.getStorageSync(key) 68 | return latestIndex 69 | } 70 | } 71 | 72 | export { ClassicModel } 73 | -------------------------------------------------------------------------------- /models/comment.js: -------------------------------------------------------------------------------- 1 | import { HTTP } from '../utils/http-p' 2 | 3 | class CommentModel extends HTTP { 4 | getComments(bid) { 5 | return this.request({ 6 | url: `${'book/'}${bid}${'/short_comment'}` 7 | }) 8 | } 9 | postComment(bid, comment) { 10 | return this.request({ 11 | url: 'book/add/short_comment', 12 | method: 'POST', 13 | data: { 14 | book_id: bid, 15 | content: comment 16 | } 17 | }) 18 | } 19 | } 20 | 21 | export { CommentModel } 22 | -------------------------------------------------------------------------------- /models/keyword.js: -------------------------------------------------------------------------------- 1 | import { HTTP } from '../utils/http-p.js' 2 | 3 | class KeywordModel extends HTTP { 4 | key = 'q' 5 | max = 10 6 | getHistory() { 7 | const words = wx.getStorageSync(this.key) 8 | if (!words) { 9 | return [] 10 | } 11 | return words 12 | } 13 | getHot() { 14 | return this.request({ 15 | url: '/book/hot_keyword' 16 | }) 17 | } 18 | addToHistory(word) { // 关键字写入缓存中 19 | let keywords = this.getHistory() 20 | // const has = keywords.inlcludes(word) 21 | let index = keywords.indexOf(word) 22 | if (index == -1) { 23 | let length = keywords.length 24 | if (length >= this.max) { 25 | keywords.pop(word) 26 | } 27 | keywords.unshift(word) 28 | wx.setStorageSync(this.key, keywords) 29 | } 30 | } 31 | } 32 | 33 | export { KeywordModel } 34 | -------------------------------------------------------------------------------- /models/like.js: -------------------------------------------------------------------------------- 1 | import { HTTP } from '../utils/http.js' 2 | 3 | class LikeModel extends HTTP { 4 | constructor() { 5 | super() 6 | } 7 | /** 8 | * @param {string} behavior 状态 9 | * @param {number} artID 电影 id 号 10 | * @param {string} category 状态码 11 | * @return: success 12 | */ 13 | like(behavior, artID, category) { 14 | let url = behavior === 'like' ? 'like' : 'like/cancel' 15 | this.request({ 16 | url: url, 17 | method: 'POST', 18 | data: { 19 | art_id: artID, 20 | type: category 21 | }, 22 | success: data => { 23 | console.log(data) 24 | } 25 | }) 26 | } 27 | getClassicLikeStatus(artID, category, success) { 28 | this.request({ 29 | url: `classic/${category}/${artID}/favor`, 30 | success: success 31 | }) 32 | } 33 | } 34 | 35 | export { LikeModel } 36 | -------------------------------------------------------------------------------- /pages/about/about.js: -------------------------------------------------------------------------------- 1 | // pages/about/about.js 2 | Page({ 3 | 4 | /** 5 | * Page initial data 6 | */ 7 | data: { 8 | 9 | }, 10 | 11 | /** 12 | * Lifecycle function--Called when page load 13 | */ 14 | onLoad: function (options) { 15 | 16 | }, 17 | 18 | /** 19 | * Lifecycle function--Called when page is initially rendered 20 | */ 21 | onReady: function () { 22 | 23 | }, 24 | 25 | /** 26 | * Lifecycle function--Called when page show 27 | */ 28 | onShow: function () { 29 | 30 | }, 31 | 32 | /** 33 | * Lifecycle function--Called when page hide 34 | */ 35 | onHide: function () { 36 | 37 | }, 38 | 39 | /** 40 | * Lifecycle function--Called when page unload 41 | */ 42 | onUnload: function () { 43 | 44 | }, 45 | 46 | /** 47 | * Page event handler function--Called when user drop down 48 | */ 49 | onPullDownRefresh: function () { 50 | 51 | }, 52 | 53 | /** 54 | * Called when page reach bottom 55 | */ 56 | onReachBottom: function () { 57 | 58 | }, 59 | 60 | /** 61 | * Called when user click on the top right corner to share 62 | */ 63 | onShareAppMessage: function () { 64 | 65 | } 66 | }) -------------------------------------------------------------------------------- /pages/about/about.json: -------------------------------------------------------------------------------- 1 | { 2 | "disableScroll": true 3 | } 4 | -------------------------------------------------------------------------------- /pages/about/about.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /pages/book-detail/book-detail.js: -------------------------------------------------------------------------------- 1 | import { BookModel } from '../../models/book.js' 2 | import { LikeModel } from '../../models/like.js' 3 | import { CommentModel } from '../../models/comment.js' 4 | 5 | let bookModel = new BookModel() 6 | let commentModel = new CommentModel() 7 | let likeModel = new LikeModel() 8 | 9 | Page({ 10 | data: { 11 | book: null, 12 | comments: [], 13 | noComment: true, 14 | posting: false, 15 | like: false, 16 | count: 0 17 | }, 18 | onLoad: function(options) { // Lifecycle function--Called when page load 19 | wx.showLoading() 20 | // pages 组件传入的参数在 options 中 21 | const bid = options.bid // 接受从外部传来的参数 22 | const detail = bookModel.getDetail(bid) 23 | const comments = bookModel.getComments(bid) 24 | const likeStatus = bookModel.getLikeStatus(bid) 25 | // detail.then(res => { 26 | // this.setData({ 27 | // book: res 28 | // }) 29 | // }) 30 | // comments.then(res => { 31 | // this.setData({ 32 | // noComment: res.comments == false ? true : false, 33 | // comments: res.comments 34 | // }) 35 | // }) 36 | // likeStatus.then(res => { 37 | // this.setData({ 38 | // like: res.like_status, 39 | // count: res.fav_nums 40 | // }) 41 | // }) 42 | Promise.all([detail, comments, likeStatus]).then(res => { // Promise.all 三个异步都完成后才调用 then 43 | // console.log(res) 44 | this.setData({ 45 | book: res[0], 46 | comments: res[1].comments, 47 | likeStatus: res[2].like_status, 48 | likeCount: res[2].fav_nums 49 | }) 50 | wx.hideLoading() 51 | }) 52 | }, 53 | onFakePost: function() { 54 | this.setData({ 55 | posting: true 56 | }) 57 | }, 58 | onCancel: function() { 59 | this.setData({ 60 | posting: false 61 | }) 62 | }, 63 | onLike: function(event) { 64 | let like_or_cancel = event.detail.behavior 65 | likeModel.like(like_or_cancel, this.data.book.id, 400) 66 | }, 67 | onPost: function(event) { 68 | // event.detail.value: input 输入的值 69 | // event.detail.text: 事件触发定义的值 70 | let comment = event.detail.value || event.detail.text 71 | if (!comment) { 72 | return 73 | } 74 | if (comment.length > 12) { 75 | wx.showToast({ 76 | title: '短评最多12个字', 77 | icon: 'none' 78 | }) 79 | return 80 | } 81 | commentModel 82 | .postComment(this.data.book.id, comment) 83 | .then(res => { 84 | wx.showToast({ 85 | title: '+ 1', 86 | icon: 'none' 87 | }) 88 | this.data.comments.unshift({ 89 | content: comment, 90 | nums: 1 91 | }) 92 | this.setData({ 93 | comments: this.data.comments, 94 | noComment: false 95 | }) 96 | }) 97 | }, 98 | // Called when user click on the top right corner to share 99 | onShareAppMessage: function() {} 100 | }) 101 | -------------------------------------------------------------------------------- /pages/book-detail/book-detail.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": { 3 | "tag-cmp": "/components/tag/index", 4 | "like-cmp": "/components/like/index", 5 | "mask-cmp": "/components/mask/index", 6 | "img-btn-cmp": "/components/image-button/index" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /pages/book-detail/book-detail.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{book.title}} 6 | {{book.author}} 7 | 8 | 9 | 短评 10 | 还没有短评 11 | 12 | 13 | 14 | 15 | 16 | {{'+' + item.nums}} 17 | 18 | 19 | 20 | 21 | 22 | 内容简介 23 | 24 | {{util.format(book.summary)}} 25 | 26 | 27 | 书本信息 28 | 29 | 30 | 出版社 31 | 出版年 32 | 页数 33 | 定价 34 | 装帧 35 | 36 | 37 | {{book.publisher}} 38 | {{book.pubdate}} 39 | {{book.pages}} 40 | {{book.price}} 41 | {{book.binding}} 42 | 43 | 44 | 45 | 46 | 47 | 48 | 输入短评 49 | 50 | 56 | 57 | 58 | 59 | 60 | 仅可点击标签+1 61 | 暂无短评 62 | 取消 63 | 64 | 65 | 66 | 67 | 68 | 69 | {{'+' + item.nums}} 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | // wxml 写 js, 尽量用 javascript 原生语法 不能用 es6 语法 79 | var limit = function(array, length) { 80 | return array.slice(0, length) 81 | } 82 | var format = function(text){ 83 | if(!text){ 84 | return 85 | } 86 | var reg = getRegExp('\\\\n','g') 87 | var text = text.replace(reg,'\n     ') 88 | return text 89 | } 90 | var heightlight = function(index) { 91 | if(index == 0) { 92 | return 'ex-tag1' 93 | } 94 | if(index == 1) { 95 | return 'ex-tag2' 96 | } 97 | return '' 98 | } 99 | module.exports = { 100 | limit: limit, 101 | format: format, 102 | heightlight: heightlight 103 | } 104 | -------------------------------------------------------------------------------- /pages/book-detail/book-detail.wxss: -------------------------------------------------------------------------------- 1 | .container { 2 | width: 100%; 3 | background-color: #f5f5f5; 4 | } 5 | 6 | .head { 7 | display: flex; 8 | flex-direction: column; 9 | align-items: center; 10 | padding-top: 40rpx; 11 | padding-bottom: 40rpx; 12 | background-color: #fff; 13 | } 14 | 15 | .title { 16 | margin-top: 20rpx; 17 | font-size: 38rpx; 18 | font-weight: 600; 19 | color: #2f2f2f; 20 | } 21 | 22 | .shadow { 23 | color: #999; 24 | } 25 | 26 | .author { 27 | font-size: 28rpx; 28 | color: #999; 29 | } 30 | 31 | .head image { 32 | width: 200rpx; 33 | height: 300rpx; 34 | box-shadow: 4rpx 4rpx 6rpx #e3e3e3; 35 | } 36 | 37 | .sub-container { 38 | display: flex; 39 | flex-direction: column; 40 | align-items: center; 41 | margin-top: 30rpx; 42 | padding: 30rpx; 43 | width: 690rpx; 44 | background-color: #fff; 45 | } 46 | 47 | .comment-container { 48 | display: flex; 49 | flex-direction: row; 50 | justify-content: flex-start; 51 | flex-wrap: wrap; 52 | padding: 0 30rpx; 53 | width: 100%; 54 | } 55 | 56 | .content { 57 | font-weight: 500; 58 | text-indent: 58rpx; 59 | color: #000; 60 | } 61 | 62 | .headline { 63 | margin-bottom: 20rpx; 64 | font-size: 30rpx; 65 | font-weight: 600; 66 | color: #2f2f2f; 67 | } 68 | 69 | .post-container { 70 | display: flex; 71 | flex-direction: row; 72 | justify-content: space-between; 73 | align-items: center; 74 | position: fixed; 75 | bottom: 0; 76 | box-shadow: 1px -1px 1px #e3e3e3; 77 | width: 690rpx; 78 | height: 100rpx; 79 | padding: 0 30rpx; 80 | background-color: #fff; 81 | } 82 | 83 | .post-fake { 84 | display: flex; 85 | flex-direction: row; 86 | align-items: center; 87 | padding-left: 20rpx; 88 | border-radius: 15px; 89 | border: 1px solid #999; 90 | height: 60rpx; 91 | width: 460rpx; 92 | font-size: 22rpx; 93 | } 94 | 95 | .post { 96 | margin: 30rpx auto; 97 | padding-left: 25rpx; 98 | height: 56rpx; 99 | width: 690rpx; 100 | border-radius: 15px; 101 | background-color: #f5f5f5; 102 | } 103 | 104 | .posting-container { 105 | display: flex; 106 | flex-direction: column; 107 | align-items: center; 108 | z-index: 999; 109 | position: fixed; 110 | bottom: 0; 111 | width: 100%; 112 | background-color: #fff; 113 | } 114 | 115 | .like { 116 | margin-right: 30rpx; 117 | margin-top: 10rpx; 118 | } 119 | 120 | .like-container { 121 | display: flex; 122 | flex-direction: row; 123 | justify-content: space-between; 124 | align-items: center; 125 | } 126 | 127 | .share-btn { 128 | margin-top: 28rpx; 129 | margin-left: 10rpx; 130 | } 131 | 132 | .share { 133 | width: 40rpx; 134 | height: 40rpx; 135 | } 136 | 137 | .posting-container .comment-container { 138 | padding: 0 30rpx; 139 | width: 690rpx; 140 | } 141 | 142 | .post-header { 143 | display: flex; 144 | flex-direction: row; 145 | align-items: center; 146 | justify-content: space-between; 147 | border-top: 1px solid #f5f5f5; 148 | border-bottom: 1px solid #f5f5f5; 149 | width: 100%; 150 | height: 100rpx; 151 | } 152 | 153 | .post-header > text:first-child { 154 | font-size: 28rpx; 155 | color: #bbb; 156 | } 157 | 158 | .cancel { 159 | color: #666; 160 | } 161 | 162 | .post-header text { 163 | padding: 25rpx; 164 | } 165 | 166 | .num { 167 | margin-left: 5px; 168 | font-size: 22rpx; 169 | color: #aaa; 170 | } 171 | 172 | .comment-container > tag-cmp:nth-child(1) view { 173 | background-color: #fffbdd; 174 | } 175 | 176 | .comment-container > tag-cmp:nth-child(2) view { 177 | background-color: #eefbff !important; 178 | } 179 | 180 | .tag { 181 | margin-right: 15rpx; 182 | margin-bottom: 10rpx; 183 | border-radius: 30px !important; 184 | } 185 | 186 | .ex-tag1 { 187 | background-color: #fffbdd !important; 188 | } 189 | 190 | .ex-tag2 { 191 | background-color: #eefbff !important; 192 | } 193 | 194 | .posting-container .comment-container { 195 | padding: 40rpx 30rpx 0 30rpx; 196 | } 197 | 198 | .detail-contaner { 199 | display: flex; 200 | flex-direction: row; 201 | justify-content: flex-start; 202 | margin-bottom: 100rpx; 203 | width: 100%; 204 | font-size: 28rpx; 205 | color: #666; 206 | } 207 | 208 | .vertical { 209 | display: flex; 210 | flex-direction: column; 211 | } 212 | 213 | .vertical-1 { 214 | align-items: flex-end; 215 | } 216 | 217 | .description { 218 | margin-right: 30rpx; 219 | color: #999; 220 | } 221 | 222 | .tip { 223 | margin-top: 20rpx; 224 | margin-bottom: 30rpx; 225 | width: 694rpx; 226 | height: 130rpx; 227 | } 228 | -------------------------------------------------------------------------------- /pages/book/book.js: -------------------------------------------------------------------------------- 1 | import { BookModel } from '../../models/book.js' 2 | import { random } from '../../utils/util.js' 3 | 4 | let bookModel = new BookModel() 5 | 6 | Page({ 7 | data: { 8 | searchPanel: false, 9 | books: Object, 10 | more: false // 加载更多 11 | }, 12 | onReachBottom: function() { 13 | this.setData({ 14 | more: random(16) // 改成 true, random() 保证 more 的值是变化的 15 | }) 16 | }, 17 | onLoad: function(options) { // Lifecycle function--Called when page load 18 | // const promise = new Promise((resolve, reject) => { // promise 对象能保存状态, 函数不能保存状态会马上返回, 闭包函数能保存状态 异步代码写在 promise 中 19 | // wx.getSystemInfo({ // promise 状态: pending(进行中) fulfilled(成功) rejected(失败) 20 | // success: res => { 21 | // resolve(res) // 修改状态: pending(进行中) -> fulfilled(成功), 之后会凝固 22 | // }, 23 | // fail: err => { 24 | // reject(err) // 修改状态: pending(进行中) -> rejected(失败), 之后会凝固 25 | // } 26 | // }) 27 | // }) 28 | 29 | // promise.then( // then(): 拿到异步执行后的结果状态 30 | // res => { 31 | // console.log(res + ' success!') 32 | // }, 33 | // err => { 34 | // console.log(err + ' fail!') 35 | // } 36 | // ) 37 | 38 | // 链式调用 api1, api2, api3 39 | // bookModel 40 | // .getHotList() 41 | // .then(res => { 42 | // console.log(res) // res -> api1 结果 43 | // return bookModel.getMyBookCount() // api2 调用 44 | // }) 45 | // .then(res => { 46 | // console.log(res) // res -> api2 结果 47 | // return bookModel.getMyBookCount() // api3 调用 48 | // }) 49 | // .then(res => { 50 | // console.log(res) // res -> api3 结果 51 | // }) 52 | 53 | bookModel 54 | .getHotList() 55 | .then(res => { 56 | this.setData({ 57 | books: res 58 | }) 59 | }) 60 | }, 61 | onActivateSearch: function() { 62 | this.setData({ 63 | searchPanel: true 64 | }) 65 | }, 66 | onCancel: function() { 67 | this.setData({ 68 | searchPanel: false 69 | }) 70 | }, 71 | onShareAppMessage() {} 72 | }) 73 | -------------------------------------------------------------------------------- /pages/book/book.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": { 3 | "book-cmp": "/components/book/index", 4 | "search-cmp": "/components/search/index" 5 | }, 6 | "backgroundColor": "#f5f5f5" 7 | } 8 | -------------------------------------------------------------------------------- /pages/book/book.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 搜索书籍 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /pages/book/book.wxss: -------------------------------------------------------------------------------- 1 | .container { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | width: 100%; 6 | } 7 | 8 | .header { 9 | z-index: 99; 10 | display: flex; 11 | flex-direction: row; 12 | justify-content: center; 13 | align-items: center; 14 | position: fixed; 15 | box-shadow: 0 0 6rpx 0 #e3e3e3; 16 | border-top: 2rpx solid #f5f5f5; 17 | border-bottom: 2rpx solid #f5f5f5; 18 | width: 100%; 19 | height: 100rpx; 20 | background-color: #fff; 21 | } 22 | 23 | .sub-container { 24 | display: flex; 25 | flex-direction: column; 26 | align-items: center; 27 | margin: 100rpx 0 0 0; 28 | background-color: #f5f5f5; 29 | } 30 | 31 | .books-container { 32 | display: flex; 33 | flex-direction: row; 34 | justify-content: space-between; 35 | flex-wrap: wrap; 36 | margin: 10rpx 0 0 0; 37 | padding: 0 90rpx; 38 | } 39 | 40 | .books-container book-cmp { 41 | margin: 0 0 30rpx 0; 42 | } 43 | 44 | .box { 45 | display: flex; 46 | flex-direction: row; 47 | justify-content: center; 48 | align-items: center; 49 | border-radius: 100rpx; 50 | height: 68rpx; 51 | width: 700rpx; 52 | color: #999; 53 | background-color: #f5f5f5; 54 | } 55 | 56 | .box image { 57 | margin: 0 20rpx -4rpx 0; 58 | width: 28rpx; 59 | height: 28rpx; 60 | } 61 | 62 | .head-img { 63 | margin: 40rpx 0 0 0; 64 | width: 106rpx; 65 | height: 34rpx; 66 | } 67 | -------------------------------------------------------------------------------- /pages/classic-detail/classic-detail.js: -------------------------------------------------------------------------------- 1 | // pages/classic/classic.js 2 | import { ClassicModel } from '../../models/classic.js' 3 | import { LikeModel } from '../../models/like.js' 4 | 5 | let classicModel = new ClassicModel() 6 | let likeModel = new LikeModel() 7 | 8 | Component({ 9 | properties: {}, 10 | data: { 11 | classic: null, 12 | latest: true, 13 | first: false, 14 | like: false, 15 | count: 0 16 | }, 17 | methods: { 18 | onLoad: function(options) { 19 | let cid = options.cid 20 | let type = options.type 21 | classicModel.getById(cid, type, data => { 22 | this._getLikeStatus(data.id, data.type) 23 | this.setData({ 24 | classic: data 25 | }) 26 | }) 27 | }, 28 | onPrevious: function(event) { 29 | let index = this.data.classic.index 30 | classicModel.getPrevious(index, data => { 31 | if (data) { 32 | this._getLikeStatus(data.id, data.type) 33 | this.setData({ 34 | classic: data, 35 | latest: classicModel.isLatest(data.index), 36 | first: classicModel.isFirst(data.index) 37 | }) 38 | } else { 39 | console.log('not more classic') 40 | } 41 | }) 42 | }, 43 | onNext: function(event) { 44 | let index = this.data.classic.index 45 | classicModel.getNext(index, data => { 46 | if (data) { 47 | this._getLikeStatus(data.id, data.type) 48 | this.setData({ 49 | classic: data, 50 | latest: classicModel.isLatest(data.index), 51 | first: classicModel.isFirst(data.index) 52 | }) 53 | } else { 54 | console.log('not more classic') 55 | } 56 | }) 57 | }, 58 | onLike: function(event) { 59 | let like_or_cancel = event.detail.behavior 60 | likeModel.like(like_or_cancel, this.data.classic.id, this.data.classic.type) 61 | }, 62 | _getLikeStatus: function(cid, type) { 63 | likeModel.getClassicLikeStatus(cid, type, data => { 64 | this.setData({ 65 | like: data.like_status, 66 | count: data.fav_nums 67 | }) 68 | }) 69 | }, 70 | onShareAppMessage() {} 71 | } 72 | }) 73 | -------------------------------------------------------------------------------- /pages/classic-detail/classic-detail.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": { 3 | "navi-cmp": "/components/navi/index", 4 | "epsoide-cmp": "/components/epsoide/index", 5 | "like-cmp": "/components/like/index", 6 | "movie-cmp": "/components/classic/movie/index", 7 | "music-cmp": "/components/classic/music/index", 8 | "essay-cmp": "/components/classic/essay/index", 9 | "img-btn-cmp": "/components/image-button/index" 10 | }, 11 | "disableScroll": true 12 | } 13 | -------------------------------------------------------------------------------- /pages/classic-detail/classic-detail.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /pages/classic-detail/classic-detail.wxss: -------------------------------------------------------------------------------- 1 | .header { 2 | width: 100%; 3 | display: flex; 4 | flex-direction: row; 5 | height: 50px; 6 | align-items: center; 7 | justify-content: space-between; 8 | border-top: 1px solid #f5f5f5; 9 | border-bottom: 1px solid #f5f5f5; 10 | } 11 | 12 | .container { 13 | width: 100%; 14 | display: flex; 15 | flex-direction: column; 16 | align-items: center; 17 | } 18 | 19 | .like { 20 | margin-right: 30rpx; 21 | margin-top: 12rpx; 22 | } 23 | 24 | .like-container { 25 | display: flex; 26 | flex-direction: row; 27 | justify-content: space-between; 28 | align-items: center; 29 | margin-right: 30rpx; 30 | } 31 | 32 | .share-btn { 33 | margin-top: 28rpx; 34 | margin-left: 10rpx; 35 | } 36 | 37 | .share { 38 | /* padding:10rpx; */ 39 | width: 40rpx; 40 | height: 40rpx; 41 | } 42 | 43 | .navi { 44 | position: absolute; 45 | bottom: 40rpx; 46 | } 47 | 48 | .epsoide { 49 | margin-left: 10px; 50 | margin-top: 7px; 51 | } 52 | -------------------------------------------------------------------------------- /pages/classic/classic.js: -------------------------------------------------------------------------------- 1 | import { ClassicModel } from '../../models/classic.js' 2 | import { LikeModel } from '../../models/like.js' 3 | 4 | let classicModel = new ClassicModel() // Instantiated object 5 | let likeModel = new LikeModel() 6 | 7 | Page({ 8 | data: { 9 | classic: null, 10 | likeCount: 0, 11 | likeStatus: false, 12 | first: false, 13 | latest: true 14 | }, 15 | onLoad: function(options) { // Lifecycle function--listening page load 16 | // wx.request({ // async request 17 | // url: 'http://bl.7yue.pro/v1/classic/latest', 18 | // header: { 19 | // appkey: 'GgRhTjUNUYn1fHke' 20 | // }, 21 | // success: (res) => { // Receive the result of an asyn call res 22 | // console.log(res) 23 | // console.log(this.data.likeCount) 24 | // console.log(this.res.count) 25 | // } 26 | // }) 27 | 28 | // 使用回调函数剥夺了 return 能力, 不能赋值操作, promise 能解决且带有 return 能力, 回调函数能获取值 let a = ... 29 | // classicModel.getClassic() 是异步,不能用同步方式调用, 里面没有 return, let latest = classicModel.getClassic() 30 | classicModel.getLatest(res => { 31 | // console.log(res) 32 | // this._getLikeStatus(res.id, res.type) 33 | this.setData({ // setData: modify data inside data, data update 34 | classic: res, 35 | likeCount: res.fav_nums, 36 | likeStatus: res.like_status 37 | }) 38 | }) 39 | }, 40 | onLike: function(event) { 41 | let behavior = event.detail.behavior // 获取 like/index.js 传过来的参数 42 | likeModel.like(behavior, this.data.classic.id, this.data.classic.type) 43 | }, 44 | onPrevious: function() { 45 | this._updateClassic('previous') 46 | }, 47 | onNext: function() { 48 | this._updateClassic('next') 49 | }, 50 | _updateClassic: function(nextOrPrevious) { 51 | let index = this.data.classic.index 52 | classicModel.getClassic(index, nextOrPrevious, res => { 53 | this._getLikeStatus(res.id, res.type) 54 | this.setData({ 55 | classic: res, 56 | latest: classicModel.isLatest(res.index), 57 | first: classicModel.isFirst(res.index) 58 | }) 59 | }) 60 | }, 61 | _getLikeStatus: function(artID, category) { 62 | likeModel.getClassicLikeStatus(artID, category, data => { 63 | this.setData({ 64 | likeStatus: data.like_status, 65 | likeCount: data.fav_nums 66 | }) 67 | }) 68 | } 69 | }) 70 | -------------------------------------------------------------------------------- /pages/classic/classic.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": { 3 | "like-cmp": "/components/like/index", 4 | "movie-cmp": "/components/classic/movie/index", 5 | "epsoide-cmp": "/components/epsoide/index", 6 | "essay-cmp": "/components/classic/essay/index", 7 | "navi-cmp": "/components/navi/index", 8 | "music-cmp": "/components/classic/music/index" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /pages/classic/classic.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /pages/classic/classic.wxss: -------------------------------------------------------------------------------- 1 | .container { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | width: 100%; 6 | } 7 | 8 | .header { 9 | display: flex; 10 | flex-direction: row; 11 | justify-content: space-between; 12 | align-items: center; 13 | border-top: 1px solid #f5f5f5; 14 | border-bottom: 1px solid #f5f5f5; 15 | width: 100%; 16 | height: 50px; 17 | } 18 | 19 | .epsoide { 20 | margin-left: 10px; 21 | margin-top: 7px; 22 | } 23 | 24 | .like-container { 25 | display: flex; 26 | flex-direction: row; 27 | justify-content: space-between; 28 | align-items: center; 29 | margin-right: 30rpx; 30 | } 31 | 32 | .like { 33 | margin-right: 30rpx; 34 | margin-top: 12rpx; 35 | } 36 | 37 | .share-btn { 38 | margin-top: 28rpx; 39 | margin-left: 10rpx; 40 | } 41 | 42 | .share { 43 | /* padding:10rpx; */ 44 | width: 40rpx; 45 | height: 40rpx; 46 | } 47 | 48 | .navi { 49 | position: absolute; 50 | bottom: 40rpx; 51 | } 52 | -------------------------------------------------------------------------------- /pages/course/course.js: -------------------------------------------------------------------------------- 1 | // pages/course/course.js 2 | Page({ 3 | 4 | /** 5 | * Page initial data 6 | */ 7 | data: { 8 | 9 | }, 10 | 11 | /** 12 | * Lifecycle function--Called when page load 13 | */ 14 | onLoad: function (options) { 15 | 16 | }, 17 | 18 | /** 19 | * Lifecycle function--Called when page is initially rendered 20 | */ 21 | onReady: function () { 22 | 23 | }, 24 | 25 | /** 26 | * Lifecycle function--Called when page show 27 | */ 28 | onShow: function () { 29 | 30 | }, 31 | 32 | /** 33 | * Lifecycle function--Called when page hide 34 | */ 35 | onHide: function () { 36 | 37 | }, 38 | 39 | /** 40 | * Lifecycle function--Called when page unload 41 | */ 42 | onUnload: function () { 43 | 44 | }, 45 | 46 | /** 47 | * Page event handler function--Called when user drop down 48 | */ 49 | onPullDownRefresh: function () { 50 | 51 | }, 52 | 53 | /** 54 | * Called when page reach bottom 55 | */ 56 | onReachBottom: function () { 57 | 58 | }, 59 | 60 | /** 61 | * Called when user click on the top right corner to share 62 | */ 63 | onShareAppMessage: function () { 64 | 65 | } 66 | }) -------------------------------------------------------------------------------- /pages/course/course.json: -------------------------------------------------------------------------------- 1 | { 2 | "backgroundColor": "#f5f5f5" 3 | } 4 | -------------------------------------------------------------------------------- /pages/course/course.wxml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pages/course/course.wxss: -------------------------------------------------------------------------------- 1 | .img { 2 | width: 100%; 3 | height: 1984rpx; 4 | } 5 | -------------------------------------------------------------------------------- /pages/my/my.js: -------------------------------------------------------------------------------- 1 | import { ClassicModel } from '../../models/classic.js' 2 | import { BookModel } from '../../models/book.js' 3 | 4 | let classicModel = new ClassicModel() 5 | let bookModel = new BookModel() 6 | 7 | Page({ 8 | data: { 9 | hasUserInfo: true, 10 | userInfo: null, 11 | classics: [], 12 | myBooksCount: 0 13 | }, 14 | onShow: function() { // 生命周期函数--监听页面加载 15 | this.getMyFavor() 16 | this.hasGottenUserInfo() 17 | this.getMyBookCount() 18 | }, 19 | getMyBookCount() { 20 | bookModel.getMyBookCount(data => { 21 | this.setData({ 22 | myBooksCount: data.count 23 | }) 24 | }) 25 | }, 26 | hasGottenUserInfo: function() { 27 | wx.getSetting({ // 获取用户的当前设置 28 | success: data => { 29 | if (data.authSetting['scope.userInfo']) { // 如果用户已经授权 30 | wx.getUserInfo({ 31 | success: data => { 32 | this.setData({ 33 | hasUserInfo: true, 34 | userInfo: data.userInfo 35 | }) 36 | } 37 | }) 38 | } else { 39 | this.setData({ 40 | hasUserInfo: false 41 | }) 42 | } 43 | } 44 | }) 45 | }, 46 | onGetUserInfo: function(event) { 47 | let userInfo = event.detail.userInfo 48 | if (userInfo) { 49 | this.setData({ 50 | hasUserInfo: true, 51 | userInfo: userInfo 52 | }) 53 | } 54 | }, 55 | getMyFavor: function() { 56 | classicModel.getMyFavor(data => { 57 | this.setData({ 58 | classics: data 59 | }) 60 | }) 61 | }, 62 | onPreviewTap: function(event) { 63 | wx.navigateTo({ 64 | url: '/pages/classic-detail/classic-detail?cid=' + event.detail.cid + '&type=' + event.detail.type 65 | }) 66 | }, 67 | onJumpToAbout: function() { 68 | wx.navigateTo({ 69 | url: '/pages/about/about' 70 | }) 71 | }, 72 | onStudy: function() { 73 | wx.navigateTo({ 74 | url: '/pages/course/course' 75 | }) 76 | }, 77 | onShareAppMessage() {} 78 | }) 79 | -------------------------------------------------------------------------------- /pages/my/my.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": { 3 | "img-btn-cmp": "/components/image-button/index", 4 | "tag-cmp": "/components/tag/index", 5 | "previe-cmp": "/components/preview/index" 6 | }, 7 | "backgroundColor": "#f5f5f5" 8 | } 9 | -------------------------------------------------------------------------------- /pages/my/my.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 关于我们 15 | 16 | 17 | {{myBooksCount}} 18 | 喜欢的书 19 | 20 | 21 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /pages/my/my.wxss: -------------------------------------------------------------------------------- 1 | .container { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | } 6 | 7 | .bg { 8 | width: 750rpx; 9 | height: 574rpx; 10 | } 11 | 12 | .avatar-position { 13 | position: absolute; 14 | top: 255rpx; 15 | } 16 | 17 | .my-img { 18 | width: 120rpx; 19 | height: 120rpx; 20 | } 21 | 22 | .avatar-container { 23 | display: flex; 24 | flex-direction: column; 25 | align-items: center; 26 | } 27 | 28 | .avatar { 29 | width: 120rpx; 30 | height: 120rpx; 31 | border-radius: 50%; 32 | /* margin-bottom: 10rpx; */ 33 | } 34 | 35 | .about-container { 36 | padding: 0 100rpx; 37 | width: 550rpx; 38 | display: flex; 39 | flex-direction: row; 40 | justify-content: space-between; 41 | position: absolute; 42 | top: 440rpx; 43 | } 44 | 45 | .about-us image { 46 | width: 34rpx; 47 | height: 34rpx; 48 | } 49 | .preview-container { 50 | margin-top: 30rpx; 51 | display: flex; 52 | flex-direction: row; 53 | padding: 0 30rpx; 54 | flex-wrap: wrap; 55 | justify-content: space-between; 56 | } 57 | 58 | .preview { 59 | margin-bottom: 30rpx; 60 | } 61 | .about-us { 62 | display: flex; 63 | flex-direction: column; 64 | align-items: center; 65 | justify-content: space-between; 66 | } 67 | 68 | .book-num { 69 | font-size: 36rpx; 70 | color: #000000; 71 | } 72 | 73 | .description { 74 | font-size: 24rpx; 75 | color: #999999; 76 | } 77 | 78 | .about-container > view:nth-child(2) { 79 | margin-top: -5rpx; 80 | } 81 | 82 | .like-container { 83 | /* margin-top:30rpx; */ 84 | width: 100%; 85 | margin-top: -13rpx; 86 | display: flex; 87 | flex-direction: column; 88 | align-items: center; 89 | background-color: #f5f5f5; 90 | } 91 | 92 | .headline { 93 | margin-top: 30rpx; 94 | width: 97rpx; 95 | height: 42rpx; 96 | } 97 | 98 | .study { 99 | width: 88rpx; 100 | height: 88rpx; 101 | position: absolute; 102 | top: 40rpx; 103 | right: 45rpx; 104 | } 105 | 106 | .test { 107 | background-color: red !important; 108 | border-radius: 15px !important; 109 | } 110 | -------------------------------------------------------------------------------- /project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "Project configuration file", 3 | "packOptions": { 4 | "ignore": [] 5 | }, 6 | "setting": { 7 | "urlCheck": false, 8 | "es6": true, 9 | "postcss": true, 10 | "minified": true, 11 | "newFeature": true 12 | }, 13 | "compileType": "miniprogram", 14 | "libVersion": "2.3.0", 15 | "appid": "wxabcaad13aeed9229", 16 | "projectname": "wx-pure", 17 | "debugOptions": { 18 | "hidedInDevtools": [] 19 | }, 20 | "isGameTourist": false, 21 | "simulatorType": "wechat", 22 | "simulatorPluginLibVersion": {}, 23 | "condition": { 24 | "search": { 25 | "current": -1, 26 | "list": [] 27 | }, 28 | "conversation": { 29 | "current": -1, 30 | "list": [] 31 | }, 32 | "plugin": { 33 | "current": -1, 34 | "list": [] 35 | }, 36 | "game": { 37 | "currentL": -1, 38 | "list": [] 39 | }, 40 | "miniprogram": { 41 | "current": 5, 42 | "list": [ 43 | { 44 | "id": -1, 45 | "name": "book-detail", 46 | "pathName": "pages/book-detail/book-detail", 47 | "query": "bid=7" 48 | }, 49 | { 50 | "id": -1, 51 | "name": "classic", 52 | "pathName": "pages/classic/classic", 53 | "query": "" 54 | }, 55 | { 56 | "id": -1, 57 | "name": "book-detail", 58 | "pathName": "pages/book-detail/book-detail", 59 | "query": "bid=1120" 60 | }, 61 | { 62 | "id": -1, 63 | "name": "book", 64 | "pathName": "pages/book/book", 65 | "query": "" 66 | }, 67 | { 68 | "id": -1, 69 | "name": "search", 70 | "pathName": "components/search/index", 71 | "query": "" 72 | }, 73 | { 74 | "id": -1, 75 | "name": "my", 76 | "pathName": "pages/my/my", 77 | "query": "" 78 | } 79 | ] 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /promise.md: -------------------------------------------------------------------------------- 1 | # promise 2 | 3 | promise 对象能保存状态, 函数不能保存状态会马上返 4 | 回, 闭包函数能保存状态 5 | 异步代码写在 promise 中 6 | 7 | ```js 8 | const promise = new Promise((resolve, reject) => { 9 | /* promise 状态: pending(进行中) fulfilled(成功) rejected(失败) */ 10 | wx.getSystemInfo({ 11 | success: res => { 12 | /* 修改状态: pending(进行中) -> fulfilled(成功), 之后会凝固 */ 13 | resolve(res) 14 | }, 15 | fail: err => { 16 | /* 修改状态: pending(进行中) -> rejected(失败), 之后会凝固 */ 17 | reject(err) 18 | } 19 | }) 20 | }) 21 | /* then(): 拿到异步执行后的结果状态 */ 22 | promise.then( 23 | res => { 24 | console.log(res + ' success!') 25 | }, 26 | err => { 27 | console.log(err + ' fail!') 28 | } 29 | ) 30 | ``` 31 | 32 | ```js 33 | bookModel 34 | .getHotList() 35 | .then(res => { 36 | /* res -> api1 result */ 37 | console.log(res) 38 | /* invoked api2 */ 39 | return bookModel.getMyBookCount() 40 | }) 41 | .then(res => { 42 | /* res -> api2 result */ 43 | console.log(res) 44 | /* invoked api3 */ 45 | return bookModel.getMyBookCount() 46 | }) 47 | .then(res => { 48 | /* res -> api3 result */ 49 | console.log(res) 50 | }) 51 | ``` 52 | -------------------------------------------------------------------------------- /sitemap.json: -------------------------------------------------------------------------------- 1 | { 2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", 3 | "rules": [{ 4 | "action": "allow", 5 | "page": "*" 6 | }] 7 | } -------------------------------------------------------------------------------- /utils/filter.wxs: -------------------------------------------------------------------------------- 1 | var limit = function(array, length) { 2 | return array.slice(0, length) 3 | } 4 | 5 | // 不能用 const, wxs 不能用 es6 语法 6 | var format = function(text) { 7 | if (!text) { 8 | return 9 | } 10 | var reg = getRegExp('\\\\n', 'g') 11 | var text = text.replace(reg, '\n     ') 12 | return text 13 | } 14 | 15 | module.exports = { 16 | format: format, 17 | limit: limit 18 | } 19 | -------------------------------------------------------------------------------- /utils/http-p.js: -------------------------------------------------------------------------------- 1 | import { config } from '../config.js' 2 | 3 | const tips = { 4 | 1: '出现一个错误!', 5 | 1005: 'appkey 无效', 6 | 3000: '期刊不存在' 7 | } 8 | 9 | class HTTP { 10 | request({ url, data = {}, method = 'GET' }) { // 解构 {} 11 | return new Promise((resolve, reject) => { 12 | this._request(url, resolve, reject, data, method) // 必填参数在默认参数之前 13 | }) 14 | } 15 | _request(url, resolve, reject, data = {}, method = 'GET') { // 必填参数在默认参数前 16 | wx.request({ 17 | url: config.api_blink_url + url, 18 | data: data, 19 | method: method, 20 | header: { 21 | 'content-type': 'application/json', 22 | appkey: config.appkey 23 | }, 24 | success: res => { 25 | const code = res.statusCode.toString() // 判断以2(2xx)开头的状态码为正确 26 | if (code.startsWith('2')) { 27 | resolve(res.data) 28 | } else { 29 | reject() 30 | const error_code = res.data.error_code 31 | this._show_error(error_code) 32 | } 33 | }, 34 | fail: err => { // 没网络时才调用 35 | reject() 36 | this._show_error(1) 37 | } 38 | }) 39 | } 40 | _show_error(error_code) { 41 | if (!error_code) { 42 | error_code = 1 43 | } 44 | const tip = tips[error_code] 45 | wx.showToast({ 46 | title: tip ? tip : tips[1], 47 | icon: 'none', 48 | duration: 2000 49 | }) 50 | } 51 | } 52 | 53 | export { HTTP } 54 | -------------------------------------------------------------------------------- /utils/http.js: -------------------------------------------------------------------------------- 1 | import { config } from '../config.js' 2 | 3 | const tips = { 4 | 1: '出现一个错误!', 5 | 1005: 'appkey 无效', 6 | 3000: '期刊不存在' 7 | } 8 | 9 | class HTTP { 10 | constructor() { 11 | this.baseRestUrl = config.api_blink_url 12 | } 13 | request(params) { 14 | let url = this.baseRestUrl + params.url 15 | if (!params.method) { 16 | params.method = 'GET' 17 | } 18 | wx.request({ // wx.request: async request 19 | url: url, 20 | data: params.data, 21 | method: params.method, 22 | header: { 23 | 'content-type': 'application/json', 24 | appkey: config.appkey 25 | }, 26 | success: res => { // Receive the result of an asyn call res 27 | const code = res.statusCode.toString() 28 | if (code.startsWith('2')) { 29 | params.success && params.success(res.data) // params.success 是否为 null, 如果不是则执行后面代码 30 | } else { 31 | const error_code = res.data.error_code 32 | this._show_error(error_code) 33 | } 34 | }, 35 | fail: err => { // no network invoked, 4xx not invoked 36 | this._show_error(1) 37 | } 38 | }) 39 | } 40 | _show_error(error_code) { // wechat no private 41 | if (!error_code) { 42 | error_code = 1 43 | } 44 | const tip = tips[error_code] 45 | wx.showToast({ 46 | title: tip ? tip : tips[1], 47 | icon: 'none', 48 | duration: 2000 49 | }) 50 | } 51 | } 52 | 53 | export { HTTP } 54 | -------------------------------------------------------------------------------- /utils/util.js: -------------------------------------------------------------------------------- 1 | const chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'] 2 | 3 | const random = function generateMixed(n) { 4 | var res = '' 5 | for (var i = 0; i < n; i++) { 6 | var id = Math.ceil(Math.random() * 35) 7 | res += chars[id] 8 | } 9 | return res 10 | } 11 | 12 | function breakSection(text) {} 13 | 14 | module.exports = { 15 | random: random, 16 | breakSection: breakSection 17 | } 18 | -------------------------------------------------------------------------------- /纯正商业级应用-微信小程序开发实战.mmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GanYihuan/wx-pure/50d4878ca8e278e69697f52000551d8c765e4368/纯正商业级应用-微信小程序开发实战.mmap --------------------------------------------------------------------------------