├── .eslintrc.js
├── LICENSE
├── README.md
├── cloudfunctions
├── statisticRouter
│ ├── config.json
│ ├── index.js
│ ├── package.json
│ └── utils
│ │ └── response_content.js
├── userRouter
│ ├── config.json
│ ├── index.js
│ ├── package-lock.json
│ ├── package.json
│ └── utils
│ │ ├── default_avatar_pic.js
│ │ ├── init_of_matrix.js
│ │ └── response_content.js
└── wordRouter
│ ├── config.json
│ ├── index.js
│ ├── package.json
│ └── utils
│ ├── format_time.js
│ ├── get_all_sort_list.js
│ ├── jstat.min.js
│ ├── response_content.js
│ └── sm-5.js
├── images
├── after_login_index.jpg
├── after_login_overview_1.jpg
├── after_login_overview_2.jpg
├── after_login_user.jpg
├── before_login_index.jpg
├── before_login_user.jpg
├── learning_1.jpg
├── learning_3.jpg
├── learning_4.jpg
├── learning_5.jpg
├── learning_6.jpg
├── learning_8.jpg
├── login.jpg
├── miniprogram_QRcode.jpg
├── search_1.jpg
├── search_translation.jpg
├── search_word_big.jpg
├── search_word_small.jpg
├── settings.jpg
├── title_1.png
├── title_2.png
├── title_3.png
├── title_4.png
├── word_detail.jpg
├── word_list.jpg
└── 整体框架图.png
├── miniprogram
├── app.js
├── app.json
├── app.wxss
├── components
│ ├── cloudTipModal
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ ├── ec-canvas
│ │ ├── ec-canvas.js
│ │ ├── ec-canvas.json
│ │ ├── ec-canvas.wxml
│ │ ├── ec-canvas.wxss
│ │ ├── echarts.js
│ │ ├── echartsForBar.js
│ │ └── wx-canvas.js
│ ├── image-cropper
│ │ ├── image-cropper.js
│ │ ├── image-cropper.json
│ │ ├── image-cropper.wxml
│ │ └── image-cropper.wxss
│ └── mp-progress
│ │ ├── mp-progress.js
│ │ ├── mp-progress.json
│ │ ├── mp-progress.wxml
│ │ ├── progress.js
│ │ └── progress.min.js
├── envList.js
├── lib
│ ├── jstat.min.js
│ ├── runtime
│ │ └── runtime.js
│ └── sm-5.js
├── pages
│ ├── image_cropper
│ │ ├── image_cropper.js
│ │ ├── image_cropper.json
│ │ ├── image_cropper.less
│ │ ├── image_cropper.wxml
│ │ └── image_cropper.wxss
│ ├── index
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.less
│ │ ├── index.wxml
│ │ └── index.wxss
│ ├── learning
│ │ ├── learning.js
│ │ ├── learning.json
│ │ ├── learning.less
│ │ ├── learning.wxml
│ │ └── learning.wxss
│ ├── login
│ │ ├── login.js
│ │ ├── login.json
│ │ ├── login.less
│ │ ├── login.wxml
│ │ └── login.wxss
│ ├── overview
│ │ ├── overview.js
│ │ ├── overview.json
│ │ ├── overview.less
│ │ ├── overview.wxml
│ │ └── overview.wxss
│ ├── review
│ │ ├── review.js
│ │ ├── review.json
│ │ ├── review.less
│ │ ├── review.wxml
│ │ └── review.wxss
│ ├── search
│ │ ├── search.js
│ │ ├── search.json
│ │ ├── search.less
│ │ ├── search.wxml
│ │ └── search.wxss
│ ├── user
│ │ ├── user.js
│ │ ├── user.json
│ │ ├── user.less
│ │ ├── user.wxml
│ │ └── user.wxss
│ ├── user_settings
│ │ ├── user_settings.js
│ │ ├── user_settings.json
│ │ ├── user_settings.less
│ │ ├── user_settings.wxml
│ │ └── user_settings.wxss
│ ├── word_detail
│ │ ├── word_detail.js
│ │ ├── word_detail.json
│ │ ├── word_detail.less
│ │ ├── word_detail.wxml
│ │ └── word_detail.wxss
│ └── word_list
│ │ ├── word_list.js
│ │ ├── word_list.json
│ │ ├── word_list.less
│ │ ├── word_list.wxml
│ │ └── word_list.wxss
├── sitemap.json
├── static
│ ├── color.wxss
│ ├── iconfont.wxss
│ └── images
│ │ ├── logo.png
│ │ ├── tab-learn-007BFF.png
│ │ ├── tab-learn-3880B7.png
│ │ ├── tab-learn-62BEFF.png
│ │ ├── tab-learn-A6D6FA.png
│ │ ├── tab-learn-CDCDCD.png
│ │ ├── tab-learn-F6F6F6.png
│ │ ├── tab-learn-FFFFFF.png
│ │ ├── tab-overview-007BFF.png
│ │ ├── tab-overview-3880B7.png
│ │ ├── tab-overview-62BEFF.png
│ │ ├── tab-overview-A6D6FA.png
│ │ ├── tab-overview-CDCDCD.png
│ │ ├── tab-user-007BFF.png
│ │ ├── tab-user-3880B7.png
│ │ ├── tab-user-62BEFF.png
│ │ ├── tab-user-A6D6FA.png
│ │ └── tab-user-CDCDCD.png
└── utils
│ ├── color.js
│ ├── format_time.js
│ ├── response_content.js
│ ├── userApi.js
│ ├── wordApi.js
│ └── word_utils.js
├── project.config.json
└── project.private.config.json
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Eslint config file
3 | * Documentation: https://eslint.org/docs/user-guide/configuring/
4 | * Install the Eslint extension before using this feature.
5 | */
6 | module.exports = {
7 | env: {
8 | es6: true,
9 | browser: true,
10 | node: true,
11 | },
12 | ecmaFeatures: {
13 | modules: true,
14 | },
15 | parserOptions: {
16 | ecmaVersion: 2018,
17 | sourceType: 'module',
18 | },
19 | globals: {
20 | wx: true,
21 | App: true,
22 | Page: true,
23 | getCurrentPages: true,
24 | getApp: true,
25 | Component: true,
26 | requirePlugin: true,
27 | requireMiniProgram: true,
28 | },
29 | // extends: 'eslint:recommended',
30 | rules: {},
31 | }
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Mint-green
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 学不会单词
2 |
3 | 一个背单词小程序
4 |
5 |
6 |
7 |
8 | ### 词汇数据来源
9 | [ECDICT](https://github.com/skywind3000/ECDICT)
10 |
11 |
12 |
13 | ### 简介
14 | 这是一个背单词小程序,是仿**不背单词**App做的(因为不背的UI真的太好看了),词库是刚好找到了大佬的**ECDICT**项目,把这些数据稍微做了些处理导入了数据库。
15 | 主要实现搜索,学习单词,复习单词,统计,登录等功能。
16 |
17 |
18 |
19 |
20 | ### 整体结构
21 | 
22 |
23 |
24 |
25 | ### 功能模块及页面
26 | - [x] 登录模块(支持账号密码、微信登录&注册)
27 |
28 | - [x] 主页
29 | - [x] 每日一句(获取&发音)
30 | - [x] 主页显示需要背以及复习的量
31 |
32 | - [x] 概述页
33 | - [x] 显示相关基础及统计数据(词书、已背数量等)
34 | - [x] 切换词书
35 | - [x] 查看所有学过/未学习的单词等各项统计的单词队列
36 | - [x] 收藏夹
37 | - [x] 每日任务
38 | - [x] ECharts显示历史学习记录
39 |
40 | - [x] 个人主页
41 | - [x] 个人信息更改(头像、昵称、密码)
42 |
43 | - [x] 单词详情页
44 |
45 | - [x] 搜索模块
46 | - [x] 用英文搜索(前缀、搜原型、空格模糊搜索)
47 | - [x] 中文释义进行搜索(直接当空格模糊使,近义词替代和自动分词太难了没做)
48 | - [x] 历史搜索
49 | - [x] 切换大小词库(小的快/大的全)
50 |
51 | - [x] 学习/复习单词
52 | - [x] 三种题型(看词选义、看词识义、看义识词)
53 | - [x] 遮挡单词or词义样式(倒计时自动取消or遮挡条点击取消)
54 | - [x] 循环逻辑及实现
55 | - [x] 跳过or设置为已掌握
56 | - [x] 复习时间间隔算法(参考SuperMemo系列SM-5算法)
57 | - [ ] 拼写页面
58 |
59 | - [x] 设置页
60 |
61 |
62 |
63 | ### 效果图
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | ### 体验
82 |
83 | ~~想要玩一下的可以扫描以下二维码~~:
84 |
85 |
86 |
87 | 由于微信要取消云开发基础套餐的免费使用了,而本人暂无精力完善此项目,这个月(22.10)20号会清除本项目的云开发数据,目前已将已有数据备份,有机会会再放出来给大家体验的!
88 | 不过还是老样子,大家有什么需求或问题都可以提一下issue,我会竭力帮大家解决的~
89 |
90 |
91 |
92 | ### 自行部署
93 |
94 | 1. 由于本项目依托微信小程序提供的云开发能力,因此需要一些注册等的基本操作,可以参考我的另一个项目...的指引,如果会申请小程序使用云开发能力的可以朋友可以略过这一步:[GuGuMusic的使用方法](https://github.com/Mint-green/GuGumusic#%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95)
95 | 2. 下载基础数据库的文件,最近还是没能力完善说明各个表格的具体字段等,大家可以查看数据后大致判断,[度盘链接](https://pan.baidu.com/s/1LR6Q6BojBTQ0ywWiJVFX6w),提取码:dddd
96 | 3. cloudfunctions文件夹在的云函数右键部署,在云开发服务的地方也按照2中的文档建好并导入需要的数据后,应该就可以用了
97 |
98 |
99 |
100 | ### 更多
101 |
102 | 最近比较忙,先简单列列已完成的and放放效果图(请原谅我放那么多图),详细的介绍之后再上,持续更新ing~
103 | 有问题都可以提问,有什么想法也可以提一提呀~
104 |
105 |
106 |
107 | ### 更新日志
108 |
109 | **22.10.02** 修复第一个用户(普通/微信)无法创建成功问题
110 |
111 | **22.10.02** 由于微信调整云开发计费规则,本项目小程序测试版将于22年10月中旬停止开放
--------------------------------------------------------------------------------
/cloudfunctions/statisticRouter/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "permissions": {
3 | "openapi": [
4 | ]
5 | }
6 | }
--------------------------------------------------------------------------------
/cloudfunctions/statisticRouter/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "statisticRouter",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "wx-server-sdk": "~2.5.3",
13 | "tcb-router": "^1.1.2"
14 | }
15 | }
--------------------------------------------------------------------------------
/cloudfunctions/statisticRouter/utils/response_content.js:
--------------------------------------------------------------------------------
1 | const SUCCESS = { errorcode: 100, errormsg: "success" } //成功
2 | const LOGINOK = { errorcode: 1, errormsg: "Login successfully" } //登录成功
3 | const REGISTEROK= { errorcode: 2, errormsg: "Register successfully" } //注册成功
4 | const DBERR = { errorcode: -1, errormsg: "Database error!" } //数据库操作失败
5 | const ROUTERERR = { errorcode: -2, errormsg: "Wrong router name" } //路由名字有误
6 | const LOGINERR = { errorcode: -3, errormsg: "Wrong username or pwd" } //登录信息有误
7 | const DATAERR = { errorcode: -4, errormsg: "Wrong data!" } //数据有误
8 | const UNKOWNERR = { errorcode: -100, errormsg: "Unkown error!" } //出现未知错误
9 |
10 |
11 | module.exports={
12 | SUCCESS: SUCCESS,
13 | LOGINOK: LOGINOK,
14 | REGISTEROK: REGISTEROK,
15 | DBERR: DBERR,
16 | ROUTERERR: ROUTERERR,
17 | LOGINERR: LOGINERR,
18 | DATAERR: DATAERR,
19 | UNKOWNERR: UNKOWNERR,
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/cloudfunctions/userRouter/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "permissions": {
3 | "openapi": [
4 | ]
5 | }
6 | }
--------------------------------------------------------------------------------
/cloudfunctions/userRouter/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "userRouter",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "tcb-router": {
8 | "version": "1.1.2",
9 | "resolved": "https://registry.npmjs.org/tcb-router/-/tcb-router-1.1.2.tgz",
10 | "integrity": "sha512-VB+83paVdYG0LWaodh73JUy660te2oleM5gETslbCHLnhTtgXXYfAR0dlHBU5dIhhH47V1nKp43lZUo6Xm9O4g=="
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/cloudfunctions/userRouter/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "userRouter",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "tcb-router": "^1.1.2",
13 | "wx-server-sdk": "~2.5.3"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/cloudfunctions/userRouter/utils/default_avatar_pic.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | 'https://pic2.zhimg.com/50/v2-34395fd10798f4b5bad583d61f98c849_hd.jpg?source=1940ef5c',
3 | 'https://pic2.zhimg.com/50/v2-b1e4eb7f72908a04306958f13ce45d94_hd.jpg?source=1940ef5c',
4 | 'https://inews.gtimg.com/newsapp_bt/0/13804696252/1000',
5 | 'https://inews.gtimg.com/newsapp_bt/0/13808742009/1000'
6 | ]
--------------------------------------------------------------------------------
/cloudfunctions/userRouter/utils/init_of_matrix.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = {
3 | '1.3': [5],
4 | '1.4': [5],
5 | '1.5': [5],
6 | '1.6': [5],
7 | '1.7': [5],
8 | '1.8': [5],
9 | '1.9': [5],
10 | '2.0': [5],
11 | '2.1': [5],
12 | '2.2': [5],
13 | '2.3': [5],
14 | '2.4': [5],
15 | '2.5': [5],
16 | '2.6': [5],
17 | '2.7': [5],
18 | '2.8': [5],
19 | }
--------------------------------------------------------------------------------
/cloudfunctions/userRouter/utils/response_content.js:
--------------------------------------------------------------------------------
1 | const SUCCESS = { errorcode: 100, errormsg: "success" } //成功
2 | const LOGINOK = { errorcode: 1, errormsg: "Login successfully" } //登录成功
3 | const REGISTEROK= { errorcode: 2, errormsg: "Register successfully" } //注册成功
4 | const DBERR = { errorcode: -1, errormsg: "Database error!" } //数据库操作失败
5 | const ROUTERERR = { errorcode: -2, errormsg: "Wrong router name" } //路由名字有误
6 | const LOGINERR = { errorcode: -3, errormsg: "Wrong username or pwd" } //登录信息有误
7 | const DATAERR = { errorcode: -4, errormsg: "Wrong data!" } //数据有误
8 | const UNKOWNERR = { errorcode: -100, errormsg: "Unkown error!" } //出现未知错误
9 |
10 |
11 | module.exports={
12 | SUCCESS: SUCCESS,
13 | LOGINOK: LOGINOK,
14 | REGISTEROK: REGISTEROK,
15 | DBERR: DBERR,
16 | ROUTERERR: ROUTERERR,
17 | LOGINERR: LOGINERR,
18 | DATAERR: DATAERR,
19 | UNKOWNERR: UNKOWNERR,
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/cloudfunctions/wordRouter/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "permissions": {
3 | "openapi": [
4 | ]
5 | }
6 | }
--------------------------------------------------------------------------------
/cloudfunctions/wordRouter/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "wordRouter",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "tcb-router": "^1.1.2",
13 | "wx-server-sdk": "~2.5.3",
14 | "bent": "<=7.3.12"
15 | }
16 | }
--------------------------------------------------------------------------------
/cloudfunctions/wordRouter/utils/format_time.js:
--------------------------------------------------------------------------------
1 | // 传入时间的毫秒数(date.getTime())获取时间详情
2 |
3 | const formatTime = (time) => {
4 | var date = new Date(time)
5 | var y = date.getFullYear()
6 | var m = date.getMonth() + 1
7 | var d = date.getDate()
8 | var h = date.getHours()
9 | var min = date.getMinutes()
10 | var s = date.getSeconds()
11 | var timeStr = y + "-" + enterZero(m) + "-" + enterZero(d) + " " + enterZero(h) + ":" + enterZero(min) + ":" + enterZero(s)
12 | return timeStr
13 | }
14 |
15 | const formatDate = (time) => {
16 | var date = new Date(time)
17 | var y = date.getFullYear()
18 | var m = date.getMonth() + 1
19 | var d = date.getDate()
20 | var dateStr = y + "-" + enterZero(m) + "-" + enterZero(d)
21 | return dateStr
22 | }
23 |
24 | const dateNum = (time) => {
25 | var date = new Date(time)
26 | var y = date.getFullYear()
27 | var m = date.getMonth() + 1
28 | var d = date.getDate()
29 | var num = y *10000 + m*100 + d
30 | return num
31 | }
32 |
33 | const enterZero = (num) => {
34 | num = Math.abs(num)
35 | if (num <= 9) {
36 | num = "0" + num
37 | }
38 | return num
39 | }
40 |
41 | module.exports = {
42 | formatTime: formatTime,
43 | formatDate: formatDate,
44 | dateNum: dateNum,
45 | }
--------------------------------------------------------------------------------
/cloudfunctions/wordRouter/utils/get_all_sort_list.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {*} source 源数组
4 | * @param {*} count 要取出多少项
5 | * @param {*} isPermutation 是否使用排列的方式
6 | * @return {any[]} 所有排列组合,格式为 [ [1,2], [1,3]] ...
7 | */
8 | const getAllSortList = (source, count, isPermutation = true) => {
9 | //如果只取一位,返回数组中的所有项,例如 [ [1], [2], [3] ]
10 | let currentList = source.map((item) => [item]);
11 | if (count === 1) {
12 | return currentList;
13 | }
14 | let result = [];
15 | //取出第一项后,再取出后面count - 1 项的排列组合,并把第一项的所有可能(currentList)和 后面count-1项所有可能交叉组合
16 | for (let i = 0; i < currentList.length; i++) {
17 | let current = currentList[i];
18 | //如果是排列的方式,在取count-1时,源数组中排除当前项
19 | let children = [];
20 | if (isPermutation) {
21 | children = getAllSortList(source.filter(item => item !== current[0]), count - 1, isPermutation);
22 | }
23 | //如果是组合的方法,在取count-1时,源数组只使用当前项之后的
24 | else {
25 | children = getAllSortList(source.slice(i + 1), count - 1, isPermutation);
26 | }
27 | for (let child of children) {
28 | result.push([...current, ...child]);
29 | }
30 | }
31 | return result;
32 | }
33 |
34 | // let arr = [1, 2, 3];
35 | // const result = getNumbers(arr, 2, false);
36 | // console.log(result);
37 | // //[ [ 1, 2 ], [ 1, 3 ], [ 2, 3 ] ]
38 |
39 | // const result2 = getNumbers(arr, 2);
40 | // console.log(result2);
41 | // //[ [ 1, 2 ], [ 1, 3 ], [ 2, 1 ], [ 2, 3 ], [ 3, 1 ], [ 3, 2 ] ]
42 |
43 | module.exports = {
44 | getAllSortList: getAllSortList,
45 | }
46 |
--------------------------------------------------------------------------------
/cloudfunctions/wordRouter/utils/response_content.js:
--------------------------------------------------------------------------------
1 | const SUCCESS = { errorcode: 100, errormsg: "success" } //成功
2 | const LOGINOK = { errorcode: 1, errormsg: "Login successfully" } //登录成功
3 | const REGISTEROK= { errorcode: 2, errormsg: "Register successfully" } //注册成功
4 | const DBERR = { errorcode: -1, errormsg: "Database error!" } //数据库操作失败
5 | const ROUTERERR = { errorcode: -2, errormsg: "Wrong router name" } //路由名字有误
6 | const LOGINERR = { errorcode: -3, errormsg: "Wrong username or pwd" } //登录信息有误
7 | const DATAERR = { errorcode: -4, errormsg: "Wrong data!" } //数据有误
8 | const UNKOWNERR = { errorcode: -100, errormsg: "Unkown error!" } //出现未知错误
9 |
10 |
11 | module.exports={
12 | SUCCESS: SUCCESS,
13 | LOGINOK: LOGINOK,
14 | REGISTEROK: REGISTEROK,
15 | DBERR: DBERR,
16 | ROUTERERR: ROUTERERR,
17 | LOGINERR: LOGINERR,
18 | DATAERR: DATAERR,
19 | UNKOWNERR: UNKOWNERR,
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/cloudfunctions/wordRouter/utils/sm-5.js:
--------------------------------------------------------------------------------
1 | // SM-5算法
2 | // 计算下一个最优间隔的同时更新OF矩阵,从而单词在学习的时候不是一个个体,而是
3 |
4 | // 用于生成最佳区间的随机散布 NOI--near-optimal intervals
5 | // -------------------------------------------------------------
6 | // 优点1: 通过一些差异值来加速OF矩阵优化过程
7 | // 优点2: 消除复习的块状问题,将同一时期学习的内容适当分散进行复习
8 | // 公式: NOI=PI+(OI-PI)*(1+m) m∈(-0.5, 0.5)
9 | // m需满足(设概率密度函数为f(x)):
10 | // (0, 0.5)内的概率为0.5,即 ∫[0, 0.5]f(x)dx=0.5
11 | // m=0的概率为m=0.5的概率的100倍 即 f(0)/f(0.5)=100
12 | // 假设概率密度函数为 f(x)=a*exp(-b*x)
13 | // -------------------------------------------------------------
14 | // Piotr Wozniak求得 a=0.047; b=0.092;
15 | // 从0到m的积分记为概率p,对于每一个p都有一个对应的m存在,p∈(0, 0.5)
16 | // 生成一个(0, 1)之间的随机数,减去0.5得p,则|p|∈(0, 0.5),而p的符号可以控制m的符号
17 | // 则 ∫[0, m]f(x)dx=|p| => ∫[0, m]d( a*exp(-b*x) / (-b) )=|p| => m=-1/b*ln(1-b/a*|p|))
18 | //
19 | // const createNOI = (PI, OI) => {
20 | // let a = 0.047
21 | // let b = 0.092
22 | // let randNum = Math.random()
23 | // let p = randNum - 0.5
24 | // console.log('random p', p)
25 | // let m = -1 / b * (Math.log((1 - b / a * Math.abs(p))))
26 | // m = m * Math.sign(p)
27 | // console.log('random m', m)
28 | // let NOI = PI + (OI - PI) * (1 + m)
29 | // NOI = Math.round(NOI)
30 | // return NOI
31 | // }
32 |
33 | // -------------------------------------------------------------
34 | // 由于作者给出的参数带入是有误的,采用类正态分布实现分布函数
35 | // 原型(标准正态分布):f(x) = 1/(√(2π)*Ω) * e(-x^2/(2Ω^2))
36 | // 简化:f(x) = a*e^(-b*x^2)
37 | // f(0) = 100*f(0.5) 可求得 b = -18.420680743952367
38 | // ∫[0, 0.5]f(x)dx = 0.5 可求得 a = 2.4273047133848933
39 | // 积分计算器网址: https://zh.numberempire.com/definiteintegralcalculator.php
40 | // 画函数图像网址:https://www.desmos.com/calculator?lang=zh-CN
41 | // 这里使用能解正态分布分位数的库进行运算
42 | // f(0) = 100*f(0.5) 按正态分布算,可求得 std=0.1647525572455652
43 | // X ~ N(0,0.1647525572455652) 从0~0.5的累计分布值为0.4987967402705885
44 | // 故若要满足∫[0, 0.5]f(x)dx = 0.5,要在前面再乘上
45 | // JStat库的jStat.normal.inv( p, mean, std )可以求出N(mean,std)分布从负无穷开始累计分布为p的分位点
46 | // 因此思路转变为,首先随机获取[0, 1)的数r, r-0.5得到[-0.5, 0.5)的数m,(m*0.4987967402705885/0.5+0.5)得到累计值
47 | // 即jStat.normal.inv(abs(m*0.4987967402705885/0.5)+0.5, 0, 0.1647525572455652) 可得到分位点
48 |
49 | const jStat = require("./jstat.min.js")
50 | const createNOI = (PI, OI) => {
51 | let mean = 0
52 | let std = 0.1647525572455652
53 | let randNum = Math.random()
54 | // console.log('randNum', randNum)
55 | let p = Math.abs((randNum - 0.5) * 0.4987967402705885 / 0.5) + 0.5
56 | // console.log('random p', p)
57 | let inv_cdf = jStat.normal.inv(p, mean, std)
58 | let m = inv_cdf * Math.sign(randNum - 0.5)
59 | // console.log('random m', m)
60 | let NOI = PI + (OI - PI) * (1 + m)
61 | NOI = Math.round(NOI)
62 | return NOI
63 | }
64 |
65 |
66 | // 符号函数
67 | const sgn = (num) => {
68 | if (num < 0) {
69 | return -1
70 | } else if (num == 0) {
71 | return 0
72 | } else {
73 | return 1
74 | }
75 | }
76 |
77 | // 计算新的OF矩阵对应项
78 | // 输入:
79 | // last_i - 用于相关项目的最后(上一个)间隔(原文描述为the last interval used for the item in question)
80 | // q - 重复响应的质量
81 | // used_OF - 用于计算相关项目的最后一个间隔时使用的最佳因子
82 | // old_OF - 与项目的相关重复次数和电子因子相对应的 OF 条目的前一个值
83 | // fraction - 属于确定修改速率的范围 (0,1) 的数字 (OF矩阵的变化越快)
84 | // 输出:
85 | // new_OF - 考虑的 OF 矩阵条目的新计算值
86 | // 局部变量:
87 | // modifier - 确定 OF 值将增加或减少多少次的数字
88 | // mod5 - 在 q=5 的情况下为修饰符建议的值
89 | // mod2 - 在 q=2 的情况下为修饰符建议的值
90 | const calculateNewOF = (last_i, q, used_OF, old_OF, fraction = 0.8) => {
91 | let modifier
92 | let mod5 = (last_i + 1) / last_i
93 | if (mod5 < 1.05) mod5 = 1.05
94 | let mod2 = (last_i - 1) / last_i
95 | if (mod2 > 0.75) mod2 = 0.75
96 | if (q > 4) {
97 | modifier = 1 + (mod5 - 1) * (q - 4)
98 | } else {
99 | modifier = 1 - (1 - mod2) / 2 * (4 - q)
100 | }
101 | if (modifier < 0.05) modifier = 0.05
102 | let new_OF = used_OF * modifier
103 | if (q > 4) if (new_OF < old_OF) new_OF = old_OF
104 | if (q < 4) if (new_OF > old_OF) new_OF = old_OF
105 | new_OF = new_OF * fraction + old_OF * (1 - fraction)
106 | if (new_OF < 1.2) new_OF = 1.2
107 | new_OF = new_OF.toFixed(4)
108 | new_OF = parseFloat(new_OF)
109 | return new_OF
110 | }
111 |
112 | // 单词记录提供数据:循环次数,上次的EF,上次的间隔时间(/天), q(quality,回忆质量)
113 | // 其他:OF矩阵
114 | const sm_5 = (OF, wd_learning_record) => {
115 | let EF = wd_learning_record.EF
116 | let q = wd_learning_record.q
117 | let last_NOI = wd_learning_record.NOI
118 | let n = wd_learning_record.next_n
119 | let last_l = wd_learning_record.last_l
120 | let next_l = wd_learning_record.next_l
121 | let master = wd_learning_record.master
122 |
123 | if (master) {
124 | return {
125 | wd_learning_record: {
126 | word_id: wd_learning_record.word_id,
127 | last_l,
128 | next_l,
129 | NOI: last_NOI,
130 | EF,
131 | next_n: n,
132 | master,
133 | },
134 | OF,
135 | }
136 | }
137 |
138 | // 计算此时与上次复习/学习的时间差(/天)
139 | let now = new Date()
140 | now.setMilliseconds(0)
141 | now.setSeconds(0)
142 | now.setMinutes(0)
143 | now.setHours(0)
144 | let last_i = Math.ceil((now.getTime() - last_l) / 86400000)
145 | // console.log('word', wd_learning_record.word_id, 'last interval', last_i)
146 |
147 | // 更改EF(由于作为键,EF规定为一位小数转换成的字符串)
148 | EF = parseFloat(EF) + (0.1 - (5 - q) * (0.08 + (5 - q) * 0.02))
149 | if (EF < 1.3) EF = 1.3
150 | if (EF > 2.8) EF = 2.8
151 | EF = EF.toFixed(1)
152 |
153 | // 更改矩阵对应项,这里认为若实际间隔时间超过所需间隔时间的1.5倍
154 | // 则视为极大异常值,规整为1.5倍,且不更改矩阵
155 | let used_OF = OF[EF][n - 1]
156 | if (!used_OF) used_OF = 1.2
157 | n++
158 | if (!OF[EF][n - 1]) OF[EF][n - 1] = 1.2
159 | if (last_i <= 1.5 * last_NOI) {
160 | let old_OF = OF[EF][n - 1]
161 | let new_OF = calculateNewOF(last_i, q, used_OF, old_OF)
162 | // console.log('new_OF of', 'OF[', EF, '][', n - 1, ']:', new_OF)
163 | OF[EF][n - 1] = new_OF
164 | } else {
165 | // console.log('last_i', last_i, 'is longer than 1.5 expected interval :', last_NOI)
166 | last_i = Math.round(last_NOI * 1.5)
167 | }
168 |
169 | // 计算最优间隔时长并进行指定分布的随机分散
170 | // 同时计算下次需要复习的时间(1970.1.1至今毫秒数表示)
171 | let NOI
172 | if (q < 2) {
173 | n = 0
174 | NOI = 1
175 | } else if (q < 3) {
176 | n = 1
177 | let interval = OF[EF][0]
178 | NOI = Math.round(interval)
179 | } else {
180 | let interval = n == 1 ? 5 : OF[EF][n - 1] * last_i
181 | // 若下个最优间隔时间大于100天,则将单词标记为已掌握
182 | if (interval > 100) master = true
183 | console.log('next optimal interval', interval)
184 | NOI = Math.round(createNOI(last_i, interval))
185 | if (NOI > 100 && !master) NOI = 100
186 | if (NOI < 0 && !master) NOI = 1
187 | }
188 | last_l = now.getTime()
189 | next_l = last_l + NOI * 86400000
190 |
191 | return {
192 | wd_learning_record: {
193 | word_id: wd_learning_record.word_id,
194 | last_l,
195 | next_l,
196 | NOI,
197 | EF,
198 | next_n: n,
199 | master,
200 | },
201 | OF,
202 | }
203 | }
204 |
205 | module.exports = {
206 | sm_5: sm_5,
207 | }
--------------------------------------------------------------------------------
/images/after_login_index.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/after_login_index.jpg
--------------------------------------------------------------------------------
/images/after_login_overview_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/after_login_overview_1.jpg
--------------------------------------------------------------------------------
/images/after_login_overview_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/after_login_overview_2.jpg
--------------------------------------------------------------------------------
/images/after_login_user.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/after_login_user.jpg
--------------------------------------------------------------------------------
/images/before_login_index.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/before_login_index.jpg
--------------------------------------------------------------------------------
/images/before_login_user.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/before_login_user.jpg
--------------------------------------------------------------------------------
/images/learning_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/learning_1.jpg
--------------------------------------------------------------------------------
/images/learning_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/learning_3.jpg
--------------------------------------------------------------------------------
/images/learning_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/learning_4.jpg
--------------------------------------------------------------------------------
/images/learning_5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/learning_5.jpg
--------------------------------------------------------------------------------
/images/learning_6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/learning_6.jpg
--------------------------------------------------------------------------------
/images/learning_8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/learning_8.jpg
--------------------------------------------------------------------------------
/images/login.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/login.jpg
--------------------------------------------------------------------------------
/images/miniprogram_QRcode.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/miniprogram_QRcode.jpg
--------------------------------------------------------------------------------
/images/search_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/search_1.jpg
--------------------------------------------------------------------------------
/images/search_translation.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/search_translation.jpg
--------------------------------------------------------------------------------
/images/search_word_big.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/search_word_big.jpg
--------------------------------------------------------------------------------
/images/search_word_small.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/search_word_small.jpg
--------------------------------------------------------------------------------
/images/settings.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/settings.jpg
--------------------------------------------------------------------------------
/images/title_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/title_1.png
--------------------------------------------------------------------------------
/images/title_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/title_2.png
--------------------------------------------------------------------------------
/images/title_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/title_3.png
--------------------------------------------------------------------------------
/images/title_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/title_4.png
--------------------------------------------------------------------------------
/images/word_detail.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/word_detail.jpg
--------------------------------------------------------------------------------
/images/word_list.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/word_list.jpg
--------------------------------------------------------------------------------
/images/整体框架图.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/images/整体框架图.png
--------------------------------------------------------------------------------
/miniprogram/app.js:
--------------------------------------------------------------------------------
1 | // app.js
2 | const rescontent = require('./utils/response_content.js')
3 | const { formatTime } = require('./utils/format_time.js')
4 | const userApi = require("./utils/userApi.js")
5 |
6 | App({
7 | onLaunch: function () {
8 | if (!wx.cloud) {
9 | console.error('请使用 2.2.3 或以上的基础库以使用云能力');
10 | } else {
11 | wx.cloud.init({
12 | // env 参数说明:
13 | // env 参数决定接下来小程序发起的云开发调用(wx.cloud.xxx)会默认请求到哪个云环境的资源
14 | // 此处请填入环境 ID, 环境 ID 可打开云控制台查看
15 | // 如不填则使用默认环境(第一个创建的环境)
16 | // env: 'my-env-id',
17 | traceUser: true,
18 | });
19 | }
20 |
21 | this.checkLogin()
22 | wx.disableAlertBeforeUnload()
23 | },
24 |
25 | globalData: {
26 | isLogin: false,
27 | tryingLogin: true,
28 | userInfo: {
29 | // user_id: 2,
30 | // l_book_id: 2,
31 | settings: {
32 | // learn_repeat_t: 3,
33 | // group_size: 10,
34 | // learn_first_m: 'chooseTrans',
35 | // learn_second_m: 'recallTrans',
36 | // learn_third_m: 'recallWord',
37 | // learn_fourth_m: 'recallTrans',
38 | // timing: true,
39 | // timing_duration: 1000,
40 | // autoplay: false,
41 | // type: 1,
42 | // review_repeat_t: 2,
43 | // review_first_m: 'recallTrans',
44 | // review_second_m: 'chooseTrans',
45 | // review_second_m: 'recallWord',
46 | // review_third_m: 'recallTrans',
47 | }
48 | },
49 | updatedForIndex: false,
50 | updatedForOverview: false,
51 | forChangeAvatar: {
52 | change: false,
53 | tempImgSrc: '',
54 | imgSrc: '',
55 | }
56 | },
57 |
58 | checkLogin: async function () {
59 | this.globalData.tryingLogin = true
60 | // let history = wx.getStorageSync('history')
61 | // wx.clearStorageSync()
62 | // wx.setStorageSync('history', history)
63 | // console.log('checkLogin')
64 | // console.log('this.globalData.tryingLogin ', this.globalData.tryingLogin)
65 | let storageContent = wx.getStorageSync('userInfo')
66 | if (storageContent && (new Date().getTime() - storageContent.time) < 86400000 * 2) {
67 | let res = await userApi.getUserInfoViaId({ user_id: storageContent.info.user_id })
68 | if (res.errorcode == rescontent.SUCCESS.errorcode) {
69 | this.globalData.isLogin = true
70 | this.globalData.userInfo = res.data
71 | let lastlogin = formatTime(res.data.last_login)
72 | wx.showToast({
73 | title: `自动登录成功,上次登录时间 ${lastlogin}`,
74 | icon: 'none',
75 | duration: 1500,
76 | })
77 | storageContent.info = res.data
78 | wx.setStorageSync('userInfo', storageContent)
79 | } else {
80 | wx.showToast({
81 | title: '自动登录失败,请重新登录',
82 | icon: 'none',
83 | duration: 1500,
84 | })
85 | wx.removeStorageSync('userInfo')
86 | }
87 | } else if (storageContent) {
88 | wx.showToast({
89 | title: '登录已过期,请重新登录',
90 | icon: 'none',
91 | duration: 1500,
92 | })
93 | wx.removeStorageSync('userInfo')
94 | }
95 | this.globalData.tryingLogin = false
96 | // console.log('this.globalData.tryingLogin ', this.globalData.tryingLogin)
97 | },
98 | });
99 |
--------------------------------------------------------------------------------
/miniprogram/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages": [
3 | "pages/index/index",
4 | "pages/user/user",
5 | "pages/overview/overview",
6 | "pages/login/login",
7 | "pages/search/search",
8 | "pages/word_detail/word_detail",
9 | "pages/learning/learning",
10 | "pages/review/review",
11 | "pages/word_list/word_list",
12 | "pages/image_cropper/image_cropper",
13 | "pages/user_settings/user_settings"
14 | ],
15 | "window": {
16 | "backgroundColor": "#FFFFFF",
17 | "backgroundTextStyle": "light",
18 | "navigationBarBackgroundColor": "#FFFFFF",
19 | "navigationBarTitleText": "学不会单词",
20 | "navigationBarTextStyle": "black"
21 | },
22 | "tabBar": {
23 | "color": "#F0F0F0",
24 | "backgroundColor": "#FFFFFF",
25 | "selectedColor": "#6DAFFE",
26 | "borderStyle": "white",
27 | "position": "bottom",
28 | "list": [
29 | {
30 | "pagePath": "pages/index/index",
31 | "text": " ",
32 | "iconPath": "static/images/tab-learn-CDCDCD.png",
33 | "selectedIconPath": "static/images/tab-learn-A6D6FA.png"
34 | },
35 | {
36 | "pagePath": "pages/overview/overview",
37 | "text": " ",
38 | "iconPath": "static/images/tab-overview-CDCDCD.png",
39 | "selectedIconPath": "static/images/tab-overview-A6D6FA.png"
40 | },
41 | {
42 | "pagePath": "pages/user/user",
43 | "text": " ",
44 | "iconPath": "static/images/tab-user-CDCDCD.png",
45 | "selectedIconPath": "static/images/tab-user-A6D6FA.png"
46 | }
47 | ]
48 | },
49 | "sitemapLocation": "sitemap.json",
50 | "style": "v2",
51 | "lazyCodeLoading": "requiredComponents"
52 | }
--------------------------------------------------------------------------------
/miniprogram/app.wxss:
--------------------------------------------------------------------------------
1 | /**app.wxss**/
2 |
3 | @import './static/iconfont.wxss';
4 | @import './static/color.wxss';
5 |
6 | .container {
7 | display: flex;
8 | flex-direction: column;
9 | align-items: center;
10 | box-sizing: border-box;
11 | }
12 |
13 | button {
14 | background: initial;
15 | }
16 |
17 | button:focus {
18 | outline: 0;
19 | }
20 |
21 | button::after {
22 | border: none;
23 | }
24 |
25 |
26 | page {
27 | background: #f6f6f6;
28 | display: flex;
29 | flex-direction: column;
30 | justify-content: flex-start;
31 | /* overflow: hidden; */
32 | }
--------------------------------------------------------------------------------
/miniprogram/components/cloudTipModal/index.js:
--------------------------------------------------------------------------------
1 | // miniprogram/components/cloudTipModal/index.js
2 | const { isMac } = require('../../envList.js');
3 |
4 | Component({
5 |
6 | /**
7 | * 页面的初始数据
8 | */
9 | data: {
10 | showUploadTip: false,
11 | tipText: isMac ? 'sh ./uploadCloudFunction.sh' : './uploadCloudFunction.bat'
12 | },
13 | properties: {
14 | showUploadTipProps: Boolean
15 | },
16 | observers: {
17 | showUploadTipProps: function(showUploadTipProps) {
18 | this.setData({
19 | showUploadTip: showUploadTipProps
20 | });
21 | }
22 | },
23 | methods: {
24 | onChangeShowUploadTip() {
25 | this.setData({
26 | showUploadTip: !this.data.showUploadTip
27 | });
28 | },
29 |
30 | copyShell() {
31 | wx.setClipboardData({
32 | data: this.data.tipText,
33 | });
34 | },
35 | }
36 |
37 | });
38 |
--------------------------------------------------------------------------------
/miniprogram/components/cloudTipModal/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {},
3 | "component": true
4 | }
--------------------------------------------------------------------------------
/miniprogram/components/cloudTipModal/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 体验前需部署云资源
6 | 请开启调试器进入终端窗口,复制并运行以下命令
7 |
8 | {{tipText}}
9 | 复制
10 |
11 | 已执行命令
12 |
13 |
14 |
--------------------------------------------------------------------------------
/miniprogram/components/cloudTipModal/index.wxss:
--------------------------------------------------------------------------------
1 | .install_tip_back {
2 | position: fixed;
3 | top: 0;
4 | right: 0;
5 | bottom: 0;
6 | left: 0;
7 | background-color: rgba(0,0,0,0.4);
8 | z-index: 1;
9 | }
10 |
11 | .install_tip_detail {
12 | position: fixed;
13 | background-color: white;
14 | right: 0;
15 | bottom: 0;
16 | left: 0;
17 | top: 60%;
18 | border-radius: 40rpx 40rpx 0 0;
19 | padding: 50rpx;
20 | z-index: 9;
21 | }
22 |
23 | .install_tip_detail_title {
24 | font-weight: 400;
25 | font-size: 40rpx;
26 | text-align: center;
27 | }
28 |
29 | .install_tip_detail_tip {
30 | font-size: 25rpx;
31 | color: rgba(0,0,0,0.4);
32 | margin-top: 20rpx;
33 | text-align: center;
34 | }
35 |
36 | .install_tip_detail_shell {
37 | margin: 70rpx 0;
38 | display: flex;
39 | justify-content: center;
40 | }
41 |
42 | .install_tip_detail_copy {
43 | color: #546488;
44 | margin-left: 10rpx;
45 | }
46 |
47 | .install_tip_detail_button {
48 | color: #07C160;
49 | font-weight: 500;
50 | background-color: rgba(0,0,0,0.1);
51 | width: 60%;
52 | text-align: center;
53 | height: 90rpx;
54 | line-height: 90rpx;
55 | border-radius: 10rpx;
56 | margin: 0 auto;
57 | }
--------------------------------------------------------------------------------
/miniprogram/components/ec-canvas/ec-canvas.js:
--------------------------------------------------------------------------------
1 | import WxCanvas from './wx-canvas';
2 | import * as echarts from './echarts';
3 | // import * as echarts from './echartsForBar';
4 |
5 | let ctx;
6 |
7 | function compareVersion(v1, v2) {
8 | v1 = v1.split('.')
9 | v2 = v2.split('.')
10 | const len = Math.max(v1.length, v2.length)
11 |
12 | while (v1.length < len) {
13 | v1.push('0')
14 | }
15 | while (v2.length < len) {
16 | v2.push('0')
17 | }
18 |
19 | for (let i = 0; i < len; i++) {
20 | const num1 = parseInt(v1[i])
21 | const num2 = parseInt(v2[i])
22 |
23 | if (num1 > num2) {
24 | return 1
25 | } else if (num1 < num2) {
26 | return -1
27 | }
28 | }
29 | return 0
30 | }
31 |
32 | Component({
33 | properties: {
34 | canvasId: {
35 | type: String,
36 | value: 'ec-canvas'
37 | },
38 |
39 | ec: {
40 | type: Object
41 | },
42 |
43 | forceUseOldCanvas: {
44 | type: Boolean,
45 | value: false
46 | }
47 | },
48 |
49 | data: {
50 | isUseNewCanvas: false
51 | },
52 |
53 | ready: function () {
54 | // Disable prograssive because drawImage doesn't support DOM as parameter
55 | // See https://developers.weixin.qq.com/miniprogram/dev/api/canvas/CanvasContext.drawImage.html
56 | echarts.registerPreprocessor(option => {
57 | if (option && option.series) {
58 | if (option.series.length > 0) {
59 | option.series.forEach(series => {
60 | series.progressive = 0;
61 | });
62 | }
63 | else if (typeof option.series === 'object') {
64 | option.series.progressive = 0;
65 | }
66 | }
67 | });
68 |
69 | if (!this.data.ec) {
70 | console.warn('组件需绑定 ec 变量,例:');
72 | return;
73 | }
74 |
75 | if (!this.data.ec.lazyLoad) {
76 | this.init();
77 | this.triggerEvent('initok', {isinit: true}, {})
78 | }
79 | },
80 |
81 | methods: {
82 | init: function (callback) {
83 | const version = wx.getSystemInfoSync().SDKVersion
84 |
85 | const canUseNewCanvas = compareVersion(version, '2.9.0') >= 0;
86 | const forceUseOldCanvas = this.data.forceUseOldCanvas;
87 | const isUseNewCanvas = canUseNewCanvas && !forceUseOldCanvas;
88 | this.setData({ isUseNewCanvas });
89 |
90 | if (forceUseOldCanvas && canUseNewCanvas) {
91 | console.warn('开发者强制使用旧canvas,建议关闭');
92 | }
93 |
94 | if (isUseNewCanvas) {
95 | // console.log('微信基础库版本大于2.9.0,开始使用');
96 | // 2.9.0 可以使用
97 | this.initByNewWay(callback);
98 | } else {
99 | const isValid = compareVersion(version, '1.9.91') >= 0
100 | if (!isValid) {
101 | console.error('微信基础库版本过低,需大于等于 1.9.91。'
102 | + '参见:https://github.com/ecomfe/echarts-for-weixin'
103 | + '#%E5%BE%AE%E4%BF%A1%E7%89%88%E6%9C%AC%E8%A6%81%E6%B1%82');
104 | return;
105 | } else {
106 | console.warn('建议将微信基础库调整大于等于2.9.0版本。升级后绘图将有更好性能');
107 | this.initByOldWay(callback);
108 | }
109 | }
110 | },
111 |
112 | initByOldWay(callback) {
113 | // 1.9.91 <= version < 2.9.0:原来的方式初始化
114 | ctx = wx.createCanvasContext(this.data.canvasId, this);
115 | const canvas = new WxCanvas(ctx, this.data.canvasId, false);
116 |
117 | echarts.setCanvasCreator(() => {
118 | return canvas;
119 | });
120 | // const canvasDpr = wx.getSystemInfoSync().pixelRatio // 微信旧的canvas不能传入dpr
121 | const canvasDpr = 1
122 | var query = wx.createSelectorQuery().in(this);
123 | query.select('.ec-canvas').boundingClientRect(res => {
124 | if (typeof callback === 'function') {
125 | this.chart = callback(canvas, res.width, res.height, canvasDpr);
126 | }
127 | else if (this.data.ec && typeof this.data.ec.onInit === 'function') {
128 | this.chart = this.data.ec.onInit(canvas, res.width, res.height, canvasDpr);
129 | }
130 | else {
131 | this.triggerEvent('init', {
132 | canvas: canvas,
133 | width: res.width,
134 | height: res.height,
135 | canvasDpr: canvasDpr // 增加了dpr,可方便外面echarts.init
136 | });
137 | }
138 | }).exec();
139 | },
140 |
141 | initByNewWay(callback) {
142 | // version >= 2.9.0:使用新的方式初始化
143 | const query = wx.createSelectorQuery().in(this)
144 | query
145 | .select('.ec-canvas')
146 | .fields({ node: true, size: true })
147 | .exec(res => {
148 | const canvasNode = res[0].node
149 | this.canvasNode = canvasNode
150 |
151 | const canvasDpr = wx.getSystemInfoSync().pixelRatio
152 | const canvasWidth = res[0].width
153 | const canvasHeight = res[0].height
154 |
155 | const ctx = canvasNode.getContext('2d')
156 |
157 | const canvas = new WxCanvas(ctx, this.data.canvasId, true, canvasNode)
158 | echarts.setCanvasCreator(() => {
159 | return canvas
160 | })
161 |
162 | if (typeof callback === 'function') {
163 | this.chart = callback(canvas, canvasWidth, canvasHeight, canvasDpr)
164 | } else if (this.data.ec && typeof this.data.ec.onInit === 'function') {
165 | this.chart = this.data.ec.onInit(canvas, canvasWidth, canvasHeight, canvasDpr)
166 | } else {
167 | this.triggerEvent('init', {
168 | canvas: canvas,
169 | width: canvasWidth,
170 | height: canvasHeight,
171 | dpr: canvasDpr
172 | })
173 | }
174 | })
175 | },
176 | canvasToTempFilePath(opt) {
177 | if (this.data.isUseNewCanvas) {
178 | // 新版
179 | const query = wx.createSelectorQuery().in(this)
180 | query
181 | .select('.ec-canvas')
182 | .fields({ node: true, size: true })
183 | .exec(res => {
184 | const canvasNode = res[0].node
185 | opt.canvas = canvasNode
186 | wx.canvasToTempFilePath(opt)
187 | })
188 | } else {
189 | // 旧的
190 | if (!opt.canvasId) {
191 | opt.canvasId = this.data.canvasId;
192 | }
193 | ctx.draw(true, () => {
194 | wx.canvasToTempFilePath(opt, this);
195 | });
196 | }
197 | },
198 |
199 | touchStart(e) {
200 | if (this.chart && e.touches.length > 0) {
201 | var touch = e.touches[0];
202 | var handler = this.chart.getZr().handler;
203 | handler.dispatch('mousedown', {
204 | zrX: touch.x,
205 | zrY: touch.y
206 | });
207 | handler.dispatch('mousemove', {
208 | zrX: touch.x,
209 | zrY: touch.y
210 | });
211 | handler.processGesture(wrapTouch(e), 'start');
212 | }
213 | },
214 |
215 | touchMove(e) {
216 | if (this.chart && e.touches.length > 0) {
217 | var touch = e.touches[0];
218 | var handler = this.chart.getZr().handler;
219 | handler.dispatch('mousemove', {
220 | zrX: touch.x,
221 | zrY: touch.y
222 | });
223 | handler.processGesture(wrapTouch(e), 'change');
224 | }
225 | },
226 |
227 | touchEnd(e) {
228 | if (this.chart) {
229 | const touch = e.changedTouches ? e.changedTouches[0] : {};
230 | var handler = this.chart.getZr().handler;
231 | handler.dispatch('mouseup', {
232 | zrX: touch.x,
233 | zrY: touch.y
234 | });
235 | handler.dispatch('click', {
236 | zrX: touch.x,
237 | zrY: touch.y
238 | });
239 | handler.processGesture(wrapTouch(e), 'end');
240 | }
241 | }
242 | }
243 | });
244 |
245 | function wrapTouch(event) {
246 | for (let i = 0; i < event.touches.length; ++i) {
247 | const touch = event.touches[i];
248 | touch.offsetX = touch.x;
249 | touch.offsetY = touch.y;
250 | }
251 | return event;
252 | }
253 |
--------------------------------------------------------------------------------
/miniprogram/components/ec-canvas/ec-canvas.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {}
4 | }
--------------------------------------------------------------------------------
/miniprogram/components/ec-canvas/ec-canvas.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/miniprogram/components/ec-canvas/ec-canvas.wxss:
--------------------------------------------------------------------------------
1 | .ec-canvas {
2 | width: 100%;
3 | height: 100%;
4 | }
5 |
--------------------------------------------------------------------------------
/miniprogram/components/ec-canvas/wx-canvas.js:
--------------------------------------------------------------------------------
1 | export default class WxCanvas {
2 | constructor(ctx, canvasId, isNew, canvasNode) {
3 | this.ctx = ctx;
4 | this.canvasId = canvasId;
5 | this.chart = null;
6 | this.isNew = isNew
7 | if (isNew) {
8 | this.canvasNode = canvasNode;
9 | }
10 | else {
11 | this._initStyle(ctx);
12 | }
13 |
14 | // this._initCanvas(zrender, ctx);
15 |
16 | this._initEvent();
17 | }
18 |
19 | getContext(contextType) {
20 | if (contextType === '2d') {
21 | return this.ctx;
22 | }
23 | }
24 |
25 | // canvasToTempFilePath(opt) {
26 | // if (!opt.canvasId) {
27 | // opt.canvasId = this.canvasId;
28 | // }
29 | // return wx.canvasToTempFilePath(opt, this);
30 | // }
31 |
32 | setChart(chart) {
33 | this.chart = chart;
34 | }
35 |
36 | attachEvent() {
37 | // noop
38 | }
39 |
40 | detachEvent() {
41 | // noop
42 | }
43 |
44 | _initCanvas(zrender, ctx) {
45 | zrender.util.getContext = function () {
46 | return ctx;
47 | };
48 |
49 | zrender.util.$override('measureText', function (text, font) {
50 | ctx.font = font || '12px sans-serif';
51 | return ctx.measureText(text);
52 | });
53 | }
54 |
55 | _initStyle(ctx) {
56 | ctx.createRadialGradient = () => {
57 | return ctx.createCircularGradient(arguments);
58 | };
59 | }
60 |
61 | _initEvent() {
62 | this.event = {};
63 | const eventNames = [{
64 | wxName: 'touchStart',
65 | ecName: 'mousedown'
66 | }, {
67 | wxName: 'touchMove',
68 | ecName: 'mousemove'
69 | }, {
70 | wxName: 'touchEnd',
71 | ecName: 'mouseup'
72 | }, {
73 | wxName: 'touchEnd',
74 | ecName: 'click'
75 | }];
76 |
77 | eventNames.forEach(name => {
78 | this.event[name.wxName] = e => {
79 | const touch = e.touches[0];
80 | this.chart.getZr().handler.dispatch(name.ecName, {
81 | zrX: name.wxName === 'tap' ? touch.clientX : touch.x,
82 | zrY: name.wxName === 'tap' ? touch.clientY : touch.y
83 | });
84 | };
85 | });
86 | }
87 |
88 | set width(w) {
89 | if (this.canvasNode) this.canvasNode.width = w
90 | }
91 | set height(h) {
92 | if (this.canvasNode) this.canvasNode.height = h
93 | }
94 |
95 | get width() {
96 | if (this.canvasNode)
97 | return this.canvasNode.width
98 | return 0
99 | }
100 | get height() {
101 | if (this.canvasNode)
102 | return this.canvasNode.height
103 | return 0
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/miniprogram/components/image-cropper/image-cropper.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true
3 | }
--------------------------------------------------------------------------------
/miniprogram/components/image-cropper/image-cropper.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 |
--------------------------------------------------------------------------------
/miniprogram/components/image-cropper/image-cropper.wxss:
--------------------------------------------------------------------------------
1 | .image-cropper {
2 | background: rgba(14, 13, 13, .8);
3 | position: fixed;
4 | top: 0;
5 | left: 0;
6 | width: 100vw;
7 | height: 100vh;
8 | z-index: 1;
9 | }
10 |
11 | .image-cropper .main {
12 | position: absolute;
13 | width: 100vw;
14 | height: 100vh;
15 | overflow: hidden;
16 | }
17 |
18 | .image-cropper .content {
19 | z-index: 9;
20 | position: absolute;
21 | width: 100vw;
22 | height: 100vh;
23 | display: flex;
24 | flex-direction: column;
25 | pointer-events: none;
26 | }
27 |
28 | .image-cropper .bg_black {
29 | background: rgba(0, 0, 0, 0.8) !important;
30 | }
31 |
32 | .image-cropper .bg_gray {
33 | background: rgba(0, 0, 0, 0.45);
34 | transition-duration: .35s;
35 | }
36 |
37 | .image-cropper .content>.content_top {
38 | pointer-events: none;
39 | }
40 |
41 | .image-cropper .content>.content_middle {
42 | display: flex;
43 | height: 200px;
44 | width: 100%;
45 | }
46 |
47 | .image-cropper .content_middle_middle {
48 | width: 200px;
49 | box-sizing: border-box;
50 | position: relative;
51 | transition-duration: .3s;
52 | }
53 |
54 | .image-cropper .content_middle_right {
55 | flex: auto;
56 | }
57 |
58 | .image-cropper .content>.content_bottom {
59 | flex: auto;
60 | }
61 |
62 | .image-cropper .img {
63 | z-index: 2;
64 | top: 0;
65 | left: 0;
66 | position: absolute;
67 | border: none;
68 | width: 100%;
69 | backface-visibility: hidden;
70 | transform-origin: center;
71 | }
72 |
73 | .image-cropper .image-cropper-canvas {
74 | position: fixed;
75 | background: white;
76 | width: 150px;
77 | height: 150px;
78 | z-index: 10;
79 | top: -200%;
80 | pointer-events: none;
81 | }
82 |
83 | .image-cropper .border {
84 | background: white;
85 | pointer-events: auto;
86 | position: absolute;
87 | }
88 |
89 | .image-cropper .border-top-left {
90 | left: -2.5px;
91 | top: -2.5px;
92 | height: 2.5px;
93 | width: 33rpx;
94 | }
95 |
96 | .image-cropper .border-top-right {
97 | right: -2.5px;
98 | top: -2.5px;
99 | height: 2.5px;
100 | width: 33rpx;
101 | }
102 |
103 | .image-cropper .border-right-top {
104 | top: -1px;
105 | width: 2.5px;
106 | height: 30rpx;
107 | right: -2.5px;
108 | }
109 |
110 | .image-cropper .border-right-bottom {
111 | width: 2.5px;
112 | height: 30rpx;
113 | right: -2.5px;
114 | bottom: -1px;
115 | }
116 |
117 | .image-cropper .border-bottom-left {
118 | height: 2.5px;
119 | width: 33rpx;
120 | bottom: -2.5px;
121 | left: -2.5px;
122 | }
123 |
124 | .image-cropper .border-bottom-right {
125 | height: 2.5px;
126 | width: 33rpx;
127 | bottom: -2.5px;
128 | right: -2.5px;
129 | }
130 |
131 | .image-cropper .border-left-top {
132 | top: -1px;
133 | width: 2.5px;
134 | height: 30rpx;
135 | left: -2.5px;
136 | }
137 |
138 | .image-cropper .border-left-bottom {
139 | width: 2.5px;
140 | height: 30rpx;
141 | left: -2.5px;
142 | bottom: -1px;
143 | }
--------------------------------------------------------------------------------
/miniprogram/components/mp-progress/mp-progress.js:
--------------------------------------------------------------------------------
1 | // import MpProgress from "../progress.min.js";
2 | import MpProgress from "./progress.js";
3 |
4 | Component({
5 | options: {
6 | addGlobalClass: true,
7 | },
8 | properties: {
9 | config: {
10 | type: Object,
11 | value: {}
12 | },
13 | percentage: {
14 | type: Number,
15 | value: 0
16 | },
17 | reset: {
18 | type: Boolean,
19 | value: false
20 | },
21 | isStop: {
22 | type: Boolean,
23 | value: false
24 | }
25 | },
26 | data: {
27 | customOptions: {
28 | // canvasSize: {
29 | // width: 100,
30 | // height: 100
31 | // },
32 | percent: 100
33 | },
34 | percentage: 100,
35 | canvasId: `mp_progress_${new Date().getTime()}`
36 | },
37 | attached() {
38 | // const customOptions = Object.assign({}, this.data.customOptions, this.data.config);
39 | // this.setData({
40 | // customOptions,
41 | // });
42 | // let canvasId = `mp_progress_${new Date().getTime()}`;
43 | // this.setData({
44 | // canvasId,
45 | // });
46 | },
47 | ready() {
48 | // this._mpprogress = new MpProgress(Object.assign({}, this.data.customOptions, { canvasId: this.data.canvasId, target: this }));
49 | // this._mpprogress.draw(this.data.percentage || 0);
50 | },
51 | observers: {
52 | 'config': function (config) {
53 | // console.log('Get Config')
54 | if (JSON.stringify(config) == "{}") return;
55 | // console.log("go init");
56 | // const customOptions = Object.assign({}, this.data.customOptions, this.data.config);
57 | const customOptions = config;
58 | // let canvasId = `mp_progress_${new Date().getTime()}`;
59 | this.setData({
60 | customOptions,
61 | // canvasId,
62 | });
63 | let options = JSON.parse(JSON.stringify(this.data.customOptions));
64 | options.canvasId = this.data.canvasId;
65 | options.target = this;
66 | this._mpprogress = new MpProgress(options);
67 | // this._mpprogress = new MpProgress(Object.assign({}, this.data.customOptions, { canvasId: this.data.canvasId, target: this }));
68 | this._mpprogress.draw(this.data.percentage || 0);
69 | },
70 | 'reset': function (reset) {
71 | if (reset) {
72 | if (this._mpprogress) {
73 | this._mpprogress.stopAnimation(true);
74 | }
75 | // let canvasId = `mp_progress_${new Date().getTime()}`;
76 | // this.setData({
77 | // canvasId,
78 | // });
79 | let options = JSON.parse(JSON.stringify(this.data.customOptions));
80 | options.canvasId = this.data.canvasId;
81 | options.target = this;
82 | this._mpprogress = new MpProgress(options);
83 | // this._mpprogress = new MpProgress(Object.assign({}, this.data.customOptions, { canvasId: this.data.canvasId, target: this }));
84 | // delete this._mpprogress
85 | this._mpprogress.draw(this.data.percentage || 0);
86 | }
87 | },
88 | 'isStop': function (isStop) {
89 | if (isStop && this._mpprogress) { this._mpprogress.stopAnimation(isStop); }
90 | // this._mpprogress.stopAnimation();
91 | },
92 | // 'percentage': function (percentage) {
93 | // if (this._mpprogress) {
94 | // // 第一次进来的时候还没有初始化完成
95 | // this._mpprogress.draw(percentage);
96 | // }
97 | // },
98 | }
99 | });
100 |
--------------------------------------------------------------------------------
/miniprogram/components/mp-progress/mp-progress.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {}
4 | }
--------------------------------------------------------------------------------
/miniprogram/components/mp-progress/mp-progress.wxml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/miniprogram/components/mp-progress/progress.min.js:
--------------------------------------------------------------------------------
1 | /*! mp-progress.js v1.2.13 https://www.npmjs.com/package/mp-progress */
2 | var t,e;t=window,e=function(){return i={},o.m=n=[function(t,e,n){"use strict";function i(e,t){var n,i=Object.keys(e);return Object.getOwnPropertySymbols&&(n=Object.getOwnPropertySymbols(e),t&&(n=n.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),i.push.apply(i,n)),i}function o(o){for(var t=1;t100]: 已自动调整为100")),this._options.percentage=+t||0,this._context)this.drawFn();else try{var n=this._options.target,i=wx.createSelectorQuery().in(n);n.$wx&&n.$wx.$wepy&&(i=wx.createSelectorQuery()),i.select("#".concat(this._options.canvasId)).node(function(t){var e=t.node;o._requestAnimationFrame=e.requestAnimationFrame.bind(e);var n=e.getContext("2d"),i=wx.getSystemInfoSync().pixelRatio;e.width=e._width*i,e.height=e._height*i,n.scale(i,i),o._context=n,o.drawFn()}).exec()}catch(t){console.warn(t)}else console.warn("[绘图过程出现错误]: 调用draw方法必须传入百分比参数")}},{key:"drawFn",value:function(){var n=this;try{var t=this._options.barStyle;if(0 ∫[0, m]d( a*exp(-b*x) / (-b) )=|p| => m=-1/b*ln(1-b/a*|p|))
18 | //
19 | // const createNOI = (PI, OI) => {
20 | // let a = 0.047
21 | // let b = 0.092
22 | // let randNum = Math.random()
23 | // let p = randNum - 0.5
24 | // console.log('random p', p)
25 | // let m = -1 / b * (Math.log((1 - b / a * Math.abs(p))))
26 | // m = m * Math.sign(p)
27 | // console.log('random m', m)
28 | // let NOI = PI + (OI - PI) * (1 + m)
29 | // NOI = Math.round(NOI)
30 | // return NOI
31 | // }
32 | // -------------------------------------------------------------
33 | // 由于作者给出的参数带入是有误的,采用类正态分布实现分布函数
34 | // 原型(标准正态分布):f(x) = 1/(√(2π)*Ω) * e(-x^2/(2Ω^2))
35 | // 简化:f(x) = a*e(-b*x^2)
36 | // f(0) = 100*f(0.5) 可求得 b = -18.420680743952367
37 | // ∫[0, 0.5]f(x)dx = 0.5 可求得 a = 2.4273047133848933
38 | // 积分计算器网址: https://zh.numberempire.com/definiteintegralcalculator.php
39 | // 画函数图像网址:https://www.desmos.com/calculator?lang=zh-CN
40 | // 这里使用能解正态分布分位数的库进行运算
41 | // f(0) = 100*f(0.5) 按正态分布算,可求得 std=0.1647525572455652
42 | // X ~ N(0,0.1647525572455652) 从0~0.5的累计分布值为0.4987967402705885
43 | // 故若要满足∫[0, 0.5]f(x)dx = 0.5,要在前面再乘上
44 | // JStat库的jStat.normal.inv( p, mean, std )可以求出N(mean,std)分布从负无穷开始累计分布为p的分位点
45 | // 因此思路转变为,首先随机获取[0, 1)的数r, r-0.5得到[-0.5, 0.5)的数m,(m*0.4987967402705885/0.5+0.5)得到累计值
46 | // 即jStat.normal.inv(abs(m*0.4987967402705885/0.5)+0.5, 0, 0.1647525572455652) 可得到分位点
47 |
48 | const jStat = require("./jstat.min.js")
49 | const createNOI = (PI, OI) => {
50 | let mean = 0
51 | let std = 0.1647525572455652
52 | let randNum = Math.random()
53 | // console.log('randNum', randNum)
54 | let p = Math.abs((randNum - 0.5) * 0.4987967402705885 / 0.5) + 0.5
55 | // console.log('random p', p)
56 | let inv_cdf = jStat.normal.inv(p, mean, std)
57 | let m = inv_cdf * Math.sign(randNum - 0.5)
58 | // console.log('random m', m)
59 | let NOI = PI + (OI - PI) * (1 + m)
60 | NOI = Math.round(NOI)
61 | return NOI
62 | }
63 |
64 |
65 | // 符号函数
66 | const sgn = (num) => {
67 | if (num < 0) {
68 | return -1
69 | } else if (num == 0) {
70 | return 0
71 | } else {
72 | return 1
73 | }
74 | }
75 |
76 | // 计算新的OF矩阵对应项
77 | // 输入:
78 | // last_i - 用于相关项目的最后(上一个)间隔(原文描述为the last interval used for the item in question)
79 | // q - 重复响应的质量
80 | // used_OF - 用于计算相关项目的最后一个间隔时使用的最佳因子
81 | // old_OF - 与项目的相关重复次数和电子因子相对应的 OF 条目的前一个值
82 | // fraction - 属于确定修改速率的范围 (0,1) 的数字 (OF矩阵的变化越快)
83 | // 输出:
84 | // new_OF - 考虑的 OF 矩阵条目的新计算值
85 | // 局部变量:
86 | // modifier - 确定 OF 值将增加或减少多少次的数字
87 | // mod5 - 在 q=5 的情况下为修饰符建议的值
88 | // mod2 - 在 q=2 的情况下为修饰符建议的值
89 | const calculateNewOF = (last_i, q, used_OF, old_OF, fraction = 0.8) => {
90 | let modifier
91 | let mod5 = (last_i + 1) / last_i
92 | if (mod5 < 1.05) mod5 = 1.05
93 | let mod2 = (last_i - 1) / last_i
94 | if (mod2 > 0.75) mod2 = 0.75
95 | if (q > 4) {
96 | modifier = 1 + (mod5 - 1) * (q - 4)
97 | } else {
98 | modifier = 1 - (1 - mod2) / 2 * (4 - q)
99 | }
100 | if (modifier < 0.05) modifier = 0.05
101 | let new_OF = used_OF * modifier
102 | if (q > 4) if (new_OF < old_OF) new_OF = old_OF
103 | if (q < 4) if (new_OF > old_OF) new_OF = old_OF
104 | new_OF = new_OF * fraction + old_OF * (1 - fraction)
105 | if (new_OF < 1.2) new_OF = 1.2
106 | new_OF = new_OF.toFixed(4)
107 | new_OF = parseFloat(new_OF)
108 | return new_OF
109 | }
110 |
111 | // 单词记录提供数据:循环次数,上次的EF,上次的间隔时间(/天), q(quality,回忆质量)
112 | // 其他:OF矩阵
113 | const sm_5 = (OF, wd_learning_record) => {
114 | let EF = wd_learning_record.EF
115 | let q = wd_learning_record.q
116 | let last_NOI = wd_learning_record.NOI
117 | let n = wd_learning_record.next_n
118 | let last_l = wd_learning_record.last_l
119 | let next_l = wd_learning_record.next_l
120 | let master = wd_learning_record.master
121 |
122 | if (master) {
123 | return {
124 | wd_learning_record: {
125 | word_id: wd_learning_record.word_id,
126 | last_l,
127 | next_l,
128 | NOI: last_NOI,
129 | EF,
130 | next_n: n,
131 | master,
132 | },
133 | OF,
134 | }
135 | }
136 |
137 | // 计算此时与上次复习/学习的时间差(/天)
138 | let now = new Date()
139 | now.setMilliseconds(0)
140 | now.setSeconds(0)
141 | now.setMinutes(0)
142 | now.setHours(0)
143 | let last_i = Math.ceil((now.getTime() - last_l) / 86400000)
144 | // console.log('word', wd_learning_record.word_id, 'last interval', last_i)
145 |
146 | // 更改EF(由于作为键,EF规定为一位小数转换成的字符串)
147 | EF = parseFloat(EF) + (0.1 - (5 - q) * (0.08 + (5 - q) * 0.02))
148 | if (EF < 1.3) EF = 1.3
149 | if (EF > 2.8) EF = 2.8
150 | EF = EF.toFixed(1)
151 |
152 | // 更改矩阵对应项,这里认为若实际间隔时间超过所需间隔时间的1.5倍
153 | // 则视为极大异常值,规整为1.5倍,且不更改矩阵
154 | let used_OF = OF[EF][n - 1]
155 | if (!used_OF) used_OF = 1.2
156 | n++
157 | if (!OF[EF][n - 1]) OF[EF][n - 1] = 1.2
158 | if (last_i <= 1.5 * last_NOI) {
159 | let old_OF = OF[EF][n - 1]
160 | let new_OF = calculateNewOF(last_i, q, used_OF, old_OF)
161 | // console.log('new_OF of', 'OF[', EF, '][', n - 1, ']:', new_OF)
162 | OF[EF][n - 1] = new_OF
163 | } else {
164 | // console.log('last_i', last_i, 'is longer than 1.5 expected interval :', last_NOI)
165 | last_i = Math.round(last_NOI * 1.5)
166 | }
167 |
168 | // 计算最优间隔时长并进行指定分布的随机分散
169 | // 同时计算下次需要复习的时间(1970.1.1至今毫秒数表示)
170 | let NOI
171 | if (q < 2) {
172 | n = 0
173 | NOI = 1
174 | } else if (q < 3) {
175 | n = 1
176 | let interval = OF[EF][0]
177 | NOI = Math.round(interval)
178 | } else {
179 | let interval = n == 1 ? 5 : OF[EF][n - 1] * last_i
180 | // 若下个最优间隔时间大于100天,则将单词标记为已掌握
181 | if (interval > 100) master = true
182 | console.log('next optimal interval', interval)
183 | NOI = Math.round(createNOI(last_i, interval))
184 | if (NOI > 100 && !master) NOI = 100
185 | if (NOI < 0 && !master) NOI = 1
186 | }
187 | last_l = now.getTime()
188 | next_l = last_l + NOI * 86400000
189 |
190 | return {
191 | wd_learning_record: {
192 | word_id: wd_learning_record.word_id,
193 | last_l,
194 | next_l,
195 | NOI,
196 | EF,
197 | next_n: n,
198 | master,
199 | },
200 | OF,
201 | }
202 | }
203 |
204 | module.exports = {
205 | sm_5: sm_5,
206 | }
--------------------------------------------------------------------------------
/miniprogram/pages/image_cropper/image_cropper.js:
--------------------------------------------------------------------------------
1 | //获取应用实例
2 | const app = getApp()
3 | import regeneratorRuntime, { async } from '../../lib/runtime/runtime';
4 | const userApi = require("../../utils/userApi.js")
5 |
6 | Page({
7 | data: {
8 | src: '',
9 | width: 250, //宽度
10 | height: 250, //高度
11 | max_width: 300,
12 | max_height: 300,
13 | },
14 | cropper: undefined,
15 |
16 | onLoad: function (options) {
17 | this.cropper = this.selectComponent("#image-cropper")
18 | this.setData({
19 | src: app.globalData.forChangeAvatar.tempImgSrc
20 | })
21 | },
22 |
23 | cropperload(e) {
24 | console.log('cropper加载完成')
25 | },
26 |
27 | loadimage(e) {
28 | wx.hideLoading()
29 | console.log('图片')
30 | this.cropper.imgReset()
31 | },
32 |
33 | clickcut(e) {
34 | console.log(e.detail)
35 | //图片预览
36 | wx.previewImage({
37 | current: e.detail.url, // 当前显示图片的http链接
38 | urls: [e.detail.url] // 需要预览的图片http链接列表
39 | })
40 | },
41 |
42 | chooseImage() {
43 | let that = this;
44 | wx.chooseImage({
45 | count: 1,
46 | sizeType: ['compressed'],
47 | sourceType: ['album', 'camera'],
48 | success(res) {
49 | wx.showLoading({
50 | title: '加载中',
51 | })
52 | const tempFilePaths = res.tempFilePaths[0]
53 | app.globalData.forChangeAvatar.tempImgSrc = tempFilePaths
54 | //重置图片角度、缩放、位置
55 | that.cropper.imgReset()
56 | that.setData({
57 | src: tempFilePaths
58 | })
59 | }
60 | })
61 | },
62 |
63 | submit() {
64 | this.cropper.getImg(this.uploadAndModify)
65 | },
66 |
67 | async uploadAndModify(obj) {
68 | wx.showLoading({
69 | title: '头像上传中...',
70 | mask: true,
71 | })
72 | let res1 = await userApi.uploadFile(obj.url)
73 | let file = res1.fileID
74 | if (!file) {
75 | wx.hideLoading()
76 | wx.showToast({
77 | title: '更改失败,请重试',
78 | icon: 'none',
79 | duration: 1500,
80 | })
81 | return
82 | }
83 | console.log('file', file)
84 | this.changeAvatar(file)
85 | },
86 |
87 | async uploadAndModify1(obj) {
88 | console.log(obj)
89 | let fileExtName = /\.\w+$/.exec(obj.url)[0] //获取文件格式(后缀名)
90 | let _this = this
91 | wx.cloud.uploadFile({
92 | cloudPath: 'avatar_pic/' + Date.now() + '-' + Math.floor(Math.random() * 10000) + fileExtName, //生成添加时间戳后的随机序列作为文件名
93 | filePath: obj.url,
94 | success: res1 => {
95 | let file = res1.fileID
96 | console.log('file', file)
97 | _this.changeAvatar(file)
98 | },
99 | fail: err => {
100 | console.log(err)
101 | wx.showToast({
102 | title: '更改失败,请重试',
103 | icon: 'none',
104 | duration: 1500,
105 | })
106 | }
107 | })
108 | },
109 |
110 | async changeAvatar(file) {
111 | let data = {
112 | user_id: app.globalData.userInfo.user_id,
113 | }
114 | if (app.globalData.userInfo.wx_user == true && app.globalData.userInfo.settings.auto_update_avatar == true) {
115 | data.type = ['avatar_pic', 'settings']
116 | data.value = [file, { auto_update_avatar: false }]
117 | } else {
118 | data.type = 'avatar_pic'
119 | data.value = file
120 | }
121 |
122 | let res2 = await userApi.changeUserInfo(data)
123 | console.log(res2)
124 | wx.hideLoading()
125 | if (res2.data == true) {
126 | app.globalData.userInfo.avatar_pic = file
127 | app.globalData.forChangeAvatar.change = true
128 | app.globalData.forChangeAvatar.imgSrc = file
129 | if (app.globalData.userInfo.wx_user == true && app.globalData.userInfo.settings.auto_update_avatar == true) {
130 | app.globalData.userInfo.settings.auto_update_avatar = false
131 | }
132 | wx.navigateBack({
133 | delta: -1
134 | })
135 | } else {
136 | wx.showToast({
137 | title: '更改失败,请重试',
138 | icon: 'none',
139 | duration: 1500,
140 | })
141 | }
142 | },
143 |
144 | rotate() {
145 | //在用户旋转的基础上旋转90°
146 | this.cropper.setAngle(this.cropper.data.angle += 90)
147 | },
148 |
149 | setWidth(e) {
150 | this.setData({
151 | width: e.detail.value < 10 ? 10 : e.detail.value
152 | })
153 | this.setData({
154 | cut_left: this.cropper.data.cut_left
155 | })
156 | },
157 |
158 | setHeight(e) {
159 | this.setData({
160 | height: e.detail.value < 10 ? 10 : e.detail.value
161 | })
162 | this.setData({
163 | cut_top: this.cropper.data.cut_top
164 | })
165 | },
166 |
167 | setCutTop(e) {
168 | this.setData({
169 | cut_top: e.detail.value
170 | })
171 | this.setData({
172 | cut_top: this.cropper.data.cut_top
173 | })
174 | },
175 |
176 | setCutLeft(e) {
177 | this.setData({
178 | cut_left: e.detail.value
179 | })
180 | this.setData({
181 | cut_left: this.cropper.data.cut_left
182 | })
183 | },
184 | })
--------------------------------------------------------------------------------
/miniprogram/pages/image_cropper/image_cropper.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "裁切头像",
3 | "disableScroll": true,
4 | "navigationBarBackgroundColor": "#292929",
5 | "navigationBarTextStyle": "white",
6 | "backgroundColor": "#292929",
7 | "usingComponents": {
8 | "image-cropper": "../../components/image-cropper/image-cropper"
9 | }
10 | }
--------------------------------------------------------------------------------
/miniprogram/pages/image_cropper/image_cropper.less:
--------------------------------------------------------------------------------
1 | /* pages/image_cropper/image_cropper.wxss */
2 | // .top {
3 | // position: absolute;
4 | // width: 100%;
5 | // top: 10rpx;
6 | // display: flex;
7 | // flex-flow: wrap;
8 | // z-index: 10;
9 | // color: white;
10 | // justify-content: space-around;
11 | // }
12 |
13 | .hint {
14 | position: absolute;
15 | top: 10rpx;
16 | width: 100%;
17 | font-size: 33rpx;
18 | text-align: center;
19 | color: white;
20 | z-index: 10;
21 | }
22 |
23 | .bottom {
24 | position: absolute;
25 | width: 100%;
26 | height: 100rpx;
27 | bottom: 50rpx;
28 | display: flex;
29 | z-index: 10;
30 | justify-content: space-around;
31 | align-items: center;
32 | flex-wrap: wrap;
33 | font-weight: 600;
34 |
35 | .btnText {
36 | font-size: 32rpx;
37 | color: #ffffff;
38 | width: 200rpx;
39 | height: 80rpx;
40 | line-height: 80rpx;
41 | text-align: center;
42 | }
43 |
44 | .icon-rotate {
45 | font-size: 44rpx;
46 | font-weight: 300;
47 | }
48 |
49 | .button {
50 | font-size: 36rpx;
51 | padding: 0;
52 | margin: 0;
53 | z-index: 2;
54 | width: 200rpx;
55 | height: 80rpx;
56 | text-align: center;
57 | line-height: 80rpx;
58 | // color: white;
59 | // background-color: #757575;
60 | }
61 | }
--------------------------------------------------------------------------------
/miniprogram/pages/image_cropper/image_cropper.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 | 点击中间裁剪框可查看裁剪后的图片
10 |
11 | 更换
12 |
13 |
14 |
--------------------------------------------------------------------------------
/miniprogram/pages/image_cropper/image_cropper.wxss:
--------------------------------------------------------------------------------
1 | /* pages/image_cropper/image_cropper.wxss */
2 | .hint {
3 | position: absolute;
4 | top: 10rpx;
5 | width: 100%;
6 | font-size: 33rpx;
7 | text-align: center;
8 | color: white;
9 | z-index: 10;
10 | }
11 | .bottom {
12 | position: absolute;
13 | width: 100%;
14 | height: 100rpx;
15 | bottom: 50rpx;
16 | display: flex;
17 | z-index: 10;
18 | justify-content: space-around;
19 | align-items: center;
20 | flex-wrap: wrap;
21 | font-weight: 600;
22 | }
23 | .bottom .btnText {
24 | font-size: 32rpx;
25 | color: #ffffff;
26 | width: 200rpx;
27 | height: 80rpx;
28 | line-height: 80rpx;
29 | text-align: center;
30 | }
31 | .bottom .icon-rotate {
32 | font-size: 44rpx;
33 | font-weight: 300;
34 | }
35 | .bottom .button {
36 | font-size: 36rpx;
37 | padding: 0;
38 | margin: 0;
39 | z-index: 2;
40 | width: 200rpx;
41 | height: 80rpx;
42 | text-align: center;
43 | line-height: 80rpx;
44 | }
45 |
--------------------------------------------------------------------------------
/miniprogram/pages/index/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {}
3 | }
--------------------------------------------------------------------------------
/miniprogram/pages/index/index.less:
--------------------------------------------------------------------------------
1 | .bgWrapper {
2 | width: 100%;
3 | height: 100%;
4 | position: absolute;
5 | z-index: -100;
6 | background-image: linear-gradient(to bottom, #86e3ce, #FFFFFF);
7 |
8 | // -webkit-filter: blur(10px);
9 | // filter: blur(10px);
10 | .bg {
11 | margin-left: -15%;
12 | margin-top: -15%;
13 | width: 130%;
14 | height: 130%;
15 | }
16 | }
17 |
18 | .wrapper {
19 | width: 100%;
20 | height: 100%;
21 | position: absolute;
22 | z-index: -1;
23 | }
24 |
25 | .searchBtn {
26 | position: absolute;
27 | top: 35rpx;
28 | right: 45rpx;
29 | height: 60rpx;
30 | width: 60rpx;
31 | border-radius: 34rpx;
32 | // background-color: #f6f6f6;
33 | // border: solid 3rpx rgba(250, 153, 93, 0.2);
34 | // border: solid 4rpx #fa995d;
35 | // border: solid 4rpx #f6f6f6;
36 | border: solid 4rpx #70ac9e;
37 | display: flex;
38 | justify-content: center;
39 | align-items: center;
40 | background: transparent;
41 | background: rgba(144, 194, 182, 0.2);
42 |
43 | .searchIcon {
44 | // font-size: 32rpx;
45 | font-size: 40rpx;
46 | background: transparent;
47 | font-weight: 600;
48 | // color: #e0e0e0;
49 | // color: #fa995d;
50 | // color: #f6f6f6;
51 | // color: #757575;
52 | color: #70ac9e;
53 | border-radius: 50%;
54 | }
55 | }
56 |
57 | // .wasTaped {
58 | // background: rgba(112, 172, 158, 0.2);
59 | // }
60 |
61 | .swiperContainer {
62 | margin-top: 300rpx;
63 | width: 100%;
64 | height: 500rpx;
65 |
66 | .dailySentenceWrapper {
67 | width: 90%;
68 | height: 500rpx;
69 | margin-left: auto;
70 | margin-right: auto;
71 | display: flex;
72 | flex-direction: column;
73 | justify-content: center;
74 | align-items: center;
75 |
76 | .content {
77 | width: 100%;
78 | font-size: 42rpx;
79 | font-weight: 800;
80 | font-family: 'Microsoft YaHei';
81 | text-align: center;
82 | color: #333333;
83 | // color: #ee9c6c;
84 | // color: white;
85 | margin-bottom: 20rpx;
86 | }
87 |
88 | .voice {
89 | width: 50rpx;
90 | height: 50rpx;
91 | font-size: 40rpx;
92 | line-height: 50rpx;
93 | text-align: center;
94 | color: #8a8a8a;
95 | // color: white;
96 | margin-top: -10rpx;
97 | margin-bottom: 10rpx;
98 | }
99 |
100 | .translation {
101 | width: 100%;
102 | height: 60rpx;
103 | font-size: 32rpx;
104 | font-weight: 800;
105 | font-family: 'Microsoft YaHei';
106 | color: #4A4A4A;
107 | // color: #f5b994;
108 | // color: white;
109 | text-align: center;
110 | }
111 | }
112 | }
113 |
114 | .btnWrapper {
115 | margin-top: 100rpx;
116 | width: 100%;
117 | height: 140rpx;
118 | display: flex;
119 | flex-direction: column;
120 | justify-content: center;
121 | align-items: center;
122 |
123 | .loginBtn {
124 | width: 50%;
125 | height: 100rpx;
126 | // background-color: #007bff;
127 | // background-color: #6fb3b8;
128 | background-color: #90ced3;
129 | color: #FFFFFF;
130 | font-size: 40rpx;
131 | line-height: 100rpx;
132 | text-align: center;
133 | border-radius: 10rpx;
134 | font-weight: 800;
135 | box-shadow: 4rpx 4rpx 4rpx #e6e6e6;
136 | }
137 | }
138 |
139 | .learnBtnWrapper {
140 | position: absolute;
141 | bottom: 100rpx;
142 | width: 100%;
143 | // left: 20rpx;
144 | height: 150rpx;
145 | display: flex;
146 | justify-content: space-between;
147 | // justify-content: space-around;
148 | align-items: center;
149 |
150 | .both {
151 | width: 38%;
152 | height: 135rpx;
153 | display: flex;
154 | justify-content: center;
155 | flex-direction: column;
156 | padding-left: 40rpx;
157 | border-radius: 10rpx;
158 | box-shadow: 4rpx 4rpx 4rpx #e6e6e6;
159 |
160 | .text {
161 | font-size: 42rpx;
162 | // color: #b3ddd1;
163 | // color: white;
164 | color: #515151;
165 | font-weight: 800;
166 | // margin-bottom: 10rpx;
167 | }
168 |
169 | .number {
170 | font-size: 32rpx;
171 | // color: #b3ddd1;
172 | // color: #f6f6f6;
173 | color: #fa995d;
174 | font-weight: 700;
175 | }
176 | }
177 |
178 | .forLearn {
179 | background-image: linear-gradient(to bottom, #ffc8cb, #FFFFFF);
180 | // background-color: rgba(150, 150, 150, 0.1);c6e5fa
181 | margin-left: 35rpx;
182 | }
183 |
184 | // .wasTaped {
185 | // opacity: 0.7;
186 | // }
187 |
188 | .forReview {
189 | background-image: linear-gradient(to bottom, #e4d1fe, #FFFFFF);
190 | background-image: linear-gradient(to bottom, #87cafe, #FFFFFF);
191 | margin-right: 35rpx;
192 | }
193 | }
194 |
195 | .wasTaped {
196 | // filter: grayscale(40%);
197 | opacity: 0.7;
198 | }
199 |
200 | .mask {
201 | position: absolute;
202 | top: 0;
203 | left: 0;
204 | width: 750rpx;
205 | height: 1200rpx;
206 | // width: 100%;
207 | // height: 100%;
208 | z-index: 80;
209 | background-color: rgba(0, 0, 0, 0.7);
210 | }
211 |
212 | .changeBookWrapper {
213 | width: 750rpx;
214 | height: 600rpx;
215 | margin-top: 50rpx;
216 | position: relative;
217 | z-index: 101;
218 |
219 | .book {
220 | width: 750rpx;
221 | height: 160rpx;
222 | display: flex;
223 | justify-content: center;
224 | align-items: center;
225 | position: relative;
226 | margin-bottom: 10rpx;
227 |
228 | .bookCover {
229 | // margin-top: 30rpx;
230 | margin-left: 20rpx;
231 | margin-right: 40rpx;
232 | width: 106rpx; //遵循A4纸21*27.9的比例
233 | height: 140rpx;
234 | background-color: rgb(37, 134, 229);
235 | background-color: rgb(105, 149, 194);
236 | border-radius: 10rpx;
237 |
238 | .name {
239 | width: 28rpx;
240 | height: 100rpx;
241 | font-size: 28rpx;
242 | // line-height: 50rpx;
243 | color: #ffffff;
244 | margin-left: 10rpx;
245 | margin-top: 10rpx;
246 | font-weight: 600;
247 | }
248 | }
249 |
250 | .info {
251 | width: 70%;
252 | height: 160rpx;
253 | position: relative;
254 | font-weight: 600;
255 |
256 | .bookName {
257 | color: #757575;
258 | font-size: 28rpx;
259 | margin-top: 10rpx;
260 | font-weight: 700;
261 | }
262 |
263 | .des {
264 | margin-top: 10rpx;
265 | font-size: 22rpx;
266 | color: #8a8a8a;
267 | }
268 |
269 | .total {
270 | position: absolute;
271 | bottom: 10rpx;
272 | font-size: 22rpx;
273 | color: #8a8a8a;
274 |
275 | .num {
276 | font-size: 26rpx;
277 | }
278 | }
279 | }
280 |
281 | }
282 |
283 | .wasTaped {
284 | opacity: 1;
285 | background-color: rgba(150, 150, 150, 0.1);
286 | }
287 | }
--------------------------------------------------------------------------------
/miniprogram/pages/index/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
10 |
11 |
12 | {{item.content}}
13 |
14 |
15 | {{item.translation}}
16 |
17 |
18 |
19 |
20 |
21 | 登录
22 |
23 |
24 |
25 |
26 | 学习
27 | {{needToLearn}}
28 |
29 |
30 | 复习
31 | {{needToReview}}
32 |
33 |
34 |
35 |
36 |
37 |
39 |
40 |
41 |
42 | {{item.name}}
43 |
44 |
45 | {{item.name}}
46 | {{item.description}}
47 | 词汇量 {{item.total}}
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/miniprogram/pages/index/index.wxss:
--------------------------------------------------------------------------------
1 | .bgWrapper {
2 | width: 100%;
3 | height: 100%;
4 | position: absolute;
5 | z-index: -100;
6 | background-image: linear-gradient(to bottom, #86e3ce, #FFFFFF);
7 | }
8 | .bgWrapper .bg {
9 | margin-left: -15%;
10 | margin-top: -15%;
11 | width: 130%;
12 | height: 130%;
13 | }
14 | .wrapper {
15 | width: 100%;
16 | height: 100%;
17 | position: absolute;
18 | z-index: -1;
19 | }
20 | .searchBtn {
21 | position: absolute;
22 | top: 35rpx;
23 | right: 45rpx;
24 | height: 60rpx;
25 | width: 60rpx;
26 | border-radius: 34rpx;
27 | border: solid 4rpx #70ac9e;
28 | display: flex;
29 | justify-content: center;
30 | align-items: center;
31 | background: transparent;
32 | background: rgba(144, 194, 182, 0.2);
33 | }
34 | .searchBtn .searchIcon {
35 | font-size: 40rpx;
36 | background: transparent;
37 | font-weight: 600;
38 | color: #70ac9e;
39 | border-radius: 50%;
40 | }
41 | .swiperContainer {
42 | margin-top: 300rpx;
43 | width: 100%;
44 | height: 500rpx;
45 | }
46 | .swiperContainer .dailySentenceWrapper {
47 | width: 90%;
48 | height: 500rpx;
49 | margin-left: auto;
50 | margin-right: auto;
51 | display: flex;
52 | flex-direction: column;
53 | justify-content: center;
54 | align-items: center;
55 | }
56 | .swiperContainer .dailySentenceWrapper .content {
57 | width: 100%;
58 | font-size: 42rpx;
59 | font-weight: 800;
60 | font-family: 'Microsoft YaHei';
61 | text-align: center;
62 | color: #333333;
63 | margin-bottom: 20rpx;
64 | }
65 | .swiperContainer .dailySentenceWrapper .voice {
66 | width: 50rpx;
67 | height: 50rpx;
68 | font-size: 40rpx;
69 | line-height: 50rpx;
70 | text-align: center;
71 | color: #8a8a8a;
72 | margin-top: -10rpx;
73 | margin-bottom: 10rpx;
74 | }
75 | .swiperContainer .dailySentenceWrapper .translation {
76 | width: 100%;
77 | height: 60rpx;
78 | font-size: 32rpx;
79 | font-weight: 800;
80 | font-family: 'Microsoft YaHei';
81 | color: #4A4A4A;
82 | text-align: center;
83 | }
84 | .btnWrapper {
85 | margin-top: 100rpx;
86 | width: 100%;
87 | height: 140rpx;
88 | display: flex;
89 | flex-direction: column;
90 | justify-content: center;
91 | align-items: center;
92 | }
93 | .btnWrapper .loginBtn {
94 | width: 50%;
95 | height: 100rpx;
96 | background-color: #90ced3;
97 | color: #FFFFFF;
98 | font-size: 40rpx;
99 | line-height: 100rpx;
100 | text-align: center;
101 | border-radius: 10rpx;
102 | font-weight: 800;
103 | box-shadow: 4rpx 4rpx 4rpx #e6e6e6;
104 | }
105 | .learnBtnWrapper {
106 | position: absolute;
107 | bottom: 100rpx;
108 | width: 100%;
109 | height: 150rpx;
110 | display: flex;
111 | justify-content: space-between;
112 | align-items: center;
113 | }
114 | .learnBtnWrapper .both {
115 | width: 38%;
116 | height: 135rpx;
117 | display: flex;
118 | justify-content: center;
119 | flex-direction: column;
120 | padding-left: 40rpx;
121 | border-radius: 10rpx;
122 | box-shadow: 4rpx 4rpx 4rpx #e6e6e6;
123 | }
124 | .learnBtnWrapper .both .text {
125 | font-size: 42rpx;
126 | color: #515151;
127 | font-weight: 800;
128 | }
129 | .learnBtnWrapper .both .number {
130 | font-size: 32rpx;
131 | color: #fa995d;
132 | font-weight: 700;
133 | }
134 | .learnBtnWrapper .forLearn {
135 | background-image: linear-gradient(to bottom, #ffc8cb, #FFFFFF);
136 | margin-left: 35rpx;
137 | }
138 | .learnBtnWrapper .forReview {
139 | background-image: linear-gradient(to bottom, #e4d1fe, #FFFFFF);
140 | background-image: linear-gradient(to bottom, #87cafe, #FFFFFF);
141 | margin-right: 35rpx;
142 | }
143 | .wasTaped {
144 | opacity: 0.7;
145 | }
146 | .mask {
147 | position: absolute;
148 | top: 0;
149 | left: 0;
150 | width: 750rpx;
151 | height: 1200rpx;
152 | z-index: 80;
153 | background-color: rgba(0, 0, 0, 0.7);
154 | }
155 | .changeBookWrapper {
156 | width: 750rpx;
157 | height: 600rpx;
158 | margin-top: 50rpx;
159 | position: relative;
160 | z-index: 101;
161 | }
162 | .changeBookWrapper .book {
163 | width: 750rpx;
164 | height: 160rpx;
165 | display: flex;
166 | justify-content: center;
167 | align-items: center;
168 | position: relative;
169 | margin-bottom: 10rpx;
170 | }
171 | .changeBookWrapper .book .bookCover {
172 | margin-left: 20rpx;
173 | margin-right: 40rpx;
174 | width: 106rpx;
175 | height: 140rpx;
176 | background-color: #2586e5;
177 | background-color: #6995c2;
178 | border-radius: 10rpx;
179 | }
180 | .changeBookWrapper .book .bookCover .name {
181 | width: 28rpx;
182 | height: 100rpx;
183 | font-size: 28rpx;
184 | color: #ffffff;
185 | margin-left: 10rpx;
186 | margin-top: 10rpx;
187 | font-weight: 600;
188 | }
189 | .changeBookWrapper .book .info {
190 | width: 70%;
191 | height: 160rpx;
192 | position: relative;
193 | font-weight: 600;
194 | }
195 | .changeBookWrapper .book .info .bookName {
196 | color: #757575;
197 | font-size: 28rpx;
198 | margin-top: 10rpx;
199 | font-weight: 700;
200 | }
201 | .changeBookWrapper .book .info .des {
202 | margin-top: 10rpx;
203 | font-size: 22rpx;
204 | color: #8a8a8a;
205 | }
206 | .changeBookWrapper .book .info .total {
207 | position: absolute;
208 | bottom: 10rpx;
209 | font-size: 22rpx;
210 | color: #8a8a8a;
211 | }
212 | .changeBookWrapper .book .info .total .num {
213 | font-size: 26rpx;
214 | }
215 | .changeBookWrapper .wasTaped {
216 | opacity: 1;
217 | background-color: rgba(150, 150, 150, 0.1);
218 | }
219 |
--------------------------------------------------------------------------------
/miniprogram/pages/learning/learning.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "mpProgress": "../../components/mp-progress/mp-progress"
4 | }
5 | }
--------------------------------------------------------------------------------
/miniprogram/pages/learning/learning.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{learnedNum}} / {{learnNum}}
7 |
8 |
9 |
10 | {{wordDetail.word}}
11 |
12 |
14 |
16 |
18 |
20 |
21 | / {{wordDetail.phonetic}} /
23 |
24 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
38 | {{wrongTransWordList[item].translation.pos}}
39 | {{wrongTransWordList[item].translation.meaning}}
40 |
41 |
42 |
43 |
44 | {{item.pos}}
45 | {{item.meaning}}
47 |
48 |
49 |
50 |
51 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
66 | 答案
67 |
68 |
69 |
70 |
71 | 认识
72 |
73 |
74 |
75 | 不认识
76 |
77 |
78 |
79 |
80 |
81 | 下一个
82 |
83 |
84 |
85 | 记错了
86 |
87 |
88 |
89 |
91 | 下一个
92 |
93 |
94 |
107 |
108 |
109 |
110 | 本组单词学习已完成
111 | 完成学习
112 | 继续学习
113 |
114 |
115 |
--------------------------------------------------------------------------------
/miniprogram/pages/login/login.js:
--------------------------------------------------------------------------------
1 | //login.js
2 | const app = getApp()
3 | import regeneratorRuntime, { async } from '../../lib/runtime/runtime.js';
4 | const { formatTime } = require('../../utils/format_time.js')
5 | const error_message = [
6 | '',
7 | '请完成填写再重试',
8 | '账号或密码错误',
9 | '该账号已被注册',
10 | '两次输入密码不同',
11 | '用户名仅能包含数字、中英文和下划线',
12 | '用户名不能以下划线开头或结尾',
13 | '密码仅能包含数字、英文字母和下划线',
14 | '密码不能以下划线开头或结尾',
15 | ]
16 | const userApi = require("../../utils/userApi.js")
17 | const rescontent = require('../../utils/response_content.js')
18 |
19 | Page({
20 | data: {
21 | isregister: false,
22 | errmsg: error_message,
23 | errtype: 0,
24 | },
25 | user: {
26 | username: '',
27 | pwd: '',
28 | confirm_pwd: '',
29 | },
30 | // isUsernameChecked: false,
31 |
32 | onLoad(options) {
33 | wx.setNavigationBarColor({
34 | backgroundColor: '#d0e6a5',
35 | frontColor: '#ffffff',
36 | })
37 |
38 | wx.setNavigationBarTitle({
39 | title: '登录',
40 | })
41 | },
42 |
43 | //处理input内容变化时的时间
44 | handleInput(e) {
45 | let inputtype = e.target.dataset.inputtype
46 | let value = e.detail.value
47 | this.user[inputtype] = value
48 | // if (inputtype == "username") {
49 | // if (this.data.isregister) {
50 | // this.isUsernameChecked = false
51 | // }
52 | // }
53 | // console.log(inputtype, this.user[inputtype])
54 | },
55 |
56 | async checkUsername() {
57 | let username = this.user.username
58 | if (username == '') { return false }
59 | if(!(this.checkUsernameVaild())) return false
60 | // console.log('check whether', username, 'have been registered')
61 | let res = await userApi.checkUsernameInDB({ username })
62 | // console.log('checkUsername', res)
63 | if (!res.errorcode) { return false }
64 | if (res.data.isFind) {
65 | this.setErrType(3)
66 | return false
67 | }
68 | // this.isUsernameChecked = true
69 | return true
70 | },
71 |
72 | checkUsernameVaild(register = true) {
73 | // 用户名合法性判断,只能包含字母、数字、中文、下划线且不能以下划线开头或结尾
74 | // let exp1 = /^(?!_)(?!.*?_$)[a-zA-Z0-9_\u4e00-\u9fa5]+$/
75 | let username = this.user.username
76 | let exp1 = /^[a-zA-Z0-9_\u4e00-\u9fa5]+$/
77 | let exp2 = /^(?!_)(?!.*?_$).+$/
78 | if (!exp1.test(username)) {
79 | this.setErrType(register ? 5 : 2)
80 | return false
81 | }
82 | if (!exp2.test(username)) {
83 | this.setErrType(register ? 6 : 2)
84 | return false
85 | }
86 | return true
87 | },
88 |
89 | checkPwd(register = true) {
90 | // 密码合法性判断,只能包含字母、数字、下划线且不能以下划线开头或结尾
91 | let pwd = this.user.pwd
92 | let exp1 = /^[a-zA-Z0-9_]+$/
93 | let exp2 = /^(?!_)(?!.*?_$).+$/
94 | if (!exp1.test(pwd)) {
95 | this.setErrType(register ? 7 : 2)
96 | return false
97 | }
98 | if (!exp2.test(pwd)) {
99 | this.setErrType(register ? 8 : 2)
100 | return false
101 | }
102 | return true
103 | },
104 |
105 | checkTwoPwd() {
106 | let pwd = this.user.pwd
107 | let confirm_pwd = this.user.confirm_pwd
108 | if (pwd != confirm_pwd) {
109 | this.setErrType(4)
110 | return false
111 | }
112 | return true
113 | },
114 |
115 | checkEmptyField() {
116 | if (this.user.username != '' && this.user.pwd != '') {
117 | if (this.data.isregister) {
118 | if (this.user.confirm_pwd != '') {
119 | return true
120 | }
121 | } else {
122 | return true
123 | }
124 | }
125 | this.setErrType(1)
126 | return false
127 | },
128 |
129 | changeType(e) {
130 | this.setData({
131 | isregister: !(this.data.isregister),
132 | errtype: 0,
133 | })
134 | this.user = {
135 | username: '',
136 | pwd: '',
137 | confirm_pwd: '',
138 | }
139 | // this.isUsernameChecked = false
140 | },
141 |
142 | setErrType(errtype) {
143 | let _this = this
144 | this.setData({ errtype })
145 | clearTimeout(this.timer)
146 | this.timer = setTimeout(() => {
147 | _this.setData({ errtype: 0 })
148 | }, 1500)
149 | },
150 |
151 | async login() {
152 | if (!(this.checkEmptyField()) || !(this.checkUsernameVaild(false)) || !(this.checkPwd(false))) {
153 | return
154 | }
155 | console.log('try to login')
156 | let username = this.user.username
157 | let pwd = this.user.pwd
158 | let res = await userApi.login({ username, pwd })
159 | console.log(res)
160 | this.afterLogin(res)
161 | },
162 |
163 | async register() {
164 | if (!(this.checkEmptyField()) || !(this.checkPwd()) || !(this.checkTwoPwd())) {
165 | return
166 | }
167 | // if (!(this.isUsernameChecked)) {
168 | let usernameOk = await this.checkUsername()
169 | if (!usernameOk) { return }
170 | // this.isUsernameChecked = true
171 | // }
172 | console.log('try to register')
173 | // return
174 | let username = this.user.username
175 | let pwd = this.user.pwd
176 | let res = await userApi.register({ username, pwd })
177 | // console.log(res)
178 | this.afterLogin(res)
179 | },
180 |
181 | async wxLogin() {
182 | console.log('login/register using wechat userinfo')
183 | let res = await userApi.getWxUserInfo()
184 | if (!res.userInfo) { return }
185 | let username = res.userInfo.nickName
186 | let avatar_pic = res.userInfo.avatarUrl
187 | let res1 = await userApi.wxLogin({ username, avatar_pic })
188 | console.log(res1)
189 | this.afterLogin(res1)
190 | },
191 |
192 | afterLogin(res) {
193 | let duration = 1000
194 | if (res.errorcode == rescontent.LOGINERR.errorcode) {
195 | this.setErrType(2)
196 | return
197 | } else if (res.errorcode == rescontent.REGISTEROK.errorcode) {
198 | wx.showToast({
199 | title: `注册成功`,
200 | icon: 'none',
201 | duration: duration,
202 | })
203 | } else if (res.errorcode == rescontent.LOGINOK.errorcode) {
204 | let lastlogin = formatTime(res.data.last_login)
205 | wx.showToast({
206 | title: `登录成功,上次登录时间 ${lastlogin}`,
207 | icon: 'none',
208 | duration: duration,
209 | })
210 | } else {
211 | wx.showToast({
212 | title: '服务出错,请重试',
213 | icon: 'none',
214 | duration: duration
215 | })
216 | return
217 | }
218 |
219 | setTimeout(function () {
220 | app.globalData.isLogin = true
221 | app.globalData.userInfo = res.data
222 | app.globalData.updatedForIndex = true
223 | app.globalData.updatedForOverview = true
224 | let storageContent = {
225 | time: new Date().getTime(),
226 | info: res.data,
227 | }
228 | wx.setStorageSync('userInfo', storageContent)
229 | wx.navigateBack({
230 | delta: 1,
231 | complete: (res) => { console.log('navigate back complete', res) },
232 | })
233 | }, duration)
234 | },
235 |
236 |
237 | })
--------------------------------------------------------------------------------
/miniprogram/pages/login/login.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {}
3 | }
--------------------------------------------------------------------------------
/miniprogram/pages/login/login.less:
--------------------------------------------------------------------------------
1 | .bgWrapper {
2 | width: 100%;
3 | height: 100%;
4 | position: absolute;
5 | z-index: -100;
6 | background-image: linear-gradient(to bottom, #d0e6a5, #FFFFFF);
7 | // -webkit-filter: blur(10px);
8 | // filter: blur(10px);
9 |
10 | .bg {
11 | margin-left: -15%;
12 | margin-top: -15%;
13 | width: 130%;
14 | height: 130%;
15 | }
16 | }
17 |
18 | .wrapper {
19 | width: 80%;
20 | height: 500rpx;
21 | margin-left: auto;
22 | margin-right: auto;
23 | margin-top: 300rpx;
24 | margin-bottom: auto;
25 |
26 | .title {
27 | margin-top: 30rpx;
28 | width: 100%;
29 | font-size: 56rpx;
30 | text-align: center;
31 | font-weight: 800;
32 | color: #819c4b;
33 | }
34 |
35 | .inputField {
36 | height: 70rpx;
37 | font-size: 34rpx;
38 | background-color: rgba(255, 255, 255, 0.7);
39 | padding-left: 20rpx;
40 | border: solid 4rpx #e2e2e2;
41 | }
42 |
43 | .username {
44 | margin-top: 40rpx;
45 | border-top-left-radius: 10rpx;
46 | border-top-right-radius: 10rpx;
47 | border-bottom: 2rpx solid #e2e2e2;
48 | }
49 |
50 | .middlePwd {
51 | border-top: 2rpx solid #e2e2e2;
52 | border-bottom: 2rpx solid #e2e2e2;
53 | margin-top: -2rpx;
54 | }
55 |
56 | .pwd {
57 | border-bottom-left-radius: 10rpx;
58 | border-bottom-right-radius: 10rpx;
59 | border-top: 2rpx solid #e2e2e2;
60 | margin-top: -2rpx;
61 | }
62 |
63 | .btnWrapper {
64 | margin-top: 10rpx;
65 | width: 100%;
66 | height: 40rpx;
67 |
68 | .changeBtn {
69 | width: 60rpx;
70 | height: 40rpx;
71 | font-size: 28rpx;
72 | line-height: 40rpx;
73 | color: #819c4b;
74 | font-weight: 500;
75 | }
76 |
77 | .loginBtn {
78 | margin-left: 10rpx;
79 | }
80 |
81 | .registerBtn {
82 | margin-right: 10rpx;
83 | }
84 | }
85 |
86 | .registerBtnWrapper {
87 | display: flex;
88 | justify-content: flex-end;
89 | }
90 |
91 | .errmsg {
92 | height: 50rpx;
93 | width: 100%;
94 | text-align: center;
95 | line-height: 50rpx;
96 | font-size: 30rpx;
97 | color: rgb(247, 98, 96);
98 | }
99 |
100 | .submit {
101 | margin-top: 0rpx;
102 | width: 100%;
103 | color: white;
104 | // background-color: #007bff;
105 | background-color: #b9ce8e;
106 | }
107 | }
108 |
109 | .wxLoginWrapper {
110 | position: absolute;
111 | bottom: 150rpx;
112 | width: 100%;
113 | height: 150rpx;
114 | margin-left: 0;
115 | margin-right: 0;
116 |
117 | .loginBtn {
118 | width: 100rpx;
119 | height: 100rpx;
120 | border-radius: 50%;
121 | margin-left: auto;
122 | margin-right: auto;
123 | background-color: rgb(42, 174, 103);
124 | display: flex;
125 | align-items: center;
126 | justify-content: center;
127 |
128 | .logo {
129 | width: 85%;
130 | height: 85%;
131 | border-radius: 50%;
132 | }
133 | }
134 |
135 | .wxLoginTip {
136 | margin-top: 20rpx;
137 | width: 100%;
138 | height: 24rpx;
139 | font-size: 22rpx;
140 | color: rgba(0, 0, 0, 0.3);
141 | text-align: center;
142 | }
143 | }
144 |
145 | .wasTaped {
146 | filter: grayscale(30%);
147 | }
148 |
149 | .avatarPicTest {
150 | width: 100rpx;
151 | height: 100rpx;
152 | margin-top: 50rpx;
153 | margin-right: auto;
154 | margin-left: auto;
155 | border-radius: 50rpx;
156 |
157 | .pic {
158 | width: 100rpx;
159 | height: 100rpx;
160 | border-radius: 50rpx;
161 | }
162 | }
--------------------------------------------------------------------------------
/miniprogram/pages/login/login.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 登录
6 |
7 |
8 |
9 | 注册
10 |
11 | {{errmsg[errtype]}}
12 |
13 |
14 |
15 |
16 | 注册
17 |
18 |
19 |
20 |
21 | 登录
22 |
23 | {{errmsg[errtype]}}
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | 微信登录无需注册哦~
32 |
--------------------------------------------------------------------------------
/miniprogram/pages/login/login.wxss:
--------------------------------------------------------------------------------
1 | .bgWrapper {
2 | width: 100%;
3 | height: 100%;
4 | position: absolute;
5 | z-index: -100;
6 | background-image: linear-gradient(to bottom, #d0e6a5, #FFFFFF);
7 | }
8 | .bgWrapper .bg {
9 | margin-left: -15%;
10 | margin-top: -15%;
11 | width: 130%;
12 | height: 130%;
13 | }
14 | .wrapper {
15 | width: 80%;
16 | height: 500rpx;
17 | margin-left: auto;
18 | margin-right: auto;
19 | margin-top: 300rpx;
20 | margin-bottom: auto;
21 | }
22 | .wrapper .title {
23 | margin-top: 30rpx;
24 | width: 100%;
25 | font-size: 56rpx;
26 | text-align: center;
27 | font-weight: 800;
28 | color: #819c4b;
29 | }
30 | .wrapper .inputField {
31 | height: 70rpx;
32 | font-size: 34rpx;
33 | background-color: rgba(255, 255, 255, 0.7);
34 | padding-left: 20rpx;
35 | border: solid 4rpx #e2e2e2;
36 | }
37 | .wrapper .username {
38 | margin-top: 40rpx;
39 | border-top-left-radius: 10rpx;
40 | border-top-right-radius: 10rpx;
41 | border-bottom: 2rpx solid #e2e2e2;
42 | }
43 | .wrapper .middlePwd {
44 | border-top: 2rpx solid #e2e2e2;
45 | border-bottom: 2rpx solid #e2e2e2;
46 | margin-top: -2rpx;
47 | }
48 | .wrapper .pwd {
49 | border-bottom-left-radius: 10rpx;
50 | border-bottom-right-radius: 10rpx;
51 | border-top: 2rpx solid #e2e2e2;
52 | margin-top: -2rpx;
53 | }
54 | .wrapper .btnWrapper {
55 | margin-top: 10rpx;
56 | width: 100%;
57 | height: 40rpx;
58 | }
59 | .wrapper .btnWrapper .changeBtn {
60 | width: 60rpx;
61 | height: 40rpx;
62 | font-size: 28rpx;
63 | line-height: 40rpx;
64 | color: #819c4b;
65 | font-weight: 500;
66 | }
67 | .wrapper .btnWrapper .loginBtn {
68 | margin-left: 10rpx;
69 | }
70 | .wrapper .btnWrapper .registerBtn {
71 | margin-right: 10rpx;
72 | }
73 | .wrapper .registerBtnWrapper {
74 | display: flex;
75 | justify-content: flex-end;
76 | }
77 | .wrapper .errmsg {
78 | height: 50rpx;
79 | width: 100%;
80 | text-align: center;
81 | line-height: 50rpx;
82 | font-size: 30rpx;
83 | color: #f76260;
84 | }
85 | .wrapper .submit {
86 | margin-top: 0rpx;
87 | width: 100%;
88 | color: white;
89 | background-color: #b9ce8e;
90 | }
91 | .wxLoginWrapper {
92 | position: absolute;
93 | bottom: 150rpx;
94 | width: 100%;
95 | height: 150rpx;
96 | margin-left: 0;
97 | margin-right: 0;
98 | }
99 | .wxLoginWrapper .loginBtn {
100 | width: 100rpx;
101 | height: 100rpx;
102 | border-radius: 50%;
103 | margin-left: auto;
104 | margin-right: auto;
105 | background-color: #2aae67;
106 | display: flex;
107 | align-items: center;
108 | justify-content: center;
109 | }
110 | .wxLoginWrapper .loginBtn .logo {
111 | width: 85%;
112 | height: 85%;
113 | border-radius: 50%;
114 | }
115 | .wxLoginWrapper .wxLoginTip {
116 | margin-top: 20rpx;
117 | width: 100%;
118 | height: 24rpx;
119 | font-size: 22rpx;
120 | color: rgba(0, 0, 0, 0.3);
121 | text-align: center;
122 | }
123 | .wasTaped {
124 | filter: grayscale(30%);
125 | }
126 | .avatarPicTest {
127 | width: 100rpx;
128 | height: 100rpx;
129 | margin-top: 50rpx;
130 | margin-right: auto;
131 | margin-left: auto;
132 | border-radius: 50rpx;
133 | }
134 | .avatarPicTest .pic {
135 | width: 100rpx;
136 | height: 100rpx;
137 | border-radius: 50rpx;
138 | }
139 |
--------------------------------------------------------------------------------
/miniprogram/pages/overview/overview.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "mpProgress": "../../components/mp-progress/mp-progress",
4 | "ec-canvas": "../../components/ec-canvas/ec-canvas"
5 | }
6 | }
--------------------------------------------------------------------------------
/miniprogram/pages/review/review.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "mpProgress": "../../components/mp-progress/mp-progress"
4 | }
5 | }
--------------------------------------------------------------------------------
/miniprogram/pages/review/review.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{reviewedNum}} / {{reviewNum}}
7 |
8 |
9 |
10 | {{wordDetail.word}}
11 |
12 |
14 |
16 |
18 |
19 | / {{wordDetail.phonetic}} /
21 |
22 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
36 | {{wrongTransWordList[item].translation.pos}}
37 | {{wrongTransWordList[item].translation.meaning}}
38 |
39 |
40 |
41 |
42 | {{item.pos}}
43 | {{item.meaning}}
45 |
46 |
47 |
48 |
49 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
64 | 答案
65 |
66 |
67 |
68 |
70 | 认识
71 |
72 |
73 |
75 | 模糊
76 |
77 |
78 |
80 | 不认识
81 |
82 |
83 |
84 |
85 |
86 | 下一个
87 |
88 |
89 |
91 | 记错了
92 |
93 |
94 |
95 |
97 | 下一个
98 |
99 |
100 |
109 |
110 |
111 |
112 | 本组单词复习已完成
113 |
114 |
115 | 单词
116 | 下次学习时间
117 |
118 |
119 |
120 | {{item.word}}
121 | {{item.NOI}}天后
122 | 已掌握
123 | 上传失败
124 |
125 |
126 |
127 |
128 | 完成复习
129 | 继续复习
130 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/miniprogram/pages/search/search.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {}
3 | }
--------------------------------------------------------------------------------
/miniprogram/pages/search/search.less:
--------------------------------------------------------------------------------
1 | .searchWrapper {
2 | width: 100%;
3 | height: 100rpx;
4 | position: fixed;
5 | z-index: 8;
6 | display: flex;
7 | align-items: center;
8 | justify-content: center;
9 | background-color: #f6f6f6;
10 |
11 | .searchIcon {
12 | position: absolute;
13 | top: 30rpx;
14 | left: 40rpx;
15 | font-size: 40rpx;
16 | font-weight: 500;
17 | color: #808080;
18 | z-index: 10;
19 | }
20 |
21 | .search {
22 | width: 85%;
23 | height: 70rpx;
24 | font-size: 32rpx;
25 | line-height: 60rpx;
26 | padding-left: 70rpx;
27 | // border: 4rpx solid #e2e2e2;
28 | border: 2rpx solid #e2e2e2;
29 | border-radius: 15rpx;
30 | background-color: white;
31 | color: #333333;
32 | font-family: Arial;
33 | }
34 |
35 | .placeHolder {
36 | font-size: 32rpx;
37 | line-height: 60rpx;
38 | // padding-left: 70rpx;
39 | // color: #333333;
40 | // font-family: 'Microsoft YaHei', Arial;
41 | }
42 | }
43 |
44 | .cancelWrapper {
45 | position: fixed;
46 | top: 0rpx;
47 | right: 8rpx;
48 | width: 100rpx;
49 | height: 100rpx;
50 | z-index: 9999;
51 | display: flex;
52 | align-items: center;
53 | justify-content: center;
54 |
55 | .cancel {
56 | width: 36rpx;
57 | height: 36rpx;
58 | // text-align: center;
59 | // font-size: 36rpx;
60 | // line-height: 36rpx;
61 | // color: #757575;
62 | background-color: #d6d6d6;
63 | border-radius: 18rpx;
64 | display: flex;
65 | align-items: center;
66 | justify-content: center;
67 |
68 | .cancelIcon {
69 | font-size: 24rpx;
70 | color: white;
71 | }
72 | }
73 | }
74 |
75 | .resultWrapper {
76 | margin-top: 100rpx;
77 | width: 100%;
78 | display: flex;
79 | flex-direction: column;
80 | align-items: center;
81 | // margin-bottom: 10rpx;
82 |
83 | .result {
84 | width: 670rpx; // 750-40*2
85 | height: 80rpx;
86 | line-height: 80rpx;
87 | font-size: 32rpx;
88 | padding-left: 40rpx;
89 | padding-right: 40rpx;
90 | display: -webkit-box;
91 | overflow: hidden;
92 | -webkit-box-orient: vertical;
93 | -webkit-line-clamp: 1;
94 |
95 | .word {
96 | color: #333333;
97 | }
98 |
99 | .desc {
100 | color: #333333;
101 | }
102 |
103 | .trans {
104 | color: #757575;
105 | font-size: 28rpx;
106 | }
107 | }
108 |
109 | .wasTaped {
110 | background-color: #e6e6e6;
111 | }
112 | }
113 |
114 | .resultTips {
115 | width: 100%;
116 | height: 60rpx;
117 | margin-bottom: 130rpx;
118 | display: flex;
119 | align-items: center;
120 | justify-content: center;
121 |
122 | .text {
123 | font-size: 28rpx;
124 | color: #757575;
125 | }
126 | }
127 |
128 | .historyWrapper {
129 | margin-top: 100rpx;
130 | width: 100%;
131 | display: flex;
132 | flex-direction: column;
133 | align-items: center;
134 | margin-bottom: 140rpx;
135 |
136 | .history {
137 | width: 670rpx; // 750-40*2
138 | height: 80rpx;
139 | line-height: 80rpx;
140 | font-size: 32rpx;
141 | padding-left: 40rpx;
142 | padding-right: 40rpx;
143 | position: relative;
144 |
145 | .wordInfo {
146 | width: 630rpx;
147 | display: -webkit-box;
148 | overflow: hidden;
149 | -webkit-box-orient: vertical;
150 | -webkit-line-clamp: 1;
151 |
152 | .word {
153 | color: #333333;
154 | }
155 |
156 | .trans {
157 | color: #757575;
158 | font-size: 28rpx;
159 | }
160 |
161 | }
162 |
163 | .delete {
164 | position: absolute;
165 | top: 0rpx;
166 | right: 40rpx;
167 | width: 30rpx;
168 | height: 80rpx;
169 | z-index: 5;
170 | // border-radius: 18rpx;
171 | display: flex;
172 | align-items: center;
173 | justify-content: center;
174 |
175 | .deleteIcon {
176 | font-size: 30rpx;
177 | color: #515151;
178 | }
179 | }
180 | }
181 |
182 | .clearAll {
183 | margin-top: 20rpx;
184 | margin-left: auto;
185 | margin-right: auto;
186 | width: 200rpx;
187 | font-size: 28rpx;
188 | color: #808080;
189 | }
190 |
191 | .wasTaped {
192 | background-color: #e6e6e6;
193 | }
194 | }
195 |
196 | .changeBigDB {
197 | position: fixed;
198 | width: 100%;
199 | height: 80rpx;
200 | padding-bottom: 40rpx;
201 | bottom: 0rpx;
202 | display: flex;
203 | flex-direction: column;
204 | align-items: center;
205 | justify-content: center;
206 | background-color: #f6f6f6;
207 | z-index: 10;
208 |
209 | .text {
210 | font-size: 24rpx;
211 | line-height: 30rpx;
212 | color: #a0a0a0;
213 |
214 | .changeBtn {
215 | color: #515151;
216 | }
217 | }
218 | }
--------------------------------------------------------------------------------
/miniprogram/pages/search/search.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
17 | {{item.word}}
18 | 的{{item.exchange}}
19 | {{item.translation}}
20 |
21 |
23 | {{item.word}}
24 | {{item.translation}}
25 |
26 |
27 |
28 | 没有更多结果了哦
29 |
30 |
31 |
32 |
34 |
35 | {{item.word}}
36 | {{item.translation}}
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | 清除全部历史
45 |
46 |
47 |
48 |
49 | 当前在使用小词库,速度较快,能满足大部分需求
50 | 可切换大词库获得更多的搜索结果
51 | 当前在使用大词库,包含本应用所有词汇,速度较慢
52 | 可切换小词库获得更快的搜索速度
53 |
--------------------------------------------------------------------------------
/miniprogram/pages/search/search.wxss:
--------------------------------------------------------------------------------
1 | .searchWrapper {
2 | width: 100%;
3 | height: 100rpx;
4 | position: fixed;
5 | z-index: 8;
6 | display: flex;
7 | align-items: center;
8 | justify-content: center;
9 | background-color: #f6f6f6;
10 | }
11 | .searchWrapper .searchIcon {
12 | position: absolute;
13 | top: 30rpx;
14 | left: 40rpx;
15 | font-size: 40rpx;
16 | font-weight: 500;
17 | color: #808080;
18 | z-index: 10;
19 | }
20 | .searchWrapper .search {
21 | width: 85%;
22 | height: 70rpx;
23 | font-size: 32rpx;
24 | line-height: 60rpx;
25 | padding-left: 70rpx;
26 | border: 2rpx solid #e2e2e2;
27 | border-radius: 15rpx;
28 | background-color: white;
29 | color: #333333;
30 | font-family: Arial;
31 | }
32 | .searchWrapper .placeHolder {
33 | font-size: 32rpx;
34 | line-height: 60rpx;
35 | }
36 | .cancelWrapper {
37 | position: fixed;
38 | top: 0rpx;
39 | right: 8rpx;
40 | width: 100rpx;
41 | height: 100rpx;
42 | z-index: 9999;
43 | display: flex;
44 | align-items: center;
45 | justify-content: center;
46 | }
47 | .cancelWrapper .cancel {
48 | width: 36rpx;
49 | height: 36rpx;
50 | background-color: #d6d6d6;
51 | border-radius: 18rpx;
52 | display: flex;
53 | align-items: center;
54 | justify-content: center;
55 | }
56 | .cancelWrapper .cancel .cancelIcon {
57 | font-size: 24rpx;
58 | color: white;
59 | }
60 | .resultWrapper {
61 | margin-top: 100rpx;
62 | width: 100%;
63 | display: flex;
64 | flex-direction: column;
65 | align-items: center;
66 | }
67 | .resultWrapper .result {
68 | width: 670rpx;
69 | height: 80rpx;
70 | line-height: 80rpx;
71 | font-size: 32rpx;
72 | padding-left: 40rpx;
73 | padding-right: 40rpx;
74 | display: -webkit-box;
75 | overflow: hidden;
76 | -webkit-box-orient: vertical;
77 | -webkit-line-clamp: 1;
78 | }
79 | .resultWrapper .result .word {
80 | color: #333333;
81 | }
82 | .resultWrapper .result .desc {
83 | color: #333333;
84 | }
85 | .resultWrapper .result .trans {
86 | color: #757575;
87 | font-size: 28rpx;
88 | }
89 | .resultWrapper .wasTaped {
90 | background-color: #e6e6e6;
91 | }
92 | .resultTips {
93 | width: 100%;
94 | height: 60rpx;
95 | margin-bottom: 130rpx;
96 | display: flex;
97 | align-items: center;
98 | justify-content: center;
99 | }
100 | .resultTips .text {
101 | font-size: 28rpx;
102 | color: #757575;
103 | }
104 | .historyWrapper {
105 | margin-top: 100rpx;
106 | width: 100%;
107 | display: flex;
108 | flex-direction: column;
109 | align-items: center;
110 | margin-bottom: 140rpx;
111 | }
112 | .historyWrapper .history {
113 | width: 670rpx;
114 | height: 80rpx;
115 | line-height: 80rpx;
116 | font-size: 32rpx;
117 | padding-left: 40rpx;
118 | padding-right: 40rpx;
119 | position: relative;
120 | }
121 | .historyWrapper .history .wordInfo {
122 | width: 630rpx;
123 | display: -webkit-box;
124 | overflow: hidden;
125 | -webkit-box-orient: vertical;
126 | -webkit-line-clamp: 1;
127 | }
128 | .historyWrapper .history .wordInfo .word {
129 | color: #333333;
130 | }
131 | .historyWrapper .history .wordInfo .trans {
132 | color: #757575;
133 | font-size: 28rpx;
134 | }
135 | .historyWrapper .history .delete {
136 | position: absolute;
137 | top: 0rpx;
138 | right: 40rpx;
139 | width: 30rpx;
140 | height: 80rpx;
141 | z-index: 5;
142 | display: flex;
143 | align-items: center;
144 | justify-content: center;
145 | }
146 | .historyWrapper .history .delete .deleteIcon {
147 | font-size: 30rpx;
148 | color: #515151;
149 | }
150 | .historyWrapper .clearAll {
151 | margin-top: 20rpx;
152 | margin-left: auto;
153 | margin-right: auto;
154 | width: 200rpx;
155 | font-size: 28rpx;
156 | color: #808080;
157 | }
158 | .historyWrapper .wasTaped {
159 | background-color: #e6e6e6;
160 | }
161 | .changeBigDB {
162 | position: fixed;
163 | width: 100%;
164 | height: 80rpx;
165 | padding-bottom: 40rpx;
166 | bottom: 0rpx;
167 | display: flex;
168 | flex-direction: column;
169 | align-items: center;
170 | justify-content: center;
171 | background-color: #f6f6f6;
172 | z-index: 10;
173 | }
174 | .changeBigDB .text {
175 | font-size: 24rpx;
176 | line-height: 30rpx;
177 | color: #a0a0a0;
178 | }
179 | .changeBigDB .text .changeBtn {
180 | color: #515151;
181 | }
182 |
--------------------------------------------------------------------------------
/miniprogram/pages/user/user.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {}
3 | }
--------------------------------------------------------------------------------
/miniprogram/pages/user/user.less:
--------------------------------------------------------------------------------
1 | .header {
2 | width: 100%;
3 | height: 500rpx;
4 | display: flex;
5 | flex-direction: column;
6 | align-items: center;
7 | justify-content: center;
8 | position: relative;
9 |
10 | .background {
11 | position: absolute;
12 | top: 0;
13 | left: 0;
14 | width: 100%;
15 | height: 100%;
16 | filter: blur(60rpx);
17 | z-index: -1;
18 | opacity: 0.6;
19 |
20 | .bgImg {
21 | width: 100%;
22 | height: 100%;
23 | }
24 | }
25 |
26 | .loginBtn {
27 | width: 300rpx;
28 | height: 80rpx;
29 | background-color: #90ced3;
30 | color: #FFFFFF;
31 | font-size: 36rpx;
32 | line-height: 80rpx;
33 | text-align: center;
34 | border-radius: 10rpx;
35 | font-weight: 800;
36 | // box-shadow: 4rpx 4rpx 4rpx #e6e6e6;
37 | }
38 |
39 | .wasTaped {
40 | opacity: 0.7;
41 | }
42 |
43 | .avatar {
44 | width: 160rpx;
45 | height: 160rpx;
46 | border-radius: 50%;
47 | border: solid 4rpx #e6e6e6;
48 | margin-top: 20rpx;
49 | }
50 |
51 | .username {
52 | margin-top: 30rpx;
53 | color: #ffffff;
54 | font-size: 44rpx;
55 | text-shadow: 2rpx 2rpx 2rpx #bfbfbf;
56 | }
57 | }
58 |
59 | .optionList {
60 | width: 100%;
61 | // height: 600rpx;
62 | background-color: #ffffff;
63 |
64 | .option {
65 | width: 670rpx; // 750-40*2
66 | height: 100rpx;
67 | padding: 0 40rpx;
68 | background-color: #ffffff;
69 | // background-color: #f6f6f6;
70 | // border-bottom: solid 4rpx #e6e6e6;
71 | display: flex;
72 | align-items: center;
73 | justify-content: center;
74 | position: relative;
75 | font-weight: 600;
76 |
77 | .optionIcon {
78 | width: 40rpx;
79 | height: 40rpx;
80 | color: #bfbfbf;
81 | color: #8a8a8a;
82 | // color: #fd6802;
83 | // font-weight: 600;
84 | font-size: 40rpx;
85 | }
86 |
87 | .optionName {
88 | width: 600rpx; // 670-40-30
89 | margin-left: 30rpx;
90 | color: #515151;
91 | font-weight: 600;
92 | font-size: 32rpx;
93 | }
94 |
95 | .more {
96 | position: absolute;
97 | right: 40rpx;
98 | top: 30rpx;
99 | width: 40rpx;
100 | height: 40rpx;
101 | color: #bfbfbf;
102 | color: #8a8a8a;
103 | // font-weight: 600;
104 | font-size: 40rpx;
105 |
106 | }
107 | }
108 |
109 | .split {
110 | width: 100%;
111 | height: 20rpx;
112 | background-color: #f6f6f6;
113 | }
114 |
115 | .wasTaped {
116 | background-color: #e6e6e6;
117 | }
118 | }
119 |
120 | .logoutBtn {
121 | width: 250rpx;
122 | height: 80rpx;
123 | line-height: 80rpx;
124 | text-align: center;
125 | margin-top: 50rpx;
126 | margin-left: auto;
127 | margin-right: auto;
128 | color: #8a8a8a;
129 | color: #bfbfbf;
130 | font-weight: 600;
131 | background-color: #f6f6f6;
132 | border-radius: 10rpx;
133 | }
134 |
135 | .wasTaped {
136 | background-color: rgba(150, 150, 150, 0.1);
137 | }
138 |
139 | .customizeWrapper {
140 | width: 750rpx;
141 | height: 500rpx;
142 | margin-top: 50rpx;
143 | position: relative;
144 | z-index: 101;
145 |
146 | .customValue {
147 | width: 600rpx;
148 | height: 80rpx;
149 | margin-top: 20rpx;
150 | margin-left: auto;
151 | margin-right: auto;
152 | padding: 0 30rpx;
153 | border: 2rpx solid #e2e2e2;
154 | border-radius: 10rpx;
155 | font-size: 36rpx;
156 | color: #515151;
157 | }
158 |
159 | .placeHolder {
160 | font-size: 30rpx;
161 | }
162 |
163 | .errMsg{
164 | margin-top: 20rpx;
165 | width: 600rpx;
166 | height: 60rpx;
167 | margin-left: auto;
168 | margin-right: auto;
169 | text-align: center;
170 | line-height: 60rpx;
171 | font-size: 30rpx;
172 | color: rgb(247, 98, 96);
173 | }
174 |
175 | .btn {
176 | width: 300rpx;
177 | height: 80rpx;
178 | margin-top: 20rpx;
179 | margin-left: auto;
180 | margin-right: auto;
181 | font-size: 36rpx;
182 | font-weight: 600;
183 | line-height: 80rpx;
184 | text-align: center;
185 | color: #ffffff;
186 | background-color: #90ced3;
187 | // background-color: #fd6802;
188 | border-radius: 10rpx;
189 | }
190 |
191 | .wasTaped {
192 | opacity: 0.7;
193 | }
194 | }
--------------------------------------------------------------------------------
/miniprogram/pages/user/user.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
14 |
15 |
16 | 更改头像
17 |
18 |
19 |
20 | 更改昵称
21 |
22 |
23 |
24 | 修改密码
25 |
26 |
27 |
28 |
29 | 更多设置
30 |
31 |
32 |
33 | 退出登录
34 |
35 |
37 |
38 |
41 |
44 |
47 | {{errMsg}}
48 | 确认
49 |
50 |
--------------------------------------------------------------------------------
/miniprogram/pages/user/user.wxss:
--------------------------------------------------------------------------------
1 | .header {
2 | width: 100%;
3 | height: 500rpx;
4 | display: flex;
5 | flex-direction: column;
6 | align-items: center;
7 | justify-content: center;
8 | position: relative;
9 | }
10 | .header .background {
11 | position: absolute;
12 | top: 0;
13 | left: 0;
14 | width: 100%;
15 | height: 100%;
16 | filter: blur(60rpx);
17 | z-index: -1;
18 | opacity: 0.6;
19 | }
20 | .header .background .bgImg {
21 | width: 100%;
22 | height: 100%;
23 | }
24 | .header .loginBtn {
25 | width: 300rpx;
26 | height: 80rpx;
27 | background-color: #90ced3;
28 | color: #FFFFFF;
29 | font-size: 36rpx;
30 | line-height: 80rpx;
31 | text-align: center;
32 | border-radius: 10rpx;
33 | font-weight: 800;
34 | }
35 | .header .wasTaped {
36 | opacity: 0.7;
37 | }
38 | .header .avatar {
39 | width: 160rpx;
40 | height: 160rpx;
41 | border-radius: 50%;
42 | border: solid 4rpx #e6e6e6;
43 | margin-top: 20rpx;
44 | }
45 | .header .username {
46 | margin-top: 30rpx;
47 | color: #ffffff;
48 | font-size: 44rpx;
49 | text-shadow: 2rpx 2rpx 2rpx #bfbfbf;
50 | }
51 | .optionList {
52 | width: 100%;
53 | background-color: #ffffff;
54 | }
55 | .optionList .option {
56 | width: 670rpx;
57 | height: 100rpx;
58 | padding: 0 40rpx;
59 | background-color: #ffffff;
60 | display: flex;
61 | align-items: center;
62 | justify-content: center;
63 | position: relative;
64 | font-weight: 600;
65 | }
66 | .optionList .option .optionIcon {
67 | width: 40rpx;
68 | height: 40rpx;
69 | color: #bfbfbf;
70 | color: #8a8a8a;
71 | font-size: 40rpx;
72 | }
73 | .optionList .option .optionName {
74 | width: 600rpx;
75 | margin-left: 30rpx;
76 | color: #515151;
77 | font-weight: 600;
78 | font-size: 32rpx;
79 | }
80 | .optionList .option .more {
81 | position: absolute;
82 | right: 40rpx;
83 | top: 30rpx;
84 | width: 40rpx;
85 | height: 40rpx;
86 | color: #bfbfbf;
87 | color: #8a8a8a;
88 | font-size: 40rpx;
89 | }
90 | .optionList .split {
91 | width: 100%;
92 | height: 20rpx;
93 | background-color: #f6f6f6;
94 | }
95 | .optionList .wasTaped {
96 | background-color: #e6e6e6;
97 | }
98 | .logoutBtn {
99 | width: 250rpx;
100 | height: 80rpx;
101 | line-height: 80rpx;
102 | text-align: center;
103 | margin-top: 50rpx;
104 | margin-left: auto;
105 | margin-right: auto;
106 | color: #8a8a8a;
107 | color: #bfbfbf;
108 | font-weight: 600;
109 | background-color: #f6f6f6;
110 | border-radius: 10rpx;
111 | }
112 | .wasTaped {
113 | background-color: rgba(150, 150, 150, 0.1);
114 | }
115 | .customizeWrapper {
116 | width: 750rpx;
117 | height: 500rpx;
118 | margin-top: 50rpx;
119 | position: relative;
120 | z-index: 101;
121 | }
122 | .customizeWrapper .customValue {
123 | width: 600rpx;
124 | height: 80rpx;
125 | margin-top: 20rpx;
126 | margin-left: auto;
127 | margin-right: auto;
128 | padding: 0 30rpx;
129 | border: 2rpx solid #e2e2e2;
130 | border-radius: 10rpx;
131 | font-size: 36rpx;
132 | color: #515151;
133 | }
134 | .customizeWrapper .placeHolder {
135 | font-size: 30rpx;
136 | }
137 | .customizeWrapper .errMsg {
138 | margin-top: 20rpx;
139 | width: 600rpx;
140 | height: 60rpx;
141 | margin-left: auto;
142 | margin-right: auto;
143 | text-align: center;
144 | line-height: 60rpx;
145 | font-size: 30rpx;
146 | color: #f76260;
147 | }
148 | .customizeWrapper .btn {
149 | width: 300rpx;
150 | height: 80rpx;
151 | margin-top: 20rpx;
152 | margin-left: auto;
153 | margin-right: auto;
154 | font-size: 36rpx;
155 | font-weight: 600;
156 | line-height: 80rpx;
157 | text-align: center;
158 | color: #ffffff;
159 | background-color: #90ced3;
160 | border-radius: 10rpx;
161 | }
162 | .customizeWrapper .wasTaped {
163 | opacity: 0.7;
164 | }
165 |
--------------------------------------------------------------------------------
/miniprogram/pages/user_settings/user_settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {}
3 | }
--------------------------------------------------------------------------------
/miniprogram/pages/user_settings/user_settings.less:
--------------------------------------------------------------------------------
1 | .optionList {
2 | width: 100%;
3 | margin-bottom: 100rpx;
4 |
5 | .option {
6 | width: 100%;
7 | height: 100rpx;
8 | display: flex;
9 | align-items: center;
10 | justify-content: space-between;
11 | background-color: #ffffff;
12 |
13 | .optionName {
14 | font-size: 32rpx;
15 | font-weight: 600;
16 | color: #515151;
17 | margin-left: 40rpx;
18 | }
19 |
20 | .optionValue {
21 | font-size: 28rpx;
22 | font-weight: 600;
23 | color: #757575;
24 | margin-right: 40rpx;
25 |
26 | .switch {
27 | zoom: 0.9;
28 | margin-right: -10rpx;
29 | }
30 | }
31 | }
32 |
33 | .wasTaped {
34 | background-color: rgba(150, 150, 150, 0.1);
35 | }
36 |
37 | .split {
38 | width: 100%;
39 | height: 20rpx;
40 | background-color: #f6f6f6;
41 | }
42 | }
43 |
44 | .mask {
45 | position: absolute;
46 | width: 100%;
47 | height: 100%;
48 | z-index: 100;
49 | background-color: rgba(0, 0, 0, 0.7);
50 | }
51 |
52 | .customizeWrapper {
53 | width: 750rpx;
54 | height: 500rpx;
55 | margin-top: 50rpx;
56 | position: relative;
57 | z-index: 101;
58 |
59 | .customValue {
60 | width: 600rpx;
61 | height: 80rpx;
62 | margin-top: 20rpx;
63 | margin-left: auto;
64 | margin-right: auto;
65 | padding: 0 30rpx;
66 | border: 2rpx solid #e2e2e2;
67 | border-radius: 10rpx;
68 | font-size: 36rpx;
69 | color: #515151;
70 | }
71 |
72 | .placeHolder{
73 | font-size: 30rpx;
74 | }
75 |
76 | .btn {
77 | width: 300rpx;
78 | height: 80rpx;
79 | margin-top: 100rpx;
80 | margin-left: auto;
81 | margin-right: auto;
82 | font-size: 36rpx;
83 | font-weight: 600;
84 | line-height: 80rpx;
85 | text-align: center;
86 | color: #ffffff;
87 | background-color: #90ced3;
88 | // background-color: #fd6802;
89 | border-radius: 10rpx;
90 | }
91 |
92 | .wasTaped {
93 | opacity: 0.7;
94 | }
95 | }
96 |
97 | .resetbtn {
98 | margin-top: 100rpx;
99 | margin-left: auto;
100 | margin-right: auto;
101 | }
--------------------------------------------------------------------------------
/miniprogram/pages/user_settings/user_settings.wxss:
--------------------------------------------------------------------------------
1 | .optionList {
2 | width: 100%;
3 | margin-bottom: 100rpx;
4 | }
5 | .optionList .option {
6 | width: 100%;
7 | height: 100rpx;
8 | display: flex;
9 | align-items: center;
10 | justify-content: space-between;
11 | background-color: #ffffff;
12 | }
13 | .optionList .option .optionName {
14 | font-size: 32rpx;
15 | font-weight: 600;
16 | color: #515151;
17 | margin-left: 40rpx;
18 | }
19 | .optionList .option .optionValue {
20 | font-size: 28rpx;
21 | font-weight: 600;
22 | color: #757575;
23 | margin-right: 40rpx;
24 | }
25 | .optionList .option .optionValue .switch {
26 | zoom: 0.9;
27 | margin-right: -10rpx;
28 | }
29 | .optionList .wasTaped {
30 | background-color: rgba(150, 150, 150, 0.1);
31 | }
32 | .optionList .split {
33 | width: 100%;
34 | height: 20rpx;
35 | background-color: #f6f6f6;
36 | }
37 | .mask {
38 | position: absolute;
39 | width: 100%;
40 | height: 100%;
41 | z-index: 100;
42 | background-color: rgba(0, 0, 0, 0.7);
43 | }
44 | .customizeWrapper {
45 | width: 750rpx;
46 | height: 500rpx;
47 | margin-top: 50rpx;
48 | position: relative;
49 | z-index: 101;
50 | }
51 | .customizeWrapper .customValue {
52 | width: 600rpx;
53 | height: 80rpx;
54 | margin-top: 20rpx;
55 | margin-left: auto;
56 | margin-right: auto;
57 | padding: 0 30rpx;
58 | border: 2rpx solid #e2e2e2;
59 | border-radius: 10rpx;
60 | font-size: 36rpx;
61 | color: #515151;
62 | }
63 | .customizeWrapper .placeHolder {
64 | font-size: 30rpx;
65 | }
66 | .customizeWrapper .btn {
67 | width: 300rpx;
68 | height: 80rpx;
69 | margin-top: 100rpx;
70 | margin-left: auto;
71 | margin-right: auto;
72 | font-size: 36rpx;
73 | font-weight: 600;
74 | line-height: 80rpx;
75 | text-align: center;
76 | color: #ffffff;
77 | background-color: #90ced3;
78 | border-radius: 10rpx;
79 | }
80 | .customizeWrapper .wasTaped {
81 | opacity: 0.7;
82 | }
83 | .resetbtn {
84 | margin-top: 100rpx;
85 | margin-left: auto;
86 | margin-right: auto;
87 | }
88 |
--------------------------------------------------------------------------------
/miniprogram/pages/word_detail/word_detail.js:
--------------------------------------------------------------------------------
1 | // pages/word_detail/word_detail.js
2 | import regeneratorRuntime, { async } from '../../lib/runtime/runtime';
3 | const wordApi = require("../../utils/wordApi.js")
4 | const word_utils = require("../../utils/word_utils.js")
5 |
6 | const app = getApp()
7 | const colorList = ['#ffb284', '#99c4d3', '#d0e6a5', '#86e3ce', '#ffdd95', '#fa897b',
8 | '#ccabd8', '#80beaf', '#b3ddd1', '#d1dce2', '#ef9d6d', '#c6c09c', '#f5cec7',
9 | '#ffc98b', '#b598c6', '#73c8dd', '#c56a4b']
10 | const innerAudioContext = wx.createInnerAudioContext({ useWebAudioImplement: true })
11 |
12 | Page({
13 |
14 | /**
15 | * 页面的初始数据
16 | */
17 | data: {
18 | // bgStyle: '#ffb284',
19 | // bgStyle: '#d1dce0',
20 | colorType: 16,
21 | word_id: 0,
22 | wordDetail: {},
23 | voiceUrl: '',
24 | isInNotebook: false,
25 | },
26 |
27 | /**
28 | * 生命周期函数--监听页面加载
29 | */
30 | onLoad: function (options) {
31 | wx.setNavigationBarTitle({
32 | title: '单词详情',
33 | })
34 |
35 | let colorType = Math.floor(Math.random() * 17)
36 | if (options.colorType) {
37 | colorType = options.colorType
38 | }
39 | wx.setNavigationBarColor({
40 | backgroundColor: colorList[colorType],
41 | frontColor: '#ffffff',
42 | })
43 | this.setData({ colorType })
44 |
45 | console.log(options)
46 | // let pages = getCurrentPages()
47 | // let thisPage = pages[pages.length-1]
48 | // let pagesOptions = thisPage.options
49 | // console.log(pagesOptions)
50 | let word_id = parseInt(options.word_id)
51 | this.getDetail(word_id)
52 | },
53 |
54 | async getDetail(word_id) {
55 | let user_id = -1
56 | let isLogin = app.globalData.isLogin
57 | if (isLogin) user_id = app.globalData.userInfo.user_id
58 | let res = await wordApi.getWordDetail({
59 | word_id,
60 | user_id,
61 | })
62 | let wordDetail = JSON.parse(JSON.stringify(res.data))
63 | console.log(wordDetail)
64 | wordDetail = word_utils.handleWordDetail(wordDetail)
65 | console.log(wordDetail)
66 | this.setData({
67 | wordDetail,
68 | isLogin,
69 | isInNotebook: wordDetail.in_notebook,
70 | })
71 | let voiceUrl = word_utils.getWordVoiceUrl(wordDetail.word)
72 | innerAudioContext.src = voiceUrl
73 | },
74 |
75 | playVoice() {
76 | innerAudioContext.stop()
77 | innerAudioContext.play()
78 | },
79 |
80 | // 调整是否添加到生词本
81 | toggleAddToNB: async function () {
82 | let add = this.data.isInNotebook
83 | let res = await wordApi.toggleAddToNB({
84 | user_id: app.globalData.userInfo.user_id,
85 | word_id: this.data.wordDetail.word_id,
86 | add: !add,
87 | })
88 | console.log(res)
89 | if (res.data) {
90 | this.setData({
91 | isInNotebook: !add,
92 | })
93 | } else {
94 | wx.showToast({
95 | title: '操作出错,请重试',
96 | icon: 'none',
97 | duration: 1000,
98 | })
99 | }
100 | },
101 |
102 | /**
103 | * 生命周期函数--监听页面初次渲染完成
104 | */
105 | onReady: function () {
106 |
107 | },
108 |
109 | /**
110 | * 生命周期函数--监听页面显示
111 | */
112 | onShow: function () {
113 |
114 | },
115 |
116 | /**
117 | * 生命周期函数--监听页面隐藏
118 | */
119 | onHide: function () {
120 |
121 | },
122 |
123 | /**
124 | * 生命周期函数--监听页面卸载
125 | */
126 | onUnload: function () {
127 | if (this.data.wordDetail.in_notebook != this.data.isInNotebook) app.globalData.updatedForOverview = true
128 | },
129 |
130 | /**
131 | * 页面相关事件处理函数--监听用户下拉动作
132 | */
133 | onPullDownRefresh: function () {
134 |
135 | },
136 |
137 | /**
138 | * 页面上拉触底事件的处理函数
139 | */
140 | onReachBottom: function () {
141 |
142 | },
143 |
144 | /**
145 | * 用户点击右上角分享
146 | */
147 | onShareAppMessage: function () {
148 |
149 | }
150 | })
--------------------------------------------------------------------------------
/miniprogram/pages/word_detail/word_detail.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {}
3 | }
--------------------------------------------------------------------------------
/miniprogram/pages/word_detail/word_detail.less:
--------------------------------------------------------------------------------
1 | .bgWrapper {
2 | width: 100%;
3 | height: 100%;
4 | position: fixed;
5 | z-index: -100;
6 | // background-image: linear-gradient(to bottom, #99c4d3, #FFFFFF);
7 | }
8 |
9 | .word {
10 | margin-top: 70rpx;
11 | margin-left: 40rpx;
12 | height: 80rpx;
13 | font-size: 64rpx;
14 | // font-family: 'Microsoft YaHei', 'Times New Roman', Times, serif;
15 | font-weight: 700;
16 | line-height: 70rpx;
17 | position: relative;
18 |
19 | .notebookBtn {
20 | position: absolute;
21 | top: 0;
22 | right: 10rpx;
23 | width: 80rpx;
24 | height: 80rpx;
25 | font-size: 46rpx;
26 | color: #f0f0f0;
27 | line-height: 80rpx;
28 | text-align: center;
29 | }
30 |
31 | .icon-addToNB-yes {
32 | color: #fb6a00;
33 | }
34 |
35 | .wasTaped-bottom {
36 | color: #ffffff;
37 | }
38 |
39 | .wasTaped-bottom1 {
40 | filter: grayscale(20%);
41 | }
42 | }
43 |
44 | .pron {
45 | margin-top: 20rpx;
46 | margin-left: 45rpx;
47 | height: 40rpx;
48 | line-height: 40rpx;
49 | font-size: 30rpx;
50 | // font-weight: 600;
51 | font-family: Arial, Helvetica, sans-serif;
52 | // color: #f6f6f6;
53 | color: #ffffff;
54 | }
55 |
56 | .tagContainer {
57 | width: 670rpx;
58 | margin-top: 10rpx;
59 | margin-bottom: 40rpx;
60 | margin-left: auto;
61 | margin-right: auto;
62 | display: flex;
63 | flex-wrap: wrap;
64 |
65 | .tag {
66 | margin-right: 10rpx;
67 | height: 40rpx;
68 | line-height: 40rpx;
69 | font-size: 26rpx;
70 | border-radius: 20rpx;
71 | background-color: rgba(0, 0, 0, 0.2);
72 | color: #e6e6e6;
73 | padding: 0rpx 20rpx;
74 | margin-top: 10rpx;
75 | }
76 | }
77 |
78 | .contentCard {
79 | width: 95%;
80 | margin-top: 20rpx;
81 | margin-left: auto;
82 | margin-right: auto;
83 | background-color: rgba(255, 255, 255, 0.6);
84 | border-radius: 20rpx;
85 | box-shadow: 2rpx 2rpx 10rpx rgba(0, 0, 0, 0.1);
86 |
87 | .title {
88 | width: 655rpx;
89 | margin-top: 26rpx;
90 | margin-left: auto;
91 | margin-right: auto;
92 | font-size: 36rpx;
93 | line-height: 60rpx;
94 | font-weight: 700;
95 | }
96 |
97 | .contentWrapper {
98 | width: 650rpx;
99 | margin-top: 14rpx;
100 | margin-left: auto;
101 | margin-right: auto;
102 | padding-bottom: 50rpx;
103 |
104 | .content {
105 | font-size: 32rpx;
106 | // font-family: Arial, Helvetica, sans-serif;
107 | color: #757575;
108 | // color: #515151;
109 | margin-bottom: 10rpx;
110 | // font-weight: 600;
111 | line-height: 40rpx;
112 |
113 | .exchangeName {
114 | display: inline-block;
115 | width: 220rpx;
116 | }
117 |
118 | .exchangeWord {
119 | display: inline-block;
120 | }
121 |
122 | .pos {
123 | font-size: 28rpx;
124 | color: #a0a0a0;
125 | margin-right: 10rpx;
126 | }
127 | }
128 | }
129 | }
130 |
131 | .last {
132 | margin-bottom: 50rpx;
133 | }
--------------------------------------------------------------------------------
/miniprogram/pages/word_detail/word_detail.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{wordDetail.word}}
8 |
10 |
11 |
12 | / {{wordDetail.phonetic}} /
14 |
15 | {{item}}
16 |
17 |
18 |
19 |
20 | 英文释义
21 |
22 |
23 |
24 | {{item.pos}}
25 | {{item.meaning}}
26 |
27 |
28 |
29 |
30 |
31 | 中文释义
32 |
33 |
34 | {{item.pos}}
35 | {{item.meaning}}
36 |
37 |
38 |
39 |
40 |
41 | 词形变换
42 |
43 |
44 |
46 | {{item.name}}
47 | {{item.word}}
48 | {{item.word}} 的{{item.name}}
49 |
50 |
51 |
--------------------------------------------------------------------------------
/miniprogram/pages/word_detail/word_detail.wxss:
--------------------------------------------------------------------------------
1 | .bgWrapper {
2 | width: 100%;
3 | height: 100%;
4 | position: fixed;
5 | z-index: -100;
6 | }
7 | .word {
8 | margin-top: 70rpx;
9 | margin-left: 40rpx;
10 | height: 80rpx;
11 | font-size: 64rpx;
12 | font-weight: 700;
13 | line-height: 70rpx;
14 | position: relative;
15 | }
16 | .word .notebookBtn {
17 | position: absolute;
18 | top: 0;
19 | right: 10rpx;
20 | width: 80rpx;
21 | height: 80rpx;
22 | font-size: 46rpx;
23 | color: #f0f0f0;
24 | line-height: 80rpx;
25 | text-align: center;
26 | }
27 | .word .icon-addToNB-yes {
28 | color: #fb6a00;
29 | }
30 | .word .wasTaped-bottom {
31 | color: #ffffff;
32 | }
33 | .word .wasTaped-bottom1 {
34 | filter: grayscale(20%);
35 | }
36 | .pron {
37 | margin-top: 20rpx;
38 | margin-left: 45rpx;
39 | height: 40rpx;
40 | line-height: 40rpx;
41 | font-size: 30rpx;
42 | font-family: Arial, Helvetica, sans-serif;
43 | color: #ffffff;
44 | }
45 | .tagContainer {
46 | width: 670rpx;
47 | margin-top: 10rpx;
48 | margin-bottom: 40rpx;
49 | margin-left: auto;
50 | margin-right: auto;
51 | display: flex;
52 | flex-wrap: wrap;
53 | }
54 | .tagContainer .tag {
55 | margin-right: 10rpx;
56 | height: 40rpx;
57 | line-height: 40rpx;
58 | font-size: 26rpx;
59 | border-radius: 20rpx;
60 | background-color: rgba(0, 0, 0, 0.2);
61 | color: #e6e6e6;
62 | padding: 0rpx 20rpx;
63 | margin-top: 10rpx;
64 | }
65 | .contentCard {
66 | width: 95%;
67 | margin-top: 20rpx;
68 | margin-left: auto;
69 | margin-right: auto;
70 | background-color: rgba(255, 255, 255, 0.6);
71 | border-radius: 20rpx;
72 | box-shadow: 2rpx 2rpx 10rpx rgba(0, 0, 0, 0.1);
73 | }
74 | .contentCard .title {
75 | width: 655rpx;
76 | margin-top: 26rpx;
77 | margin-left: auto;
78 | margin-right: auto;
79 | font-size: 36rpx;
80 | line-height: 60rpx;
81 | font-weight: 700;
82 | }
83 | .contentCard .contentWrapper {
84 | width: 650rpx;
85 | margin-top: 14rpx;
86 | margin-left: auto;
87 | margin-right: auto;
88 | padding-bottom: 50rpx;
89 | }
90 | .contentCard .contentWrapper .content {
91 | font-size: 32rpx;
92 | color: #757575;
93 | margin-bottom: 10rpx;
94 | line-height: 40rpx;
95 | }
96 | .contentCard .contentWrapper .content .exchangeName {
97 | display: inline-block;
98 | width: 220rpx;
99 | }
100 | .contentCard .contentWrapper .content .exchangeWord {
101 | display: inline-block;
102 | }
103 | .contentCard .contentWrapper .content .pos {
104 | font-size: 28rpx;
105 | color: #a0a0a0;
106 | margin-right: 10rpx;
107 | }
108 | .last {
109 | margin-bottom: 50rpx;
110 | }
111 |
--------------------------------------------------------------------------------
/miniprogram/pages/word_list/word_list.js:
--------------------------------------------------------------------------------
1 | // pages/word_list/word_list.js
2 | import regeneratorRuntime, { async } from '../../lib/runtime/runtime';
3 | const wordApi = require("../../utils/wordApi.js")
4 | const word_utils = require("../../utils/word_utils.js")
5 | const color = require("../../utils/color.js")
6 |
7 | const app = getApp()
8 |
9 | let typeParameter = {
10 | getBkLearnedWord: { navTitle: '本书已学', user_id: true, wd_bk_id: true },
11 | getBkMasteredWord: { navTitle: '本书已掌握', user_id: true, wd_bk_id: true },
12 | getBkUnlearnedWord: { navTitle: '本书未学', user_id: true, wd_bk_id: true },
13 | getBkWord: { navTitle: '本书全部单词', user_id: false, wd_bk_id: true },
14 | getLearnedWord: { navTitle: '已学单词', user_id: true, wd_bk_id: false },
15 | getMasteredWord: { navTitle: '已掌握单词', user_id: true, wd_bk_id: false },
16 | getReviewWord: { navTitle: '复习中单词', user_id: true, wd_bk_id: false },
17 | getNoteBookWord: { navTitle: '收藏夹', user_id: true, wd_bk_id: false },
18 | today: { navTitle: '今日学习&复习', user_id: true, wd_bk_id: false },
19 | }
20 |
21 | Page({
22 |
23 | /**
24 | * 页面的初始数据
25 | */
26 | data: {
27 | wordList: [],
28 | hasMore: true,
29 | learnHasMore: true,
30 | reviewHasMore: true,
31 | isToday: false,
32 | todayLearn: undefined,
33 | todayReview: undefined,
34 | todayType: -1,
35 | },
36 | skip: 0,
37 | learnSkip: undefined,
38 | reviewSkip: undefined,
39 | type: '',
40 |
41 | /**
42 | * 生命周期函数--监听页面加载
43 | */
44 | onLoad: function (options) {
45 | let type = this.options.type
46 | console.log('type', type)
47 |
48 | wx.setNavigationBarTitle({
49 | title: typeParameter[type].navTitle,
50 | })
51 | this.type = type
52 |
53 | if (type != 'today') {
54 | this.getData()
55 | } else {
56 | this.setData({
57 | todayType: 0
58 | })
59 | this.getTodayWord(0)
60 | this.getTodayWord(1)
61 | }
62 | },
63 |
64 | async getData() {
65 | let type = this.type
66 | if (!this.data.hasMore) return
67 | wx.showLoading({
68 | title: '加载中...',
69 | })
70 | let parameters = {}
71 | if (typeParameter[type].user_id) parameters.user_id = app.globalData.userInfo.user_id
72 | if (typeParameter[type].wd_bk_id) parameters.wd_bk_id = app.globalData.userInfo.l_book_id
73 | parameters.skip = this.skip
74 | let wordList = this.data.wordList
75 | console.log('parameters', parameters)
76 | let res = await wordApi[type](parameters)
77 |
78 | console.log('res', res)
79 |
80 | for (let i = 0; i < res.data.length; i++) {
81 | if (res.data[i].translation.indexOf('\n') != -1) {
82 | res.data[i].translation = res.data[i].translation.substring(0, res.data[i].translation.indexOf('\n'))
83 | }
84 | // console.log('rect length of:', directres[i], word_utils.getResObjRectLength(directres[i]))
85 | }
86 |
87 | wordList = wordList.concat(res.data)
88 | this.skip = wordList.length
89 | let hasMore = true
90 | if (res.data.length < 20) hasMore = false
91 |
92 | this.setData({
93 | wordList,
94 | hasMore
95 | })
96 | wx.hideLoading()
97 | },
98 |
99 | async getTodayWord(todayType) {
100 | if (todayType === undefined) todayType = this.data.todayType
101 | let hasMoreType = ['learnHasMore', 'reviewHasMore']
102 | if (!this.data[hasMoreType[todayType]]) return
103 | wx.showLoading({
104 | title: '加载中...',
105 | })
106 | let apiNameType = ['getTodayLearnWord', 'getTodayReviewWord']
107 | let skipType = ['getTodayLearnWord', 'getTodayReviewWord']
108 | let wordListType = ['todayLearn', 'todayReview']
109 | let type = apiNameType[todayType]
110 | let parameters = {}
111 | parameters.user_id = app.globalData.userInfo.user_id
112 | if (this[skipType[todayType]] === undefined) this[skipType[todayType]] = 0
113 | parameters.skip = this[skipType[todayType]]
114 | if (this.data[wordListType[todayType]] === undefined) this.data[wordListType[todayType]] = []
115 | let wordList = this.data[wordListType[todayType]]
116 |
117 | console.log('parameters', parameters)
118 | let res = await wordApi[type](parameters)
119 |
120 | console.log('res', res)
121 |
122 | for (let i = 0; i < res.data.length; i++) {
123 | if (res.data[i].translation.indexOf('\n') != -1) {
124 | res.data[i].translation = res.data[i].translation.substring(0, res.data[i].translation.indexOf('\n'))
125 | }
126 | // console.log('rect length of:', directres[i], word_utils.getResObjRectLength(directres[i]))
127 | }
128 |
129 | wordList = wordList.concat(res.data)
130 | this[skipType[todayType]] = wordList.length
131 | let hasMore = true
132 | if (res.data.length < 20) hasMore = false
133 |
134 | let updateData = {}
135 | updateData[wordListType[todayType]] = wordList
136 | updateData[hasMoreType[todayType]] = hasMore
137 |
138 | this.setData(updateData)
139 | wx.hideLoading()
140 | },
141 |
142 | getWordDetail(e) {
143 | let wordListName = 'wordList'
144 | if (this.data.todayType != -1) {
145 | let wordListType = ['todayLearn', 'todayReview']
146 | wordListName = wordListType[this.data.todayType]
147 | }
148 | let index = e.currentTarget.dataset.index
149 | let word_id = this.data[wordListName][index].word_id
150 | wx.navigateTo({
151 | url: `../word_detail/word_detail?word_id=${word_id}`,
152 | })
153 | },
154 |
155 | changeType() {
156 | this.setData({
157 | todayType: (this.data.todayType + 1) % 2
158 | })
159 | },
160 |
161 | /**
162 | * 页面上拉触底事件的处理函数
163 | */
164 | onReachBottom: function () {
165 | console.log('onReachBottom')
166 | if (this.data.todayType == -1) {
167 | this.getData()
168 | } else {
169 | this.getTodayWord()
170 | }
171 | },
172 |
173 | /**
174 | * 生命周期函数--监听页面初次渲染完成
175 | */
176 | onReady: function () {
177 |
178 | },
179 |
180 | /**
181 | * 生命周期函数--监听页面显示
182 | */
183 | onShow: function () {
184 |
185 | },
186 |
187 | /**
188 | * 生命周期函数--监听页面隐藏
189 | */
190 | onHide: function () {
191 |
192 | },
193 |
194 | /**
195 | * 生命周期函数--监听页面卸载
196 | */
197 | onUnload: function () {
198 |
199 | },
200 |
201 | /**
202 | * 页面相关事件处理函数--监听用户下拉动作
203 | */
204 | onPullDownRefresh: function () {
205 |
206 | },
207 |
208 | /**
209 | * 用户点击右上角分享
210 | */
211 | onShareAppMessage: function () {
212 |
213 | }
214 | })
--------------------------------------------------------------------------------
/miniprogram/pages/word_list/word_list.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {}
3 | }
--------------------------------------------------------------------------------
/miniprogram/pages/word_list/word_list.less:
--------------------------------------------------------------------------------
1 | @wordItemHeight: 80rpx;
2 |
3 | .wordWrapper {
4 | // margin-top: 10rpx;
5 | width: 100%;
6 | // margin-bottom: 10rpx;
7 | // margin-bottom: 130rpx;
8 | // background-color: #ffffff;
9 |
10 | .wordItem {
11 | // width: 670rpx;
12 | width: 750rpx;
13 | height: wordItemHeight;
14 | // margin-left: auto;
15 | // margin-right: auto;
16 | background-color: #ffffff;
17 | // margin-bottom: 6rpx;
18 | display: flex;
19 | align-items: center;
20 | justify-content: center;
21 | font-weight: 600;
22 |
23 | .dot {
24 | width: 16rpx;
25 | height: 16rpx;
26 | border-radius: 8rpx;
27 | background-color: #fd6802;
28 | // margin-left: 40rpx;
29 | margin-right: 24rpx;
30 | }
31 |
32 | .wordInfo {
33 | width: 630rpx; // 750-40*2-20-20
34 | height: @wordItemHeight;
35 | line-height: @wordItemHeight;
36 | font-size: 32rpx;
37 | // padding-left: 40rpx;
38 | // padding-right: 40rpx;
39 | display: -webkit-box;
40 | overflow: hidden;
41 | -webkit-box-orient: vertical;
42 | -webkit-line-clamp: 1;
43 | // border-bottom: solid 4rpx #f6f6f6;
44 |
45 | .word {
46 | // color: #333333;
47 | color: #757575;
48 | }
49 |
50 | .trans {
51 | // color: #757575;
52 | color: #8a8a8a;
53 | font-size: 28rpx;
54 | }
55 | }
56 | }
57 |
58 | .wasTaped {
59 | background-color: #e6e6e6;
60 | }
61 |
62 | .tips {
63 | width: 100%;
64 | height: 100rpx;
65 | color: #8a8a8a;
66 | font-size: 28rpx;
67 | display: flex;
68 | align-items: center;
69 | justify-content: center;
70 | }
71 |
72 | .changeType {
73 | width: 100%;
74 | height: 100rpx;
75 | font-size: 32rpx;
76 | display: flex;
77 | background-color: #ffffff;
78 | position: fixed;
79 |
80 | .type {
81 | width: 50%;
82 | height: 100rpx;
83 | display: flex;
84 | flex-direction: column;
85 | align-items: center;
86 | justify-content: center;
87 |
88 | .text {
89 | font-size: 26rpx;
90 | color: #8a8a8a;
91 | font-weight: 600;
92 | }
93 |
94 | .decorate {
95 | margin-top: 10rpx;
96 | width: 30rpx;
97 | height: 10rpx;
98 | border-radius: 5rpx;
99 | background-color: #fd6802;
100 | }
101 |
102 | .active {
103 | font-size: 30rpx;
104 | color: #515151;
105 | margin-top: 10rpx;
106 | }
107 | }
108 | }
109 |
110 | .forToday {
111 | width: 100%;
112 | margin-top: 100rpx;
113 | }
114 |
115 | .bottom {
116 | width: 100%;
117 | height: 100rpx;
118 | }
119 | }
--------------------------------------------------------------------------------
/miniprogram/pages/word_list/word_list.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
8 | {{item.word}}
9 | {{item.translation}}
10 |
11 |
12 | 没有更多了哦~
13 | ~
14 |
15 |
16 |
17 | 今日学习
18 |
19 |
20 |
21 | 今日复习
22 |
23 |
24 |
25 |
26 |
28 |
29 |
30 | {{item.word}}
31 | {{item.translation}}
32 |
33 |
34 |
35 | 没有更多了哦~
36 |
37 |
--------------------------------------------------------------------------------
/miniprogram/pages/word_list/word_list.wxss:
--------------------------------------------------------------------------------
1 | .wordWrapper {
2 | width: 100%;
3 | }
4 | .wordWrapper .wordItem {
5 | width: 750rpx;
6 | height: wordItemHeight;
7 | background-color: #ffffff;
8 | display: flex;
9 | align-items: center;
10 | justify-content: center;
11 | font-weight: 600;
12 | }
13 | .wordWrapper .wordItem .dot {
14 | width: 16rpx;
15 | height: 16rpx;
16 | border-radius: 8rpx;
17 | background-color: #fd6802;
18 | margin-right: 24rpx;
19 | }
20 | .wordWrapper .wordItem .wordInfo {
21 | width: 630rpx;
22 | height: 80rpx;
23 | line-height: 80rpx;
24 | font-size: 32rpx;
25 | display: -webkit-box;
26 | overflow: hidden;
27 | -webkit-box-orient: vertical;
28 | -webkit-line-clamp: 1;
29 | }
30 | .wordWrapper .wordItem .wordInfo .word {
31 | color: #757575;
32 | }
33 | .wordWrapper .wordItem .wordInfo .trans {
34 | color: #8a8a8a;
35 | font-size: 28rpx;
36 | }
37 | .wordWrapper .wasTaped {
38 | background-color: #e6e6e6;
39 | }
40 | .wordWrapper .tips {
41 | width: 100%;
42 | height: 100rpx;
43 | color: #8a8a8a;
44 | font-size: 28rpx;
45 | display: flex;
46 | align-items: center;
47 | justify-content: center;
48 | }
49 | .wordWrapper .changeType {
50 | width: 100%;
51 | height: 100rpx;
52 | font-size: 32rpx;
53 | display: flex;
54 | background-color: #ffffff;
55 | position: fixed;
56 | }
57 | .wordWrapper .changeType .type {
58 | width: 50%;
59 | height: 100rpx;
60 | display: flex;
61 | flex-direction: column;
62 | align-items: center;
63 | justify-content: center;
64 | }
65 | .wordWrapper .changeType .type .text {
66 | font-size: 26rpx;
67 | color: #8a8a8a;
68 | font-weight: 600;
69 | }
70 | .wordWrapper .changeType .type .decorate {
71 | margin-top: 10rpx;
72 | width: 30rpx;
73 | height: 10rpx;
74 | border-radius: 5rpx;
75 | background-color: #fd6802;
76 | }
77 | .wordWrapper .changeType .type .active {
78 | font-size: 30rpx;
79 | color: #515151;
80 | margin-top: 10rpx;
81 | }
82 | .wordWrapper .forToday {
83 | width: 100%;
84 | margin-top: 100rpx;
85 | }
86 | .wordWrapper .bottom {
87 | width: 100%;
88 | height: 100rpx;
89 | }
90 |
--------------------------------------------------------------------------------
/miniprogram/sitemap.json:
--------------------------------------------------------------------------------
1 | {
2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
3 | "rules":[{
4 | "action": "allow",
5 | "page": "pages/index/index"
6 | }, {
7 | "action": "disallow",
8 | "page": "*"
9 | }]
10 | }
--------------------------------------------------------------------------------
/miniprogram/static/color.wxss:
--------------------------------------------------------------------------------
1 | /* for #ffb284 */
2 | .bg-linear-0 {
3 | background-image: linear-gradient(to bottom, #ffb284, #FFFFFF);
4 | }
5 |
6 | .word-color-0 {
7 | color: #ee5b20;
8 | }
9 |
10 | .content-title-color-0 {
11 | color: #fa804f;
12 | }
13 |
14 | .bg-color-light-0 {
15 | background-color: #fa804f;
16 | }
17 |
18 | /* for #99c4d3 */
19 | .bg-linear-1 {
20 | background-image: linear-gradient(to bottom, #99c4d3, #FFFFFF);
21 | }
22 |
23 | .word-color-1 {
24 | color: #166381;
25 | }
26 |
27 | .content-title-color-1 {
28 | color: #66a8eb;
29 | }
30 |
31 | .bg-color-light-1 {
32 | background-color: #66a8eb;
33 | }
34 |
35 | /* for #d0e6a5 */
36 | .bg-linear-2 {
37 | background-image: linear-gradient(to bottom, #d0e6a5, #FFFFFF);
38 | }
39 |
40 | .word-color-2 {
41 | color: #7a9e32;
42 | }
43 |
44 | .content-title-color-2 {
45 | color: #adc57c;
46 | }
47 |
48 | .bg-color-light-2 {
49 | background-color: #adc57c;
50 | }
51 |
52 | /* for #86e3ce */
53 | .bg-linear-3 {
54 | background-image: linear-gradient(to bottom, #86e3ce, #FFFFFF);
55 | }
56 |
57 | .word-color-3 {
58 | color: #30a58a;
59 | }
60 |
61 | .content-title-color-3 {
62 | color: #60d4b9;
63 | }
64 |
65 | .bg-color-light-3 {
66 | background-color: #60d4b9;
67 | }
68 |
69 | /* for #ffdd95 */
70 | .bg-linear-4 {
71 | background-image: linear-gradient(to bottom, #ffdd95, #FFFFFF);
72 | }
73 |
74 | .word-color-4 {
75 | color: #c79b3d;
76 | }
77 |
78 | .content-title-color-4 {
79 | color: #f0c76f;
80 | }
81 |
82 | .bg-color-light-4 {
83 | background-color: #f0c76f;
84 | }
85 |
86 | /* for #fa897b */
87 | .bg-linear-5 {
88 | background-image: linear-gradient(to bottom, #fa897b, #FFFFFF);
89 | }
90 |
91 | .word-color-5 {
92 | color: #d84c39;
93 | }
94 |
95 | .content-title-color-5 {
96 | color: #fd7361;
97 | }
98 |
99 | .bg-color-light-5 {
100 | background-color: #fd7361;
101 | }
102 |
103 | /* for #ccabd8 */
104 | .bg-linear-6 {
105 | background-image: linear-gradient(to bottom, #ccabd8, #FFFFFF);
106 | }
107 |
108 | .word-color-6 {
109 | color: #b163ce;
110 | }
111 |
112 | .content-title-color-6 {
113 | color: #be78d8;
114 | }
115 |
116 | .bg-color-light-6 {
117 | background-color: #be78d8;
118 | }
119 |
120 | /* for #80beaf */
121 | .bg-linear-7 {
122 | background-image: linear-gradient(to bottom, #80beaf, #FFFFFF);
123 | }
124 |
125 | .word-color-7 {
126 | color: #46927f;
127 | }
128 |
129 | .content-title-color-7 {
130 | color: #61cfb4;
131 | }
132 |
133 | .bg-color-light-7 {
134 | background-color: #61cfb4;
135 | }
136 |
137 | /* for #b3ddd1 */
138 | .bg-linear-8 {
139 | background-image: linear-gradient(to bottom, #b3ddd1, #FFFFFF);
140 | }
141 |
142 | .word-color-8 {
143 | color: #459780;
144 | }
145 |
146 | .content-title-color-8 {
147 | color: #7adabe;
148 | }
149 |
150 | .bg-color-light-8 {
151 | background-color: #7adabe;
152 | }
153 |
154 | /* for #d1dce2 */
155 | .bg-linear-9 {
156 | background-image: linear-gradient(to bottom, #d1dce2, #FFFFFF);
157 | }
158 |
159 | .word-color-9 {
160 | color: #6fa7c5;
161 | }
162 |
163 | .content-title-color-9 {
164 | color: #95bfd6;
165 | }
166 |
167 | .bg-color-light-9 {
168 | background-color: #95bfd6;
169 | }
170 |
171 | /* for #ef9d6d */
172 | .bg-linear-10 {
173 | background-image: linear-gradient(to bottom, #ef9d6d, #FFFFFF);
174 | }
175 |
176 | .word-color-10 {
177 | color: #c4632c;
178 | }
179 |
180 | .content-title-color-10 {
181 | color: #f38b4e;
182 | }
183 |
184 | .bg-color-light-10 {
185 | background-color: #f38b4e;
186 | }
187 |
188 | /* for #c6c09c */
189 | .bg-linear-11 {
190 | background-image: linear-gradient(to bottom, #c6c09c, #FFFFFF);
191 | }
192 |
193 | .word-color-11 {
194 | color: #ac9f5a;
195 | }
196 |
197 | .content-title-color-11 {
198 | color: #c7b861;
199 | }
200 |
201 | .bg-color-light-11 {
202 | background-color: #c7b861;
203 | }
204 |
205 | /* for #f5cec7 */
206 | .bg-linear-12 {
207 | background-image: linear-gradient(to bottom, #f5cec7, #FFFFFF);
208 | }
209 |
210 | .word-color-12 {
211 | color: #c7938a;
212 | }
213 |
214 | .content-title-color-12 {
215 | color: #f0b2a7;
216 | }
217 |
218 | .bg-color-light-12 {
219 | background-color: #f0b2a7;
220 | }
221 |
222 | /* for #ffc98b */
223 | .bg-linear-13 {
224 | background-image: linear-gradient(to bottom, #ffc98b, #FFFFFF);
225 | }
226 |
227 | .word-color-13 {
228 | color: #ce9553;
229 | }
230 |
231 | .content-title-color-13 {
232 | color: #f1b167;
233 | }
234 |
235 | .bg-color-light-13 {
236 | background-color: #f1b167;
237 | }
238 |
239 | /* for #b598c6 */
240 | .bg-linear-14 {
241 | background-image: linear-gradient(to bottom, #b598c6, #FFFFFF);
242 | }
243 |
244 | .word-color-14 {
245 | color: #866699;
246 | }
247 |
248 | .content-title-color-14 {
249 | color: #ae78ce;
250 | }
251 |
252 | .bg-color-light-14 {
253 | background-color: #ae78ce;
254 | }
255 |
256 | /* for #73c8dd */
257 | .bg-linear-15 {
258 | background-image: linear-gradient(to bottom, #73c8dd, #FFFFFF);
259 | }
260 |
261 | .word-color-15 {
262 | color: #4899ad;
263 | }
264 |
265 | .content-title-color-15 {
266 | color: #50c1dd;
267 | }
268 |
269 | .bg-color-light-15 {
270 | background-color: #50c1dd;
271 | }
272 |
273 | /* for #c56a4b */
274 | .bg-linear-16 {
275 | background-image: linear-gradient(to bottom, #c56a4b, #FFFFFF);
276 | }
277 |
278 | .word-color-16 {
279 | color: #a14323;
280 | }
281 |
282 | .content-title-color-16 {
283 | color: #e26e47;
284 | }
285 |
286 | .bg-color-light-16 {
287 | background-color: #e26e47;
288 | }
289 |
290 |
--------------------------------------------------------------------------------
/miniprogram/static/iconfont.wxss:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: "iconfont"; /* Project id 2904327 */
3 | src: url('//at.alicdn.com/t/font_2904327_ob31m8hc8ul.woff2?t=1641287710427') format('woff2'),
4 | url('//at.alicdn.com/t/font_2904327_ob31m8hc8ul.woff?t=1641287710427') format('woff'),
5 | url('//at.alicdn.com/t/font_2904327_ob31m8hc8ul.ttf?t=1641287710427') format('truetype');
6 | }
7 |
8 | .iconfont {
9 | font-family: "iconfont" !important;
10 | font-size: 16px;
11 | font-style: normal;
12 | -webkit-font-smoothing: antialiased;
13 | -moz-osx-font-smoothing: grayscale;
14 | }
15 |
16 | .icon-rotate:before {
17 | content: "\e61d";
18 | }
19 |
20 | .icon-settings:before {
21 | content: "\e8b7";
22 | }
23 |
24 | .icon-pwd:before {
25 | content: "\e600";
26 | }
27 |
28 | .icon-toDetail:before {
29 | content: "\e775";
30 | }
31 |
32 | .icon-camera:before {
33 | content: "\e77f";
34 | }
35 |
36 | .icon-settings_old:before {
37 | content: "\e892";
38 | }
39 |
40 | .icon-nickname:before {
41 | content: "\e608";
42 | }
43 |
44 | .icon-learned:before {
45 | content: "\e721";
46 | }
47 |
48 | .icon-addToNB-no:before {
49 | content: "\e8b9";
50 | }
51 |
52 | .icon-addToNB-yes:before {
53 | content: "\e8c6";
54 | }
55 |
56 | .icon-skip:before {
57 | content: "\e622";
58 | }
59 |
60 | .icon-getDetail:before {
61 | content: "\e68e";
62 | }
63 |
64 | .icon-cancel:before {
65 | content: "\e668";
66 | }
67 |
68 | .icon-delete:before {
69 | content: "\e621";
70 | }
71 |
72 | .icon-bin:before {
73 | content: "\e652";
74 | }
75 |
76 | .icon-search1:before {
77 | content: "\e8d6";
78 | }
79 |
80 | .icon-search:before {
81 | content: "\e60c";
82 | }
83 |
84 | .icon-sound:before {
85 | content: "\e7a8";
86 | }
87 |
--------------------------------------------------------------------------------
/miniprogram/static/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/miniprogram/static/images/logo.png
--------------------------------------------------------------------------------
/miniprogram/static/images/tab-learn-007BFF.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/miniprogram/static/images/tab-learn-007BFF.png
--------------------------------------------------------------------------------
/miniprogram/static/images/tab-learn-3880B7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/miniprogram/static/images/tab-learn-3880B7.png
--------------------------------------------------------------------------------
/miniprogram/static/images/tab-learn-62BEFF.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/miniprogram/static/images/tab-learn-62BEFF.png
--------------------------------------------------------------------------------
/miniprogram/static/images/tab-learn-A6D6FA.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/miniprogram/static/images/tab-learn-A6D6FA.png
--------------------------------------------------------------------------------
/miniprogram/static/images/tab-learn-CDCDCD.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/miniprogram/static/images/tab-learn-CDCDCD.png
--------------------------------------------------------------------------------
/miniprogram/static/images/tab-learn-F6F6F6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/miniprogram/static/images/tab-learn-F6F6F6.png
--------------------------------------------------------------------------------
/miniprogram/static/images/tab-learn-FFFFFF.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/miniprogram/static/images/tab-learn-FFFFFF.png
--------------------------------------------------------------------------------
/miniprogram/static/images/tab-overview-007BFF.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/miniprogram/static/images/tab-overview-007BFF.png
--------------------------------------------------------------------------------
/miniprogram/static/images/tab-overview-3880B7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/miniprogram/static/images/tab-overview-3880B7.png
--------------------------------------------------------------------------------
/miniprogram/static/images/tab-overview-62BEFF.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/miniprogram/static/images/tab-overview-62BEFF.png
--------------------------------------------------------------------------------
/miniprogram/static/images/tab-overview-A6D6FA.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/miniprogram/static/images/tab-overview-A6D6FA.png
--------------------------------------------------------------------------------
/miniprogram/static/images/tab-overview-CDCDCD.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/miniprogram/static/images/tab-overview-CDCDCD.png
--------------------------------------------------------------------------------
/miniprogram/static/images/tab-user-007BFF.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/miniprogram/static/images/tab-user-007BFF.png
--------------------------------------------------------------------------------
/miniprogram/static/images/tab-user-3880B7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/miniprogram/static/images/tab-user-3880B7.png
--------------------------------------------------------------------------------
/miniprogram/static/images/tab-user-62BEFF.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/miniprogram/static/images/tab-user-62BEFF.png
--------------------------------------------------------------------------------
/miniprogram/static/images/tab-user-A6D6FA.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/miniprogram/static/images/tab-user-A6D6FA.png
--------------------------------------------------------------------------------
/miniprogram/static/images/tab-user-CDCDCD.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mint-green/UnlearnableWord/b7aabd362e138cc9b3c86d1ede3c958e222c5c10/miniprogram/static/images/tab-user-CDCDCD.png
--------------------------------------------------------------------------------
/miniprogram/utils/color.js:
--------------------------------------------------------------------------------
1 | const colorList = ['#ffb284', '#99c4d3', '#d0e6a5', '#86e3ce', '#ffdd95', '#fa897b',
2 | '#ccabd8', '#80beaf', '#b3ddd1', '#d1dce2', '#ef9d6d', '#c6c09c', '#f5cec7',
3 | '#ffc98b', '#b598c6', '#73c8dd', '#c56a4b']
4 |
5 | const deeperColorList = ['#ee5b20', '#166381', '#7a9e32', '#30a58a', '#c79b3d', '#d84c39',
6 | '#b163ce', '#46927f', '#459780', '#6fa7c5', '#c4632c', '#ac9f5a', '#c7938a',
7 | '#ce9553', '#866699', '#4899ad', '#a14323']
8 |
9 | module.exports = {
10 | colorList: colorList,
11 | deeperColorList: deeperColorList,
12 | }
--------------------------------------------------------------------------------
/miniprogram/utils/format_time.js:
--------------------------------------------------------------------------------
1 | // 传入时间的毫秒数(date.getTime())获取时间详情
2 |
3 | const formatTime = (time) => {
4 | var date = new Date(time)
5 | var y = date.getFullYear()
6 | var m = date.getMonth() + 1
7 | var d = date.getDate()
8 | var h = date.getHours()
9 | var min = date.getMinutes()
10 | var s = date.getSeconds()
11 | var timeStr = y + "-" + enterZero(m) + "-" + enterZero(d) + " " + enterZero(h) + ":" + enterZero(min) + ":" + enterZero(s)
12 | return timeStr
13 | }
14 |
15 | const formatDate = (time) => {
16 | var date = new Date(time)
17 | var y = date.getFullYear()
18 | var m = date.getMonth() + 1
19 | var d = date.getDate()
20 | var dateStr = y + "-" + enterZero(m) + "-" + enterZero(d)
21 | return dateStr
22 | }
23 |
24 | const getDayZeroTime = (time = new Date().getTime()) => {
25 | var date = new Date(time)
26 | date.setMilliseconds(0)
27 | date.setSeconds(0)
28 | date.setMinutes(0)
29 | date.setHours(0)
30 | return date.getTime()
31 | }
32 |
33 | const dateNum = (time) => {
34 | var date = new Date(time)
35 | var y = date.getFullYear()
36 | var m = date.getMonth() + 1
37 | var d = date.getDate()
38 | var num = y * 10000 + m * 100 + d
39 | return num
40 | }
41 |
42 | const enterZero = (num) => {
43 | num = Math.abs(num)
44 | if (num <= 9) {
45 | num = "0" + num
46 | }
47 | return num
48 | }
49 |
50 | module.exports = {
51 | formatTime: formatTime,
52 | formatDate: formatDate,
53 | dateNum: dateNum,
54 | getDayZeroTime: getDayZeroTime,
55 | }
--------------------------------------------------------------------------------
/miniprogram/utils/response_content.js:
--------------------------------------------------------------------------------
1 | const SUCCESS = { errorcode: 100, errormsg: "success" } //成功
2 | const LOGINOK = { errorcode: 1, errormsg: "Login successfully" } //登录成功
3 | const REGISTEROK= { errorcode: 2, errormsg: "Register successfully" } //注册成功
4 | const DBERR = { errorcode: -1, errormsg: "Database error!" } //数据库操作失败
5 | const ROUTERERR = { errorcode: -2, errormsg: "Wrong router name" } //路由名字有误
6 | const LOGINERR = { errorcode: -3, errormsg: "Wrong username or pwd" } //登录信息有误
7 | const DATAERR = { errorcode: -4, errormsg: "Wrong data!" } //数据有误
8 | const UNKOWNERR = { errorcode: -100, errormsg: "Unkown error!" } //出现未知错误
9 |
10 |
11 | module.exports={
12 | SUCCESS: SUCCESS,
13 | LOGINOK: LOGINOK,
14 | REGISTEROK: REGISTEROK,
15 | DBERR: DBERR,
16 | ROUTERERR: ROUTERERR,
17 | LOGINERR: LOGINERR,
18 | DATAERR: DATAERR,
19 | UNKOWNERR: UNKOWNERR,
20 | }
21 |
--------------------------------------------------------------------------------
/miniprogram/utils/userApi.js:
--------------------------------------------------------------------------------
1 | const checkUsernameInDB = (data) => {
2 | data.$url = 'checkUsername'
3 | return new Promise((resolve, reject) => {
4 | wx.cloud.callFunction({
5 | name: "userRouter",
6 | data,
7 | success: (res) => {
8 | resolve(res.result)
9 | },
10 | fail: (err) => {
11 | reject(err)
12 | }
13 | })
14 | })
15 | }
16 |
17 | const register = (data) => {
18 | data.$url = 'register'
19 | return new Promise((resolve, reject) => {
20 | wx.cloud.callFunction({
21 | name: "userRouter",
22 | data,
23 | success: (res) => {
24 | resolve(res.result)
25 | },
26 | fail: (err) => {
27 | reject(err)
28 | }
29 | })
30 | })
31 | }
32 |
33 | const login = (data) => {
34 | data.$url = 'login'
35 | return new Promise((resolve, reject) => {
36 | wx.cloud.callFunction({
37 | name: "userRouter",
38 | data,
39 | success: (res) => {
40 | resolve(res.result)
41 | },
42 | fail: (err) => {
43 | reject(err)
44 | }
45 | })
46 | })
47 | }
48 |
49 | const getWxUserInfo = () => {
50 | return new Promise((resolve, reject) => {
51 | wx.getUserProfile({
52 | desc: '信息用于快捷登录小程序',
53 | success: (res) => {
54 | resolve(res)
55 | },
56 | fail: (err) => {
57 | console.log('获取微信用户信息失败')
58 | reject(err)
59 | }
60 | })
61 | })
62 | }
63 |
64 | const wxLogin = (data) => {
65 | data.$url = 'wxLogin'
66 | return new Promise((resolve, reject) => {
67 | wx.cloud.callFunction({
68 | name: "userRouter",
69 | data,
70 | success: (res) => {
71 | resolve(res.result)
72 | },
73 | fail: (err) => {
74 | reject(err)
75 | }
76 | })
77 | })
78 | }
79 |
80 | const changeWordBook = (data) => {
81 | // let data = {}
82 | data.$url = 'changeWordBook'
83 | return new Promise((resolve, reject) => {
84 | wx.cloud.callFunction({
85 | name: "userRouter",
86 | data,
87 | success: (res) => {
88 | resolve(res.result)
89 | },
90 | fail: (err) => {
91 | reject(err)
92 | }
93 | })
94 | })
95 | }
96 |
97 | const changeSettings = (data) => {
98 | // let data = {}
99 | data.$url = 'changeSettings'
100 | return new Promise((resolve, reject) => {
101 | wx.cloud.callFunction({
102 | name: "userRouter",
103 | data,
104 | success: (res) => {
105 | resolve(res.result)
106 | },
107 | fail: (err) => {
108 | reject(err)
109 | }
110 | })
111 | })
112 | }
113 |
114 | const getUserInfoViaId = (data) => {
115 | // let data = {}
116 | data.$url = 'getUserInfoViaId'
117 | return new Promise((resolve, reject) => {
118 | wx.cloud.callFunction({
119 | name: "userRouter",
120 | data,
121 | success: (res) => {
122 | resolve(res.result)
123 | },
124 | fail: (err) => {
125 | reject(err)
126 | }
127 | })
128 | })
129 | }
130 |
131 | const changeUserInfo = (data) => {
132 | // let data = {}
133 | data.$url = 'changeUserInfo'
134 | return new Promise((resolve, reject) => {
135 | wx.cloud.callFunction({
136 | name: "userRouter",
137 | data,
138 | success: (res) => {
139 | resolve(res.result)
140 | },
141 | fail: (err) => {
142 | reject(err)
143 | }
144 | })
145 | })
146 | }
147 |
148 | const changePwd = (data) => {
149 | // let data = {}
150 | data.$url = 'changePwd'
151 | return new Promise((resolve, reject) => {
152 | wx.cloud.callFunction({
153 | name: "userRouter",
154 | data,
155 | success: (res) => {
156 | resolve(res.result)
157 | },
158 | fail: (err) => {
159 | reject(err)
160 | }
161 | })
162 | })
163 | }
164 |
165 | const uploadFile = (imgSrc) => {
166 | return new Promise((resolve, reject) => {
167 | let fileExtName = /\.\w+$/.exec(imgSrc)[0] //获取文件格式(后缀名)
168 | wx.cloud.uploadFile({
169 | cloudPath: 'avatar_pic/' + Date.now() + '-' + Math.floor(Math.random() * 10000) + fileExtName, //生成添加时间戳后的随机序列作为文件名
170 | filePath: imgSrc,
171 | success: (res) => {
172 | resolve(res)
173 | },
174 | fail: (err) => {
175 | console.log(err)
176 | reject(err)
177 | }
178 | })
179 | })
180 | }
181 |
182 | const downloadFile = (imgSrc) => {
183 | return new Promise((resolve, reject) => {
184 | wx.downloadFile({
185 | url: imgSrc,
186 | success(res) {
187 | // 只要服务器有响应数据,就会把响应内容写入文件并进入 success 回调,业务需要自行判断是否下载到了想要的内容
188 | if (res.statusCode === 200) {
189 | // console.log(res)
190 | resolve(res)
191 | }
192 | },
193 | fail: (err) => {
194 | console.log(err)
195 | reject(err)
196 | }
197 | })
198 | })
199 | }
200 |
201 | module.exports = {
202 | checkUsernameInDB: checkUsernameInDB,
203 | register: register,
204 | login: login,
205 | getWxUserInfo: getWxUserInfo,
206 | wxLogin: wxLogin,
207 | changeWordBook: changeWordBook,
208 | changeSettings: changeSettings,
209 | getUserInfoViaId: getUserInfoViaId,
210 | changeUserInfo: changeUserInfo,
211 | changePwd: changePwd,
212 | downloadFile: downloadFile,
213 | uploadFile: uploadFile,
214 | }
215 |
--------------------------------------------------------------------------------
/project.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "miniprogramRoot": "miniprogram/",
3 | "cloudfunctionRoot": "cloudfunctions/",
4 | "setting": {
5 | "urlCheck": true,
6 | "es6": true,
7 | "enhance": true,
8 | "postcss": true,
9 | "preloadBackgroundData": false,
10 | "minified": true,
11 | "newFeature": true,
12 | "coverView": true,
13 | "nodeModules": false,
14 | "autoAudits": false,
15 | "showShadowRootInWxmlPanel": true,
16 | "scopeDataCheck": false,
17 | "uglifyFileName": false,
18 | "checkInvalidKey": true,
19 | "checkSiteMap": true,
20 | "uploadWithSourceMap": true,
21 | "compileHotReLoad": false,
22 | "lazyloadPlaceholderEnable": false,
23 | "useMultiFrameRuntime": true,
24 | "useApiHook": true,
25 | "useApiHostProcess": true,
26 | "babelSetting": {
27 | "ignore": [],
28 | "disablePlugins": [],
29 | "outputPath": ""
30 | },
31 | "enableEngineNative": false,
32 | "useIsolateContext": false,
33 | "userConfirmedBundleSwitch": false,
34 | "packNpmManually": false,
35 | "packNpmRelationList": [],
36 | "minifyWXSS": true,
37 | "disableUseStrict": false,
38 | "minifyWXML": true,
39 | "showES6CompileOption": false,
40 | "useCompilerPlugins": false
41 | },
42 | "appid": "wx9d444179caa0a6b5",
43 | "projectname": "%E5%AD%A6%E4%B8%8D%E4%BC%9A%E5%8D%95%E8%AF%8D",
44 | "libVersion": "2.20.1",
45 | "cloudfunctionTemplateRoot": "cloudfunctionTemplate",
46 | "condition": {
47 | "search": {
48 | "list": []
49 | },
50 | "conversation": {
51 | "list": []
52 | },
53 | "plugin": {
54 | "list": []
55 | },
56 | "game": {
57 | "list": []
58 | },
59 | "miniprogram": {
60 | "list": []
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/project.private.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "setting": {},
3 | "condition": {
4 | "plugin": {
5 | "list": []
6 | },
7 | "game": {
8 | "list": []
9 | },
10 | "gamePlugin": {
11 | "list": []
12 | },
13 | "miniprogram": {
14 | "list": [
15 | {
16 | "name": "pages/search/search",
17 | "pathName": "pages/search/search",
18 | "query": "",
19 | "scene": null
20 | },
21 | {
22 | "name": "pages/word_detail/word_detail",
23 | "pathName": "pages/word_detail/word_detail",
24 | "query": "word_id=1630",
25 | "scene": null
26 | },
27 | {
28 | "name": "pages/login/login",
29 | "pathName": "pages/login/login",
30 | "query": "",
31 | "scene": null
32 | },
33 | {
34 | "name": "pages/learning/learning",
35 | "pathName": "pages/learning/learning",
36 | "query": "",
37 | "scene": null
38 | },
39 | {
40 | "name": "pages/overview/overview",
41 | "pathName": "pages/overview/overview",
42 | "query": "",
43 | "scene": null
44 | },
45 | {
46 | "name": "pages/review/review",
47 | "pathName": "pages/review/review",
48 | "query": "",
49 | "scene": null
50 | },
51 | {
52 | "name": "pages/word_list/word_list",
53 | "pathName": "pages/word_list/word_list",
54 | "query": "type=getBkLearnedWord",
55 | "scene": null
56 | },
57 | {
58 | "name": "pages/user/user",
59 | "pathName": "pages/user/user",
60 | "query": "",
61 | "scene": null
62 | },
63 | {
64 | "name": "pages/user_settings/user_settings",
65 | "pathName": "pages/user_settings/user_settings",
66 | "query": "",
67 | "scene": null
68 | },
69 | {
70 | "name": "",
71 | "pathName": "pages/image_cropper/image_cropper",
72 | "query": "",
73 | "scene": null
74 | }
75 | ]
76 | }
77 | }
78 | }
--------------------------------------------------------------------------------