ソースを参照

update: 覆盖

KELECHUAN 2 年 前
コミット
17989bac78
100 ファイル変更24507 行追加0 行削除
  1. 16 0
      .hbuilderx/launch.json
  2. 3 0
      .vs/ProjectSettings.json
  3. 6 0
      .vs/VSWorkspaceState.json
  4. BIN
      .vs/slnx.sqlite
  5. 11 0
      .vs/teammodelwxapp/project-colors.json
  6. BIN
      .vs/teammodelwxapp/v17/.suo
  7. BIN
      .vs/teammodelwxapp/v17/workspaceFileList.bin
  8. 24 0
      App.vue
  9. 811 0
      common/global_js/MockData.js
  10. 156 0
      common/global_scss/pages_style.scss
  11. 21 0
      common/global_scss/theme_style.scss
  12. 149 0
      components/loading/loading.vue
  13. 421 0
      components/th-autograph/th-autograph.vue
  14. 139 0
      components/th-autograph/th-color.vue
  15. 103 0
      components/th-autograph/th-line.vue
  16. 141 0
      components/top-info/top-info.vue
  17. 90 0
      components/top-return/top-return.vue
  18. 92 0
      components/top-semester/top-semester.vue
  19. 118 0
      components/z-calendar/dateBox.vue
  20. 68 0
      components/z-calendar/js/utils.js
  21. 513 0
      components/z-calendar/zsy-calendar.vue
  22. 34 0
      main.js
  23. 81 0
      manifest.json
  24. 19 0
      package.json
  25. 268 0
      pages.json
  26. 60 0
      pages/init/init.vue
  27. 211 0
      pages/style/tab_pages.scss
  28. 353 0
      pages/tab_exam/tab_exam.vue
  29. 846 0
      pages/tab_home/tab_home.vue
  30. 323 0
      pages/tab_mine/tab_mine.vue
  31. 326 0
      pages/tab_swap/tab_swap.vue
  32. 312 0
      pages/tab_work/tab_work.vue
  33. 58 0
      static/default_icons/boy_avatar.svg
  34. 69 0
      static/default_icons/girl_avatar.svg
  35. 4 0
      static/iconfont/iconfont-font.css
  36. 631 0
      static/iconfont/iconfont-weapp-icon.css
  37. BIN
      static/tab_icons/exam.png
  38. BIN
      static/tab_icons/examselect.png
  39. BIN
      static/tab_icons/home.png
  40. BIN
      static/tab_icons/homeselect.png
  41. BIN
      static/tab_icons/mine.png
  42. BIN
      static/tab_icons/mineselect.png
  43. BIN
      static/tab_icons/swap.png
  44. BIN
      static/tab_icons/swapselect.png
  45. BIN
      static/tab_icons/work.png
  46. BIN
      static/tab_icons/workselect.png
  47. 1 0
      static/th-autograph/back.svg
  48. BIN
      static/th-autograph/checkRow.png
  49. 1 0
      static/th-autograph/clear.svg
  50. 1 0
      static/th-autograph/color.svg
  51. 1 0
      static/th-autograph/pencli.svg
  52. 41 0
      store/chart.js
  53. 63 0
      store/children.js
  54. 60 0
      store/parent.js
  55. 21 0
      store/store.js
  56. 87 0
      subpkg/datalist/data_pages.scss
  57. 106 0
      subpkg/datalist/examList.vue
  58. 755 0
      subpkg/datalist/examReport.vue
  59. 131 0
      subpkg/datalist/swapList.vue
  60. 72 0
      subpkg/datalist/swapReport.vue
  61. 40 0
      subpkg/datalist/top_info.scss
  62. 128 0
      subpkg/datalist/workList.vue
  63. 475 0
      subpkg/datalist/workReport.vue
  64. 670 0
      subpkg/exam/examPractice.vue
  65. 41 0
      subpkg/exam/gradelist_pages.scss
  66. 131 0
      subpkg/exam/level.vue
  67. 143 0
      subpkg/exam/rank.vue
  68. 97 0
      subpkg/exam/single.vue
  69. 99 0
      subpkg/exam/subject.vue
  70. 274 0
      subpkg/exam/total.vue
  71. 286 0
      subpkg/home/classList.vue
  72. 319 0
      subpkg/home/clockStats.vue
  73. 11 0
      subpkg/home/courseRecommend.vue
  74. 211 0
      subpkg/mine/childInfo.vue
  75. 148 0
      subpkg/mine/msgList.vue
  76. 246 0
      subpkg/mine/parentInfo.vue
  77. 464 0
      subpkg/mine/subInfo.vue
  78. 108 0
      subpkg/startup/guide.vue
  79. 113 0
      subpkg/startup/login.vue
  80. 97 0
      subpkg/startup/options.vue
  81. 72 0
      subpkg/startup/startup_pages.scss
  82. 452 0
      subpkg/swap/swapStats.vue
  83. 82 0
      subpkg/work/workStats.vue
  84. 669 0
      subpkg/work/wrongBook.vue
  85. 5 0
      uni.scss
  86. 246 0
      uni_modules/qiun-data-charts/changelog.md
  87. 1607 0
      uni_modules/qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue
  88. 46 0
      uni_modules/qiun-data-charts/components/qiun-error/qiun-error.vue
  89. 162 0
      uni_modules/qiun-data-charts/components/qiun-loading/loading1.vue
  90. 170 0
      uni_modules/qiun-data-charts/components/qiun-loading/loading2.vue
  91. 173 0
      uni_modules/qiun-data-charts/components/qiun-loading/loading3.vue
  92. 222 0
      uni_modules/qiun-data-charts/components/qiun-loading/loading4.vue
  93. 229 0
      uni_modules/qiun-data-charts/components/qiun-loading/loading5.vue
  94. 36 0
      uni_modules/qiun-data-charts/components/qiun-loading/qiun-loading.vue
  95. 422 0
      uni_modules/qiun-data-charts/js_sdk/u-charts/config-echarts.js
  96. 676 0
      uni_modules/qiun-data-charts/js_sdk/u-charts/config-ucharts.js
  97. 5 0
      uni_modules/qiun-data-charts/js_sdk/u-charts/readme.md
  98. 7297 0
      uni_modules/qiun-data-charts/js_sdk/u-charts/u-charts.js
  99. 18 0
      uni_modules/qiun-data-charts/js_sdk/u-charts/u-charts.min.js
  100. 0 0
      uni_modules/qiun-data-charts/license.md

+ 16 - 0
.hbuilderx/launch.json

@@ -0,0 +1,16 @@
+{ // launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
+  // launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数
+    "version": "0.0",
+    "configurations": [{
+     	"default" : 
+     	{
+     		"launchtype" : "local"
+     	},
+     	"mp-weixin" : 
+     	{
+     		"launchtype" : "local"
+     	},
+     	"type" : "uniCloud"
+     }
+    ]
+}

+ 3 - 0
.vs/ProjectSettings.json

@@ -0,0 +1,3 @@
+{
+  "CurrentProjectSetting": null
+}

+ 6 - 0
.vs/VSWorkspaceState.json

@@ -0,0 +1,6 @@
+{
+  "ExpandedNodes": [
+    ""
+  ],
+  "PreviewInSolutionExplorer": false
+}

BIN
.vs/slnx.sqlite


+ 11 - 0
.vs/teammodelwxapp/project-colors.json

@@ -0,0 +1,11 @@
+{
+  "Version": 1,
+  "ProjectMap": {
+    "a2fe74e1-b743-11d0-ae1a-00a0c90fffc3": {
+      "ProjectGuid": "a2fe74e1-b743-11d0-ae1a-00a0c90fffc3",
+      "DisplayName": "杂项文件",
+      "ColorIndex": -1
+    }
+  },
+  "NextColorIndex": 0
+}

BIN
.vs/teammodelwxapp/v17/.suo


BIN
.vs/teammodelwxapp/v17/workspaceFileList.bin


+ 24 - 0
App.vue

@@ -0,0 +1,24 @@
+<script>
+export default {
+  onLaunch: function () {
+		console.log('App onLaunch')
+  },
+  onShow: function () {
+    console.log('App Show')
+  },
+  onHide: function () {
+    console.log('App Hide')
+  }
+}
+</script>
+
+<style lang="scss">
+/*每个页面公共css */
+@import '@/common/global_scss/pages_style';
+/*uView配置 */
+@import '@/uni_modules/uview-ui/index.scss';
+/*iconfont */
+@import '@/static/iconfont/iconfont-weapp-icon.css';
+/*字体 */
+@import url('~@/static/iconfont/iconfont-font.css');
+</style>

+ 811 - 0
common/global_js/MockData.js

@@ -0,0 +1,811 @@
+const subjectData = [
+	{
+		categories: [
+			"开学考试",
+			"第一月考",
+			"第二月考",
+			"期中考试",
+			"第三月考",
+			"期末考试"
+		],
+		series: [{
+				"name": "语文成绩",
+				"data": [
+					90,
+					95,
+					72,
+					89,
+					88,
+					84
+				]
+			},
+			{
+				"name": "班级平均",
+				"data": [
+					85,
+					98,
+					84,
+					72,
+					83,
+					89
+				]
+			},
+			{
+				"name": "年纪平均",
+				"data": [
+					88,
+					79,
+					88,
+					74,
+					81,
+					92
+				]
+			}
+		],
+		categories: [
+			"开学考试",
+			"第一月考",
+			"第二月考",
+			"期中考试",
+			"第三月考",
+			"期末考试"
+		],
+		series: [{
+				"name": "语文成绩",
+				"data": [
+					90,
+					95,
+					92,
+					80,
+					88,
+					99
+				]
+			},
+			{
+				"name": "班级平均",
+				"data": [
+					85,
+					88,
+					84,
+					42,
+					93,
+					89
+				]
+			},
+			{
+				"name": "年纪平均",
+				"data": [
+					88,
+					79,
+					77,
+					74,
+					85,
+					59
+				]
+			}
+		],
+	},
+	{
+		categories: [
+			"开学考试",
+			"第一月考",
+			"第二月考",
+			"期中考试",
+			"第三月考",
+			"期末考试"
+		],
+		series: [{
+				"name": "数学成绩",
+				"data": [
+					90,
+					95,
+					62,
+					69,
+					88,
+					99
+				]
+			},
+			{
+				"name": "班级平均",
+				"data": [
+					85,
+					88,
+					84,
+					92,
+					73,
+					89
+				]
+			},
+			{
+				"name": "年纪平均",
+				"data": [
+					88,
+					99,
+					77,
+					74,
+					85,
+					89
+				]
+			}
+		],
+	},
+	{
+		categories: [
+			"开学考试",
+			"第一月考",
+			"第二月考",
+			"期中考试",
+			"第三月考",
+			"期末考试"
+		],
+		series: [{
+				"name": "英语成绩",
+				"data": [
+					90,
+					75,
+					92,
+					77,
+					88,
+					99
+				]
+			},
+			{
+				"name": "班级平均",
+				"data": [
+					85,
+					48,
+					84,
+					92,
+					93,
+					89
+				]
+			},
+			{
+				"name": "年纪平均",
+				"data": [
+					88,
+					99,
+					77,
+					74,
+					85,
+					86
+				]
+			}
+		],
+	},
+	{
+		categories: [
+			"开学考试",
+			"第一月考",
+			"第二月考",
+			"期中考试",
+			"第三月考",
+			"期末考试"
+		],
+		series: [{
+				"name": "科学成绩",
+				"data": [
+					90,
+					95,
+					92,
+					50,
+					56,
+					99
+				]
+			},
+			{
+				"name": "班级平均",
+				"data": [
+					85,
+					88,
+					84,
+					92,
+					63,
+					89
+				]
+			},
+			{
+				"name": "年纪平均",
+				"data": [
+					78,
+					79,
+					77,
+					74,
+					85,
+					89
+				]
+			}
+		],
+	},
+	{
+		categories: [
+			"开学考试",
+			"第一月考",
+			"第二月考",
+			"期中考试",
+			"第三月考",
+			"期末考试"
+		],
+		series: [{
+				"name": "体育成绩",
+				"data": [
+					90,
+					95,
+					92,
+					70,
+					66,
+					99
+				]
+			},
+			{
+				"name": "班级平均",
+				"data": [
+					85,
+					88,
+					84,
+					92,
+					83,
+					89
+				]
+			},
+			{
+				"name": "年纪平均",
+				"data": [
+					88,
+					79,
+					87,
+					74,
+					55,
+					89
+				]
+			}
+		],
+	},
+	{
+		categories: [
+			"开学考试",
+			"第一月考",
+			"第二月考",
+			"期中考试",
+			"第三月考",
+			"期末考试"
+		],
+		series: [{
+				"name": "思品成绩",
+				"data": [
+					90,
+					95,
+					92,
+					60,
+					88,
+					72
+				]
+			},
+			{
+				"name": "班级平均",
+				"data": [
+					85,
+					88,
+					84,
+					92,
+					93,
+					79
+				]
+			},
+			{
+				"name": "年纪平均",
+				"data": [
+					88,
+					79,
+					77,
+					74,
+					55,
+					89
+				]
+			}
+		],
+	},
+]
+
+const rankData = [
+	{
+		name: "语文",
+		categories: [
+			"开学考试",
+			"第一月考",
+			"第二月考",
+			"期中考试",
+			"第三月考",
+			"期末考试"
+		],
+		series: [{
+				"name": "超过年级中",
+				"data": [
+					90,
+					95,
+					82,
+					76,
+					88,
+					99
+				]
+			},
+			{
+				"name": "超过班级中",
+				"data": [
+					95,
+					58,
+					64,
+					92,
+					93,
+					79
+				]
+			}
+		]
+	},
+	{
+		name: "数学",
+		categories: [
+			"开学考试",
+			"第一月考",
+			"第二月考",
+			"期中考试",
+			"第三月考",
+			"期末考试"
+		],
+		series: [{
+				"name": "超过年级中",
+				"data": [
+					90,
+					95,
+					82,
+					76,
+					88,
+					99
+				]
+			},
+			{
+				"name": "超过班级中",
+				"data": [
+					95,
+					58,
+					88,
+					92,
+					93,
+					79
+				]
+			}
+		]
+	},
+	{
+		name: "英语",
+		categories: [
+			"开学考试",
+			"第一月考",
+			"第二月考",
+			"期中考试",
+			"第三月考",
+			"期末考试"
+		],
+		series: [{
+				"name": "超过年级中",
+				"data": [
+					90,
+					74,
+					82,
+					66,
+					77,
+					99
+				]
+			},
+			{
+				"name": "超过班级中",
+				"data": [
+					95,
+					89,
+					64,
+					75,
+					93,
+					92
+				]
+			}
+		]
+	},
+	{
+		name: "思品",
+		categories: [
+			"开学考试",
+			"第一月考",
+			"第二月考",
+			"期中考试",
+			"第三月考",
+			"期末考试"
+		],
+		series: [{
+				"name": "超过年级中",
+				"data": [
+					80,
+					91,
+					82,
+					76,
+					55,
+					99
+				]
+			},
+			{
+				"name": "超过班级中",
+				"data": [
+					95,
+					92,
+					69,
+					92,
+					93,
+					55
+				]
+			}
+		]
+	},
+	{
+		name: "体育",
+		categories: [
+			"开学考试",
+			"第一月考",
+			"第二月考",
+			"期中考试",
+			"第三月考",
+			"期末考试"
+		],
+		series: [{
+				"name": "超过年级中",
+				"data": [
+					90,
+					33,
+					82,
+					45,
+					88,
+					99
+				]
+			},
+			{
+				"name": "超过班级中",
+				"data": [
+					95,
+					99,
+					64,
+					77,
+					93,
+					79
+				]
+			}
+		]
+	},
+	{
+		name: "科学",
+		categories: [
+			"开学考试",
+			"第一月考",
+			"第二月考",
+			"期中考试",
+			"第三月考",
+			"期末考试"
+		],
+		series: [{
+				"name": "超过年级中",
+				"data": [
+					50,
+					95,
+					55,
+					76,
+					66,
+					99
+				]
+			},
+			{
+				"name": "超过班级中",
+				"data": [
+					30,
+					58,
+					64,
+					92,
+					22,
+					79
+				]
+			}
+		]
+	},
+]
+
+const classData = {
+	"周四":[{
+		title: '文章鉴赏',
+		name: '语文',
+		teacher: '王老师',
+		time: '09:00-09:50',
+		timeFrame: '上午第一节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg2.mp4',
+		attendance: true
+	}, {
+		title: '计算练习',
+		name: '数学',
+		teacher: '李老师',
+		time: '09:50-10:50',
+		timeFrame: '上午第二节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg1.mp4',
+		attendance: true
+	}, {
+		title: '阅读专项训练',
+		name: '外语',
+		teacher: '张老师',
+		time: '10:50-11:50',
+		timeFrame: '上午第三节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg3.mp4',
+		attendance: true
+	}, {
+		title: '思想品德教育',
+		name: '思品',
+		teacher: '史老师',
+		time: '11:50-14:50',
+		timeFrame: '下午第一节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg2.mp4',
+		attendance: true
+	}, {
+		title: '户外运动锻炼',
+		name: '体育',
+		teacher: '李老师',
+		time: '14:50-17:55',
+		timeFrame: '下午第二节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg1.mp4',
+		attendance: true
+	}, {
+		title: '科学学习实验',
+		name: '科学',
+		teacher: '张老师',
+		time: '17:55-20:50',
+		timeFrame: '上午第三节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg3.mp4',
+		attendance: true
+	}, {
+		title: '随堂测验',
+		name: '数学',
+		teacher: '李老师',
+		time: '20:50-21:50',
+		timeFrame: '下午第四节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg1.mp4',
+		attendance: true
+	}],
+	"周五":[{
+		title: '计算练习',
+		name: '数学',
+		teacher: '李老师',
+		time: '09:00-09:50',
+		timeFrame: '上午第一节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg2.mp4',
+		attendance: true
+	}, {
+		title: '文言文学习',
+		name: '语文',
+		teacher: '王老师',
+		time: '09:50-10:50',
+		timeFrame: '上午第二节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg1.mp4',
+		attendance: true
+	}, {
+		title: '阅读专项训练',
+		name: '外语',
+		teacher: '张老师',
+		time: '10:50-11:50',
+		timeFrame: '上午第三节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg3.mp4',
+		attendance: true
+	}, {
+		title: '思想品德教育',
+		name: '思品',
+		teacher: '史老师',
+		time: '11:50-14:50',
+		timeFrame: '下午第一节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg2.mp4',
+		attendance: true
+	}, {
+		title: '户外运动锻炼',
+		name: '体育',
+		teacher: '李老师',
+		time: '14:50-17:55',
+		timeFrame: '下午第二节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg1.mp4',
+		attendance: true
+	}, {
+		title: '科学学习实验',
+		name: '科学',
+		teacher: '张老师',
+		time: '17:55-20:50',
+		timeFrame: '上午第三节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg3.mp4',
+		attendance: true
+	}, {
+		title: '随堂测验',
+		name: '数学',
+		teacher: '李老师',
+		time: '20:50-21:50',
+		timeFrame: '下午第四节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg1.mp4',
+		attendance: true
+	}],
+	"周六": '',
+	"周日": '',
+	"周一":[{
+		title: '阅读专项训练',
+		name: '英语',
+		teacher: '张老师',
+		time: '09:00-09:50',
+		timeFrame: '上午第一节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg2.mp4',
+		attendance: true
+	}, {
+		title: '计算练习',
+		name: '数学',
+		teacher: '李老师',
+		time: '09:50-10:50',
+		timeFrame: '上午第二节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg1.mp4',
+		attendance: true
+	}, {
+		title: '作文练习',
+		name: '语文',
+		teacher: '王老师',
+		time: '10:50-11:50',
+		timeFrame: '上午第三节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg3.mp4',
+		attendance: true
+	}, {
+		title: '思想品德教育',
+		name: '思品',
+		teacher: '史老师',
+		time: '11:50-14:50',
+		timeFrame: '下午第一节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg2.mp4',
+		attendance: true
+	}, {
+		title: '户外运动锻炼',
+		name: '体育',
+		teacher: '李老师',
+		time: '14:50-17:55',
+		timeFrame: '下午第二节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg1.mp4',
+		attendance: true
+	}, {
+		title: '科学学习实验',
+		name: '科学',
+		teacher: '张老师',
+		time: '17:55-20:50',
+		timeFrame: '上午第三节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg3.mp4',
+		attendance: true
+	}, {
+		title: '随堂测验',
+		name: '数学',
+		teacher: '李老师',
+		time: '20:50-21:50',
+		timeFrame: '下午第四节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg1.mp4',
+		attendance: true
+	}],
+	"周二":[{
+		title: '文章鉴赏',
+		name: '语文',
+		teacher: '王老师',
+		time: '09:00-09:50',
+		timeFrame: '上午第一节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg2.mp4',
+		attendance: true
+	}, {
+		title: '计算练习',
+		name: '数学',
+		teacher: '李老师',
+		time: '09:50-10:50',
+		timeFrame: '上午第二节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg1.mp4',
+		attendance: true
+	}, {
+		title: '阅读专项训练',
+		name: '外语',
+		teacher: '张老师',
+		time: '10:50-11:50',
+		timeFrame: '上午第三节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg3.mp4',
+		attendance: true
+	}, {
+		title: '思想品德教育',
+		name: '思品',
+		teacher: '史老师',
+		time: '11:50-14:50',
+		timeFrame: '下午第一节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg2.mp4',
+		attendance: true
+	}, {
+		title: '户外运动锻炼',
+		name: '体育',
+		teacher: '李老师',
+		time: '14:50-17:55',
+		timeFrame: '下午第二节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg1.mp4',
+		attendance: true
+	}, {
+		title: '科学学习实验',
+		name: '科学',
+		teacher: '张老师',
+		time: '17:55-20:50',
+		timeFrame: '上午第三节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg3.mp4',
+		attendance: true
+	}, {
+		title: '随堂测验',
+		name: '数学',
+		teacher: '李老师',
+		time: '20:50-21:50',
+		timeFrame: '下午第四节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg1.mp4',
+		attendance: true
+	}],
+	"周三":[{
+		title: '文章鉴赏',
+		name: '语文',
+		teacher: '王老师',
+		time: '09:00-09:50',
+		timeFrame: '上午第一节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg2.mp4',
+		attendance: true
+	}, {
+		title: '计算练习',
+		name: '数学',
+		teacher: '李老师',
+		time: '09:50-10:50',
+		timeFrame: '上午第二节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg1.mp4',
+		attendance: true
+	}, {
+		title: '阅读专项训练',
+		name: '外语',
+		teacher: '张老师',
+		time: '10:50-11:50',
+		timeFrame: '上午第三节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg3.mp4',
+		attendance: true
+	}, {
+		title: '思想品德教育',
+		name: '思品',
+		teacher: '史老师',
+		time: '11:50-14:50',
+		timeFrame: '下午第一节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg2.mp4',
+		attendance: true
+	}, {
+		title: '户外运动锻炼',
+		name: '体育',
+		teacher: '李老师',
+		time: '14:50-17:55',
+		timeFrame: '下午第二节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg1.mp4',
+		attendance: true
+	}, {
+		title: '科学学习实验',
+		name: '科学',
+		teacher: '张老师',
+		time: '17:55-20:50',
+		timeFrame: '上午第三节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg3.mp4',
+		attendance: true
+	}, {
+		title: '随堂测验',
+		name: '数学',
+		teacher: '李老师',
+		time: '20:50-21:50',
+		timeFrame: '下午第四节',
+		resource: 'https://klxxcdn.oss-cn-hangzhou.aliyuncs.com/histudy/hrm/media/bg1.mp4',
+		attendance: true
+	}],
+}
+
+export default {
+	subjectData, //主要科目列表
+	rankData, //排行科目列表
+	classData, //课程数据列表
+}

+ 156 - 0
common/global_scss/pages_style.scss

@@ -0,0 +1,156 @@
+page{
+	background-color: $page-color;
+}
+.page-view{
+	display: flex;
+	flex-direction: column;
+	width: 100%;
+	height: 100%;
+	overflow-x: hidden; //隐藏多余的页面
+}
+.title{
+	line-height: 35rpx;
+	font-size: 35rpx;
+	font-weight: bold;
+	color: $title;
+}
+.subtitle{
+	line-height: 30rpx;
+	font-size: 30rpx;
+	font-weight: bold;
+	color: $subtitle;
+}
+.YS-title{
+	line-height: 35rpx;
+	font-size: 35rpx;
+	color: $title;
+	font-family: YSfont;
+}
+.YS-subtitle{
+	line-height: 32rpx;
+	font-size: 32rpx;
+	color: $subtitle;
+	font-family: YSfont;
+}
+//标题头
+.front-tag {
+	margin-right: 20rpx;
+	height: 100%;
+	width: 10rpx;
+	border-radius: 6rpx;
+	background-image: linear-gradient(#4169E1, rgba(65,105,225,0.3));
+	z-index: 99;
+}
+//标题底
+.bottom-tag{
+	margin-top: -10rpx;
+	margin-left: 20%;
+	height: 20rpx;
+	width: 90%;
+	border-radius: 12rpx;
+	background-image: linear-gradient(to right, #4169E1, rgba(1,1,1,0));
+	z-index: -1;
+}
+//标签
+.tag {
+	border-radius: 50rpx;
+	border: 1rpx solid $color-blue;
+	padding: 2rpx 12rpx;
+
+	.tag-text {
+		font-size: 22rpx;
+		color: $color-blue;
+	}
+}
+//标签
+.tag-fill{
+	display: flex;
+	align-items: center;
+	border-radius: 6rpx;
+	background-color: $color-blue;
+	padding: 6rpx 12rpx;
+	.tag-text {
+		font-size: 24rpx;
+		color: #FFF;
+	}
+}
+//卡片
+.card-view {
+	display: flex;
+	flex-flow: row wrap;
+	margin: 20rpx;
+	justify-content: space-between;
+
+	.card-item {
+		margin: 2% 0;
+		width: 48%;
+		height: auto;
+		display: flex;
+		flex-direction: column;
+		background-color: #FFF;
+		border-radius: $border-radius;
+		overflow: hidden;
+		z-index: 55;
+
+		.card-title {
+			display: flex;
+			align-items: center;
+			padding: 20rpx;
+			z-index: 55;
+
+			.title {
+				font-size: 32rpx;
+				line-height: 40rpx;
+			}
+		}
+	}
+}
+//横向flex布局
+.flex-row{
+	display:flex;
+	align-items: center;
+}
+//竖向flex布局
+.flex-column{
+	display:flex;
+	flex-direction: column;
+}
+//横向baseline布局
+.flex-baseline{
+	display: flex;
+	align-items: baseline;
+}
+//插画
+.detail-image {
+	width: 100%;
+	height: 450rpx;
+	background-size: cover; //背景图片自适应
+	background-repeat: no-repeat;
+	z-index: 50;
+}
+//图标
+.t-icon {
+    display: inline-block;
+    width: 40rpx; 
+    height: 40rpx;
+    background-repeat: no-repeat;
+    background-position: center;
+    background-size: 100%;
+}
+//头部背景
+.bg-box1 {
+	position: fixed;
+	width: 100%;
+	height: 800rpx;
+	background-size: 100%;
+	background-repeat: no-repeat;
+	background-image: linear-gradient(to top, #f3f4f9, rgba(255, 255, 255, 0) 45%),url('https://image.meiye.art/pic_1628634662880');
+}
+.bg-box2{
+	position: fixed;
+	width: 100%;
+	height: 800rpx;
+	background-size: 100%;
+	background-repeat: no-repeat;
+	background-image: linear-gradient(to top, #f3f4f9, rgba(255, 255, 255, 0) 45%),url('https://image.meiye.art/pic_1628634712718');
+}

+ 21 - 0
common/global_scss/theme_style.scss

@@ -0,0 +1,21 @@
+//主题色
+$color-blue: #4169E1;
+$color-green: #23b46c;
+$color-pink: #ff8caf;
+$color-yellow: #f9c752;
+$color-red: #ff5959;
+$color-orange: #FF6D31;
+$color-cyan: #0dc2b3;
+//次级色
+$subcolor-blue: #d8deff;
+//页面色
+$page-color: #f3f4f9;
+//字体色
+$title: #303133;
+$subtitle: #909399;
+//渐变
+$gradient-color: linear-gradient(to right, #4169E1, #d8deff );
+//卡片圆弧
+$border-radius: 12rpx;
+//阴影
+$box-shadow: 0 10rpx 20rpx rgba(0, 0, 0, 0.1);

+ 149 - 0
components/loading/loading.vue

@@ -0,0 +1,149 @@
+<template>
+	<view class="flex">
+		<view class="sk-folding-cube">
+			<view class="sk-cube1 sk-cube"></view>
+			<view class="sk-cube2 sk-cube"></view>
+			<view class="sk-cube4 sk-cube"></view>
+			<view class="sk-cube3 sk-cube"></view>
+		</view>
+		<view class="YS-title loading">正在加载中...</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "loading",
+		data() {
+			return {
+
+			};
+		}
+	}
+</script>
+
+<style lang="scss">
+	.flex {
+		width: 100vw;
+		height: 100vh;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.loading{
+		margin-top: 20rpx;color: #555555;
+	}
+
+	.sk-folding-cube {
+		margin: 20px auto;
+		width: 40px;
+		height: 40px;
+		position: relative;
+		-webkit-transform: rotateZ(45deg);
+		transform: rotateZ(45deg);
+	}
+
+	.sk-folding-cube .sk-cube {
+		float: left;
+		width: 50%;
+		height: 50%;
+		position: relative;
+		-webkit-transform: scale(1.1);
+		-ms-transform: scale(1.1);
+		transform: scale(1.1);
+	}
+
+	.sk-folding-cube .sk-cube:before {
+		content: '';
+		position: absolute;
+		top: 0;
+		left: 0;
+		width: 100%;
+		height: 100%;
+		background-color: #555555;
+		-webkit-animation: sk-foldCubeAngle 2.4s infinite linear both;
+		animation: sk-foldCubeAngle 2.4s infinite linear both;
+		-webkit-transform-origin: 100% 100%;
+		-ms-transform-origin: 100% 100%;
+		transform-origin: 100% 100%;
+	}
+
+	.sk-folding-cube .sk-cube2 {
+		-webkit-transform: scale(1.1) rotateZ(90deg);
+		transform: scale(1.1) rotateZ(90deg);
+	}
+
+	.sk-folding-cube .sk-cube3 {
+		-webkit-transform: scale(1.1) rotateZ(180deg);
+		transform: scale(1.1) rotateZ(180deg);
+	}
+
+	.sk-folding-cube .sk-cube4 {
+		-webkit-transform: scale(1.1) rotateZ(270deg);
+		transform: scale(1.1) rotateZ(270deg);
+	}
+
+	.sk-folding-cube .sk-cube2:before {
+		-webkit-animation-delay: 0.3s;
+		animation-delay: 0.3s;
+	}
+
+	.sk-folding-cube .sk-cube3:before {
+		-webkit-animation-delay: 0.6s;
+		animation-delay: 0.6s;
+	}
+
+	.sk-folding-cube .sk-cube4:before {
+		-webkit-animation-delay: 0.9s;
+		animation-delay: 0.9s;
+	}
+
+	@-webkit-keyframes sk-foldCubeAngle {
+
+		0%,
+		10% {
+			-webkit-transform: perspective(140px) rotateX(-180deg);
+			transform: perspective(140px) rotateX(-180deg);
+			opacity: 0;
+		}
+
+		25%,
+		75% {
+			-webkit-transform: perspective(140px) rotateX(0deg);
+			transform: perspective(140px) rotateX(0deg);
+			opacity: 1;
+		}
+
+		90%,
+		100% {
+			-webkit-transform: perspective(140px) rotateY(180deg);
+			transform: perspective(140px) rotateY(180deg);
+			opacity: 0;
+		}
+	}
+
+	@keyframes sk-foldCubeAngle {
+
+		0%,
+		10% {
+			-webkit-transform: perspective(140px) rotateX(-180deg);
+			transform: perspective(140px) rotateX(-180deg);
+			opacity: 0;
+		}
+
+		25%,
+		75% {
+			-webkit-transform: perspective(140px) rotateX(0deg);
+			transform: perspective(140px) rotateX(0deg);
+			opacity: 1;
+		}
+
+		90%,
+		100% {
+			-webkit-transform: perspective(140px) rotateY(180deg);
+			transform: perspective(140px) rotateY(180deg);
+			opacity: 0;
+		}
+	}
+</style>

+ 421 - 0
components/th-autograph/th-autograph.vue

@@ -0,0 +1,421 @@
+<template>
+	<view class="autograph-box">
+		<canvas class="autograph" :canvas-id="canvasId" :id="canvasId" @touchstart="canvasStart($event)" @touchmove="canvasMove($event)">
+			<view v-if="history.length==0" :class="['default-text',horizontalScreen?'rote-text':'']">草稿区域</view>
+		</canvas>
+		<view :class="['action-box',horizontalScreen?'horizontalScreen':'']">
+			<view class="action-bar">
+				<view :class="[actionShow?'action-open':'action-close']">
+<!-- 					<image src="../../static/th-autograph/pencli.svg" @click="openAction('thLine')" v-if="judge('pencli')"></image> -->
+					<image src="../../static/th-autograph/color.svg" @click="openAction('thColor')" v-if="judge('color')"></image>
+					<image src="../../static/th-autograph/back.svg" @click="goBack" v-if="judge('back')"></image>
+					<image src="../../static/th-autograph/clear.svg" @click="clear" v-if="judge('clear')"></image>
+				</view>
+				<image src="../../static/th-autograph/checkRow.png" @click="checkAction"
+				v-if="actionBar.length!=0"
+				:class="[actionShow?'roteRight':'roteLeft']"></image>
+			</view>
+			<!-- <view class="th-submit" @click="saveCanvas">确定</view> -->
+		</view>
+		<th-color ref="thColor" @setColor="setColor"></th-color>
+		<th-line ref="thLine" @setLine="setLine"></th-line>
+	</view>
+</template>
+
+<script>
+	/**
+	 * @property {Array} actionBar 操作按钮配置 pencli(线条)  color(颜色)  back(返回)  clear(清空)
+	 * @property {String} canvasId CanvasId
+	 * @property {Boolean} isDownload 是否下载签名
+	 * @property {Boolean} horizontalScreen 是否横屏
+	 * @property {String} fileName 文件名称
+	 * @property {String} delineColor 线颜色
+	 * @property {Number} delineWidth 线宽度
+	 **/
+	import thColor from "./th-color.vue"
+	import thLine from "./th-line.vue"
+	export default {
+		props: {
+			//canvasId
+			canvasId: {
+				type: String,
+				default: `th-${Date.now()}`
+			},
+			//配置栏
+			actionBar:{
+				type:Array,
+				default:()=>{
+					return [
+						'pencli',
+						'color',
+						'back',
+						'clear'
+					]
+				}
+			},
+			//是否下载签名
+			isDownload: {
+				type: Boolean,
+				default: true
+			},
+			//是否横屏
+			horizontalScreen: {
+				type: Boolean,
+				default: false
+			},
+			//文件名称
+			fileName: {
+				type: String,
+				default: '签名'
+			},
+			//线颜色
+			delineColor: {
+				type: String,
+				default: '#000'
+			},
+			//线宽度
+			delineWidth: {
+				type: Number,
+				default: 4
+			}
+		},
+		data() {
+			return {
+				context:"",
+				actionShow:true,
+				history:[],
+				lineColor:"#000",
+				lineWidth:4
+			}
+		},
+		components:{
+			thColor,thLine
+		},
+		mounted () {
+			this.lineColor = this.delineColor
+			this.lineWidth = this.delineWidth
+			const ctx = uni.createCanvasContext(this.canvasId,this)
+			this.context = ctx;
+		},
+		methods: {
+			//操作栏显示控制
+			judge(key) {
+				if(this.actionBar.includes(key)){
+					return true
+				}else{
+					return false;
+				}
+			},
+			//打开选择器
+			openAction(ref) {
+				this.$refs[ref].checkModel()
+			},
+			//设置颜色
+			setColor(color) {
+				this.lineColor = color;
+			},
+			//设置线条
+			setLine(width) {
+				this.lineWidth = width;
+			},
+			//切换控制栏
+			checkAction() {
+				this.actionShow = !this.actionShow
+			},
+			//保存
+			async saveCanvas() {
+				const tempFilePath = await this.canvasToFilPath()
+				if(!this.isDownload) {
+					this.$emit('submit',tempFilePath)
+					return false;
+				}
+				return new Promise((resolve, reject) => {
+					// #ifdef H5
+					try {
+						const a = document.createElement('a')
+						a.href = tempFilePath
+						a.download = this.fileName
+						document.body.appendChild(a)
+						a.click()
+						a.remove()
+						resolve()
+					} catch (e) {
+						reject(e)
+					}
+					// #endif
+					// #ifndef H5
+					uni.saveImageToPhotosAlbum({
+						filePath: tempFilePath,
+						success(resObj) {
+							this.$emit('submit',tempFilePath)
+							resolve(resObj)
+						},
+						fail(err) {
+							this.$emit('dowmloadErr',err)
+							reject(err)
+						}
+					})
+					// #endif
+				})
+			},
+			// 保存临时路径
+			canvasToFilPath(conf = {}) {
+				return new Promise((resolve, reject) => {
+					uni.canvasToTempFilePath(
+						{
+							canvasId: this.canvasId,
+							success: res => {
+								resolve(res.tempFilePath)
+							},
+							fail: err => {
+								reject(err)
+							}
+						}
+					)
+				})
+			},
+			//撤回
+			goBack() {
+				this.context.draw()
+				this.history.pop();
+				this.history.forEach((item, index) => {
+					let {color,width} = item.style
+					this.context.beginPath()
+					this.context.setLineCap('round')
+					this.context.setStrokeStyle(color)
+					this.context.setLineWidth(width)
+					if (item.coordinates.length >= 2) {
+						item.coordinates.forEach(it => {
+							if (it.type == 'touchstart') {
+								this.context.moveTo(it.x, it.y)
+							} else {
+								this.context.lineTo(it.x, it.y)
+							}
+						})
+					} else {
+						const point = item.coordinates[0]
+						this.context.moveTo(point.x, point.y)
+						this.context.lineTo(point.x + 1, point.y)
+					}
+					this.context.stroke()
+				})
+				this.context.draw(true)
+			},
+			//清空画布
+			clear() {
+				this.history = [];
+				this.context.draw()
+			},
+			canvasStart(event) {
+				let {x,y} =  event.touches[0]
+				this.history.push({
+					style: {
+						color: this.lineColor,
+						width: this.lineWidth
+					},
+					coordinates: [
+						{
+							type: event.type,
+							x: x,
+							y: y
+						}
+					]
+				})
+				this.drawGraphics()
+			},
+			canvasMove(e) {
+				// e.preventDefault()
+				let {x,y} = e.touches[0]
+				this.history[this.history.length - 1].coordinates.push({
+					type: e.type,
+					x: x,
+					y: y
+				})
+				this.drawGraphics()
+			},
+			//绘制
+			drawGraphics() {
+				let historyLen = this.history.length
+				if (!historyLen) return
+				let currentData = this.history[historyLen - 1]
+				let coordinates = currentData.coordinates
+				if (!coordinates.length) return
+				let startPoint,endPoint;
+				if (coordinates.length < 2) {
+					startPoint = coordinates[coordinates.length - 1]
+					endPoint = {
+						x: startPoint.x + 1,
+						y: startPoint.y
+					}
+				} else {
+					startPoint = coordinates[coordinates.length - 2]
+					endPoint = coordinates[coordinates.length - 1]
+				}
+				let style = currentData.style
+				this.context.beginPath()
+				this.context.setLineCap('round')
+				this.context.setStrokeStyle(style.color)
+				this.context.setLineWidth(style.width)
+				this.context.moveTo(startPoint.x, startPoint.y)
+				this.context.lineTo(endPoint.x, endPoint.y)
+				this.context.stroke()
+				this.context.draw(true)
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.autograph{
+		width: 100%;
+		height:100%;
+		box-sizing: border-box;
+		// border:1px dashed #ccc;
+	}
+	.horizontalScreen{
+		left: -150upx !important;
+		bottom: 0 !important;
+		right: auto !important;
+		transform: rotate(90deg);
+		transform-origin:bottom right;
+	}
+	.rote-text{
+		transform:rotate(90deg);
+	}
+	.action-box{
+		position: absolute;
+		bottom: 0;
+		right: 0;
+		z-index: 50;
+		display: flex;
+		flex-direction: column;
+		align-items: flex-end;
+	}
+	.th-submit{
+		width: 150upx;
+		height: 100upx;
+		background-color: #4169E1;
+		border-radius: 70upx 0 0 0;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		color: #FFFFFF;
+		font-size: 30upx;
+	}
+	.action-bar{
+		margin-bottom: 30upx;
+		margin-right: 35upx;
+		image{
+			width: 40upx;
+			height: 40upx;
+		}
+		>image{
+			transition: all 0.3s;
+		}
+		>view{
+			display: flex;
+			flex-direction: column;
+			image{
+				width: 40upx;
+				height: 40upx;
+				margin-bottom: 52upx;
+			}
+		}
+	}
+	.autograph-box{
+		width: 100%;
+		height: 100%;
+		position: relative;
+		.default-text{
+			width: 100%;
+			height: 100%;
+			position: absolute;
+			top: 0;
+			left: 0;
+			display: flex;
+			align-items: center;
+			z-index: -1;
+			justify-content: center;
+			font-size: 38upx;
+			color: #C0C0C0;
+			letter-spacing: 5upx;
+		}
+	}
+	.roteRight{
+		transform: rotate(136deg);
+	}
+	.roteLeft{
+		transform: rotate(0deg);
+	}
+	.action-open{
+		animation:bounceIn 1s;
+	}
+	.action-close{
+		animation:bounceOut 0.5s forwards;
+	}
+	@keyframes bounceIn {
+	
+		0%,
+		20%,
+		40%,
+		60%,
+		80%,
+		to {
+			-webkit-animation-timing-function: cubic-bezier(.215, .61, .355, 1);
+			animation-timing-function: cubic-bezier(.215, .61, .355, 1)
+		}
+	
+		0% {
+			opacity: 0;
+			-webkit-transform: scale3d(.3, .3, .3);
+			transform: scale3d(.3, .3, .3)
+		}
+	
+		20% {
+			-webkit-transform: scale3d(1.1, 1.1, 1.1);
+			transform: scale3d(1.1, 1.1, 1.1)
+		}
+	
+		40% {
+			-webkit-transform: scale3d(.9, .9, .9);
+			transform: scale3d(.9, .9, .9)
+		}
+	
+		60% {
+			opacity: 1;
+			-webkit-transform: scale3d(1.03, 1.03, 1.03);
+			transform: scale3d(1.03, 1.03, 1.03)
+		}
+	
+		80% {
+			-webkit-transform: scale3d(.97, .97, .97);
+			transform: scale3d(.97, .97, .97)
+		}
+	
+		to {
+			opacity: 1;
+			-webkit-transform: scaleX(1);
+			transform: scaleX(1)
+		}
+	}
+	@keyframes bounceOut {
+		20% {
+			-webkit-transform: scale3d(.9, .9, .9);
+			transform: scale3d(.9, .9, .9)
+		}
+	
+		50%,
+		55% {
+			opacity: 1;
+			-webkit-transform: scale3d(1.1, 1.1, 1.1);
+			transform: scale3d(1.1, 1.1, 1.1)
+		}
+	
+		to {
+			opacity: 0;
+			-webkit-transform: scale3d(.3, .3, .3);
+			transform: scale3d(.3, .3, .3);
+			display: none;
+		}
+	}
+</style>

+ 139 - 0
components/th-autograph/th-color.vue

@@ -0,0 +1,139 @@
+<template>
+	<view class="th-color" v-if="colorShow" @click="checkModel">
+		<view :class="[colorShow?'open-color':'close-color']" @click.stop="()=>{}">
+			<view class="color-head">颜色选择器</view>
+			<view class="color-box">
+				<view v-for="(item,index) in colorData" :key="item" 
+				 @click="checkColor(item)"
+				:class="{'checkItem':checkItem==item}">
+					<view>
+						<view :style="{'background':item}"></view>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				colorShow:false,
+				colorData:["red",'black','blue','yellow','green','#d925ff','#00b4ff','#ff00cc','#35ff81','#ff9c00','#ff7e00',
+				'#b4ff00','#28caa6','#490086','#deb7fe','#acacad','#525252','#a5896f','#bb3a30','#0058b2'
+				],
+				checkItem:""
+			}
+		},
+		methods:{
+			checkModel() {
+				this.colorShow = !this.colorShow;
+			},
+			//选择颜色
+			checkColor(item) {
+				this.checkItem = item;
+				this.colorShow = false;
+				this.$emit('setColor',item)
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+.checkItem{
+	border: 1px dashed #4169E1;
+	box-sizing: border-box;
+}
+.th-color{
+	width: 100%;
+	height: 100%;
+	background-color: rgba(0,0,0,0.5);
+	position: fixed;
+	bottom: 0;
+	left: 0;
+	z-index: 100;
+	display: flex;
+	align-items: flex-end;
+	>view{
+		width: 100%;
+		height: 470upx;
+		background: #FFFFFF;
+		box-shadow: 0 0 10upx #999999;
+		border-radius: 60upx 60upx 0 0;
+		box-sizing: border-box;
+		padding: 0 40upx;
+		overflow: hidden;
+		.color-head{
+			text-align: center;
+			font-size: 30upx;
+			height: 100upx;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			margin-bottom: 20upx;
+		}
+		.color-box{
+			display: flex;
+			align-items: center;
+			flex-wrap: wrap;
+			>view{
+				width: 20%;
+				height: 80upx;
+				border-radius: 10upx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				// margin-bottom: 30upx;
+				>view{
+					width: 50upx;
+					height: 50upx;
+					overflow: hidden;
+					border-radius: 50%;
+					box-sizing: border-box;
+					padding: 7upx;
+					border: 1px solid #C0C0C0;
+					>view{
+						width: 100%;
+						height: 100%;
+						border-radius: 50%;
+						background-color: red;
+					}
+				}
+			}
+		}
+	}
+}
+.open-color{
+	animation:fadeInUp 0.4s ;
+}
+.close-color{
+	animation:fadeInDown 0.5s ;
+}
+@keyframes fadeInUp {
+	0% {
+		opacity: 0;
+		-webkit-transform: translate3d(0, 100%, 0);
+		transform: translate3d(0, 100%, 0)
+	}
+
+	to {
+		opacity: 1;
+		-webkit-transform: translateZ(0);
+		transform: translateZ(0)
+	}
+}
+@keyframes fadeInDown {
+	0% {
+		opacity: 0;
+		-webkit-transform: translate3d(0, -100%, 0);
+		transform: translate3d(0, -100%, 0)
+	}
+
+	to {
+		opacity: 1;
+		-webkit-transform: translateZ(0);
+		transform: translateZ(0)
+	}
+}
+</style>

+ 103 - 0
components/th-autograph/th-line.vue

@@ -0,0 +1,103 @@
+<template>
+	<view class="th-line" v-if="lineShow" @click="checkModel">
+		<view :class="[lineShow?'open-line':'close-line']" @click.stop="()=>{}">
+			<view class="line-head">线条选择器</view>
+			<view class="line-box">
+				<view v-for="(item,index) in lineData" :key="item"
+				 @click="checkline(item)"
+				 :style="{'height':item+'px'}"></view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				lineShow:false,
+				lineData:[4,8,12,16,18]
+			}
+		},
+		methods:{
+			checkModel() {
+				this.lineShow = !this.lineShow;
+			},
+			checkline(item) {
+				this.lineShow = false;
+				this.$emit('setLine',item)
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+.th-line{
+	width: 100%;
+	height: 100%;
+	background-color: rgba(0,0,0,0.5);
+	position: fixed;
+	bottom: 0;
+	left: 0;
+	z-index: 100;
+	display: flex;
+	align-items: flex-end;
+	>view{
+		width: 100%;
+		height: 500upx;
+		background: #FFFFFF;
+		box-shadow: 0 0 10upx #999999;
+		border-radius: 60upx 60upx 0 0;
+		.line-head{
+			text-align: center;
+			font-size: 30upx;
+			height: 100upx;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			margin-bottom: 20upx;
+		}
+		.line-box{
+			box-sizing: border-box;
+			padding: 0 70upx;
+			>view{
+				margin-bottom:56upx;
+				width: 100%;
+				background-color: #000;
+			}
+		}
+	}
+}
+.open-line{
+	animation:fadeInUp 0.4s ;
+}
+.close-line{
+	animation:fadeInDown 0.5s ;
+}
+@keyframes fadeInUp {
+	0% {
+		opacity: 0;
+		-webkit-transform: translate3d(0, 100%, 0);
+		transform: translate3d(0, 100%, 0)
+	}
+
+	to {
+		opacity: 1;
+		-webkit-transform: translateZ(0);
+		transform: translateZ(0)
+	}
+}
+@keyframes fadeInDown {
+	0% {
+		opacity: 0;
+		-webkit-transform: translate3d(0, -100%, 0);
+		transform: translate3d(0, -100%, 0)
+	}
+
+	to {
+		opacity: 1;
+		-webkit-transform: translateZ(0);
+		transform: translateZ(0)
+	}
+}
+</style>

+ 141 - 0
components/top-info/top-info.vue

@@ -0,0 +1,141 @@
+<template>
+	<view>
+		<view class="info-box">
+			<image class="avatar" :src="childInfo.gender==='M'?'/static/default_icons/boy_avatar.svg':childInfo.gender===null?'/static/default_icons/boy_avatar.svg':'/static/default_icons/girl_avatar.svg'"></image>
+			<view class="flex-column">
+				<view class="info-name">{{childInfo.name}}</view>
+				<view class="info-class">{{childInfo.className}}</view>
+			</view>
+			<view class="capsule-box">
+				<view class="time-stamp">
+					{{timeStamp}}更新
+				</view>
+				<view class="sub-tag" @click="navSubscribe">
+					<view class="t-icon t-icon-huangguan1"></view>
+					<view class="sub-tag-text">
+						{{userData.subscribeLevel}}
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState,
+		mapMutations
+	} from 'vuex'
+
+	export default {
+		name: "top-info",
+		props: {
+			timeStamp: {
+				type: String,
+				default: false
+			}
+		},
+		computed: {
+			...mapState('m_children', ['childInfo']),
+			...mapState('m_parent', ['userData'])
+		},
+		data() {
+			return {
+				capsuleWidth: ''
+			};
+		},
+		created() {
+			this.getCapsuleSite()
+		},
+		methods: {
+			getCapsuleSite() {
+				let res = uni.getMenuButtonBoundingClientRect()
+				this.capsuleWidth = res.width - 14
+			},
+			navSubscribe() {
+				uni.navigateTo({
+					url: '/subpkg/mine/subInfo'
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.info-box {
+		margin: 560rpx 50rpx 0 50rpx;
+		display: flex;
+		align-items: center;
+		z-index: 3;
+
+		.avatar {
+			width: 112rpx;
+			height: 112rpx;
+			border-radius: 100%;
+			border: 4rpx solid #FFF;
+			box-shadow: 0 10rpx 20rpx rgba(0, 0, 0, 0.2);
+			z-index: 55;
+		}
+
+		.flex-column {
+			margin-left: 40rpx;
+			width: 200rpx;
+			height: 120rpx;
+			justify-content: space-around;
+
+			.info-name {
+				font-size: 55rpx;
+				font-family: YSfont;
+				color: #FFF;
+				z-index: 99;
+			}
+
+			.info-class {
+				font-size: 40rpx;
+				font-family: YSfont;
+				color: #FFF;
+				z-index: 99;
+			}
+		}
+
+		.capsule-box {
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			justify-content: space-around;
+			margin-left: auto;
+			height: 120rpx;
+
+			.sub-tag {
+				display: flex;
+				align-items: center;
+				border-radius: 6rpx;
+				padding: 2rpx 12rpx;
+				transform: skew(-5deg);
+				background: #2f3137;
+				z-index: 99;
+
+				.sub-tag-text {
+					margin-left: 2rpx;
+					font-size: 28rpx;
+					font-family: YSfont;
+					color: #d0a97e;
+					z-index: 99;
+				}
+
+				.t-icon {
+					width: 28rpx;
+					height: 28rpx;
+					margin-top: -2rpx;
+					margin-right: 2rpx;
+				}
+			}
+
+			.time-stamp {
+				color: #FFF;
+				font-size: 24rpx;
+				font-family: YSfont;
+			}
+		}
+	}
+</style>

+ 90 - 0
components/top-return/top-return.vue

@@ -0,0 +1,90 @@
+<template>
+	<view class="back" :style="{height: capsuleHeight+ 'px',top:capsuleTop+'px'}">
+		<view v-if="!refresh">
+			<u-icon name="arrow-left" v-if="show === 'back'" :color="color" size="24" @click="backIconHandler"></u-icon>
+			<u-icon name="home-fill" v-if="show === 'home'" :color="color" size="24" @click="backHomeHandler"></u-icon>
+		</view>
+		
+		<view v-if="refresh">
+			<u-icon name="arrow-left" v-if="show === 'back'" :color="color" size="24" @click="backIconHandlerRefresh"></u-icon>
+			<u-icon name="home-fill" v-if="show === 'home'" :color="color" size="24" @click="backIconHandlerRefresh"></u-icon>
+		</view>
+		<view class="back-text" :style="{color: color}">{{ text }}</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "top-return",
+		props: {
+			text: {
+				type: String,
+				default: ''
+			},
+			color: {
+				type: String,
+				default: '#303133'
+			},
+			show: {
+				type: String,
+				default: 'back'
+			},
+			refresh: {
+				type: Boolean,
+				default: false
+			}
+		},
+		data() {
+			return {
+				//胶囊
+				capsuleHeight: 0,
+				capsuleTop: 0,
+			};
+		},
+		created() {
+			this.getCapsuleSite()
+		},
+		methods: {
+			backIconHandler() {
+				uni.navigateBack()
+			},
+			backIconHandlerRefresh() {
+				let pages = getCurrentPages(); // 当前页面
+				let beforePage = pages[pages.length - 2]; // 上一页
+				uni.navigateBack({
+					success: function() {
+						beforePage.onLoad()// 执行上一页的onLoad方法
+					}
+				})
+			},
+			backHomeHandler() {
+				uni.switchTab({
+					url: '/pages/tab_home/tab_home'
+				})
+			},
+			//获取胶囊位置信息
+			getCapsuleSite() {
+				let res = uni.getMenuButtonBoundingClientRect()
+				this.capsuleHeight = res.height
+				this.capsuleTop = res.top
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.back {
+		position: relative;
+		padding: 0 0 0 20rpx;
+		display: flex;
+		align-items: center;
+		z-index: 999;
+
+		.back-text {
+			margin:0 0 5rpx 20rpx;
+			font-size: 40rpx;
+			font-weight: bold;
+			z-index: 999;
+		}
+	}
+</style>

+ 92 - 0
components/top-semester/top-semester.vue

@@ -0,0 +1,92 @@
+<template>
+	<view>
+		<!-- 页面标题内容 -->
+		<view class="flex-row" style="margin: 140rpx 40rpx 0 40rpx;">
+			<view class="info-box">
+				<view class="flex-baseline">
+					<view class="info-title">{{currentYear}}</view>
+					<view class="info-subtitle">学年</view>
+					<view class="info-title" style="margin-left: 10rpx;">{{childInfo.periodName}}</view>
+				</view>
+				<view class="flex-baseline">
+					<view class="tag" style="margin-left: 0;">
+						<view class="tag-text">{{childInfo.schoolName}}</view>
+					</view>
+					<view class="tag">
+						<view class="tag-text">{{childInfo.className}}</view>
+					</view>
+					<view class="tag">
+						<view class="tag-text">{{childInfo.name}}同学</view>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState,
+		mapMutations
+	} from 'vuex'
+	export default {
+		name: "top-semester",
+		computed: {
+			...mapState('m_children', ['childInfo']),
+		},
+		data() {
+			return {
+				currentYear: ''
+			};
+		},
+		created() {
+			this.getYear()
+		},
+		methods: {
+			getYear() {
+				this.currentYear = new Date().getFullYear()
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.info-box {
+		display: flex;
+		flex-direction: column;
+		height: 170rpx;
+		justify-content: space-around;
+
+		.info-title {
+			font-size: 70rpx;
+			font-family: YSfont;
+			color: #FFF;
+			z-index: 2;
+			text-shadow: 1px -1px 0px #c0c0c0, 2px -2px 0px #b0b0b0, 1px -1px 0px #a0a0a0, 2px -2px 0px #909090;
+		}
+
+		.info-subtitle {
+			font-size: 40rpx;
+			font-family: YSfont;
+			color: #FFF;
+			z-index: 2;
+			margin-left: 10rpx;
+			text-shadow: 1px -1px 0px #c0c0c0, 2px -2px 0px #b0b0b0, 1px -1px 0px #a0a0a0, 2px -2px 0px #909090;
+		}
+	}
+
+	.tag {
+		margin-left: 20rpx;
+		border-radius: 6rpx;
+		border: 2px solid #FFF;
+		padding: 0 6rpx;
+		z-index: 9;
+
+		.tag-text {
+			font-size: 32rpx;
+			font-family: YSfont;
+			color: #FFF;
+			z-index: 9;
+		}
+	}
+</style>

+ 118 - 0
components/z-calendar/dateBox.vue

@@ -0,0 +1,118 @@
+<template>
+	<!-- 日期显示 -->
+	<view class="date_box">
+		<view v-for="(dateInfo, dateIndex) in dates" :key="dateIndex" class="calendar_date__box">
+			<!-- 选择圆背景 -->
+			<view class="calendar_date" :class="{ isSelected: dateInfo.isSelected }" :style="{height: cellHeight + 'rpx',width: cellHeight + 'rpx',color: dateInfo.type === 'cur' ? '#3B4144' : '#aaaaaa' ,backgroundColor: dateInfo.isSelected ? dateActiveColor : ''}" @tap="chooseDate(dateInfo, dateIndex)">
+				<!-- 数字 -->
+				<view class="calendar_date__number">{{ dateInfo.date }}</view>
+				<!-- 今天 -->
+				<view class="calendar_date__isToday" v-if="dateInfo.isToday"
+					:style="{ backgroundColor: dateActiveColor }"></view>
+				<!-- 圆点 -->
+				<view class="cirle_attend" v-show="dateInfo.isAttend === 1" ></view>
+				<view class="cirle_noattend" v-show="dateInfo.isAttend === 0" ></view>
+				<view class="cirle_arrive_weekend" v-show="dateInfo.isAttend === -1 || dateInfo.isAttend === 7" ></view>
+				
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			dates: {
+				type: Array, //日期列表
+				default: []
+			},
+			cellHeight: { // 一列的高度
+				type: Number,
+				default: 75
+			},
+			dateActiveColor: { // 日期选中颜色
+				type: String,
+				default: '#4169E1'
+			},
+			swiperMode: { // 日历显示模式
+				type: String,
+				default: 'open'
+			}
+		},
+		methods: {
+			//选择时间
+			chooseDate(dateInfo, dateIndex) {
+				this.$emit('chooseDate', dateInfo, dateIndex)
+			},
+
+		},
+	}
+</script>
+
+<style>
+	/* 日历轮播 */
+	.date_box {
+		display: flex;
+		flex-wrap: wrap;
+		justify-content: space-between;
+	}
+
+
+	.date_box .calendar_date__box {
+		width: calc(100% / 7);
+		margin-top: 20rpx;
+	}
+
+	.calendar_date__box .calendar_date {
+		text-align: center;
+		margin: 0 auto;
+		font-weight: bold;
+		font-size: 28rpx;
+		border-radius: 50%;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: center;
+		position: relative;
+	}
+
+	.calendar_date__box .calendar_date.isSelected {
+		color: #FFFFFF !important;
+	}
+
+	.calendar_date .calendar_date__isToday {
+		width: 100%;
+		height: 100%;
+		position: absolute;
+		top: 0;
+		left: 0;
+		border-radius: 50%;
+		z-index: -1;
+		opacity: 0.3;
+	}
+/* 圆点 */
+	.calendar_date .cirle_attend {
+		width: 9rpx;
+		height: 9rpx;
+		border-radius: 50%;
+		margin-top: 5rpx;
+		background-color: #4169E1;
+	}
+	.calendar_date .cirle_noattend {
+		width: 9rpx;
+		height: 9rpx;
+		border-radius: 50%;
+		margin-top: 5rpx;
+		background-color: #ff5959;
+	}
+	.calendar_date .cirle_arrive_weekend {
+		width: 9rpx;
+		height: 9rpx;
+		border-radius: 50%;
+		margin-top: 5rpx;
+		background-color: #FFFFFF;
+	}
+
+
+	/* 日历轮播 */
+</style>

+ 68 - 0
components/z-calendar/js/utils.js

@@ -0,0 +1,68 @@
+/**
+ * 时间格式化
+ * @param {String} time
+ * @param {String} cFormat
+ */
+export function parseTime(time, cFormat) {
+	if (arguments.length === 0) {
+	  return null
+	}
+  if (!time) return ''
+  /* 修复IOS系统上面的时间不兼容*/
+  if (time.toString().indexOf('-') > 0) {
+    time = time.replace(/-/g, '/')
+  }
+  const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
+  let date
+  if (typeof time === 'object') {
+    date = time
+  } else {
+    if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
+      time = parseInt(time)
+    }
+    if ((typeof time === 'number') && (time.toString().length === 10)) {
+      time = time * 1000
+    }
+    date = new Date(time)
+  }
+  const formatObj = {
+    y: date.getFullYear(),
+    m: date.getMonth() + 1,
+    d: date.getDate(),
+    h: date.getHours(),
+    i: date.getMinutes(),
+    s: date.getSeconds(),
+    a: date.getDay()
+  }
+  const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
+    const value = formatObj[key]
+    // Note: getDay() returns 0 on Sunday
+    if (key === 'a') {
+      return ['日', '一', '二', '三', '四', '五', '六'][value]
+    }
+    return value.toString().padStart(2, '0')
+  })
+  return time_str
+}
+
+/**
+ * This is just a simple version of deep copy
+ * Has a lot of edge cases bug
+ * If you want to use a perfect deep copy, use lodash's _.cloneDeep
+ * @param {Object} source
+ * @returns {Object}
+ */
+export function deepClone(source) {
+	if (!source && typeof source !== 'object') {
+		throw new Error('error arguments', 'deepClone')
+	}
+	const targetObj = Object.prototype.toString.call(source) === "[object Array]" ? [] : {}
+	Object.keys(source).forEach(keys => {
+		if (source[keys] && typeof source[keys] === 'object') {
+			targetObj[keys] = deepClone(source[keys])
+		} else {
+			targetObj[keys] = source[keys]
+		}
+	})
+	return targetObj
+}

+ 513 - 0
components/z-calendar/zsy-calendar.vue

@@ -0,0 +1,513 @@
+<template>
+	<!-- 日历滚动插件 -->
+	<view class="zsy_calendar">
+		<!-- 日历顶部信息 -->
+		<view class="calendar_info">
+			<text class="title">打卡记录</text>
+			<text class="desc">
+				[{{ getAssignDateInfo(false, 0) === getAssignDateInfo(true, 0) ? '' : getAssignDateInfo(false, 0) + '年' }}{{ getAssignDateInfo(false, 1) }}月]
+			</text>
+			<text v-show="showBackToTodayBtn" class="backToToday" :style="{color: dateActiveColor}"
+				@tap="goToDate()">回到今天</text>
+		</view>
+
+		<!-- 日历周数 -->
+		<view class="calendar_week">
+			<view v-for="(item, index) in week" :key="index" class="calendar_week__item">{{ item }}</view>
+		</view>
+
+		<!-- 日历轮播 -->
+		<view class="calendar_swiper">
+			<!-- 展开情况下的日历轮播 -->
+			<swiper v-if="swiperMode === 'open'" key="normalSwiper" circular :style="{height: swiperHeight('open')}"
+				:current="current" :duration="duration" :skip-hidden-item-layout="true"
+				@change="e => current = e.detail.current">
+				<swiper-item v-for="(swiper, swiperIndex) in 3" :key="swiperIndex" class="swiper-item">
+					<DateBox :dates="calendarSwiperDates[swiperIndex]" :cellHeight="cellHeight" :swiperMode="swiperMode" @chooseDate="chooseDate" />
+				</swiper-item>
+			</swiper>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState,
+		mapMutations
+	} from 'vuex'
+	import {
+		parseTime,
+		deepClone
+	} from './js/utils.js'
+	import DateBox from './dateBox.vue'
+	export default {
+		name: 'ZsyCalendar',
+		components: {
+			DateBox
+		},
+		props: {
+			duration: { // 轮播图动画时长
+				type: Number,
+				default: 300
+			},
+			cellHeight: { // 一列的高度
+				type: Number,
+				default: 75
+			},
+			dateActiveColor: { // 日期选中颜色
+				type: String,
+				default: '#4169E1'
+			},
+			sundayIndex: { // 星期天所在索引,0表示第一个、6表示最后一个
+				type: Number,
+				default: 6
+			},
+			mode: { // 日历模式
+				type: String,
+				default: 'open'
+			},
+			changeSetDefault: { // 月份切换时是否显示一号还是当前月份选中高亮
+				type: Boolean,
+				default: true
+			}
+		},
+		data() {
+			return {
+				today: parseTime(new Date(), '{y}-{m}-{d}'), // 今天日期
+				selectedDate: null, // 选中日期
+				week: [], // 日历周数
+				current: 1, // 当前日历轮播默认显示索引
+				// shrinkCurrent: 1, // 缩放日历轮播默认显示索引
+				calendarSwiperDates: [], // 日历轮播日期信息
+				calendarSwiperShrinkDates: [], // 日历轮播收缩时的日期信息
+				dateActive: -1, // 日期选中索引
+				swiperByClick: false, // 是否通过点击上月份或下月份的日期进行轮播切换
+				shrinkSwiperByClick: false, // 是否通过点击上月份或下月份的日期进行收缩日历的轮播切换
+				swiperMode: this.mode, // 日历轮播显示模式 open:展开 close:收缩
+				dateCache: {}, // 日期缓存
+				emitTimer: null, // 日期改变向父级传递当前选中日期计时器
+				dateClick: false, // 是否进行了日期的点击选择
+			}
+		},
+		computed: {
+			...mapState('m_children', ['clockData']),
+			/* 获取指定日期信息
+			isCurDate: 是否获取当天的信息还是选中日期的信息
+			index: 0 表示年份 1 表示月份 2 表示日期 */
+			getAssignDateInfo() {
+				return (isCurDate, index) => {
+					return (isCurDate ? this.today : this.selectedDate).split('-')[index] * 1
+				}
+			},
+			// 是否显示回到今天按钮
+			showBackToTodayBtn() {
+				return this.getAssignDateInfo(false, 0) !== this.getAssignDateInfo(true, 0) || this.getAssignDateInfo(
+					false, 1) !== this.getAssignDateInfo(true, 1)
+			},
+			// 返回轮播图高度
+			swiperHeight() {
+				return (swiperMode) => {
+					const normalHeight = (this.calendarSwiperDates[this.current] || []).length / 7 * (this.cellHeight +
+						20) + 'rpx'
+					const shrinkHeight = this.cellHeight + 20 + 'rpx'
+					return swiperMode === 'open' ? normalHeight : shrinkHeight
+				}
+			}
+		},
+		watch: {
+			// 展开日历轮播切换
+			current(newV, oldV) {
+				if (newV === 0 && oldV === 2) { // 右滑
+					this.swiperChange(1)
+					return
+				}
+				if (newV === 2 && oldV === 0) { // 左滑
+					this.swiperChange(-1)
+					return
+				}
+				if (newV > oldV) { // 右滑
+					this.swiperChange(1)
+				} else { // 左滑
+					this.swiperChange(-1)
+				}
+			},
+			selectedDate: {
+				deep: true,
+				handler(newV, oldV) {
+					if (newV && (oldV === null || this.dateClick)) { // 初始化/日历点击选择时直接返回
+						this.emitDate()
+						this.dateClick = false
+					} else { // 其它情况做防抖处理
+						if (this.emitTimer !== null) {
+							clearTimeout(this.emitTimer)
+						}
+						this.emitTimer = setTimeout(() => {
+							this.emitDate()
+						}, this.duration + 1)
+					}
+				}
+			}
+		},
+		created() {
+			this.init() // 初始化数据
+		},
+		methods: {
+			...mapMutations('m_children', ['updateNoAttendNum']),
+			// 初始化数据
+			init() {
+				if (this.selectedDate === null) this.selectedDate = this.today // 默认选中日期为当天
+				this.initWeek() // 初始化要显示的周数
+				this.initCalendarSwiperDates() // 初始化日历轮播日期信息
+				// 解决swiperMode初始化为收缩时没有初始化日历收缩轮播日期信息
+			},
+			// 初始化周数
+			initWeek() {
+				const normalWeek = ['日', '一', '二', '三', '四', '五', '六'] // 正常周数
+				const sIndex = this.sundayIndex < 0 ? 0 : this.sundayIndex >= normalWeek.length ? normalWeek.length - 1 :
+					this.sundayIndex
+				normalWeek.unshift(...normalWeek.slice(-sIndex))
+				normalWeek.length = 7
+				this.week = normalWeek
+			},
+			// 初始化展开时的日历轮播日期信息
+			initCalendarSwiperDates(cb) {
+				const year = this.getAssignDateInfo(false, 0)
+				const month = this.getAssignDateInfo(false, 1)
+				const cur = this.generateCalendar(year, month)
+				const prev = this.generateCalendar(month === 1 ? year - 1 : year, month === 1 ? 12 : month - 1)
+				const next = this.generateCalendar(month === 12 ? year + 1 : year, month === 12 ? 1 : month + 1)
+				// 根据current来判断相邻的轮播存放哪些日历数据
+				if (this.current === 0) {
+					this.calendarSwiperDates = [cur, next, prev]
+				} else if (this.current === 1) {
+					this.calendarSwiperDates = [prev, cur, next]
+				} else if (this.current === 2) {
+					this.calendarSwiperDates = [next, prev, cur]
+				}
+				this.swiperByClick = false
+
+				// 初始化日期信息完毕执行回调函数
+				cb && cb()
+			},
+
+			// 生成展开的日历数据
+			generateCalendar(year, month) {
+				let calendarDate = []
+				// 先获取缓存里面有没有该月的日期数据
+				if (this.dateCache[`${year}-${month}`]) {
+					calendarDate = deepClone(this.dateCache[`${year}-${month}`])
+				} else { // 进行月份日期的计算
+					const monthDates = new Date(year, month, 0).getDate() // 获取此月份总天数
+					const normalWeek = ['一', '二', '三', '四', '五', '六', '日'] // 正常周数
+					const monthFirstDay = normalWeek[new Date(year, month - 1, 0).getDay()] // 获取本月一号为星期几
+					const monthFirstDayIndex = this.week.indexOf(monthFirstDay) // 计算本月一号在日历周数中的索引,索引之前的填充上个月的后几天
+					// 本月一号在日历中不是第一个位置,需要进行填充
+					if (monthFirstDayIndex !== 0) {
+						const prevMonthDates = new Date(year, month - 1, 0).getDate() // 获取上一个月份的总天数
+						// 填充本月一号之前的数据
+						for (let i = 0; i < monthFirstDayIndex; i++) {
+							const item = {
+								year: month === 1 ? year - 1 : year,
+								month: month === 1 ? 12 : month - 1,
+								date: prevMonthDates - i,
+								type: 'prev',
+								isAttend: 0, //未打卡
+							}
+							this.theDateIsToday(item)
+							calendarDate.unshift(item)
+						}
+					}
+					// 循环生成当月所有日期
+					for (let i = 1; i <= monthDates; i++) {
+						let item = {
+							year,
+							month,
+							date: i,
+							isSelected: false,
+							isToday: false,
+							type: 'cur',
+							isAttend: 0, //未打卡
+						}
+
+						// 今天的日期在不在里面
+						this.theDateIsToday(item)
+						calendarDate.push(item)
+					}
+					const residue = calendarDate.length % 7
+					// 判断是否需要填充下个月的前几天
+					if (residue !== 0) {
+						for (let i = 1; i <= 7 - residue; i++) {
+							const item = {
+								year: month === 12 ? year + 1 : year,
+								month: month === 12 ? 1 : month + 1,
+								date: i,
+								type: 'next',
+								isAttend: 0, //未打卡
+							}
+							this.theDateIsToday(item)
+							calendarDate.push(item)
+						}
+					}
+					this.dateCache[`${year}-${month}`] = deepClone(calendarDate)
+				}
+				// 进行日期的默认选中
+				if (year === this.getAssignDateInfo(false, 0) && month === this.getAssignDateInfo(false, 1)) {
+					for (let i = 0, len = calendarDate.length; i < len; i++) {
+						if (calendarDate[i].type === 'cur' && calendarDate[i].date === this.getAssignDateInfo(false, 2)) {
+							calendarDate[i].isSelected = true
+							this.dateActive = i
+							break
+						}
+					}
+				}
+				//周末数据
+				let weekendArr = []
+				//获取本月周末存为数组
+				const monthDays = new Date(year, month, 0).getDate()
+				for (let i = 1; i <= monthDays; i++) {
+					if (new Date(`${year}-${month}-${i}`).getDay() === 0 ||
+						new Date(`${year}-${month}-${i}`).getDay() === 6) {
+						weekendArr.push({
+							m: month,
+							d: i
+						})
+					}
+				}
+				//上一月
+				const prevMonthDays = new Date(year, month-1, 0).getDate()
+				for (let i = 1; i <= prevMonthDays; i++) {
+					if (new Date(`${year}-${month-1}-${i}`).getDay() === 0 ||
+						new Date(`${year}-${month-1}-${i}`).getDay() === 6) {
+						weekendArr.push({
+							m: month-1,
+							d: i
+						})
+					}
+				}
+				//下一月
+				const nextMonthDays = new Date(year, month+1, 0).getDate()
+				for (let i = 1; i <= nextMonthDays; i++) {
+					if (new Date(`${year}-${month+1}-${i}`).getDay() === 0 ||
+						new Date(`${year}-${month+1}-${i}`).getDay() === 6) {
+						weekendArr.push({
+							m: month+1,
+							d: i
+						})
+					}
+				}
+
+				//判断是否打卡和时间对比并修改数据
+				let todayDate = Date.now() //毫秒数
+				calendarDate.forEach(item => {
+					if (this.clockData.find(x => x.month === item.month && x.year === item.year && x.date === item.date)) {
+						item.isAttend = 1 //已打卡
+					}
+					//判断是否在当前日期之后
+					let valueTime = (new Date(`${item.year}/${item.month}/${item.date}`)).getTime();
+					if (valueTime > todayDate) {
+						item.isAttend = -1 //时间未到
+					}
+					//判断是否为周末
+					if (weekendArr.find(x=>x.m === item.month && x.d === item.date)){
+						item.isAttend = 7 //周末数据
+					}
+				})
+
+				return calendarDate
+			},
+
+			// 判断日期是否为今天
+			theDateIsToday(item) {
+				if (item.year + '-' + item.month + '-' + item.date === this.getAssignDateInfo(true, 0) + '-' + this
+					.getAssignDateInfo(true, 1) + '-' + this.getAssignDateInfo(true, 2)) {
+					item.isToday = true
+				}
+			},
+			// 展开日历轮播切换
+			swiperChange(type) {
+				// 通过点击上个月/下个月日期进行切换,不需要默认选中下个月的一号,直接选中点击的那个日期
+				if (!this.swiperByClick && this.swiperMode === 'open') {
+					this.getPrevOrNextDate(type)
+				}
+				setTimeout(() => { // 设置定时器是为了防止轮播切换时生成数据造成页面卡顿
+					this.initCalendarSwiperDates(() => {
+						this.swiperMode === 'close'
+					}) // 初始化日历轮播日期信息
+				}, this.swiperMode === 'open' ? this.duration : 0)
+			},
+			// 获取上一个月/下一个月的一号日期
+			getPrevOrNextDate(type) {
+				const year = this.getAssignDateInfo(false, 0)
+				let month = this.getAssignDateInfo(false, 1)
+				month = month + type
+				// 判断切换月份时选中当前日期高亮还是一号,若选中当前日期高亮需进行大小判断
+				const curActiveDate = this.getAssignDateInfo(false, 2)
+				const maxDate = new Date(year, month, 0).getDate()
+				const date = this.changeSetDefault ? 1 : curActiveDate > maxDate ? maxDate : curActiveDate
+				this.selectedDate = parseTime(new Date(year, month - 1, date), '{y}-{m}-{d}')
+			},
+			// 获取上个星期/下一星期的开始日期
+			getPrevOrNextStartDate(type) {
+				const date = this.calendarSwiperShrinkDates[this.shrinkCurrent][0]
+				this.selectedDate = parseTime(new Date(date.year, date.month - 1, date.date), '{y}-{m}-{d}')
+			},
+			// 前往某一天 格式 YYYY-MM | YYYY-MM-DD
+			goToDate(date = this.today) {
+				try {
+					if (date.split('-').length < 2 || date.split('-').length > 3) throw '参数有误'
+					if (date.split('-').length === 2) {
+						date += '-01'
+					}
+				} catch (err) {
+					throw Error('请检查参数是否符合规范')
+				}
+				this.selectedDate = date
+				this.initCalendarSwiperDates(() => {})
+			},
+			// 日历轮播展开的情况下选择日期
+			chooseDate(dateInfo, dateIndex) {
+				// 重复点击后续不做处理
+				if (dateInfo.isSelected) return false
+				// 是否点击了上个月份的后几天或者点击了下个月份的前几天
+				if (dateInfo.type !== 'cur') {
+					if (dateInfo.type === 'prev') { // 点击了上个月份的后几天,滑到上个月
+						this.current = this.current === 0 ? 2 : this.current - 1
+					} else { // 点击了下个月份的前几天,滑到下个月
+						this.current = this.current === 2 ? 0 : this.current + 1
+					}
+					// 将选中日期赋值为当前点击的那个日期
+					this.selectedDate = parseTime(new Date(dateInfo.year, dateInfo.month - 1, dateInfo.date),
+						'{y}-{m}-{d}')
+					this.swiperByClick = true
+					this.$emit('chooseDate', dateInfo, dateIndex)
+					return false
+				}
+				// 将当前选中的日期清空并选中最新的日期
+				this.calendarSwiperDates[this.current][this.dateActive].isSelected = false
+				this.dateActive = dateIndex
+				const date = this.calendarSwiperDates[this.current][this.dateActive]
+				date.isSelected = true
+				this.selectedDate = parseTime(new Date(date.year, date.month - 1, date.date), '{y}-{m}-{d}')
+				this.dateClick = true
+				this.$emit('chooseDate', dateInfo, dateIndex)
+			},
+			// 向父组件传递当前选中数据
+			emitDate() {
+				//获取当前日包含数据
+				const {
+					year,
+					month,
+					date,
+					isAttend
+				} = this.calendarSwiperDates[this.current][this.dateActive]
+				//传递数据
+				const e = {
+					selectedDate: this.selectedDate,
+					year,
+					month,
+					date,
+					isAttend
+				}
+				this.$emit('change', e)
+			},
+
+		}
+	}
+</script>
+
+<style>
+	.zsy_calendar {
+		width: 100%;
+		padding: 30rpx 10rpx 0rpx 10rpx;
+		box-sizing: border-box;
+		background-color: #fff;
+		border-radius: 20rpx;
+	}
+
+	/* 日历顶部信息 */
+	.calendar_info {
+		display: flex;
+		align-items: center;
+		padding: 0 20rpx;
+	}
+
+	.calendar_info .title {
+		font-size: 32rpx;
+		font-weight: bold;
+		color: #303133;
+	}
+
+	.calendar_info .desc {
+		margin-left: 29rpx;
+		font-size: 28rpx;
+		color: #959595;
+	}
+
+	.calendar_info .backToToday {
+		margin-left: auto;
+		font-size: 26rpx;
+	}
+
+	/* 日历顶部信息 */
+
+	/* 日历周数 */
+	.calendar_week {
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		font-size: 26rpx;
+		color: #959595;
+		margin: 20rpx 0rpx;
+	}
+
+	.calendar_week .calendar_week__item {
+		width: calc(100% / 7);
+		text-align: center;
+	}
+
+	/* 日历周数 */
+
+	/* 日历切换模式 */
+	.calendar_toggle {
+		position: relative;
+		padding: 10rpx 0;
+		margin: 10rpx 20rpx 0;
+		display: flex;
+		justify-content: center;
+	}
+
+	/* .calendar_toggle .icon {
+		width: 30rpx;
+		height: 30rpx;
+		background-image: url('../../subpkg/zsy-calendar/icon/arrow.png');
+		background-size: contain;
+		background-repeat: no-repeat;
+		margin: 0 auto;
+		transition: all .3s;
+	}
+
+	.icon.down {
+		transform: rotate(180deg);
+	} */
+
+	.calendar_toggle::before,
+	.calendar_toggle::after {
+		width: calc(50% - 30rpx);
+		border-top: solid 2rpx #EAEAEA;
+		content: '';
+		display: block;
+		position: absolute;
+		top: 50%;
+		transform: translateY(-50%);
+	}
+
+	.calendar_toggle::before {
+		left: 0;
+	}
+
+	.calendar_toggle::after {
+		right: 0;
+	}
+
+	/* 日历切换模式 */
+</style>

+ 34 - 0
main.js

@@ -0,0 +1,34 @@
+import App from './App'
+import Vue from 'vue'
+import uView from '@/uni_modules/uview-ui'
+import store from '@/store/store.js'
+import Common from '@/utils/CommonMethods.js'
+import Request from '@/utils/RequestHandler.js'
+import apiTools from '@/utils/Api.js'
+//挂载全局方法
+Date.prototype.format = Common.dateUtil
+Vue.prototype.$noMultipleClicks = Common.noMultipleClicks
+Vue.prototype.$getRecentDateArray = Common.getRecentDateArray
+Vue.prototype.$timeStampToTime = Common.timeStampToTime
+Vue.prototype.$logOut = Common.logOut
+
+
+Vue.prototype.$initStart = Request.initStart
+Vue.prototype.$initTab = Request.initTab
+Vue.prototype.$initHome = Request.initHome
+Vue.prototype.$initExam = Request.initExam
+Vue.prototype.$initWork = Request.initWork
+Vue.prototype.$initSwap = Request.initSwap
+
+Vue.prototype.$api = new apiTools()
+//挂载使用
+Vue.use(uView);
+
+
+Vue.config.productionTip = false;
+App.mpType = 'app';
+const app = new Vue({
+  ...App,
+	store
+});
+app.$mount();

+ 81 - 0
manifest.json

@@ -0,0 +1,81 @@
+{
+    "name" : "teammodelwxapp",
+    "appid" : "__UNI__74CA2D5",
+    "description" : "",
+    "versionName" : "1.0.0",
+    "versionCode" : "100",
+    "transformPx" : false,
+    /* 5+App特有相关 */
+    "app-plus" : {
+        "usingComponents" : true,
+        "nvueStyleCompiler" : "uni-app",
+        "compilerVersion" : 3,
+        "splashscreen" : {
+            "alwaysShowBeforeRender" : true,
+            "waiting" : true,
+            "autoclose" : true,
+            "delay" : 0
+        },
+        "optimization" : {
+            "subPackages" : true
+        },
+        "runmode" : "liberate",
+        // 开启分包优化后,必须配置资源释放模式
+        /* 模块配置 */
+        "modules" : {},
+        /* 应用发布信息 */
+        "distribute" : {
+            /* android打包配置 */
+            "android" : {
+                "permissions" : [
+                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
+                    "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
+                    "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
+                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera\"/>",
+                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
+                ]
+            },
+            /* ios打包配置 */
+            "ios" : {},
+            /* SDK配置 */
+            "sdkConfigs" : {}
+        }
+    },
+    /* 快应用特有相关 */
+    "quickapp" : {},
+    /* 小程序特有相关 */
+    "mp-weixin" : {
+        "appid" : "wx5705da8747c77cfe",
+        "setting" : {
+            "urlCheck" : true,
+            "es6" : true,
+            "postcss" : true,
+            "minified" : true
+        },
+        "usingComponents" : true,
+        "permission" : {}
+    },
+    "mp-alipay" : {
+        "usingComponents" : true
+    },
+    "mp-baidu" : {
+        "usingComponents" : true
+    },
+    "mp-toutiao" : {
+        "usingComponents" : true
+    },
+    "uniStatistics" : {
+        "enable" : false
+    },
+    "vueVersion" : "2"
+}

+ 19 - 0
package.json

@@ -0,0 +1,19 @@
+{
+    "id": "th-autograph",
+    "name": "签名画板组件(兼容多端,支持横竖屏切换)",
+    "version": "0.1.2",
+    "description": "手写画板,支持颜色、线条、撤回、清空、横竖屏切换、操作栏控制等,简约风",
+    "keywords": [
+        "签名",
+        "横竖屏",
+        "canvas",
+        "画板",
+        "电子签名"
+    ],
+    "dcloudext": {
+        "category": [
+            "前端组件",
+            "通用组件"
+        ]
+    }
+}

+ 268 - 0
pages.json

@@ -0,0 +1,268 @@
+{
+	"pages": [{
+			"path": "pages/init/init",
+			"style": {
+				"enablePullDownRefresh": false,
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path": "pages/tab_home/tab_home",
+			"style": {
+				"enablePullDownRefresh": true,
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path": "pages/tab_exam/tab_exam",
+			"style": {
+				"enablePullDownRefresh": true,
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path": "pages/tab_work/tab_work",
+			"style": {
+				"enablePullDownRefresh": true,
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path": "pages/tab_swap/tab_swap",
+			"style": {
+				"enablePullDownRefresh": true,
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path": "pages/tab_mine/tab_mine",
+			"style": {
+				"enablePullDownRefresh": false,
+				"navigationStyle": "custom"
+			}
+		}
+	],
+	"subPackages": [{
+		"root": "subpkg",
+		"pages": [{
+				"path": "startup/login",
+				"style": {
+					"enablePullDownRefresh": false,
+					"navigationStyle": "custom",
+					"disableScroll": true
+				}
+			},
+			{
+				"path": "startup/guide",
+				"style": {
+					"enablePullDownRefresh": false,
+					"navigationStyle": "custom",
+					"disableScroll": true
+				}
+			},
+			{
+				"path": "startup/options",
+				"style": {
+					"enablePullDownRefresh": false,
+					"navigationStyle": "custom",
+					"disableScroll": true
+				}
+			},
+			{
+				"path": "home/classList",
+				"style": {
+					"enablePullDownRefresh": true,
+					"navigationStyle": "custom"
+				}
+			},
+			{
+				"path": "mine/msgList",
+				"style": {
+					"enablePullDownRefresh": true,
+					"navigationStyle": "custom"
+				}
+			},
+			{
+				"path": "mine/childInfo",
+				"style": {
+					"enablePullDownRefresh": true,
+					"navigationStyle": "custom",
+					"disableScroll": true
+				}
+			},
+			{
+				"path": "mine/parentInfo",
+				"style": {
+					"enablePullDownRefresh": true,
+					"navigationStyle": "custom",
+					"disableScroll": true
+				}
+			},
+			{
+				"path": "mine/subInfo",
+				"style": {
+					"enablePullDownRefresh": false,
+					"navigationStyle": "custom",
+					"disableScroll": true
+				}
+			},
+			{
+				"path": "exam/total",
+				"style": {
+					"enablePullDownRefresh": false,
+					"navigationStyle": "custom"
+				}
+			},
+			{
+				"path": "exam/single",
+				"style": {
+					"enablePullDownRefresh": false,
+					"navigationStyle": "custom"
+				}
+			},
+			{
+				"path": "exam/rank",
+				"style": {
+					"enablePullDownRefresh": false,
+					"navigationStyle": "custom"
+				}
+			},
+			{
+				"path": "exam/subject",
+				"style": {
+					"enablePullDownRefresh": false,
+					"navigationStyle": "custom"
+				}
+			},
+			{
+				"path": "exam/level",
+				"style": {
+					"enablePullDownRefresh": false,
+					"navigationStyle": "custom"
+				}
+			},	
+			{
+				"path": "work/workStats",
+				"style": {
+					"enablePullDownRefresh": false,
+					"navigationStyle": "custom"
+				}
+			},
+			{
+				"path": "swap/swapStats",
+				"style": {
+					"enablePullDownRefresh": false,
+					"navigationStyle": "custom"
+				}
+			},
+			{
+				"path": "home/clockStats",
+				"style": {
+					"enablePullDownRefresh": false,
+					"navigationStyle": "custom",
+					"disableScroll": true
+				}
+			},
+			{
+				"path": "datalist/examReport",
+				"style": {
+					"enablePullDownRefresh": false,
+					"navigationStyle": "custom"
+				}
+			},
+			{
+				"path": "datalist/workReport",
+				"style": {
+					"enablePullDownRefresh": false,
+					"navigationStyle": "custom"
+				}
+			},
+			{
+				"path": "datalist/swapReport",
+				"style": {
+					"enablePullDownRefresh": false,
+					"navigationStyle": "custom"
+				}
+			},
+			{
+				"path": "datalist/examList",
+				"style": {
+					"enablePullDownRefresh": false,
+					"navigationStyle": "custom"
+				}
+			},
+			{
+				"path": "datalist/workList",
+				"style": {
+					"enablePullDownRefresh": false,
+					"navigationStyle": "custom"
+				}
+			},
+			{
+				"path": "datalist/swapList",
+				"style": {
+					"enablePullDownRefresh": false,
+					"navigationStyle": "custom"
+				}
+			},
+			{
+				"path": "exam/examPractice",
+				"style": {
+					"enablePullDownRefresh": false,
+					"navigationStyle": "custom"
+				}
+			},
+			{
+				"path": "home/courseRecommend",
+				"style": {
+					"enablePullDownRefresh": false,
+					"navigationStyle": "custom"
+				}
+			},
+			{
+				"path": "work/wrongBook",
+				"style": {
+					"enablePullDownRefresh": false,
+					"navigationStyle": "custom"
+				}
+			}
+
+		]
+	}],
+	"globalStyle": {
+		"navigationBarTextStyle": "black",
+		"navigationBarBackgroundColor": "#f7f7f7",
+		"backgroundColor": "#f7f7f7"
+	},
+	"tabBar": {
+		"backgroundColor": "#FFFFFF",
+		"borderStyle": "white",
+
+		"list": [{
+				"pagePath": "pages/tab_home/tab_home",
+				"iconPath": "static/tab_icons/home.png",
+				"selectedIconPath": "static/tab_icons/homeselect.png"
+			},
+			{
+				"pagePath": "pages/tab_exam/tab_exam",
+				"iconPath": "static/tab_icons/exam.png",
+				"selectedIconPath": "static/tab_icons/examselect.png"
+			},
+			{
+				"pagePath": "pages/tab_work/tab_work",
+				"iconPath": "static/tab_icons/work.png",
+				"selectedIconPath": "static/tab_icons/workselect.png"
+			},
+			{
+				"pagePath": "pages/tab_swap/tab_swap",
+				"iconPath": "static/tab_icons/swap.png",
+				"selectedIconPath": "static/tab_icons/swapselect.png"
+			},
+			{
+				"pagePath": "pages/tab_mine/tab_mine",
+				"iconPath": "static/tab_icons/mine.png",
+				"selectedIconPath": "static/tab_icons/mineselect.png"
+			}
+		]
+	}
+}

+ 60 - 0
pages/init/init.vue

@@ -0,0 +1,60 @@
+<template>
+	<view>
+		<loading></loading>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex'
+	export default {
+		computed: {
+			...mapState('m_children', ['examData', 'workData', 'swapData'])
+		},
+		onLoad() {
+			//缓存中同步token
+			if (!uni.getStorageSync('token')) {
+				console.log('无Token跳转登录');
+				setTimeout(function() {
+					uni.redirectTo({
+						url: '/subpkg/startup/login'
+					})
+				}, 1500);
+
+			} else {
+				if (!uni.getStorageSync('phoneNumber')) {
+					uni.redirectTo({
+						url: '/subpkg/startup/guide'
+					})
+					return console.log('有Token无手机号跳转引导页');
+				}
+				if (!uni.getStorageSync('childInfo')) {
+					uni.redirectTo({
+						url: '/subpkg/startup/options'
+					})
+					return console.log('有Token有手机号无孩子信息跳转选择页');
+				}
+				console.log('有Token跳转首页');
+				this.allTasks()
+			}
+		},
+		methods: {
+			//获得异步请求返回值
+			async allTasks() {
+				try {
+					await this.$initTab()
+					uni.switchTab({
+						url: '/pages/tab_home/tab_home'
+					})
+				} catch (e) {
+					this.$logOut()
+				}
+			},
+		}
+	}
+</script>
+
+<style lang="scss">
+
+</style>

+ 211 - 0
pages/style/tab_pages.scss

@@ -0,0 +1,211 @@
+	//头部背景
+	.bg1 {
+		display: flex;
+		flex-direction: column;
+		margin-top: -400rpx;
+		// width: 1000rpx;
+		height: 1200rpx;
+		border-radius: 100rpx;
+		border-bottom-right-radius: 0;
+		background-color: $color-blue;
+		z-index: 2;
+	
+		.scroll-view {
+			white-space: nowrap;
+			height: 400rpx;
+			margin: 70rpx 0 50rpx 0;
+	
+			.view-box{
+				margin: 0 50rpx;
+				.scroll-view-item {
+					position: relative;
+					display: inline-block;
+					vertical-align: top;
+					margin: 0 50rpx 0 0rpx;
+					width: 380rpx;
+					height: 400rpx;
+					border-radius: 30rpx;
+					background-color: #FFF;
+					
+					.card-info {
+						position: relative;
+						display: flex;
+						align-items: center;
+						padding: 20rpx;
+					
+						.title {
+							font-size: 30rpx;
+							line-height: 40rpx;
+							margin-left: 20rpx;
+						}
+					}
+					
+					.chart-box {
+						width: 100%;
+						height: 300rpx;
+					}
+				}
+			}
+		}
+	}
+	//数据表列
+	.data-list {
+		display: flex;
+		flex-direction: column;
+		justify-content: space-between;
+		margin: 0 30rpx 20rpx 30rpx;
+
+		.data-item {
+			display: flex;
+			flex-direction: column;
+			justify-content: space-around;
+			margin: 10rpx 0;
+			padding: 6rpx 0;
+			height: 120rpx;
+			border-bottom: 4rpx solid #f3f4f9;
+			border-top: 4rpx solid #f3f4f9;
+
+			.item-title {
+				font-size: 38rpx;
+				font-family: YSfont;
+				color: $title;
+			}
+
+			.item-subtitle {
+				font-size: 30rpx;
+				font-weight: bold;
+				color: $subtitle; 
+				overflow: hidden;    
+				text-overflow:ellipsis;    
+				white-space: nowrap;
+			}
+
+			.item-detail {
+				margin-left: 40rpx;
+				line-height: 30rpx;
+				font-size: 36rpx;
+				font-family: YSfont;
+				color: $subtitle;
+			}
+		}
+	}
+	//统计卡片
+	.stat-card{
+		display: flex;
+		justify-content: space-around;
+		margin: 2% 0;
+		width: 100%;
+		height: 220rpx;
+		background-color: $color-pink;
+		border-radius: $border-radius;
+		.card-column{
+			display: flex;
+			flex-direction: column;
+			justify-content: space-around;
+			margin: 20rpx 0 20rpx 20rpx;
+		}
+		// 卡片字体
+		._title{
+			font-size: 54rpx;	
+			font-family: YSfont;
+			color: #FFF;
+		}
+		._subtitle{
+			font-size: 34rpx;
+			font-family: YSfont;
+			color: #FFF;
+		}
+		._unit{
+			margin-left: 20rpx;
+			font-size: 30rpx;
+			font-family: YSfont;
+			opacity: 0.7;
+			color: #FFF;
+		}
+		// 卡片图片
+		.card-image {
+			position: relative;
+			top: -40rpx;
+			right: -40rpx;
+			height: 300rpx;
+			width: 300rpx;
+			background-size: cover;
+			background-repeat: no-repeat;
+			z-index: 2;
+		}
+	}
+
+	.scroll-view-bottom{
+		white-space: nowrap;
+		padding-bottom: 40rpx;
+
+		.scroll-item{
+			margin: 0 20rpx;
+			display: inline-block;
+			vertical-align: top;
+			background-color: #FFF;
+			border-radius: $border-radius;
+			height: 320rpx;
+			width: 280rpx;
+			overflow: hidden;
+			z-index: 55;
+			.t-icon {
+				width: 120rpx;
+				height: 120rpx;
+			}
+		}
+	}
+	.circle-line1 {
+		position: absolute;
+		width: 352rpx;
+		height: 352rpx;
+		margin-top: 440rpx;
+		margin-left: -70rpx;
+		border: 4rpx solid transparent;
+		border-radius: 100%;
+		background-clip: padding-box, border-box;
+		background-origin: padding-box, border-box;
+		background-image: linear-gradient(to right, #4169E1, #4169E1), linear-gradient(90deg, #FFF -50%, rgba(255, 255, 255, 0.0));
+	}
+	.circle-line2 {
+		position: absolute;
+		width: 232rpx;
+		height: 232rpx;
+		margin-top: 500rpx;
+		margin-left: -10rpx;
+		border: 4rpx solid transparent;
+		border-radius: 100%;
+		background-clip: padding-box, border-box;
+		background-origin: padding-box, border-box;
+		background-image: linear-gradient(to right, #4169E1, #4169E1), linear-gradient(0deg, #FFF -75%, rgba(255, 255, 255, 0.0));
+		z-index: 2;
+	}
+	.circle-line3 {
+		position: absolute;
+		width: 176rpx;
+		height: 176rpx;
+		margin-top: 530rpx;
+		margin-left: 20rpx;
+		border: 2rpx solid transparent;
+		border-radius: 100%;
+		background-clip: padding-box, border-box;
+		background-origin: padding-box, border-box;
+		background-image: linear-gradient(to right, #4169E1, #4169E1), linear-gradient(-90deg, #FFF -100%, rgba(255, 255, 255, 0.0));
+		z-index: 3;
+	}
+	
+	.image-box{
+		display: flex;
+		flex-direction: column;
+		height: 100%;
+		align-items: center;
+		margin-bottom: 30rpx;
+	}
+	.detail-image-none {
+		margin-top: -50rpx;
+	  width: 100%;
+	  height: 450rpx;
+	  background-size: cover; //背景图片自适应
+	  background-repeat: no-repeat;
+	  z-index: 50;
+	}

+ 353 - 0
pages/tab_exam/tab_exam.vue

@@ -0,0 +1,353 @@
+<template>
+	<view class="page-view">
+		<!-- 统计 -->
+		<view class="bg1">
+			<view class="circle-line1"></view>
+			<view class="circle-line2"></view>
+			<view class="circle-line3"></view>
+			<top-info :timeStamp="timeStamp"></top-info>
+			<scroll-view class="scroll-view" scroll-x="true" :scroll-with-animation="true" scroll-left="0">
+				<view class="view-box">
+					<view class="scroll-view-item" v-for="(item,index) in cardList" :key="index"
+						@click="navGradeList(index)">
+						<view class="card-info">
+							<view :class="item.icon"></view>
+							<view class="title">{{item.title}}</view>
+						</view>
+						<view class="chart-box">
+							<qiun-data-charts :type="item.type" :chartData="item.data" />
+						</view>
+					</view>
+				</view>
+			</scroll-view>
+		</view>
+		<!-- 统计卡片 -->
+		<view class="card-view">
+			<view class="stat-card">
+				<view class="card-column">
+					<view class="flex-baseline">
+						<text class="_title">评测总数</text>
+						<text class="_title" style="margin-left: 20rpx;">{{examData.length}}</text>
+						<text class="_unit">例</text>
+					</view>
+					<view class="flex-baseline">
+						<text class="_subtitle">已完成</text>
+						<text class="_subtitle" style="margin-left: 20rpx;">{{finishData.length}}</text>
+						<text class="_unit">例</text>
+					</view>
+					<view class="flex-baseline">
+						<text class="_subtitle">完成情况</text>
+						<text class="_subtitle" style="margin-left: 20rpx;">{{performance}}</text>
+					</view>
+				</view>
+				<view class="card-image" :style="{backgroundImage:`url(${image})`}"></view>
+			</view>
+			<!-- 列表卡片 -->
+			<view class="card-item" style="width: 100%;">
+				<view class="card-title">
+					<view class="front-tag"></view>
+					<view class="title">评测列表</view>
+					<view class="flex-row" style="margin: 0 0 0 auto;" @click="navExamList" v-if="examData.length != 0">
+						<view class="t-icon t-icon-fenlei"></view>
+						<view class="title" style="color: #4169E1;margin-left: 10rpx;">评测详情</view>
+					</view>
+				</view>
+				<view class="data-list">
+					<view class="data-item" :style="{borderImage: none}" v-for="(item,index) in examData" :key="index"
+						@click="navExamReport(index)" v-if="examData.length != 0">
+						<view class="flex-row" style="margin: 0 20rpx;">
+							<view class="t-icon t-icon-examicon" style="width: 60rpx; height: 60rpx;"></view>
+							<view class="flex-column" style="height:92rpx;justify-content: space-between;">
+								<view class="flex-row" style="margin-left: 20rpx;">
+									<view class="item-title">{{item.examInfo.name}}</view>
+								</view>
+								<view class="flex-row">
+									<view class="tag-fill">
+										<view class="tag-text">{{item.examInfo.subjects[0].name}}</view>
+									</view>
+									<view class="tag-fill">
+										<view class="tag-text">{{item.examInfo.examType.name}}</view>
+									</view>
+									<view class="tag-fill"
+										:style="{backgroundColor: item.examInfo.progress === 'finish'? '#23b46c':'#ff5959'}">
+										<view class="tag-text">{{item.examInfo.progress === 'finish' ? '已完成' : '进行中'}}
+										</view>
+									</view>
+								</view>
+							</view>
+						</view>
+					</view>
+					<view class="image-box" v-if="examData.length === 0">
+						<view class="detail-image-none" :style="{backgroundImage:`url(${image1})`}"></view>
+						<view class="subtitle">今日孩子暂无评测活动</view>
+					</view>
+				</view>
+			</view>
+			
+			
+			
+			
+			
+
+			<view class="flex-column" style="margin: 15rpx 0 10rpx 20rpx;">
+				<view class="title" style="font-size: 32rpx;">评测练习</view>
+				<view class="bottom-tag"></view>
+			</view>
+
+			<view class="flex-row" style="width: 70%;"></view>
+		</view>
+		<scroll-view class="scroll-view-bottom" scroll-x="true" :scroll-with-animation="true" scroll-left="0">
+			<view class="scroll-item" v-for="(item,index) in examPractice" :key="index"
+				@click="navExamPractice(index)">
+				<view class="flex-column" style="height: 320rpx;">
+					<view class="flex-row" style="margin: 10rpx;">
+						<view :class="subjectIcon.find(x=>x.name === item.subject).icon"></view>
+						<view class="flex-title">
+							<view class="YS-title" style="font-size: 40rpx;">{{item.subject}}</view>
+							<view class="tag-fill">
+								<view class="t-icon t-icon-zhengceguizhang"></view>
+								<view class="tag-text">{{item.type}}</view>
+							</view>
+						</view>
+					</view>
+					<view class="flex-desc">
+						<view class="YS-title">{{item.title}}</view>
+						<view class="YS-title" style="font-size: 30rpx;">「 {{item.modality}} 」</view>
+						<view class="flex-baseline">
+							<view class="desc">评测题量,共</view>
+							<view class="num" style="margin-left: 4rpx;">
+								{{item.amount}}
+							</view>
+							<view class="desc" style="margin-left: 4rpx;">题</view>
+						</view>
+					</view>
+				</view>
+			</view>
+		</scroll-view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex'
+	export default {
+		computed: {
+			...mapState('m_chart', ['examChartData']),
+			...mapState('m_children', ['examData', 'examPractice'])
+		},
+		data() {
+			return {
+				cardList: [{
+					icon: 't-icon t-icon-zoushi',
+					title: '总成绩走势',
+					type: 'mini-area',
+					data: ''
+				}, {
+					icon: 't-icon t-icon-shuju',
+					title: '单次考试分析',
+					type: 'mini-column',
+					data: ''
+				}, {
+					icon: 't-icon t-icon-jiangzhang',
+					title: '排行占比分析',
+					type: 'mini-area',
+					data: ''
+				}, {
+					icon: 't-icon t-icon-yingyong',
+					title: '优劣科目分析',
+					type: 'mini-rose',
+					data: ''
+				}, {
+					icon: 't-icon t-icon-yunwei',
+					title: '考试能力分析',
+					type: 'mini-column',
+					data: ''
+				}],
+				subjectIcon: [{
+					icon: 't-icon t-icon-yuwen',
+					name: '语文'
+				}, {
+					icon: 't-icon t-icon-shuxue',
+					name: '数学'
+				}, {
+					icon: 't-icon t-icon-yingyu',
+					name: '英语'
+				}, {
+					icon: 't-icon t-icon-tiyu',
+					name: '体育'
+				}, {
+					icon: 't-icon t-icon-tianwen',
+					name: '科学'
+				}, {
+					icon: 't-icon t-icon-zuixinkecheng',
+					name: '思品'
+				}, {
+					icon: 't-icon t-icon-wuli',
+					name: '物理'
+				}, {
+					icon: 't-icon t-icon-huaxue',
+					name: '化学'
+				}, {
+					icon: 't-icon t-icon-meishu',
+					name: '美术'
+				}, {
+					icon: 't-icon t-icon-yinle',
+					name: '音乐'
+				}, {
+					icon: 't-icon t-icon-dili',
+					name: '地理'
+				}, {
+					icon: 't-icon t-icon-lishi',
+					name: '历史'
+				}],
+				image: 'https://ouch-cdn2.icons8.com/yFl5NWU3aVehLBlQf9ctvnZPqtm5U0hqM3IzWvFDCaQ/rs:fit:912:912/czM6Ly9pY29uczgu/b3VjaC1wcm9kLmFz/c2V0cy9wbmcvNzY5/LzY1ZTQxZmZjLTg1/YWQtNDYyMi1hYzU0/LWQ3NDEzZmY2NGI1/YS5wbmc.png',
+				//完成情况
+				performance: '',
+				//完成数据
+				finishData: '',
+				finishRate: '',
+				timeStamp: '',
+				image1: 'https://image.meiye.art/pic_1631411821365LA63Wc70BLbmyHhj2XjiL',
+			};
+		},
+		onLoad() {
+			this.init()
+		},
+		//刷新页面
+		onPullDownRefresh() {
+			this.init()
+			setTimeout(function() {
+				uni.stopPullDownRefresh();
+			}, 1000);
+		},
+		methods: {
+			//初始化
+			init() {
+				this.timeStamp = (new Date()).format("hh:mm")
+				this.$initExam()
+				this.getChartData()
+				this.getPerformance()
+			},
+			//初始化cardList数据
+			getChartData() {
+				this.cardList[0].data = this.examChartData.totalChartData[0]
+				this.cardList[1].data = this.examChartData.singleChartData[0]
+				this.cardList[2].data = this.examChartData.rankChartData[0]
+				this.cardList[3].data = this.examChartData.subjectChartData[0]
+				this.cardList[4].data = this.examChartData.levelChartData[0]
+			},
+			//获得评判信息
+			getPerformance() {
+				if (this.examData.length != 0) {
+					this.finishData = this.examData.filter(x => x.examInfo.progress === 'finish')
+					this.finishRate = (this.finishData.length * 100 / this.examData.length).toFixed(0)
+					this.performance = this.finishData.length / this.examData.length >= 0.4 ?
+						(this.finishData.length / this.examData.length >= 0.7 ? '优秀' : '良好') : '较差'
+				} else {
+					this.finishData = []
+					this.finishRate = 0
+					this.performance = '无评测'
+				}
+
+			},
+			//导航
+			navGradeList(index) {
+				let urlArr = ['/subpkg/exam/total',
+					'/subpkg/exam/single',
+					'/subpkg/exam/rank',
+					'/subpkg/exam/subject',
+					'/subpkg/exam/level'
+				]
+				uni.navigateTo({
+					url: urlArr[index]
+				})
+			},
+			navExamList() {
+				let value = this.finishRate
+				uni.navigateTo({
+					url: `/subpkg/datalist/examList?value=${value}`
+				})
+			},
+			navExamReport(index) {
+				uni.navigateTo({
+					url: `/subpkg/datalist/examReport?index=${index}`
+				})
+			},
+			navExamPractice(index) {
+				uni.navigateTo({
+					url: `/subpkg/exam/examPractice?index=${index}`
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import '@/pages/style/tab_pages.scss';
+
+	.bg1 {
+		background-color: $color-pink;
+	}
+
+	.tag-fill {
+		background-color: $color-pink;
+		margin-left: 20rpx;
+	}
+
+	.circle-line1 {
+		background-image: linear-gradient(to right, #ff8caf, #ff8caf), linear-gradient(90deg, #FFF -50%, rgba(255, 255, 255, 0.0));
+	}
+
+	.circle-line2 {
+		background-image: linear-gradient(to right, #ff8caf, #ff8caf), linear-gradient(180deg, #FFF -50%, rgba(255, 255, 255, 0.0));
+	}
+
+	.circle-line3 {
+		background-image: linear-gradient(to right, #ff8caf, #ff8caf), linear-gradient(0deg, #FFF -50%, rgba(255, 255, 255, 0.0));
+	}
+
+	.flex-title {
+		display: flex;
+		flex-direction: column;
+		height: 100rpx;
+		justify-content: space-around;
+
+		.tag-fill {
+			background-color: #d8deff;
+			width: fit-content;
+			margin-left: 0;
+			padding: 5rpx 10rpx;
+
+			.t-icon {
+				width: 30rpx;
+				height: 30rpx;
+				margin-right: 5rpx;
+			}
+
+			.tag-text {
+				color: #4169E1;
+			}
+		}
+	}
+
+	.flex-desc {
+		display: flex;
+		flex-direction: column;
+		height: 100%;
+		justify-content: space-around;
+		margin: 0 30rpx 20rpx 30rpx;
+
+		.desc {
+			line-height: 28rpx;
+			font-size: 28rpx;
+			color: $subtitle;
+		}
+
+		.num {
+			line-height: 40rpx;
+			font-size: 40rpx;
+			color: $subtitle;
+		}
+	}
+</style>

+ 846 - 0
pages/tab_home/tab_home.vue

@@ -0,0 +1,846 @@
+<template>
+	<view>
+		<view v-if="!isHomeLoad">
+			<loading></loading>
+		</view>
+		<view class="page-view" v-if="isHomeLoad">
+			<!-- 成绩统计 -->
+			<view class="bg1">
+				<view class="circle-line1"></view>
+				<view class="circle-line2"></view>
+				<view class="circle-line3"></view>
+				<top-info :timeStamp="timeStamp"></top-info>
+				<scroll-view class="scroll-view" scroll-x="true" :scroll-with-animation="true" scroll-left="0">
+					<view class="view-box">
+						<view class="scroll-view-item" v-for="(item,index) in cardList" :key="index"
+							@click="navTab(index)">
+							<view class="card-info">
+								<view :class="item.icon"></view>
+								<view class="title">{{item.title}}</view>
+							</view>
+							<view class="chart-box">
+								<qiun-data-charts type="arcbar" :chartData="item.data" :canvas2d='true'
+									:canvasId='item.canvasId' :opts="item.chartOpts" />
+							</view>
+						</view>
+					</view>
+				</scroll-view>
+			</view>
+			<!-- 通知 -->
+			<view class="bg2">
+				<view class="notice">
+					<u-notice-bar :text="noticeData" bgColor="rgba(65,105,225,0.4)" color="#FFF"
+						url="/subpkg/mine/msgList"></u-notice-bar>
+				</view>
+			</view>
+			<!-- 课程 -->
+			<view class="card-view">
+				<!-- 今日课程模块 -->
+				<view class="card-item" style="width: 100%;" v-if="classCurrent != -1">
+					<view class="card-title">
+						<view class="front-tag"></view>
+						<view class="title">今日课程</view>
+						<view class="flex-row" style="margin: 0 0 0 auto;" @click="navClassList">
+							<view class="t-icon t-icon-fenlei"></view>
+							<view class="title" style="color: #4169E1;margin-left: 10rpx;">课程列表</view>
+						</view>
+					</view>
+					<view class="data-list">
+						<!-- 上上节 -->
+						<view class="data-item" v-if="classCurrent === classList.length">
+							<view class="flex-row">
+								<view class="t-icon t-icon-classicon-copy" style="width: 60rpx; height: 60rpx;"></view>
+								<view class="flex-column">
+									<view class="row-margin">
+										<view class="item-title">{{classList[classCurrent - 3].title}}</view>
+										<view class="tag">
+											<view class="tag-text">{{classList[classCurrent - 3].name}}</view>
+										</view>
+										<view class="tag">
+											<view class="tag-text">{{classList[classCurrent - 3].teacher}}</view>
+										</view>
+									</view>
+									<view class="row-margin">
+										<view class="item-subtitle">上节</view>
+										<view class="item-detail">
+											{{classList[classCurrent - 3].time}}
+										</view>
+									</view>
+								</view>
+
+								<view class="state">
+									<view class="state-text">{{classList[classCurrent - 3].attendance?'已出勤':'未出勤'}}
+									</view>
+								</view>
+
+							</view>
+						</view>
+						<!-- 上节 -->
+						<view class="data-item" v-if="classCurrent >= 2">
+							<view class="flex-row">
+								<view class="t-icon t-icon-classicon-copy" style="width: 60rpx; height: 60rpx;"></view>
+								<view class="flex-column">
+									<view class="row-margin">
+										<view class="item-title">{{classList[classCurrent - 2].title}}</view>
+										<view class="tag">
+											<view class="tag-text">{{classList[classCurrent - 2].name}}</view>
+										</view>
+										<view class="tag">
+											<view class="tag-text">{{classList[classCurrent - 2].teacher}}</view>
+										</view>
+									</view>
+									<view class="row-margin">
+										<view class="item-subtitle">上节</view>
+										<view class="item-detail">
+											{{classList[classCurrent - 2].time}}
+										</view>
+									</view>
+								</view>
+
+								<view class="state">
+									<view class="state-text">{{classList[classCurrent - 2].attendance?'已出勤':'未出勤'}}
+									</view>
+								</view>
+
+							</view>
+						</view>
+						<!-- 当前 -->
+						<view class="data-item" style="border-image: linear-gradient(to right, #4169E1, #FFF) 1;">
+							<view class="flex-row">
+								<view class="t-icon t-icon-classicon-copy" style="width: 60rpx; height: 60rpx;"></view>
+								<view class="flex-column">
+									<view class="row-margin">
+										<view class="item-title" style="color: #4169E1;">
+											{{classList[classCurrent - 1].title}}
+										</view>
+										<view class="tag">
+											<view class="tag-text">{{classList[classCurrent - 1].name}}</view>
+										</view>
+										<view class="tag">
+											<view class="tag-text">{{classList[classCurrent - 1].teacher}}</view>
+										</view>
+									</view>
+									<view class="row-margin">
+										<view class="item-subtitle" style="color: #4169E1;">当前</view>
+										<view class="item-detail" style="color: #4169E1;">
+											{{classList[classCurrent - 1].time}}
+										</view>
+									</view>
+								</view>
+
+								<view class="state" style="background-color: #ff5959;">
+									<view class="state-text">{{classList[classCurrent - 1].attendance?'课程中':'未出勤'}}
+									</view>
+								</view>
+
+							</view>
+						</view>
+						<!-- 下节 -->
+						<view class="data-item" v-if="classCurrent != classList.length">
+							<view class="flex-row">
+								<view class="t-icon t-icon-classicon-noarrive" style="width: 60rpx; height: 60rpx;">
+								</view>
+								<view class="flex-column">
+									<view class="row-margin">
+										<view class="item-title">{{classList[classCurrent].title}}</view>
+										<view class="tag">
+											<view class="tag-text">{{classList[classCurrent].name}}</view>
+										</view>
+										<view class="tag">
+											<view class="tag-text">{{classList[classCurrent].teacher}}</view>
+										</view>
+									</view>
+									<view class="row-margin">
+										<view class="item-subtitle">下节</view>
+										<view class="item-detail">
+											{{classList[classCurrent].time}}
+										</view>
+									</view>
+								</view>
+
+								<view class="state" style="background-color: #909399;">
+									<view class="state-text">未开始</view>
+								</view>
+
+							</view>
+						</view>
+						<!-- 下下节 -->
+						<view class="data-item" v-if="classCurrent === 1">
+							<view class="flex-row">
+								<view class="t-icon t-icon-classicon-noarrive" style="width: 60rpx; height: 60rpx;">
+								</view>
+								<view class="flex-column">
+									<view class="row-margin">
+										<view class="item-title">{{classList[classCurrent+1].title}}</view>
+										<view class="tag">
+											<view class="tag-text">{{classList[classCurrent+1].name}}</view>
+										</view>
+										<view class="tag">
+											<view class="tag-text">{{classList[classCurrent+1].teacher}}</view>
+										</view>
+									</view>
+									<view class="row-margin">
+										<view class="item-subtitle">下节</view>
+										<view class="item-detail">
+											{{classList[classCurrent+1].time}}
+										</view>
+									</view>
+								</view>
+
+								<view class="state" style="background-color: #909399;">
+									<view class="state-text">未开始</view>
+								</view>
+
+							</view>
+						</view>
+					</view>
+				</view>
+				<!-- 插画模块 -->
+				<view class="card-item" style="width: 100%;" v-if="classCurrent === -1">
+					<view class="card-title">
+						<view class="front-tag"></view>
+						<view class="title">今日课程</view>
+					</view>
+					<view class="detail-image-none" :style="{backgroundImage:`url(${image})`}"></view>
+					<view class="data-list">
+						<view class="data-item" style="height: 120rpx;">
+							<view class="flex-row" style="justify-content: space-between;">
+								<view class="item-title" v-if="!isAfterDayClass">
+									{{classList.length === 0 ? '假期充电' : '课间休息'}}
+								</view>
+								<view class="item-title" v-if="isAfterDayClass">课程完成</view>
+								<view class="tag" style="margin: 0;">
+									<view class="tag-text" v-if="!isAfterDayClass">
+										{{classList.length === 0 ? '无课' : '下课'}}
+									</view>
+									<view class="tag-text" v-if="isAfterDayClass">放学</view>
+								</view>
+								<view class="item-subtitle" style="font-weight: 400;font-size: 26rpx;"
+									v-if="!isAfterDayClass">
+									{{classList.length === 0 ? '合理规划' : '预习下节'}}
+								</view>
+								<view class="item-subtitle" style="font-weight: 400;font-size: 26rpx;"
+									v-if="isAfterDayClass">巩固所学</view>
+								<view class="flex-row" @click="navClassList">
+									<view class="t-icon t-icon-fenlei"></view>
+									<view class="item-title" style="color: #4169E1;margin-left: 10rpx;">课程列表
+									</view>
+								</view>
+							</view>
+						</view>
+					</view>
+				</view>
+				<!-- 今日打卡模块 -->
+				<view class="card-item" style="height: 300rpx;" @click="navClockStats">
+					<view class="flex-row" style="margin: 20rpx 20rpx 0 20rpx;">
+						<view class="icon-box" style="width: 120rpx;height: 120rpx; background-color: #d8deff;">
+							<view class="t-icon t-icon-a-rilidaka" style="width: 60rpx;height: 60rpx;"></view>
+						</view>
+						<view class="clock-block">
+							<view class="subtitle">打卡记录</view>
+							<view class="flex-baseline">
+								<view class="YS-title">{{dayTime.split('月')[0]}}</view>
+								<view class="YS-title" style="font-size: 30rpx; margin-left: 4rpx;">月</view>
+								<view class="YS-title" style="margin-left: 4rpx;">
+									{{dayTime.split('月')[1]}}
+								</view>
+								<view class="YS-title" style="font-size: 30rpx; margin-left: 4rpx;">日</view>
+							</view>
+						</view>
+					</view>
+					<view class="flex-row" style="margin: auto 20rpx 20rpx 20rpx;justify-content: space-between;">
+						<view class="clock-block">
+							<view class="subtitle">打卡时间</view>
+							<view class="YS-title" v-if="clockTime === '无记录'">
+								{{clockTime}}
+							</view>
+							<view class="flex-baseline" v-if="clockTime != '无记录'">
+								<view class="YS-title">
+									{{clockTime.split(':')[0].replace('0','')}}
+								</view>
+								<view class="YS-title" style="font-size: 30rpx; margin-left: 4rpx;">点</view>
+								<view class="YS-title" style="margin-left: 4rpx;">
+									{{clockTime.split(':')[1]}}
+								</view>
+								<view class="YS-title" style="font-size: 30rpx; margin-left: 4rpx;">分</view>
+							</view>
+						</view>
+						<view class="icon-box" style="width: 120rpx;height: 120rpx;"
+							:style="{backgroundColor: clockState === '未打卡' ? '#ff5959':'#4169E1'}">
+							<view class="YS-title" style="color: #FFF;font-size: 32rpx;">
+								{{clockState}}
+							</view>
+						</view>
+					</view>
+					<view style="width: 0;height: 0;">
+						<view class="clock-image"
+							:style="{backgroundImage: clockState === '已打卡'?`url(${image2})`:`url(${image1})`}">
+						</view>
+					</view>
+				</view>
+				<!-- 今日出席模块 -->
+				<view class="card-item" style="background-color: #f3f4f9;justify-content: space-between;">
+					<!-- 当前课程 -->
+					<view class="class-box">
+						<view class="icon-box" style="background-color: #d8deff; margin-left: 20rpx;">
+							<view class="t-icon t-icon-shangke-"></view>
+						</view>
+						<view class="info-column">
+							<view class="subtitle" style="font-size: 24rpx;">当前课程</view>
+							<view class="YS-title" v-if="classCurrent!=-1">
+								{{classList[classCurrent - 1].name}}
+							</view>
+							<view class="YS-title" v-if="classCurrent===-1">无课程</view>
+						</view>
+						<view v-if="classCurrent != -1">
+							<view class="icon-box" style="margin-right: 20rpx;"
+								:style="{backgroundColor: classList[classCurrent - 1].attendance ? '#23b46c':'#ff5959'}">
+								<view class="YS-title" style="color: #FFF;font-size: 32rpx;">
+									{{classList[classCurrent - 1].attendance ? '出勤':'缺勤'}}
+								</view>
+							</view>
+						</view>
+						<view v-if="classCurrent === -1">
+							<view class="icon-box" style="margin-right: 20rpx;background-color: #f9c752;">
+								<view class="YS-title" style="color: #FFF;font-size: 32rpx;">休息</view>
+							</view>
+						</view>
+					</view>
+					<!-- 出勤课程统计 -->
+					<view class="class-box">
+						<view class="icon-box" style="background-color: #d8deff;margin-left: 20rpx;">
+							<view class="t-icon t-icon-shangkejilu"></view>
+						</view>
+						<view class="info-column">
+							<view class="subtitle" style="font-size: 24rpx;">出勤课程</view>
+							<view class="YS-title" v-if="classList">{{finishClassNum}}节课</view>
+							<view class="YS-title" v-if="!classList">0 节</view>
+						</view>
+						<view v-if="classList">
+							<view class="icon-box" style="margin-right: 20rpx;"
+								:style="{backgroundColor: classAttendanceQuality === '全勤' ? '#23b46c':'#ff5959'}">
+								<view class="YS-title" style="color: #FFF;font-size: 32rpx;">{{classAttendanceQuality}}
+								</view>
+							</view>
+						</view>
+						<view v-if="!classList">
+							<view class="icon-box" style="margin-right: 20rpx;background-color: #f9c752;">
+								<view class="YS-title" style="color: #FFF;font-size: 32rpx;">休息</view>
+							</view>
+						</view>
+					</view>
+				</view>
+
+				<!-- 推荐课例列表 -->
+				<view class="flex-column" style="margin: 15rpx 0 10rpx 20rpx;">
+					<view class="title" style="font-size: 32rpx;">课程推荐</view>
+					<view class="bottom-tag"></view>
+				</view>
+				<view class="flex-row" style="width: 70%;"></view>
+			</view>
+			<scroll-view class="scroll-view-bottom" scroll-x="true" :scroll-with-animation="true" scroll-left="0">
+				<view class="box-container" v-for="(item,index) in classData" :key="index"
+					@click="navCourseRecommend(index)">
+					<view class="clounm-container" v-for="(classItem,i) in item" :key="i">
+						<view class="item-box">
+							<view class="thumb" :style="{backgroundImage: `url(${classItem.coverImage})`}"></view>
+							<view class="info-box">
+								<view class="title" style="font-size: 32rpx;">{{classItem.title}}</view>
+								<view class="flex-row">
+									<view class="tag-fill">
+										<view class="t-icon t-icon-a-wangluokechengzaixianjiaoyu"></view>
+										<view class="tag-text">{{classItem.classHour}} 学时</view>
+									</view>
+									<view class="tag-fill" style="margin-left: 20rpx;">
+										<view class="t-icon t-icon-xiaoyuanredian"></view>
+										<view class="tag-text">{{classItem.learnNum}} 已学</view>
+									</view>
+								</view>
+								<view class="desc">{{classItem.description}}</view>
+							</view>
+						</view>
+					</view>
+				</view>
+			</scroll-view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState,
+		mapMutations
+	} from 'vuex'
+
+	export default {
+		computed: {
+			...mapState('m_children', ['classList', 'examData', 'workData', 'swapData', 'clockData']),
+			...mapState('m_parent', ['userData', 'classData'])
+		},
+		data() {
+			return {
+				cardList: [{
+					icon: 't-icon t-icon-chakandingdan',
+					title: '评测记录',
+					canvasId: 'tab_home_chart1',
+					data: {
+						"series": [{
+							"name": "评测完成率",
+							"data": '无评测',
+							"color": "#ff8caf"
+						}]
+					},
+					chartOpts: {}
+				}, {
+					icon: 't-icon t-icon-renwu',
+					title: '作业记录',
+					canvasId: 'tab_home_chart2',
+					data: {
+						"series": [{
+							"name": "作业完成率",
+							"data": '无作业',
+							"color": "#f9c752"
+						}]
+					},
+					chartOpts: {}
+				}, {
+					icon: 't-icon t-icon-wenjian',
+					title: '活动记录',
+					canvasId: 'tab_home_chart3',
+					data: {
+						"series": [{
+							"name": "活动完成率",
+							"data": '无活动',
+							"color": "#FF6D31"
+						}]
+					},
+					chartOpts: {}
+				}],
+				noticeData: '',
+				//当前课程索引
+				classCurrent: '',
+				//已上课程
+				finishClassNum: '',
+				//课程缺省image
+				image: 'https://image.meiye.art/pic_1631411821366fqhkuMI110LbOlAIdv1SV',
+				//时间戳
+				timeStamp: '',
+				//今日时间
+				dayTime: '',
+				//打卡状态
+				clockState: '',
+				//打卡时间
+				clockTime: '',
+				//出勤课程统计信息
+				classAttendanceQuality: '',
+				//打卡状态image
+				image1: 'https://ouch-cdn2.icons8.com/2farWQUdLe8J4mb4oQoEvJpl5OFXtM5P7AZi8nhuOxk/rs:fit:912:912/czM6Ly9pY29uczgu/b3VjaC1wcm9kLmFz/c2V0cy9zdmcvOTYz/L2VkZGEwNzAzLTAw/MWYtNGZiZS1hY2I3/LTVlNjRhZGYzNTAx/Mi5zdmc.png',
+				image2: 'https://ouch-cdn2.icons8.com/6CkTSZQdyBYaGiqmNJRhbqoYi8QDcLFn-04VEQyQaCo/rs:fit:962:912/czM6Ly9pY29uczgu/b3VjaC1wcm9kLmFz/c2V0cy9zdmcvNzMz/LzlhYmUzYjIyLTRl/ZGQtNDVkMi1iYWEw/LTVjYjk2NThmNDJi/OC5zdmc.png',
+				//当前页面加载是否完成
+				isHomeLoad: false,
+				//今日课程是否上完
+				isAfterDayClass: false
+			};
+		},
+		onLoad() {
+			this.init()
+		},
+		//刷新页面
+		onPullDownRefresh() {
+			this.init()
+			setTimeout(function() {
+				uni.stopPullDownRefresh();
+			}, 1000);
+		},
+		methods: {
+			//初始化页面
+			async init() {
+				await this.$initHome()
+				this.dayTime = (new Date()).format('M-d').replace('-', '月')
+				this.timeStamp = (new Date()).format("hh:mm")
+				this.getClassCurrent()
+				this.getChartData()
+				this.getNoticeData()
+				this.getClockData()
+				this.getClassAttendance()
+				this.isHomeLoad = true
+			},
+
+			//计算出当前课程
+			getClassCurrent() {
+				//当前时间戳是否在课程时间段内
+				function CompareDate(start, finish) {
+					//获得当前时间时间戳
+					let timeNow = (new Date()).format("yyyy-MM-dd hh:mm").replace(new RegExp("-", "gm"), "/")
+					let timeHaoMiao = (new Date(timeNow)).getTime()
+					//获得课程开始结束时间戳
+					let today = (new Date()).format("yyyy-MM-dd ")
+					let classStart = (today + start).replace(new RegExp("-", "gm"), "/")
+					let classFinish = (today + finish).replace(new RegExp("-", "gm"), "/")
+					let classStartHaoMiao = (new Date(classStart)).getTime()
+					let classFinishHaoMiao = (new Date(classFinish)).getTime()
+					//比较
+					if (timeHaoMiao < classFinishHaoMiao) {
+						if (classStartHaoMiao < timeHaoMiao)
+							return true
+					}
+					return false
+				}
+				//当前时间戳是否在课程开始时间之前
+				function CompareDateStart(start) {
+					//获得当前时间时间戳
+					let timeNow = (new Date()).format("yyyy-MM-dd hh:mm").replace(new RegExp("-", "gm"), "/")
+					let timeHaoMiao = (new Date(timeNow)).getTime()
+					//获得课程开始结束时间戳
+					let today = (new Date()).format("yyyy-MM-dd ")
+					let classStart = (today + start).replace(new RegExp("-", "gm"), "/")
+					let classStartHaoMiao = (new Date(classStart)).getTime()
+					//比较
+					if (timeHaoMiao < classStartHaoMiao)
+						return true
+					return false
+				}
+				//今日有课程
+				if (this.classList.length != 0) {
+					//当前课程索引
+					let classIndex = -100
+					//完成课程数目
+					let finishNum = -100
+					//是否在课堂中
+					let isInClass = false
+					//判断是否在课程中,若是则赋值为当前课程索引
+					this.classList.some((item, index) => {
+						let timeArr = item.time.split("-")
+						//在课堂中
+						let res = CompareDate(timeArr[0], timeArr[1])
+						if (res) {
+							classIndex = index + 1
+							finishNum = index + 1
+							return isInClass = true
+						}
+					})
+					if (isInClass) {
+						//当前课程赋值
+						this.classCurrent = classIndex
+						//已上课程赋值
+						this.finishClassNum = finishNum
+					} else {
+						//是否放学
+						this.classList.some((item, index) => {
+							let timeArr = item.time.split("-")
+							//没在课堂中
+							let value = CompareDateStart(timeArr[0])
+							//课间时间
+							if (value) {
+								classIndex = -1
+								finishNum = index - 1
+								this.isAfterDayClass = false
+							} else {
+								//放学时间(有课程但已上完状态)
+								classIndex = -1
+								finishNum = this.classList.length
+								this.isAfterDayClass = true
+							}
+						})
+						//当前课程赋值
+						this.classCurrent = classIndex
+						//已上课程赋值
+						this.finishClassNum = finishNum
+					}
+					//无课程,放假时间
+				} else {
+					//当前课程赋值
+					this.classCurrent = -1
+					//已上课程赋值
+					this.finishClassNum = 0
+				}
+			},
+			//更新图表数据
+			getChartData() {
+				//完成数据
+				if (this.examData.length != 0) {
+					let examFinishData = this.examData.filter(x => x.examInfo.progress === 'finish')
+					this.cardList[0].data.series[0].data = parseFloat((examFinishData.length / this.examData.length)
+						.toFixed(2))
+				}
+				if (this.workData.length != 0) {
+					let workFinishData = this.workData.filter(x => x.work.progress === 'finish')
+					this.cardList[1].data.series[0].data = parseFloat((workFinishData.length / this.workData.length)
+						.toFixed(2))
+				}
+				if (this.swapData.length != 0) {
+					let swapFinishData = this.swapData.filter(x => x.vote && x.vote.progress === 'finish')
+					swapFinishData.push(...this.swapData.filter(x => x.survey && x.survey.progress === 'finish'))
+					this.cardList[2].data.series[0].data = parseFloat((swapFinishData.length / this.swapData.length)
+						.toFixed(2))
+				}
+				//完成率传入图表
+				for (let i = 0; i < 3; i++) {
+					if (typeof(this.cardList[i].data.series[0].data) === typeof(0)) {
+						let opt = {
+							title: {
+								name: (this.cardList[i].data.series[0].data * 100).toFixed(0) + '%',
+								color: this.cardList[i].data.series[0].color
+							},
+							subtitle: {
+								name: this.cardList[i].data.series[0].name
+							},
+						}
+						this.cardList[i].chartOpts = JSON.parse(JSON.stringify(opt))
+					} else {
+						let opt = {
+							title: {
+								name: this.cardList[i].data.series[0].data,
+								color: this.cardList[i].data.series[0].color
+							},
+							subtitle: {
+								name: this.cardList[i].data.series[0].name
+							},
+						}
+						this.cardList[i].chartOpts = JSON.parse(JSON.stringify(opt))
+					}
+				}
+			},
+			//日历数据获取
+			getClockData() {
+				//获得当前时间时间戳
+				let today = (new Date()).format("yyyy-M-dd")
+				let timeArr = today.split("-")
+				if (this.clockData.length != 0) {
+					let val = this.clockData.filter(x => x.year == timeArr[0] && x.month == timeArr[1] && x.date ==
+						timeArr[2])
+					if (val.length != 0) {
+						this.clockState = '已打卡'
+						this.clockTime = val[0].time
+					} else {
+						this.clockState = '未打卡'
+						this.clockTime = '无记录'
+					}
+				} else {
+					this.clockState = '未打卡'
+					this.clockTime = '无记录'
+				}
+			},
+			//获取滚动通知
+			getNoticeData() {
+				if (this.userData.msgList)
+					this.noticeData = `您有 ${this.userData.msgList.length} 条通知,请点击查看`
+				if (!this.userData.msgList)
+					this.noticeData = `您已查看全部通知`
+			},
+			//获取出勤课程统计
+			getClassAttendance() {
+				let finishClassData = []
+				for (let i = 0; i < this.finishClassNum; i++) {
+					finishClassData.push(this.classList[i])
+				}
+				if (finishClassData.length != 0) {
+					let isAttendArr = finishClassData.filter(x => x.attendance === true)
+					this.classAttendanceQuality = isAttendArr.length === this.finishClassNum ? '全勤' : '缺勤'
+				}
+			},
+			//导航
+			navClassList() {
+				let current = this.classCurrent
+				uni.navigateTo({
+					url: `/subpkg/home/classList?index=${current}`
+				})
+			},
+			navTab(index) {
+				let urlArr = ['/pages/tab_exam/tab_exam',
+					'/pages/tab_work/tab_work',
+					'/pages/tab_swap/tab_swap'
+				]
+				uni.switchTab({
+					url: urlArr[index]
+				})
+			},
+			navClockStats() {
+				uni.navigateTo({
+					url: '/subpkg/home/clockStats'
+				})
+			},
+			navCourseRecommend(index) {
+				uni.navigateTo({
+					url: `/subpkg/home/courseRecommend?index=${index}`
+				})
+			}
+
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import '@/pages/style/tab_pages.scss';
+
+	.bg2 {
+		margin-top: -1065rpx;
+		height: 1200rpx;
+		border-radius: 100rpx;
+		border-bottom-left-radius: 0;
+		background-color: #FFF;
+		z-index: 1;
+
+		.notice {
+			margin: 1095rpx 50rpx 20rpx 50rpx;
+			width: 650rpx;
+		}
+	}
+
+	.YS-title {
+		font-size: 38rpx;
+	}
+
+	.row-margin {
+		display: flex;
+		align-items: center;
+		margin: 10rpx 20rpx;
+	}
+
+	.tag {
+		margin-left: 20rpx;
+	}
+
+	//课程出勤
+	.class-box {
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		width: 100%;
+		height: 140rpx;
+		background-color: #FFF;
+		border-radius: $border-radius;
+
+		.info-column {
+			height: 80rpx;
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			justify-content: space-around;
+		}
+	}
+
+	.icon-box {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		width: 80rpx;
+		height: 80rpx;
+		border-radius: 12rpx;
+		z-index: 9;
+
+		.t-icon {
+			width: 50rpx;
+			height: 50rpx;
+		}
+	}
+
+	.clock-block {
+		display: flex;
+		flex-direction: column;
+		width: 180rpx;
+		height: 120rpx;
+		justify-content: space-around;
+		align-items: center;
+	}
+
+	.state {
+		display: flex;
+		align-items: center;
+		margin-left: auto;
+		border-radius: $border-radius;
+		background-color: $color-green;
+		padding: 24rpx 12rpx;
+
+		.t-icon {
+			width: 32rpx;
+			height: 32rpx;
+		}
+
+		.state-text {
+			color: #FFF;
+			font-size: 24rpx;
+			font-weight: bold;
+			transform: skew(-10deg);
+		}
+	}
+
+	.scroll-view-bottom {
+		white-space: nowrap;
+		padding-bottom: 20rpx;
+	}
+
+	.clock-image {
+		margin-top: -160rpx;
+		margin-left: 20rpx;
+		height: 160rpx;
+		width: 160rpx;
+		background-size: 100%;
+		background-repeat: no-repeat;
+		opacity: 0.25;
+		z-index: 1;
+	}
+
+	.box-container {
+		margin: 0 20rpx;
+		display: inline-block;
+		vertical-align: top;
+		width: 84%;
+
+		.clounm-container {
+			height: 180rpx;
+			width: 100%;
+			margin-bottom: 20rpx;
+			border-radius: $border-radius;
+			background-color: #FFF;
+			overflow: hidden;
+
+			.item-box {
+				display: flex;
+				width: 100%;
+				height: 100%;
+
+				.thumb {
+					width: 180rpx;
+					height: 180rpx;
+					border-radius: $border-radius;
+					background-size: cover; //背景图片自适应
+					background-repeat: no-repeat;
+					z-index: 50;
+				}
+
+				.info-box {
+					display: flex;
+					flex-direction: column;
+					margin: 20rpx 20rpx 20rpx 30rpx;
+					justify-content: space-between;
+					width: 400rpx;
+
+					.tag-fill {
+						background-color: #d8deff;
+						width: fit-content;
+
+						.t-icon {
+							width: 30rpx;
+							height: 30rpx;
+							margin-right: 5rpx;
+						}
+
+						.tag-text {
+							color: #4169E1;
+						}
+					}
+
+					.desc {
+						line-height: 26rpx;
+						font-size: 26rpx;
+						color: #909399;
+						white-space: nowrap;
+						overflow: hidden;
+						text-overflow: ellipsis;
+					}
+				}
+			}
+		}
+	}
+</style>

+ 323 - 0
pages/tab_mine/tab_mine.vue

@@ -0,0 +1,323 @@
+<template>
+	<view>
+		<view class="content">
+			<view class="bg1"></view>
+			<view class="bg2"></view>
+			<view class="bg3"></view>
+			<!-- 个人信息 -->
+			<view class="info-box">
+				<image class="avatar" :src="parentInfo.avatarUrl"></image>
+				<view class="flex-column">
+					<view class="info-title">{{parentInfo.nickName}}</view>
+					<view class="info-subtitle">{{childInfo.name}}家长</view>
+				</view>
+			</view>
+			<!-- 卡片列表 -->
+			<view class="card-view" style="margin-top: 50rpx;">
+				<view class="card-item" style="background-color: #d7e4ff;" @click="navChooseChild">
+					<view class="flex-row">
+						<view class="t-icon t-icon-a-boshimaojiaoyu"></view>
+						<view class="flex-column">
+							<view class="box-title">孩子切换</view>
+							<view class="box-subtitle">更多孩子信息</view>
+						</view>
+					</view>
+				</view>
+				<view class="card-item" style="background-color: #ffe1e7;" @click="navChildInfo">
+					<view class="flex-row">
+						<view class="t-icon t-icon-a-jiangpaijiangzhang"></view>
+						<view class="flex-column">
+							<view class="box-title">孩子名片</view>
+							<view class="box-subtitle">晒出优秀表现</view>
+						</view>
+					</view>
+				</view>
+				<!-- 功能模块 -->
+				<view class="card-item" style="width: 100%;">
+					<view class="com-box">
+						<view class="cell" @click="navInfo">
+							<view class="cell-left">
+								<view class="t-icon t-icon-zhanghu"></view>
+								<view class="cell-text">个人信息</view>
+							</view>
+							<view class="t-icon t-icon-you"></view>
+						</view>
+						<view class="cell" @click="navMsg">
+							<view class="cell-left">
+								<view class="t-icon t-icon-a-liaotianpingluntaolunduihua"></view>
+								<view class="cell-text">我的消息</view>
+							</view>
+							<view class="cell-right" v-if="userData.msgList.length != 0">
+								<view style="margin-right: 20rpx;">
+									<u-badge type="warning" shape="horn" :value="userData.msgList.length"></u-badge>
+								</view>
+								<view class="t-icon t-icon-you"></view>
+							</view>
+						</view>
+						<view class="cell" @click="navSubscribe">
+							<view class="cell-left">
+								<view class="t-icon t-icon-shoucang"></view>
+								<view class="cell-text">订阅中心</view>
+							</view>
+							<view class="t-icon t-icon-you"></view>
+						</view>
+					</view>
+				</view>
+				<!-- 功能模块 -->
+				<view class="card-item" style="width: 100%;">
+					<view class="com-box">
+						<view class="cell" @click="logOut">
+							<view class="cell-left">
+								<view class="t-icon t-icon-a-tuichulikai"></view>
+								<view class="cell-text">退出登录</view>
+							</view>
+							<view class="t-icon t-icon-you"></view>
+						</view>
+						<view class="cell">
+							<view class="cell-left">
+								<view class="t-icon t-icon-a-appyingyongchengxukaifa"></view>
+								<view class="cell-text">帮助中心</view>
+							</view>
+							<view class="t-icon t-icon-you"></view>
+						</view>
+						<view class="cell">
+							<view class="cell-left">
+								<view class="t-icon t-icon-shuji"></view>
+								<view class="cell-text">用户协议</view>
+							</view>
+							<view class="t-icon t-icon-you"></view>
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState,
+		mapMutations
+	} from 'vuex'
+	export default {
+		computed: {
+			...mapState('m_parent', ['parentInfo', 'userData', 'childrenData']),
+			...mapState('m_children', ['childInfo'])
+		},
+		data() {
+			return {};
+		},
+		methods: {
+			...mapMutations('m_parent', ['updateToken', 'updateParentInfo', 'updatePhoneNumber', 'updateChildrenData',
+				'updateUserData'
+			]),
+			...mapMutations('m_children', ['updateChildInfo']),
+			//退出登录事件
+			async logOut() {
+				const [err, succ] = await uni.showModal({
+					title: '提示',
+					content: '确认退出登录吗?'
+				}).catch(err => err)
+				if (succ && succ.confirm) {
+					this.$logOut()
+				}
+			},
+			//切换孩子
+			navChooseChild() {
+				uni.navigateTo({
+					url: '/subpkg/startup/options'
+				})
+			},
+			//孩子名片
+			navChildInfo() {
+				let tmdidArr = this.childrenData.map(x => {
+					return x.tmdid
+				})
+				let index = tmdidArr.indexOf(this.childInfo.tmdid)
+				uni.navigateTo({
+					url: `/subpkg/mine/childInfo?index=${index}`
+				})
+			},
+			//家长信息
+			navInfo() {
+				uni.navigateTo({
+					url: '/subpkg/mine/parentInfo'
+				})
+			},
+			//我的消息
+			navMsg() {
+				uni.navigateTo({
+					url: '/subpkg/mine/msgList'
+				})
+			},
+			//订阅信息
+			navSubscribe() {
+				uni.navigateTo({
+					url: '/subpkg/mine/subInfo'
+				})
+			}
+
+
+		}
+	}
+</script>
+
+<style lang="scss">
+	//登录页面
+	.content {
+		height: 100%;
+		width: 100%;
+		overflow-x: hidden;
+
+		.bg1 {
+			position: fixed;
+			top: -250rpx;
+			right: -250rpx;
+			width: 680rpx;
+			height: 680rpx;
+			border-radius: 100%;
+			background-color: $color-blue;
+			z-index: 5;
+		}
+
+		.bg2 {
+			position: fixed;
+			right: -300rpx;
+			top: 200rpx;
+			width: 600rpx;
+			height: 600rpx;
+			border-radius: 100%;
+			background-color: $color-red;
+			z-index: 4;
+		}
+
+		.bg3 {
+			position: fixed;
+			top: 500rpx;
+			right: 450rpx;
+			width: 600rpx;
+			height: 600rpx;
+			border-radius: 100%;
+			background-color: $color-yellow;
+			z-index: 4;
+		}
+
+		.info-box {
+			width: 100%;
+			margin-top: 200rpx;
+			margin-left: 40rpx;
+			display: flex;
+			align-items: center;
+			z-index: 10;
+
+			.avatar {
+				width: 120rpx;
+				height: 120rpx;
+				border-radius: 100%;
+				border: 4rpx solid #FFFFFF;
+				box-shadow: 0 10rpx 20rpx rgba(0, 0, 0, 0.2);
+			}
+
+			.flex-column {
+				margin-left: 40rpx;
+				width: 200rpx;
+				height: 120rpx;
+				justify-content: space-around;
+				.info-title{
+					font-size: 55rpx;
+					line-height: 55rpx;
+					color: $title;
+					font-family: YSfont;
+					z-index: 99;
+				}
+				.info-subtitle{
+					font-size: 40rpx;
+					line-height: 40rpx;
+					color: $subtitle;
+					font-family: YSfont;
+					z-index: 99;
+				}
+			}
+		}
+
+		// 功能按钮模块
+		.com-box {
+			overflow: hidden;
+			border-radius: $border-radius;
+
+			.cell {
+				height: 100rpx;
+				padding-left: 20rpx;
+				padding-right: 20rpx;
+				display: flex;
+				justify-content: space-between;
+				align-items: center;
+				background: #fff;
+				border-bottom: 1px solid #f8f8f8;
+
+				&:active {
+					background: #f2f2f2;
+				}
+
+				&:last-child {
+					border-bottom: none !important;
+				}
+
+				.cell-left {
+					display: flex;
+					align-items: center;
+					padding-left: 20rpx;
+
+					.t-icon {
+						width: 40rpx;
+						height: 40rpx;
+					}
+
+					.cell-text {
+						color: #666;
+						font-size: 30rpx;
+						line-height: 40rpx;
+						margin-left: 20rpx;
+						font-family: YSfont;
+						font-weight: 300;
+					}
+				}
+
+				.cell-right {
+					display: flex;
+					align-items: center;
+
+					.u-badge {
+						margin-right: 10rpx;
+					}
+				}
+			}
+		}
+	}
+
+	.flex-row {
+		.flex-column {
+			margin: 30rpx 0 30rpx 25rpx;
+
+			.box-title {
+				font-size: 40rpx;
+				line-height: 80rpx;
+				color: $title;
+				font-family: YSfont;
+			}
+
+			.box-subtitle {
+				font-size: 30rpx;
+				line-height: 50rpx;
+				color: $subtitle;
+				font-family: YSfont;
+			}
+		}
+
+		.t-icon {
+			width: 60rpx;
+			height: 60rpx;
+			margin-left: 25rpx;
+		}
+	}
+</style>

+ 326 - 0
pages/tab_swap/tab_swap.vue

@@ -0,0 +1,326 @@
+<template>
+	<view class="page-view">
+		<!-- 统计 -->
+		<view class="bg1">
+			<view class="circle-line1"></view>
+			<view class="circle-line2"></view>
+			<view class="circle-line3"></view>
+			<top-info :timeStamp="timeStamp"></top-info>
+			<scroll-view class="scroll-view" scroll-x="true" :scroll-with-animation="true" scroll-left="0">
+				<view class="view-box">
+					<view class="scroll-view-item" v-for="(item,index) in cardList" :key="index" @click="navSwapStats">
+						<view class="card-info">
+							<view :class="item.icon"></view>
+							<view class="title">{{item.title}}</view>
+						</view>
+						<view class="chart-box">
+							<qiun-data-charts :type="item.type" :chartData="item.data" :opts="{legend:{show: false}}" />
+						</view>
+					</view>
+				</view>
+			</scroll-view>
+		</view>
+		<!-- 统计卡片 -->
+		<view class="card-view">
+			<view class="stat-card" style="background-color:#FF6D31">
+				<view class="card-column">
+					<view class="flex-baseline">
+						<text class="_title">今日活动</text>
+						<text class="_title" style="margin-left: 20rpx;">{{swapData.length}}</text>
+						<text class="_unit">例</text>
+					</view>
+					<view class="flex-baseline">
+						<text class="_subtitle">已完成</text>
+						<text class="_subtitle" style="margin-left: 20rpx;">{{finishData.length}}</text>
+						<text class="_unit">例</text>
+					</view>
+					<view class="flex-baseline">
+						<text class="_subtitle">完成情况</text>
+						<text class="_subtitle" style="margin-left: 20rpx;">{{performance}}</text>
+					</view>
+				</view>
+				<view class="card-image" :style="{backgroundImage:`url(${image})`}"></view>
+			</view>
+			<!-- 列表卡片 -->
+			<view class="card-item" style="width: 100%;">
+				<view class="card-title">
+					<view class="front-tag"></view>
+					<view class="title">今日活动</view>
+					<view class="flex-row" style="margin: 0 0 0 auto;" @click="navSwapList" v-if="swapData.length != 0">
+						<view class="t-icon t-icon-fenlei"></view>
+						<view class="title" style="color: #4169E1;margin-left: 10rpx;">活动列表</view>
+					</view>
+				</view>
+				<view class="data-list">
+					<view class="data-item" :style="{borderImage: none}" v-for="(item,index) in swapData" :key="index"
+						@click="navSwapReport(index)" v-if="swapData.length != 0">
+						<view class="flex-row" style="margin: 0 20rpx;">
+							<view class="t-icon t-icon-swapfont" style="width: 60rpx; height: 60rpx;"></view>
+							<view class="flex-column">
+								<view class="flex-row">
+									<view class="item-title">{{item.survey.name || item.vote.name}}</view>
+									<view class="tag-fill" style="background-color: #FF6D31;">
+										<view class="tag-text">
+											{{item.survey.scope === 'private' ? '个人':'学校' || item.vote.scope === 'private' ? '个人':'学校'}}
+										</view>
+									</view>
+									<view class="tag-fill"
+										:style="{backgroundColor: item.survey.progress === 'finish' || item.vote.progress === 'finish'? '#23b46c':'#ff5959'}">
+										<view class="tag-text">
+											{{item.survey.progress === 'finish' || item.vote.progress === 'finish' ? '已完成' : '进行中'}}
+										</view>
+									</view>
+								</view>
+								<view class="row-desc">
+									<view class="item-subtitle" style="font-size: 26rpx;font-weight: 400;">
+										{{item.vote.description || item.survey.description}}
+									</view>
+								</view>
+							</view>
+						</view>
+					</view>
+					<view class="image-box" v-if="swapData.length === 0">
+						<view class="detail-image-none" :style="{backgroundImage:`url(${image1})`}"></view>
+						<view class="subtitle">今日暂无投票问卷活动</view>
+					</view>
+				</view>
+			</view>
+
+			<view class="flex-column" style="margin: 15rpx 0 10rpx 20rpx;">
+				<view class="title" style="font-size: 32rpx;">家校共育</view>
+				<view class="bottom-tag"></view>
+			</view>
+			<!-- 占位 -->
+			<view class="flex-row" style="width: 70%;"></view>
+		</view>
+		<scroll-view class="scroll-view-bottom" scroll-x="true" :scroll-with-animation="true" scroll-left="0">
+			<view class="scroll-item" v-for="(item,index) in interchangeData" :key="index">
+				<view class="icon-box">
+					<view :class="item.icon"></view>
+					<view class="flex-column">
+						<view class="icon-box-title">{{item.name}}</view>
+						<view class="icon-box-subtitle"></view>
+					</view>
+				</view>
+			</view>
+		</scroll-view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState,
+		mapMutations
+	} from 'vuex'
+	export default {
+		computed: {
+			...mapState('m_children', ['swapData']),
+			...mapState('m_parent', ['childDailyData'])
+		},
+		data() {
+			return {
+				//图表卡片列表
+				cardList: [{
+					icon: 't-icon t-icon-zoushi1',
+					title: '近期学习对比',
+					type: 'mini-column',
+					data: '',
+				}, {
+					icon: 't-icon t-icon-lishijilu',
+					title: '近期运动记录',
+					type: 'pie',
+					data: '',
+				}, {
+					icon: 't-icon t-icon-naozhong',
+					title: '近期睡眠记录',
+					type: 'ring',
+					data: '',
+				}],
+				interchangeData: [{
+					name: '请假申请',
+					icon: 't-icon t-icon-wj-qjd'
+				}, {
+					name: '体温记录',
+					icon: 't-icon t-icon-wj-jzbg'
+				}, {
+					name: '假期表现',
+					icon: 't-icon t-icon-wj-by'
+				}, {
+					name: '缴费概览',
+					icon: 't-icon t-icon-wj-zd'
+				}],
+				image: 'https://ouch-cdn2.icons8.com/LW70TMgW1cGfYeGNSTEp7__kiKVgIhwdZwUmykdLYMY/rs:fit:912:912/czM6Ly9pY29uczgu/b3VjaC1wcm9kLmFz/c2V0cy9wbmcvOTI0/LzU3MWU4ZDZkLTg0/NzEtNGM5YS04MDJk/LTEzNTM5YmZmZTM2/YS5wbmc.png',
+				//完成情况
+				performance: '',
+				//完成数据
+				finishData: '',
+				finishRate: '',
+				timeStamp: '',
+				image1: 'https://image.meiye.art/pic_1631411820764Vm5iw82gnV2lVKWRokFmU'
+			};
+		},
+		onLoad() {
+			this.init()
+		},
+		//刷新页面
+		onPullDownRefresh() {
+			this.init()
+			setTimeout(function() {
+				uni.stopPullDownRefresh();
+			}, 1000);
+		},
+		methods: {
+			...mapMutations('m_chart', ['updateSwapChartData']),
+			//初始化
+			init() {
+				this.timeStamp = (new Date()).format("hh:mm")
+				this.getPerformance()
+				this.$initSwap()
+				this.getSwapChartData()
+			},
+			//获得统计图表信息
+			getSwapChartData() {
+				let recentDate = this.$getRecentDateArray(this.childDailyData.study.length);
+				let swapChartData = [];
+				let studyColumn = {
+					categories: recentDate,
+					series: [{
+							name: '自主学习',
+							data: this.childDailyData.study
+						},
+						{
+							name: '娱乐放松',
+							data: this.childDailyData.rest
+						}
+					]
+				};
+				//运动记录表
+				let exercisePie = {
+					series: [{
+						data: [{}, {}, {}, {}, {}, {}, {}]
+					}]
+				};
+				//睡眠记录表
+				let sleepRing = {
+					series: [{
+						data: [{}, {}, {}, {}, {}, {}, {}]
+					}]
+				};
+				studyColumn.categories.forEach((value, index) => {
+					exercisePie.series[0].data[index].name = value;
+					exercisePie.series[0].data[index].value = parseFloat((this.childDailyData.exercise[index]));
+					sleepRing.series[0].data[index].name = value;
+					sleepRing.series[0].data[index].value = this.childDailyData.sleep[index];
+				});
+				swapChartData.push(studyColumn);
+				swapChartData.push(exercisePie);
+				swapChartData.push(sleepRing);
+				this.updateSwapChartData(swapChartData)
+				this.cardList[0].data = studyColumn
+				this.cardList[1].data = exercisePie
+				this.cardList[2].data = sleepRing
+			},
+			//获得评判信息
+			getPerformance() {
+				if (this.swapData.length != 0) {
+					this.finishData = this.swapData.filter(x => x.vote && x.vote.progress === 'finish')
+					this.finishData.push(...this.swapData.filter(x => x.survey && x.survey.progress === 'finish'))
+					this.finishRate = (this.finishData.length * 100 / this.swapData.length).toFixed(0)
+					this.performance = this.finishData.length / this.swapData.length >= 0.4 ?
+						(this.finishData.length / this.swapData.length >= 0.7 ? '优秀' : '良好') : '较差'
+				} else {
+					this.finishData = []
+					this.finishRate = 0
+					this.performance = '无活动'
+				}
+			},
+			navSwapStats() {
+				uni.navigateTo({
+					url: '/subpkg/swap/swapStats'
+				})
+			},
+			navSwapList() {
+				let value = this.finishRate
+				uni.navigateTo({
+					url: `/subpkg/datalist/swapList?value=${value}`
+				})
+			},
+			navSwapReport(index) {
+				uni.navigateTo({
+					url: `/subpkg/datalist/swapReport?index=${index}`
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import '@/pages/style/tab_pages.scss';
+
+	.bg1 {
+		background-color: $color-orange;
+	}
+
+	.flex-row {
+		margin: 5rpx 20rpx;
+	}
+
+	.row-desc {
+		margin: 5rpx 20rpx;
+		display: flex;
+		align-items: center;
+		width: 510rpx;
+		overflow: hidden;
+		white-space: nowrap;
+		text-overflow: ellipsis
+	}
+
+	.tag-fill {
+		background-color: $color-orange;
+		margin-left: 20rpx;
+	}
+
+	.circle-line1 {
+		background-image: linear-gradient(to right, #FF6D31, #FF6D31), linear-gradient(90deg, #FFF -50%, rgba(255, 255, 255, 0.0));
+	}
+
+	.circle-line2 {
+		background-image: linear-gradient(to right, #FF6D31, #FF6D31), linear-gradient(180deg, #FFF -50%, rgba(255, 255, 255, 0.0));
+	}
+
+	.circle-line3 {
+		background-image: linear-gradient(to right, #FF6D31, #FF6D31), linear-gradient(0deg, #FFF -50%, rgba(255, 255, 255, 0.0));
+	}
+
+	.scroll-item {
+		height: 120rpx !important;
+		width: 260rpx !important;
+
+		.icon-box {
+			display: flex;
+			align-items: center;
+			justify-content: space-around;
+			padding: 0 20rpx;
+			height: 120rpx;
+			width: 220rpx;
+			border-radius: $border-radius;
+			background-image: linear-gradient(to right, #FF6D31, rgba(255,109,49,0.5));
+			.t-icon{
+				width: 55rpx;
+				height: 55rpx;
+			}
+			.icon-box-title{
+				line-height: 40rpx;
+				font-size: 40rpx;
+				color: #FFF;
+				font-family: YSfont;
+			}
+			.icon-box-subtitle{
+				line-height: 30rpx;
+				font-size: 30rpx;
+				color: #FFF;
+				font-family: YSfont;
+			}
+		}
+	}
+</style>

+ 312 - 0
pages/tab_work/tab_work.vue

@@ -0,0 +1,312 @@
+<template>
+	<view class="page-view">
+		<!-- 统计 -->
+		<view class="bg1">
+			<view class="circle-line1"></view>
+			<view class="circle-line2"></view>
+			<view class="circle-line3"></view>
+			<top-info :timeStamp="timeStamp"></top-info>
+			<scroll-view class="scroll-view" scroll-x="true" :scroll-with-animation="true" scroll-left="0">
+				<view class="view-box">
+					<view class="scroll-view-item" v-for="(item,index) in cardList" :key="index" @click="navWorkStats">
+						<view class="card-info">
+							<view :class="item.icon"></view>
+							<view class="title">{{item.title}}</view>
+						</view>
+						<view class="chart-box">
+							<qiun-data-charts :type="item.type" :chartData="item.data" />
+						</view>
+					</view>
+				</view>
+			</scroll-view>
+		</view>
+		<!-- 统计卡片 -->
+		<view class="card-view">
+			<view class="stat-card" style="background-color:#f9c752">
+				<view class="card-column">
+					<view class="flex-baseline">
+						<text class="_title">今日作业</text>
+						<text class="_title" style="margin-left: 20rpx;">{{workData.length}}</text>
+						<text class="_unit">例</text>
+					</view>
+					<view class="flex-baseline">
+						<text class="_subtitle">已完成</text>
+						<text class="_subtitle" style="margin-left: 20rpx;">{{finishData.length}}</text>
+						<text class="_unit">例</text>
+					</view>
+					<view class="flex-baseline">
+						<text class="_subtitle">完成情况</text>
+						<text class="_subtitle" style="margin-left: 20rpx;">{{performance}}</text>
+					</view>
+				</view>
+				<view class="card-image" :style="{backgroundImage:`url(${image})`}"></view>
+			</view>
+			<!-- 列表卡片 -->
+			<view class="card-item" style="width: 100%;">
+				<view class="card-title">
+					<view class="front-tag"></view>
+					<view class="title">今日作业</view>
+					<view class="flex-row" style="margin: 0 0 0 auto;" @click="navWorkList" v-if="workData.length != 0">
+						<view class="t-icon t-icon-fenlei"></view>
+						<view class="title" style="color: #4169E1;margin-left: 10rpx;">作业列表</view>
+					</view>
+				</view>
+				<view class="data-list">
+					<view class="data-item"
+						:style="{borderImage: none}"
+						v-for="(item,index) in workData" :key="index" @click="navWorkReport(index)"
+						v-if="workData.length != 0">
+						<view class="flex-row" style="margin: 0 20rpx;">
+							<view class="t-icon t-icon-workicon" style="width: 60rpx; height: 60rpx;"></view>
+							<view class="flex-column">
+								<view class="flex-row">
+									<view class="item-title">{{item.work.name}}</view>
+									<view class="tag-fill" style="background-color: #f9c752;">
+										<view class="tag-text">{{item.work.scope === 'private' ? '个人':'学校'}}</view>
+									</view>
+									<view class="tag-fill"
+										:style="{backgroundColor: item.work.progress === 'finish'? '#23b46c':'#ff5959'}">
+										<view class="tag-text">{{item.work.progress === 'finish' ? '已完成' : '进行中'}}
+										</view>
+									</view>
+								</view>
+								<view class="row-desc">
+									<view class="item-subtitle" style="font-size: 26rpx;font-weight: 400;">
+										{{item.work.description}}
+									</view>
+								</view>
+							</view>
+						</view>
+					</view>
+					<view class="image-box" v-if="workData.length === 0">
+						<view class="detail-image-none" :style="{backgroundImage:`url(${image1})`}"></view>
+						<view class="subtitle">今日孩子暂无作业活动</view>
+					</view>
+				</view>
+			</view>
+
+			<view class="flex-column" style="margin: 15rpx 0 10rpx 20rpx;">
+				<view class="title" style="font-size: 32rpx;">错题本</view>
+				<view class="bottom-tag"></view>
+			</view>
+
+			<view class="flex-row" style="width: 70%;"></view>
+		</view>
+		<scroll-view class="scroll-view-bottom" scroll-x="true" :scroll-with-animation="true" scroll-left="0">
+			<view class="scroll-item" v-for="(item,index) in mistakeData" :key="index" @click="navWrongBook(index)">
+				<view class="flex-column-book" :style="{backgroundColor: item.color}">
+					<view class="book-shadow"></view>
+					<view class="bg-title">{{item.subject}}</view>
+					<view class="book-info">
+						<view class="book-title">{{item.subject}}</view>
+						<view class="flex-baseline" style="margin-left: auto;">
+							<view class="book-subtitle" style="margin-left: 0;">收录错题</view>
+							<view class="book-subtitle" style="font-size: 40rpx;">{{item.amount}}</view>
+							<view class="book-subtitle">道</view>
+						</view>
+					</view>
+				</view>
+			</view>
+		</scroll-view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex'
+	export default {
+		computed: {
+			...mapState('m_children', ['workData', 'mistakeData']),
+			...mapState('m_chart', ['workChartData'])
+		},
+		data() {
+			return {
+				cardList: [{
+					icon: 't-icon t-icon-gongzuo',
+					title: '近期作业完成率',
+					type: 'mini-column',
+					data: ''
+				}, {
+					icon: 't-icon t-icon-renzheng',
+					title: '近期作业得分率',
+					type: 'mini-area',
+					data: ''
+				}],
+				image: 'https://ouch-cdn2.icons8.com/AVOwJ9emg_ZOeHvQaunQAZlgeLsG-b1cGhiYvgoJ06g/rs:fit:912:912/czM6Ly9pY29uczgu/b3VjaC1wcm9kLmFz/c2V0cy9wbmcvNTAw/LzI5YjU1YWQ4LWMw/YTEtNDE1MS1iYmQw/LWIyMDdhYmRkOTE0/Mi5wbmc.png',
+				//完成情况
+				performance: '',
+				//完成数据
+				finishData: '',
+				finishRate: '',
+				timeStamp: '',
+				image1: 'https://image.meiye.art/pic_16314118207650DBDbJB8Ao3fE8_1bY3Fj',
+			};
+		},
+		onLoad() {
+			this.init()
+		},
+		//刷新页面
+		onPullDownRefresh() {
+			this.init()
+			setTimeout(function() {
+				uni.stopPullDownRefresh();
+			}, 1000);
+		},
+		methods: {
+			//初始化
+			init() {
+				this.timeStamp = (new Date()).format("hh:mm")
+				this.$initWork()
+				this.getWorkChartData()
+				this.getPerformance()
+			},
+			//获得作业图表信息
+			getWorkChartData() {
+				this.cardList[0].data = this.workChartData[0]
+				this.cardList[1].data = this.workChartData[1]
+			},
+			//获得评判信息
+			getPerformance() {
+				if (this.workData.length != 0) {
+					this.finishData = this.workData.filter(x => x.work.progress === 'finish')
+					this.finishRate = (this.finishData.length * 100 / this.workData.length).toFixed(0)
+					this.performance = this.finishData.length / this.workData.length >= 0.4 ?
+						(this.finishData.length / this.workData.length >= 0.7 ? '优秀' : '良好') : '较差'
+				} else {
+					this.finishData = []
+					this.finishRate = 0
+					this.performance = '无作业'
+				}
+			},
+			navWorkStats() {
+				uni.navigateTo({
+					url: '/subpkg/work/workStats'
+				})
+			},
+			navWorkList() {
+				let value = this.finishRate
+				uni.navigateTo({
+					url: `/subpkg/datalist/workList?value=${value}`
+				})
+			},
+			navWorkReport(index) {
+				uni.navigateTo({
+					url: `/subpkg/datalist/workReport?index=${index}`
+				})
+			},
+			navWrongBook(index){
+				uni.navigateTo({
+					url: `/subpkg/work/wrongBook?index=${index}`
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import '@/pages/style/tab_pages.scss';
+
+	.bg1 {
+		background-color: $color-yellow;
+	}
+
+	.flex-row {
+		margin: 5rpx 20rpx;
+	}
+	.row-desc{
+		margin: 5rpx 20rpx;
+		display: flex;
+		align-items: center;
+		width: 510rpx;
+		overflow: hidden;
+		white-space: nowrap;
+		text-overflow: ellipsis
+	}
+
+	.tag-fill {
+		background-color: $color-pink;
+		margin-left: 20rpx;
+	}
+
+	.image {
+		top: -50rpx;
+	}
+
+	.circle-line1 {
+		background-image: linear-gradient(to right, #f9c752, #f9c752), linear-gradient(90deg, #FFF -50%, rgba(255, 255, 255, 0.0));
+	}
+
+	.circle-line2 {
+		background-image: linear-gradient(to right, #f9c752, #f9c752), linear-gradient(180deg, #FFF -50%, rgba(255, 255, 255, 0.0));
+	}
+
+	.circle-line3 {
+		background-image: linear-gradient(to right, #f9c752, #f9c752), linear-gradient(0deg, #FFF -50%, rgba(255, 255, 255, 0.0));
+	}
+
+	.scroll-view-bottom {
+		margin-top: -10rpx;
+
+		.scroll-item {
+			margin: 10rpx 20rpx 0 20rpx;
+			display: inline-block;
+			vertical-align: top;
+			background-color: #FFF;
+			border-radius: $border-radius;
+			height: 300rpx;
+			width: 240rpx;
+			z-index: 55;
+			box-shadow: 1px 0px 2px #ffffff, 2px -1px 2px #d2d2d2, 3px -2px 2px #b4b4b4;
+		}
+	}
+
+	.flex-column-book {
+		display: flex;
+		flex-direction: column;
+		height: 100%;
+		width: 100%;
+		overflow: hidden;
+	}
+
+	.bg-title {
+		position: absolute;
+		margin-top: 60rpx;
+		margin-left: 80rpx;
+		font-size: 130rpx;
+		font-weight: 600;
+		color: #FFF;
+		opacity: 0.2;
+		writing-mode: vertical-lr;
+	}
+
+	.book-shadow {
+		position: absolute;
+		margin-left: 20rpx;
+		height: 300rpx;
+		width: 20rpx;
+		background-image: linear-gradient(to right, rgba(105, 105, 105, 0.1), rgba(255, 255, 255, 0.1));
+	}
+
+	.book-info {
+		display: flex;
+		flex-direction: column;
+		height: 100rpx;
+		width: 200rpx;
+		margin: 160rpx 20rpx 40rpx 20rpx;
+		justify-content: space-between;
+		z-index: 99;
+		.book-title{
+			line-height: 60rpx;
+			font-family: YSfont;
+			color: #FFF;
+			font-size: 60rpx;
+			margin-left: auto;
+		}
+		.book-subtitle{
+			font-size: 28rpx;
+			color: #FFF;
+			margin-left: 4rpx;
+		}
+	}
+</style>

+ 58 - 0
static/default_icons/boy_avatar.svg

@@ -0,0 +1,58 @@
+<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 1024 1024" height="1024px" width="1024px">
+    <title>头像-男学生4</title>
+    <defs>
+        <circle r="512" cy="512" cx="512" id="path-1"></circle>
+        <rect height="133" width="94" y="0" x="0" id="path-3"></rect>
+        <path id="path-5" d="M347.567605,-5.73763259e-13 C457.803482,42.9842549 538,174.063276 538,329.095567 C538,519.081521 417.564598,673.095567 269,673.095567 C120.435402,673.095567 9.43064043e-15,519.081521 2.10639249e-14,329.095567 C3.05569149e-14,174.063276 80.1965178,42.9842549 190.432395,-5.77315973e-13 L190.433606,0.010785417 C209.979969,14.8222948 237.944984,24.095567 269,24.095567 C299.729123,24.095567 327.432759,15.0159017 346.948258,0.475249013 Z"></path>
+    </defs>
+    <g fill-rule="evenodd" fill="none" stroke-width="1" stroke="none" id="头像-男学生4">
+        <rect height="1024" width="1024" y="0" x="0" fill="#FFFFFF"></rect>
+        <g id="编组-3">
+            <mask fill="white" id="mask-2">
+                <use xlink:href="#path-1"></use>
+            </mask>
+            <use xlink:href="#path-1" fill="#77C4F9" fill-opacity="0.2" id="蒙版"></use>
+            <g mask="url(#mask-2)" id="编组-2">
+                <g id="编组" transform="translate(208.927982, 153.975009)">
+                    <path fill="#489AD2" id="形状结合" d="M303.072018,627.024991 C330.404969,627.024991 356.785783,632.238171 381.639622,641.929424 L381.638412,641.940209 C362.092048,656.751719 334.127034,666.024991 303.072018,666.024991 C272.017239,666.024991 244.052415,656.75186 224.506072,641.940549 L224.505016,641.929189 C249.358679,632.238087 275.739287,627.024991 303.072018,627.024991 Z"></path>
+                    <rect rx="112" height="324" width="580" y="116.024991" x="13.0720177" fill="#110D2E" id="矩形"></rect>
+                    <path fill="#FBB4B4" id="椭圆形备份-4" d="M66.5219796,475.850124 C83.9796604,467.270421 86.6032391,443.317655 72.3819068,422.350124 C58.1605745,401.382594 32.4796604,391.340276 15.0219796,399.91998 C-2.43570115,408.499683 -5.05927994,432.452449 9.16205237,453.41998 C23.3833847,474.38751 49.0642988,484.429828 66.5219796,475.850124 Z"></path>
+                    <path fill="#FBB4B4" id="椭圆形备份-12" d="M539.02198,475.850124 C521.564299,467.270421 518.94072,443.317655 533.162052,422.350124 C547.383385,401.382594 573.064299,391.340276 590.52198,399.91998 C607.97966,408.499683 610.603239,432.452449 596.381907,453.41998 C582.160575,474.38751 556.47966,484.429828 539.02198,475.850124 Z"></path>
+                    <line stroke-linejoin="round" stroke-linecap="round" opacity="0.106926328" stroke-width="7" stroke="#000000" id="路径-6" y2="885.661003" x2="144.572018" y1="799.524991" x1="170.572018"></line>
+                    <line transform="translate(448.572018, 842.362677) scale(-1, 1) translate(-448.572018, -842.362677)" stroke-linejoin="round" stroke-linecap="round" opacity="0.106926328" stroke-width="7" stroke="#000000" id="路径-6备份" y2="885.661003" x2="435.572018" y1="799.524991" x1="461.572018"></line>
+                    <g transform="translate(256.072018, 558.024991)" id="椭圆形备份-11">
+                        <mask fill="white" id="mask-4">
+                            <use xlink:href="#path-3"></use>
+                        </mask>
+                        <use xlink:href="#path-3" fill="#FFCACA" id="蒙版"></use>
+                        <ellipse ry="47" rx="79" cy="5" cx="47" mask="url(#mask-4)" opacity="0.214906238" style="mix-blend-mode: multiply;" fill="#EC8484"></ellipse>
+                    </g>
+                    <ellipse ry="225" rx="255" cy="370.024991" cx="303.072018" fill="#FFCACA" id="椭圆形"></ellipse>
+                    <path stroke-linejoin="round" stroke-linecap="round" stroke-width="8" stroke="#FF9494" id="路径-5备份" d="M293.072018,440.024991 L293.072018,466.024991 C293.072018,473.756977 299.340031,480.024991 307.072018,480.024991 L313.904967,480.024991 L313.904967,480.024991"></path>
+                    <circle r="19" cy="413.024991" cx="206.072018" fill="#110D2E" id="椭圆形"></circle>
+                    <circle r="19" cy="413.024991" cx="400.072018" fill="#110D2E" id="椭圆形备份-7"></circle>
+                    <path stroke-linejoin="round" stroke-linecap="round" stroke-width="10" stroke="#EC8484" id="路径-35" d="M260.072018,526.524991 L266.696357,529.386852 C289.575079,539.270966 315.706543,538.21795 337.715776,526.524991 L337.715776,526.524991 L337.715776,526.524991"></path>
+                    <path stroke-linejoin="round" stroke-linecap="round" stroke-width="6" stroke="#110D2E" id="路径-4备份" d="M171.072018,365.653731 C185.19021,361.901238 196.679672,360.024991 205.540404,360.024991 C214.401137,360.024991 226.163897,361.901238 240.828686,365.653731"></path>
+                    <path transform="translate(399.950352, 362.839361) scale(-1, 1) translate(-399.950352, -362.839361)" stroke-linejoin="round" stroke-linecap="round" stroke-width="6" stroke="#110D2E" id="路径-4备份-2" d="M365.072018,365.653731 C379.19021,361.901238 390.679672,360.024991 399.540404,360.024991 C408.401137,360.024991 420.163897,361.901238 434.828686,365.653731"></path>
+                    <rect rx="112.5" height="225" width="545" y="69.0249907" x="31.0720177" fill="#110D2E" id="矩形"></rect>
+                    <ellipse ry="69.5" rx="36.5" cy="66.3599272" cx="296.822018" transform="translate(296.822018, 66.359927) rotate(-300.000000) translate(-296.822018, -66.359927)" fill="#110D2E" id="椭圆形"></ellipse>
+                    <ellipse ry="69.5" rx="36.5" cy="69.3599272" cx="361.822018" transform="translate(361.822018, 69.359927) rotate(-300.000000) translate(-361.822018, -69.359927)" fill="#110D2E" id="椭圆形备份"></ellipse>
+                    <ellipse ry="69.5" rx="36.5" cy="66.3599272" cx="475.822018" transform="translate(475.822018, 66.359927) rotate(-300.000000) translate(-475.822018, -66.359927)" fill="#110D2E" id="椭圆形备份-2"></ellipse>
+                    <ellipse ry="69.5" rx="36.5" cy="115.359927" cx="492.822018" transform="translate(492.822018, 115.359927) rotate(-300.000000) translate(-492.822018, -115.359927)" fill="#110D2E" id="椭圆形备份-3"></ellipse>
+                    <g transform="translate(34.072018, 641.929424)" id="矩形-+-矩形备份-2-+-矩形备份-蒙版">
+                        <mask fill="white" id="mask-6">
+                            <use xlink:href="#path-5"></use>
+                        </mask>
+                        <use xlink:href="#path-5" fill="#77C4F9" id="蒙版"></use>
+                        <rect height="182" width="44" y="19.095567" x="110" mask="url(#mask-6)" fill="#1A82C9" id="矩形"></rect>
+                        <rect height="182" width="318" y="130.095567" x="110" mask="url(#mask-6)" fill="#1A82C9" id="矩形备份-2"></rect>
+                        <rect height="182" width="44" y="19.095567" x="384" mask="url(#mask-6)" fill="#1A82C9" id="矩形备份"></rect>
+                    </g>
+                    <circle r="8" cy="695.024991" cx="303.072018" fill="#1A82C9" id="椭圆形"></circle>
+                    <circle r="8" cy="753.024991" cx="303.072018" fill="#1A82C9" id="椭圆形备份-5"></circle>
+                    <circle r="8" cy="724.024991" cx="303.072018" fill="#1A82C9" id="椭圆形备份-6"></circle>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

+ 69 - 0
static/default_icons/girl_avatar.svg

@@ -0,0 +1,69 @@
+<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 1024 1024" height="1024px" width="1024px">
+    <title>头像-女学生5</title>
+    <defs>
+        <circle r="512" cy="512" cx="512" id="path-1"></circle>
+        <rect height="133" width="94" y="0" x="0" id="path-3"></rect>
+        <ellipse ry="269" rx="344" cy="344" cx="269" id="path-5"></ellipse>
+    </defs>
+    <g fill-rule="evenodd" fill="none" stroke-width="1" stroke="none" id="头像-女学生5">
+        <rect height="1024" width="1024" y="0" x="0" fill="#FFFFFF"></rect>
+        <g id="编组-3">
+            <mask fill="white" id="mask-2">
+                <use xlink:href="#path-1"></use>
+            </mask>
+            <use xlink:href="#path-1" fill="#1C8784" fill-opacity="0.2" id="蒙版"></use>
+            <g mask="url(#mask-2)" id="编组-2">
+                <g transform="translate(77.482128, 130.947862)">
+                    <ellipse ry="123.5" rx="72.5" cy="425.552138" cx="189.017872" fill-rule="evenodd" fill="#110D2E" stroke="none" id="椭圆形"></ellipse>
+                    <ellipse ry="123.5" rx="72.5" cy="425.552138" cx="680.017872" fill-rule="evenodd" fill="#110D2E" stroke="none" id="椭圆形备份-9"></ellipse>
+                    <g transform="translate(0.000000, 473.052138)" fill-rule="evenodd" fill="none" stroke-width="1" stroke="none" id="编组">
+                        <circle r="72.5" cy="72.5" cx="189.017872" fill="#110D2E" id="椭圆形备份-5"></circle>
+                        <circle r="49.5" cy="141.5" cx="133.017872" fill="#110D2E" id="椭圆形备份-6"></circle>
+                        <circle r="39" cy="186" cx="92.5178719" fill="#110D2E" id="椭圆形备份-8"></circle>
+                        <path transform="translate(56.735254, 219.960819) rotate(-16.000000) translate(-56.735254, -219.960819)" fill="#110D2E" id="路径-41" d="M109.735254,198.960819 L41.9068525,234.461905 C34.9170394,238.120343 26.2879493,235.738986 22.163787,229.013443 L16.6126387,219.960819 C12.631122,213.467897 14.6670182,204.976687 21.15994,200.99517 C23.3292811,199.664911 25.8243878,198.960819 28.3691137,198.960819 L109.735254,198.960819 L109.735254,198.960819 Z"></path>
+                    </g>
+                    <g transform="translate(738.758936, 600.430185) scale(-1, 1) translate(-738.758936, -600.430185) translate(608.000000, 473.052138)" fill-rule="evenodd" fill="none" stroke-width="1" stroke="none" id="编组备份">
+                        <circle r="72.5" cy="72.5" cx="189.017872" fill="#110D2E" id="椭圆形备份-5"></circle>
+                        <circle r="49.5" cy="141.5" cx="133.017872" fill="#110D2E" id="椭圆形备份-6"></circle>
+                        <circle r="39" cy="186" cx="92.5178719" fill="#110D2E" id="椭圆形备份-8"></circle>
+                        <path transform="translate(56.735254, 219.960819) rotate(-16.000000) translate(-56.735254, -219.960819)" fill="#110D2E" id="路径-41" d="M109.735254,198.960819 L41.9068525,234.461905 C34.9170394,238.120343 26.2879493,235.738986 22.163787,229.013443 L16.6126387,219.960819 C12.631122,213.467897 14.6670182,204.976687 21.15994,200.99517 C23.3292811,199.664911 25.8243878,198.960819 28.3691137,198.960819 L109.735254,198.960819 L109.735254,198.960819 Z"></path>
+                    </g>
+                    <path fill-rule="evenodd" fill="#FBB4B4" stroke="none" id="椭圆形备份-4" d="M197.967834,498.877271 C215.425515,490.297567 218.049093,466.344802 203.827761,445.377271 C189.606429,424.409741 163.925515,414.367423 146.467834,422.947127 C129.010153,431.52683 126.386574,455.479596 140.607907,476.447127 C154.829239,497.414657 180.510153,507.456975 197.967834,498.877271 Z"></path>
+                    <path fill-rule="evenodd" fill="#FBB4B4" stroke="none" id="椭圆形备份-12" d="M670.467834,498.877271 C653.010153,490.297567 650.386574,466.344802 664.607907,445.377271 C678.829239,424.409741 704.510153,414.367423 721.967834,422.947127 C739.425515,431.52683 742.049093,455.479596 727.827761,476.447127 C713.606429,497.414657 687.925515,507.456975 670.467834,498.877271 Z"></path>
+                    <line stroke-linejoin="round" stroke-linecap="round" opacity="0.106926328" fill="none" stroke-width="7" stroke="#000000" id="路径-6" y2="908.68815" x2="276.017872" y1="822.552138" x1="302.017872"></line>
+                    <line transform="translate(580.017872, 865.389824) scale(-1, 1) translate(-580.017872, -865.389824)" stroke-linejoin="round" stroke-linecap="round" opacity="0.106926328" fill="none" stroke-width="7" stroke="#000000" id="路径-6备份" y2="908.68815" x2="567.017872" y1="822.552138" x1="593.017872"></line>
+                    <g transform="translate(387.517872, 581.052138)" fill-rule="evenodd" fill="none" stroke-width="1" stroke="none" id="椭圆形备份-11">
+                        <mask fill="white" id="mask-4">
+                            <use xlink:href="#path-3"></use>
+                        </mask>
+                        <use xlink:href="#path-3" fill="#FFCACA" id="蒙版"></use>
+                        <ellipse ry="47" rx="79" cy="5" cx="47" mask="url(#mask-4)" opacity="0.214906238" style="mix-blend-mode: multiply;" fill="#EC8484"></ellipse>
+                    </g>
+                    <ellipse ry="225" rx="255" cy="393.052138" cx="434.517872" fill-rule="evenodd" fill="#FFCACA" stroke="none" id="椭圆形"></ellipse>
+                    <path stroke-linejoin="round" stroke-linecap="round" fill="none" stroke-width="8" stroke="#FF9494" id="路径-5备份" d="M424.517872,463.052138 L424.517872,489.052138 C424.517872,496.784124 430.785885,503.052138 438.517872,503.052138 L445.350822,503.052138 L445.350822,503.052138"></path>
+                    <circle r="19" cy="436.052138" cx="337.517872" fill-rule="evenodd" fill="#110D2E" stroke="none" id="椭圆形"></circle>
+                    <circle r="19" cy="436.052138" cx="531.517872" fill-rule="evenodd" fill="#110D2E" stroke="none" id="椭圆形备份-7"></circle>
+                    <path stroke-linejoin="round" stroke-linecap="round" fill="none" stroke-width="10" stroke="#EC8484" id="路径-35" d="M391.517872,549.552138 L398.142211,552.413999 C421.020933,562.298113 447.152397,561.245097 469.16163,549.552138 L469.16163,549.552138 L469.16163,549.552138"></path>
+                    <path stroke-linejoin="round" stroke-linecap="round" fill="none" stroke-width="6" stroke="#110D2E" id="路径-4备份" d="M302.517872,388.680878 C316.636064,384.928385 328.125526,383.052138 336.986258,383.052138 C345.846991,383.052138 357.609751,384.928385 372.27454,388.680878"></path>
+                    <path transform="translate(531.396206, 385.866508) scale(-1, 1) translate(-531.396206, -385.866508)" stroke-linejoin="round" stroke-linecap="round" fill="none" stroke-width="6" stroke="#110D2E" id="路径-4备份-2" d="M496.517872,388.680878 C510.636064,384.928385 522.125526,383.052138 530.986258,383.052138 C539.846991,383.052138 551.609751,384.928385 566.27454,388.680878"></path>
+                    <g transform="translate(165.517872, 650.052138)" fill-rule="evenodd" fill="none" stroke-width="1" stroke="none" id="路径-23备份-+-路径-23备份-蒙版">
+                        <mask fill="white" id="mask-6">
+                            <use xlink:href="#path-5"></use>
+                        </mask>
+                        <use xlink:href="#path-5" transform="translate(269.000000, 344.000000) rotate(-90.000000) translate(-269.000000, -344.000000)" fill="#FFFFFF" id="蒙版"></use>
+                        <rect height="362" width="191" y="-1.8189894e-12" x="1.8189894e-12" mask="url(#mask-6)" fill="#1C8784" id="矩形"></rect>
+                        <rect height="362" width="191" y="-1.8189894e-12" x="341" mask="url(#mask-6)" fill="#1C8784" id="矩形备份"></rect>
+                        <ellipse ry="24" rx="72" cy="2" cx="269" mask="url(#mask-6)" fill="#FFCACA" id="椭圆形"></ellipse>
+                    </g>
+                    <circle r="8" cy="740.052138" cx="434.517872" fill-rule="evenodd" fill="#1C8784" stroke="none" id="椭圆形"></circle>
+                    <circle r="8" cy="803.052138" cx="434.517872" fill-rule="evenodd" fill="#1C8784" stroke="none" id="椭圆形备份-2"></circle>
+                    <circle r="8" cy="866.052138" cx="434.517872" fill-rule="evenodd" fill="#1C8784" stroke="none" id="椭圆形备份-3"></circle>
+                    <line stroke-linejoin="round" stroke-linecap="round" opacity="0.106926328" fill="none" stroke-width="7" stroke="#000000" id="路径-6" y2="908.68815" x2="276.017872" y1="822.552138" x1="302.017872"></line>
+                    <line transform="translate(580.017872, 865.389824) scale(-1, 1) translate(-580.017872, -865.389824)" stroke-linejoin="round" stroke-linecap="round" opacity="0.106926328" fill="none" stroke-width="7" stroke="#000000" id="路径-6备份" y2="908.68815" x2="567.017872" y1="822.552138" x1="593.017872"></line>
+                    <ellipse ry="206.5" rx="135" cy="241.476966" cx="284.828502" transform="translate(284.828502, 241.476966) rotate(-315.000000) translate(-284.828502, -241.476966)" fill-rule="evenodd" fill="#110D2E" stroke="none" id="椭圆形"></ellipse>
+                    <ellipse ry="206.5" rx="135" cy="241.476966" cx="584.828502" transform="translate(584.828502, 241.476966) scale(-1, 1) rotate(-315.000000) translate(-584.828502, -241.476966)" fill-rule="evenodd" fill="#110D2E" stroke="none" id="椭圆形备份"></ellipse>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

ファイルの差分が大きいため隠しています
+ 4 - 0
static/iconfont/iconfont-font.css


ファイルの差分が大きいため隠しています
+ 631 - 0
static/iconfont/iconfont-weapp-icon.css


BIN
static/tab_icons/exam.png


BIN
static/tab_icons/examselect.png


BIN
static/tab_icons/home.png


BIN
static/tab_icons/homeselect.png


BIN
static/tab_icons/mine.png


BIN
static/tab_icons/mineselect.png


BIN
static/tab_icons/swap.png


BIN
static/tab_icons/swapselect.png


BIN
static/tab_icons/work.png


BIN
static/tab_icons/workselect.png


ファイルの差分が大きいため隠しています
+ 1 - 0
static/th-autograph/back.svg


BIN
static/th-autograph/checkRow.png


ファイルの差分が大きいため隠しています
+ 1 - 0
static/th-autograph/clear.svg


ファイルの差分が大きいため隠しています
+ 1 - 0
static/th-autograph/color.svg


ファイルの差分が大きいため隠しています
+ 1 - 0
static/th-autograph/pencli.svg


+ 41 - 0
store/chart.js

@@ -0,0 +1,41 @@
+//导出全局表信息存储模块
+export default {
+	//开启命名空间
+	namespaced: true,
+	//模块数据
+	state: () => ({
+		//成绩图表数据
+		examChartData: '',
+		//作业图表数据
+		workChartData: '',
+		//家校图表数据
+		swapChartData: '',
+		//考试与科目信息
+		subjectExamData: '',
+	}),
+	//模块方法(修改数据)
+	mutations: {
+		//更新成绩图表数据
+		updateExamChartData(state, examChartData) {
+			state.examChartData = examChartData
+		},
+		//更新作业图表数据
+		updateWorkChartData(state, workChartData) {
+			state.workChartData = workChartData
+		},
+		//更新家校图表数据
+		updateSwapChartData(state, swapChartData){
+			state.swapChartData = swapChartData
+		},
+		//更新考试与科目信息
+		updateSubjectExamData(state, subjectExamData){
+			state.subjectExamData = subjectExamData
+		},
+
+
+	},
+	//模块属性(数据包装)
+	getters: {
+
+	}
+}

+ 63 - 0
store/children.js

@@ -0,0 +1,63 @@
+export default {
+	namespaced: true,
+	
+	state: () => ({
+		//当前孩子信息
+		childInfo: JSON.parse(uni.getStorageSync('childInfo') || '{}'),
+		//当日课程数据
+		classList: '',
+		//评测数据
+		examData: '',
+		//作业数据
+		workData: '',
+		//活动数据
+		swapData: '',
+		//打卡数据
+		clockData: '',
+		//勋章数据
+		medalData: '',
+		//评测练习
+		examPractice: '',
+		//错题数据
+		mistakeData: '',
+	}),
+	mutations: {
+		//更新当前孩子信息
+		updateChildInfo(state, childInfo){
+			state.childInfo = childInfo
+			uni.setStorageSync('childInfo',JSON.stringify(state.childInfo))
+		},
+		//更新今日课程信息
+		updateClassList(state, classList){
+			state.classList = classList
+		},
+		//更新评测
+		updateExamData(state, examData){
+			state.examData = examData
+		},
+		//更新作业
+		updateWorkData(state, workData){
+			state.workData = workData
+		},
+		//更新活动
+		updateSwapData(state, swapData){
+			state.swapData = swapData
+		},
+		//更新打卡记录
+		updateClockData(state, clockData){
+			state.clockData = clockData
+		},
+		//更新勋章数据
+		updateMedalData(state, medalData){
+			state.medalData = medalData
+		},
+		//更新评测练习
+		updateExamPractice(state, examPractice){
+			state.examPractice = examPractice
+		},
+		//更新错题数据
+		updateMistakeData(state, mistakeData){
+			state.mistakeData = mistakeData
+		}
+	}
+}

+ 60 - 0
store/parent.js

@@ -0,0 +1,60 @@
+export default {
+	namespaced: true,
+	
+	state: () => ({
+		//登录凭证openid和session_key
+		token: uni.getStorageSync('token') || '',
+		//家长信息
+		parentInfo: JSON.parse(uni.getStorageSync('parentInfo') || '{}'),
+		//家长手机号
+		phoneNumber: uni.getStorageSync('phoneNumber') || '',
+		//家长所有孩子信息
+		childrenData: JSON.parse(uni.getStorageSync('childrenData') || '{}'),
+		//个人数据
+		userData: JSON.parse(uni.getStorageSync('userData') || '{}'),
+		//已购课程数据
+		classData: JSON.parse(uni.getStorageSync('classData') || '{}'),
+		//孩子日常记录数据
+		childDailyData: JSON.parse(uni.getStorageSync('childDailyData') || '{}'),
+	}),
+	mutations: {
+		//更新登录凭证
+		updateToken(state, token){
+			state.token = token
+			uni.setStorageSync('token',state.token)
+		},
+		//更新用户信息
+		updateParentInfo(state, parentInfo) {
+			state.parentInfo = parentInfo
+			uni.setStorageSync('parentInfo', JSON.stringify(state.parentInfo))
+		},
+		//更新家长手机号
+		updatePhoneNumber(state, phoneNumber){
+			state.phoneNumber = phoneNumber
+			uni.setStorageSync('phoneNumber', state.phoneNumber)
+		},
+		//更新家长所有孩子信息
+		updateChildrenData(state, childrenData){
+			state.childrenData = childrenData
+			uni.setStorageSync('childrenData', JSON.stringify(state.childrenData))
+		},
+		//更新个人数据
+		updateUserData(state,userData){
+			state.userData = userData
+			uni.setStorageSync('userData', JSON.stringify(state.userData))
+		},
+		//更新已购课程数据
+		updateClassData(state,classData){
+			state.classData = classData
+			uni.setStorageSync('classData', JSON.stringify(state.classData))
+		},
+		//更新孩子日常记录数据
+		updateChildDailyData(state,childDailyData){
+			state.childDailyData = childDailyData
+			uni.setStorageSync('childDailyData', JSON.stringify(state.childDailyData))
+		},
+	},
+	getters:{
+		
+	}
+}

+ 21 - 0
store/store.js

@@ -0,0 +1,21 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+
+import moduleparent from './parent.js'
+import modulechildren from './children.js'
+import modulechart from './chart.js'
+
+Vue.use(Vuex)
+
+//创建Store的实例对象
+const store = new Vuex.Store({
+	//挂载应用模块
+	modules:{
+		'm_parent': moduleparent,
+		'm_children': modulechildren,
+		'm_chart': modulechart
+	},
+})
+
+//向外共享Store的实例对象
+export default store

+ 87 - 0
subpkg/datalist/data_pages.scss

@@ -0,0 +1,87 @@
+	.card-view{
+		.card-item {
+			width: 100%;
+			.card-title {
+				display: flex;
+				align-items: center;
+				padding: 40rpx;
+				height: 40rpx;
+		
+				.t-icon {
+					height: 40rpx;
+					width: 40rpx;
+					margin-right: 10rpx;
+				}
+		
+				.state-seal {
+					width: 55px;
+					height: 55px;
+					margin-left: auto;
+					margin-right: -20rpx;
+				}
+			}
+		
+			.card-info {
+				display: flex;
+				flex-direction: column;
+				margin: 0	40rpx 40rpx 40rpx;
+				.info-type {
+					font-size: 26rpx;
+					line-height: 30rpx;
+					color: $subtitle;
+				}
+			}
+			
+			.content-box {
+				margin: 20rpx;
+				padding: 0 20rpx;
+				background-color: #f6f6f6;
+				border-radius: 10rpx;
+			
+				.title-box {
+					position: relative;
+					top: -20rpx;
+					width: fit-content;
+					height: 36rpx;
+					border-radius: 6rpx;
+					padding: 5rpx 20rpx;
+			
+					.title-text {
+						font-size: 25rpx;
+						font-weight: bold;
+						color: #FFF;
+					}
+				}
+			
+				.content-detail {
+					font-size: 30rpx;
+					font-weight: bold;
+					color: $title;
+					word-break: break-all;
+				}
+			
+				.content-subtitle {
+					font-size: 25rpx;
+					font-weight: bold;
+					color: $subtitle;
+				}
+			}
+		}
+	}
+
+	.report-title {
+		font-size: 75rpx;
+		line-height: 75rpx;
+		font-family: YSfont;
+		color: #FFF;
+		z-index: 99;
+	}
+	
+	.report-subtitle {
+		font-size: 40rpx;
+		font-family: YSfont;
+		margin-top: 40rpx;
+		margin-bottom: 20rpx;
+		color: #FFF;
+		z-index: 99;
+	}

+ 106 - 0
subpkg/datalist/examList.vue

@@ -0,0 +1,106 @@
+<template>
+	<view class="page-view">
+		<top-return :color="'#FFF'" text="评测列表"></top-return>
+
+		<view class="bg-box2"></view>
+		<!-- 页面标题内容 -->
+		<view class="top-box">
+			<view class="flex-baseline">
+				<view class="info-title" style="margin-left: 0;">{{dayTime.split('月')[0]}}</view>
+				<view class="info-subtitle">月</view>
+				<view class="info-title">{{dayTime.split('月')[1]}}</view>
+				<view class="info-subtitle">日</view>
+				<view class="info-subtitle" style="margin-left: 20rpx;">已完成</view>
+				<view class="info-title">{{value}}%</view>
+			</view>
+			<view class="flex-baseline">
+				<view class="data-subtitle" style="margin-left: 0;">孩子今日共</view>
+				<view class="data-title">{{examData.length}}</view>
+				<view class="data-subtitle">例评测</view>
+			</view>
+		</view>
+		<!-- 卡片内容 -->
+		<view class="card-view">
+			<view class="card-item" v-for="(item,index) in examData" :key="index"
+				@click="navExamReport(index)">
+				<view class="card-title">
+					<view class="t-icon t-icon-examicon"></view>
+					<view class="YS-title" style="font-size: 45rpx;">{{item.examInfo.name}}</view>
+					<view
+						:class="[item.examInfo.progress === 'finish'?'t-icon t-icon-yiwancheng1':'t-icon t-icon-jinhangzhong','state-seal']">
+					</view>
+				</view>
+				<view class="card-info">
+					<view class="flex-row">
+						<view class="tag-fill"
+							:style="{backgroundColor: item.examInfo.progress === 'finish'? '#23b46c': '#ff8caf' }">
+							<view class="tag-text">{{item.examInfo.subjects[0].name}}</view>
+						</view>
+						<view class="tag-fill" style="margin-left: 20rpx;"
+							:style="{backgroundColor: item.examInfo.progress === 'finish'? '#23b46c': '#ff8caf' }">
+							<view class="tag-text">{{item.examInfo.examType.name}}</view>
+						</view>
+					</view>
+					<view class="flex-baseline" style="margin-top: 20rpx;">
+						<view class="info-type">布置老师:</view>
+						<view class="YS-title" style="margin-left: 10rpx;">{{item.examInfo.creatorId}}
+						</view>
+						<view class="info-type" style="margin-left: 20rpx;">截止时间:</view>
+						<view class="YS-title" style="margin-left: 10rpx;">
+							{{$timeStampToTime(item.examInfo.endTime)}}
+						</view>
+					</view>
+				</view>
+				<view class="content-box">
+					<view class="title-box"
+						:style="{backgroundColor: item.examInfo.progress === 'finish'? '#23b46c': '#ff8caf' }">
+						<view class="title-text">{{item.examInfo.papers[0].name}}</view>
+					</view>
+					<view class="content-detail"></view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState,
+		mapMutations
+	} from 'vuex'
+	export default {
+		computed: {
+			...mapState('m_children', ['examData'])
+		},
+		data() {
+			return {
+				// tabList: [{
+				// 	name: '已完成'
+				// }, {
+				// 	name: '未完成'
+				// }],
+				value: '',
+				dayTime: ''
+			}
+		},
+		onLoad(parameter) {
+			this.value = parameter.value
+			this.dayTime = (new Date()).format('M-d').replace('-', '月')
+		},
+		methods: {
+			navExamReport(index) {
+				uni.navigateTo({
+					url: `/subpkg/datalist/examReport?index=${index}`
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import 'data_pages.scss';
+	@import 'top_info.scss';
+	.tag-fill {
+		background-color: $color-pink;
+	}
+</style>

+ 755 - 0
subpkg/datalist/examReport.vue

@@ -0,0 +1,755 @@
+<template>
+	<view class="page-view">
+		<top-return color="#FFF"></top-return>
+		<!-- 背景 -->
+		<view class="bg1"></view>
+
+		<view class="flex-row">
+			<view class="flex-column" style="margin: 120rpx 0 0 50rpx;">
+				<view class="report-title">评测</view>
+				<view class="report-title">分析报告</view>
+				<view class="report-subtitle">{{examData[index].examInfo.name}}</view>
+			</view>
+			<view class="detail-image1" :style="{backgroundImage:`url(${image1})`}"></view>
+			<view class="detail-image2" :style="{backgroundImage:`url(${image2})`}"></view>
+		</view>
+
+
+		<view class="card-view">
+			<view class="card-item">
+				<view class="card-box">
+					<view class="card-image" :style="{backgroundImage:`url(${image3})`}"></view>
+					<view class="flex-column">
+						<view class="total-card-title">成绩总分:</view>
+						<view class="flex-row">
+							<view class="total-card-data">{{reportData.totalScore}}</view>
+							<view class="total-card-title" style="margin: 16rpx 0 0 6rpx;">分</view>
+						</view>
+					</view>
+				</view>
+				<view class="card-data">
+					<view class="flex-column" v-for="(item,i) in reportData.gradeData" :key="i">
+						<view class="YS-title">{{item.subject}}</view>
+						<view class="flex-baseline">
+							<view class="title">{{item.grade}}</view>
+							<view class="subtitle">/{{item.score}}</view>
+						</view>
+					</view>
+				</view>
+			</view>
+
+			<view class="card-item">
+				<view class="title-box">
+					<view class="title-tag"></view>
+					<view class="title">成绩对比</view>
+					<view class="subsection">
+						<u-subsection :list="contrastList" :current="contrastCurrent" @change="changeContrast"
+							activeColor="#FFF">
+						</u-subsection>
+					</view>
+				</view>
+				<view class="table-container">
+					<uni-table :loading="tableLoading">
+						<!-- 表头行 -->
+						<uni-tr>
+							<uni-th width="40" align="center">科目</uni-th>
+							<uni-th width="25" align="center">分数</uni-th>
+							<!-- <uni-th>名次</uni-th> -->
+							<uni-th width="25" align="center">平均分</uni-th>
+							<uni-th width="25" align="center">最高分</uni-th>
+							<uni-th width="25" align="center">名次</uni-th>
+						</uni-tr>
+						<uni-tr v-for="(item,index) in reportData.tableData" :key="index">
+							<uni-td width="40" align="center">
+								<view class="title">{{item.subject}}</view>
+							</uni-td>
+							<uni-td width="25" align="center">
+								<view class="data" :style="{color: item.grade > item.average ?'#23b46c':'#ff5959'}">
+									{{item.grade}}
+								</view>
+							</uni-td>
+							<uni-td width="25" align="center">
+								<view class="data" style="color: #909399;">{{item.average}}</view>
+							</uni-td>
+							<uni-td width="25" align="center">
+								<view class="data" style="color: #ff8caf;">{{item.top}}</view>
+							</uni-td>
+							<uni-td width="25" align="center">
+								<view class="data">
+									{{item.rank}}
+								</view>
+							</uni-td>
+						</uni-tr>
+					</uni-table>
+				</view>
+				<view class="msg-box">
+					<view class="flex-baseline">
+						<view class="subtitle">班级</view>
+						<view class="title">{{reportData.classNum}}</view>
+						<view class="subtitle">人</view>
+					</view>
+					<view class="flex-baseline">
+						<view class="subtitle">年级</view>
+						<view class="title">{{reportData.gradeNum}}</view>
+						<view class="subtitle">人</view>
+					</view>
+					<view class="flex-baseline">
+						<view class="subtitle">联考</view>
+						<view class="title">{{reportData.areaNum}}</view>
+						<view class="subtitle">人</view>
+					</view>
+				</view>
+			</view>
+
+			<view class="card-item">
+				<view class="title-box">
+					<view class="title-tag"></view>
+					<view class="title">成绩分布</view>
+					<view class="subsection">
+						<u-subsection :list="distributionList" :current="distributionCurrent"
+							@change="changeDistribution" activeColor="#FFF">
+						</u-subsection>
+					</view>
+				</view>
+				<view class="chart-box" style="height: 420rpx;">
+					<qiun-data-charts type="column" ontouch="true" :chartData="reportData.distributionChartData"
+						tooltipFormat="distributionColumn"
+						:opts="{legend:{show:false},padding:[20, 20, 20, 10],yAxis:{gridType: 'dash',dashLength: 10},extra:{column:{barBorderCircle: false ,barBorderRadius: [6,6,0,0]}}}" />
+				</view>
+				<view class="distribution-box">
+					<view class="segment-data">
+						<view class="text">孩子分段数</view>
+						<view class="text">{{reportData.distributionNum}}分</view>
+					</view>
+					<view class="sutdent-data">
+						<view class="data-item">
+							<view class="title-box">
+								<view class="title">班级学生数</view>
+							</view>
+							<view class="flex-baseline">
+								<view class="data">{{reportData.distributionData[0]}}</view>
+								<view class="unit">人</view>
+							</view>
+						</view>
+						<view class="data-item">
+							<view class="title-box">
+								<view class="title">年级学生数</view>
+							</view>
+							<view class="flex-baseline">
+								<view class="data">{{reportData.distributionData[1]}}</view>
+								<view class="unit">人</view>
+							</view>
+						</view>
+						<view class="data-item">
+							<view class="title-box">
+								<view class="title">联考学生数</view>
+							</view>
+							<view class="flex-baseline">
+								<view class="data">{{reportData.distributionData[2]}}</view>
+								<view class="unit">人</view>
+							</view>
+						</view>
+					</view>
+				</view>
+			</view>
+
+			<view class="card-item">
+				<view class="title-box">
+					<view class="title-tag"></view>
+					<view class="title">近期对比</view>
+				</view>
+				<view class="chart-box" style="height: 550rpx;">
+					<qiun-data-charts type="column" ontouch="true" :chartData="reportData.recentContrastChartData"
+						tooltipFormat='tooltipScore'
+						:opts="{padding:[-10, 20, 20, 10],yAxis:{gridType: 'dash',dashLength: 10},extra:{column:{barBorderCircle: false ,barBorderRadius: [6,6,0,0]}}}" />
+				</view>
+				<view class="cutting-line" />
+
+				<view class="title-box">
+					<view class="title-tag"></view>
+					<view class="title">诊断分析</view>
+				</view>
+				<view class="analysis-box">
+					<view class="flex-baseline">
+						<view class="subtitle">本次考试中</view>
+						<view class="title">{{advantage.name}}</view>
+						<view class="subtitle">得分率最高,是孩子优势科目;</view>
+					</view>
+					<view class="flex-baseline" style="margin-top: 20rpx;">
+						<view class="title" style="color: #ff5959;margin-left: 0;">{{disadvantage.name}}</view>
+						<view class="subtitle">相较其他科目</view>
+						<view class="title" style="color: #ff5959;">失分率最高</view>
+						<view class="subtitle">是劣势科目;</view>
+					</view>
+					<view class="flex-baseline" style="margin-top: 20rpx;">
+						<view class="subtitle">劣势科目失分率为</view>
+						<view class="title" style="color: #ff5959;">{{(1-disadvantage.score).toFixed(2)*100}}%</view>
+						<view class="subtitle">希望继续努力!</view>
+					</view>
+				</view>
+				<view class="subtitle" style="margin:30rpx;font-size: 26rpx;">#结果由系统维度分析得出,仅供参考#</view>
+				<view class="btn">
+					<view class="btn-text">获取提分方案</view>
+				</view>
+			</view>
+
+			<view class="card-item">
+				<view class="title-box">
+					<view class="title-tag"></view>
+					<view class="title">科目优劣</view>
+					<view class="subsection">
+						<u-subsection :list="meritsList" :current="meritsCurrent" @change="changeMerits"
+							activeColor="#FFF">
+						</u-subsection>
+					</view>
+				</view>
+				<view class="chart-box">
+					<qiun-data-charts type="radar" ontouch="true" :chartData="reportData.advantageChartData"
+						tooltipFormat="meritsRadar" />
+				</view>
+				<view class="cutting-line" />
+
+				<view class="title-box">
+					<view class="title-tag"></view>
+					<view class="title">偏科分析</view>
+				</view>
+
+				<view class="analysis-box">
+					<view class="flex-baseline">
+						<view class="subtitle">本次考试中</view>
+						<view class="title">{{advantage.name}}</view>
+						<view class="subtitle">得分率最高,是孩子优势科目;</view>
+					</view>
+					<view class="flex-baseline" style="margin-top: 20rpx;">
+						<view class="title" style="color: #ff5959;margin-left: 0;">{{disadvantage.name}}</view>
+						<view class="subtitle">相较其他科目</view>
+						<view class="title" style="color: #ff5959;">失分率最高</view>
+						<view class="subtitle">是劣势科目;</view>
+					</view>
+					<view class="flex-baseline" style="margin-top: 20rpx;">
+						<view class="subtitle">劣势科目失分率为</view>
+						<view class="title" style="color: #ff5959;">{{(1-disadvantage.score).toFixed(2)*100}}%</view>
+						<view class="subtitle">希望继续努力!</view>
+					</view>
+				</view>
+				<view class="subtitle" style="margin:30rpx;font-size: 26rpx;">#结果由系统维度分析得出,仅供参考#</view>
+				<view class="btn">
+					<view class="btn-text">获取提分方案</view>
+				</view>
+			</view>
+
+			<view class="card-item">
+				<view class="title-box">
+					<view class="title-tag"></view>
+					<view class="title">评测分析报告</view>
+				</view>
+				<view class="btn-box">
+					<view class="subbtn">
+						<view class="subbtn-text">下载报告</view>
+					</view>
+					<view class="subbtn">
+						<view class="subbtn-text">分享报告</view>
+					</view>
+				</view>
+			</view>
+
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex'
+	export default {
+		computed: {
+			...mapState('m_children', ['examData'])
+		},
+		data() {
+			return {
+				index: '',
+				reportData: {
+					totalScore: 525,
+					gradeData: [{
+						subject: '语文',
+						grade: 82,
+						score: 100,
+					}, {
+						subject: '数学',
+						grade: 94,
+						score: 100,
+					}, {
+						subject: '英语',
+						grade: 84,
+						score: 100,
+					}, {
+						subject: '科学',
+						grade: 78,
+						score: 100,
+					}, {
+						subject: '思品',
+						grade: 95,
+						score: 100,
+					}, {
+						subject: '体育',
+						grade: 92,
+						score: 100,
+					}],
+					tableData: [{
+							subject: '总分',
+							grade: 525,
+							average: 499,
+							top: 521,
+							rank: 5
+						},
+						{
+							subject: '语文',
+							grade: 83,
+							average: 80,
+							top: 92,
+							rank: 9
+						},
+						{
+							subject: '数学',
+							grade: 93,
+							average: 84,
+							top: 99,
+							rank: 6
+						},
+						{
+							subject: '外语',
+							grade: 92,
+							average: 87,
+							top: 96,
+							rank: 4
+						},
+						{
+							subject: '思品',
+							grade: 80,
+							average: 83,
+							top: 92,
+							rank: 3
+						},
+						{
+							subject: '体育',
+							grade: 99,
+							average: 87,
+							top: 99,
+							rank: 1
+						},
+						{
+							subject: '科学',
+							grade: 93,
+							average: 89,
+							top: 96,
+							rank: 3
+						}
+					],
+					classNum: 55,
+					gradeNum: 1200,
+					areaNum: 16000,
+					distributionChartData: {
+						"categories": ["0-100", "100-200", "200-300", "300-400", "400-500", "500-600", "600-700"],
+						"series": [{
+								"name": "年级学生数",
+								"data": [7, 15, 72, 252, 333, 243, 18]
+							},
+							{
+								"name": "班级学生数",
+								"data": [1, 5, 12, 23, 22, 7, 1]
+							}
+						]
+					},
+					distributionNum: "500-600",
+					distributionData: [12, 130, 333],
+					advantageChartData: {
+						"categories": ["语文", "数学", "英语", "科学", "思品", "体育"],
+						"series": [{
+								"name": "个人得分率",
+								"data": [82, 94, 84, 78, 95, 92]
+							},
+							{
+								"name": "平均得分率",
+								"data": [88, 67, 90, 82, 75, 81]
+							},
+							{
+								"name": "最高得分率",
+								"data": [96, 92, 94, 91, 89, 90]
+							}
+						]
+					},
+					recentContrastChartData: {
+						"categories": ["语文", "数学", "英语", "科学", "思品", "体育"],
+						series: [{
+								name: "当前测验成绩",
+								data: [82, 94, 84, 78, 95, 92]
+							},
+							{
+								name: "上次测验成绩",
+								data: [88, 84, 97, 92, 89, 93]
+							}
+						],
+					}
+				},
+				contrastList: ['班级', '年级', '联考'],
+				contrastCurrent: 0,
+				distributionList: ['校级', '联考'],
+				distributionCurrent: 0,
+				meritsList: ['班级', '年级', '联考'],
+				meritsCurrent: 0,
+				tableLoading: false,
+				advantage: '',
+				disadvantage: '',
+				image1: 'https://ouch-cdn2.icons8.com/PvGwCISfYx-NAQwl4UsdY2QXtMMiNDB6LllqLZ4jGoA/rs:fit:367:456/czM6Ly9pY29uczgu/b3VjaC1wcm9kLmFz/c2V0cy9wbmcvNzg1/LzhiM2MwZWU2LWFl/ODMtNDM2Mi05MGQy/LTBmMDk0N2M4N2E1/OC5wbmc.png',
+				image2: 'https://ouch-cdn2.icons8.com/I-PEjM-V1LXrgVE1_yaPi7LY2XrgFXgKmEvBD3r1h_Y/rs:fit:484:456/czM6Ly9pY29uczgu/b3VjaC1wcm9kLmFz/c2V0cy9wbmcvMzcy/LzA0ZDY3Y2NlLTM3/YTUtNGE3OC1iZTVi/LTY4MzgyYTQ2YmUz/Zi5wbmc.png',
+				image3: 'https://cdn-icons-png.flaticon.com/512/4524/4524478.png',
+			};
+		},
+		onLoad(param) {
+			this.index = param.index
+			this.getAnalysisData()
+		},
+		methods: {
+			changeContrast(e) {
+				this.contrastCurrent = e
+			},
+			changeDistribution(e) {
+				this.distributionCurrent = e
+			},
+			changeMerits(e) {
+				this.meritsCurrent = e
+			},
+			getAnalysisData() {
+				let advantage = {
+					name: '',
+					score: 0
+				}
+				let disadvantage = {
+					name: '',
+					score: 1
+				}
+				this.reportData.gradeData.forEach((item, index) => {
+					if (item.grade / item.score > advantage.score) {
+						advantage.score = item.grade / item.score
+						advantage.name = item.subject
+					}
+					if (item.grade / item.score < disadvantage.score) {
+						disadvantage.score = item.grade / item.score
+						disadvantage.name = item.subject
+					}
+				})
+				this.advantage = advantage
+				this.disadvantage = disadvantage
+			}
+		},
+	}
+</script>
+
+<style lang="scss">
+	@import 'data_pages.scss';
+	@import 'top_info.scss';
+
+	.bg1 {
+		position: fixed;
+		width: 100%;
+		height: 1200rpx;
+		background-size: 100%;
+		background-repeat: no-repeat;
+		background-image: linear-gradient(to top, #f3f4f9, #ff8caf);
+	}
+
+	.detail-image1 {
+		position: absolute;
+		top: 150rpx;
+		left: 560rpx;
+		width: 300rpx;
+		height: 350rpx;
+		background-size: 100%;
+		background-repeat: no-repeat;
+		z-index: 51;
+	}
+
+	.detail-image2 {
+		position: absolute;
+		top: 200rpx;
+		left: 380rpx;
+		width: 300rpx;
+		height: 350rpx;
+		background-size: 100%;
+		background-repeat: no-repeat;
+		z-index: 50;
+	}
+
+	.card-item {
+		width: 100%;
+
+		.card-box {
+			display: flex;
+			padding: 20rpx 30rpx;
+			justify-content: space-around;
+			height: 180rpx;
+			border-radius: $border-radius;
+			background-color: #ff8caf;
+			opacity: 0.8;
+
+			.flex-column {
+				height: 100%;
+				justify-content: space-around;
+
+				.total-card-title {
+					line-height: 45rpx;
+					font-size: 45rpx;
+					color: #FFF;
+					font-family: YSfont;
+				}
+
+				.total-card-data {
+					color: #FFF;
+					font-size: 85rpx;
+					line-height: 45rpx;
+					font-family: YSfont;
+				}
+			}
+
+			.card-image {
+				position: relative;
+				top: -20rpx;
+				height: 220rpx;
+				width: 220rpx;
+				background-size: cover;
+				background-repeat: no-repeat;
+				z-index: 2;
+			}
+		}
+
+		.card-data {
+			padding: 20rpx;
+			display: flex;
+			flex-flow: row wrap;
+			justify-content: space-between;
+
+			.flex-column {
+				justify-content: space-around;
+				height: 120rpx;
+				margin: 20rpx 40rpx;
+
+				.title {
+					font-size: 40rpx;
+				}
+
+				.subtitle {
+					font-weight: 400;
+				}
+
+				.YS-title {
+					font-size: 40rpx;
+				}
+			}
+		}
+
+		.title-box {
+			display: flex;
+			align-items: center;
+			padding: 20rpx 0;
+
+			.title-tag {
+				margin-left: -10rpx;
+				margin-right: 20rpx;
+				height: 100%;
+				width: 20rpx;
+				border-radius: 100rpx;
+				background-color: #ff8caf;
+				z-index: 99;
+			}
+
+			.title {
+				font-size: 35rpx;
+				line-height: 50rpx;
+			}
+
+			.subsection {
+				width: 300rpx;
+				height: 100%;
+				margin: 0 30rpx 0 auto;
+
+				.u-subsection--button__bar {
+					background-color: #ff8caf !important;
+				}
+			}
+		}
+
+		.table-container {
+			margin-bottom: 20rpx;
+
+			.title {
+				line-height: 30rpx;
+				font-size: 30rpx;
+				color: $title;
+			}
+
+			.data {
+				line-height: 32rpx;
+				font-size: 32rpx;
+				font-weight: bold;
+				color: $title;
+			}
+		}
+
+		.msg-box {
+			margin: 0 20rpx 40rpx 20rpx;
+			padding: 20rpx;
+			display: flex;
+			border-radius: $border-radius;
+			justify-content: space-around;
+			background-color: #f3f4f9;
+
+			.title {
+				height: 32rpx;
+				line-height: 32rpx;
+				color: #ff8caf;
+				margin: 0 6rpx;
+			}
+		}
+
+		.chart-box {
+			height: 650rpx;
+		}
+
+		.distribution-box {
+			margin: 0 20rpx 40rpx 20rpx;
+			height: 150rpx;
+			display: flex;
+			border-radius: $border-radius;
+			background-color: #f3f4f9;
+			overflow: hidden;
+
+			.segment-data {
+				display: flex;
+				flex-direction: column;
+				align-items: center;
+				background-color: #ff8caf;
+				justify-content: space-around;
+				padding: 16rpx 0;
+				width: 30%;
+
+				.text {
+					font-size: 30rpx;
+					line-height: 30rpx;
+					color: #FFF;
+				}
+			}
+
+			.sutdent-data {
+				display: flex;
+				justify-content: space-around;
+				width: 70%;
+
+				.data-item {
+					display: flex;
+					flex-direction: column;
+					align-items: center;
+					width: 33%;
+					height: 100%;
+
+					.title-box {
+						display: flex;
+						align-items: center;
+						justify-content: center;
+						background-color: #ffe6ed;
+						height: 40rpx;
+						width: 101%;
+
+						.title {
+							line-height: 28rpx;
+							font-size: 28rpx;
+							font-weight: 400;
+							color: $title;
+						}
+					}
+
+					.data {
+						line-height: 70rpx;
+						font-size: 35rpx;
+						font-weight: bold;
+						color: #ff8caf;
+					}
+					.unit{
+						margin-left: 4rpx;
+						line-height: 26rpx;
+						font-size: 26rpx;
+						font-weight: bold;
+						color: $subtitle;
+					}
+				}
+			}
+		}
+
+		.cutting-line {
+			margin: 0 50rpx 20rpx 50rpx;
+			height: 1px;
+			background-color: #e6e7eb;
+		}
+
+		.analysis-box {
+			display: flex;
+			flex-direction: column;
+			margin: 10rpx 30rpx;
+
+			.title {
+				margin: 0 10rpx;
+				line-height: 35rpx;
+				font-size: 35rpx;
+				color: $color-pink;
+			}
+
+			.subtitle {
+				line-height: 30rpx;
+				font-size: 30rpx;
+				font-weight: 400;
+				color: $title;
+			}
+		}
+
+		.btn {
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			height: 80rpx;
+			margin: 0 30rpx 30rpx 30rpx;
+			background-color: #ff8caf;
+			border-radius: $border-radius;
+			box-shadow: $box-shadow;
+
+			.btn-text {
+				line-height: 38rpx;
+				font-size: 38rpx;
+				color: #FFF;
+				font-family: YSfont;
+			}
+		}
+
+		.btn-box {
+			display: flex;
+			justify-content: space-between;
+			margin: 10rpx 30rpx 30rpx 30rpx;
+
+			.subbtn {
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				height: 80rpx;
+				width: 46%;
+				border: 4rpx solid #ff8caf;
+				border-radius: $border-radius;
+				box-shadow: $box-shadow;
+
+				.subbtn-text {
+					line-height: 38rpx;
+					font-size: 38rpx;
+					color: #ff8caf;
+					font-family: YSfont;
+				}
+			}
+		}
+	}
+</style>

+ 131 - 0
subpkg/datalist/swapList.vue

@@ -0,0 +1,131 @@
+<template>
+	<view class="page-view">
+		<top-return :color="'#FFF'" text="活动列表"></top-return>
+
+		<view class="bg-box2"></view>
+
+		<!-- 页面标题内容 -->
+		<view class="top-box">
+			<view class="flex-baseline">
+				<view class="info-title" style="margin-left: 0;">{{dayTime.split('月')[0]}}</view>
+				<view class="info-subtitle">月</view>
+				<view class="info-title">{{dayTime.split('月')[1]}}</view>
+				<view class="info-subtitle">日</view>
+				<view class="info-subtitle" style="margin-left: 20rpx;">已完成</view>
+				<view class="info-title">{{value}}%</view>
+			</view>
+			<view class="flex-baseline">
+				<view class="data-subtitle" style="margin-left: 0;">当前共</view>
+				<view class="data-title">{{swapData.length}}</view>
+				<view class="data-subtitle">场活动</view>
+			</view>
+		</view>
+
+		<view class="card-view">
+			<view class="card-item" v-for="(item,index) in swapData" :key="index" @click="navSwapReport(index)">
+				<view class="card-title">
+					<view class="t-icon t-icon-swapfont"></view>
+					<view class="YS-title" style="font-size: 45rpx;">{{item.survey.name||item.vote.name}}</view>
+					<view
+						:class="[item.survey.progress === 'finish'||item.vote.progress === 'finish'?'t-icon t-icon-yiwancheng1':'t-icon t-icon-jinhangzhong-copy','state-seal']"
+						style="width: 55px;height: 55px;margin-left: auto;margin-right: -20rpx;"></view>
+				</view>
+				<view class="card-info">
+					<view class="flex-baseline">
+						<view class="info-type">布置老师:</view>
+						<view class="YS-title" style="margin-left: 10rpx;">
+							{{item.survey.creatorId||item.vote.creatorId}}</view>
+						<view class="info-type" style="margin-left: 20rpx;">截至时间:</view>
+						<view class="YS-title" style="margin-left: 10rpx;" v-if="item.survey">
+							{{$timeStampToTime(item.survey.endTime)}}</view>
+						<view class="YS-title" style="margin-left: 10rpx;" v-if="item.vote">
+							{{$timeStampToTime(item.vote.endTime)}}</view>
+					</view>
+					<view class="flex-row" style="margin-top: 20rpx;">
+						<u-parse class="YS-title" style="font-size: 30rpx;"
+							:content="item.survey.description||item.vote.description" :selectable="true"></u-parse>
+					</view>
+				</view>
+				<!-- 正文 -->
+				<view class="content-box">
+					<!-- 问卷 -->
+					<view class="title-box"
+						:style="{backgroundColor: item.survey.progress === 'finish'? '#23b46c': '#FF6D31' }"
+						v-if="item.survey">
+						<view class="title-text">问卷详情</view>
+					</view>
+					<view class="flex-row" style="justify-content: space-around;">
+						<view class="option-box"
+							:style="{backgroundColor: item.survey.progress === 'finish'? '#23b46c': '#FF6D31' }"
+							v-for="(option,i) in item.survey.answers[0]" :key="i">
+							<view class="content-subtitle">{{option}}</view>
+						</view>
+					</view>
+					<!-- 投票 -->
+					<view class="title-box"
+						:style="{backgroundColor: item.vote.progress === 'finish'? '#23b46c': '#FF6D31' }"
+						v-if="item.vote">
+						<view class="title-text">{{item.vote.secret ? '匿名投票':'普通投票'}}</view>
+					</view>
+					<view class="flex-row" style="justify-content: space-around;">
+						<view class="flex-column" style="align-items: center;" v-for="(option,j) in item.vote.options"
+							:key="j">
+							<u-parse class="title" style="font-size: 30rpx;margin-bottom: 15rpx;"
+								:content="option.value"></u-parse>
+							<view class="option-box"
+								:style="{backgroundColor: item.vote.progress === 'finish'? '#23b46c': '#FF6D31' }">
+								<view class="content-subtitle">{{option.code}}</view>
+							</view>
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState,
+		mapMutations
+	} from 'vuex'
+	export default {
+		computed: {
+			...mapState('m_children', ['swapData'])
+		},
+		data() {
+			return {
+				value: '',
+				dayTime: ''
+			}
+		},
+		onLoad(parameter) {
+			this.value = parameter.value
+			this.dayTime = (new Date()).format('M-d').replace('-', '月')
+		},
+		methods: {
+			fixNum(num) {
+				return num.toFixed(2)
+			},
+			navSwapReport(index) {
+				uni.navigateTo({
+					url: `/subpkg/datalist/swapReport?index=${index}`
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import 'data_pages.scss';
+	@import 'top_info.scss';
+	.option-box {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		width: 120rpx;
+		height: 50rpx;
+		border-radius: 10rpx;
+		padding: 5rpx;
+	}
+</style>

+ 72 - 0
subpkg/datalist/swapReport.vue

@@ -0,0 +1,72 @@
+<template>
+	<view class="page-view">
+		<top-return color="#FFF"></top-return>
+		<view class="flex-row">
+			<view class="flex-column" style="margin: 120rpx 0 0 50rpx;">
+				<view class="report-title">活动</view>
+				<view class="report-title">详情信息</view>
+				<view class="report-subtitle">{{swapData[index].survey.name||swapData[index].vote.name}}</view>
+			</view>
+			<view class="bg1"></view>
+			<view class="detail-image" :style="{backgroundImage:`url(${image})`}"></view>
+		</view>
+
+
+		<view class="card-view">
+			<view class="card-item" style="width: 100%;height: 2300rpx;opacity: 0.9;"></view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex'
+	export default {
+		computed: {
+			...mapState('m_children', ['swapData'])
+		},
+		data() {
+			return {
+				index: '',
+				image: 'https://ouch-cdn2.icons8.com/09Q_OTq1lYT1dr5CbEAtnG8KH-WNnh3fIkoN8Ehg8D8/rs:fit:256:277/czM6Ly9pY29uczgu/b3VjaC1wcm9kLmFz/c2V0cy9wbmcvODc3/LzUyODcyMGM0LTI0/MTEtNGU5MS04ZWM0/LTQ0ODVhOGQzMDcw/YS5wbmc.png'
+			};
+		},
+		onLoad(param) {
+			this.index = param.index
+		},
+		methods: {
+
+		},
+	}
+</script>
+
+<style lang="scss">
+	@import 'data_pages.scss';
+	@import 'top_info.scss';
+
+	.page-view {
+		background-color: $color-orange;
+	}
+
+	.bg1 {
+		position: absolute;
+		top: 200rpx;
+		left: 450rpx;
+		width: 430rpx;
+		height: 430rpx;
+		border-radius: 50%;
+		background-color: #ff9c5a;
+	}
+
+	.detail-image {
+		position: absolute;
+		top: 140rpx;
+		left: 430rpx;
+		width: 370rpx;
+		height: 350rpx;
+		background-size: 100%;
+		background-repeat: no-repeat;
+		z-index: 50;
+	}
+</style>

+ 40 - 0
subpkg/datalist/top_info.scss

@@ -0,0 +1,40 @@
+	.top-box {
+		display: flex;
+		flex-direction: column;
+		margin: 140rpx 0 0 50rpx;
+		height: 170rpx;
+		justify-content: space-around;
+	
+		.info-title {
+			margin-left: 10rpx;
+			font-size: 70rpx;
+			font-family: YSfont;
+			color: #FFF;
+			z-index: 2;
+			text-shadow: 1px -1px 0px #c0c0c0, 2px -2px 0px #b0b0b0, 1px -1px 0px #a0a0a0, 2px -2px 0px #909090;
+		}
+		.info-subtitle {
+			margin-left: 10rpx;
+			font-size: 40rpx;
+			font-family: YSfont;
+			color: #FFF;
+			z-index: 2;
+			text-shadow: 1px -1px 0px #c0c0c0, 2px -2px 0px #b0b0b0, 1px -1px 0px #a0a0a0, 2px -2px 0px #909090;
+		}
+	
+		.data-title {
+			font-size: 60rpx;
+			font-family: YSfont;
+			color: #FFF;
+			z-index: 2;
+			margin-left: 20rpx;
+		}
+		.data-subtitle {
+			font-size: 40rpx;
+			font-family: YSfont;
+			color: #FFF;
+			z-index: 2;
+			opacity: 0.8;
+			margin-left: 20rpx;
+		}
+	}

+ 128 - 0
subpkg/datalist/workList.vue

@@ -0,0 +1,128 @@
+<template>
+	<view class="page-view">
+		<top-return :color="'#FFF'" text="作业列表"></top-return>
+
+		<view class="bg-box2"></view>
+
+		<!-- 页面标题内容 -->
+		<view class="top-box">
+			<view class="flex-baseline">
+				<view class="info-title" style="margin-left: 0;">{{dayTime.split('月')[0]}}</view>
+				<view class="info-subtitle">月</view>
+				<view class="info-title">{{dayTime.split('月')[1]}}</view>
+				<view class="info-subtitle">日</view>
+				<view class="info-subtitle" style="margin-left: 20rpx;">已完成</view>
+				<view class="info-title">{{value}}%</view>
+			</view>
+			<view class="flex-baseline">
+				<view class="data-subtitle" style="margin-left: 0;">孩子今日共</view>
+				<view class="data-title">{{workData.length}}</view>
+				<view class="data-subtitle">份作业</view>
+			</view>
+		</view>
+
+		<view class="card-view">
+			<view class="card-item" v-for="(item,index) in workData" :key="index" @click="navWorkReport(index)">
+				<view class="card-title">
+					<view class="t-icon t-icon-workicon">
+					</view>
+					<view class="YS-title" style="font-size: 45rpx;">{{item.work.name}}</view>
+					<view
+						:class="[item.work.progress === 'finish'?'t-icon t-icon-yiwancheng1':'t-icon t-icon-jinhangzhong-copy1','state-seal']">
+					</view>
+				</view>
+				<view class="card-info">
+					<view class="flex-baseline">
+						<view class="info-type">布置老师:</view>
+						<view class="YS-title" style="margin-left: 10rpx;">{{item.work.creatorId}}</view>
+						<view class="info-type" style="margin-left: 20rpx;">截止时间:</view>
+						<view class="YS-title" style="margin-left: 10rpx;">
+							{{$timeStampToTime(item.work.endTime)}}
+						</view>
+					</view>
+					<view class="flex-row" style="margin-top: 20rpx;">
+						<u-parse class="YS-title" style="font-size: 30rpx;" :content="item.work.description"
+							:selectable="true"></u-parse>
+					</view>
+				</view>
+				<!-- 正文 -->
+				<view class="content-box">
+					<view class="title-box"
+						:style="{backgroundColor: item.work.progress === 'finish'? '#23b46c': '#f9c752' }">
+						<view class="title-text">作业附件</view>
+					</view>
+					<view v-for="(attachment,i) in item.work.attachments" :key="i">
+						<view class="attachment-box">
+							<view v-if="attachment.type == 'word'" class="t-icon t-icon-WORD"></view>
+							<view v-if="attachment.type == 'excel'" class="t-icon t-icon-ECEL"></view>
+							<view v-if="attachment.type == 'pdf'" class="t-icon t-icon-PDF"></view>
+							<view v-if="attachment.type == 'image'" class="t-icon t-icon-tupianziliao"></view>
+							<view v-if="attachment.type == 'ppt'" class="t-icon t-icon-PPT"></view>
+							<view class="attachment-info" style="margin-left: 20rpx;">
+								<view class="content-detail">文件名: {{attachment.name}}</view>
+								<view class="content-subtitle">文件大小: {{fixNum(attachment.size/8/1024)}}KB</view>
+							</view>
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState,
+		mapMutations
+	} from 'vuex'
+	export default {
+		computed: {
+			...mapState('m_children', ['workData'])
+		},
+		data() {
+			return {
+				value: '',
+				dayTime: ''
+			}
+		},
+		onLoad(parameter) {
+			this.value = parameter.value
+			this.dayTime = (new Date()).format('M-d').replace('-', '月')
+		},
+		methods: {
+			fixNum(num) {
+				return num.toFixed(2)
+			},
+			navWorkReport(index) {
+				uni.navigateTo({
+					url: `/subpkg/datalist/workReport?index=${index}`
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import 'data_pages.scss';
+	@import 'top_info.scss';
+
+	.attachment-box {
+		display: flex;
+		margin-bottom: 20rpx;
+		align-items: center;
+		padding: 6rpx 20rpx;
+		background-color: #FFF;
+		border-radius: 10rpx;
+
+		.t-icon {
+			width: 60rpx;
+			height: 60rpx;
+		}
+
+		.attachment-info {
+			display: flex;
+			flex-direction: column;
+			margin: 20rpx 50rpx;
+		}
+	}
+</style>

+ 475 - 0
subpkg/datalist/workReport.vue

@@ -0,0 +1,475 @@
+<template>
+	<view class="page-view">
+		<top-return color="#FFF"></top-return>
+		<!-- 背景 -->
+		<view class="bg1"></view>
+
+		<view class="flex-row">
+			<view class="flex-column" style="margin: 120rpx 0 0 50rpx;">
+				<view class="report-title">作业</view>
+				<view class="report-title">分析报告</view>
+				<view class="report-subtitle">{{workData[index].work.name}}</view>
+			</view>
+			<view class="detail-image" :style="{backgroundImage:`url(${image})`}"></view>
+		</view>
+
+		<view class="card-view">
+			<view class="card-item">
+				<view class="title-box">
+					<view class="title-tag"></view>
+					<view class="title">作业题详情</view>
+				</view>
+				<view class="table-container">
+					<uni-table :loading="tableLoading">
+						<!-- 表头行 -->
+						<uni-tr>
+							<uni-th width="46" align="center">题号</uni-th>
+							<uni-th width="12" align="center">题型</uni-th>
+							<!-- <uni-th>名次</uni-th> -->
+							<uni-th width="25" align="center">作答</uni-th>
+							<uni-th width="25" align="center">答案</uni-th>
+							<uni-th width="25" align="center">更多</uni-th>
+						</uni-tr>
+						<uni-tr v-for="(item,index) in reportData.tableData" :key="index" v-if="index < showTableNum">
+							<uni-td width="46" align="center">
+								<view class="data">{{item.name}}</view>
+							</uni-td>
+							<uni-td width="12" align="center">
+								<view class="subtitle">{{item.type}}</view>
+							</uni-td>
+							<uni-td width="25" align="center">
+								<view v-if="item.answer != '详情'" class="data"
+									:style="{color: item.answer === item.rightAnswer?'#23b46c':'#ff5959'}">
+									{{item.answer}}
+								</view>
+								<view class="table-box" v-if="item.answer === '详情'">
+									<view class="data" style="color: #4169E1">{{item.answer}}
+									</view>
+									<view class="t-icon t-icon-you"></view>
+								</view>
+							</uni-td>
+							<uni-td width="25" align="center">
+								<view v-if="item.rightAnswer != '详情'" class="data">
+									{{item.rightAnswer}}
+								</view>
+								<view class="table-box" v-if="item.rightAnswer === '详情'">
+									<view class="data" style="color: #4169E1">{{item.rightAnswer}}
+									</view>
+									<view class="t-icon t-icon-you"></view>
+								</view>
+							</uni-td>
+							<uni-td width="25" align="center">
+								<view class="table-box">
+									<view class="data" style="color: #4169E1;">解析</view>
+									<view class="t-icon t-icon-you"></view>
+								</view>
+							</uni-td>
+						</uni-tr>
+					</uni-table>
+				</view>
+				<view class="table-btn" v-if="reportData.tableData.length > showTableNum">
+					<view class="btn-text" @click="showTableList">展开全部作业题</view>
+					<u-icon name="arrow-down" color="#616367" @click="showTableList"></u-icon>
+				</view>
+			</view>
+
+			<view class="card-item">
+				<view class="title-box">
+					<view class="title-tag"></view>
+					<view class="title">知识点分析</view>
+					<view class="subsection">
+						<u-subsection :list="pointList" :current="pointCurrent" @change="changePoint"
+							activeColor="#FFF">
+						</u-subsection>
+					</view>
+				</view>
+				<view class="chart-box" style="height: 700rpx;width: 100%;">
+					<qiun-data-charts type="bar" ontouch="true" :chartData="reportData.pointChartData"
+						:opts="{legend:{position: 'top',float:'left'},xAxis:{format:'xAxisBar'}}" />
+				</view>
+				<view class="point-analyse">
+					<view class="flex-row">
+						<view class="analyse-box1">
+							<view class="analyse-title">知识点</view>
+						</view>
+						<view class="analyse-box2">
+							<view class="analyse-subtitle">掌握程度</view>
+						</view>
+					</view>
+					<view class="flex-row" v-for="(item,index) in reportData.pointData" :key="index">
+						<view class="analyse-box1" style="background-color: #f3f4f9;">
+							<view class="point-box">
+								<view class="point-title" style="margin-left: 30rpx;">{{item.pointName}}</view>
+							</view>
+						</view>
+						<view class="analyse-box2" style="background-color: #f3f4f9;">
+							<view class="circle" :style="{backgroundColor: item.level === '优秀掌握'?'#23b46c': item.level === '部分掌握'? '#f9c752':'#FF6D31'}"></view>
+							<view class="point-title">{{item.level}}</view>
+							<u-icon name="arrow-right" color="#616367" size="15"></u-icon>
+						</view>
+					</view>
+				</view>
+				
+				<view class="cutting-line"></view>
+				
+				<view class="title-box">
+					<view class="title-tag"></view>
+					<view class="title">诊断分析</view>
+				</view>
+				
+				<view class="analysis-box">
+							<view class="subtitle">本次作业孩子在:</view>
+							<view class="title" style="color: #ff5959;">[化学能与热能]、[反应速率与化学平衡]</view>
+							<view class="subtitle">等知识点上的掌握低于班级平均水平,请重点加强练习。</view>
+					</view>
+					<view class="subtitle" style="margin:30rpx;font-size: 26rpx;">#结果由系统维度分析得出,仅供参考#</view>
+					<view class="btn">
+						<view class="btn-text">获取练习方案</view>
+					</view>
+				</view>
+				<view class="card-item">
+					<view class="title-box">
+						<view class="title-tag"></view>
+						<view class="title">作业分趋势</view>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex'
+	export default {
+		computed: {
+			...mapState('m_children', ['workData'])
+		},
+		data() {
+			return {
+				index: '',
+				reportData: {
+					tableData: [{
+						name: '单选题01',
+						type: '单选',
+						answer: 'A',
+						rightAnswer: 'A',
+					}, {
+						name: '单选题02',
+						type: '单选',
+						answer: 'B',
+						rightAnswer: 'A',
+					}, {
+						name: '单选题03',
+						type: '单选',
+						answer: 'C',
+						rightAnswer: 'C',
+					}, {
+						name: '单选题04',
+						type: '单选',
+						answer: 'A',
+						rightAnswer: 'D',
+					}, {
+						name: '填空题01',
+						type: '填空',
+						answer: '123',
+						rightAnswer: '321',
+					}, {
+						name: '填空题02',
+						type: '填空',
+						answer: '正确',
+						rightAnswer: '错误',
+					}, {
+						name: '解答题01',
+						type: '解答',
+						answer: '详情',
+						rightAnswer: '详情',
+					}, {
+						name: '解答题02',
+						type: '解答',
+						answer: '详情',
+						rightAnswer: '详情',
+					}],
+					pointChartData: {
+						"categories": ["文案居中", "知识点信息", "知识点信息", "知识点信息", "知识点信息", "知识点信息"],
+						"series": [{
+								"name": "个人得分率",
+								"data": [80, 100, 55, 10, 100, 70]
+							},
+							{
+								"name": "班级得分率",
+								"data": [70, 90, 65, 50, 80, 50]
+							}
+						]
+					},
+					pointData: [{
+							pointName: '化学能与热能',
+							level: '未掌握'
+						},
+						{
+							pointName: '化学反应速率与化学平衡',
+							level: '未掌握'
+						},
+						{
+							pointName: '溶液中得离子平衡',
+							level: '部分掌握'
+						},
+						{
+							pointName: '化学能与电能',
+							level: '部分掌握'
+						},
+						{
+							pointName: '化学反应原理综合',
+							level: '部分掌握'
+						},
+						{
+							pointName: '原子结构与性质',
+							level: '优秀掌握'
+						},
+						{
+							pointName: '晶体结构与性质',
+							level: '优秀掌握'
+						}
+					]
+				},
+				showTableNum: 5,
+				tableLoading: false,
+				pointList: ['优势', '短板'],
+				pointCurrent: 0,
+				image: 'https://ouch-cdn2.icons8.com/L7XZ0sgjVoRcfTOPCIQaYDAjSFWSuLHiH__hrCVy_CQ/rs:fit:439:456/czM6Ly9pY29uczgu/b3VjaC1wcm9kLmFz/c2V0cy9wbmcvNTM2/L2M3ZmQyOTdiLTgz/ODEtNGQzYy1hNzk1/LWY1MmY3ZWUyMjIw/YS5wbmc.png'
+			};
+		},
+		onLoad(param) {
+			this.index = param.index
+		},
+		methods: {
+			showTableList() {
+				this.showTableNum = this.reportData.tableData.length
+			},
+			changePoint(e) {
+				this.pointCurrent = e
+			}
+		},
+	}
+</script>
+
+<style lang="scss">
+	@import 'data_pages.scss';
+	@import 'top_info.scss';
+
+	.bg1 {
+		position: fixed;
+		width: 100%;
+		height: 1200rpx;
+		background-size: 100%;
+		background-repeat: no-repeat;
+		background-image: linear-gradient(to top, #f3f4f9, #f9c752);
+	}
+
+	.detail-image {
+		position: absolute;
+		top: 140rpx;
+		left: 430rpx;
+		width: 330rpx;
+		height: 360rpx;
+		background-size: 100%; //背景图片自适应
+		background-repeat: no-repeat;
+		z-index: 50;
+	}
+
+	.card-item {
+		width: 100%;
+
+		.title-box {
+			display: flex;
+			align-items: center;
+			padding: 20rpx 0;
+
+			.title-tag {
+				margin-left: -10rpx;
+				margin-right: 20rpx;
+				height: 100%;
+				width: 20rpx;
+				border-radius: 100rpx;
+				background-color: #f9c752;
+				z-index: 99;
+			}
+
+			.title {
+				font-size: 35rpx;
+				line-height: 50rpx;
+			}
+
+			.subsection {
+				width: 300rpx;
+				height: 100%;
+				margin: 0 30rpx 0 auto;
+
+				.u-subsection--button__bar {
+					background-color: #f9c752 !important;
+				}
+			}
+		}
+
+		.table-container {
+			margin-bottom: 20rpx;
+
+			.uni-table-td {
+				padding: 26rpx 10rpx !important;
+			}
+
+			.table-box {
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				margin-right: -22rpx;
+			}
+
+			.data {
+				line-height: 28rpx;
+				font-size: 28rpx;
+				font-weight: bold;
+				color: $title;
+			}
+
+			.subtitle {
+				line-height: 24rpx;
+				font-size: 24rpx;
+				font-weight: bold;
+				color: $subtitle;
+			}
+
+			.t-icon {
+				width: 30rpx;
+				height: 30rpx;
+			}
+		}
+
+		.table-btn {
+			width: 100%;
+			height: 50rpx;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			margin-bottom: 40rpx;
+
+			.btn-text {
+				font-size: 26rpx;
+				font-weight: bold;
+				color: #616367;
+				margin-right: 10rpx;
+			}
+		}
+
+		.point-analyse {
+			margin: 0 20rpx 40rpx 20rpx;
+			border-radius: $border-radius;
+			display: flex;
+			flex-direction: column;
+			border-radius: $border-radius;
+			overflow: hidden;
+
+			.analyse-box1 {
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				background-color: #f9c752;
+				height: 80rpx;
+				width: 70%;
+				.point-box{
+					display: flex;
+					align-items: center;
+					width: 100%;
+					height: 100%;
+				}
+
+				.analyse-title {
+					line-height: 32rpx;
+					font-size: 32rpx;
+					font-weight: bold;
+					color: #FFF;
+				}
+
+				.point-title {
+					line-height: 30rpx;
+					font-size: 30rpx;
+					font-weight: bold;
+					color: #616367;
+				}
+			}
+
+			.analyse-box2 {
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				background-color: #f9edc6;
+				height: 80rpx;
+				width: 30%;
+				.circle{
+					height: 24rpx;
+					width: 24rpx;
+					border-radius: 50%;
+					margin-right: 10rpx;
+				}
+
+				.analyse-subtitle {
+					line-height: 32rpx;
+					font-size: 32rpx;
+					font-weight: bold;
+					color: $title;
+				}
+
+				.point-title {
+					line-height: 28rpx;
+					font-size: 28rpx;
+					font-weight: bold;
+					color: #616367;
+				}
+			}
+		}
+		.cutting-line {
+			margin: 0 50rpx 20rpx 50rpx;
+			height: 1px;
+			background-color: #e6e7eb;
+		}
+		
+		.analysis-box {
+			display: flex;
+			flex-direction: column;
+			margin: 10rpx 30rpx;
+		
+			.title {
+				margin: 10rpx;
+				line-height: 35rpx;
+				font-size: 35rpx;
+				color: $color-pink;
+			}
+		
+			.subtitle {
+				line-height: 30rpx;
+				font-size: 30rpx;
+				font-weight: 400;
+				color: $title;
+			}
+		}
+		
+		.btn {
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			height: 80rpx;
+			margin: 0 30rpx 30rpx 30rpx;
+			background-color: #f9c752;
+			border-radius: $border-radius;
+			box-shadow: $box-shadow;
+		
+			.btn-text {
+				line-height: 38rpx;
+				font-size: 38rpx;
+				color: #FFF;
+				font-family: YSfont;
+			}
+		}
+	}
+</style>

+ 670 - 0
subpkg/exam/examPractice.vue

@@ -0,0 +1,670 @@
+<template>
+	<view class="page-view">
+		<top-return text="评测练习"></top-return>
+
+		<view class="icon-view">
+			<view class="icon-card">
+				<view class="t-icon t-icon-naozhong1" style="margin-right: 10rpx;"></view>
+				<view class="time-title">练习时间</view>
+				<u-count-down :time="60 * 60 * 1000" format="mm:ss"></u-count-down>
+			</view>
+			<view class="icon-card" style="margin-left: auto;">
+				<view :class="signList.includes(curr)?'t-icon t-icon-ding-copy':'t-icon t-icon-ding'"
+					@click="addToSignList"></view>
+				<view :class="showNoteBox? 't-icon t-icon-bianji1-copy':'t-icon t-icon-bianji1'"
+					@click="showNoteBox = !showNoteBox"></view>
+				<view :class="answerSheet? 't-icon t-icon-cengji-copy':'t-icon t-icon-cengji'"
+					@click="answerSheet = !answerSheet" style="margin-right: 0;"></view>
+			</view>
+		</view>
+
+		<view class="note-view" catchtouchmove="true" v-if="showNoteBox">
+			<view class="note-box">
+				<th-autograph :is-download="false" canvas-id="autograph">
+				</th-autograph>
+			</view>
+		</view>
+
+		<swiper class="swiper-box" :style="{height: clientHeight?clientHeight+'px':'auto'}" :current="curr"
+			@change="setCurr">
+			<swiper-item v-for="(item,i) in practiceData" :key="i">
+				<scroll-view :style="{height: clientHeight?clientHeight+'px':'auto'}">
+					<view class="item-card" :id="'card' + i">
+						<view class="flex-baseline">
+							<view class="YS-title">{{examPractice[cardIndex].title}}{{examPractice[cardIndex].modality}}
+							</view>
+							<view class="title" style="color: #4169E1;margin-left: 10rpx;">{{i+1}}</view>
+							<view class="subtitle" style="margin: 0 10rpx;">/</view>
+							<view class="subtitle">{{examPractice[cardIndex].amount}}</view>
+							<view class="YS-title" style="margin-left: 10rpx;">题</view>
+						</view>
+
+						<view class="tag-fill" style="margin-top: 40rpx;">
+							<view class="tag-text">{{item.type}}</view>
+						</view>
+
+						<view class="content">{{item.content}}</view>
+
+						<view class="answer-container">
+							<view class="answer-box" v-for="(x,y) in item.options" :key="y">
+								<view :class="answerList[i].answer == x.option?'answer-tag-select':'answer-tag'"
+									@click="selectOption(i,y)">
+									<view class="tag-text">{{x.option}}</view>
+								</view>
+								<view class="answer-content" @click="selectOption(i,y)">{{x.answer}}</view>
+							</view>
+						</view>
+					</view>
+				</scroll-view>
+			</swiper-item>
+			<!-- 答题卡 -->
+			<swiper-item>
+				<scroll-view :style="{height: clientHeight?clientHeight+'px':'auto'}">
+					<view class="item-card">
+						<view class="tag-list">
+							<view :class="item.answer != ''?'answer-tag-select':'answer-tag'"
+								v-for="(item,index) in answerList" :key="index" @click="navTopic(index)"
+								style="margin: 40rpx 20rpx;">
+
+								<view class="sign-icon" v-if="signList.includes(index)">
+									<view class="t-icon t-icon-ding-copy"></view>
+								</view>
+
+								<view class="tag-text">{{item.index + 1}}</view>
+							</view>
+						</view>
+						<view class="btn">
+							<view class="btn-text">交卷</view>
+						</view>
+					</view>
+				</scroll-view>
+			</swiper-item>
+		</swiper>
+		<u-action-sheet :show="answerSheet" @close="answerSheet = false" title="答题卡" :round="6">
+			<view style="margin: 20rpx 50rpx;">
+				<view class="tag-list">
+					<view :class="item.answer != ''?'answer-tag-select':'answer-tag'" v-for="(item,index) in answerList"
+						:key="index" @click="navTopic(index)" style="margin: 40rpx 20rpx;">
+
+						<view class="sign-icon" v-if="signList.includes(index)">
+							<view class="t-icon t-icon-ding-copy"></view>
+						</view>
+
+						<view class="tag-text">{{item.index + 1}}</view>
+					</view>
+				</view>
+				<view class="btn">
+					<view class="btn-text">交卷</view>
+				</view>
+			</view>
+		</u-action-sheet>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex'
+	import thAutograph from "../../components/th-autograph/th-autograph.vue"
+	export default {
+		components: {
+			thAutograph
+		},
+		computed: {
+			...mapState('m_children', ['examPractice'])
+		},
+		watch: {
+			curr: {
+				handler(newValue) {
+					if (this.curr <= (this.practiceData.length - 1))
+						this.getSwiperHeight()
+				},
+				immediate: true
+			},
+		},
+		data() {
+			return {
+				cardIndex: '',
+				clientHeight: '',
+				curr: 0,
+				showNoteBox: false,
+				answerSheet: false,
+				signList: [],
+				answerList: '',
+				practiceData: [{
+						content: '题目内容一的外号对哦奥委会的卡号大家看上课进度吧,阿玛尼的卡乌诺迪克兰的三大我看啦到哪里扣篮代码是你',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					},
+					{
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。3192087jhcuyastgdjahkgsduyagwd',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					},
+					{
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。h217893y1jahsdbyugcjhzxbcytfu1231',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					},
+					{
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快32189371298hjahdsu。',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一dkajghcjxzncuktwiajkjbsuydgi2uyhqjkn'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三312897319hjkabcjhxz'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					},
+					{
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。2318209uasiohsdjkaxnczuiywa',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一123i7auhcjkzxgczx'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三31289dyasjkdhciuxcz'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					}, {
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。adnauiychkajnwyiujagdhjabyuczxg2',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					}, {
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					}, {
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					}, {
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					}, {
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					}, {
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					}, {
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					}, {
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					}, {
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					}, {
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					},
+				],
+			}
+		},
+		onLoad(param) {
+			this.cardIndex = param.index
+			this.getAnswerList()
+		},
+		methods: {
+			//生成自适应高度swiper
+			getSwiperHeight() {
+				let query = uni.createSelectorQuery().in(this)
+				query.select('#card' + this.curr).boundingClientRect(data => {
+					this.clientHeight = data.height + 40
+					console.log('swiper高度', this.clientHeight);
+				}).exec();
+			},
+			setCurr(e) {
+				let thisCurr = e.detail.current || 0;
+				this.curr = thisCurr;
+			},
+			//生成答题卡
+			getAnswerList() {
+				if (this.answerList === '') {
+					this.answerList = []
+					this.practiceData.forEach((item, index) => {
+						let answer = {
+							index: index,
+							answer: ''
+						}
+						this.answerList.push(answer)
+					})
+					console.log(this.answerList);
+				}
+			},
+			//选择选项
+			selectOption(i, y) {
+				this.answerList[i].answer = this.practiceData[i].options[y].option
+				if (this.curr <= (this.practiceData.length - 1)) {
+					setTimeout(() => {
+						this.curr = i + 1
+					}, 300);
+				}
+			},
+			//导航到题目
+			navTopic(index) {
+				this.curr = index
+				this.answerSheet = false
+			},
+			//标记题目
+			addToSignList() {
+				if(this.curr <= (this.practiceData.length - 1)){
+					if (this.signList.includes(this.curr)) {
+						this.signList = this.signList.filter(x => x != this.curr)
+					} else {
+						this.signList.push(this.curr)
+					}
+				}
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.icon-view {
+		margin: 120rpx 20rpx 0 20rpx;
+		display: flex;
+		align-items: center;
+
+		.icon-card {
+			display: flex;
+			align-items: center;
+			padding: 20rpx;
+			height: 50rpx;
+			border-radius: $border-radius;
+			background-color: #FFF;
+
+			.t-icon {
+				margin-right: 40rpx;
+				width: 50rpx;
+				height: 50rpx;
+			}
+
+			.time-title {
+				font-size: 30rpx;
+				line-height: 30rpx;
+				margin-right: 10rpx;
+			}
+
+			.u-count-down__text.data-v-463368ae {
+				line-height: 30rpx !important;
+			}
+		}
+	}
+
+	.item-card {
+		margin: 20rpx;
+		padding: 40rpx 40rpx 80rpx 40rpx;
+		border-radius: $border-radius;
+		background-color: #FFF;
+
+		.content {
+			margin-top: 20rpx;
+			line-height: 60rpx;
+			font-size: 35rpx;
+			color: $title;
+			word-break: break-all;
+		}
+
+		.YS-title {
+			line-height: 38rpx;
+			font-size: 38rpx;
+		}
+
+		.tag-fill {
+			background-color: #d8deff;
+			width: fit-content;
+			margin-left: 0;
+			padding: 6rpx 12rpx;
+
+			.tag-text {
+				font-size: 28rpx;
+				color: #4169E1;
+			}
+		}
+
+		.answer-container {
+			display: flex;
+			flex-direction: column;
+
+			.answer-box {
+				margin-top: 40rpx;
+				display: flex;
+				align-items: center;
+
+				.answer-content {
+					margin-left: 40rpx;
+					font-size: 35rpx;
+					line-height: 60rpx;
+					color: $title;
+					word-break: break-all;
+				}
+			}
+		}
+	}
+
+	.answer-tag {
+		display: flex;
+		flex-shrink: 0;
+		align-items: center;
+		justify-content: center;
+		height: 66rpx;
+		width: 66rpx;
+		border-radius: 50%;
+		border: 2rpx solid $subtitle;
+
+		.tag-text {
+			font-size: 35rpx;
+			line-height: 35rpx;
+			color: $subtitle;
+		}
+	}
+
+	.answer-tag-select {
+		display: flex;
+		flex-shrink: 0;
+		align-items: center;
+		justify-content: center;
+		height: 70rpx;
+		width: 70rpx;
+		border-radius: 50%;
+		background-color: #4169E1;
+
+		.tag-text {
+			font-size: 35rpx;
+			line-height: 35rpx;
+			color: #FFF;
+		}
+	}
+
+	.tag-list {
+		display: flex;
+		align-items: center;
+		align-content: flex-start;
+		justify-content: space-between;
+		flex-wrap: wrap;
+
+		.sign-icon {
+			position: relative;
+			left: 20rpx;
+			top: -60rpx;
+			width: 0rpx;
+			height: 0rpx;
+
+			.t-icon {
+				height: 50rpx;
+				width: 50rpx;
+			}
+		}
+	}
+
+	.btn {
+		margin: 40rpx 20rpx 0 20rpx;
+		height: 80rpx;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		background-color: #4169E1;
+		border-radius: 40rpx;
+
+		.btn-text {
+			color: #FFF;
+			line-height: 36rpx;
+			font-size: 36rpx;
+			font-family: YSfont;
+		}
+	}
+
+	.note-view {
+		width: 100%;
+		height: 550rpx;
+		margin: 20rpx 0 5rpx 0;
+
+		.note-box {
+			width: 710rpx;
+			height: 100%;
+			margin: 0 20rpx;
+			border-radius: $border-radius;
+			overflow: hidden;
+			background-color: #FFF;
+		}
+	}
+</style>

+ 41 - 0
subpkg/exam/gradelist_pages.scss

@@ -0,0 +1,41 @@
+	.chart-box{
+		width: 100%;
+		height: 550rpx;
+	}
+	.analysis-box {
+		padding: 20rpx 25rpx;
+		height: 100%;
+		display: flex;
+		flex-direction: column;
+		justify-content: space-around;
+		overflow: hidden;
+	}
+	.analysis-text {
+		font-size: 30rpx;
+		font-weight: bold;
+		color: #FFF;
+		z-index: 5;
+	}
+	
+	.analysis-data {
+		font-size: 50rpx;
+		color: #FFF;
+		font-family: YSfont;
+		z-index: 5;
+	}
+	
+	.icon-box {
+		width: 0rpx;
+		height: 0rpx;
+	
+		.t-icon {
+			position: relative;
+			top: -230rpx;
+			left: 160rpx;
+			width: 200rpx;
+			height: 200rpx;
+			z-index: 1;
+			background-repeat: no-repeat;
+			background-size: 100%;
+		}
+	}

+ 131 - 0
subpkg/exam/level.vue

@@ -0,0 +1,131 @@
+<template>
+	<view class="page-view">
+		<top-return color="#FFF" text="考试能力"></top-return>
+		<!-- 背景 -->
+		<view class="bg-box1"></view>
+		<!-- 头部学期信息 -->
+		<top-semester></top-semester>
+		<!-- 分析列表 -->
+		<view class="card-view">
+			<view class="card-item" style="background-color: #4169E1;height: 200rpx;">
+				<view class="analysis-box">
+					<view class="analysis-text">成绩波动对比</view>
+					<view class="flex-baseline">
+						<view class="analysis-data">{{mainExamUndulate>=quizExamUndulate?'小考':'大考'}}</view>
+						<view class="analysis-text" style="margin-left: 20rpx;">发挥稳定</view>
+					</view>
+				</view>
+				<view class="icon-box">
+					<view v-if="mainExamUndulate>=quizExamUndulate" class="t-icon t-icon-a-bianzu7"></view>
+					<view v-if="mainExamUndulate<quizExamUndulate" class="t-icon t-icon-a-bianzu6"></view>
+				</view>
+			</view>
+			<view class="card-item" style="background-color: #ff8caf;height: 200rpx;">
+				<view class="analysis-box">
+					<view class="analysis-text">得分能力对比</view>
+					<view class="flex-baseline">
+						<view class="analysis-data">{{avgMain>=avgquiz?'大考':'小考'}}</view>
+						<view class="analysis-text" style="margin-left: 20rpx;">得分能力强</view>
+					</view>
+				</view>
+				<view class="icon-box">
+					<view v-if="avgMain<avgquiz" class="t-icon t-icon-a-bianzu7"></view>
+					<view v-if="avgMain>=avgquiz" class="t-icon t-icon-a-bianzu6"></view>
+				</view>
+			</view>
+			<!-- 图表 -->
+			<view class="card-item" style="width: 100%;">
+				<view class="card-title">
+					<view class="front-tag"></view>
+					<view class="title">重要考试对比</view>
+				</view>
+				<view class="chart-box">
+					<qiun-data-charts type="column" ontouch="true" :chartData="examChartData.levelChartData[0]"
+						tooltipFormat='tooltipScoreShort' :canvas2d="true" canvasId="level_chart1" />
+				</view>
+			</view>
+			<view class="card-item" style="width: 100%;">
+				<view class="card-title">
+					<view class="front-tag"></view>
+					<view class="title">普通测验记录</view>
+				</view>
+				<view class="chart-box">
+					<qiun-data-charts type="column" ontouch="true" :chartData="examChartData.levelChartData[1]"
+						tooltipFormat='tooltipScoreShort' :canvas2d="true" canvasId="level_chart2" />
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex'
+	
+	export default {
+		computed: {
+			...mapState('m_chart', ['examChartData']),
+		},
+		data() {
+			return {
+				//成绩波动参数(标准差)
+				mainExamUndulate: 0,
+				quizExamUndulate: 0,
+				//大小考每次考试平均成绩
+				avgMain: 0,
+				avgquiz: 0,
+			}
+		},
+		onLoad() {
+			this.getExamUndulate()
+		},
+		methods: {
+			//成绩波动数据(标准差)
+			getExamUndulate(){
+				function arrSum(array) {
+					let cont = 0
+					for (let i = 0; i < array.length; i++) {
+						cont += array[i]
+					}
+					return cont;
+				}
+				const mainArr = []
+				const quizArr = []
+				//统计每次考试总成绩并存为数组
+				for (let item of this.examChartData.levelChartData[0].series) {
+					mainArr.push(arrSum(item.data))
+				}
+				for (let item of this.examChartData.levelChartData[1].series) {
+					quizArr.push(arrSum(item.data))
+				}
+				//大小考试平均成绩
+				this.avgMain = arrSum(mainArr) / mainArr.length
+				this.avgquiz = arrSum(quizArr) / quizArr.length
+				//标准差函数
+				function standardDeviation(arr) {
+					let length = arr.length;
+					let sum = arrSum(arr);
+					let avg = sum / length;
+					let temp = [];
+					for (let i = 0; i < length; i++) {
+				
+						let dev = (arr[i]) - avg; //计算数组元素与平均值的差
+				
+						temp[i] = Math.pow(dev, 2); //计算差的平方
+					}
+					let powSum = arrSum(temp); //差的平方和
+					let standardDeviation = parseFloat(Math.sqrt(powSum / length).toFixed(2)); //标准差
+					return standardDeviation
+				}
+				this.mainExamUndulate = standardDeviation(mainArr)
+				this.quizExamUndulate = standardDeviation(quizArr)
+			},
+			
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import 'gradelist_pages.scss';
+</style>

+ 143 - 0
subpkg/exam/rank.vue

@@ -0,0 +1,143 @@
+<template>
+	<view class="page-view">
+		<top-return color="#FFF" text="排行占比"></top-return>
+		<!-- 背景 -->
+		<view class="bg-box1"></view>
+		<!-- 头部学期信息 -->
+		<top-semester></top-semester>
+		<!-- 分析列表 -->
+		<view class="card-view">
+			<view class="card-item" v-for="(item,index) in analysisData" :key="index"
+				:style="{background: item.color,height: 200+ 'rpx'}">
+				<view class="analysis-box">
+					<view class="analysis-text">{{item.title}}</view>
+					<view class="flex-baseline">
+						<view class="analysis-data">{{item.data}}%</view>
+						<view class="analysis-text" style="margin-left: 20rpx;">的学生</view>
+					</view>
+				</view>
+				<view class="icon-box">
+					<view :class="item.data>=40?(item.data>=70?'t-icon t-icon-a-bianzu6':'t-icon t-icon-a-bianzu7'): 't-icon t-icon-a-bianzu8'"></view>
+				</view>
+			</view>
+			<!-- 图表 -->
+			<view class="card-item" style="width: 100%;">
+				<view class="card-title">
+					<view class="front-tag"></view>
+					<view class="title">总成绩排行对比</view>
+				</view>
+				<view class="chart-box">
+					<qiun-data-charts type="area" ontouch="true" :chartData="examChartData.rankChartData[0]"
+						tooltipFormat='subjectRankArea' :canvas2d="true" canvasId="ranking_chart1" />
+				</view>
+			</view>
+			
+			<view class="card-item" style="width: 100%;">
+				<view class="card-title">
+					<view class="front-tag"></view>
+					<view class="title">{{subjectCurrent}}排行对比</view>
+					<view class="flex-row" style="margin-left: auto;" @click="subjectPicker = true">
+						<text class="title" style="color: #4169E1;font-weight: 400;">{{subjectCurrent}}</text>
+						<view class="t-icon t-icon-xia"></view>
+					</view>
+				</view>
+				<view class="chart-box">
+					<qiun-data-charts type="area" ontouch="true" :chartData="examChartData.rankChartData[1]"
+						tooltipFormat='subjectRankArea' :canvas2d="true" canvasId="ranking_chart2" />
+				</view>
+			</view>
+			
+			<!-- 科目选择 -->
+			<u-picker :show="subjectPicker" :columns="subjectList" @confirm="subjectConfirm" @cancel="cancel">
+			</u-picker>
+		</view>
+	</view>
+</template>
+
+<script>
+	import MockData from '@/common/global_js/MockData.js'
+	import {
+		mapState,
+		mapMutations
+	} from 'vuex'
+	export default {
+		computed: {
+			...mapState('m_chart', ['examChartData','subjectExamData']),
+		},
+		watch: {
+			subjectCurrent: {
+				handler(newValue) {
+					let subjectChartData = this.mockData.find(x=>x.name.includes(newValue))
+					let temp = this.examChartData
+					temp.rankChartData[1] = subjectChartData
+					this.updateExamChartData(temp)
+				},
+				immediate: false
+			},
+		},
+		data() {
+			return {
+				mockData: MockData.rankData,
+				subjectPicker: false,
+				subjectCurrent: '',
+				subjectList: '',
+				//分析模块数据
+				analysisData: [{
+					title: '平均排行超年级',
+					data: '',
+					color: '#4169E1',
+				}, {
+					title: '平均排行超班级',
+					data: '',
+					color: '#ff8caf',
+				}],
+			}
+		},
+		onLoad() {
+			this.init()
+		},
+		methods: {
+			...mapMutations('m_chart',['updateExamChartData']),
+			init() {
+				this.getAnalysisData()
+				this.setChartOptions()
+			},
+			getAnalysisData() {
+				function arrSum(array) {
+					let cont = 0
+					for (let i = 0; i < array.length; i++) {
+						cont += array[i]
+					}
+					return cont;
+				}
+				//平均超班级
+				this.analysisData[1].data = parseInt(arrSum(this.examChartData.rankChartData[0].series[1].data) / this
+					.examChartData.rankChartData[0].series[1].data.length)
+				//平均超年级
+				this.analysisData[0].data = parseInt(arrSum(this.examChartData.rankChartData[0].series[0].data) / this
+					.examChartData.rankChartData[0].series[0].data.length)
+			},
+			//图表配置
+			setChartOptions(){
+				if (this.subjectList === '') {
+					let arr = []
+					arr.push(this.subjectExamData.subjectList)
+					this.subjectList = arr
+					if (this.subjectCurrent === '')
+						this.subjectCurrent = this.subjectList[0][0]
+				}
+			},
+			subjectConfirm(e){
+				this.subjectCurrent = e.value[0]
+				this.subjectPicker = false
+			},
+			cancel(){
+				this.subjectPicker = false
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import 'gradelist_pages.scss';
+</style>

+ 97 - 0
subpkg/exam/single.vue

@@ -0,0 +1,97 @@
+<template>
+	<view class="page-view">
+		<top-return color="#FFF" text="单次考试"></top-return>
+		<!-- 背景 -->
+		<view class="bg-box1"></view>
+		<!-- 头部学期信息 -->
+		<top-semester></top-semester>
+		<!-- 分析列表 -->
+		<view class="card-view">
+			<view class="card-item" v-for="(item,index) in analysisData" :key="index" :style="{background: item.color,height: 200+ 'rpx'}">
+				<view class="analysis-box">
+					<view class="analysis-text">{{item.title}}</view>
+					<view class="flex-baseline">
+						<view class="analysis-data">{{item.data/0.01}}%</view>
+						<view class="analysis-text" style="margin-left: 20rpx;">的学生</view>
+					</view>
+				</view>
+				<view class="icon-box">
+					<view :class="item.data>=0.4?(item.data>=0.7?'t-icon t-icon-a-bianzu6':'t-icon t-icon-a-bianzu7'): 't-icon t-icon-a-bianzu8'"></view>
+				</view>
+			</view>
+			<!-- 图表 -->
+
+			<view class="card-item" style="width: 100%;">
+				<view class="card-title">
+					<view class="front-tag"></view>
+					<view class="title">最近考试单科对比</view>
+				</view>
+				<view class="chart-box">
+					<qiun-data-charts type="column" ontouch="true" :chartData="examChartData.singleChartData[0]"
+						tooltipFormat='tooltipScore' />
+				</view>
+			</view>
+			<view class="card-item" style="width: 100%;">
+				<view class="card-title">
+					<view class="front-tag"></view>
+					<view class="title">最近单科平均对比</view>
+				</view>
+				<view class="chart-box">
+					<qiun-data-charts type="column" ontouch="true" :chartData="examChartData.singleChartData[1]"
+						tooltipFormat='tooltipScore' />
+				</view>
+			</view>
+			<view class="card-item" style="width: 100%;">
+				<view class="card-title">
+					<view class="front-tag"></view>
+					<view class="title">最近考试单科排行</view>
+				</view>
+				<view class="chart-box">
+					<qiun-data-charts type="column" ontouch="true" :chartData="examChartData.singleChartData[2]"
+						tooltipFormat='subjectRankColum' />
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex'
+	export default {
+		computed: {
+			...mapState('m_chart', ['examChartData']),
+		},
+		data() {
+			return {
+				//分析模块数据
+				analysisData: [{
+					title: '总成绩超过年级中',
+					data: '',
+					color: '#4169E1',
+				}, {
+					title: '总成绩超过班级中',
+					data: '',
+					color: '#ff8caf',
+				}],
+			}
+		},
+		onLoad() {
+			this.init()
+		},
+		methods: {
+			init() {
+				this.getAnalysisData()
+			},
+			getAnalysisData() {
+				this.analysisData[0].data = 0.53
+				this.analysisData[1].data = 0.72
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import 'gradelist_pages.scss';
+</style>

+ 99 - 0
subpkg/exam/subject.vue

@@ -0,0 +1,99 @@
+<template>
+	<view class="page-view">
+		<top-return color="#FFF" text="优劣科目"></top-return>
+		<!-- 背景 -->
+		<view class="bg-box1"></view>
+		<!-- 头部学期信息 -->
+		<top-semester></top-semester>
+		<!-- 分析列表 -->
+		<view class="card-view">
+			<view class="card-item" v-for="(item,index) in analysisData" :key="index"
+				:style="{background: item.color,height: 200+ 'rpx'}">
+				<view class="analysis-box">
+					<view class="flex-baseline">
+						<view class="analysis-text">{{item.title}}</view>
+						<view class="analysis-text" style="font-size: 40rpx; margin-left: 20rpx;"> {{item.data.name}}
+						</view>
+					</view>
+					<view class="flex-baseline">
+						<view class="analysis-data">{{item.data.value}}%</view>
+						<view class="analysis-text" style="margin-left: 20rpx;">得分率</view>
+					</view>
+				</view>
+				<view class="icon-box">
+					<view :class="item.data.value>=40?(item.data.value>=70?'t-icon t-icon-a-bianzu6':'t-icon t-icon-a-bianzu7'): 't-icon t-icon-a-bianzu8'"></view>
+				</view>
+			</view>
+			<!-- 图表 -->
+			<view class="card-item" style="width: 100%;">
+				<view class="card-title">
+					<view class="front-tag"></view>
+					<view class="title">最近考试得分率对比</view>
+				</view>
+				<view class="chart-box">
+					<qiun-data-charts type="rose" :chartData="examChartData.subjectChartData[0]" :tapLegend="true"
+						tooltipFormat='tooltipScoreShort' :canvas2d="true" canvasId="subject_chart1"/>
+				</view>
+			</view>
+
+			<view class="card-item" style="width: 100%;">
+				<view class="card-title">
+					<view class="front-tag"></view>
+					<view class="title">学期平均得分率对比</view>
+				</view>
+				<view class="chart-box">
+					<qiun-data-charts type="rose" :chartData="examChartData.subjectChartData[1]" :tapLegend="true"
+						tooltipFormat='tooltipScoreShort' :canvas2d="true" canvasId="subject_chart2"/>
+				</view>
+			</view>
+		</view>
+
+	</view>
+
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex'
+
+	export default {
+		computed: {
+			...mapState('m_chart', ['examChartData']),
+		},
+		data() {
+			return {
+				//分析模块数据
+				analysisData: [{
+					title: '优势科目',
+					data: '',
+					color: '#4169E1'
+				}, {
+					title: '劣势科目',
+					data: '',
+					color: '#ff8caf',
+				}]
+			}
+		},
+		onLoad() {
+			this.init()
+		},
+		methods: {
+			init() {
+				this.getAnalysisData()
+			},
+			getAnalysisData() {
+				//获取成绩最好科目
+				this.analysisData[0].data = this.examChartData.subjectChartData[1].series[0].data.reduce((pre, cur) => pre
+					.value > cur.value ? pre : cur)
+				//劣势科目
+				this.analysisData[1].data = this.examChartData.subjectChartData[1].series[0].data.reduce((pre, cur) => pre
+					.value < cur.value ? pre : cur)
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import 'gradelist_pages.scss';
+</style>

+ 274 - 0
subpkg/exam/total.vue

@@ -0,0 +1,274 @@
+<template>
+	<view class="page-view">
+		<top-return color="#FFF" text="成绩走势"></top-return>
+		<!-- 背景 -->
+		<view class="bg-box1"></view>
+		<!-- 头部学期信息 -->
+		<top-semester></top-semester>
+		<!-- 分析列表 -->
+		<view class="card-view">
+
+			<view class="card-item" style="background-color: #4169E1;height: 200rpx;">
+				<view class="analysis-box">
+					<view class="analysis-text">{{analysisData[0].title}}</view>
+
+					<view class="flex-baseline">
+						<view class="analysis-data" style="font-size: 44rpx;">{{totalSemAvg}}</view>
+						<view class="analysis-text" style="margin-right: 20rpx;font-size: 26rpx;">分</view>
+						<view class="analysis-text" style="font-size: 26rpx;" v-if="analysisData[0].data != 'btm'">超过
+						</view>
+						<view class="analysis-text" style="font-size: 26rpx;" v-if="analysisData[0].data === 'btm'">未超过
+						</view>
+					</view>
+
+					<view class="flex-baseline">
+						<view class="analysis-text">
+							{{analysisData[0].data === 'top' ? '班级和年级学期平均':(analysisData[0].data === 'midClass'? '班级学期平均分':(analysisData[0].data === 'midGrade'?'年级学期平均分':'班级和年级学期平均'))}}
+						</view>
+					</view>
+				</view>
+				<view class="icon-box">
+					<view v-if="analysisData[0].data==='top'" class="t-icon t-icon-a-bianzu6"></view>
+					<view v-if="analysisData[0].data==='midGrade'||analysisData[0].data === 'midClass'"
+						class="t-icon t-icon-a-bianzu7">
+					</view>
+					<view v-if="analysisData[0].data==='btm'" class="t-icon t-icon-a-bianzu8"></view>
+				</view>
+			</view>
+
+			<view class="card-item" style="background-color: #ff8caf;height: 200rpx;">
+				<view class="analysis-box">
+					<view class="analysis-text">{{analysisData[1].title}}</view>
+
+					<view class="flex-baseline">
+						<view class="analysis-data" style="font-size: 44rpx;">{{singleSemAvg}}</view>
+						<view class="analysis-text" style="margin-right: 20rpx;font-size: 26rpx;">分</view>
+						<view class="analysis-text" style="font-size: 26rpx;" v-if="analysisData[1].data != 'btm'">超过
+						</view>
+						<view class="analysis-text" style="font-size: 26rpx;" v-if="analysisData[1].data === 'btm'">未超过
+						</view>
+					</view>
+
+					<view class="flex-baseline">
+						<view class="analysis-text">
+							{{analysisData[1].data === 'top' ? '班级和年级学期平均':(analysisData[1].data === 'midClass'? '班级学期平均分':(analysisData[1].data === 'midGrade'?'年级学期平均分':'班级和年级学期平均'))}}
+						</view>
+					</view>
+				</view>
+				<view class="icon-box">
+					<view v-if="analysisData[1].data==='top'" class="t-icon t-icon-a-bianzu6"></view>
+					<view v-if="analysisData[1].data==='midGrade'||analysisData[1].data === 'midClass'"
+						class="t-icon t-icon-a-bianzu7">
+					</view>
+					<view v-if="analysisData[1].data==='btm'" class="t-icon t-icon-a-bianzu8"></view>
+				</view>
+			</view>
+
+			<!-- 总成绩对比 -->
+			<view class="card-item" style="width: 100%;">
+				<view class="card-title">
+					<view class="front-tag"></view>
+					<view class="title">总成绩趋势</view>
+					<view class="t-icon t-icon-tishi2" style="margin-left: auto;" @click="isShowHint = true"></view>
+				</view>
+				<view class="chart-box">
+					<qiun-data-charts type="area" ontouch="true" :chartData="examChartData.totalChartData[0]"
+						tooltipFormat='tooltipScore' :canvas2d="true" canvasId="total_chart1" />
+				</view>
+			</view>
+			<!-- 单科与平均对比 -->
+			<view class="card-item" style="width: 100%;">
+				<view class="card-title">
+					<view class="front-tag"></view>
+					<view class="title">单科成绩趋势</view>
+					<view class="flex-row" style="margin-left: auto;" @click="subjectPicker = true">
+						<text class="title" style="color: #4169E1;font-weight: 400;">{{subjectCurrent}}</text>
+						<view class="t-icon t-icon-xia"></view>
+					</view>
+				</view>
+				<view class="chart-box">
+					<qiun-data-charts type="area" ontouch="true" :chartData="examChartData.totalChartData[1]"
+						tooltipFormat='tooltipScore' :canvas2d="true" canvasId="total_chart2" />
+				</view>
+			</view>
+			<!-- 个人单科对比 -->
+			<view class="card-item" style="width: 100%;">
+				<view class="card-title">
+					<view class="front-tag"></view>
+					<view class="title">单科对比趋势</view>
+					<view class="flex-row" style="margin-left: auto;" @click="scoreTypePicker = true">
+						<text class="title" style="color: #4169E1;font-weight: 400;">{{scoreTypeCurrent}}</text>
+						<view class="t-icon t-icon-xia"></view>
+					</view>
+				</view>
+				<view class="chart-box" v-if="scoreTypeCurrent === '得分'">
+					<qiun-data-charts type="line" ontouch="true" :chartData="examChartData.totalChartData[2]"
+						tooltipFormat='tooltipScore' :canvas2d="true" canvasId="total_chart3" />
+				</view>
+				<view class="chart-box" v-if="scoreTypeCurrent === '得分率'">
+					<qiun-data-charts type="line" ontouch="true" :chartData="examChartData.totalChartData[2]"
+						tooltipFormat='tooltipScoreShort' :canvas2d="true" canvasId="total_chart4" />
+				</view>
+			</view>
+		</view>
+		<!-- 选择器 -->
+		<!-- 科目选择 -->
+		<u-picker :show="subjectPicker" :columns="subjectList" @confirm="subjectConfirm" @cancel="cancel" />
+		<!-- 模式选择 -->
+		<u-picker :show="scoreTypePicker" :columns="scoreTypeList" @confirm="scoreTypeConfirm" @cancel="cancel" />
+		<!-- 模态框 -->
+		<u-modal :content="content" title="数据图表的基础使用" :show="isShowHint" :zoom="false"
+			@confirm="() => isShowHint = false"></u-modal>
+
+	</view>
+</template>
+
+<script>
+	import MockData from '@/common/global_js/MockData.js'
+	import {
+		mapState,
+		mapMutations
+	} from 'vuex'
+	export default {
+		computed: {
+			...mapState('m_chart', ['examChartData', 'subjectExamData']),
+		},
+		watch: {
+			subjectCurrent: {
+				handler(newValue) {
+					let subjectChartData = this.mockData.find(x => x.series[0].name.includes(newValue))
+					let temp = this.examChartData
+					temp.totalChartData[1] = subjectChartData
+					this.updateExamChartData(temp)
+					this.chooseAnalysisSubject()
+				},
+				immediate: false
+			},
+		},
+		data() {
+			return {
+				mockData: MockData.subjectData,
+				//选择器显示
+				subjectPicker: false,
+				scoreTypePicker: false,
+				//选择器内容
+				subjectList: '',
+				scoreTypeList: [
+					['得分', '得分率']
+				],
+				//当前选中
+				subjectCurrent: '',
+				scoreTypeCurrent: '',
+				//分析模块数据
+				analysisData: [{
+					title: '学期平均总得分',
+					data: '',
+					color: '#4169E1',
+				}, {
+					title: '学期平均分',
+					data: '',
+					color: '#ff8caf',
+				}],
+				//学期平均总得分
+				totalSemAvg: '',
+				//单科学期平均得分
+				singleSemAvg: '',
+				isShowHint: false,
+				content: '点击图表展示详细内容\n点击上方数据名可以隐藏或显示数据\n信息过多可以试试左右滑动查看'
+			}
+		},
+		onLoad() {
+			this.init()
+		},
+		methods: {
+			...mapMutations('m_chart', ['updateExamChartData']),
+			init() {
+				this.setChartOptions()
+				this.getAnalysisData()
+			},
+			//获得分析数据
+			getAnalysisData() {
+				function arrSum(array) {
+					let cont = 0
+					for (let i = 0; i < array.length; i++) {
+						cont += array[i]
+					}
+					return cont;
+				}
+				let totalSemAvg = parseInt((arrSum(this.examChartData.totalChartData[0].series[0].data) / this
+					.examChartData.totalChartData[0].series[0].data.length).toFixed(0))
+				this.totalSemAvg = totalSemAvg
+				let classSemAvg = parseInt((arrSum(this.examChartData.totalChartData[0].series[1].data) / this
+					.examChartData.totalChartData[0].series[1].data.length).toFixed(0))
+				let gradeSemAvg = parseInt((arrSum(this.examChartData.totalChartData[0].series[2].data) / this
+					.examChartData.totalChartData[0].series[2].data.length).toFixed(0))
+				if (totalSemAvg > classSemAvg && totalSemAvg > gradeSemAvg) {
+					this.analysisData[0].data = 'top'
+				} else if (totalSemAvg > classSemAvg && totalSemAvg <= gradeSemAvg) {
+					this.analysisData[0].data = 'midClass'
+				} else if (totalSemAvg > gradeSemAvg && totalSemAvg <= classSemAvg) {
+					this.analysisData[0].data = 'midGrade'
+				} else {
+					this.analysisData[0].data = 'btm'
+				}
+			},
+			chooseAnalysisSubject() {
+				function arrSum(array) {
+					let cont = 0
+					for (let i = 0; i < array.length; i++) {
+						cont += array[i]
+					}
+					return cont;
+				}
+				this.analysisData[1].title = this.subjectCurrent + '学期平均分'
+				let singleSemAvg = parseInt((arrSum(this.examChartData.totalChartData[1].series[0].data) / this
+					.examChartData.totalChartData[1].series[0].data.length).toFixed(0))
+				this.singleSemAvg = singleSemAvg
+				let classSemSinAvg = parseInt((arrSum(this.examChartData.totalChartData[1].series[1].data) / this
+					.examChartData.totalChartData[1].series[1].data.length).toFixed(0))
+				let gradeSemSinAvg = parseInt((arrSum(this.examChartData.totalChartData[1].series[2].data) / this
+					.examChartData.totalChartData[1].series[2].data.length).toFixed(0))
+				if (singleSemAvg > classSemSinAvg && singleSemAvg > gradeSemSinAvg) {
+					this.analysisData[1].data = 'top'
+				} else if (singleSemAvg > classSemSinAvg && singleSemAvg <= gradeSemSinAvg) {
+					this.analysisData[1].data = 'midClass'
+				} else if (singleSemAvg > gradeSemSinAvg && singleSemAvg <= classSemSinAvg) {
+					this.analysisData[1].data = 'midGrade'
+				} else {
+					this.analysisData[1].data = 'btm'
+				}
+			},
+			//初始化选择器内容(图表配置)
+			setChartOptions() {
+				if (this.scoreTypeCurrent === '')
+					this.scoreTypeCurrent = this.scoreTypeList[0][0]
+				if (this.subjectList === '') {
+					let arr = []
+					arr.push(this.subjectExamData.subjectList)
+					this.subjectList = arr
+					this.subjectCurrent = this.subjectList[0][0]
+				} else {
+					this.subjectCurrent = this.subjectList[0][0]
+				}
+			},
+			//切换科目
+			subjectConfirm(e) {
+				this.subjectCurrent = e.value[0]
+				this.subjectPicker = false
+			},
+			//切换模式
+			scoreTypeConfirm(e) {
+				this.scoreTypeCurrent = e.value[0]
+				this.scoreTypePicker = false
+			},
+			cancel() {
+				this.subjectPicker = false
+				this.scoreTypePicker = false
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import 'gradelist_pages.scss';
+</style>

+ 286 - 0
subpkg/home/classList.vue

@@ -0,0 +1,286 @@
+<template>
+	<view class="page-view">
+		<top-return color="#FFF" text="课程详情"></top-return>
+		<!-- 背景 -->
+		<view class="bg-box2"></view>
+		<!-- 页面标题内容 -->
+		<view class="top-box">
+			<view class="flex-baseline">
+				<view class="info-title" style="margin-left: 0;">{{dayTime.split('月')[0]}}</view>
+				<view class="info-subtitle">月</view>
+				<view class="info-title">{{dayTime.split('月')[1]}}
+				</view>
+				<view class="info-subtitle">日</view>
+				<view class="info-title" style="margin-left: 20rpx;">{{weekTime}}</view>
+			</view>
+			<view class="flex-baseline">
+				<view class="data-subtitle" style="margin-left: 0;">孩子今日共</view>
+				<view class="data-title">
+					{{classList.length}}
+				</view>
+				<view class="data-subtitle">节课程</view>
+			</view>
+		</view>
+		<!-- 天数选择 -->
+		<scroll-view class="week-view" scroll-x="true">
+			<view style="margin-top:20rpx;">
+				<view v-for="(item,index) in weekList" :key="index"
+					:class="isactive == index ? 'week-item-select' : 'week-item' " @click='chooseDay(index,item)'>
+					<view class="item-box">
+						<view class="item-title">{{item.weekNum}}</view>
+						<view class="item-day">{{item.dayNum}}</view>
+						<view class="tag-fill" v-if="isactive == index">
+							<view class="tag-text" v-if="isactive == index && currentClassList.length != 0">
+								{{currentClassList.length}} 节课
+							</view>
+							<view class="tag-text" v-if="isactive == index && currentClassList.length === 0">无课程</view>
+						</view>
+					</view>
+				</view>
+			</view>
+		</scroll-view>
+
+		<!-- 课程表 -->
+		<view class="card-view">
+			<view class="card-item" style="width: 100%;">
+				<view class="card-title">
+					<view class="front-tag"></view>
+					<view class="title">{{weekList[isactive].weekNum}}课程表</view>
+				</view>
+				<view class="class-list">
+					<view class="class-item"
+						:style="{borderImage: index == current&& isactive == 0?'linear-gradient(to right, #4169E1, #FFF) 1': none}"
+						v-for="(item,index) in currentClassList" :key="index">
+						<view class="flex-row" style="justify-content: space-around;">
+							<view class="t-icon t-icon-shuji2"></view>
+							<view class="item-title"
+								:style="{color: index == current && isactive == 0?'#4169E1':'#303133'}">{{item.name}}
+							</view>
+							<view class="tag" style="margin: 0;">
+								<view class="tag-text">{{item.teacher}}</view>
+							</view>
+							<view class="item-subtitle"
+								:style="{color: index == current && isactive == 0?'#4169E1':'#909399',fontSize: 24 + 'rpx'}">
+								{{index == current && isactive == 0?'课程进行中':item.timeFrame}}</view>
+							<view class="item-title"
+								:style="{color: index == current && isactive == 0?'#4169E1':'#303133'}">{{item.time}}
+							</view>
+						</view>
+					</view>
+				</view>
+				<view class="image-box" v-if="!currentClassList">
+					<view class="detail-image1" :style="{backgroundImage:`url(${image1})`}"></view>
+					<view class="subtitle">当前选中日期孩子暂无课程</view>
+					<view class="subtitle" style="margin-top: 20rpx;">注意劳逸结合</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import MockData from '@/common/global_js/MockData.js'
+	import {
+		mapState
+	} from 'vuex'
+	export default {
+		computed: {
+			...mapState('m_children', ['classList'])
+		},
+		data() {
+			return {
+				dayTime: '',
+				weekTime: '',
+				isactive: 0,
+				weekList: [{
+					weekNum: '',
+					dayNum: '',
+				}, {
+					weekNum: '',
+					dayNum: '',
+				}, {
+					weekNum: '',
+					dayNum: '',
+				}, {
+					weekNum: '',
+					dayNum: '',
+				}, {
+					weekNum: '',
+					dayNum: '',
+				}, {
+					weekNum: '',
+					dayNum: '',
+				}, {
+					weekNum: '',
+					dayNum: '',
+				}],
+				currentClassList: '',
+				weekClassData: MockData.classData,
+				image1: 'https://ouch-cdn2.icons8.com/kO20yenejB3M-ElZUGZMtv3FCQ4fbFa7TbOKX5dGf0w/rs:fit:456:456/czM6Ly9pY29uczgu/b3VjaC1wcm9kLmFz/c2V0cy9zdmcvNDY4/LzU4OWMzZTZkLWQz/OTAtNGQ0My04NTgx/LTY4NDkzMGZiNWRk/ZC5zdmc.png',
+				current: '',
+			};
+		},
+		onLoad(parameter) {
+			this.getPageData()
+			this.current = parameter.index - 1
+		},
+		methods: {
+			getPageData() {
+				this.dayTime = (new Date()).format('M-d').replace('-', '月')
+				this.weekTime = "星期" + "日一二三四五六".charAt(new Date().getDay());
+				this.currentClassList = this.classList
+				// 课程选择查看列表
+				this.weekList.forEach(function(item, index) {
+					var dateTime = new Date();
+					dateTime = dateTime.setDate(dateTime.getDate() + index);
+					let weekDateStr = "周" + "日一二三四五六".charAt(new Date(dateTime).getDay());
+					item.weekNum = weekDateStr
+					// if (index === 0) {
+					// 	item.weekNum = '今日'
+					// }
+					item.dayNum = new Date(dateTime).format('d') + ' 号'
+				});
+			},
+			//选中日期
+			chooseDay(index, item) {
+				this.isactive = index
+				for (const key in this.weekClassData) {
+					if (key === item.weekNum) {
+						this.currentClassList = this.weekClassData[key]
+					}
+				}
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import '@/subpkg/datalist/top_info.scss';
+	.week-view {
+		white-space: nowrap;
+
+		.week-item {
+			display: inline-block;
+			vertical-align: top;
+			height: 140rpx;
+			width: 120rpx;
+			margin: 20rpx;
+			padding: 20rpx;
+			border-radius: $border-radius;
+			background-color: #FFF;
+
+			.item-box {
+				width: 100%;
+				height: 100%;
+				display: flex;
+				flex-direction: column;
+				align-items: center;
+				justify-content: space-around;
+
+				.item-title {
+					font-size: 30rpx;
+					color: #898b91;
+				}
+
+				.item-day {
+					font-size: 40rpx;
+					font-weight: bold;
+					color: #505155;
+				}
+			}
+		}
+
+		.week-item-select {
+			display: inline-block;
+			vertical-align: top;
+			height: 160rpx;
+			width: 140rpx;
+			margin: 20rpx;
+			padding: 20rpx;
+			border-radius: $border-radius;
+			background-color: #FFF;
+			border: 3px solid $title;
+
+			.item-box {
+				width: 100%;
+				height: 100%;
+				display: flex;
+				flex-direction: column;
+				align-items: center;
+				justify-content: space-between;
+
+				.tag-fill {
+					border-radius: 6rpx;
+					background-color: $title;
+					padding: 5rpx 20rpx;
+
+					.tag-text {
+						font-size: 28rpx;
+						color: #FFF;
+					}
+				}
+
+				.item-title {
+					font-size: 34rpx;
+					color: $title;
+				}
+
+				.item-day {
+					font-size: 50rpx;
+					font-weight: bold;
+					color: $title;
+				}
+			}
+		}
+	}
+
+	.class-list {
+		display: flex;
+		flex-direction: column;
+		justify-content: space-between;
+		margin: 0 30rpx 20rpx 30rpx;
+
+		.class-item {
+			display: flex;
+			flex-direction: column;
+			justify-content: space-around;
+			margin: 10rpx 0;
+			padding: 10rpx 0;
+			height: 100rpx;
+			border-bottom: 4rpx solid #f3f4f9;
+			border-top: 4rpx solid #f3f4f9;
+			border-image: linear-gradient(to right, #FFF, #d5d5d5) 1;
+
+			.item-title {
+				font-size: 32rpx;
+				font-weight: bold;
+				color: $title;
+			}
+
+			.item-subtitle {
+				font-size: 30rpx;
+				font-weight: bold;
+				color: $subtitle;
+				overflow: hidden;
+				text-overflow: ellipsis;
+				white-space: nowrap;
+			}
+		}
+	}
+
+	.image-box {
+		display: flex;
+		flex-direction: column;
+		height: 100%;
+		align-items: center;
+		margin-bottom: 70rpx;
+	}
+
+	.detail-image1 {
+		width: 500rpx;
+		height: 600rpx;
+		background-size: 100%;
+		background-repeat: no-repeat;
+		z-index: 51;
+	}
+</style>

+ 319 - 0
subpkg/home/clockStats.vue

@@ -0,0 +1,319 @@
+<template>
+	<view class="page-view">
+		<top-return text="打卡详情" color="#FFF"></top-return>
+		<!-- 背景 -->
+		<view class="bg-box2"></view>
+		<!-- 月统计卡片信息 -->
+		<view class="card-view" style="margin-top: 140rpx;">
+			<view class="card-item" style="width: 100%;">
+				<view class="card-title" style="margin:10rpx 0 0 10rpx;">
+					<view class="title">{{currentTodayData.month}}月 打卡汇总</view>
+				</view>
+				<view class="clock-stats">
+					<view class="flex-column" style="align-items: center;">
+						<view class="number" style="color: #4169E1;">{{isClockStats}}</view>
+						<view class="number-detail">打卡次数</view>
+					</view>
+					<view class="flex-column" style="align-items: center;">
+						<view class="number" style="color: #ff5959;">{{noClockStats}}</view>
+						<view class="number-detail">缺卡次数</view>
+					</view>
+					<view class="flex-column" style="align-items: center;">
+						<view class="number"
+							:style="{color: clockStatsQuality==='优秀'?'#4169E1':(clockStatsQuality === '较差'?'#ff5959':'#f9c752')}">
+							{{clockStatsQuality}}
+						</view>
+						<view class="number-detail">出勤质量</view>
+					</view>
+				</view>
+			</view>
+			<!-- 打卡记录日历 -->
+			<view class="card-item" style="width: 100%;">
+				<view class="calendar-container">
+					<zsyCalendar :sundayIndex="6" @chooseDate="chooseDate" @change="change" />
+				</view>
+				<view class="state-box">
+					<view class="state"
+						:style="{backgroundColor: clockState==='已打卡'?'#4169E1':(clockState === '未打卡'?'#ff5959':'#bebebe')}">
+						<view class="state-text">{{clockState}}</view>
+					</view>
+					<view class="msg-box">
+						<view class="flex">
+							<text class="msg-text" style="font-weight: normal;font-size: 28rpx;">打卡时间:</text>
+							<text class="msg-text">{{clockTime.replace('0','')}}</text>
+						</view>
+						<view class="flex">
+							<text class="msg-text" style="font-weight: normal;font-size: 28rpx;">出勤效率:</text>
+							<text class="msg-text"
+								:style="{color: clockQuality==='优秀'?'#4169E1':(clockQuality === '良好'?'#f9c752':'#3B4144')}">{{clockQuality}}</text>
+						</view>
+					</view>
+					<!-- 图片信息 -->
+					<view class="image" v-if="currentTodayData.isAttend === 1"
+						:style="{backgroundImage:`url(${imageWorkday})`}"></view>
+					<view class="image" v-if="currentTodayData.isAttend === 7"
+						:style="{backgroundImage:`url(${imageWeekend})`}"></view>
+					<view class="image" v-if="currentTodayData.isAttend === 0"
+						:style="{backgroundImage:`url(${imageNoAttend})`}"></view>
+					<view class="image" v-if="currentTodayData.isAttend === -1"
+						:style="{backgroundImage:`url(${imageNoArrive})`}"></view>
+				</view>
+			</view>
+		</view>
+
+	</view>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex'
+	import zsyCalendar from '@/components/z-calendar/zsy-calendar.vue'
+	export default {
+		name: 'Calendar',
+		components: {
+			zsyCalendar
+		},
+		computed: {
+			...mapState('m_children', ['clockData']),
+		},
+		data() {
+			return {
+				//月打卡统计数据
+				isClockStats: '',
+				noClockStats: '',
+				clockStatsQuality: '',
+				//日打卡数据
+				clockState: '',
+				clockTime: '',
+				clockQuality: '',
+				//日历月份
+				calendarMonth: '',
+				//点击当日信息
+				currentTodayData: '',
+				//控制事件参数
+				isFirst: false,
+				//当日时间参数
+				todayData: '',
+				//图片
+				imageWorkday: 'https://ouch-cdn2.icons8.com/z39mAYlsJUS2hKCBbkK_ktOIjma_qhkc5J0ANdyfiKU/rs:fit:912:912/czM6Ly9pY29uczgu/b3VjaC1wcm9kLmFz/c2V0cy9zdmcvMTA3/L2FlZjQ4NmM4LTAz/NTYtNGRhNS04ZWQ2/LTBhMGIzMzdhZjNm/Mi5zdmc.png',
+				imageWeekend: 'https://ouch-cdn2.icons8.com/NJDdGibHzZkGZzgqe55ESzJ6_BrcgHO2bkz_vFG6PoY/rs:fit:912:912/czM6Ly9pY29uczgu/b3VjaC1wcm9kLmFz/c2V0cy9zdmcvNTg2/L2RlMmJhZDI4LTAz/NTQtNDMwNS1hNmQ2/LTU3Y2Y1ODJjNjc3/YS5zdmc.png',
+				imageNoAttend: 'https://ouch-cdn2.icons8.com/ehPeP69ypvrLonk6YkqIzV_WfKM1G-Ls9J7PuZvxRr8/rs:fit:912:912/czM6Ly9pY29uczgu/b3VjaC1wcm9kLmFz/c2V0cy9zdmcvMzY3/L2QzZGNmODA5LTY3/ODUtNGFkOC1hOWVi/LWI4OWYyM2ZiMzNi/Yi5zdmc.png',
+				imageNoArrive: 'https://ouch-cdn2.icons8.com/WfSBIzy4iTGDtprvhW0wA2S8lPNRoqeZqvFsNbKsraw/rs:fit:912:912/czM6Ly9pY29uczgu/b3VjaC1wcm9kLmFz/c2V0cy9zdmcvODQ3/LzI1NDY1ZDdhLTVj/NDEtNGIzMy1iN2Q1/LTRhYjgwOGU2NDk5/OS5zdmc.png'
+			}
+		},
+		watch: {
+			calendarMonth() {
+				this.getClockStatsQuality()
+			}
+		},
+		onLoad() {
+			this.init()
+		},
+		methods: {
+			init() {
+				this.getClockStatsQuality()
+				this.getTodayAttendance()
+			},
+			//判断本月出勤质量
+			getClockStatsQuality() {
+				this.clockStatsQuality = this.noClockStats / 30 <= 0.1 ? '优秀' : (this.noClockStats / 30 <= 0.2 ? '良好' :
+					'较差')
+				if (this.noClockStats === '暂无' && this.isClockStats === '暂无') {
+					this.clockStatsQuality = '暂无'
+				}
+			},
+			//今日打卡
+			getTodayAttendance() {
+				//获得当前时间时间戳
+				let timeArr = (new Date()).format("yyyy-M-dd").split("-")
+				let val = this.clockData.filter(x => x.year == timeArr[0] && x.month == timeArr[1] && x.date == timeArr[2])
+				if (val.length === 0) {
+					//出勤状况
+					this.clockState = '未打卡',
+						//打卡时间
+						this.clockTime = '无记录',
+						//出勤质量
+						this.clockQuality = '无记录'
+				} else {
+					this.clockState = '已打卡'
+					this.clockTime = val[0].time
+					this.clockQuality = val[0].time <= '08:15' ? '优秀' : (val[0].time <= '08:25' ? '良好' : '较差')
+				}
+			},
+			//选择日期
+			chooseDate(dateInfo, dateIndex) {
+				if (dateInfo.isAttend === 1) {
+					this.clockState = '已打卡'
+					this.clockTime = this.clockData.filter(x => x.date === dateInfo.date && x.month === dateInfo
+						.month && x.year === x.year)[0].time
+					this.clockQuality = this.clockTime <= '08:15' ? '优秀' : (this.clockTime <= '08:25' ?
+						'良好' : '较差')
+				}
+				if (dateInfo.isAttend === 0) {
+					this.clockState = '未打卡'
+					this.clockTime = '无记录'
+					this.clockQuality = '无记录'
+				}
+				if (dateInfo.isAttend === -1) {
+					this.clockState = '时间未到'
+					this.clockTime = '无记录'
+					this.clockQuality = '无记录'
+				}
+				if (dateInfo.isAttend === 7) {
+					this.clockState = '周末休息'
+					this.clockTime = '无记录'
+					this.clockQuality = '无记录'
+				}
+			},
+			//选中日期改变回调
+			change(e) {
+				//存入当前时间
+				if (this.isFirst === false) {
+					this.todayData = e
+					this.isFirst = true
+				}
+				//点击当日信息
+				this.currentTodayData = e
+				console.log("日历点击",this.currentTodayData);
+				//日历月份
+				this.calendarMonth = e.month
+				//当前日历月份打卡数
+				this.isClockStats = this.clockData.filter(x => x.month === e.month && x.year === e.year).length
+				// 当前日历月天数
+				let monthDays = new Date(e.year, e.month, 0).getDate()
+				//在本年当前月之前
+				if (e.year === this.todayData.year && e.month < this.todayData.month) {
+					let weekendDates = 0
+					for (let i = 1; i <= monthDays; i++) {
+						if (new Date(`${e.year}-${e.month}-${i}`).getDay() === 0 ||
+							new Date(`${e.year}-${e.month}-${i}`).getDay() === 6) {
+							weekendDates++
+						}
+					}
+					//当前日历月份未打卡数
+					this.noClockStats = monthDays - this.isClockStats - weekendDates
+				}
+				//之前年份
+				if (e.year < this.todayData.year) {
+					let weekendDates = 0
+					for (let i = 1; i <= monthDays; i++) {
+						if (new Date(`${e.year}-${e.month}-${i}`).getDay() === 0 ||
+							new Date(`${e.year}-${e.month}-${i}`).getDay() === 6) {
+							weekendDates++
+						}
+					}
+					//当前日历月份未打卡数
+					this.noClockStats = monthDays - this.isClockStats - weekendDates
+				}
+				//在本月
+				if (e.year === this.todayData.year && e.month === this.todayData.month) {
+					let weekendDates = 0
+					for (let i = 1; i <= this.todayData.date; i++) {
+						if (new Date(`${e.year}-${e.month}-${i}`).getDay() === 0 ||
+							new Date(`${e.year}-${e.month}-${i}`).getDay() === 6) {
+							weekendDates++
+						}
+					}
+					this.noClockStats = this.todayData.date - this.isClockStats - weekendDates
+				}
+				//在本年当月之后
+				if (e.year === this.todayData.year && e.month > this.todayData.month) {
+					this.noClockStats = '暂无'
+					this.isClockStats = '暂无'
+				}
+				//之后年份
+				if (e.year > this.todayData.year) {
+					this.noClockStats = '暂无'
+					this.isClockStats = '暂无'
+				}
+			},
+			
+		}
+	}
+</script>
+
+<style lang="scss">
+	.number {
+		font-size: 50rpx;
+		font-weight: bold;
+		color: $title;
+	}
+
+	.number-detail {
+		margin-top: 10rpx;
+		font-size: 30rpx;
+		color: $subtitle;
+	}
+
+	.state-box {
+		display: flex;
+		align-items: center;
+		height: 200rpx;
+		width: 100%;
+
+		.state {
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			border-radius: 100%;
+			margin: 20rpx;
+			height: 150rpx;
+			width: 150rpx;
+
+			.state-text {
+				font-size: 32rpx;
+				font-weight: bold;
+				color: #FFF;
+			}
+		}
+
+		.msg-box {
+			display: flex;
+			flex-direction: column;
+			justify-content: space-around;
+			height: 150rpx;
+			width: auto;
+
+			.msg-text {
+				color: $title;
+				font-weight: bold;
+				font-size: 36rpx;
+				margin-left: 15rpx;
+			}
+		}
+	}
+
+	.calendar-container {
+		height: 100%;
+		width: 100%;
+		background-color: #FFF;
+		margin: 0 auto;
+		box-sizing: border-box;
+		border-radius: $border-radius;
+	}
+
+	.image {
+		margin-left: auto;
+		margin-right: 20rpx;
+		width: 200rpx;
+		height: 200rpx;
+		border-radius: $border-radius;
+		background-size: 100%;
+		background-repeat: no-repeat;
+	}
+	.box_tag{
+		margin-right: 20rpx;
+		height: 100%;
+		width: 10rpx;
+		background-color: $title;
+		z-index: 99;
+	}
+	.clock-stats{
+		display: flex;
+		align-items: center;
+		justify-content: space-around;
+		height: 180rpx;
+		margin-bottom: 20rpx;
+	}
+</style>

+ 11 - 0
subpkg/home/courseRecommend.vue

@@ -0,0 +1,11 @@
+<template>
+	<view>
+		<top-return text="课程推荐"></top-return>
+	</view>
+</template>
+
+<script>
+</script>
+
+<style>
+</style>

+ 211 - 0
subpkg/mine/childInfo.vue

@@ -0,0 +1,211 @@
+<template>
+	<view class="page-view" style="width: 100vw;height: 100vh;">
+		<top-return text="孩子名片" color="#FFF"></top-return>
+		<view class="detail-image"
+			:style="{backgroundImage:`linear-gradient(to top, #f3f4f9, rgba(255, 255, 255, 0) 60%),url(${image})`}"></view>
+		<!-- 孩子头部信息 -->
+		<view class="top-info">
+			<image class="avatar" :src="childInfo.gender==='M'?'/static/default_icons/boy_avatar.svg':childInfo.gender===null?'/static/default_icons/boy_avatar.svg':'/static/default_icons/girl_avatar.svg'"></image>
+			<view class="top-name">
+				<view class="flex-baseline">
+					<text class="name">{{childInfo.name}}</text>
+					<view class="tag-fill"
+						style="margin-left: 30rpx;">
+						<view class="t-icon t-icon-xueshengziliao"></view>
+						<view class="tag-text" style="color: #4169E1;font-size: 28rpx;">{{childInfo.gender===null?'性别保密':childInfo.gender==='M'?'男孩':'女孩'}}</view>
+					</view>
+				</view>
+				<view class="flex-row">
+					<view class="tag-fill">
+						<view class="t-icon t-icon-xuewei1"></view>
+						<view class="tag-text" style="color: #4169E1;font-size: 28rpx;">{{childInfo.periodName}}学段</view>
+					</view>
+					<view class="tag-fill"
+						style="margin-left: 10rpx;">
+						<view class="t-icon t-icon-nongyekeji2">
+						</view>
+						<view class="tag-text" style="color: #4169E1;font-size: 28rpx;">{{childInfo.stuYear}}入学</view>
+					</view>
+				</view>
+			</view>
+		</view>
+		<!-- 卡片信息 -->
+		<view class="main-card">
+			<view class="flex-row">
+				<view class="t-icon t-icon-biaoqian"></view>
+				<view class="flex-column">
+					<view class="subtitle">就读学校</view>
+					<view class="title" style="margin-top: 10rpx;">{{childInfo.schoolName}}</view>
+				</view>
+			</view>
+			<view class="flex-row" style="margin-top: 50rpx;">
+				<view class="t-icon t-icon-fenlei1"></view>
+				<view class="flex-column">
+					<view class="subtitle">所在班级</view>
+					<view class="title">{{childInfo.className}}</view>
+				</view>
+			</view>
+			<view class="flex-row" style="margin-top: 50rpx;">
+				<view class="t-icon t-icon-jiaoyu"></view>
+				<view class="flex-column">
+					<view class="subtitle">主任老师</view>
+					<view class="title">{{childInfo.teacherName}}</view>
+				</view>
+			</view>
+
+			<view class="card-view" style="margin-top: 40rpx;">
+				<view class="flex-column-box" style="margin:0 auto 0 -40rpx;">
+					<view class="column-title">勋章卡片</view>
+					<view class="bottom-tag"></view>
+				</view>
+			</view>
+
+			<u-avatar-group :urls="medals" size="40" gap="0.2"></u-avatar-group>
+		</view>
+
+	</view>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex'
+	export default {
+		computed: {
+			...mapState('m_parent', ['childrenData']),
+		},
+		data() {
+			return {
+				image: 'https://image.meiye.art/pic_1628493302098',
+				medals: [
+
+				],
+				childInfo: ''
+			};
+		},
+		onLoad(param) {
+			this.childInfo = this.childrenData[param.index]
+		},
+		methods: {
+			updateAvatar() {
+				uni.chooseImage({
+					count: 1, //默认1个图片
+					sourceType: ['album'], //从相册选择
+					success: function(res) {
+						console.log(JSON.stringify(res.tempFilePaths));
+					}
+				})
+			},
+
+
+		},
+	}
+</script>
+
+<style lang="scss">
+	.flex-column {
+		height: 80rpx;
+		justify-content: space-between;
+	}
+
+	.detail-image {
+		position: fixed;
+		width: 100%;
+		height: 800rpx;
+	}
+
+	.top-info {
+		display: flex;
+		align-items: center;
+		margin-top: 180rpx;
+
+		.avatar {
+			margin-left: 50rpx;
+			width: 140rpx;
+			height: 140rpx;
+			border-radius: 100%;
+			border: 6rpx solid #FFF;
+			box-shadow: 0 10rpx 20rpx rgba(0, 0, 0, 0.2);
+			z-index: 55;
+		}
+
+		.top-name {
+			margin-left: 50rpx;
+			height: 130rpx;
+			display: flex;
+			flex-direction: column;
+			justify-content: space-around;
+			font-weight: bold;
+
+			.name {
+				color: $title;
+				font-size: 45rpx;
+				font-weight: bold;
+				z-index: 55;
+			}
+			.t-icon{
+				width: 32rpx;
+				height: 32rpx;
+				margin-right: 5rpx;
+			}
+		}
+	}
+
+	.main-card {
+		display: flex;
+		flex-direction: column;
+		padding: 80rpx 80rpx 0 80rpx;
+		position: relative;
+		background-color: #FFF;
+		height: 100%;
+		top: 80rpx;
+		left: 50rpx;
+		border-radius: 50rpx;
+		border-bottom-left-radius: 0;
+		z-index: 55;
+
+		.title {
+			line-height: 32rpx;
+			font-size: 32rpx;
+			font-weight: 400;
+			color: $title;
+		}
+
+		.subtitle {
+			line-height: 28rpx;
+			font-size: 28rpx;
+			color: $subtitle;
+			font-weight: 400;
+		}
+
+		.t-icon {
+			margin-right: 30rpx;
+			width: 80rpx;
+			height: 80rpx;
+		}
+	}
+
+	.box_title {
+		line-height: 35rpx;
+		font-size: 35rpx;
+		font-weight: bold;
+		color: $title;
+	}
+
+	.flex-column-box {
+		display: flex;
+		flex-direction: column;
+
+		.column-title {
+			line-height: 35rpx;
+			font-size: 32rpx;
+			font-weight: bold;
+			color: $title;
+		}
+	}
+	.tag-fill{
+		background-color: #d8deff;
+		width:fit-content;
+		z-index: 99;
+	}
+</style>

+ 148 - 0
subpkg/mine/msgList.vue

@@ -0,0 +1,148 @@
+<template>
+	<view class="page-view">
+		<top-return :color="'#FFF'" text="个人通知"></top-return>
+		<view class="bg-box2"></view>
+		<view class="card-view" style="margin-top: 140rpx;">
+			<view class="card-item" style="width: 100%;" v-for="(item,index) in userData.msgList" :key="index">
+				<view class="card-title" style="margin-right: 10rpx;">
+					<view class="t-icon t-icon-tongzhihuotixing"></view>
+					<view class="title" style="margin-left: 20rpx;font-weight: 400;">{{item.title}}</view>
+					<view class="subtitle" style="margin-left: auto;font-size: 24rpx;">{{item.msgTime}}</view>
+				</view>
+				<view class="title" style="margin: 0 30rpx;font-size: 28rpx;">{{item.content}}</view>
+				<image class="msg-poster" :src="item.image" mode="scaleToFill"></image>
+			</view>
+		</view>
+		<view>
+			 <button type="btn" @click="openAuth()">
+				<view class="btn-text">发送消息</view>
+			</button>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState,
+		mapMutations
+	} from 'vuex';
+
+	export default {
+		computed: {
+			...mapState('m_parent', ['userData'])
+		},
+		data() {
+			return {
+				tmplIds: ['tmMsJJSh3bVhbCh34x15pTqNwPXIL52mk7r64Z8BnZs'],
+			};
+		},
+		onLoad() {
+			this.sendMsg()
+		},
+		methods: {
+			...mapMutations('m_parent', ['updateUserData']),
+			//删除信息
+			deleteMsg(index) {
+				let msgList = this.userData.msgList
+				let data = msgList.splice(index, 1)
+				this.updateUserData(data)
+			},
+			openAuth() {
+				let templateId = this.tmplIds[0]
+				uni.requestSubscribeMessage({
+					tmplIds: this.tmplIds,
+					success: res => {
+						console.log('确认按钮', res);
+						this.sendMsg()
+					}
+				})
+			},
+			// 获取access_token
+			getAccessToken() {
+				return new Promise((resolve, reject) => {
+					uni.request({
+						url: 'https://api.weixin.qq.com/cgi-bin/token',
+						data: {
+							appid: 'wx5705da8747c77cfe',
+							secret: 'd5adf260a866ca43e74fbb40cec00799',
+							grant_type: 'client_credential'
+						},
+						success: (res) => {
+							console.log('返回access_token',res);
+							resolve(res.data.access_token)
+						},
+						fail: (err) => {
+							reject(err)
+						}
+					})
+				})
+			},
+
+			async sendMsg() {
+				const openid = uni.getStorageSync('token').miniappData.openid
+				const access_token = await this.getAccessToken();
+				uni.request({
+					url: 'https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=' +
+						access_token,
+					method: 'POST',
+					data: {
+						touser: openid,
+						template_id: this.tmplIds[0], // 第一个模板id
+						page: "pages/init/init", // 点击消息卡片跳转地址
+						data: { // data是模板内容,属性名为模板中所给,value值是需要传递的。
+							name1: {
+								value: '测试用户'
+							},
+							time2: {
+								value: '2022-07-11 20:33:44'
+							},
+							thing3: {
+								value: '测试测评'
+							},
+							number4: {
+								value: 123
+							}
+						}
+					},
+					success: (res) => {
+						console.log('发送模板消息',res);
+					}
+				})
+			},
+
+
+		}
+	}
+</script>
+
+<style lang="scss">
+	.msg-poster {
+		margin: 20rpx auto;
+		width: 94%;
+		height: 300rpx;
+		border-radius: 20rpx;
+	}
+
+	.t-icon {
+		width: 40rpx;
+		height: 40rpx;
+	}
+
+	.btn {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		height: 80rpx;
+		margin: 0 20rpx 20rpx 20rpx;
+		background-color: #4169E1;
+		border-radius: $border-radius;
+		box-shadow: $box-shadow;
+
+		.btn-text {
+			line-height: 38rpx;
+			font-size: 38rpx;
+			color: #FFF;
+			font-family: YSfont;
+		}
+	}
+</style>

+ 246 - 0
subpkg/mine/parentInfo.vue

@@ -0,0 +1,246 @@
+<template>
+	<view class="page-view" style="width: 100vw;height: 100vh;">
+		<top-return text="个人信息" color="#FFF"></top-return>
+		<view class="detail-image"
+			:style="{backgroundImage:`linear-gradient(to top, #f3f4f9, rgba(255, 255, 255, 0) 60%),url(${image})`}">
+		</view>
+		<!-- 个人头部信息 -->
+		<view class="top-info">
+			<image class="top-avatar" :src="parentInfo.avatarUrl"></image>
+			<view class="top-name">
+				<text class="name">{{parentInfo.nickName}}</text>
+				<view class="tag-fill">
+					<view class="t-icon t-icon-lianmengzhuanjia"></view>
+					<view class="tag-text" style="color: #4169E1;font-size: 28rpx;">{{phoneNumber}} 绑定手机</view>
+				</view>
+			</view>
+		</view>
+		<!-- 卡片信息 -->
+		<view class="main-card">
+			<view class="flex-row">
+				<view class="t-icon t-icon-huangguan"></view>
+				<view class="flex-column">
+					<view class="subtitle">我的订阅</view>
+					<view class="title">{{userData.subscribeLevel}}</view>
+				</view>
+			</view>
+			<view class="flex-row" style="margin-top: 50rpx;">
+				<view class="t-icon t-icon-jiesuo"></view>
+				<view class="flex-column">
+					<view class="subtitle">订阅时间</view>
+					<view class="title">{{userData.subscribeTime}}</view>
+				</view>
+			</view>
+			<view class="flex-row" style="margin-top: 50rpx;">
+				<view class="t-icon t-icon-quanxian"></view>
+				<view class="flex-column">
+					<view class="subtitle">订阅权益</view>
+					<view class="title">{{userData.subscribePrivilege}}</view>
+				</view>
+			</view>
+
+			<view class="card-view" style="margin-top: 40rpx;">
+				<view class="flex-column-box" style="margin:0 auto 0 -40rpx;">
+					<view class="column-title">孩子名片</view>
+					<view class="bottom-tag"></view>
+				</view>
+			</view>
+
+			<view class="card-box">
+				<view class="card" v-for="(item,index) in childrenData" :key="index" @click="navChildInfo(index)">
+					<image class="avatar" :src="item.gender==='M'?'/static/default_icons/boy_avatar.svg':item.gender===null?'/static/default_icons/boy_avatar.svg':'/static/default_icons/girl_avatar.svg'"></image>
+					<view class="card-info">
+						<view class="flex-baseline">
+							<view class="YS-title">{{item.name}}</view>
+							<view class="card-title">{{item.periodName}}学段</view>
+						</view>
+						<view class="flex-row">
+							<view class="t-icon t-icon-xuewei1"></view>
+							<view class="card-subtitle">{{item.schoolName}}</view>
+							<view class="t-icon t-icon-zhengceguizhang2" style="margin-left: 20rpx;"></view>
+							<view class="card-subtitle">{{item.className}}</view>
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex'
+	export default {
+		computed: {
+			...mapState('m_parent', ['parentInfo', 'phoneNumber', 'userData', 'childrenData']),
+		},
+		data() {
+			return {
+				image: 'https://image.meiye.art/pic_1628493294944',
+			};
+		},
+		methods: {
+			//孩子名片
+			navChildInfo(index) {
+				uni.navigateTo({
+					url: `/subpkg/mine/childInfo?index=${index}`
+				})
+			},
+		},
+	}
+</script>
+
+<style lang="scss">
+	.flex-column {
+		display: flex;
+		flex-direction: column;
+		height: 80rpx;
+		justify-content: space-between;
+	}
+
+	.detail-image {
+		position: fixed;
+		width: 100%;
+		height: 800rpx;
+	}
+
+	.top-info {
+		display: flex;
+		align-items: center;
+		margin-top: 180rpx;
+
+		.top-avatar {
+			margin-left: 50rpx;
+			width: 140rpx;
+			height: 140rpx;
+			border-radius: 100%;
+			border: 6rpx solid #FFF;
+			box-shadow: 0 10rpx 20rpx rgba(0, 0, 0, 0.2);
+			z-index: 55;
+		}
+
+		.top-name {
+			margin-left: 50rpx;
+			height: 130rpx;
+			display: flex;
+			flex-direction: column;
+			justify-content: space-around;
+			font-weight: bold;
+
+			.name {
+				color: $title;
+				font-size: 45rpx;
+				font-weight: bold;
+				z-index: 55;
+			}
+
+			.t-icon {
+				width: 32rpx;
+				height: 32rpx;
+				margin-right: 5rpx;
+			}
+		}
+	}
+
+	.main-card {
+		display: flex;
+		flex-direction: column;
+		padding: 80rpx 80rpx 0 80rpx;
+		position: relative;
+		background-color: #FFF;
+		height: 100%;
+		top: 80rpx;
+		left: 50rpx;
+		border-radius: 50rpx;
+		border-bottom-left-radius: 0;
+		z-index: 55;
+
+		.title {
+			line-height: 32rpx;
+			font-size: 32rpx;
+			font-weight: 400;
+			color: $title;
+		}
+
+		.subtitle {
+			line-height: 28rpx;
+			font-size: 28rpx;
+			color: $subtitle;
+			font-weight: 400;
+		}
+
+		.t-icon {
+			margin-right: 30rpx;
+			width: 80rpx;
+			height: 80rpx;
+		}
+	}
+
+	.flex-column-box {
+		display: flex;
+		flex-direction: column;
+
+		.column-title {
+			line-height: 35rpx;
+			font-size: 32rpx;
+			font-weight: bold;
+			color: $title;
+		}
+	}
+
+	.card-box {
+		display: flex;
+		align-items: center;
+		flex-wrap: wrap; //元素换行
+
+		.card {
+			width: 100%;
+			margin: 10rpx 0 10rpx 0;
+			padding: 20rpx;
+			display: flex;
+			align-items: center;
+			border: 2rpx solid #f3f4f9;
+			background-color: #FFFFFF;
+			border-radius: $border-radius;
+			z-index: 99;
+
+			.card-title {
+				margin-left: 20rpx;
+				font-size: 28rpx;
+				color: $title;
+			}
+
+			.card-subtitle {
+				line-height: 26rpx;
+				font-size: 26rpx;
+				color: $subtitle;
+			}
+
+			.avatar {
+				width: 100rpx;
+				height: 100rpx;
+			}
+		}
+	}
+
+	.tag-fill {
+		background-color: #d8deff;
+		width: fit-content;
+		z-index: 99;
+	}
+
+	.card-info {
+		display: flex;
+		flex-direction: column;
+		margin-left: 30rpx;
+		height: 100rpx;
+		justify-content: space-around;
+
+		.t-icon {
+			width: 32rpx;
+			height: 32rpx;
+			margin-right: 5rpx;
+		}
+	}
+</style>

+ 464 - 0
subpkg/mine/subInfo.vue

@@ -0,0 +1,464 @@
+<template>
+	<view>
+		<top-return text="订阅中心" color="#FFF"></top-return>
+
+		<view class="bg1">
+			<view class="card">
+				<view class="flex-row">
+					<image class="avatar" :src="parentInfo.avatarUrl"></image>
+					<view class="flex-column" style="margin-left: 30rpx;justify-content: space-between;height: 100rpx;">
+						<view class="flex-row">
+							<view class="card-title">{{parentInfo.nickName}}</view>
+							<view class="subscribe-tag" style="margin-left: 30rpx;">
+								<view class="t-icon t-icon-huangguan1" style="margin-right: 2rpx;"></view>
+								<view class="subscribe-tag-text" style="margin-left: 2rpx;font-size: 28rpx;">
+									{{userData.subscribeLevel}}
+								</view>
+							</view>
+						</view>
+						<view class="card-subtitle">{{userData.subscribeTime}} 到期</view>
+					</view>
+				</view>
+
+				<view class="icon-box">
+					<view class="t-icon t-icon-huangguan1-copy"></view>
+					<view class="t-icon t-icon-huangguan1-copy"
+						style="margin-top: -132px;margin-left: -30rpx;width: 300rpx;height: 300rpx;opacity: 0.75;">
+					</view>
+					<view class="t-icon t-icon-huangguan1-copy"
+						style="margin-top: -107px;margin-left: 30rpx;width: 250rpx;height: 250rpx;opacity: 0.5;">
+					</view>
+					<view class="t-icon t-icon-huangguan1-copy"
+						style="margin-top: -82px;margin-left: 80rpx;width: 200rpx;height: 200rpx;opacity: 0.5;">
+					</view>
+				</view>
+			</view>
+		</view>
+		<view class="bg2"></view>
+
+		<view class="flex-row" style="margin: 370rpx 100rpx 0 100rpx;">
+			<view class="subscribe-tag" style="padding: 6rpx 12rpx;" @click="subscribeShow = true">
+				<view class="subscribe-tag-text" @click="subscribeShow = true">续费会员</view>
+			</view>
+			<view class="subscribe-tag" style="padding: 6rpx 12rpx;margin-left: 50rpx;" @click="subscribeShow = true">
+				<view class="subscribe-tag-text" @click="subscribeShow = true">升级会员</view>
+			</view>
+		</view>
+
+		<view class="sub-view">
+			<view class="flex-row">
+				<view class="subscribe-front-tag"></view>
+				<view class="title">基础版会员特权</view>
+			</view>
+
+			<view style="margin: 20rpx;">
+				<view class="flex-row" style="margin: 40rpx 0;">
+					<view class="t-icon t-icon-jiance"></view>
+					<view class="sub-detail-box">
+						<view class="sub-title">畅享成绩进阶分析</view>
+						<view class="sub-subtitle">全方位掌握孩子考试能力</view>
+					</view>
+				</view>
+				<view class="flex-row" style="margin: 40rpx 0;">
+					<view class="t-icon t-icon-renwu"></view>
+					<view class="sub-detail-box">
+						<view class="sub-title">测验作业内容早知道</view>
+						<view class="sub-subtitle">随时随地了解孩子学习表现</view>
+					</view>
+				</view>
+				<view class="flex-row" style="margin: 40rpx 0;">
+					<view class="t-icon t-icon-tishi"></view>
+					<view class="sub-detail-box">
+						<view class="sub-title">家校互动零距离</view>
+						<view class="sub-subtitle">记录孩子在校在家点点滴滴</view>
+					</view>
+				</view>
+			</view>
+
+			<view class="flex-row">
+				<view class="subscribe-front-tag"></view>
+				<view class="title">专业版会员特权</view>
+			</view>
+
+			<view style="margin: 20rpx;">
+				<view class="privilege-card">
+					<view class="t-icon t-icon-renzheng"></view>
+					<view class="sub-detail-box">
+						<view class="sub-title">敬请期待</view>
+						<view class="sub-subtitle">敬请期待</view>
+					</view>
+				</view>
+				<view class="privilege-card">
+					<view class="t-icon t-icon-erweima"></view>
+					<view class="sub-detail-box">
+						<view class="sub-title">敬请期待</view>
+						<view class="sub-subtitle">敬请期待</view>
+					</view>
+				</view>
+				<view class="privilege-card">
+					<view class="t-icon t-icon-dianzan"></view>
+					<view class="sub-detail-box">
+						<view class="sub-title">敬请期待</view>
+						<view class="sub-subtitle">敬请期待</view>
+					</view>
+				</view>
+			</view>
+		</view>
+
+		<u-action-sheet :show="subscribeShow" @close="subscribeShow = false" :round="10">
+			<view class="top-background"
+				:style="{backgroundImage:`linear-gradient(to top, #FFF, rgba(255, 255, 255, 0)),url(${image})`}">
+				<view class="background-title">会员套餐</view>
+				<view class="tag">
+					<view class="tag-text">更多优惠活动</view>
+					<u-icon name="arrow-right" color="#31343d"></u-icon>
+				</view>
+			</view>
+			<view class="pri-box">
+				<view v-for="(item,index) in priceBlock" :key="index"
+					:class="isactive == index ? 'price-select' : 'price-block' " @click='choosePrice(index)'>
+					<view class="pri-title">{{item.title}}</view>
+					<view class="flex-baseline">
+						<view class="price" style="font-size: 30rpx;margin-left: -15rpx;">¥</view>
+						<view class="price">{{item.price}}</view>
+					</view>
+					<view class="pri-subtitle">{{item.subtitle}}</view>
+				</view>
+			</view>
+			<view class="detail-subtitle">订阅即同意连续订阅服务协议、醍摩豆家长端会员服务协议</view>
+			<view class="detail-subtitle">购买前请仔细阅读上述相关协议</view>
+			<button class="btn">立即开通</button>
+			<view class="item-box">
+				<view class="detail-subtitle">使用条款</view>
+				<view class="detail-subtitle">|</view>
+				<view class="detail-subtitle">隐私政策</view>
+				<view class="detail-subtitle">|</view>
+				<view class="detail-subtitle">疑难解答</view>
+			</view>
+		</u-action-sheet>
+
+	</view>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex'
+	export default {
+		computed: {
+			...mapState('m_parent', ['userData', 'parentInfo', 'phoneNumber'])
+		},
+		data() {
+			return {
+				subscribeShow: false,
+				priceBlock: [{
+					title: '连续包月',
+					price: 15,
+					subtitle: '次月¥15续费可随时取消'
+				}, {
+					title: '连续包年',
+					price: 150,
+					subtitle: '次年¥150续费可随时取消'
+				}, {
+					title: '连续包季',
+					price: 40,
+					subtitle: '次季¥40续费可随时取消'
+				}],
+				isactive: 1,
+				image: 'https://image.meiye.art/pic_1632705853492qQO3MFUSDC-SNRS4re5uL'
+			};
+		},
+		onLoad() {
+
+		},
+		methods: {
+			choosePrice(index) {
+				this.isactive = index
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.bg1 {
+		position: fixed;
+		left: 50%;
+		right: 50%;
+		transform: translate(-50%, -50%);
+		width: 2300rpx;
+		height: 950rpx;
+		border-radius: 50%;
+		background-color: #797572;
+		background-image:
+			linear-gradient(-173deg, rgba(255, 255, 255, 0.20) 0%, #000000 100%),
+			linear-gradient(72deg, rgba(255, 255, 255, 0.25) 25%, rgba(0, 0, 0, 0.25) 100%),
+			radial-gradient(47% 102%, rgba(255, 255, 255, 0.50) 0%, rgba(21, 24, 32, 0.60) 120%);
+		background-blend-mode: multiply;
+		z-index: -1;
+		overflow: hidden;
+	}
+
+	.bg2 {
+		position: fixed;
+		left: 50%;
+		right: 50%;
+		transform: translate(-50%, -50%);
+		width: 2000rpx;
+		height: 1000rpx;
+		border-radius: 50%;
+		background-image: linear-gradient(90deg, #636667, #919394, #c2c4c4, #f6f6f6);
+		z-index: -2;
+	}
+
+	.card {
+		position: fixed;
+		left: 50%;
+		right: 50%;
+		transform: translate(-50%, -15%);
+		display: flex;
+		flex-direction: column;
+		padding: 50rpx;
+		margin-top: 700rpx;
+		height: 250rpx;
+		width: 580rpx;
+		border-radius: 30rpx;
+		background-image: linear-gradient(90deg, #ffc87e, #ffd192, #ffddae, #f5c592);
+		opacity: 0.95;
+		border: 2rpx solid #FFFFFF;
+		box-shadow: 4px -4px 10px #2b2b2b;
+		overflow: hidden;
+		z-index: 99;
+
+		.card-title {
+			font-size: 40rpx;
+			font-weight: bold;
+			color: #714c1b;
+			z-index: 99;
+		}
+
+		.card-subtitle {
+			font-size: 30rpx;
+			color: #714c1b;
+			z-index: 99;
+		}
+
+		.icon-box {
+			position: absolute;
+			display: flex;
+			flex-direction: column;
+			margin: -90rpx 0 0 320rpx;
+
+			.t-icon {
+				width: 350rpx;
+				height: 350rpx;
+			}
+		}
+	}
+
+	.avatar {
+		width: 92rpx;
+		height: 92rpx;
+		border-radius: 100%;
+		border: 2px solid #FFFFFF;
+	}
+
+	.subscribe-tag {
+		display: flex;
+		align-items: center;
+		border-radius: 6rpx;
+		padding: 4rpx 10rpx;
+		transform: skew(-5deg);
+		background: #2f3137;
+		z-index: 99;
+
+		.subscribe-tag-text {
+			font-size: 30rpx;
+			font-family: YSfont;
+			color: #d0a97e;
+			z-index: 99;
+		}
+
+		.t-icon {
+			width: 28rpx;
+			height: 28rpx;
+			margin-top: -2rpx;
+		}
+	}
+
+	.sub-view {
+		display: flex;
+		flex-direction: column;
+		margin: 120rpx 35rpx 20rpx 35rpx;
+
+		.sub-title {
+			line-height: 30rpx;
+			font-size: 30rpx;
+			color: $title;
+		}
+
+		.sub-subtitle {
+			line-height: 24rpx;
+			font-size: 24rpx;
+			color: $subtitle;
+		}
+
+		.sub-detail-box {
+			display: flex;
+			flex-direction: column;
+			margin-left: 30rpx;
+			height: 80rpx;
+			justify-content: space-around;
+		}
+
+		.t-icon {
+			width: 80rpx;
+			height: 80rpx;
+		}
+
+		.privilege-card {
+			display: flex;
+			align-items: center;
+			height: 100rpx;
+			width: 100%;
+			border-radius: $border-radius;
+			background-color: #FFF;
+			margin: 20rpx 0 20rpx -20rpx;
+			padding: 10rpx 20rpx;
+		}
+	}
+
+	.subscribe-front-tag {
+		margin-right: 20rpx;
+		height: 35rpx;
+		width: 10rpx;
+		background-image: linear-gradient(#ffc87e, #ffddae);
+		z-index: 99;
+	}
+
+	//弹出层
+	.top-background {
+		display: flex;
+		flex-direction: column;
+		width: 100%;
+		height: 300rpx;
+		border-top-left-radius: 20rpx;
+		border-top-right-radius: 20rpx;
+		background-size: 100%;
+		background-repeat: no-repeat;
+
+		.background-title {
+			font-size: 70rpx;
+			font-family: YSfont;
+			color: #FFF;
+			text-shadow: 1px -1px 0px #c0c0c0,
+				2px -2px 0px #b0b0b0,
+				1px -1px 0px #a0a0a0,
+				2px -2px 0px #909090;
+			margin: 50rpx auto 20rpx 50rpx;
+		}
+
+		.tag {
+			display: flex;
+			align-items: center;
+			justify-content: space-around;
+			margin: 20rpx 50rpx 50rpx 50rpx;
+			width: 200rpx;
+			border-radius: 6rpx;
+			border: 2px solid #31343d;
+			padding: 8rpx 16rpx;
+
+			.tag-text {
+				font-size: 28rpx;
+				font-weight: bold;
+				transform: skew(-10deg);
+				color: #31343d;
+			}
+		}
+	}
+
+	.price-select {
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: space-around;
+		padding: 30rpx;
+		width: 150rpx;
+		height: 200rpx;
+		border: 3px solid #d0a97e;
+		border-radius: $border-radius;
+
+		.pri-title {
+			font-size: 30rpx;
+			color: #d0a97e;
+		}
+
+		.pri-subtitle {
+			font-size: 24rpx;
+			color: $subtitle;
+		}
+
+		.price {
+			font-size: 50rpx;
+			font-weight: bold;
+			color: #d0a97e;
+		}
+	}
+
+	.price-block {
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: space-around;
+		padding: 30rpx;
+		width: 150rpx;
+		height: 200rpx;
+		border: 3px solid #31343d;
+		border-radius: $border-radius;
+
+		.pri-title {
+			font-size: 30rpx;
+			color: #31343d;
+		}
+
+		.pri-subtitle {
+			font-size: 24rpx;
+			color: $subtitle;
+		}
+
+		.price {
+			font-size: 50rpx;
+			font-weight: bold;
+			color: #31343d;
+		}
+	}
+
+	.detail-subtitle {
+		font-size: 24rpx;
+		color: $subtitle;
+	}
+
+	.btn {
+		margin-top: 20rpx;
+		line-height: 100rpx;
+		border-radius: $border-radius;
+		height: 100rpx;
+		width: 710rpx;
+		font-weight: bold;
+		font-size: 36rpx;
+		color: #d0a97e;
+		background-color: #31343d;
+		z-index: 99;
+	}
+	.pri-box{
+		margin: 20rpx;
+		display: flex;
+		justify-content: space-between;
+	}
+	.item-box{
+		display: flex;
+		align-items: center;
+		padding:10rpx 180rpx;
+		justify-content:space-between;
+		margin:20rpx 0;
+	}
+</style>

+ 108 - 0
subpkg/startup/guide.vue

@@ -0,0 +1,108 @@
+<template>
+	<view class="flex-column">
+		<!-- 标题 -->
+		<view class="top">
+			<view class="YS-title" style="color: #4169E1;">欢迎您的使用</view>
+			<view class="YS-subtitle">醍摩豆家长助您孩子成长</view>
+		</view>
+		<view class="detail-image" :style="{backgroundImage:`url(${image})`}"></view>
+		<button class="btn" plain="true" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">获取您的孩子信息</button>
+		<!-- 动画 -->
+		<view class="ocean"></view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState,
+		mapMutations
+	} from 'vuex'
+	//引入解密工具
+	import WXBizDataCrypt from "@/utils/WXBizDataCrypt.js";
+	export default {
+		computed: {
+			...mapState('m_parent', ['token', 'parentInfo'])
+		},
+		data() {
+			return {
+				image: 'https://image.meiye.art/pic_1631411821366jJzYRG2jdJOxwXZk_jz7o',
+				isClick: false
+			}
+		},
+		methods: {
+			...mapMutations('m_parent', ['updateChildrenData', 'updateUserData', 'updatePhoneNumber']),
+			//获取用户手机号
+			async getPhoneNumber(e) {
+				if (this.isClick === false) {
+					this.isClick = true
+					if (e.detail.errMsg !== "getPhoneNumber:ok") {
+						return uni.showToast({
+							title: '您已拒绝授权',
+							icon: 'error'
+						});
+					} else {
+						try {
+							if (this.token) {
+								let proof = await new WXBizDataCrypt('wx5705da8747c77cfe',
+									this.token.miniappData.session_key)
+								let numData = await proof.decryptData(e.detail.encryptedData, e.detail.iv)
+								this.updatePhoneNumber(numData.phoneNumber)
+								console.log(numData.phoneNumber);
+								//初始化App
+								// await this.$initStart(numData.phoneNumber)
+								this.$api.getChildrenInfo({
+									mobile: '17711533106'
+								}).then(res => {
+									console.log('返回数据', res);
+									this.updateChildrenData(res.data.guardian.students)
+								}).catch(err => {
+									uni.showToast({
+										title: '加载数据失败~',
+										icon: 'error',
+									})
+								})
+								this.$api.getUserData({
+									phoneNumber: numData.phoneNumber
+								}).then(res => {
+									console.log('返回数据', res);
+									this.updateUserData(res.data)
+								}).catch(err => {
+									uni.showToast({
+										title: '加载数据失败~',
+										icon: 'error',
+									})
+								})
+								uni.navigateTo({
+									url: '/subpkg/startup/options'
+								})
+							} else {
+								this.$logOut()
+								return uni.showToast({
+									title: '获取不到您的信息请重新登录',
+									icon: 'error'
+								});
+							}
+						} catch (e) {
+							this.$logOut()
+							return uni.showToast({
+								title: '身份验证已过期请重新登录',
+								icon: 'error'
+							});
+						}
+					}
+					this.isClick = false
+				}
+			},
+		},
+	}
+</script>
+
+<style lang="scss">
+	@import 'startup_pages.scss';
+
+	.detail-image {
+		height: 600rpx;
+		margin: 400rpx 0 0 0;
+		background-size: 100% 100%;
+	}
+</style>

+ 113 - 0
subpkg/startup/login.vue

@@ -0,0 +1,113 @@
+<template>
+	<view>
+		<!-- 登录 -->
+		<view class="content">
+			<view class="bg1"></view>
+			<view class="bg2"></view>
+			<view class="bg3"></view>
+			<view class="top">
+				<text class="YS-title">请登录</text>
+				<text class="YS-subtitle">醍摩豆家长端</text>
+			</view>
+
+			<button @click="$noMultipleClicks(getUserInfo)" class="btn" plain="true">微信一键登录</button>
+		</view>
+		<!-- 动画 -->
+		<view class="ocean"></view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapMutations
+	} from 'vuex';
+	export default {
+		data() {
+			return {
+				//没有点击
+				noClick: true
+			}
+		},
+		methods: {
+			...mapMutations('m_parent', ['updateParentInfo', 'updateToken']),
+			//获取用户信息事件
+			async getUserInfo() {
+				await uni.getUserProfile({
+					desc: '获取您的基本信息',
+					success: infoRes => {
+						uni.login({
+							success: loginRes => {
+								this.$api.getUserToken({
+									js_code: loginRes.code
+								}).then(res => {
+									console.log(res);
+									this.updateToken(res.data)
+									// uni.setStorageSync('tokenKey',res.data.token)
+								}).catch(err => {
+									uni.showToast({
+										title: '加载数据失败~',
+										icon: 'none',
+									})
+								})
+							}
+						})
+						this.updateParentInfo(infoRes.userInfo)
+						uni.redirectTo({
+							url: '/subpkg/startup/guide'
+						})
+					},
+					fail: err => {
+						uni.showToast({
+							title: '您已拒绝授权',
+							icon: 'error'
+						});
+					}
+				});
+			},
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import 'startup_pages.scss';
+
+	//登录页面
+	.content {
+		width: 100vw;
+		height: 100vh;
+		background-color: #FFFFFF;
+
+		.bg1 {
+			position: fixed;
+			top: -250rpx;
+			right: -250rpx;
+			width: 680rpx;
+			height: 680rpx;
+			border-radius: 100%;
+			background-color: $color-blue;
+			z-index: 5;
+		}
+
+		.bg2 {
+			position: fixed;
+			right: -300rpx;
+			top: 200rpx;
+			width: 600rpx;
+			height: 600rpx;
+			border-radius: 100%;
+			background-color: $color-red;
+			z-index: 4;
+		}
+
+		.bg3 {
+			position: fixed;
+			top: 500rpx;
+			right: 450rpx;
+			width: 600rpx;
+			height: 600rpx;
+			border-radius: 100%;
+			background-color: $color-yellow;
+			z-index: 4;
+		}
+	}
+</style>

+ 97 - 0
subpkg/startup/options.vue

@@ -0,0 +1,97 @@
+<template>
+	<view>
+		<top-return></top-return>
+		<view class="top">
+			<view class="YS-title" style="color: #4169E1;">选择您的孩子</view>
+		</view>
+
+		<!-- 孩子选择界面 -->
+		<view class="card-box">
+			<view class="card" v-for="(item,index) in childrenData" :key="index" @click="chooseChild(item)">
+				<view class="flex-row" style="width: 100%;">
+					<view class="front-tag"></view>
+					<view class="card-title">{{item.name}}</view>
+				</view>
+				<view class="avatar-box">
+						<image class="avatar" :src="item.gender==='M'?'/static/default_icons/boy_avatar.svg':item.gender===null?'/static/default_icons/boy_avatar.svg':'/static/default_icons/girl_avatar.svg'"></image>
+				</view>
+			</view>
+		</view>
+
+		<!-- 动画 -->
+		<view class="ocean"></view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState,
+		mapMutations
+	} from 'vuex'
+	export default {
+		computed: {
+			...mapState('m_parent', ['childrenData'])
+		},
+		data() {
+			return {
+
+			};
+		},
+		onLoad() {},
+		methods: {
+			...mapMutations('m_children', ['updateChildInfo']),
+			//选择孩子并跳转首页传入id查询显示孩子信息
+			async chooseChild(item) {
+				this.updateChildInfo(item)
+				await this.$initTab()
+				uni.switchTab({
+					url: '/pages/tab_home/tab_home'
+				})
+			},
+
+
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import 'startup_pages.scss';
+
+	.card-box {
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		flex-wrap: wrap; //元素换行
+		margin: 250rpx 0 0 0;
+
+		.card {
+			width: 280rpx;
+			height: 280rpx;
+			margin: 20rpx;
+			padding: 20rpx;
+			display: flex;
+			flex-direction: column;
+			justify-content: center;
+			align-items: center;
+			box-shadow: $box-shadow;
+			background-color: #FFFFFF;
+			border-radius: $border-radius;
+			z-index: 99;
+
+			.card-title {
+				line-height: 35rpx;
+				font-size: 35rpx;
+				font-weight: bold;
+				color: $title;
+			}
+
+			.avatar-box {
+				padding-top: 10rpx;
+				.avatar {
+					width: 240rpx;
+					height: 240rpx;
+				}
+			}
+		}
+	}
+</style>

+ 72 - 0
subpkg/startup/startup_pages.scss

@@ -0,0 +1,72 @@
+.top {
+	position: absolute;
+	top:200rpx;
+	left:50rpx;
+	display: flex;
+	flex-direction: column;
+}
+.YS-title {
+	line-height: 80rpx;
+	font-size: 70rpx;
+	z-index: 99;
+}
+.YS-subtitle {
+	line-height: 70rpx;
+	font-size: 50rpx;
+	z-index: 99;
+}
+.btn {
+	line-height: 100rpx;
+	border-radius: 100rpx;
+	height: 100rpx;
+	width: 90%;
+	top: 1000rpx;
+	left:5%;
+	font-weight: bold;
+	font-size: 36rpx;
+	color: #FFFFFF !important;
+	position: absolute;
+	border: none !important;
+	background: $gradient-color;
+	box-shadow: $box-shadow;
+	z-index: 99;
+}
+.ocean {
+		margin-top: -600rpx;
+		height: 2200rpx;
+		background-color: $color-blue;
+
+		&::before,
+		&::after {
+			content: "";
+			position: absolute;
+			width: 1600rpx;
+			height: 1600rpx;
+			top: 850rpx;
+			left: 50%;
+			border-radius: 43%;
+			background-color: #FFFFFF;
+			transform: translate(-50%, -70%) rotate(0);
+			animation: rotate 6s linear infinite;
+			z-index: 2;
+		}
+
+		&::after {
+			border-radius: 40%;
+			background-color: #FFFFFF;
+			opacity: 0.5;
+			transform: translate(-50%, -70%) rotate(0);
+			animation: rotate 10s linear -5s infinite;
+			z-index: 3;
+		}
+	}
+
+	@keyframes rotate {
+		50% {
+			transform: translate(-50%, -73%) rotate(180deg);
+		}
+
+		100% {
+			transform: translate(-50%, -70%) rotate(360deg);
+		}
+	}

+ 452 - 0
subpkg/swap/swapStats.vue

@@ -0,0 +1,452 @@
+<template>
+	<view class="page-view">
+		<top-return color="#FFF" text="日常记录" refresh="true"></top-return>
+		<!-- 背景 -->
+		<view class="bg-box1"></view>
+		<!-- 页面标题内容 -->
+		<view class="top-box">
+			<view class="flex-baseline">
+				<view class="info-title" style="margin-left: 0;">{{dayTime.split('月')[0]}}</view>
+				<view class="info-subtitle">月</view>
+				<view class="info-title">{{dayTime.split('月')[1]}}
+				</view>
+				<view class="info-subtitle">日</view>
+				<view class="info-title" style="margin-left: 20rpx;">{{weekTime}}</view>
+			</view>
+			<view class="flex-baseline">
+				<view class="data-subtitle" style="margin-left: 0;">记录今日孩子表现吧</view>
+			</view>
+		</view>
+		<!-- 记录模块 -->
+		<view class="module-box" style="margin-top: 20rpx;">
+			<view class="module-item" v-for="(item,index) in moduleData" :key="index" :style="item.color"
+				@click="setTime(index)">
+				<view class="module-item-subtext" style="margin-left: 30rpx;">{{item.text}}</view>
+
+				<view class="flex-baseline" style="margin-left: 30rpx;" v-if="item.numData === ''">
+					<text class="module-item-text">记录</text>
+					<text class="module-item-subtext" style="margin-left: 8rpx;opacity:0.8;">今日时长</text>
+				</view>
+				<view class="flex-baseline" style="margin-left: 30rpx;"
+					v-if="item.numData.includes('小时') && item.numData != ''">
+					<text class="module-item-text">{{item.numData.split('小时')[0]}}</text>
+					<text class="module-item-subtext" style="margin-left: 8rpx;opacity:0.8;">小时</text>
+					<text class="module-item-text"
+						style="margin-left: 8rpx;">{{item.numData.split('小时')[1].replace('分','')}}</text>
+					<text class="module-item-subtext" style="margin-left: 8rpx;opacity:0.8;">分钟</text>
+				</view>
+				<view class="flex-baseline" style="margin-left: 30rpx;"
+					v-if="item.numData.includes('小时') === false && item.numData != ''">
+					<text class="module-item-text" style="margin-left: 8rpx;">{{item.numData.replace('分','')}}</text>
+					<text class="module-item-subtext" style="margin-left: 8rpx;opacity:0.8;">分钟</text>
+				</view>
+				<view :class="item.icon"></view>
+			</view>
+		</view>
+		<!-- 时间选择器 -->
+		<u-picker :show="setTimePicker" :columns="pickerList" @confirm="pickerConfirm" @cancel="cancel">
+		</u-picker>
+		<!-- 统计列表 -->
+		<view class="card-view" style="margin-top: 0;">
+			<!-- 统计列表 -->
+			<view class="flex-column-box" style="margin-left: 20rpx;">
+				<view class="title" style="font-size: 32rpx;">近期统计</view>
+				<view class="bottom-tag"
+					style="background-image: linear-gradient(to right, #4169E1, rgba(255, 255, 255, 0.01));"></view>
+			</view>
+			<!-- 总成绩对比 -->
+			<view class="card-item" style="width: 100%;">
+				<view class="card-title">
+					<view class="front-tag"></view>
+					<view class="title">学习娱乐时长对比</view>
+				</view>
+				<view class="chart-box">
+					<qiun-data-charts type="column" ontouch="true" :chartData="swapChartData[0]"
+						tooltipFormat='tooltipHourColum' :canvas2d="true" canvasId="swap_chart1" />
+				</view>
+			</view>
+			<!-- 单科与平均对比 -->
+			<view class="card-item">
+				<view class="card-title">
+					<view class="front-tag"></view>
+					<view class="title">近期运动记录</view>
+				</view>
+				<view class="chart-box" style="height: 350rpx;">
+					<qiun-data-charts type="pie" :chartData="swapChartData[1]" tooltipFormat='pieMinute'
+						:canvas2d="true" canvasId="swap_chart2" />
+				</view>
+			</view>
+			<view class="card-item">
+				<view class="card-title">
+					<view class="front-tag"></view>
+					<view class="title">近期睡眠记录</view>
+				</view>
+				<view class="chart-box" style="height: 350rpx;">
+					<qiun-data-charts type="ring" :chartData="swapChartData[2]" tooltipFormat='pieHour' :canvas2d="true"
+						canvasId="swap_chart3" :opts="ringOpts" />
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState,
+		mapMutations
+	} from 'vuex'
+	export default {
+		computed: {
+			...mapState('m_chart', ['swapChartData'])
+		},
+		data() {
+			return {
+				//记录卡片
+				moduleData: [{
+						text: '学习时长',
+						color: 'background-color: #4169E1;',
+						icon: 't-icon t-icon-bianjibi',
+						numData: '',
+					},
+					{
+						text: '娱乐时长',
+						color: 'background-color: #ff5959;',
+						icon: 't-icon t-icon-leimucuyule',
+						numData: '',
+					},
+					{
+						text: '运动时长',
+						color: 'background-color: #ff8caf;',
+						icon: 't-icon t-icon-yundong',
+						numData: '',
+					},
+					{
+						text: '睡眠时长',
+						color: 'background-color: #f9c752;',
+						icon: 't-icon t-icon-a-icon_wananyueliangshuimian',
+						numData: '',
+					}
+				],
+				//标题配置
+				ringOpts: {},
+				//当前记录卡片
+				cardCurrent: 5,
+				//选择器
+				setTimePicker: false,
+				//时间表
+				pickerList: [
+					['0小时', '1小时', '2小时', '3小时', '4小时', '5小时', '6小时', '7小时', '8小时', '9小时', '10小时'],
+					['5分', '10分', '15分', '20分', '25分', '30分', '35分', '40分', '45分', '50分', '55分']
+				],
+				//历史数据
+				dayTime: '',
+				weekTime: '',
+				//是否重新记录
+				setTimeRecord: false
+			}
+		},
+		onLoad() {
+			this.init()
+		},
+		methods: {
+			...mapMutations('m_chart', ['updateSwapChartData']),
+			...mapMutations('m_parent', ['updateChildDailyData']),
+			init() {
+				this.getToday()
+				this.getData()
+				this.getRingOpts()
+			},
+			getToday() {
+				this.dayTime = (new Date()).format('M-d').replace('-', '月')
+				this.weekTime = "星期" + "日一二三四五六".charAt(new Date().getDay());
+			},
+			//记录信息初始化
+			getData() {
+				if (uni.getStorageSync('moduleData'))
+					this.moduleData = JSON.parse(uni.getStorageSync('moduleData'));
+				if (uni.getStorageSync('childDailyData'))
+					this.historyData = JSON.parse(uni.getStorageSync('childDailyData'));
+				this.saveToStudyChart()
+			},
+			
+			//睡眠记录统计
+			getRingOpts() {
+				let sleepData = ''
+				if (uni.getStorageSync('childDailyData'))
+				sleepData = JSON.parse(uni.getStorageSync('childDailyData')).sleep;
+				let sum = 0
+				for (let i = 0; i < sleepData.length; i++) {
+					sum += sleepData[i]
+				}
+				let sleepAvg = (sum / sleepData.length).toFixed(1)
+				let opt = {
+					title: {
+						name: '平均睡眠',
+						color: '#909399'
+					},
+					subtitle: {
+						name: sleepAvg + ' 小时',
+						color: '#4169E1'
+					},
+				}
+				this.ringOpts = opt
+			},
+			//点击卡片唤起picker
+			setTime(index) {
+				if (this.moduleData[index].numData === '') {
+					this.cardCurrent = index
+					this.setTimePicker = true
+				}
+				if (this.moduleData[index].numData != '') {
+					let that = this;
+					uni.showModal({
+						title: `今日${that.moduleData[index].text}已记录`,
+						content: '需要重新记录吗?',
+						success: function(res) {
+							if (res.confirm) {
+								that.cardCurrent = index
+								that.setTimePicker = true
+								that.setTimeRecord = true
+							} else if (res.cancel) {
+								console.log('取消记录');
+							}
+						}
+					})
+				}
+			},
+			//记录数据
+			pickerConfirm(e) {
+				if (this.setTimeRecord) {
+					if (e.value[0] === '0小时') {
+						this.moduleData[this.cardCurrent].numData = e.value[1]
+					} else {
+						this.moduleData[this.cardCurrent].numData = e.value[0] + e.value[1]
+					}
+					//转换为数据记录到图表中
+					if (this.moduleData[this.cardCurrent].numData.includes('小时') === false) {
+						let timeData = parseFloat((parseInt(this.moduleData[this.cardCurrent].numData.replace('分', '')) /
+								60)
+							.toFixed(1))
+						switch (this.cardCurrent) {
+							case 0:
+								this.historyData.study[6] = timeData
+								break
+							case 1:
+								this.historyData.rest[6] = timeData
+								break
+							case 2:
+								let numExercise = parseInt(this.moduleData[this.cardCurrent].numData.replace('分', ''))
+								this.historyData.exercise[6] = numExercise
+								break
+							case 3:
+								this.historyData.sleep[6] = timeData
+								break
+						}
+						uni.setStorageSync('moduleData', JSON.stringify(this.moduleData))
+						this.updateChildDailyData(this.historyData)
+						this.saveToStudyChart()
+					} else {
+						let timeTemp = this.moduleData[this.cardCurrent].numData.replace('小时', '.').replace('分', '').split(
+							'.')
+						let timeData = parseInt(timeTemp[0]) + parseFloat((timeTemp[1] / 60).toFixed(1))
+						switch (this.cardCurrent) {
+							case 0:
+								this.historyData.study[6] = timeData
+								break
+							case 1:
+								this.historyData.rest[6] = timeData
+								break
+							case 2:
+								let numExerciseData = parseInt(timeTemp[0] * 60) + parseFloat((timeTemp[1]))
+								this.historyData.exercise[6] = numExerciseData
+								break
+							case 3:
+								this.historyData.sleep[6] = timeData
+								break
+						}
+						uni.setStorageSync('moduleData', JSON.stringify(this.moduleData))
+						this.updateChildDailyData(this.historyData)
+						this.saveToStudyChart()
+					}
+					this.setTimePicker = false
+					this.setTimeRecord = false
+				} else {
+					if (e.value[0] === '0小时') {
+						this.moduleData[this.cardCurrent].numData = e.value[1]
+					} else {
+						this.moduleData[this.cardCurrent].numData = e.value[0] + e.value[1]
+					}
+					//转换为数据记录到图表中
+					if (this.moduleData[this.cardCurrent].numData.includes('小时') === false) {
+						let timeData = parseFloat((parseInt(this.moduleData[this.cardCurrent].numData.replace('分', '')) /
+								60)
+							.toFixed(1))
+						switch (this.cardCurrent) {
+							case 0:
+								this.historyData.study.push(timeData)
+								this.historyData.study.shift()
+								break
+							case 1:
+								this.historyData.rest.push(timeData)
+								this.historyData.rest.shift()
+								break
+							case 2:
+								let numExercise = parseInt(this.moduleData[this.cardCurrent].numData.replace('分', ''))
+								this.historyData.exercise.push(numExercise)
+								this.historyData.exercise.shift()
+								break
+							case 3:
+								this.historyData.sleep.push(timeData)
+								this.historyData.sleep.shift()
+								break
+						}
+						uni.setStorageSync('moduleData', JSON.stringify(this.moduleData))
+						this.updateChildDailyData(this.historyData)
+						this.saveToStudyChart()
+					} else {
+						let timeTemp = this.moduleData[this.cardCurrent].numData.replace('小时', '.').replace('分', '').split(
+							'.')
+						let timeData = parseInt(timeTemp[0]) + parseFloat((timeTemp[1] / 60).toFixed(1))
+						switch (this.cardCurrent) {
+							case 0:
+								this.historyData.study.push(timeData)
+								this.historyData.study.shift()
+								break
+							case 1:
+								this.historyData.rest.push(timeData)
+								this.historyData.rest.shift()
+								break
+							case 2:
+								let numExerciseData = parseInt(timeTemp[0] * 60) + parseFloat((timeTemp[1]))
+								this.historyData.exercise.push(numExerciseData)
+								this.historyData.exercise.shift()
+								break
+							case 3:
+								this.historyData.sleep.push(timeData)
+								this.historyData.sleep.shift()
+								break
+						}
+						uni.setStorageSync('moduleData', JSON.stringify(this.moduleData))
+						this.updateChildDailyData(this.historyData)
+						this.saveToStudyChart()
+					}
+					this.setTimePicker = false
+				}
+			},
+			//取消
+			cancel() {
+				this.setTimePicker = false
+			},
+			//存储到图表
+			saveToStudyChart() {
+				let swapChartData = []
+				let studyColumn = {
+					categories: [],
+					series: [{
+							name: '自主学习',
+							data: this.historyData.study
+						},
+						{
+							name: '娱乐放松',
+							data: this.historyData.rest
+						}
+					]
+				}
+				//时间
+				studyColumn.categories = this.$getRecentDateArray(this.historyData.study.length)
+				//学习记录表数据记录
+				switch (this.cardCurrent) {
+					case 0:
+						studyColumn.series[0].data = this.historyData.study
+						break
+					case 1:
+						studyColumn.series[1].data = this.historyData.rest
+						break
+				}
+				//运动记录表
+				let exercisePie = {
+					series: [{
+						data: [{}, {}, {}, {}, {}, {}, {}]
+					}]
+				}
+				//睡眠记录表
+				let sleepRing = {
+					series: [{
+						data: [{}, {}, {}, {}, {}, {}, {}]
+					}]
+				}
+				studyColumn.categories.forEach((value, index) => {
+					exercisePie.series[0].data[index].name = value
+					exercisePie.series[0].data[index].value = parseFloat((this.historyData.exercise[index])
+						.toFixed(1))
+					sleepRing.series[0].data[index].name = value
+					sleepRing.series[0].data[index].value = this.historyData.sleep[index]
+				})
+				swapChartData.push(studyColumn)
+				swapChartData.push(exercisePie)
+				swapChartData.push(sleepRing)
+				this.updateSwapChartData(swapChartData)
+				this.getRingOpts()
+			},
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import '@/subpkg/datalist/top_info.scss';
+	.chart-box {
+		width: 100%;
+		height: 500rpx;
+	}
+
+	.flex-column-box {
+		margin: 20rpx 0;
+		display: flex;
+		flex-direction: column;
+		z-index: 55;
+	}
+
+	.module-box {
+		display: flex;
+		flex-flow: row wrap;
+		margin: 0 20rpx;
+		justify-content: space-between;
+
+		.module-item {
+			margin: 2% 0;
+			width: 48%;
+			height: auto;
+			display: flex;
+			flex-direction: column;
+			padding: 24rpx 0 20rpx 0;
+			background-color: #FFF;
+			border-radius: 20rpx;
+			justify-content: space-between;
+			overflow: hidden;
+			z-index: 3;
+
+			.module-item-text {
+				line-height: 80rpx;
+				color: #FFF;
+				font-size: 50rpx;
+				font-family: YSfont;
+				z-index: 5;
+			}
+
+			.module-item-subtext {
+				line-height: 80rpx;
+				color: #FFF;
+				font-size: 30rpx;
+				font-weight: bold;
+				z-index: 5;
+			}
+		}
+
+		.t-icon {
+			width: 250rpx;
+			height: 250rpx;
+			margin: -250rpx 0 0 160rpx;
+			z-index: 1;
+		}
+	}
+</style>

+ 82 - 0
subpkg/work/workStats.vue

@@ -0,0 +1,82 @@
+<template>
+	<view class="page-view">
+		<top-return color="#FFF" text="作业统计"></top-return>
+		<!-- 背景 -->
+		<view class="bg-box1"></view>
+		<!-- 页面标题内容 -->
+		<view class="top-box">
+			<view class="flex-baseline">
+				<view class="info-title" style="margin-left: 0;">{{dayTime.split('月')[0]}}</view>
+				<view class="info-subtitle">月</view>
+				<view class="info-title">{{dayTime.split('月')[1]}}
+				</view>
+				<view class="info-subtitle">日</view>
+				<view class="info-title" style="margin-left: 20rpx;">{{weekTime}}</view>
+			</view>
+			<view class="flex-baseline">
+				<view class="data-subtitle" style="margin-left: 0;">孩子今日共</view>
+				<view class="data-title">{{workData.length}}</view>
+				<view class="data-subtitle">份作业</view>
+			</view>
+		</view>
+		<!-- 统计列表 -->
+		<view class="card-view">
+			<view class="card-item" style="width: 100%;">
+				<view class="card-title">
+					<view class="front-tag"></view>
+					<view class="title">近期作业完成率</view>
+				</view>
+				<view class="chart-box">
+					<qiun-data-charts type="column" ontouch="true" :chartData="workChartData[0]"
+						tooltipFormat='HomeworkPercent' :canvas2d="true" canvasId="work_chart1" />
+				</view>
+			</view>
+
+			<view class="card-item" style="width: 100%;">
+				<view class="card-title">
+					<view class="front-tag"></view>
+					<view class="title">近期作业得分率</view>
+				</view>
+				<view class="chart-box">
+					<qiun-data-charts type="area" ontouch="true" :chartData="workChartData[1]"
+						tooltipFormat='HomeworkPercent' :canvas2d="true" canvasId="work_chart2" />
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex'
+	export default {
+		computed: {
+			...mapState('m_children', ['workData']),
+			...mapState('m_chart', ['workChartData']),
+		},
+		data() {
+			return {
+				dayTime: '',
+				weekTime: ''
+			};
+		},
+		onLoad() {
+			this.getToday()
+		},
+		methods: {
+			getToday() {
+				this.dayTime = (new Date()).format('M-d').replace('-', '月')
+				this.weekTime = "星期" + "日一二三四五六".charAt(new Date().getDay());
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import '@/subpkg/datalist/top_info.scss';
+	.chart-box {
+		width: 100%;
+		height: 500rpx;
+	}
+</style>

+ 669 - 0
subpkg/work/wrongBook.vue

@@ -0,0 +1,669 @@
+<template>
+	<view class="page-view">
+		<top-return text="错题本"></top-return>
+
+		<view class="icon-view">
+			<view class="icon-card">
+				<view class="t-icon t-icon-naozhong1" style="margin-right: 10rpx;"></view>
+				<view class="time-title">巩固时间</view>
+				<u-count-down :time="60 * 60 * 1000" format="mm:ss"></u-count-down>
+			</view>
+			<view class="icon-card" style="margin-left: auto;">
+				<view :class="signList.includes(curr)?'t-icon t-icon-ding-copy':'t-icon t-icon-ding'"
+					@click="addToSignList"></view>
+				<view :class="showNoteBox? 't-icon t-icon-bianji1-copy':'t-icon t-icon-bianji1'"
+					@click="showNoteBox = !showNoteBox"></view>
+				<view :class="answerSheet? 't-icon t-icon-cengji-copy':'t-icon t-icon-cengji'"
+					@click="answerSheet = !answerSheet" style="margin-right: 0;"></view>
+			</view>
+		</view>
+
+		<view class="note-view" catchtouchmove="true" v-if="showNoteBox">
+			<view class="note-box">
+				<th-autograph :is-download="false" canvas-id="autograph">
+				</th-autograph>
+			</view>
+		</view>
+
+		<swiper class="swiper-box" :style="{height: clientHeight?clientHeight+'px':'auto'}" :current="curr"
+			@change="setCurr">
+			<swiper-item v-for="(item,i) in mistakeDataList" :key="i">
+				<scroll-view :style="{height: clientHeight?clientHeight+'px':'auto'}">
+					<view class="item-card" :id="'card' + i">
+						<view class="flex-baseline">
+							<view class="YS-title">{{mistakeData[cardIndex].subject}}错题集</view>
+							<view class="title" style="color: #4169E1;margin-left: 10rpx;">{{i+1}}</view>
+							<view class="subtitle" style="margin: 0 10rpx;">/</view>
+							<view class="subtitle">{{mistakeData[cardIndex].amount}}</view>
+							<view class="YS-title" style="margin-left: 10rpx;">题</view>
+						</view>
+
+						<view class="tag-fill" style="margin-top: 40rpx;">
+							<view class="tag-text">{{item.type}}</view>
+						</view>
+
+						<view class="content">{{item.content}}</view>
+
+						<view class="answer-container">
+							<view class="answer-box" v-for="(x,y) in item.options" :key="y">
+								<view :class="answerList[i].answer == x.option?'answer-tag-select':'answer-tag'"
+									@click="selectOption(i,y)">
+									<view class="tag-text">{{x.option}}</view>
+								</view>
+								<view class="answer-content" @click="selectOption(i,y)">{{x.answer}}</view>
+							</view>
+						</view>
+					</view>
+				</scroll-view>
+			</swiper-item>
+			<!-- 答题卡 -->
+			<swiper-item>
+				<scroll-view :style="{height: clientHeight?clientHeight+'px':'auto'}">
+					<view class="item-card">
+						<view class="tag-list">
+							<view :class="item.answer != ''?'answer-tag-select':'answer-tag'"
+								v-for="(item,index) in answerList" :key="index" @click="navTopic(index)"
+								style="margin: 40rpx 20rpx;">
+
+								<view class="sign-icon" v-if="signList.includes(index)">
+									<view class="t-icon t-icon-ding-copy"></view>
+								</view>
+
+								<view class="tag-text">{{item.index + 1}}</view>
+							</view>
+						</view>
+						<view class="btn">
+							<view class="btn-text">交卷</view>
+						</view>
+					</view>
+				</scroll-view>
+			</swiper-item>
+		</swiper>
+		<u-action-sheet :show="answerSheet" @close="answerSheet = false" title="答题卡" :round="6">
+			<view style="margin: 20rpx 50rpx;">
+				<view class="tag-list">
+					<view :class="item.answer != ''?'answer-tag-select':'answer-tag'" v-for="(item,index) in answerList"
+						:key="index" @click="navTopic(index)" style="margin: 40rpx 20rpx;">
+
+						<view class="sign-icon" v-if="signList.includes(index)">
+							<view class="t-icon t-icon-ding-copy"></view>
+						</view>
+
+						<view class="tag-text">{{item.index + 1}}</view>
+					</view>
+				</view>
+				<view class="btn">
+					<view class="btn-text">交卷</view>
+				</view>
+			</view>
+		</u-action-sheet>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex'
+	import thAutograph from "../../components/th-autograph/th-autograph.vue"
+	export default {
+		components: {
+			thAutograph
+		},
+		computed: {
+			...mapState('m_children',['mistakeData'])
+		},
+		watch: {
+			curr: {
+				handler(newValue) {
+					if (this.curr <= (this.mistakeDataList.length - 1))
+						this.getSwiperHeight()
+				},
+				immediate: true
+			},
+		},
+		data(){
+			return {
+				cardIndex: '',
+				clientHeight: '',
+				curr: 0,
+				showNoteBox: false,
+				answerSheet: false,
+				signList: [],
+				answerList: '',
+				mistakeDataList: [{
+						content: '题目内容一的外号对哦奥委会的卡号大家看上课进度吧,阿玛尼的卡乌诺迪克兰的三大我看啦到哪里扣篮代码是你',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					},
+					{
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。3192087jhcuyastgdjahkgsduyagwd',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					},
+					{
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。h217893y1jahsdbyugcjhzxbcytfu1231',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					},
+					{
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快32189371298hjahdsu。',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一dkajghcjxzncuktwiajkjbsuydgi2uyhqjkn'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三312897319hjkabcjhxz'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					},
+					{
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。2318209uasiohsdjkaxnczuiywa',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一123i7auhcjkzxgczx'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三31289dyasjkdhciuxcz'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					}, {
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。adnauiychkajnwyiujagdhjabyuczxg2',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					}, {
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					}, {
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					}, {
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					}, {
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					}, {
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					}, {
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					}, {
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					}, {
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					}, {
+						content: '打完就都i阿娇的罗马里克电脑i经常兄长,达瓦ui带坏我很单纯进行只能催啊挖好的快回家,没齿难忘i垃圾我i的急啊离开你们死定了埃及低洼降低AMD扩散低洼会加大科技那么快。',
+						type: '单选题',
+						options: [{
+								option: 'A',
+								answer: '模拟答案一'
+							},
+							{
+								option: 'B',
+								answer: '模拟答案二'
+							},
+							{
+								option: 'C',
+								answer: '模拟答案三'
+							},
+							{
+								option: 'D',
+								answer: '模拟答案四'
+							}
+						]
+					},
+				],
+			}
+		},
+		onLoad(param) {
+			this.cardIndex = param.index
+			this.getAnswerList()
+		},
+		methods:{
+			//生成自适应高度swiper
+			getSwiperHeight() {
+				let query = uni.createSelectorQuery().in(this)
+				query.select('#card' + this.curr).boundingClientRect(data => {
+					this.clientHeight = data.height + 40
+					console.log('swiper高度', this.clientHeight);
+				}).exec();
+			},
+			setCurr(e) {
+				let thisCurr = e.detail.current || 0;
+				this.curr = thisCurr;
+			},
+			//生成答题卡
+			getAnswerList() {
+				if (this.answerList === '') {
+					this.answerList = []
+					this.mistakeDataList.forEach((item, index) => {
+						let answer = {
+							index: index,
+							answer: ''
+						}
+						this.answerList.push(answer)
+					})
+					console.log(this.answerList);
+				}
+			},
+			//选择选项
+			selectOption(i, y) {
+				this.answerList[i].answer = this.mistakeDataList[i].options[y].option
+				if (this.curr <= (this.mistakeDataList.length - 1)) {
+					setTimeout(() => {
+						this.curr = i + 1
+					}, 300);
+				}
+			},
+			//导航到题目
+			navTopic(index) {
+				this.curr = index
+				this.answerSheet = false
+			},
+			//标记题目
+			addToSignList() {
+				if(this.curr <= (this.mistakeDataList.length - 1)){
+					if (this.signList.includes(this.curr)) {
+						this.signList = this.signList.filter(x => x != this.curr)
+					} else {
+						this.signList.push(this.curr)
+					}
+				}
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.icon-view {
+		margin: 120rpx 20rpx 0 20rpx;
+		display: flex;
+		align-items: center;
+	
+		.icon-card {
+			display: flex;
+			align-items: center;
+			padding: 20rpx;
+			height: 50rpx;
+			border-radius: $border-radius;
+			background-color: #FFF;
+	
+			.t-icon {
+				margin-right: 40rpx;
+				width: 50rpx;
+				height: 50rpx;
+			}
+	
+			.time-title {
+				font-size: 30rpx;
+				line-height: 30rpx;
+				margin-right: 10rpx;
+			}
+	
+			.u-count-down__text.data-v-463368ae {
+				line-height: 30rpx !important;
+			}
+		}
+	}
+	
+	.item-card {
+		margin: 20rpx;
+		padding: 40rpx 40rpx 80rpx 40rpx;
+		border-radius: $border-radius;
+		background-color: #FFF;
+	
+		.content {
+			margin-top: 20rpx;
+			line-height: 60rpx;
+			font-size: 35rpx;
+			color: $title;
+			word-break: break-all;
+		}
+	
+		.YS-title {
+			line-height: 38rpx;
+			font-size: 38rpx;
+		}
+	
+		.tag-fill {
+			background-color: #d8deff;
+			width: fit-content;
+			margin-left: 0;
+			padding: 6rpx 12rpx;
+	
+			.tag-text {
+				font-size: 28rpx;
+				color: #4169E1;
+			}
+		}
+	
+		.answer-container {
+			display: flex;
+			flex-direction: column;
+	
+			.answer-box {
+				margin-top: 40rpx;
+				display: flex;
+				align-items: center;
+	
+				.answer-content {
+					margin-left: 40rpx;
+					font-size: 35rpx;
+					line-height: 60rpx;
+					color: $title;
+					word-break: break-all;
+				}
+			}
+		}
+	}
+	
+	.answer-tag {
+		display: flex;
+		flex-shrink: 0;
+		align-items: center;
+		justify-content: center;
+		height: 66rpx;
+		width: 66rpx;
+		border-radius: 50%;
+		border: 2rpx solid $subtitle;
+	
+		.tag-text {
+			font-size: 35rpx;
+			line-height: 35rpx;
+			color: $subtitle;
+		}
+	}
+	
+	.answer-tag-select {
+		display: flex;
+		flex-shrink: 0;
+		align-items: center;
+		justify-content: center;
+		height: 70rpx;
+		width: 70rpx;
+		border-radius: 50%;
+		background-color: #4169E1;
+	
+		.tag-text {
+			font-size: 35rpx;
+			line-height: 35rpx;
+			color: #FFF;
+		}
+	}
+	
+	.tag-list {
+		display: flex;
+		align-items: center;
+		align-content: flex-start;
+		justify-content: space-between;
+		flex-wrap: wrap;
+	
+		.sign-icon {
+			position: relative;
+			left: 20rpx;
+			top: -60rpx;
+			width: 0rpx;
+			height: 0rpx;
+	
+			.t-icon {
+				height: 50rpx;
+				width: 50rpx;
+			}
+		}
+	}
+	
+	.btn {
+		margin: 40rpx 20rpx 0 20rpx;
+		height: 80rpx;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		background-color: #4169E1;
+		border-radius: 40rpx;
+	
+		.btn-text {
+			color: #FFF;
+			line-height: 36rpx;
+			font-size: 36rpx;
+			font-family: YSfont;
+		}
+	}
+	
+	.note-view {
+		width: 100%;
+		height: 550rpx;
+		margin: 20rpx 0 5rpx 0;
+	
+		.note-box {
+			width: 710rpx;
+			height: 100%;
+			margin: 0 20rpx;
+			border-radius: $border-radius;
+			overflow: hidden;
+			background-color: #FFF;
+		}
+	}
+</style>

+ 5 - 0
uni.scss

@@ -0,0 +1,5 @@
+//全局主题文件
+//uView配置
+@import '@/uni_modules/uview-ui/theme.scss';
+//自定义主题
+@import '@/common/global_scss/theme_style.scss';

+ 246 - 0
uni_modules/qiun-data-charts/changelog.md

@@ -0,0 +1,246 @@
+## 2.4.3-20220505(2022-05-05)
+- 秋云图表组件 修复开启canvas2d后将series赋值为空数组显示加载图标时,再次赋值后画布闪动的bug
+- 秋云图表组件 修复升级hbx最新版后ECharts的highlight方法报错的bug
+- uCharts.js 雷达图新增参数opts.extra.radar.gridEval,数据点位网格抽希,默认1
+- uCharts.js 雷达图新增参数opts.extra.radar.axisLabel,	是否显示刻度点值,默认false
+- uCharts.js 雷达图新增参数opts.extra.radar.axisLabelTofix,刻度点值小数位数,默认0
+- uCharts.js 雷达图新增参数opts.extra.radar.labelPointShow,是否显示末端刻度圆点,默认false
+- uCharts.js 雷达图新增参数opts.extra.radar.labelPointRadius,刻度圆点的半径,默认3
+- uCharts.js 雷达图新增参数opts.extra.radar.labelPointColor,刻度圆点的颜色,默认#cccccc
+- uCharts.js 雷达图新增参数opts.extra.radar.linearType,渐变色类型,可选值"none"关闭渐变,"custom"开启渐变
+- uCharts.js 雷达图新增参数opts.extra.radar.customColor,自定义渐变颜色,数组类型对应series的数组长度以匹配不同series颜色的不同配色方案,例如["#FA7D8D", "#EB88E2"]
+- uCharts.js 雷达图优化支持series.textColor、series.textSize属性
+- uCharts.js 柱状图中温度计式图标,优化支持全圆角类型,修复边框有缝隙的bug,详见官网【演示】中的温度计图表
+- uCharts.js 柱状图新增参数opts.extra.column.activeWidth,当前点击柱状图的背景宽度,默认一个单元格单位
+- uCharts.js 混合图增加opts.extra.mix.area.gradient 区域图是否开启渐变色
+- uCharts.js 混合图增加opts.extra.mix.area.opacity 区域图透明度,默认0.2
+- uCharts.js 饼图、圆环图、玫瑰图、漏斗图,增加opts.series[0].data[i].labelText,自定义标签文字,避免formatter格式化的繁琐,详见官网【演示】中的饼图
+- uCharts.js 饼图、圆环图、玫瑰图、漏斗图,增加opts.series[0].data[i].labelShow,自定义是否显示某一个指示标签,避免因饼图类别太多导致标签重复或者居多导致图形变形的问题,详见官网【演示】中的饼图
+- uCharts.js 增加opts.series[i].legendText/opts.series[0].data[i].legendText(与series.name同级)自定义图例显示文字的方法
+- uCharts.js 优化X轴、Y轴formatter格式化方法增加形参,统一为fromatter:function(value,index,opts){}
+- uCharts.js 修复横屏模式下无法使用双指缩放方法的bug
+- uCharts.js 修复当只有一条数据或者多条数据值相等的时候Y轴自动计算的最大值错误的bug
+- 【官网模板】增加外部自定义图例与图表交互的例子,[点击跳转](https://www.ucharts.cn/v2/#/layout/info?id=2)
+
+## 注意:非unimodules 版本如因更新 hbx 至 3.4.7 导致报错如下,请到码云更新非 unimodules 版本组件,[点击跳转](https://gitee.com/uCharts/uCharts/tree/master/uni-app/uCharts-%E7%BB%84%E4%BB%B6)
+> Error in callback for immediate watcher "uchartsOpts": "SyntaxError: Unexpected token u in JSON at position 0"
+## 2.4.2-20220421(2022-04-21)
+- 秋云图表组件 修复HBX升级3.4.6.20220420版本后echarts报错的问题
+## 2.4.2-20220420(2022-04-20)
+## 重要!此版本uCharts新增了很多功能,修复了诸多已知问题
+- 秋云图表组件 新增onzoom开启双指缩放功能(仅uCharts),前提需要直角坐标系类图表类型,并且ontouch为true、opts.enableScroll为true,详见实例项目K线图
+- 秋云图表组件 新增optsWatch是否监听opts变化,关闭optsWatch后,动态修改opts不会触发图表重绘
+- 秋云图表组件 修复开启canvas2d功能后,动态更新数据后画布闪动的bug
+- 秋云图表组件 去除directory属性,改为自动获取echarts.min.js路径(升级不受影响)
+- 秋云图表组件 增加getImage()方法及@getImage事件,通过ref调用getImage()方法获,触发@getImage事件获取当前画布的base64图片文件流。
+- 秋云图表组件 支付宝、字节跳动、飞书、快手小程序支持开启canvas2d同层渲染设置。
+- 秋云图表组件 新增加【非uniCloud】版本组件,避免有些不需要uniCloud的使用组件发布至小程序需要提交隐私声明问题,请到码云[【非uniCloud版本】](https://gitee.com/uCharts/uCharts/tree/master/uni-app/uCharts-%E7%BB%84%E4%BB%B6),或npm[【非uniCloud版本】](https://www.npmjs.com/package/@qiun/uni-ucharts)下载使用。
+- uCharts.js 新增dobuleZoom双指缩放功能
+- uCharts.js 新增山峰图type="mount",数据格式为饼图类格式,不需要传入categories,具体详见新版官网在线演示
+- uCharts.js 修复折线图当数据中存在null时tooltip报错的bug
+- uCharts.js 修复饼图类当画布比较小时自动计算的半径是负数报错的bug
+- uCharts.js 统一各图表类型的series.formatter格式化方法的形参为(val, index, series, opts),方便格式化时有更多参数可用
+- uCharts.js 标记线功能增加labelText自定义显示文字,增加labelAlign标签显示位置(左侧或右侧),增加标签显示位置微调labelOffsetX、labelOffsetY
+- uCharts.js 修复条状图当数值很小时开启圆角后样式错误的bug
+- uCharts.js 修复X轴开启disabled后,X轴仍占用空间的bug
+- uCharts.js 修复X轴开启滚动条并且开启rotateLabel后,X轴文字与滚动条重叠的bug
+- uCharts.js 增加X轴rotateAngle文字旋转自定义角度,取值范围(-90至90)
+- uCharts.js 修复地图文字标签层级显示不正确的bug
+- uCharts.js 修复饼图、圆环图、玫瑰图当数据全部为0的时候不显示数据标签的bug
+- uCharts.js 修复当opts.padding上边距为0时,Y轴顶部刻度标签位置不正确的bug
+
+## 另外我们还开发了各大原生小程序组件,已发布至码云和npm
+[https://gitee.com/uCharts/uCharts](https://gitee.com/uCharts/uCharts)
+[https://www.npmjs.com/~qiun](https://www.npmjs.com/~qiun)
+
+## 对于原生uCharts文档我们已上线新版官方网站,详情点击下面链接进入官网
+[https://www.uCharts.cn/v2/](https://www.ucharts.cn/v2/)
+## 2.3.7-20220122(2022-01-22)
+## 重要!使用vue3编译,请使用cli模式并升级至最新依赖,HbuilderX编译需要使用3.3.8以上版本
+- uCharts.js 修复uni-app平台组件模式使用vue3编译到小程序报错的bug。
+## 2.3.7-20220118(2022-01-18)
+## 注意,使用vue3的前提是需要3.3.8.20220114-alpha版本的HBuilder!
+## 2.3.67-20220118(2022-01-18)
+- 秋云图表组件 组件初步支持vue3,全端编译会有些问题,具体详见下面修改:
+1. 小程序端运行时,在uni_modules文件夹的qiun-data-charts.js中搜索 new uni_modules_qiunDataCharts_js_sdk_uCharts_uCharts.uCharts,将.uCharts去掉。
+2. 小程序端发行时,在uni_modules文件夹的qiun-data-charts.js中搜索 new e.uCharts,将.uCharts去掉,变为 new e。
+3. 如果觉得上述步骤比较麻烦,如果您的项目只编译到小程序端,可以修改u-charts.js最后一行导出方式,将 export default uCharts;变更为 export default { uCharts: uCharts }; 这样变更后,H5和App端的renderjs会有问题,请开发者自行选择。(此问题非组件问题,请等待DC官方修复Vue3的小程序端)
+## 2.3.6-20220111(2022-01-11)
+- 秋云图表组件 修改组件 props 属性中的 background 默认值为 rgba(0,0,0,0)
+## 2.3.6-20211201(2021-12-01)
+- uCharts.js 修复bar条状图开启圆角模式时,值很小时圆角渲染错误的bug
+## 2.3.5-20211014(2021-10-15)
+- uCharts.js 增加vue3的编译支持(仅原生uCharts,qiun-data-charts组件后续会支持,请关注更新)
+## 2.3.4-20211012(2021-10-12)
+- 秋云图表组件 修复 mac os x 系统 mouseover 事件丢失的 bug
+## 2.3.3-20210706(2021-07-06)
+- uCharts.js 增加雷达图开启数据点值(opts.dataLabel)的显示
+## 2.3.2-20210627(2021-06-27)
+- 秋云图表组件 修复tooltipCustom个别情况下传值不正确报错TypeError: Cannot read property 'name' of undefined的bug
+## 2.3.1-20210616(2021-06-16)
+- uCharts.js 修复圆角柱状图使用4角圆角时,当数值过大时不正确的bug
+## 2.3.0-20210612(2021-06-12)
+- uCharts.js 【重要】uCharts增加nvue兼容,可在nvue项目中使用gcanvas组件渲染uCharts,[详见码云uCharts-demo-nvue](https://gitee.com/uCharts/uCharts)
+- 秋云图表组件 增加tapLegend属性,是否开启图例点击交互事件
+- 秋云图表组件 getIndex事件中增加返回uCharts实例中的opts参数,以便在页面中调用参数
+- 示例项目 pages/other/other.vue增加app端自定义tooltip的方法,详见showOptsTooltip方法
+## 2.2.1-20210603(2021-06-03)
+- uCharts.js 修复饼图、圆环图、玫瑰图,当起始角度不为0时,tooltip位置不准确的bug
+- uCharts.js 增加温度计式柱状图开启顶部半圆形的配置
+## 2.2.0-20210529(2021-05-29)
+- uCharts.js 增加条状图type="bar"
+- 示例项目 pages/ucharts/ucharts.vue增加条状图的demo
+## 2.1.7-20210524(2021-05-24)
+- uCharts.js 修复大数据量模式下曲线图不平滑的bug
+## 2.1.6-20210523(2021-05-23)
+- 秋云图表组件 修复小程序端开启滚动条更新数据后滚动条位置不符合预期的bug
+## 2.1.5-2021051702(2021-05-17)
+- uCharts.js 修复自定义Y轴min和max值为0时不能正确显示的bug
+## 2.1.5-20210517(2021-05-17)
+- uCharts.js 修复Y轴自定义min和max时,未按指定的最大值最小值显示坐标轴刻度的bug
+## 2.1.4-20210516(2021-05-16)
+- 秋云图表组件 优化onWindowResize防抖方法
+- 秋云图表组件 修复APP端uCharts更新数据时,清空series显示loading图标后再显示图表,图表抖动的bug
+- uCharts.js 修复开启canvas2d后,x轴、y轴、series自定义字体大小未按比例缩放的bug
+- 示例项目 修复format-e.vue拼写错误导致app端使用uCharts渲染图表
+## 2.1.3-20210513(2021-05-13)
+- 秋云图表组件 修改uCharts变更chartData数据为updateData方法,支持带滚动条的数据动态打点
+- 秋云图表组件 增加onWindowResize防抖方法 fix by ど誓言,如尘般染指流年づ 
+- 秋云图表组件 H5或者APP变更chartData数据显示loading图表时,原数据闪现的bug
+- 秋云图表组件 props增加errorReload禁用错误点击重新加载的方法
+- uCharts.js 增加tooltip显示category(x轴对应点位)标题的功能,opts.extra.tooltip.showCategory,默认为false
+- uCharts.js 修复mix混合图只有柱状图时,tooltip的分割线显示位置不正确的bug
+- uCharts.js 修复开启滚动条,图表在拖动中动态打点,滚动条位置不正确的bug
+- uCharts.js 修复饼图类数据格式为echarts数据格式,series为空数组报错的bug
+- 示例项目 修改uCharts.js更新到v2.1.2版本后,@getIndex方法获取索引值变更为e.currentIndex.index
+- 示例项目 pages/updata/updata.vue增加滚动条拖动更新(数据动态打点)的demo
+- 示例项目 pages/other/other.vue增加errorReload禁用错误点击重新加载的demo
+## 2.1.2-20210509(2021-05-09)
+秋云图表组件 修复APP端初始化时就传入chartData或lacaldata不显示图表的bug
+## 2.1.1-20210509(2021-05-09)
+- 秋云图表组件 变更ECharts的eopts配置在renderjs内执行,支持在config-echarts.js配置文件内写function配置。
+- 秋云图表组件 修复APP端报错Prop being mutated: "onmouse"错误的bug。
+- 秋云图表组件 修复APP端报错Error: Not Found:Page[6][-1,27] at view.umd.min.js:1的bug。
+## 2.1.0-20210507(2021-05-07)
+- 秋云图表组件 修复初始化时就有数据或者数据更新的时候loading加载动画闪动的bug
+- uCharts.js 修复x轴format方法categories为字符串类型时返回NaN的bug
+- uCharts.js 修复series.textColor、legend.fontColor未执行全局默认颜色的bug
+## 2.1.0-20210506(2021-05-06)
+- 秋云图表组件 修复极个别情况下报错item.properties undefined的bug
+- 秋云图表组件 修复极个别情况下关闭加载动画reshow不起作用,无法显示图表的bug
+- 示例项目 pages/ucharts/ucharts.vue 增加时间轴折线图(type="tline")、时间轴区域图(type="tarea")、散点图(type="scatter")、气泡图demo(type="bubble")、倒三角形漏斗图(opts.extra.funnel.type="triangle")、金字塔形漏斗图(opts.extra.funnel.type="pyramid")
+- 示例项目 pages/format-u/format-u.vue 增加X轴format格式化示例
+- uCharts.js 升级至v2.1.0版本
+- uCharts.js 修复 玫瑰图面积模式点击tooltip位置不正确的bug
+- uCharts.js 修复 玫瑰图点击图例,只剩一个类别显示空白的bug
+- uCharts.js 修复 饼图类图点击图例,其他图表tooltip位置某些情况下不准的bug
+- uCharts.js 修复 x轴为矢量轴(时间轴)情况下,点击tooltip位置不正确的bug
+- uCharts.js 修复 词云图获取点击索引偶尔不准的bug
+- uCharts.js 增加 直角坐标系图表X轴format格式化方法(原生uCharts.js用法请使用formatter)
+- uCharts.js 增加 漏斗图扩展配置,倒三角形(opts.extra.funnel.type="triangle"),金字塔形(opts.extra.funnel.type="pyramid")
+- uCharts.js 增加 散点图(opts.type="scatter")、气泡图(opts.type="bubble")
+- 后期计划 完善散点图、气泡图,增加markPoints标记点,增加横向条状图。
+## 2.0.0-20210502(2021-05-02)
+- uCharts.js 修复词云图获取点击索引不正确的bug
+## 2.0.0-20210501(2021-05-01)
+- 秋云图表组件 修复QQ小程序、百度小程序在关闭动画效果情况下,v-for循环使用图表,显示不正确的bug
+## 2.0.0-20210426(2021-04-26)
+- 秋云图表组件 修复QQ小程序不支持canvas2d的bug
+- 秋云图表组件 修复钉钉小程序某些情况点击坐标计算错误的bug
+- uCharts.js 增加 extra.column.categoryGap 参数,柱状图类每个category点位(X轴点)柱子组之间的间距
+- uCharts.js 增加 yAxis.data[i].titleOffsetY 参数,标题纵向偏移距离,负数为向上偏移,正数向下偏移
+- uCharts.js 增加 yAxis.data[i].titleOffsetX 参数,标题横向偏移距离,负数为向左偏移,正数向右偏移
+- uCharts.js 增加 extra.gauge.labelOffset 参数,仪表盘标签文字径向便宜距离,默认13px
+## 2.0.0-20210422-2(2021-04-22)
+秋云图表组件 修复 formatterAssign 未判断 args[key] == null 的情况导致栈溢出的 bug
+## 2.0.0-20210422(2021-04-22)
+- 秋云图表组件 修复H5、APP、支付宝小程序、微信小程序canvas2d模式下横屏模式的bug
+## 2.0.0-20210421(2021-04-21)
+- uCharts.js 修复多行图例的情况下,图例在上方或者下方时,图例float为左侧或者右侧时,第二行及以后的图例对齐方式不正确的bug
+## 2.0.0-20210420(2021-04-20)
+- 秋云图表组件 修复微信小程序开启canvas2d模式后,windows版微信小程序不支持canvas2d模式的bug
+- 秋云图表组件 修改非uni_modules版本为v2.0版本qiun-data-charts组件
+## 2.0.0-20210419(2021-04-19)
+## v1.0版本已停更,建议转uni_modules版本组件方式调用,点击右侧绿色【使用HBuilderX导入插件】即可使用,示例项目请点击右侧蓝色按钮【使用HBuilderX导入示例项目】。
+## 初次使用如果提示未注册&lt;qiun-data-charts&gt;组件,请重启HBuilderX,如仍不好用,请重启电脑;
+## 如果是cli项目,请尝试清理node_modules,重新install,还不行就删除项目,再重新install。
+## 此问题已于DCloud官方确认,HBuilderX下个版本会修复。
+## 其他图表不显示问题详见[常见问题选项卡](https://demo.ucharts.cn)
+## <font color=#FF0000> 新手请先完整阅读帮助文档及常见问题3遍,右侧蓝色按钮示例项目请看2遍! </font> 
+## [DEMO演示及在线生成工具(v2.0文档)https://demo.ucharts.cn](https://demo.ucharts.cn)
+## [图表组件在项目中的应用参见 UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651) 
+- uCharts.js 修复混合图中柱状图单独设置颜色不生效的bug
+- uCharts.js 修复多Y轴单独设置fontSize时,开启canvas2d后,未对应放大字体的bug
+## 2.0.0-20210418(2021-04-18)
+- 秋云图表组件 增加directory配置,修复H5端history模式下如果发布到二级目录无法正确加载echarts.min.js的bug
+## 2.0.0-20210416(2021-04-16)
+## v1.0版本已停更,建议转uni_modules版本组件方式调用,点击右侧绿色【使用HBuilderX导入插件】即可使用,示例项目请点击右侧蓝色按钮【使用HBuilderX导入示例项目】。
+## 初次使用如果提示未注册&lt;qiun-data-charts&gt;组件,请重启HBuilderX,如仍不好用,请重启电脑;
+## 如果是cli项目,请尝试清理node_modules,重新install,还不行就删除项目,再重新install。
+## 此问题已于DCloud官方确认,HBuilderX下个版本会修复。
+## 其他图表不显示问题详见[常见问题选项卡](https://demo.ucharts.cn)
+## <font color=#FF0000> 新手请先完整阅读帮助文档及常见问题3遍,右侧蓝色按钮示例项目请看2遍! </font> 
+## [DEMO演示及在线生成工具(v2.0文档)https://demo.ucharts.cn](https://demo.ucharts.cn)
+## [图表组件在项目中的应用参见 UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651) 
+- 秋云图表组件 修复APP端某些情况下报错`Not Found Page`的bug,fix by 高级bug开发技术员
+- 示例项目 修复APP端v-for循环某些情况下报错`Not Found Page`的bug,fix by 高级bug开发技术员
+- uCharts.js 修复非直角坐标系tooltip提示窗右侧超出未变换方向显示的bug
+## 2.0.0-20210415(2021-04-15)
+- 秋云图表组件 修复H5端发布到二级目录下echarts无法加载的bug
+- 秋云图表组件 修复某些情况下echarts.off('finished')移除监听事件报错的bug
+## 2.0.0-20210414(2021-04-14)
+## v1.0版本已停更,建议转uni_modules版本组件方式调用,点击右侧绿色【使用HBuilderX导入插件】即可使用,示例项目请点击右侧蓝色按钮【使用HBuilderX导入示例项目】。
+## 初次使用如果提示未注册&lt;qiun-data-charts&gt;组件,请重启HBuilderX,如仍不好用,请重启电脑;
+## 如果是cli项目,请尝试清理node_modules,重新install,还不行就删除项目,再重新install。
+## 此问题已于DCloud官方确认,HBuilderX下个版本会修复。
+## 其他图表不显示问题详见[常见问题选项卡](https://demo.ucharts.cn)
+## <font color=#FF0000> 新手请先完整阅读帮助文档及常见问题3遍,右侧蓝色按钮示例项目请看2遍! </font> 
+## [DEMO演示及在线生成工具(v2.0文档)https://demo.ucharts.cn](https://demo.ucharts.cn)
+## [图表组件在项目中的应用参见 UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651) 
+- 秋云图表组件 修复H5端在cli项目下ECharts引用地址错误的bug
+- 示例项目 增加ECharts的formatter用法的示例(详见示例项目format-e.vue)
+- uCharts.js 增加圆环图中心背景色的配置extra.ring.centerColor
+- uCharts.js 修复微信小程序安卓端柱状图开启透明色后显示不正确的bug
+## 2.0.0-20210413(2021-04-13)
+- 秋云图表组件 修复百度小程序多个图表真机未能正确获取根元素dom尺寸的bug
+- 秋云图表组件 修复百度小程序横屏模式方向不正确的bug
+- 秋云图表组件 修改ontouch时,@getTouchStart@getTouchMove@getTouchEnd的触发条件
+- uCharts.js 修复饼图类数据格式series属性不生效的bug
+- uCharts.js 增加时序区域图 详见示例项目中ucharts.vue
+## 2.0.0-20210412-2(2021-04-12)
+## v1.0版本已停更,建议转uni_modules版本组件方式调用,点击右侧绿色【使用HBuilderX导入插件】即可使用,示例项目请点击右侧蓝色按钮【使用HBuilderX导入示例项目】。
+## 初次使用如果提示未注册&lt;qiun-data-charts&gt;组件,请重启HBuilderX。如仍不好用,请重启电脑,此问题已于DCloud官方确认,HBuilderX下个版本会修复。
+## [DEMO演示及在线生成工具(v2.0文档)https://demo.ucharts.cn](https://demo.ucharts.cn)
+## [图表组件在uniCloudAdmin中的应用 UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651) 
+- 秋云图表组件 修复uCharts在APP端横屏模式下不能正确渲染的bug
+- 示例项目 增加ECharts柱状图渐变色、圆角柱状图、横向柱状图(条状图)的示例
+## 2.0.0-20210412(2021-04-12)
+- 秋云图表组件 修复created中判断echarts导致APP端无法识别,改回mounted中判断echarts初始化
+- uCharts.js 修复2d模式下series.textOffset未乘像素比的bug
+## 2.0.0-20210411(2021-04-11)
+## v1.0版本已停更,建议转uni_modules版本组件方式调用,点击右侧绿色【使用HBuilderX导入插件】即可使用,示例项目请点击右侧蓝色按钮【使用HBuilderX导入示例项目】。
+## 初次使用如果提示未注册<qiun-data-charts>组件,请重启HBuilderX,并清空小程序开发者工具缓存。
+## [DEMO演示及在线生成工具(v2.0文档)https://demo.ucharts.cn](https://demo.ucharts.cn)
+## [图表组件在uniCloudAdmin中的应用 UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651) 
+- uCharts.js 折线图区域图增加connectNulls断点续连的功能,详见示例项目中ucharts.vue
+- 秋云图表组件 变更初始化方法为created,变更type2d默认值为true,优化2d模式下组件初始化后dom获取不到的bug
+- 秋云图表组件 修复左右布局时,右侧图表点击坐标错误的bug,修复tooltip柱状图自定义颜色显示object的bug
+## 2.0.0-20210410(2021-04-10)
+- 修复左右布局时,右侧图表点击坐标错误的bug,修复柱状图自定义颜色tooltip显示object的bug
+- 增加标记线及柱状图自定义颜色的demo
+## 2.0.0-20210409(2021-04-08)
+## v1.0版本已停更,建议转uni_modules版本组件方式调用,点击右侧【使用HBuilderX导入插件】即可体验,DEMO演示及在线生成工具(v2.0文档)[https://demo.ucharts.cn](https://demo.ucharts.cn)
+## 图表组件在uniCloudAdmin中的应用 [UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651) 
+- uCharts.js 修复钉钉小程序百度小程序measureText不准确的bug,修复2d模式下饼图类activeRadius为按比例放大的bug
+- 修复组件在支付宝小程序端点击位置不准确的bug
+## 2.0.0-20210408(2021-04-07)
+- 修复组件在支付宝小程序端不能显示的bug(目前支付宝小程不能点击交互,后续修复)
+- uCharts.js 修复高分屏下柱状图类,圆弧进度条 自定义宽度不能按比例放大的bug
+## 2.0.0-20210407(2021-04-06)
+## v1.0版本已停更,建议转uni_modules版本组件方式调用,点击右侧【使用HBuilderX导入插件】即可体验,DEMO演示及在线生成工具(v2.0文档)[https://demo.ucharts.cn](https://demo.ucharts.cn)
+## 增加 通过tofix和unit快速格式化y轴的demo add by `howcode`
+## 增加 图表组件在uniCloudAdmin中的应用 [UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651) 
+## 2.0.0-20210406(2021-04-05)
+# 秋云图表组件+uCharts v2.0版本同步上线,使用方法详见https://demo.ucharts.cn帮助页
+## 2.0.0(2021-04-05)
+# 秋云图表组件+uCharts v2.0版本同步上线,使用方法详见https://demo.ucharts.cn帮助页

ファイルの差分が大きいため隠しています
+ 1607 - 0
uni_modules/qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue


ファイルの差分が大きいため隠しています
+ 46 - 0
uni_modules/qiun-data-charts/components/qiun-error/qiun-error.vue


+ 162 - 0
uni_modules/qiun-data-charts/components/qiun-loading/loading1.vue

@@ -0,0 +1,162 @@
+<template>
+	 <view class="container loading1">
+		<view class="shape shape1"></view>
+		<view class="shape shape2"></view>
+		<view class="shape shape3"></view>
+		<view class="shape shape4"></view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'loading1',
+		data() {
+			return {
+				
+			};
+		}
+	}
+</script>
+
+<style scoped="true">
+.container {
+  width: 30px;
+  height: 30px;
+  position: relative;
+}
+.container.loading1 {
+  -webkit-transform: rotate(45deg);
+          transform: rotate(45deg);
+}
+
+.container .shape {
+  position: absolute;
+  width: 10px;
+  height: 10px;
+  border-radius: 1px;
+}
+.container .shape.shape1 {
+  left: 0;
+  background-color: #1890FF;
+}
+.container .shape.shape2 {
+  right: 0;
+  background-color: #91CB74;
+}
+.container .shape.shape3 {
+  bottom: 0;
+  background-color: #FAC858;
+}
+.container .shape.shape4 {
+  bottom: 0;
+  right: 0;
+  background-color: #EE6666;
+}
+
+.loading1 .shape1 {
+  -webkit-animation: animation1shape1 0.5s ease 0s infinite alternate;
+          animation: animation1shape1 0.5s ease 0s infinite alternate;
+}
+
+@-webkit-keyframes animation1shape1 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(16px, 16px);
+            transform: translate(16px, 16px);
+  }
+}
+
+@keyframes animation1shape1 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(16px, 16px);
+            transform: translate(16px, 16px);
+  }
+}
+.loading1 .shape2 {
+  -webkit-animation: animation1shape2 0.5s ease 0s infinite alternate;
+          animation: animation1shape2 0.5s ease 0s infinite alternate;
+}
+
+@-webkit-keyframes animation1shape2 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(-16px, 16px);
+            transform: translate(-16px, 16px);
+  }
+}
+
+@keyframes animation1shape2 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(-16px, 16px);
+            transform: translate(-16px, 16px);
+  }
+}
+.loading1 .shape3 {
+  -webkit-animation: animation1shape3 0.5s ease 0s infinite alternate;
+          animation: animation1shape3 0.5s ease 0s infinite alternate;
+}
+
+@-webkit-keyframes animation1shape3 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(16px, -16px);
+            transform: translate(16px, -16px);
+  }
+}
+
+@keyframes animation1shape3 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(16px, -16px);
+            transform: translate(16px, -16px);
+  }
+}
+.loading1 .shape4 {
+  -webkit-animation: animation1shape4 0.5s ease 0s infinite alternate;
+          animation: animation1shape4 0.5s ease 0s infinite alternate;
+}
+
+@-webkit-keyframes animation1shape4 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(-16px, -16px);
+            transform: translate(-16px, -16px);
+  }
+}
+
+@keyframes animation1shape4 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(-16px, -16px);
+            transform: translate(-16px, -16px);
+  }
+}
+
+
+</style>

+ 170 - 0
uni_modules/qiun-data-charts/components/qiun-loading/loading2.vue

@@ -0,0 +1,170 @@
+<template>
+	 <view class="container loading2">
+		<view class="shape shape1"></view>
+		<view class="shape shape2"></view>
+		<view class="shape shape3"></view>
+		<view class="shape shape4"></view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'loading2',
+		data() {
+			return {
+				
+			};
+		}
+	}
+</script>
+
+<style scoped="true">
+.container {
+  width: 30px;
+  height: 30px;
+  position: relative;
+}
+
+.container.loading2 {
+  -webkit-transform: rotate(10deg);
+          transform: rotate(10deg);
+}
+.container.loading2 .shape {
+  border-radius: 5px;
+}
+.container.loading2{
+  -webkit-animation: rotation 1s infinite;
+          animation: rotation 1s infinite;
+}
+
+.container .shape {
+  position: absolute;
+  width: 10px;
+  height: 10px;
+  border-radius: 1px;
+}
+.container .shape.shape1 {
+  left: 0;
+  background-color: #1890FF;
+}
+.container .shape.shape2 {
+  right: 0;
+  background-color: #91CB74;
+}
+.container .shape.shape3 {
+  bottom: 0;
+  background-color: #FAC858;
+}
+.container .shape.shape4 {
+  bottom: 0;
+  right: 0;
+  background-color: #EE6666;
+}
+
+
+.loading2 .shape1 {
+  -webkit-animation: animation2shape1 0.5s ease 0s infinite alternate;
+          animation: animation2shape1 0.5s ease 0s infinite alternate;
+}
+
+@-webkit-keyframes animation2shape1 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(20px, 20px);
+            transform: translate(20px, 20px);
+  }
+}
+
+@keyframes animation2shape1 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(20px, 20px);
+            transform: translate(20px, 20px);
+  }
+}
+.loading2 .shape2 {
+  -webkit-animation: animation2shape2 0.5s ease 0s infinite alternate;
+          animation: animation2shape2 0.5s ease 0s infinite alternate;
+}
+
+@-webkit-keyframes animation2shape2 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(-20px, 20px);
+            transform: translate(-20px, 20px);
+  }
+}
+
+@keyframes animation2shape2 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(-20px, 20px);
+            transform: translate(-20px, 20px);
+  }
+}
+.loading2 .shape3 {
+  -webkit-animation: animation2shape3 0.5s ease 0s infinite alternate;
+          animation: animation2shape3 0.5s ease 0s infinite alternate;
+}
+
+@-webkit-keyframes animation2shape3 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(20px, -20px);
+            transform: translate(20px, -20px);
+  }
+}
+
+@keyframes animation2shape3 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(20px, -20px);
+            transform: translate(20px, -20px);
+  }
+}
+.loading2 .shape4 {
+  -webkit-animation: animation2shape4 0.5s ease 0s infinite alternate;
+          animation: animation2shape4 0.5s ease 0s infinite alternate;
+}
+
+@-webkit-keyframes animation2shape4 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(-20px, -20px);
+            transform: translate(-20px, -20px);
+  }
+}
+
+@keyframes animation2shape4 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(-20px, -20px);
+            transform: translate(-20px, -20px);
+  }
+}
+
+</style>

+ 173 - 0
uni_modules/qiun-data-charts/components/qiun-loading/loading3.vue

@@ -0,0 +1,173 @@
+<template>
+	 <view class="container loading3">
+		<view class="shape shape1"></view>
+		<view class="shape shape2"></view>
+		<view class="shape shape3"></view>
+		<view class="shape shape4"></view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'loading3',
+		data() {
+			return {
+				
+			};
+		}
+	}
+</script>
+
+<style scoped="true">
+.container {
+  width: 30px;
+  height: 30px;
+  position: relative;
+}
+
+ .container.loading3 {
+  -webkit-animation: rotation 1s infinite;
+          animation: rotation 1s infinite;
+}
+.container.loading3 .shape1 {
+  border-top-left-radius: 10px;
+}
+.container.loading3 .shape2 {
+  border-top-right-radius: 10px;
+}
+.container.loading3 .shape3 {
+  border-bottom-left-radius: 10px;
+}
+.container.loading3 .shape4 {
+  border-bottom-right-radius: 10px;
+}
+
+.container .shape {
+  position: absolute;
+  width: 10px;
+  height: 10px;
+  border-radius: 1px;
+}
+.container .shape.shape1 {
+  left: 0;
+  background-color: #1890FF;
+}
+.container .shape.shape2 {
+  right: 0;
+  background-color: #91CB74;
+}
+.container .shape.shape3 {
+  bottom: 0;
+  background-color: #FAC858;
+}
+.container .shape.shape4 {
+  bottom: 0;
+  right: 0;
+  background-color: #EE6666;
+}
+
+.loading3 .shape1 {
+  -webkit-animation: animation3shape1 0.5s ease 0s infinite alternate;
+          animation: animation3shape1 0.5s ease 0s infinite alternate;
+}
+
+@-webkit-keyframes animation3shape1 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(5px, 5px);
+            transform: translate(5px, 5px);
+  }
+}
+
+@keyframes animation3shape1 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(5px, 5px);
+            transform: translate(5px, 5px);
+  }
+}
+.loading3 .shape2 {
+  -webkit-animation: animation3shape2 0.5s ease 0s infinite alternate;
+          animation: animation3shape2 0.5s ease 0s infinite alternate;
+}
+
+@-webkit-keyframes animation3shape2 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(-5px, 5px);
+            transform: translate(-5px, 5px);
+  }
+}
+
+@keyframes animation3shape2 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(-5px, 5px);
+            transform: translate(-5px, 5px);
+  }
+}
+.loading3 .shape3 {
+  -webkit-animation: animation3shape3 0.5s ease 0s infinite alternate;
+          animation: animation3shape3 0.5s ease 0s infinite alternate;
+}
+
+@-webkit-keyframes animation3shape3 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(5px, -5px);
+            transform: translate(5px, -5px);
+  }
+}
+
+@keyframes animation3shape3 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(5px, -5px);
+            transform: translate(5px, -5px);
+  }
+}
+.loading3 .shape4 {
+  -webkit-animation: animation3shape4 0.5s ease 0s infinite alternate;
+          animation: animation3shape4 0.5s ease 0s infinite alternate;
+}
+
+@-webkit-keyframes animation3shape4 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(-5px, -5px);
+            transform: translate(-5px, -5px);
+  }
+}
+
+@keyframes animation3shape4 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(-5px, -5px);
+            transform: translate(-5px, -5px);
+  }
+}
+</style>

+ 222 - 0
uni_modules/qiun-data-charts/components/qiun-loading/loading4.vue

@@ -0,0 +1,222 @@
+<template>
+	 <view class="container loading5">
+		<view class="shape shape1"></view>
+		<view class="shape shape2"></view>
+		<view class="shape shape3"></view>
+		<view class="shape shape4"></view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'loading4',
+		data() {
+			return {
+				
+			};
+		}
+	}
+</script>
+
+<style scoped="true">
+.container {
+  width: 30px;
+  height: 30px;
+  position: relative;
+}
+
+.container.loading5 .shape {
+  width: 15px;
+  height: 15px;
+}
+
+.container .shape {
+  position: absolute;
+  width: 10px;
+  height: 10px;
+  border-radius: 1px;
+}
+.container .shape.shape1 {
+  left: 0;
+  background-color: #1890FF;
+}
+.container .shape.shape2 {
+  right: 0;
+  background-color: #91CB74;
+}
+.container .shape.shape3 {
+  bottom: 0;
+  background-color: #FAC858;
+}
+.container .shape.shape4 {
+  bottom: 0;
+  right: 0;
+  background-color: #EE6666;
+}
+
+.loading5 .shape1 {
+  animation: animation5shape1 2s ease 0s infinite reverse;
+}
+
+@-webkit-keyframes animation5shape1 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(0, 15px);
+            transform: translate(0, 15px);
+  }
+  50% {
+    -webkit-transform: translate(15px, 15px);
+            transform: translate(15px, 15px);
+  }
+  75% {
+    -webkit-transform: translate(15px, 0);
+            transform: translate(15px, 0);
+  }
+}
+
+@keyframes animation5shape1 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(0, 15px);
+            transform: translate(0, 15px);
+  }
+  50% {
+    -webkit-transform: translate(15px, 15px);
+            transform: translate(15px, 15px);
+  }
+  75% {
+    -webkit-transform: translate(15px, 0);
+            transform: translate(15px, 0);
+  }
+}
+.loading5 .shape2 {
+  animation: animation5shape2 2s ease 0s infinite reverse;
+}
+
+@-webkit-keyframes animation5shape2 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(-15px, 0);
+            transform: translate(-15px, 0);
+  }
+  50% {
+    -webkit-transform: translate(-15px, 15px);
+            transform: translate(-15px, 15px);
+  }
+  75% {
+    -webkit-transform: translate(0, 15px);
+            transform: translate(0, 15px);
+  }
+}
+
+@keyframes animation5shape2 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(-15px, 0);
+            transform: translate(-15px, 0);
+  }
+  50% {
+    -webkit-transform: translate(-15px, 15px);
+            transform: translate(-15px, 15px);
+  }
+  75% {
+    -webkit-transform: translate(0, 15px);
+            transform: translate(0, 15px);
+  }
+}
+.loading5 .shape3 {
+  animation: animation5shape3 2s ease 0s infinite reverse;
+}
+
+@-webkit-keyframes animation5shape3 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(15px, 0);
+            transform: translate(15px, 0);
+  }
+  50% {
+    -webkit-transform: translate(15px, -15px);
+            transform: translate(15px, -15px);
+  }
+  75% {
+    -webkit-transform: translate(0, -15px);
+            transform: translate(0, -15px);
+  }
+}
+
+@keyframes animation5shape3 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(15px, 0);
+            transform: translate(15px, 0);
+  }
+  50% {
+    -webkit-transform: translate(15px, -15px);
+            transform: translate(15px, -15px);
+  }
+  75% {
+    -webkit-transform: translate(0, -15px);
+            transform: translate(0, -15px);
+  }
+}
+.loading5 .shape4 {
+  animation: animation5shape4 2s ease 0s infinite reverse;
+}
+
+@-webkit-keyframes animation5shape4 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(0, -15px);
+            transform: translate(0, -15px);
+  }
+  50% {
+    -webkit-transform: translate(-15px, -15px);
+            transform: translate(-15px, -15px);
+  }
+  75% {
+    -webkit-transform: translate(-15px, 0);
+            transform: translate(-15px, 0);
+  }
+}
+
+@keyframes animation5shape4 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(0, -15px);
+            transform: translate(0, -15px);
+  }
+  50% {
+    -webkit-transform: translate(-15px, -15px);
+            transform: translate(-15px, -15px);
+  }
+  75% {
+    -webkit-transform: translate(-15px, 0);
+            transform: translate(-15px, 0);
+  }
+}
+
+</style>

+ 229 - 0
uni_modules/qiun-data-charts/components/qiun-loading/loading5.vue

@@ -0,0 +1,229 @@
+<template>
+	 <view class="container loading6">
+		<view class="shape shape1"></view>
+		<view class="shape shape2"></view>
+		<view class="shape shape3"></view>
+		<view class="shape shape4"></view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'loading5',
+		data() {
+			return {
+				
+			};
+		}
+	}
+</script>
+<style scoped="true">
+.container {
+  width: 30px;
+  height: 30px;
+  position: relative;
+}
+
+.container.loading6 {
+  -webkit-animation: rotation 1s infinite;
+          animation: rotation 1s infinite;
+}
+.container.loading6 .shape {
+  width: 12px;
+  height: 12px;
+  border-radius: 2px;
+}
+.container .shape {
+  position: absolute;
+  width: 10px;
+  height: 10px;
+  border-radius: 1px;
+}
+.container .shape.shape1 {
+  left: 0;
+  background-color: #1890FF;
+}
+.container .shape.shape2 {
+  right: 0;
+  background-color: #91CB74;
+}
+.container .shape.shape3 {
+  bottom: 0;
+  background-color: #FAC858;
+}
+.container .shape.shape4 {
+  bottom: 0;
+  right: 0;
+  background-color: #EE6666;
+}
+
+
+.loading6 .shape1 {
+  -webkit-animation: animation6shape1 2s linear 0s infinite normal;
+          animation: animation6shape1 2s linear 0s infinite normal;
+}
+
+@-webkit-keyframes animation6shape1 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(0, 18px);
+            transform: translate(0, 18px);
+  }
+  50% {
+    -webkit-transform: translate(18px, 18px);
+            transform: translate(18px, 18px);
+  }
+  75% {
+    -webkit-transform: translate(18px, 0);
+            transform: translate(18px, 0);
+  }
+}
+
+@keyframes animation6shape1 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(0, 18px);
+            transform: translate(0, 18px);
+  }
+  50% {
+    -webkit-transform: translate(18px, 18px);
+            transform: translate(18px, 18px);
+  }
+  75% {
+    -webkit-transform: translate(18px, 0);
+            transform: translate(18px, 0);
+  }
+}
+.loading6 .shape2 {
+  -webkit-animation: animation6shape2 2s linear 0s infinite normal;
+          animation: animation6shape2 2s linear 0s infinite normal;
+}
+
+@-webkit-keyframes animation6shape2 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(-18px, 0);
+            transform: translate(-18px, 0);
+  }
+  50% {
+    -webkit-transform: translate(-18px, 18px);
+            transform: translate(-18px, 18px);
+  }
+  75% {
+    -webkit-transform: translate(0, 18px);
+            transform: translate(0, 18px);
+  }
+}
+
+@keyframes animation6shape2 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(-18px, 0);
+            transform: translate(-18px, 0);
+  }
+  50% {
+    -webkit-transform: translate(-18px, 18px);
+            transform: translate(-18px, 18px);
+  }
+  75% {
+    -webkit-transform: translate(0, 18px);
+            transform: translate(0, 18px);
+  }
+}
+.loading6 .shape3 {
+  -webkit-animation: animation6shape3 2s linear 0s infinite normal;
+          animation: animation6shape3 2s linear 0s infinite normal;
+}
+
+@-webkit-keyframes animation6shape3 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(18px, 0);
+            transform: translate(18px, 0);
+  }
+  50% {
+    -webkit-transform: translate(18px, -18px);
+            transform: translate(18px, -18px);
+  }
+  75% {
+    -webkit-transform: translate(0, -18px);
+            transform: translate(0, -18px);
+  }
+}
+
+@keyframes animation6shape3 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(18px, 0);
+            transform: translate(18px, 0);
+  }
+  50% {
+    -webkit-transform: translate(18px, -18px);
+            transform: translate(18px, -18px);
+  }
+  75% {
+    -webkit-transform: translate(0, -18px);
+            transform: translate(0, -18px);
+  }
+}
+.loading6 .shape4 {
+  -webkit-animation: animation6shape4 2s linear 0s infinite normal;
+          animation: animation6shape4 2s linear 0s infinite normal;
+}
+
+@-webkit-keyframes animation6shape4 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(0, -18px);
+            transform: translate(0, -18px);
+  }
+  50% {
+    -webkit-transform: translate(-18px, -18px);
+            transform: translate(-18px, -18px);
+  }
+  75% {
+    -webkit-transform: translate(-18px, 0);
+            transform: translate(-18px, 0);
+  }
+}
+
+@keyframes animation6shape4 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(0, -18px);
+            transform: translate(0, -18px);
+  }
+  50% {
+    -webkit-transform: translate(-18px, -18px);
+            transform: translate(-18px, -18px);
+  }
+  75% {
+    -webkit-transform: translate(-18px, 0);
+            transform: translate(-18px, 0);
+  }
+}
+</style>

+ 36 - 0
uni_modules/qiun-data-charts/components/qiun-loading/qiun-loading.vue

@@ -0,0 +1,36 @@
+<template>
+	<view>
+	 <Loading1 v-if="loadingType==1"/>
+	 <Loading2 v-if="loadingType==2"/>
+	 <Loading3 v-if="loadingType==3"/>
+	 <Loading4 v-if="loadingType==4"/>
+	 <Loading5 v-if="loadingType==5"/>
+	</view>
+</template>
+
+<script>
+	import Loading1 from "./loading1.vue";
+	import Loading2 from "./loading2.vue";
+	import Loading3 from "./loading3.vue";
+	import Loading4 from "./loading4.vue";
+	import Loading5 from "./loading5.vue";
+	export default {
+		components:{Loading1,Loading2,Loading3,Loading4,Loading5},
+		name: 'qiun-loading',
+		props: {
+			loadingType: {
+				type: Number,
+				default: 4
+			},
+		},
+		data() {
+			return {
+				
+			};
+		},
+	}
+</script>
+
+<style>
+
+</style>

+ 422 - 0
uni_modules/qiun-data-charts/js_sdk/u-charts/config-echarts.js

@@ -0,0 +1,422 @@
+/*
+ * uCharts®
+ * 高性能跨平台图表库,支持H5、APP、小程序(微信/支付宝/百度/头条/QQ/360)、Vue、Taro等支持canvas的框架平台
+ * Copyright (c) 2021 QIUN®秋云 https://www.ucharts.cn All rights reserved.
+ * Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+ * 复制使用请保留本段注释,感谢支持开源!
+ * 
+ * uCharts®官方网站
+ * https://www.uCharts.cn
+ * 
+ * 开源地址:
+ * https://gitee.com/uCharts/uCharts
+ * 
+ * uni-app插件市场地址:
+ * http://ext.dcloud.net.cn/plugin?id=271
+ * 
+ */
+
+// 通用配置项
+
+// 主题颜色配置:如每个图表类型需要不同主题,请在对应图表类型上更改color属性
+const color = ['#1890FF', '#91CB74', '#FAC858', '#EE6666', '#73C0DE', '#3CA272', '#FC8452', '#9A60B4', '#ea7ccc'];
+
+const cfe = {
+  //demotype为自定义图表类型
+	"type": ["pie", "ring", "rose", "funnel", "line", "column", "area", "radar", "gauge","candle","demotype"],
+  //增加自定义图表类型,如果需要categories,请在这里加入您的图表类型例如最后的"demotype"
+	"categories": ["line", "column", "area", "radar", "gauge", "candle","demotype"],
+  //instance为实例变量承载属性,option为eopts承载属性,不要删除
+	"instance": {},
+	"option": {},
+  //下面是自定义format配置,因除H5端外的其他端无法通过props传递函数,只能通过此属性对应下标的方式来替换
+  "formatter":{
+    "tooltipDemo1":function(res){
+      let result = ''
+      for (let i in res) {
+      	if (i == 0) {
+      		result += res[i].axisValueLabel + '年销售额'
+      	}
+      	let value = '--'
+      	if (res[i].data !== null) {
+      		value = res[i].data
+      	}
+      	// #ifdef H5
+      	result += '\n' + res[i].seriesName + ':' + value + ' 万元'
+      	// #endif
+      	
+      	// #ifdef APP-PLUS
+      	result += '<br/>' + res[i].marker + res[i].seriesName + ':' + value + ' 万元'
+      	// #endif
+      }
+      return result;
+    },
+    legendFormat:function(name){
+      return "自定义图例+"+name;
+    },
+    yAxisFormatDemo:function (value, index) {
+      return value + '元';
+    },
+    seriesFormatDemo:function(res){
+      return res.name + '年' + res.value + '元';
+    }
+  },
+  //这里演示了自定义您的图表类型的option,可以随意命名,之后在组件上 type="demotype" 后,组件会调用这个花括号里的option,如果组件上还存在eopts参数,会将demotype与eopts中option合并后渲染图表。
+  "demotype":{
+    "color": color,
+    //在这里填写echarts的option即可
+    
+  },
+  //下面是自定义配置,请添加项目所需的通用配置
+	"column": {
+		"color": color,
+		"title": {
+			"text": ''
+		},
+		"tooltip": {
+			"trigger": 'axis'
+		},
+		"grid": {
+			"top": 30,
+			"bottom": 50,
+			"right": 15,
+			"left": 40
+		},
+		"legend": {
+			"bottom": 'left',
+		},
+		"toolbox": {
+			"show": false,
+		},
+		"xAxis": {
+			"type": 'category',
+			"axisLabel": {
+				"color": '#666666'
+			},
+			"axisLine": {
+				"lineStyle": {
+					"color": '#CCCCCC'
+				}
+			},
+			"boundaryGap": true,
+			"data": []
+		},
+		"yAxis": {
+			"type": 'value',
+			"axisTick": {
+				"show": false,
+			},
+			"axisLabel": {
+				"color": '#666666'
+			},
+			"axisLine": {
+				"lineStyle": {
+					"color": '#CCCCCC'
+				}
+			},
+		},
+		"seriesTemplate": {
+			"name": '',
+			"type": 'bar',
+			"data": [],
+			"barwidth": 20,
+			"label": {
+				"show": true,
+        "color": "#666666",
+				"position": 'top',
+			},
+		},
+	},
+	"line": {
+		"color": color,
+		"title": {
+			"text": ''
+		},
+		"tooltip": {
+			"trigger": 'axis'
+		},
+		"grid": {
+			"top": 30,
+			"bottom": 50,
+			"right": 15,
+			"left": 40
+		},
+		"legend": {
+			"bottom": 'left',
+		},
+		"toolbox": {
+			"show": false,
+		},
+		"xAxis": {
+			"type": 'category',
+			"axisLabel": {
+				"color": '#666666'
+			},
+			"axisLine": {
+				"lineStyle": {
+					"color": '#CCCCCC'
+				}
+			},
+			"boundaryGap": true,
+			"data": []
+		},
+		"yAxis": {
+			"type": 'value',
+			"axisTick": {
+				"show": false,
+			},
+			"axisLabel": {
+				"color": '#666666'
+			},
+			"axisLine": {
+				"lineStyle": {
+					"color": '#CCCCCC'
+				}
+			},
+		},
+		"seriesTemplate": {
+			"name": '',
+			"type": 'line',
+			"data": [],
+			"barwidth": 20,
+			"label": {
+				"show": true,
+        "color": "#666666",
+				"position": 'top',
+			},
+		},
+	},
+	"area": {
+		"color": color,
+		"title": {
+			"text": ''
+		},
+		"tooltip": {
+			"trigger": 'axis'
+		},
+		"grid": {
+			"top": 30,
+			"bottom": 50,
+			"right": 15,
+			"left": 40
+		},
+		"legend": {
+			"bottom": 'left',
+		},
+		"toolbox": {
+			"show": false,
+		},
+		"xAxis": {
+			"type": 'category',
+			"axisLabel": {
+				"color": '#666666'
+			},
+			"axisLine": {
+				"lineStyle": {
+					"color": '#CCCCCC'
+				}
+			},
+			"boundaryGap": true,
+			"data": []
+		},
+		"yAxis": {
+			"type": 'value',
+			"axisTick": {
+				"show": false,
+			},
+			"axisLabel": {
+				"color": '#666666'
+			},
+			"axisLine": {
+				"lineStyle": {
+					"color": '#CCCCCC'
+				}
+			},
+		},
+		"seriesTemplate": {
+			"name": '',
+			"type": 'line',
+			"data": [],
+			"areaStyle": {},
+			"label": {
+				"show": true,
+        "color": "#666666",
+				"position": 'top',
+			},
+		},
+	},
+	"pie": {
+		"color": color,
+		"title": {
+			"text": ''
+		},
+		"tooltip": {
+			"trigger": 'item'
+		},
+		"grid": {
+			"top": 40,
+			"bottom": 30,
+			"right": 15,
+			"left": 15
+		},
+		"legend": {
+			"bottom": 'left',
+		},
+		"seriesTemplate": {
+			"name": '',
+			"type": 'pie',
+			"data": [],
+			"radius": '50%',
+			"label": {
+				"show": true,
+        "color": "#666666",
+				"position": 'top',
+			},
+		},
+	},
+	"ring": {
+		"color": color,
+		"title": {
+			"text": ''
+		},
+		"tooltip": {
+			"trigger": 'item'
+		},
+		"grid": {
+			"top": 40,
+			"bottom": 30,
+			"right": 15,
+			"left": 15
+		},
+		"legend": {
+			"bottom": 'left',
+		},
+		"seriesTemplate": {
+			"name": '',
+			"type": 'pie',
+			"data": [],
+			"radius": ['40%', '70%'],
+			"avoidLabelOverlap": false,
+			"label": {
+				"show": true,
+        "color": "#666666",
+				"position": 'top',
+			},
+			"labelLine": {
+				"show": true
+			},
+		},
+	},
+	"rose": {
+		"color": color,
+		"title": {
+			"text": ''
+		},
+		"tooltip": {
+			"trigger": 'item'
+		},
+		"legend": {
+			"top": 'bottom'
+		},
+		"seriesTemplate": {
+			"name": '',
+			"type": 'pie',
+			"data": [],
+			"radius": "55%",
+			"center": ['50%', '50%'],
+			"roseType": 'area',
+		},
+	},
+	"funnel": {
+		"color": color,
+		"title": {
+			"text": ''
+		},
+		"tooltip": {
+			"trigger": 'item',
+			"formatter": "{b} : {c}%"
+		},
+		"legend": {
+			"top": 'bottom'
+		},
+		"seriesTemplate": {
+			"name": '',
+			"type": 'funnel',
+			"left": '10%',
+			"top": 60,
+			"bottom": 60,
+			"width": '80%',
+			"min": 0,
+			"max": 100,
+			"minSize": '0%',
+			"maxSize": '100%',
+			"sort": 'descending',
+			"gap": 2,
+			"label": {
+				"show": true,
+				"position": 'inside'
+			},
+			"labelLine": {
+				"length": 10,
+				"lineStyle": {
+					"width": 1,
+					"type": 'solid'
+				}
+			},
+			"itemStyle": {
+				"bordercolor": '#fff',
+				"borderwidth": 1
+			},
+			"emphasis": {
+				"label": {
+					"fontSize": 20
+				}
+			},
+			"data": [],
+		},
+	},
+	"gauge": {
+		"color": color,
+		"tooltip": {
+        "formatter": '{a} <br/>{b} : {c}%'
+    },
+		"seriesTemplate": {
+			"name": '业务指标',
+      "type": 'gauge',
+      "detail": {"formatter": '{value}%'},
+      "data": [{"value": 50, "name": '完成率'}]
+		},
+	},
+	"candle": {
+		"xAxis": {
+			"data": []
+		},
+		"yAxis": {},
+		"color": color,
+		"title": {
+			"text": ''
+		},
+		"dataZoom": [{
+				"type": 'inside',
+				"xAxisIndex": [0, 1],
+				"start": 10,
+				"end": 100
+			},
+			{
+				"show": true,
+				"xAxisIndex": [0, 1],
+				"type": 'slider',
+				"bottom": 10,
+				"start": 10,
+				"end": 100
+			}
+		],
+		"seriesTemplate": {
+			"name": '',
+			"type": 'k',
+			"data": [],
+		},
+	}
+}
+
+export default cfe;

+ 676 - 0
uni_modules/qiun-data-charts/js_sdk/u-charts/config-ucharts.js

@@ -0,0 +1,676 @@
+// 主题颜色配置:如每个图表类型需要不同主题,请在对应图表类型上更改color属性
+const color = ["#4169E1", "#ff5959", "#f9c752", "#d8deff", "#23b46c", "#ff8caf", "#FC8452", "#9A60B4"];
+// 提示窗配置
+const tooltip = {
+	"showBox": true,
+	"showArrow": false,
+	"showCategory": false,
+	"borderRadius": 6,
+	"bgOpacity": 0.5,
+	"splitLine": true,
+	"gridType": "dash",
+	"dashLength": 24,
+};
+//x轴配置
+const X = {
+	"disableGrid": true,
+	"fontSize": 11,
+	"scrollColor": "#F5F5F5",
+	"scrollBackgroundColor": "#D3D3D3",
+	"itemCount": 6,
+	"format": ""
+};
+//y轴配置
+const Y = {
+	"data": [{
+		// "fontSize": 11,
+		// "min": 0,
+		axisLine: false,
+	}]
+};
+//图例配置
+const legend = {
+	"show": true,
+	"position": "top",
+	"float": "right",
+	"padding": 5,
+	"margin": 15,
+	"fontSize": 13,
+};
+//标记线配置
+const markLine = {
+	"type": "solid",
+	"dashLength": 20,
+	"data": [{
+		"value": 100,
+		"lineColor": "#666",
+		"showLabel": true,
+		"labelFontColor": "#666",
+		"labelBgColor": "#FFF",
+		"labelBgOpacity": 0,
+		"yAxisIndex": 0
+	}]
+};
+const padding = [
+	0, 10, 20, 5
+]
+
+//事件转换函数,主要用作格式化x轴为时间轴,根据需求自行修改
+const formatDateTime = (timeStamp, returnType) => {
+	var date = new Date();
+	date.setTime(timeStamp * 1000);
+	var y = date.getFullYear();
+	var m = date.getMonth() + 1;
+	m = m < 10 ? ('0' + m) : m;
+	var d = date.getDate();
+	d = d < 10 ? ('0' + d) : d;
+	var h = date.getHours();
+	h = h < 10 ? ('0' + h) : h;
+	var minute = date.getMinutes();
+	var second = date.getSeconds();
+	minute = minute < 10 ? ('0' + minute) : minute;
+	second = second < 10 ? ('0' + second) : second;
+	if (returnType == 'full') {
+		return y + '-' + m + '-' + d + ' ' + h + ':' + minute + ':' + second;
+	}
+	if (returnType == 'y-m-d') {
+		return y + '-' + m + '-' + d;
+	}
+	if (returnType == 'h:m') {
+		return h + ':' + minute;
+	}
+	if (returnType == 'h:m:s') {
+		return h + ':' + minute + ':' + second;
+	}
+	return [y, m, d, h, minute, second];
+}
+
+const cfu = {
+	//demotype为自定义图表类型,一般不需要自定义图表类型,只需要改根节点上对应的类型即可
+	"type": ["pie", "ring", "rose", "arcbar", "line", "column", "area", "radar", "mainline", "mini-line",
+		"mini-area", "mini-column", "mini-rose", "mount", "bar"
+	],
+	"range": [],
+	//增加自定义图表类型,如果需要categories,请在这里加入您的图表类型,例如最后的"demotype"
+	//自定义类型时需要注意"tline","tarea","scatter","bubble"等时间轴(矢量x轴)类图表,没有categories,不需要加入categories
+	"categories": ["line", "column", "bar", "area", "radar", "mainline", "mini-line", "mini-area", "mini-column",
+		"mount", "bar"
+	],
+	//instance为实例变量承载属性,不要删除
+	"instance": {},
+	//option为opts及eopts承载属性,不要删除
+	"option": {},
+	//下面是自定义format配置,因除H5端外的其他端无法通过props传递函数,只能通过此属性对应下标的方式来替换
+	"formatter": {
+		"tooltipScore": function(item, category, index, opts) {
+			return category + ' ' + item.name + ': ' + item.data + ' 分 '
+		},
+		"tooltipScoreShort": function(item, category, index, opts) {
+			return item.name + '得分率: ' + item.data + ' % '
+		},
+		"HomeworkPercent": function(item, category, index, opts) {
+			return category.replace('-', '月') + '日 ' + item.name + ' ' + item.data + ' % '
+		},
+		"tooltipHourColum": function(item, category, index, opts) {
+			return category.replace('-', '月') + '日 ' + item.name + ': ' + item.data + ' 小时 '
+		},
+		"pieHour": function(item, category, index, opts) {
+			return item.name.replace('-', '月') + '日 ' + item.data + '小时'
+		},
+		"pieMinute": function(item, category, index, opts) {
+			return item.name.replace('-', '月') + '日 ' + item.data + '分钟'
+		},
+		"sleepExerciseCom": function(item, category, index, opts) {
+			let value = item.data <= 20 ? (item.data >= 10 ? '分配科学' : '运动量少') : '运动过量'
+			return '运动占睡眠: ' + item.data + '% ' + value
+		},
+		"subjectRankColum": function(item, category, index, opts) {
+			return category + ' ' + item.name + '超过 ' + item.data + '% 的学生'
+		},
+		"subjectRankArea": function(item, category, index, opts) {
+			return category + ' ' + item.name + item.data + '% 的学生'
+		},
+		"distributionColumn": function(item, category, index, opts) {
+			return category + '分 ' + item.name + ' ' + item.data + ' 人 '
+		},
+		"meritsRadar": function(item, category, index, opts) {
+			return category + ' ' + item.name + ' ' + item.data + ' % '
+		},
+		"xAxisBar": function(val, index, opts) {
+			return parseInt(val).toFixed(0) + '%'
+		},
+	},
+	//这里演示了自定义您的图表类型的option,可以随意命名,之后在组件上 type="demotype" 后,组件会调用这个花括号里的option,如果组件上还存在opts参数,会将demotype与opts中option合并后渲染图表。
+	//下面是自定义配置,请添加项目所需的通用配置
+	"line": {
+		"type": "line",
+		"animation": true,
+		"timing": "easeOut",
+		"duration": 500,
+		"color": color,
+		"padding": padding,
+		"dataLabel": false,
+		"fontSize": 12,
+		"xAxis": X,
+		"yAxis": Y,
+		"enableScroll": true,
+		"touchMoveLimit": 60,
+		"legend": legend,
+		"extra": {
+			"line": {
+				"type": "curve",
+				"width": 2
+			},
+			"tooltip": tooltip,
+		}
+	},
+	"column": {
+		"type": "column",
+		"animation": true,
+		"timing": "easeOut",
+		"duration": 500,
+		"color": color,
+		"padding": padding,
+		"dataLabel": false,
+		"fontSize": 12,
+		"xAxis": X,
+		"yAxis": Y,
+		"enableScroll": true,
+		"touchMoveLimit": 60,
+		"legend": legend,
+		"extra": {
+			"column": {
+				"type": "group",
+				"width": 17,
+				"seriesGap": 3,
+				"categoryGap": 5,
+				"barBorderCircle": true,
+			},
+			"tooltip": tooltip,
+		}
+	},
+	"area": {
+		"type": "area",
+		"animation": true,
+		"timing": "easeOut",
+		"duration": 500,
+		"color": color,
+		"padding": padding,
+		"dataLabel": false,
+		"fontSize": 12,
+		"xAxis": X,
+		"yAxis": Y,
+		"enableScroll": true,
+		"touchMoveLimit": 60,
+		"legend": legend,
+		"extra": {
+			"area": {
+				"type": "curve",
+				"opacity": 0.5,
+				"addLine": true,
+				"width": 2,
+				"gradient": true
+			},
+			"tooltip": tooltip,
+		}
+	},
+	"rose": {
+		"type": "rose",
+		"animation": true,
+		"timing": "easeOut",
+		"duration": 500,
+		"color": color,
+		"padding": [
+			-20,
+			5,
+			5,
+			5
+		],
+		"dataLabel": false,
+		"dataPointShape": false,
+		"dataPointShapeType": "hollow",
+		"legend": {
+			"show": true,
+			"position": "bottom",
+			"float": "center",
+		},
+		"extra": {
+			"rose": {
+				"type": "radius",
+				"minRadius": 90,
+				"border": true,
+			},
+			"tooltip": tooltip,
+		}
+	},
+	"arcbar": {
+		"type": "arcbar",
+		"animation": true,
+		"timing": "easeOut",
+		"duration": 500,
+		"padding": [30, 30, 30, 30],
+		"title": {
+			"name": "",
+			"fontSize": 28,
+			"color": "#4169E1",
+			"offsetY": -5
+		},
+		"subtitle": {
+			"name": "",
+			"fontSize": 15,
+			"color": "#909399",
+		},
+		"extra": {
+			"arcbar": {
+				"width": 15,
+				"type": "circle",
+				"backgroundColor": "#F5F5F5",
+			}
+		}
+	},
+	"radar": {
+		"type": "radar",
+		"animation": true,
+		"timing": "easeOut",
+		"duration": 500,
+		"color": color,
+		"padding": [
+			0, 15, 10, 15
+		],
+		"fontSize": 13,
+		"enableMarkLine": false,
+		"dataLabel": false,
+		"legend": {
+			"show": true,
+			"position": "top",
+			"float": "center",
+			"padding": 5,
+			"margin": 5,
+			"fontColor": "#696969",
+		},
+		"extra": {
+			"radar": {
+				"gridType": "circle",
+				"gridCount": 3,
+				"opacity": 0.2,
+				"border": true,
+				"borderWidth": 1,
+				"labelColor": '#303133',
+				"labelPointShow": true,
+			},
+			"tooltip": tooltip,
+		}
+	},
+	"pie": {
+		"type": "pie",
+		"animation": true,
+		"timing": "easeOut",
+		"duration": 500,
+		"color": color,
+		"padding": [
+			0, 3, 0, 3
+		],
+		"fontSize": 12,
+		"dataLabel": false,
+		"legend": {
+			"show": false,
+		},
+		"extra": {
+			"pie": {
+				"activeOpacity": 0.5,
+				"activeRadius": 10,
+				"offsetAngle": 0,
+				"customRadius": 0,
+				"labelWidth": 15,
+				"border": true,
+				"borderWidth": 3,
+				"borderColor": "#FFFFFF",
+				"linearType": "none"
+			},
+			"tooltip": tooltip,
+		}
+	},
+	"ring": {
+		"type": "ring",
+		"animation": true,
+		"timing": "easeOut",
+		"duration": 500,
+		"color": color,
+		"padding": [
+			0, 3, 0, 3
+		],
+		"fontSize": 12,
+		"dataLabel": false,
+		"legend": {
+			"show": false,
+		},
+		"title": {
+			"name": "",
+			"fontSize": 12,
+			"offsetY": -5
+		},
+		"subtitle": {
+			"name": "",
+			"fontSize": 16,
+		},
+		"extra": {
+			"ring": {
+				"ringWidth": 30,
+				"centerColor": "#FFFFFF",
+				"activeOpacity": 0.5,
+				"activeRadius": 10,
+				"offsetAngle": 0,
+				"customRadius": 0,
+				"labelWidth": 15,
+				"border": true,
+				"borderWidth": 3,
+				"borderColor": "#FFFFFF",
+				"linearType": "none"
+			},
+			"tooltip": tooltip,
+		}
+	},
+	"mainline": {
+		"type": "area",
+		"animation": true,
+		"timing": "easeOut",
+		"duration": 500,
+		"color": color,
+		"padding": [
+			0,
+			-20,
+			10,
+			-20
+		],
+		"dataLabel": false,
+		"dataPointShape": false,
+		"tapLegend": false,
+		"xAxis": {
+			"disabled": true,
+			"axisLine": false,
+			"disableGrid": true,
+		},
+		"yAxis": {
+			"disabled": true,
+			"disableGrid": true
+		},
+		"legend": {
+			"show": false,
+		},
+		"extra": {
+			"area": {
+				"type": "curve",
+				"opacity": 0.7,
+				"addLine": true,
+				"width": 3,
+				"gradient": true
+			},
+			"tooltip": {
+				"showBox": false,
+				"splitLine": false,
+			},
+		}
+	},
+	"mini-column": {
+		"type": "column",
+		"animation": true,
+		"timing": "easeOut",
+		"duration": 500,
+		"color": color,
+		"padding": [
+			0,
+			10,
+			10,
+			10
+		],
+		"dataLabel": false,
+		"dataPointShape": false,
+		"tapLegend": false,
+		"xAxis": {
+			"disabled": true,
+			"axisLine": false,
+			"disableGrid": true,
+		},
+		"yAxis": {
+			"disabled": true,
+			"disableGrid": true,
+		},
+		"legend": {
+			"show": false,
+		},
+		"extra": {
+			"column": {
+				"type": "group",
+				"width": 10,
+				"seriesGap": 2,
+				"categoryGap": 3,
+				"barBorderCircle": false,
+				"barBorderRadius": [
+					10,
+					10,
+					10,
+					10
+				],
+				"linearType": "opacity",
+				"linearOpacity": 0.7,
+				"customColor": [
+					"#4169E1",
+					"#FFFFFF",
+					"#ff5959",
+					"#FFFFFF",
+					"#f9c752",
+					"#FFFFFF"
+				],
+				"colorStop": 0.5,
+				"meterBorder": 1,
+				"meterFillColor": "#FFFFFF",
+				"activeBgColor": "#FFFFFF",
+				"activeBgOpacity": 0.08,
+				"meterBorde": 1
+			},
+			"tooltip": {
+				"showBox": false,
+				"splitLine": false,
+			},
+		}
+	},
+	"mini-area": {
+		"type": "area",
+		"animation": true,
+		"timing": "easeOut",
+		"duration": 500,
+		"color": color,
+		"padding": [
+			0,
+			-5,
+			10,
+			-5
+		],
+		"dataLabel": false,
+		"dataPointShape": false,
+		"tapLegend": false,
+		"xAxis": {
+			"disabled": true,
+			"axisLine": false,
+			"disableGrid": true,
+		},
+		"yAxis": {
+			"disabled": true,
+			"disableGrid": true,
+		},
+		"legend": {
+			"show": false,
+		},
+		"extra": {
+			"area": {
+				"type": "curve",
+				"opacity": 0.7,
+				"addLine": true,
+				"width": 2,
+				"gradient": true
+			},
+			"tooltip": {
+				"showBox": false,
+				"splitLine": false,
+			},
+		},
+	},
+	"mini-rose": {
+		"type": "rose",
+		"animation": true,
+		"timing": "easeOut",
+		"duration": 500,
+		"color": color,
+		"padding": [
+			0,
+			0,
+			0,
+			0
+		],
+		"dataLabel": false,
+		"dataPointShape": false,
+		"dataPointShapeType": "hollow",
+		"legend": {
+			"show": false,
+		},
+		"extra": {
+			"rose": {
+				"type": "radius",
+				"minRadius": 40,
+				"activeRadius": 0,
+				"opacity": 0.7,
+				"gradient": true,
+				"border": true,
+				"borderWidth": 2,
+				"borderColor": "#FFFFFF",
+			},
+			"tooltip": {
+				"showBox": false,
+				"splitLine": false,
+			},
+		},
+	},
+	"mount": {
+		"type": "mount",
+		"animation": true,
+		"timing": "easeOut",
+		"duration": 500,
+		"color": color,
+		"padding": [
+			0,
+			20,
+			10,
+			20
+		],
+		"dataLabel": false,
+		"dataPointShape": false,
+		"tapLegend": false,
+		"xAxis": {
+			"disableGrid": true,
+			"fontSize": 11,
+			"scrollColor": "#F5F5F5",
+			"scrollBackgroundColor": "#D3D3D3",
+			"boundaryGap": "center",
+			"disabled": true
+		},
+		"yAxis": {
+			"disableGrid": true,
+			"data": [{
+				"fontSize": 11,
+				"min": 0,
+				"disabled": true
+			}]
+		},
+		"legend": {
+			"show": false,
+		},
+		"extra": {
+			"mount": {
+				"type": "mount",
+				"borderWidth": 1.2,
+				"widthRatio": 1.7,
+				"linearType": "opacity",
+				"linearOpacity": 0.1
+			},
+			"tooltip": {
+				"showBox": true,
+				"showArrow": false,
+				"showCategory": false,
+				"borderRadius": 6,
+				"bgOpacity": 0.5,
+				"splitLine": false,
+			},
+		}
+	},
+	"bar": {
+		"type": "bar",
+		"timing": "easeOut",
+		"duration": 1000,
+		"rotate": false,
+		"rotateLock": false,
+		"color": color,
+		"padding": [0, 30, 20, 10],
+		"fontSize": 13,
+		"fontColor": "#666666",
+		"dataLabel": false,
+		"dataPointShape": true,
+		"dataPointShapeType": "solid",
+		"touchMoveLimit": 60,
+		"enableScroll": false,
+		"enableMarkLine": false,
+		"xAxis": {
+			"boundaryGap": "justify",
+			"disableGrid": false,
+			"min": 0,
+			"max": 100,
+			"axisLine": false,
+			"disabled": false,
+			"axisLineColor": "#CCCCCC",
+			"calibration": false,
+			"fontColor": "#666666",
+			"fontSize": 13,
+			"rotateLabel": false,
+			"rotateAngle": 45,
+			"itemCount": 5,
+			"splitNumber": 5,
+			"gridColor": "#CCCCCC",
+			"gridType": "dash",
+			"dashLength": 10,
+			"gridEval": 1,
+			"scrollShow": false,
+			"scrollAlign": "left",
+			"scrollColor": "#A6A6A6",
+			"scrollBackgroundColor": "#EFEBEF",
+			"format": ""
+		},
+		"yAxis": {
+			"disabled": false,
+			"disableGrid": false,
+			"splitNumber": 5,
+			"gridType": "solid",
+			"dashLength": 8,
+			"gridColor": "#CCCCCC",
+			"padding": 10,
+			"showTitle": false,
+			"data": []
+		},
+		"extra": {
+			"bar": {
+				"type": "group",
+				"width": 30,
+				"meterBorde": 1,
+				"activeBgOpacity": 0.08,
+				"seriesGap": 2,
+				"categoryGap": 3,
+				"barBorderCircle": false,
+				"barBorderRadius": [6, 6, 6, 6],
+				"linearType": "none",
+				"linearOpacity": 1,
+				"colorStop": 0
+			},
+			"tooltip": tooltip,
+		}
+	}
+}
+
+export default cfu;

+ 5 - 0
uni_modules/qiun-data-charts/js_sdk/u-charts/readme.md

@@ -0,0 +1,5 @@
+# uCharts JSSDK说明
+1、如不使用uCharts组件,可直接引用u-charts.js,打包编译后会`自动压缩`,压缩后体积约为`120kb`。
+2、如果120kb的体积仍需压缩,请手到uCharts官网通过在线定制选择您需要的图表。
+3、config-ucharts.js为uCharts组件的用户配置文件,升级前请`自行备份config-ucharts.js`文件,以免被强制覆盖。
+4、config-echarts.js为ECharts组件的用户配置文件,升级前请`自行备份config-echarts.js`文件,以免被强制覆盖。

ファイルの差分が大きいため隠しています
+ 7297 - 0
uni_modules/qiun-data-charts/js_sdk/u-charts/u-charts.js


ファイルの差分が大きいため隠しています
+ 18 - 0
uni_modules/qiun-data-charts/js_sdk/u-charts/u-charts.min.js


+ 0 - 0
uni_modules/qiun-data-charts/license.md


この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません