Browse Source

Merge pull request 'mp' (#45) from mp into develop

Reviewed-on: https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/pulls/45
pull/47/head
wally 4 years ago
parent
commit
3492bea357
  1. 2
      .env.development
  2. 2
      .env.production
  3. 346
      CHANGELOG.md
  4. 10
      README.md
  5. 58
      package.json
  6. 19
      postcss.config.js
  7. 11
      src/.hbuilderx/launch.json
  8. 69
      src/App.vue
  9. 14
      src/apis/plugin.js
  10. 7
      src/apis/project.js
  11. 7
      src/apis/role.js
  12. 32
      src/apis/tall.js
  13. 11
      src/apis/task.js
  14. 6
      src/common/styles/index.css
  15. 4462
      src/common/styles/tailwind.scss
  16. 94
      src/components/Globals/Globals.vue
  17. 37
      src/components/ImageCode/ImageCode.vue
  18. 136
      src/components/Plugin/Plugin.vue
  19. 480
      src/components/PrettyExchange/PrettyExchange.vue
  20. 157
      src/components/Projects/ProjectItem.vue
  21. 99
      src/components/Projects/Projects.vue
  22. 222
      src/components/Roles/Roles.vue
  23. 84
      src/components/Skeleton/READ_ME.md
  24. 186
      src/components/Skeleton/Skeleton.vue
  25. 45
      src/components/Skeleton/view.vue
  26. 1
      src/components/Skeleton/wisdomcar_mobile
  27. 119
      src/components/TimeLine/TimeLine.vue
  28. 42
      src/components/TimeLine/component/Barrier.vue
  29. 11
      src/components/TimeLine/component/TaskTools.vue
  30. 147
      src/components/TimeLine/component/TimeBox.vue
  31. 211
      src/components/TimeLine/component/TimeStatus.vue
  32. 7
      src/components/TimeLine/component/Title.vue
  33. 94
      src/components/Tips/Tips.vue
  34. 65
      src/components/Title/Title.vue
  35. 10
      src/components/Upload/Upload.vue
  36. 6
      src/config/app.js
  37. 3
      src/config/db.js
  38. 97
      src/config/plugin.js
  39. 17
      src/config/time.js
  40. 43
      src/config/user.js
  41. 36
      src/main.js
  42. 21
      src/manifest.json
  43. 44
      src/mixins/timeline.js
  44. 62
      src/pages.json
  45. 25
      src/pages/index/index.vue
  46. 189
      src/pages/phone-bind/phone-bind.vue
  47. 35
      src/pages/project-webview/project-webview.vue
  48. 312
      src/pages/project/project.vue
  49. 15
      src/pages/test/test.vue
  50. 7
      src/plugins/p-deliver-check/p-deliver-check.vue
  51. 20
      src/plugins/p-deliverable/p-deliverable.vue
  52. 7
      src/plugins/p-manage-member/p-manage-member.vue
  53. 7
      src/plugins/p-manage-project/p-manage-project.vue
  54. 7
      src/plugins/p-manage-role/p-manage-role.vue
  55. 7
      src/plugins/p-manage-task/p-manage-task.vue
  56. 60
      src/plugins/p-subproject/p-subproject.vue
  57. 39
      src/plugins/p-subtasks/p-subtasks.vue
  58. 20
      src/plugins/p-task-countdown/p-task-countdown.vue
  59. 16
      src/plugins/p-task-description/p-task-description.vue
  60. 34
      src/plugins/p-task-duration-delay/p-task-duration-delay.vue
  61. 22
      src/plugins/p-task-start-time-delay/p-task-start-time-delay.vue
  62. 16
      src/plugins/p-task-title/p-task-title.vue
  63. 85
      src/plugins/p-wbs-import/p-wbs-import.vue
  64. BIN
      src/static/local_play1.png
  65. BIN
      src/static/logo.png
  66. 3
      src/store/db/actions.js
  67. 3
      src/store/db/getters.js
  68. 12
      src/store/db/index.js
  69. 3
      src/store/db/mutations.js
  70. 7
      src/store/db/state.js
  71. 34
      src/store/index.js
  72. 1
      src/store/messages/mutations.js
  73. 17
      src/store/project/actions.js
  74. 19
      src/store/project/mutations.js
  75. 19
      src/store/role/actions.js
  76. 3
      src/store/role/getters.js
  77. 12
      src/store/role/index.js
  78. 30
      src/store/role/mutations.js
  79. 7
      src/store/role/state.js
  80. 45
      src/store/task/actions.js
  81. 23
      src/store/task/getters.js
  82. 12
      src/store/task/index.js
  83. 168
      src/store/task/mutations.js
  84. 31
      src/store/task/state.js
  85. 8
      src/store/user/actions.js
  86. 2
      src/store/user/mutations.js
  87. 46
      src/test/util/time.test.js
  88. 8
      src/uni.scss
  89. 62
      src/utils/cache.js
  90. 190
      src/utils/cacheAndRequest.js
  91. 185
      src/utils/indexedDB.js
  92. 5
      src/utils/request.js
  93. 14
      src/utils/storage.js
  94. 12
      src/utils/tall.js
  95. 2
      src/utils/time.js
  96. 30
      tailwind.config.js
  97. 7
      vue.config.js

2
.env.development

@ -2,3 +2,5 @@ VUE_APP_NODE_ENV=development
VUE_APP_BASE_URL=https://test.tall.wiki
VUE_APP_API_URL=https://test.tall.wiki/gateway
VUE_APP_MSG_URL=wss://test.tall.wiki/websocket/message/v4.0/ws
VUE_APP_PROJECT_PATH=https://test.tall.wiki/tall-project
VUE_APP_VERSION=v3.1.0

2
.env.production

@ -2,3 +2,5 @@ VUE_APP_NODE_ENV=production
VUE_APP_BASE_URL=https://www.tall.wiki
VUE_APP_API_URL=https://www.tall.wiki/gateway
VUE_APP_MSG_URL=wss://www.tall.wiki/websocket/message/v4.0/ws
VUE_APP_PROJECT_PATH=https://www.tall.wiki/tall-project
VUE_APP_VERSION=v3.1.0

346
CHANGELOG.md

@ -1,204 +1,230 @@
# 0.1.0 (2021-08-18)
# 0.1.0 (2021-08-31)
### 🌟 新功能
范围|描述|commitId
--|--|--
calendar, tall.js | 上下滑动切换日历的模式,tall.js中domain根据环境变量切换 | [364e25d](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/364e25d)
- | db store | [6414c4f](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/6414c4f)
default plugin | 添加默认插件;项目列表;全局项目最大高度设置 | [ed1d87b](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/ed1d87b)
- | indexedDB | [687394e](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/687394e)
pinch | alloy finger实现图片的pinch放大缩小 | [de01343](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/de01343)
plugin | 插件添加了token及param参数 | [aeb0292](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/aeb0292)
- | post 封装 | [da52e94](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/da52e94)
- | tall插件封装 | [1bcb920](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/1bcb920)
task status | 任务状态切换未完 | [7ffd135](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/7ffd135)
- | ws storage | [21b3a06](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/21b3a06)
- | 上传逻辑变化 | [3ff1dc2](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/3ff1dc2)
- | 任务状态时间显示 | [56f5183](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/56f5183)
- | 任务进行中状态数字 | [27b7326](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/27b7326)
- | 全局插件及默认插件位置修改 | [6c80d08](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/6c80d08)
- | 向右箭头图标变化 | [8e9ca55](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/8e9ca55)
- | 字体大小更改 | [82cfdd4](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/82cfdd4)
- | 存token | [b8a178d](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/b8a178d)
- | 定期任务面板骨架屏添加 | [b2698c0](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/b2698c0)
富文本插件 | 富文本插件demo测试 | [ed3d644](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/ed3d644)
- | 导入wbs | [1224fcb](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/1224fcb)
- | 导入项目,更新项目 | [5e06adf](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/5e06adf)
- | 导入项目后提示并打开项目详情页 | [410f527](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/410f527)
- | 引入dayjs | [29b8b93](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/29b8b93)
- | 提交到本地 | [9cbe411](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/9cbe411)
- | 插件参数处理调整 | [a3e68d3](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/a3e68d3)
- | 插件数据获取 | [5b91bdc](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/5b91bdc)
- | 日历定位;合并 | [ea3f937](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/ea3f937)
- | 日常任务插件调整 | [c1881f9](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/c1881f9)
- | 时间基准线,默认插件 | [a33ba1e](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/a33ba1e)
- | 时间轴修改状态时提示框增加 | [e841392](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/e841392)
- | 时间轴界面 | [33927e9](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/33927e9)
- | 标题栏变化 | [3898cfe](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/3898cfe)
- | 标题栏变化 | [c0fcd9d](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/c0fcd9d)
- | 标题栏角色栏全局任务组件新建 | [0500cb4](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/0500cb4)
- | 模拟接口测试 | [69e7931](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/69e7931)
- | 添加时间轴上下滚动 | [2b81bbc](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/2b81bbc)
- | 点击日历日期查询项目列表 | [c458385](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/c458385)
- | 角色栏实现 | [94cd671](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/94cd671)
- | 设置小红点 | [9316bcb](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/9316bcb)
- | 距调整pc端 | [5069aa1](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/5069aa1)
- | 配置默认插件接口 | [f0c177d](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/f0c177d)
- | 面变化首页变化 | [5e860f1](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/5e860f1)
- | 项目api url设置 | [6cd5245](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/6cd5245)
- | 项目列表, 项目url | [32e005b](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/32e005b)
- | 首页项目样式改变 | [8514c85](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/8514c85)
- | api封装 | 7d4edfc
bind phone | 图形验证码;短信验证码;绑定手机号 | 93ffea2
- | cache indexedDB处理 | 3388967
calendar, tall.js | 上下滑动切换日历的模式,tall.js中domain根据环境变量切换 | 364e25d
- | db store | 6414c4f
default plugin | 添加默认插件;项目列表;全局项目最大高度设置 | ed1d87b
- | indexedDB | 687394e
modules update;network | npm包升级;网络判断,网络不好才开启本地存储 | ebf7bdc
mp | 兼容小程序,去除window,document等 | 9178255
phone-bind | 验证码validate | a427250
pinch | alloy finger实现图片的pinch放大缩小 | de01343
plugin | 插件添加了token及param参数 | aeb0292
- | post 封装 | da52e94
- | tailwindcss添加部分属性 | 5b46b6d
- | tall插件封装 | 1bcb920
task status | 任务状态切换未完 | 7ffd135
- | ws storage | 21b3a06
- | 上传逻辑变化 | 3ff1dc2
- | 任务状态时间显示 | 56f5183
- | 任务进行中状态数字 | 27b7326
- | 全局插件及默认插件位置修改 | 6c80d08
- | 升级版本v3.1.0;tailwindcss添加class | 9ef05e1
- | 向右箭头图标变化 | 8e9ca55
- | 字体大小更改 | 82cfdd4
- | 存token | b8a178d
- | 定期任务面板骨架屏添加 | b2698c0
富文本插件 | 富文本插件demo测试 | ed3d644
- | 导入wbs | 1224fcb
- | 导入项目,更新项目 | 5e06adf
- | 导入项目后提示并打开项目详情页 | 410f527
- | 引入dayjs | 29b8b93
- | 提交到本地 | 9cbe411
- | 插件参数处理调整 | a3e68d3
- | 插件数据获取 | 5b91bdc
- | 日历定位;合并 | ea3f937
- | 日常任务插件调整 | c1881f9
- | 时间基准线,默认插件 | a33ba1e
- | 时间轴修改状态时提示框增加 | e841392
- | 时间轴界面 | 33927e9
- | 标题栏变化 | 3898cfe
- | 标题栏变化 | c0fcd9d
- | 标题栏角色栏全局任务组件新建 | 0500cb4
- | 模拟接口测试 | 69e7931
- | 添加 环境变量,动态控制webview project的path | 8a40481
- | 添加子任务插件 子项目插件 | 7bda7e2
- | 添加时间轴上下滚动 | 2b81bbc
- | 添加项目排序 | a0b491b
- | 点击日历日期查询项目列表 | c458385
- | 细节调整,添加project-webview | 4d9050b
- | 绑定手机号 | 52e0352
- | 缓存修改 | 63e1f0d
- | 角色栏实现 | 94cd671
- | 设置小红点 | 9316bcb
- | 距调整pc端 | 5069aa1
- | 适配小程序;小程序登录 | cefc0eb
- | 配置默认插件接口 | f0c177d
- | 面变化首页变化 | 5e860f1
- | 项目api url设置 | 6cd5245
- | 项目列表, 项目url | 32e005b
- | 项目列表排序 | 224c58b
- | 首页项目样式改变 | 8514c85
### 🎨 代码样式
范围|描述|commitId
--|--|--
- | calendar注释 | [a2ec112](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/a2ec112)
- | 代码审查 | [d75134c](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/d75134c)
- | 代码格式细节调整 | [cb2532b](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/cb2532b)
- | 任务快捷方式图标增加 | [4aba872](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/4aba872)
- | 修改角色样式 | [73e268e](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/73e268e)
- | 删除calendar中多余的console | [e339eec](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/e339eec)
- | 删除console.log | [5064a38](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/5064a38)
- | 删除index中没用的alert代码 | [9c9eec7](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/9c9eec7)
- | 删除mock,console;upload添加loading | [99d42e2](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/99d42e2)
- | 删除多余字段 | [5ae3973](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/5ae3973)
- | 删除插件携带的多余文件 | [0f392bb](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/0f392bb)
- | 删除没用代码 | [34b20e1](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/34b20e1)
- | 图标修改 | [54bca09](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/54bca09)
- | 无基本变化 | [21ac4bb](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/21ac4bb)
- | 日常任务修改 | [dfa7ee2](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/dfa7ee2)
- | 更新代码 | [8c27e68](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/8c27e68)
- | 更新代码 | [1f40a76](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/1f40a76)
- | 格式细节调整 | [b907a03](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/b907a03)
- | 添加插件数据 | [2f11b42](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/2f11b42)
- | 组件新建 | [89c0035](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/89c0035)
- | 细节调整 | [2cfc09a](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/2cfc09a)
- | calendar注释 | a2ec112
- | indexedDB.js格式整理 | b0d3a36
- | 代码审查 | d75134c
- | 代码格式细节调整 | cb2532b
- | 任务快捷方式图标增加 | 4aba872
- | 修改角色样式 | 73e268e
- | 删除calendar中多余的console | e339eec
- | 删除console.log | 5064a38
- | 删除index中没用的alert代码 | 9c9eec7
- | 删除mock,console;upload添加loading | 99d42e2
- | 删除多余字段 | 5ae3973
- | 删除插件携带的多余文件 | 0f392bb
- | 删除没用代码 | 34b20e1
- | 图标修改 | 54bca09
- | 无基本变化 | 21ac4bb
- | 日常任务修改 | dfa7ee2
- | 更新代码 | 8c27e68
- | 更新代码 | 1f40a76
- | 格式细节调整 | b907a03
- | 添加插件数据 | 2f11b42
- | 组件新建 | 89c0035
- | 细节调整 | 2cfc09a
### 🐛 Bug 修复
范围|描述|commitId
--|--|--
- | 1.时间轴数据渲染 2.时间基准线 | [d643af2](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/d643af2)
ID1000343 | 解决向下预加载查询参数时间没+1颗粒度;以及滚动加载颗粒度写死的问题 | [940603a](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/940603a), closes [#ID1000343](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/issues/ID1000343)
plugin | 插件解析机制完善 | [0f5a27d](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/0f5a27d)
project title | 项目标题修改; 切换角色移除script | [5c20017](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/5c20017)
roles | 修复默认显示不是我的角色的问题 | [b69f94f](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/b69f94f)
role | 切换角色的逻辑修正完善 | [4ae534f](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/4ae534f)
task任务逻辑完善 | 减少初始global及regular的不必要请求 | [bd4bd38](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/bd4bd38)
- | title.vue根据页面栈显示返回按钮;标题文本超出显示... | [0cbacf4](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/0cbacf4)
- | 上下滑动加载定期任务 | [4090d89](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/4090d89)
- | 上下滚动时间轴 | [d533a01](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/d533a01)
- | 下拉加载定期任务传参,时间格式化修改 | [0b95a0e](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/0b95a0e)
- | 任务开始时间延迟插件 | [992a313](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/992a313)
- | 修改main | [749ae9a](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/749ae9a)
- | 修改定期任务状态0和4时不加载圆圈 | [30e352f](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/30e352f)
- | 修改小红点传参 | [87b20fd](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/87b20fd)
- | 修改报错 | [531c14d](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/531c14d)
- | 修改接口路径 | [df6acf2](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/df6acf2)
- | 修改角色栏组件 | [a54c601](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/a54c601)
- | 切换到默认项目角色没有激活状态的bug | [438d448](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/438d448)
- | 切换日历时查询小红点 | [7091789](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/7091789)
- | 初始展示角色修改 | [2ac4053](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/2ac4053)
- | 定期任务key值修改 | [c6688db](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/c6688db)
- | 定期任务接口 | [aa4981c](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/aa4981c)
- | 定期任务插件 | [92b3254](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/92b3254)
- | 定期任务未加载时,显示空的时间轴并能上下滑动 | [ce38093](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/ce38093)
- | 定期任务骨架屏修改 | [8ff72dd](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/8ff72dd)
- | 平车演示临时去掉项目快捷方式的toast提示 | [e0b2c23](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/e0b2c23)
- | 手动展开日常任务 | [0a4a622](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/0a4a622)
- | 提示信息显示bug及日常任务收缩问题 | [f2f06c5](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/f2f06c5)
- | 插件bug解决 | [41257eb](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/41257eb)
- | 收到消息修改任务状态 | [c378063](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/c378063)
- | 日历无任务时添加小绿点,时间轴刻度无任务不显示时分 | [0f90868](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/0f90868)
- | 日常任务html数据查验 | [880ce5c](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/880ce5c)
- | 日常任务插件遍历时的key值修改 | [cd26285](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/cd26285)
- | 日常任务插件面板高度修改 | [249f9e4](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/249f9e4)
- | 时间轴上下滑动 | [4d0ae46](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/4d0ae46)
- | 时间轴上下滚动数据加载bug修改 | [e82ede4](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/e82ede4)
- | 时间轴插件 | [225d3cc](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/225d3cc)
- | 时间轴无任务时时间刻度加载修改 | [4921672](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/4921672)
- | 时间轴滚动位置修改 | [551da63](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/551da63)
- | 时间轴骨架屏修改 | [ca78d02](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/ca78d02)
- | 监听时间基本点 | [033fca0](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/033fca0)
- | 角色显示状态修改 | [7d3b906](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/7d3b906)
- | 角色栏修改 | [19228d6](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/19228d6)
- | 解决时间轴报错 | [da1eece](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/da1eece)
- | 设置时间轴自动滚动到当前位置 | [a3474f8](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/a3474f8)
- | 跳转详情页返回路径修改 | [c5e17c0](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/c5e17c0)
- | 骨架屏替换 | [e9fdd71](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/e9fdd71)
- | 1.时间轴数据渲染 2.时间基准线 | d643af2
- | api 存storage | 81032ba
ID1000343 | 解决向下预加载查询参数时间没+1颗粒度;以及滚动加载颗粒度写死的问题 | 940603a, closes #ID1000343
plugin | 插件解析机制完善 | 0f5a27d
project title | 项目标题修改; 切换角色移除script | 5c20017
roles | 修复默认显示不是我的角色的问题 | b69f94f
role | 切换角色的逻辑修正完善 | 4ae534f
task任务逻辑完善 | 减少初始global及regular的不必要请求 | bd4bd38
- | title.vue根据页面栈显示返回按钮;标题文本超出显示... | 0cbacf4
- | 上下滑动加载定期任务 | 4090d89
- | 上下滚动时间轴 | d533a01
- | 下拉加载定期任务传参,时间格式化修改 | 0b95a0e
- | 任务开始时间延迟插件 | 992a313
- | 修改main | 749ae9a
- | 修改定期任务状态0和4时不加载圆圈 | 30e352f
- | 修改小红点传参 | 87b20fd
- | 修改报错 | 531c14d
- | 修改接口路径 | df6acf2
- | 修改角色栏组件 | a54c601
- | 切换到默认项目角色没有激活状态的bug | 438d448
- | 切换日历时查询小红点 | 7091789
- | 初始展示角色修改 | 2ac4053
- | 定期任务key值修改 | c6688db
- | 定期任务接口 | aa4981c
- | 定期任务插件 | 92b3254
- | 定期任务未加载时,显示空的时间轴并能上下滑动 | ce38093
- | 定期任务本地缓存和api赋值,未完成 | 5a10856
定期任务本地缓存和api赋值,未完成 | 定期任务本地缓存和api赋值,未完成 | b22a366
- | 定期任务骨架屏修改 | 8ff72dd
- | 平车演示临时去掉项目快捷方式的toast提示 | e0b2c23
- | 手动展开日常任务 | 0a4a622
- | 提示信息显示bug及日常任务收缩问题 | f2f06c5
- | 插件bug解决 | 41257eb
- | 收到消息修改任务状态 | c378063
- | 日历无任务时添加小绿点,时间轴刻度无任务不显示时分 | 0f90868
- | 日常任务html数据查验 | 880ce5c
- | 日常任务插件遍历时的key值修改 | cd26285
- | 日常任务插件面板高度修改 | 249f9e4
- | 时间轴上下滑动 | 4d0ae46
- | 时间轴上下滚动数据加载bug修改 | e82ede4
- | 时间轴插件 | 225d3cc
- | 时间轴无任务时时间刻度加载修改 | 4921672
- | 时间轴滚动位置修改 | 551da63
- | 时间轴骨架屏修改 | ca78d02
- | 监听时间基本点 | 033fca0
- | 角色显示状态修改 | 7d3b906
- | 角色栏修改 | 19228d6
- | 解决时间轴报错 | da1eece
- | 设置时间轴自动滚动到当前位置 | a3474f8
- | 跳转详情页返回路径修改 | c5e17c0
- | 项目列表排序修改 | fd3c3ac
- | 项目列表排序修改 | 59f4c21
项目列表排序 | 项目列表排序 | 402c563
- | 骨架屏替换 | e9fdd71
### 📝 文档
范围|描述|commitId
--|--|--
- | README.md | [ab0eb05](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/ab0eb05)
- | README.md | ab0eb05
### 🔧 测试
范围|描述|commitId
--|--|--
- | 暂时移除了jest浏览器配置 | [5088d01](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/5088d01)
- | 添加测试,测试utils/time.js的computeDurationText | [e758010](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/e758010)
- | 禁用任务开始操作 | [b5425db](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/b5425db)
- | 暂时移除了jest浏览器配置 | 5088d01
- | 添加测试,测试utils/time.js的computeDurationText | e758010
- | 禁用任务开始操作 | b5425db
### 🔨 代码重构
范围|描述|commitId
--|--|--
calendar | 日历细节调整 | [1a8d6bf](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/1a8d6bf)
- | project 代码健壮性完善 | [a3202c5](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/a3202c5)
store/home | 删除store/home | [db8a3b4](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/db8a3b4)
task beginTime | 格式化任务开始时间 | [fbc0301](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/fbc0301)
template | eslint prettier sass uview tailwindcss | [9c966a1](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/9c966a1)
tips | 修改任务状态方法重构 | [b57d3ac](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/b57d3ac)
tip | 任务状态显示及tip组件数据的重构 | [78a5750](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/78a5750)
title.vue | 移除测试的repeat; 样式细节调整 | [c32d2bd](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/c32d2bd)
- | 下滑时间轴添加备注 | [4fd20e3](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/4fd20e3)
- | 任务状态重构 | [4693655](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/4693655)
- | 删除多余的weekmode store里的东西 | [0841fe0](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/0841fe0)
- | 删除多余的技术验证界面 | [542ae5b](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/542ae5b)
- | 界面样式调整 | [4367249](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/4367249)
- | 重构store分层 | [5f6fff8](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/5f6fff8)
calendar | 日历细节调整 | 1a8d6bf
- | project 代码健壮性完善 | a3202c5
store/home | 删除store/home | db8a3b4
task beginTime | 格式化任务开始时间 | fbc0301
template | eslint prettier sass uview tailwindcss | 9c966a1
tips | 修改任务状态方法重构 | b57d3ac
tip | 任务状态显示及tip组件数据的重构 | 78a5750
title.vue | 移除测试的repeat; 样式细节调整 | c32d2bd
- | 下滑时间轴添加备注 | 4fd20e3
- | 任务状态重构 | 4693655
- | 删除多余的weekmode store里的东西 | 0841fe0
- | 删除多余的技术验证界面 | 542ae5b
- | 去掉tailwindcss | 4bed47e
- | 界面样式调整 | 4367249
- | 重构store分层 | 5f6fff8
### 🚀 性能优化
范围|描述|commitId
--|--|--
- | 1.时间轴筛选相同的时间替换数据 2.整理代码 | [e082ccb](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/e082ccb)
- | 修改代码格式 | [14123d7](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/14123d7)
- | 修改定期任务骨架屏高度 | [909a734](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/909a734)
- | 插件查询及展示 | [4dba770](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/4dba770)
- | 整理代码 | [7a55315](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/7a55315)
- | 日历的更改 | [7353ac8](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/7353ac8)
- | 测试接口 | [215e074](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/215e074)
- | 组件文件夹新建 | [22bfe7b](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/22bfe7b)
- | 组件文件夹新建 | [17bb8c9](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/17bb8c9)
- | 组件文件夹新建 | [1421504](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/1421504)
- | 角色栏文字颜色修改 | [215c6b3](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/215c6b3)
- | 解决警告 | [c932b09](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/c932b09)
- | 1.时间轴筛选相同的时间替换数据 2.整理代码 | e082ccb
- | 修改代码格式 | 14123d7
- | 修改定期任务骨架屏高度 | 909a734
- | 小红点api缓存修改 | e992343
- | 插件查询及展示 | 4dba770
- | 整理代码 | 7a55315
- | 日历的更改 | 7353ac8
- | 测试接口 | 215e074
- | 组件文件夹新建 | 22bfe7b
- | 组件文件夹新建 | 17bb8c9
- | 组件文件夹新建 | 1421504
- | 角色栏文字颜色修改 | 215c6b3
- | 解决警告 | c932b09
### chore
范围|描述|commitId
--|--|--
- | api 封装 | [8dcb8a2](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/8dcb8a2)
- | env host修改 | [a79a4a5](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/a79a4a5)
- | merge globals | [b0957cc](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/b0957cc)
- | merge wrr | [5ccc7a5](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/5ccc7a5)
- | mock | [51c24a5](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/51c24a5)
package manifest | 去掉了摇树 | [f7c1dd4](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/f7c1dd4)
pwa 小程序 | 移除了pwa,alloyFinger添加平台判断 | [875fab4](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/875fab4)
- | uview-ui | [a9ea34b](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/a9ea34b)
v3.0.1 | tall api 地址从1.0改成了3.0 | [db5afd5](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/db5afd5)
信息配置 | 配置eslint等配置 | [7421443](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/7421443)
- | 修复不能build的问题 | [0b7b91e](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/0b7b91e)
- | 删除多余的构建的命令 | [3f4eb2f](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/3f4eb2f)
- | api 封装 | 8dcb8a2
- | dart-sass替换node-sass;删除多余的uni平台包 | 519f28b
- | env host修改 | a79a4a5
- | merge globals | b0957cc
- | merge wrr | 5ccc7a5
- | mock | 51c24a5
package manifest | 去掉了摇树 | f7c1dd4
pwa 小程序 | 移除了pwa,alloyFinger添加平台判断 | 875fab4
- | uview-ui | a9ea34b
v3.0.1 | tall api 地址从1.0改成了3.0 | db5afd5
信息配置 | 配置eslint等配置 | 7421443
- | 修复不能build的问题 | 0b7b91e
- | 删除多余的构建的命令 | 3f4eb2f
范围|描述|commitId
--|--|--
- | style:index | [978f272](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/978f272)
- | !2 基础模板v1.1.0 | [f5e61dd](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/f5e61dd)
- | init | [c0f1deb](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/c0f1deb)
- | style:index | 978f272
- | !2 基础模板v1.1.0 | f5e61dd
- | init | c0f1deb

10
README.md

@ -1,5 +1,13 @@
# tall-mui-cli
## 发布注意事项
环境变量里的`VUE_APP_VERSION=v3.0.1` 如果project路径变了 或者版本升级了, 发行之前一定要跟着改
本项目, TALL程序主体框架升级, 或者服务端路径变化, 要修改`manifest.json` 下的 `h5.router.base`
---
## 项目运行
### 安装依赖
@ -14,7 +22,7 @@ yarn dev:h5
```
浏览器输入网址:
127.0.0.1:8080/#/?u=1217647686598135808&p=1420652719055839232
http://localhost:8080/tall/v3.0.1/#/?u=1217647686598135808&p=1420652719055839232
- u: userId
- p: projectId
- r: roleId

58
package.json

@ -13,6 +13,7 @@
"build:h5-test": "cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build --mode development",
"build:h5": "cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build --mode production",
"build:app-plus": "cross-env NODE_ENV=production UNI_PLATFORM=app-plus vue-cli-service uni-build",
"build:mp-weixin": "cross-env NODE_ENV=production UNI_PLATFORM=mp-weixin vue-cli-service uni-build",
"cz": "npm run log && git add . && git cz",
"dev:app-plus": "cross-env NODE_ENV=development UNI_PLATFORM=app-plus vue-cli-service uni-build --watch",
"dev:custom": "cross-env NODE_ENV=development uniapp-cli custom",
@ -25,23 +26,13 @@
"test:mp-weixin": "cross-env UNI_PLATFORM=mp-weixin jest -i"
},
"dependencies": {
"@dcloudio/uni-app-plus": "^2.0.0-31920210709003",
"@dcloudio/uni-h5": "^2.0.0-31920210709003",
"@dcloudio/uni-h5": "^2.0.0-32220210818002",
"@dcloudio/uni-helper-json": "*",
"@dcloudio/uni-i18n": "^2.0.0-31920210709003",
"@dcloudio/uni-mp-360": "^2.0.0-31920210709003",
"@dcloudio/uni-mp-alipay": "^2.0.0-31920210709003",
"@dcloudio/uni-mp-baidu": "^2.0.0-31920210709003",
"@dcloudio/uni-mp-kuaishou": "^2.0.0-31920210709003",
"@dcloudio/uni-mp-qq": "^2.0.0-31920210709003",
"@dcloudio/uni-mp-toutiao": "^2.0.0-31920210709003",
"@dcloudio/uni-mp-vue": "^2.0.0-31920210709003",
"@dcloudio/uni-mp-weixin": "^2.0.0-31920210709003",
"@dcloudio/uni-quickapp-native": "^2.0.0-31920210709003",
"@dcloudio/uni-quickapp-webview": "^2.0.0-31920210709003",
"@dcloudio/uni-stat": "^2.0.0-31920210709003",
"@vue/shared": "^3.0.0",
"alloyfinger": "^0.1.16",
"@dcloudio/uni-i18n": "^2.0.0-32220210818002",
"@dcloudio/uni-mp-vue": "^2.0.0-32220210818002",
"@dcloudio/uni-mp-weixin": "^2.0.0-32220210818002",
"@dcloudio/uni-stat": "^2.0.0-32220210818002",
"@vue/shared": "^3.2.6",
"dayjs": "^1.10.6",
"flyio": "^0.6.2",
"lodash": "^4.17.21",
@ -52,17 +43,16 @@
},
"devDependencies": {
"@babel/runtime": "~7.12.0",
"@dcloudio/types": "*",
"@dcloudio/uni-automator": "^2.0.0-31920210709003",
"@dcloudio/uni-cli-shared": "^2.0.0-31920210709003",
"@dcloudio/uni-migration": "^2.0.0-31920210709003",
"@dcloudio/uni-template-compiler": "^2.0.0-31920210709003",
"@dcloudio/vue-cli-plugin-hbuilderx": "^2.0.0-31920210709003",
"@dcloudio/vue-cli-plugin-uni": "^2.0.0-31920210709003",
"@dcloudio/vue-cli-plugin-uni-optimize": "^2.0.0-31920210709003",
"@dcloudio/webpack-uni-mp-loader": "^2.0.0-31920210709003",
"@dcloudio/webpack-uni-pages-loader": "^2.0.0-31920210709003",
"@tailwindcss/postcss7-compat": "^2.2.7",
"@dcloudio/types": "^2.5.1",
"@dcloudio/uni-automator": "^2.0.0-32220210818002",
"@dcloudio/uni-cli-shared": "^2.0.0-32220210818002",
"@dcloudio/uni-migration": "^2.0.0-32220210818002",
"@dcloudio/uni-template-compiler": "^2.0.0-32220210818002",
"@dcloudio/vue-cli-plugin-hbuilderx": "^2.0.0-32220210818002",
"@dcloudio/vue-cli-plugin-uni": "^2.0.0-32220210818002",
"@dcloudio/vue-cli-plugin-uni-optimize": "^2.0.0-32220210818002",
"@dcloudio/webpack-uni-mp-loader": "^2.0.0-32220210818002",
"@dcloudio/webpack-uni-pages-loader": "^2.0.0-32220210818002",
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-vuex": "~4.5.0",
@ -73,29 +63,27 @@
"babel-plugin-import": "^1.11.0",
"commitizen": "^4.0.3",
"commitlint": "^8.2.0",
"compression-webpack-plugin": "^5.0.1",
"compression-webpack-plugin": "^5.0.2",
"conventional-changelog-cli": "^2.0.28",
"core-js": "^3.15.2",
"core-js": "^3.16.3",
"cross-env": "^7.0.3",
"eslint": "^6.7.2",
"eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-prettier": "^3.4.1",
"eslint-plugin-vue": "^6.2.2",
"husky": "^3.0.9",
"jest": "^25.4.0",
"lint-staged": "^11.0.0",
"lint-staged": "^11.1.2",
"mini-types": "*",
"miniprogram-api-typings": "*",
"node-sass": "^4.14.1",
"miniprogram-api-typings": "^3.4.3",
"postcss": "^7.0.36",
"postcss-class-rename": "^1.0.1",
"postcss-comment": "^2.0.0",
"prettier": "^2.2.1",
"puppeteer": "^10.2.0",
"right-pad": "^1.0.1",
"sass": "^1.38.2",
"sass-loader": "^8.0.2",
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.7",
"vue-cli-plugin-commitlint": "~1.0.12",
"vue-cli-plugin-eruda": "^1.3.0",
"vue-template-compiler": "^2.6.11"
},
"browserslist": [

19
postcss.config.js

@ -15,24 +15,7 @@ module.exports = {
return id;
},
}),
// require('autoprefixer')({ remove: process.env.UNI_PLATFORM !== 'h5' }),
require('autoprefixer')({ remove: process.env.UNI_PLATFORM !== 'h5' }),
require('@dcloudio/vue-cli-plugin-uni/packages/postcss'),
require('tailwindcss')({ config: "./tailwind.config.js" }),
...(
process.env.UNI_PLATFORM !== 'h5'
? [
require("postcss-class-rename")({
"\\\\:": "--",
"\\\\/": "--",
"\\\\.": "--",
".:": "--",
"\\\*": "--",
})
] : [
require("autoprefixer")({
remove: true,
}),
]
)
],
};

11
src/.hbuilderx/launch.json

@ -1,11 +0,0 @@
{ // launch.json configurations app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
// launchtypelocalremote, localremote
"version": "0.0",
"configurations": [{
"type": "uniCloud",
"default": {
"launchtype": "local"
}
}
]
}

69
src/App.vue

@ -1,8 +1,16 @@
<script>
import { mapActions, mapState } from 'vuex';
import { mapActions, mapGetters, mapMutations, mapState } from 'vuex';
export default {
async onLaunch(options) {
console.log('options: ', options);
this.checkNetwork(); //
/* #ifdef MP-WEIXIN */
await this.signin();
this.initSocket();
/* #endif */
/* #ifdef H5 */
options.query.url && (this.$t.domain = options.query.url);
if (!this.token) {
// tokenuserIdtoken
@ -11,23 +19,66 @@ export default {
// u (userId)
this.$t.ui.showToast('缺少用户信息参数');
} else {
await this.getToken(options.query.u);
const data = await this.getToken(options.query.u);
this.noPhone(data.phone);
}
}
// FIXME:
this.initSocket();
},
onShow: function () {
console.log('App Show');
},
onHide: function () {
console.log('App Hide');
/* #endif */
},
computed: mapState('user', ['token']),
computed: {
...mapGetters(['useStorage']),
...mapState('user', ['token']),
},
methods: {
...mapActions('user', ['getToken']),
...mapActions('socket', ['initSocket']),
...mapMutations(['setNetworkConnected']),
...mapMutations('user', ['setToken', 'setUser']),
// store
// 2g 3g ;
checkNetwork() {
uni.getNetworkType({
success: ({ networkType }) => {
this.setNetworkConnected(!(networkType === 'none' || networkType === '2g' || networkType === '3g'));
},
});
//
uni.onNetworkStatusChange(({ isConnected, networkType }) => {
this.setNetworkConnected(isConnected && !(networkType === '2g' || networkType === '3g'));
});
},
//
async signin() {
try {
const data = await this.$u.api.signin();
if (data && data.token) {
this.setUser(data);
this.setToken(data.token);
this.noPhone(data.phone);
} else {
this.$t.ui.showToast('返回数据异常');
}
} catch (error) {
console.error('error: ', error);
this.$t.ui.showToast(error || '登录失败');
}
},
/**
* 没有手机号 跳转绑定手机号的界面
* @param {string} phone
*/
async noPhone(phone) {
if (!phone) {
this.$u.route('/pages/phone-bind/phone-bind');
}
},
},
};
</script>

14
src/apis/plugin.js

@ -1,14 +0,0 @@
// 插件的地址是固定的
const url = process.env.VUE_APP_API_URL;
const install = (Vue, vm) => {
vm.$u.api = { ...vm.$u.api } || {};
// 获取插件信息
vm.$u.api.getOtherPlugin = param => vm.$u.post(`${url}/pluginshop/plugin/query`, param);
// 查询子任务
vm.$u.api.findSonTask = param => vm.$u.post(`${uni.$t.domain}/task/findSonTask`, param);
// 查询子项目
vm.$u.api.findSonProject = param => vm.$u.post(`${uni.$t.domain}/project/findSonProject`, param);
};
export default { install };

7
src/apis/project.js

@ -1,7 +0,0 @@
const install = (Vue, vm) => {
vm.$u.api = { ...vm.$u.api } || {};
//根据id获取项目信息
vm.$u.api.findProjectById = param => vm.$u.post(`${uni.$t.domain}/project/findProjectById`, param);
};
export default { install };

7
src/apis/role.js

@ -1,7 +0,0 @@
const install = (Vue, vm) => {
vm.$u.api = { ...vm.$u.api } || {};
//根据时间基准点和角色查找定期任务
vm.$u.api.findShowRole = param => vm.$u.post(`${uni.$t.domain}/role/show`, param);
};
export default { install };

32
src/apis/tall.js

@ -1,14 +1,44 @@
const apiUrl = process.env.VUE_APP_API_URL;
const tall = `${apiUrl}/tall3/v3.0`;
export const tall = `${apiUrl}/tall3/v3.0`;
import { mp } from '@/config/user.js';
// 登录
export const login = {
async index(params) {
try {
/* #ifdef MP-WEIXIN */
params = await mp();
/* #endif */
const data = await uni.$u.http.post(`${tall}/users/signin`, params);
return data;
} catch (error) {
throw new Error(error);
}
},
};
const install = (Vue, vm) => {
vm.$u.api = { ...vm.$u.api } || {};
// 登录
vm.$u.api.signin = params => login.index(params);
// 获取图片验证码
vm.$u.api.getImageCode = () => vm.$u.get(`${tall}/users/code`);
// 获取短信验证码
vm.$u.api.getSmsCode = params => vm.$u.get(`${tall}/users/smscode`, params);
// 根据userId获取token
vm.$u.api.getToken = userId => vm.$u.get(`${tall}/users/userId`, { userId });
// 绑定手机号
vm.$u.api.phoneBind = (phone, smsCode) => vm.$u.http.post(`${tall}/users/binding`, { phone, smsCode });
// 获取项目列表
vm.$u.api.getProjects = (startTime, endTime) => vm.$u.post(`${tall}/project/query`, { startTime, endTime });
// 查询日历是否有小红点
vm.$u.api.findRedPoint = (startTime, endTime) => vm.$u.post(`${tall}/project/day`, { startTime, endTime });
// 设置项目顺序
vm.$u.api.setProjectSort = params => vm.$u.post(`${tall}/project/setProjectSort`, params);
// 设置项目父子结构
vm.$u.api.setProjectRelation = params => vm.$u.post(`${tall}/project/setProjectRelation`, params);
};
export default { install };

11
src/apis/task.js

@ -1,11 +0,0 @@
const install = (Vue, vm) => {
vm.$u.api = { ...vm.$u.api } || {};
vm.$u.api.getGlobal = param => vm.$u.post(`${uni.$t.domain}/task/global`, param);
vm.$u.api.getPermanent = param => vm.$u.post(`${uni.$t.domain}/task/permanent`, param);
//根据时间基准点和角色查找定期任务
vm.$u.api.getRegularTask = param => vm.$u.post(`${uni.$t.domain}/task/regular`, param);
//修改任务状态
vm.$u.api.updateTaskType = param => vm.$u.post(`${uni.$t.domain}/task/type`, param);
};
export default { install };

6
src/common/styles/index.css

@ -1,6 +0,0 @@
/* ./src/common/styles/index.css */
/*! @import */
@tailwind base;
@tailwind components;
@tailwind utilities;

4462
src/common/styles/tailwind.scss

File diff suppressed because it is too large

94
src/components/Globals/Globals.vue

@ -1,94 +0,0 @@
<template>
<view class="m-2" v-if="globals && globals.length">
<u-card
@click="openCard"
:show-foot="false"
:show-head="false"
:style="{ 'max-height': isShrink ? '106rpx' : '340rpx' }"
border-radius="25"
margin="0"
>
<view slot="body">
<scroll-view :scrollY="true" :style="{ 'max-height': isShrink ? '50rpx' : '280rpx' }">
<skeleton :banner="false" :loading="!globals.length" :row="4" animate class="u-line-2 skeleton"></skeleton>
<view class="grid gap-2">
<template v-for="item in globals">
<template v-if="item.plugins">
<template v-for="pluginArr in item.plugins">
<template class="p-0 u-col-between" v-if="pluginArr.length">
<Plugin
:class="getClass(plugin.col, plugin.row)"
:task="item"
:key="plugin.pluginTaskId"
:plugin-task-id="plugin.pluginTaskId"
:plugin-id="plugin.pluginId"
:style-type="plugin.styleType || 0"
v-for="plugin in pluginArr"
/>
</template>
</template>
</template>
</template>
</view>
</scroll-view>
</view>
</u-card>
</view>
</template>
<script>
import { mapGetters, mapMutations, mapState } from 'vuex';
import Skeleton from '@/components/Skeleton/Skeleton';
export default {
name: 'Global',
components: { Skeleton },
data() {
return {
// loading: true,
task: null,
};
},
computed: {
...mapState('task', ['isShrink']),
...mapGetters('task', ['globals']),
},
methods: {
...mapMutations('task', ['setShrink']),
getClass(col, row) {
return [`row-span-${row}`, `col-span-${col}`];
},
//
openCard() {
if (this.isShrink) {
this.setShrink(false);
}
},
},
};
</script>
<style scoped lang="scss">
.u-card-wrap {
background-color: $u-bg-color;
padding: 1px;
}
.u-body-item {
font-size: 32rpx;
color: #333;
padding: 20rpx 10rpx;
}
.u-body-item image {
width: 120rpx;
flex: 0 0 120rpx;
height: 120rpx;
border-radius: 8rpx;
margin-left: 12rpx;
}
</style>

37
src/components/ImageCode/ImageCode.vue

@ -0,0 +1,37 @@
<template>
<!-- TODO: 设置默认图片 -->
<image :src="src" mode="aspectFit" class="image" @click="getCode"></image>
</template>
<script>
export default {
data() {
return { src: '' };
},
created() {
this.getCode();
},
methods: {
//
async getCode() {
try {
const data = await this.$u.api.getImageCode();
const { imageBase64, verificationCodeId } = data;
this.src = imageBase64;
this.$emit('on-code', verificationCodeId);
} catch (error) {
console.error('error: ', error);
}
},
},
};
</script>
<style lang="scss" scoped>
.image {
width: 100px !important;
height: 35px !important;
}
</style>

136
src/components/Plugin/Plugin.vue

@ -1,136 +0,0 @@
<template>
<view class="u-font-14" style="height: 100%">
<view v-if="pluginContent">
<view
style="height: 100%"
:data-uid="userId"
:data-token="token"
:data-pid="projectId"
:data-did="task.detailId"
:data-rid="roleId"
:data-tid="task.id"
:data-tname="task.name"
:data-pstart="task.planStart"
:data-rstart="task.realStart"
:data-pdu="task.planDuration"
:data-rdu="task.realDuration"
:data-param="param"
v-html="pluginContent"
></view>
</view>
<view v-else>
<!-- <plugin-default /> -->
<!-- <component :task="task" :is="pluginComponent"></component> -->
<p-task-title :task="task" v-if="pluginId === '1'" />
<p-task-description :task="task" v-if="pluginId === '2'" />
<p-task-duration-delay :task="task" v-if="pluginId === '3'" />
<p-task-start-time-delay :task="task" v-if="pluginId === '4'" />
<!-- <p-deliverable :task="task" v-if="pluginId === '5'" /> -->
<p-subtasks :task="task" v-if="pluginId === '6'" />
<p-subproject :task="task" v-if="pluginId === '7'" />
<!-- <p-task-countdown :task="task" v-if="pluginId === '8'" /> -->
<p-manage-project :task="task" v-if="pluginId === '9'" />
<p-manage-role :task="task" v-if="pluginId === '10'" />
<p-manage-member :task="task" v-if="pluginId === '11'" />
<p-manage-task :task="task" v-if="pluginId === '12'" />
<p-wbs-import :task="task" v-if="pluginId === '13' || pluginId === '14'" />
<p-deliver-check :task="task" v-if="pluginId === '15'" />
</view>
</view>
</template>
<script>
import { mapGetters, mapState } from 'vuex';
import pManageProject from '../../plugins/p-manage-project/p-manage-project.vue';
export default {
components: { pManageProject },
name: 'Plugin',
props: {
task: { default: () => {}, type: Object },
pluginId: { default: '1', type: String },
styleType: { default: 0, type: Number },
pluginTaskId: { default: '', type: String },
param: { type: String, default: '' },
},
data() {
return { pluginContent: null };
},
computed: {
...mapState('role', ['roleId']),
...mapState('user', ['token']),
...mapGetters('user', ['userId']),
...mapGetters('project', ['projectId']),
//
// pluginComponent() {
// const target = this.$t.plugin.defaults.find(item => item.id === +this.pluginId);
// if (!target) return '';
// return target.component;
// },
},
created() {
this.getPlugin();
},
methods: {
//
async getPlugin() {
const { pluginId, styleType } = this;
const data = await this.$u.api.getOtherPlugin({
pluginId,
styleType,
});
if (!data || !data.id) return;
const reg = /data-root=["|']?(\w+)["|']?/gi;
let uuid = '';
// FIXME: js, html
if (data.html) {
// data-root=xxx xxx pluginTaskId
if (reg.test(data.html)) {
uuid = RegExp.$1;
const str = data.html.replace(new RegExp(uuid, 'g'), `p${this.pluginTaskId}`);
this.pluginContent = str;
} else {
this.pluginContent = data.html;
}
const str = data.js.replace(new RegExp(uuid, 'g'), `p${this.pluginTaskId}`);
this.handleDom(str);
}
// if (data.js) {
// if (reg.test(data.js)) {
// const uuid = RegExp.$1;
// const str = data.js.replace(new RegExp(uuid, 'g'), `p${this.pluginTaskId}`);
// this.handleDom(str);
// } else {
// this.handleDom(data.js);
// }
// }
},
// script dom
handleDom(js) {
const { pluginTaskId } = this;
let domList = Array.from(document.getElementsByTagName('script'));
const index = domList.findIndex(item => item.id === `p${pluginTaskId}`);
if (index >= 0) {
document.body.removeChild(document.getElementById(`p${pluginTaskId}`));
}
const scriptDom = document.createElement('script');
scriptDom.id = `p${pluginTaskId}`;
scriptDom.setAttribute('data-type', 'plugin');
scriptDom.innerHTML = js;
this.$nextTick(() => {
document.body.append(scriptDom);
});
},
},
};
</script>

480
src/components/PrettyExchange/PrettyExchange.vue

@ -0,0 +1,480 @@
<template>
<view>
<scroll-view scroll-y="true">
<view v-if="!changeEvent">
<view :id="'cu-' + index" :key="item.id" class="cu-item flex-col" v-for="(item, index) in itemList">
<ProjectItem
class="w-full"
:index="index"
:item="item"
:menuList="menuList"
@chooseAction="chooseAction"
@openSubProject="openSubProject"
/>
</view>
</view>
<view v-else>
<view
:id="'cu-' + index"
:key="index"
:style="{ 'background-color': item.color }"
@touchend="stops($event, index)"
@touchmove.stop.prevent="move"
@touchstart="start($event, index)"
class="cu-item flex-col"
v-for="(item, index) in itemList"
>
<view class="border-100 bg-blue-500" v-if="item.showTopBorder"></view>
<!-- 内容区 -->
<!-- 父项目 -->
<view class="w-full">
<view class="flex items-center justify-between p-3">
<u-icon class="mover" name="https://www.tall.wiki/staticrec/drag.svg" size="48"></u-icon>
<view class="flex-1 px-3">
<view class="flex items-center mb-1">
<view class="mr-2">{{ item.name }}</view>
<!-- 状态 TODO:-->
<view class="px-2 text-xs text-green-400 bg-green-100 rounded-full">进行中</view>
</view>
<view class="flex items-center text-xs text-gray-400">
<view class="pr-2">{{ $moment(+item.startTime).format('MM-DD HH:mm') }}</view>
<view class="pl-2">{{ $moment(+item.endTime).format('MM-DD HH:mm') }}</view>
</view>
</view>
<!-- 箭头 -->
<view v-if="item.sonProjectList && item.sonProjectList.length">
<u-icon
@click="openSubProject(item.sonProjectList.length, index)"
class="text-gray-400"
name="arrow-up"
size="14px"
v-if="item.show"
></u-icon>
<u-icon
@click="openSubProject(item.sonProjectList.length, index)"
class="text-gray-400"
name="arrow-down"
size="14px"
v-else
></u-icon>
</view>
<u-icon class="text-gray-400" name="arrow-right" size="14px" v-else></u-icon>
</view>
<!-- 父项目 end -->
<!-- 子项目 -->
<view class="ml-8" v-if="item.show">
<view
:id="'cu-' + index + '-' + subIndex"
:key="subIndex"
@touchend.stop.prevent="stops($event, index + '-' + subIndex, item.sonProjectList.length)"
@touchmove.stop.prevent="move($event, item.sonProjectList.length)"
@touchstart.stop.prevent="start($event, index + '-' + subIndex)"
class="cu-item flex-col"
v-for="(subItem, subIndex) in item.sonProjectList"
>
<view class="flex items-center justify-between p-3 w-full">
<u-icon class="mover" name="https://www.tall.wiki/staticrec/drag.svg" size="48"></u-icon>
<view class="flex-1 px-3">
<view class="flex items-center">
<view class="mr-2">{{ subItem.name }}</view>
<!-- 状态 -->
<view
:class="
subItem.status === 0
? 'text-blue-400 bg-blue-100'
: subItem.status === 1
? 'text-green-400 bg-green-100'
: subItem.status === 2
? 'text-red-400 bg-red-100'
: 'text-gray-400 bg-gray-100'
"
class="px-2 text-xs text-gray-400 bg-gray-100 rounded-full"
>
{{ subItem.status === 0 ? '未开始' : subItem.status === 1 ? '进行中' : subItem.status === 2 ? '暂停' : '已完成' }}
</view>
</view>
</view>
<!-- 箭头 -->
<u-icon class="text-gray-400" name="arrow-right" size="14px"></u-icon>
</view>
</view>
</view>
</view>
<!-- 内容区 end -->
<view class="border-100 bg-blue-500" v-if="item.showBorder"></view>
<view class="border-80 bg-blue-500" v-if="item.showSubBorder"></view>
</view>
</view>
</scroll-view>
<!-- 移动悬浮 begin -->
<view v-if="showMoveImage">
<view :style="{ left: moveLeft + 'px', top: moveTop + 'px' }" class="cu-item absolute">
<ProjectItem class="w-full" :item="moveItem" />
</view>
</view>
<!-- 移动悬浮 end -->
</view>
</template>
<script>
import ProjectItem from '../Projects/ProjectItem.vue';
import { mapState, mapGetters, mapMutations } from 'vuex';
export default {
components: { ProjectItem },
name: 'exchange',
model: { prop: 'showPop', event: 'change' },
data() {
return {
itemTop: 0,
itemLeft: 0,
itemHeight: 0, //
subItemHeight: 0, //
itemWidth: 0, //
showMoveImage: false,
moveItem: '',
moveLeft: 0,
moveTop: 0,
deltaLeft: 0,
deltaTop: 0,
beginleft: 0,
begintop: 0,
itemList: [],
setSubItem: false,
changeEvent: false,
showMenu: false,
tips: {
text: '',
color: '#909399',
fontSize: 28,
},
menuList: [{ text: '复制' }, { text: '编辑' }, { text: '删除' }, { text: '置顶' }, { text: '排序' }],
// show: false,
border: 'border border-blue-500 shadow rounded-md',
showBorder: false,
showItemIndex: undefined,
};
},
computed: {
...mapGetters('user', ['userId']),
...mapState('project', ['projects']),
eventName() {
if (this.changeEvent) {
return 'move.stop.prevent';
} else {
return 'move';
}
},
},
mounted() {
this.$nextTick(function () {
this.itemList = this.projects;
this.itemList.forEach(item => {
item.showBorder = false;
item.showSubBorder = false;
item.showTopBorder = false;
});
});
},
watch: {
projects(val) {
this.itemList = val;
this.itemList.forEach(item => {
item.showBorder = false;
item.showSubBorder = false;
item.showTopBorder = false;
});
},
},
methods: {
...mapMutations('project', ['setProjectItemShow']),
//
openSubProject(length, index) {
this.setProjectItemShow({ index, show: this.itemList[index].show ? false : true });
if (length && index) {
this.$emit('changeHeight', length, index);
}
this.showItemIndex = index;
},
//
getDate() {
const query = uni.createSelectorQuery().in(this);
query
.select(`#cu-0`)
.boundingClientRect(data => {
console.log('data: ', data);
this.begintop = data.top;
this.beginleft = data.left;
})
.exec();
},
//
chooseAction(index) {
if (this.menuList[index].text === '排序') {
this.changeEvent = true;
this.$t.ui.showToast('请移动进行排序');
}
if (this.showItemIndex !== undefined) {
this.setProjectItemShow({ index: this.showItemIndex, show: true });
}
},
isNumber(val) {
return val === +val;
},
start(e, index) {
console.log('开始', e);
setTimeout(() => {
this.getDate();
}, 300);
if (this.isNumber(index)) {
this.setSubItem = false;
const query = uni.createSelectorQuery().in(this);
query
.select(`#cu-${index}`)
.boundingClientRect(data => {
this.moveTop = data.top;
this.moveLeft = data.left;
this.moveItem = this.itemList[index];
this.itemWidth = data.width;
this.itemHeight = data.height;
})
.exec();
} else {
let arr = index.split('-');
this.setSubItem = true;
const query = uni.createSelectorQuery().in(this);
query
.select(`#cu-${arr[0] - 0}`)
.boundingClientRect(data => {
this.itemHeight = data.height;
})
.exec();
query
.select(`#cu-${index}`)
.boundingClientRect(data => {
this.moveTop = data.top;
this.moveLeft = data.left;
this.moveItem = this.itemList[arr[0] - 0].sonProjectList[arr[1] - 0];
this.itemWidth = data.width;
this.subItemHeight = data.height;
})
.exec();
}
},
move(e, length) {
console.log('移动');
this.showMoveImage = true; //
const touch = e.touches[0];
if (this.deltaLeft == 0) {
//
this.deltaLeft = touch.pageX - this.moveLeft;
this.deltaTop = touch.pageY - this.moveTop;
}
this.moveLeft = touch.pageX - this.deltaLeft;
this.moveTop = touch.pageY - this.deltaTop;
let lastIndex = (lastIndex = this.findOverIndex(touch.pageY, length));
// 线
for (let i = 0; i < this.itemList.length; i++) {
if (this.moveLeft > 35) {
this.itemList[i].showBorder = false;
this.itemList[i].showTopBorder = false;
if (i === lastIndex) {
this.itemList[i].showSubBorder = true;
} else {
this.itemList[i].showSubBorder = false;
}
} else {
if (lastIndex === -1) {
this.itemList[0].showTopBorder = true;
this.itemList[i].showSubBorder = false;
this.itemList[i].showBorder = false;
} else {
this.itemList[i].showSubBorder = false;
this.itemList[i].showTopBorder = false;
if (i === lastIndex) {
this.itemList[i].showBorder = true;
} else {
this.itemList[i].showBorder = false;
}
}
}
}
},
stops(e, index, length) {
console.log('结束');
const touch = e.mp.changedTouches[0];
let lastIndex = (lastIndex = this.findOverIndex(touch.pageY, length));
//
for (let i = 0; i < this.itemList.length; i++) {
//
if (this.itemList[i].showTopBorder) {
if (this.isNumber(index)) {
let Value = this.itemList[index];
this.itemList.unshift(Value);
this.itemList.splice(index + 1, 1);
} else {
let arr = index.split('-');
let Value = this.itemList[arr[0] - 0].sonProjectList[arr[1] - 0];
this.itemList.unshift(Value);
this.itemList[arr[0] - 0].sonProjectList.splice([arr[1] - 0], 1);
const options = {
id: Value.id,
parentId: 0,
};
this.$emit('change', options);
}
//
this.clearSet(i);
this.$emit('change', this.itemList);
return;
}
//
if (this.itemList[i].showBorder) {
if (this.isNumber(index)) {
let Value = this.itemList[index];
this.itemList.splice(i + 1, 0, Value);
if (i < index) {
this.itemList.splice(index + 1, 1);
} else {
this.itemList.splice(index, 1);
}
} else {
let arr = index.split('-');
let Value = this.itemList[arr[0] - 0].sonProjectList[arr[1] - 0];
this.itemList.splice(i + 1, 0, Value);
this.itemList[arr[0] - 0].sonProjectList.splice([arr[1] - 0], 1);
const options = {
id: Value.id,
parentId: 0,
};
this.$emit('change', options);
}
//
this.clearSet(i);
this.$emit('change', this.itemList);
return;
}
//
if (this.itemList[i].showSubBorder) {
if (this.isNumber(index)) {
let Value = this.itemList[index];
if (this.itemList[lastIndex - 1].sonProjectList && this.itemList[lastIndex - 1].sonProjectList.length) {
this.itemList[lastIndex - 1].sonProjectList.push(Value);
} else {
this.itemList[lastIndex].sonProjectList = [Value];
}
this.itemList.splice(index, 1);
//
this.clearSet(i);
const options = {
id: Value.id,
parentId: this.itemList[lastIndex - 1].id,
};
this.$emit('change', options);
} else {
let arr = index.split('-');
let Value = this.itemList[arr[0] - 0].sonProjectList[arr[1] - 0];
if (this.itemList[lastIndex].sonProjectList && this.itemList[lastIndex].sonProjectList.length) {
this.itemList[lastIndex].sonProjectList.push(Value);
} else {
this.itemList[lastIndex].sonProjectList = [Value];
}
this.itemList[arr[0] - 0].sonProjectList.splice([arr[1] - 0], 1);
//
this.clearSet(i);
const options = {
id: Value.id,
parentId: this.itemList[lastIndex].id,
};
this.$emit('change', options);
const options1 = {
id: Value.id,
parentId: 0,
};
this.$emit('change', options1);
}
return;
}
}
},
//
clearSet(i) {
this.itemList[i].showBorder = false;
this.itemList[i].showSubBorder = false;
this.itemList[i].showTopBorder = false;
this.deltaLeft == 0;
this.showMoveImage = false;
this.setSubItem = false;
this.changeEvent = false;
this.showItemIndex = undefined;
},
//
findOverIndex(posY) {
//
let leng = this.itemList.length * this.itemHeight; //
if (posY < this.begintop) {
return -1;
}
for (var i = 0; i < this.itemList.length; i++) {
let begin = this.itemHeight * i + this.begintop;
let end = this.itemHeight * i + this.begintop + this.itemHeight;
if (begin <= posY && end >= posY) {
return i;
}
}
if (posY > leng) {
//
return this.itemList.length - 1;
} else if (posY < this.begintop) {
return 0;
}
},
},
};
</script>
<style lang="scss" scoped>
.cu-item {
width: 100%;
display: flex;
align-items: center;
font-size: 14px;
}
.border-100 {
width: 92%;
height: 4rpx;
}
.border-80 {
width: 84%;
height: 2px;
margin-left: 30px;
}
</style>

157
src/components/Projects/ProjectItem.vue

@ -1,7 +1,150 @@
<template>
<view class="flex items-center justify-between">
这是子项目
</template>
<script>
export default {};
</script>
<template>
<view class="w-full">
<!-- 有子项目 -->
<view class="flex items-center justify-between p-3">
<u-icon @click="openMenu(item)" class="mover" name="https://www.tall.wiki/staticrec/drag.svg" size="48"></u-icon>
<view @click="openProject(item)" class="flex-1 px-3">
<view class="flex items-center mb-1">
<view class="mr-2">{{ item.name }}</view>
<!-- 状态 TODO:-->
<view class="px-2 text-xs text-green-400 bg-green-100 rounded-full">进行中</view>
</view>
<view class="flex items-center text-xs text-gray-400">
<view class="pr-2">{{ $moment(+item.startTime).format('MM-DD HH:mm') }}</view>
<view class="pl-2">{{ $moment(+item.endTime).format('MM-DD HH:mm') }}</view>
</view>
</view>
<!-- 箭头 -->
<view v-if="item.sonProjectList && item.sonProjectList.length">
<u-icon
@click="$emit('openSubProject', item.sonProjectList.length, index)"
class="text-gray-400"
name="arrow-up"
size="14px"
v-if="item.show"
></u-icon>
<u-icon
@click="$emit('openSubProject', item.sonProjectList.length, index)"
class="text-gray-400"
name="arrow-down"
size="14px"
v-else
></u-icon>
</view>
<u-icon @click="openProject(item)" class="text-gray-400" name="arrow-right" size="14px" v-else></u-icon>
</view>
<!-- 有子项目 -->
<view class="ml-8" v-if="item.show">
<view
:id="'cu-' + index + '-' + subIndex"
:key="subIndex"
class="cu-item flex-col"
v-for="(subItem, subIndex) in item.sonProjectList"
>
<!-- <view :key="subItem.id" v-for="subItem in item.sonProjectList"> -->
<view class="flex items-center justify-between p-3">
<u-icon @click="openMenu(subItem)" class="mover" name="https://www.tall.wiki/staticrec/drag.svg" size="48"></u-icon>
<view @click="openProject(subItem)" class="flex-1 px-3">
<view class="flex items-center">
<view class="mr-2">{{ subItem.name }}</view>
<!-- 状态 -->
<view
:class="
subItem.status === 0
? 'text-blue-400 bg-blue-100'
: subItem.status === 1
? 'text-green-400 bg-green-100'
: subItem.status === 2
? 'text-red-400 bg-red-100'
: 'text-gray-400 bg-gray-100'
"
class="px-2 text-xs text-gray-400 bg-gray-100 rounded-full"
>
{{ subItem.status === 0 ? '未开始' : subItem.status === 1 ? '进行中' : subItem.status === 2 ? '暂停' : '已完成' }}
</view>
</view>
</view>
<!-- 箭头 -->
<u-icon @click="openProject(subItem)" class="text-gray-400" name="arrow-right" size="14px"></u-icon>
</view>
</view>
</view>
<!-- 项目操作面板 -->
<u-action-sheet :list="menuList" :tips="tips" @click="$emit('chooseAction', $event)" v-model="showMenu"></u-action-sheet>
</view>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
props: {
item: {
type: Object,
default: () => {},
},
index: {
type: Number,
default: 0,
},
menuList: {
type: Array,
default: () => [],
},
},
data() {
return {
showMenu: false,
tips: {
text: '',
color: '#909399',
fontSize: 28,
},
show: false,
border: 'border border-blue-500 shadow rounded-md',
showBorder: false,
};
},
computed: mapGetters('user', ['userId']),
methods: {
//
openProject(project) {
const { name, id, url } = project;
url && (uni.$t.domain = url);
this.$u.route('pages/project-webview/project-webview', {
u: this.userId,
p: id,
pname: name,
url: encodeURIComponent(url),
});
},
/**
* 弹出项目操作面板
*/
openMenu(project) {
this.showMenu = true;
this.tips.text = project.name;
},
},
};
</script>
<style lang="scss" scoped>
.border-100 {
height: 4rpx;
margin: 0 20rpx;
}
.border-80 {
height: 4rpx;
margin: 0 20rpx 0 90rpx;
}
</style>

99
src/components/Projects/Projects.vue

@ -1,72 +1,65 @@
<template>
<view class="py-3 mt-4 bg-white u-font-15">
<view v-for="(project, index) in projects" :key="index">
<!-- 有子项目 -->
<view class="flex items-center justify-between p-3">
<view class="text-blue-400 border border-blue-200 rounded-full order bg-blue-50">
{{ index + 1 }}
</view>
<view class="flex-1 px-3">
<view class="flex items-center mb-1">
<view class="mr-2">{{ project.name }}</view>
<!-- 状态 TODO:-->
<view class="px-2 text-xs text-green-400 bg-green-100 rounded-full">进行中</view>
</view>
<view class="flex items-center text-xs text-gray-400">
<view class="pr-2">{{ $moment(+project.startTime).format('MM-DD HH:mm') }}</view>
<view class="pl-2"> {{ $moment(+project.endTime).format('MM-DD HH:mm') }}</view>
</view>
</view>
<!-- 箭头 -->
<u-icon name="arrow-right" class="text-gray-400" size="14px" @click="openProject(project)"></u-icon>
</view>
</view>
<PrettyExchange @change="change" />
</view>
</template>
<script>
import { mapGetters, mapState } from 'vuex';
import PrettyExchange from '../PrettyExchange/PrettyExchange.vue';
export default {
components: { PrettyExchange },
data() {
return {};
},
computed: {
...mapState('project', ['projects']),
...mapGetters('user', ['userId']),
},
methods: {
change(options) {
if (options instanceof Array) {
let projectIdList = [];
let arr = [];
options.forEach(item => {
projectIdList.push(item.id);
arr.push(item.name);
});
this.setProjectSort(projectIdList);
} else {
this.setProjectRelation(options);
}
},
/**
* 设置项目顺序
* @param { Array } projectIdList 项目id
*/
async setProjectSort(projectIdList) {
try {
const params = { projectIdList };
await this.$u.api.setProjectSort(params);
this.$t.ui.showToast('排序修改成功');
} catch (error) {
console.log('error: ', error);
this.$t.ui.showToast(error.msg || '排序修改失败');
}
this.$emit('getProjects');
},
/**
* 打开项目
* @param {object} project 所点击的项目的信息
* 设置项目父子结构
* @param { string } id 当前移动的项目的id
* @param { string } parentId 父项目的id
*/
openProject(project) {
const { name, id, url } = project;
url && (uni.$t.domain = url);
this.$u.route('pages/project/project', {
u: this.userId,
p: id,
pname: name,
url: encodeURIComponent(url),
});
async setProjectRelation(options) {
try {
const params = options;
await this.$u.api.setProjectRelation(params);
this.$t.ui.showToast('排序修改成功');
} catch (error) {
console.error('error: ', error);
this.$t.ui.showToast(error.msg || '排序修改失败');
}
this.$emit('getProjects');
},
},
};
</script>
<style lang="scss" scoped>
.order {
display: flex;
justify-content: center;
align-items: center;
width: 32px;
height: 32px;
font-size: 13px;
}
</style>

222
src/components/Roles/Roles.vue

@ -1,222 +0,0 @@
<template>
<view class="px-2 bg-white wrap">
<view class="home-box u-skeleton">
<scroll-view :enable-flex="true" :scroll-left="scrollLeft" :throttle="false" scroll-with-animation scroll-x>
<view class="tab-box">
<!-- 角色项 -->
<view :key="index" @click="changeRole(item.id, index)" class="tab-item" v-for="(item, index) in roles">
<view :class="setColor(item.mine, item.id)" class="tab-children u-skeleton-fillet u-font-14">{{ item.name }}</view>
</view>
</view>
</scroll-view>
</view>
<!-- 骨架屏 -->
<u-skeleton :animation="true" :loading="loading" bg-color="#fff"></u-skeleton>
</view>
</template>
<script>
import { mapState, mapMutations, mapActions } from 'vuex';
export default {
name: 'Roles',
data() {
return {
tabIndex: 0, // 访 index 0
tabList: [], // tab dom
scrollLeft: 0, // scrollview
loading: false, //
roles: [
{ id: 1, name: '项目经理', mine: 0, pm: 1, sequence: 1 },
{ id: 2, name: '运维', mine: 0, pm: 0, sequence: 2 },
],
};
},
computed: {
...mapState('role', ['visibleRoles', 'roleId']),
...mapState('task', ['tasks']),
},
watch: {
visibleRoles(val) {
if (val && val.length) {
this.roles = [...this.visibleRoles];
this.loading = false;
}
},
},
mounted() {
if (!this.visibleRoles || !this.visibleRoles.length) {
this.loading = true;
} else {
this.roles = [...this.visibleRoles];
}
},
methods: {
...mapActions('task', ['handleRegularTask', 'getPermanent']),
...mapMutations('role', ['setRoleId']),
...mapMutations('task', ['setPermanents', 'clearEndFlag']),
//
setCurrentRole(index) {
console.log('index: ', index);
const data = document.getElementsByClassName('tab-children');
// tabList
data.forEach(item => {
this.tabList.push({
width: item.clientWidth,
left: item.offsetLeft,
});
});
//
let left = 0;
let screenWidth = window.screen.width;
for (let i = 0; i < index; i++) {
left += this.tabList[i].width + this.tabList[i].left * 2;
}
left += this.tabList[index].width;
this.scrollLeft = left - screenWidth / 2;
},
//
// projectroleId
// projectroleId
changeRole(id, index) {
try {
// script
this.clearPluginScript();
this.$nextTick(() => {
this.setRoleId(id);
//index
this.setCurrentRole(index);
});
} catch (error) {
console.error('role.vue changeRole error: ', error);
}
},
// script
clearPluginScript() {
try {
const scripts = document.querySelectorAll('script[data-type=plugin]');
for (let i = 0; i < scripts.length; i++) {
document.body.removeChild(scripts[i]);
}
} catch (error) {
console.error('clearPluginScript error: ', error);
}
},
//
setColor(mine, id) {
const { roleId } = this;
// &&
if (+mine === 1 && roleId === id) return 'default-tab-choice';
// &&
if (+mine === 1 && roleId !== id) return 'default-tab-item';
// &&
if (+mine === 0 && roleId === id) return 'tab-choice';
},
},
};
</script>
<style lang="scss" scoped>
.home-box {
// sticky
position: sticky;
top: 0;
background: #fff; //
/* #ifdef H5 */
// h5 44px
top: 88rpx;
/* #endif */
.tab-box {
position: relative;
white-space: nowrap;
// height: 84rpx;
.tab-item {
// width: 20%;
// height: 84rpx;
padding: 20rpx 24rpx;
position: relative;
display: inline-block;
text-align: center;
font-size: 30rpx;
transition-property: background-color, width;
}
.default-tab-item {
color: $roleChoiceColor;
}
.default-tab-choice {
//
position: relative;
color: $roleChoiceColor;
font-weight: 600;
}
.default-tab-choice:before {
content: '';
position: absolute;
left: 0;
bottom: -20rpx;
width: 100%;
height: 6rpx;
border-radius: 2rpx;
background: $roleChoiceColor;
}
.tab-choice {
//
position: relative;
color: $uni-color-primary;
font-weight: 600;
}
.tab-choice:before {
content: '';
position: absolute;
left: 0;
bottom: -20rpx;
width: 100%;
height: 6rpx;
border-radius: 2rpx;
background: $uni-color-primary;
}
}
}
// //
/* #ifndef APP-NVUE */
::-webkit-scrollbar,
::-webkit-scrollbar,
::-webkit-scrollbar {
display: none;
width: 0 !important;
height: 0 !important;
-webkit-appearance: none;
background: transparent;
}
/* #endif */
/* #ifdef H5 */
// 穿H5scroll-view
scroll-view ::v-deep ::-webkit-scrollbar {
display: none;
}
/* #endif */
.skeleton {
height: 44rpx;
}
</style>

84
src/components/Skeleton/READ_ME.md

@ -1,84 +0,0 @@
# skeleton组件
### 1.描述
> 此组件用于加载数据时占位图显示,跟vant-ui骨架屏用法相似,但比vant-ui更灵活
### 2.用法
- 基本用法
代码:
```vue
//基本用法
<skeleton :row="3" animate :loading="loading" >
<view>
content
</view>
</skeleton>
```
- **显示 title ——通过 **title 属性显示title占位图
代码:
```vue
//显示 title——通过 title 属性显示title占位图
<skeleton :row="3" title animate :loading="loading">
<view>
content
</view>
</skeleton>
```
- 显示头像(上面)——通过avatar=‘top’让头像的占位图上面显示
代码:
```vue
<skeleton :avatar="top" avatarAlign="left" :row="3" animate :loading="loading" style="margin-top:24rpx;">
<view>
content
</view>
</skeleton>
```
- 显示头像(左边)——通过avatar=‘left’让头像的占位图左边显示
代码:
```vue
<skeleton title :avatar="left" :row="3" animate :loading="loading" style="margin-top:24rpx;">
<view>
content
</view>
</skeleton>
```
- 显示banner**——通过 **banner属性显示banner占位图(只显示banner,不显示内容占位图时设置row="0")
代码:
```vue
<skeleton banner :row="0" animate :loading="loading" style="margin-top:24rpx;">
<view>
content
</view>
</skeleton>
```
###
### 3. API
### Props
| **属性名** | **说明** | **类型** | **默认值** | 可取值 |
| --- | --- | --- | --- | --- |
| loading | 是否显示骨架屏 | Boolean | true | true/false |
| row | 段落行数 | Number | String | 3 | 0表示不展现 |
| rowWidth | 段落行宽度 | Boolean &#124; Number | '100%' | |
| title | 是否显示标题 | Boolean &#124; String | false | |
| banner | 是否显示banner | Boolean &#124; String | false | |
| animate | 是否开启动画 | Boolean &#124; String | false | |
| avatar | 头像位置 | Boolean &#124; String | ''空 | left/top |
| avatarSize | 头像大小 | String | - | |
| avatarShape | 头像形状 | String | circle | circle/round |

186
src/components/Skeleton/Skeleton.vue

@ -1,186 +0,0 @@
<template>
<view>
<view :class="[avatarClass, animationClass]" class="lx-skeleton" v-show="loading">
<view :class="[avatarShapeClass, bannerClass]" :style="{ width: avatarSize, height: avatarSize }" class="avatar-class"></view>
<view :style="{ width: rowWidth }" class="row">
<view class="row-class lx-skeleton_title" v-if="title"></view>
<view :key="index" class="row-class" v-for="(item, index) in row"></view>
</view>
</view>
<slot v-if="!loading"></slot>
</view>
</template>
<script>
/**
* skeleton 骨架屏
* @description 用于加载数据时占位图显示跟Vant-UI用法相似但比Vant-UI更灵活
* @property {Boolean} loading 是否显示骨架屏默认为true
* @property {Number | String} row 段落行数默认为3
* @property {Boolean | Number} rowWidth 段落行宽度默认为100%
* @property {Boolean | String} title 是否显示标题默认为false
* @property {Boolean | String} banner 是否显示banner默认为false
* @property {Boolean | String} animate 是否开启动画默认为false
* @property {Boolean | String} avatar 头像位置
* @property {String} avatarSize 头像大小
* @property {String} avatarShape 头像形状默认为circle
*
* */
export default {
props: {
loading: {
type: Boolean,
default: true,
},
row: {
type: Number,
default: 3,
},
title: {
type: String,
default: '',
},
avatar: {
type: String,
default: '',
},
animate: {
type: Boolean,
default: false,
},
avatarSize: { type: String },
rowWidth: {
type: String,
default: '100%',
},
avatarShape: {
type: String,
default: 'circle',
},
banner: {
type: Boolean,
default: false,
},
// avator-size:{
// type: String,
// defualt: '32px'
// }
},
computed: {
avatarClass() {
if (this.avatar == 'top') {
return ['lx-skeleton_avator__top'];
} else if (this.avatar == 'left') {
return ['lx-skeleton_avator__left'];
} else {
return '';
}
},
animationClass() {
return [this.animate ? 'lx-skeleton_animation' : ''];
},
slotClass() {
return [!this.loading ? 'show' : 'hide'];
},
avatarShapeClass() {
return [this.avatarShape == 'round' ? 'lx-skeleton_avator__round' : ''];
},
bannerClass() {
return [this.banner ? 'lx-skeleton_banner' : ''];
},
},
data() {
return {};
},
};
</script>
<style lang="scss" scoped>
.lx-skeleton {
background-color: #fff;
padding: 12px;
}
.lx-skeleton_avator__left {
display: flex;
width: 100%;
}
.lx-skeleton_avator__left .avatar-class,
.lx-skeleton_avator__top .avatar-class {
background-color: #f2f3f5;
border-radius: 50%;
width: 32px;
height: 32px;
}
.lx-skeleton_avator__left .avatar-class.lx-skeleton_avator__round,
.lx-skeleton_avator__top .avatar-class.lx-skeleton_avator__round {
border-radius: 0;
width: 32px;
height: 32px;
}
.lx-skeleton_avator__left .avatar-class {
margin-right: 16px;
}
.lx-skeleton_avator__top .avatar-class {
margin: 0 auto 12px auto;
}
.row-class {
width: 100%;
height: 16px;
background-color: #f2f3f5;
}
.row-class:not(:first-child) {
margin-top: 12px;
}
.row {
flex: 1;
}
.lx-skeleton_avator__left .row {
width: calc(100% - 48px);
}
.row-class:nth-last-child(1) {
width: 60%;
}
.lx-skeleton_animation .row-class {
animation-duration: 1.5s;
animation-name: blink;
animation-timing-function: ease-in-out;
animation-iteration-count: infinite;
}
@keyframes blink {
50% {
opacity: 0.6;
}
}
.lx-skeleton_title {
width: 40%;
}
.show {
display: block;
}
.hide {
display: none;
}
.lx-skeleton .lx-skeleton_banner {
width: 92%;
margin: 10px auto;
height: 64px;
border-radius: 0;
background-color: #f2f3f5;
}
</style>

45
src/components/Skeleton/view.vue

@ -1,45 +0,0 @@
<template>
<view>
<nav-bar title="骨架屏"></nav-bar>
<view class="content">
基础用法
<skeleton :row="3" animate :loading="loading">
<view> content1 </view>
</skeleton>
显示 title
<skeleton :row="3" title animate :loading="loading">
<view> content2 </view>
</skeleton>
显示头像上面)
<skeleton :avatar="avatarTop" :row="3" animate :loading="loading" style="margin-top: 24rpx">
<view> content3 </view>
</skeleton>
显示头像左面
<skeleton title :avatar="avatarLeft" :row="3" animate :loading="loading" style="margin-top: 24rpx">
<view> content4 </view>
</skeleton>
显示banner
<skeleton banner :row="0" animate :loading="loading" style="margin-top: 24rpx">
<view> content5 </view>
</skeleton>
</view>
</view>
</template>
<script>
export default {
data() {
return {
loading: true, //
avatarTop: 'top',
avatarLeft: 'left',
};
},
onLoad() {
//
setTimeout(() => {
this.loading = false;
}, 3000);
},
};
</script>

1
src/components/Skeleton/wisdomcar_mobile

@ -1 +0,0 @@
Subproject commit 2603a0bc8b5036c399a5f28b93586072c4850c4b

119
src/components/TimeLine/TimeLine.vue

@ -1,119 +0,0 @@
<template>
<!-- 时间间隔栏 -->
<!-- <Barrier /> -->
<scroll-view
:lower-threshold="300"
scroll-y="true"
:upper-threshold="300"
:scroll-into-view="viewId"
@scroll="scroll"
@scrolltolower="handleScrollBottom"
@scrolltoupper="handleScrollTop"
id="scroll"
>
<!-- 时间轴 -->
<!-- <u-divider bg-color="#f3f4f6" class="pt-5" fontSize="14px" v-if="topEnd">到顶啦</u-divider> -->
<TimeBox />
<!-- <u-divider bg-color="#f3f4f6" class="pb-5" fontSize="14px" v-if="bottomEnd">到底啦</u-divider> -->
</scroll-view>
</template>
<script>
// import Barrier from './component/Barrier.vue';
import { mapState, mapMutations, mapGetters } from 'vuex';
import TimeBox from './component/TimeBox.vue';
import mixin from '@/mixins/timeline';
export default {
name: 'TimeLine',
components: { TimeBox },
mixins: [mixin],
data() {
return { top: 0 };
},
computed: {
...mapState('role', ['visibleRoles']),
...mapState('task', ['scrollTop', 'showTips', 'tasks', 'topEnd', 'bottomEnd', 'showSkeleton', 'timeNode', 'viewId']),
...mapGetters('task', ['timeGranularity']),
},
methods: {
...mapMutations('task', ['setScrollTop', 'setShrink', 'setUpTasks', 'setDownTasks', 'setViewId']),
//
scroll(e) {
this.top = e.detail.scrollTop;
this.setShrink(this.top > this.scrollTop);
this.setScrollTop(this.top);
},
//
async handleScrollTop() {
if (!this.tasks || !this.tasks.length || this.showSkeleton) return;
const startTime = this.tasks[0].planStart - 0;
if ((this.tasks[0].plugins && this.tasks[0].plugins.length === 0) || this.topEnd) {
//
console.warn('滚动到顶部没有数据时: ');
const addTasks = this.setTime(startTime, true);
this.setUpTasks(addTasks);
} else {
//
console.warn('滚动到顶部有数据时: ');
const upQuery = {
timeNode: startTime,
queryType: 0,
queryNum: 6,
};
await this.$emit('getTasks', upQuery);
}
},
//
async handleScrollBottom() {
if (!this.tasks || !this.tasks.length || this.showSkeleton) return;
const { tasks, timeGranularity } = this;
const startTime = tasks[tasks.length - 1].planStart - 0;
if ((tasks[0].plugins && tasks[0].plugins.length === 0) || this.bottomEnd) {
//
console.warn('滚动到底部没有数据时: ');
const addTasks = this.setTime(startTime, false);
this.setDownTasks(addTasks);
} else {
// =+
console.warn('滚动到底部有数据时: ');
const timeNode = this.$t.time.add(startTime, 1, timeGranularity).valueOf();
const downQuery = {
timeNode,
queryType: 1,
queryNum: 6,
};
await this.$emit('getTasks', downQuery);
}
},
//
setScrollPosition() {
const { tasks, timeNode } = this;
for (let i = 0; i < tasks.length; i++) {
const item = tasks[i];
const show = this.$t.time.isSame(+item.planStart, +timeNode, this.timeGranularity);
// storagetimeNode,storetimeNode
const taskId = this.$t.storage.getStorageSync('taskId');
// storage
if (taskId) {
this.setViewId(`a${taskId}`);
this.$t.storage.setStorageSync('taskId', '');
return;
}
if (show) {
this.setViewId(`a${item.id}`);
return;
}
}
},
},
};
</script>

42
src/components/TimeLine/component/Barrier.vue

@ -1,42 +0,0 @@
<!--
* @Author: aBin
* @email: binbin0314@126.com
* @Date: 2021-07-19 14:22:54
* @LastEditors: aBin
* @LastEditTime: 2021-07-20 11:46:04
-->
<template>
<view class>
<!-- :class="{ active: cycleTasks.time.start === filter.startTime }" -->
<view class="cycle-time active">
<!-- {{ $util.formatStartTimeToCycleTime(filter.time, cycleTasks.time.start) }} -->
2021年30周
</view>
</view>
</template>
<script>
export default {
name: 'Barrier',
data() {
return {};
},
};
</script>
<style scoped lang="scss">
.cycle-time {
padding: 8rpx 16rpx;
margin-bottom: 16rpx;
background: #fafafc;
color: $uni-text-color;
font-size: 28rpx;
position: sticky;
top: -1px;
left: 0;
z-index: 99;
&.active {
background: $uni-color-primary;
color: $uni-text-color-inverse;
}
}
</style>

11
src/components/TimeLine/component/TaskTools.vue

@ -1,11 +0,0 @@
<template>
<view class="flex justify-between" style="min-width: 90px">
<u-icon custom-prefix="custom-icon" name="C-bxl-redux" size="17px"></u-icon>
<u-icon custom-prefix="custom-icon" name="attachment" size="21px"></u-icon>
<u-icon custom-prefix="custom-icon" name="moneycollect" size="20px"></u-icon>
</view>
</template>
<script>
export default {};
</script>

147
src/components/TimeLine/component/TimeBox.vue

@ -1,147 +0,0 @@
<template>
<view class="column">
<!-- v-if="tasks && tasks.length" -->
<view>
<view :key="task.id" v-for="task in tasks" class="ssssss" :id="`a${task.id}`">
<view class="flex">
<TimeStatus :task="task" />
<view class="flex items-center justify-between flex-1 ml-2 task-column">
<view v-if="task.process !== 4">{{ $moment(+task.planStart).format(startTimeFormat) }}</view>
<view v-else>{{ $moment(+task.planStart).format('D日') }}</view>
<!-- 任务功能菜单 -->
<TaskTools v-if="task.process !== 4" />
</view>
</view>
<view class="border-l-2 border-gray-300 plugin">
<view class="h-3" v-if="task.process === 4"></view>
<view class="ml-3 overflow-hidden shadow-lg task-box">
<u-card
:show-foot="false"
:show-head="false"
:style="{ height: setHeight(task.panel) }"
class="h-16"
margin="0"
v-if="showSkeleton"
>
<view slot="body">
<view>
<skeleton :banner="false" :loading="true" :row="4" animate class="mt-2 u-line-2 skeleton"></skeleton>
</view>
</view>
</u-card>
<u-card
:show-foot="false"
:show-head="false"
:style="{ height: setHeight(task.panel) }"
class="h-16"
margin="0"
v-if="tasks && tasks.length && task.process !== 4 && !showSkeleton"
@click="onClickTask(+task.planStart, task.id)"
>
<!-- 任务面板插件 -->
<view slot="body">
<view class="p-0 u-col-between">
<view :key="pIndex" v-for="(row, pIndex) in task.plugins">
<view class="grid gap-2" v-if="row.length">
<Plugin
:class="getClass(plugin.col, plugin.row)"
:task="task"
:key="plugin.pluginTaskId"
:plugin-task-id="plugin.pluginTaskId"
:plugin-id="plugin.pluginId"
:param="plugin.param"
:style-type="styleType || 0"
v-for="plugin in row"
/>
</view>
</view>
</view>
</view>
</u-card>
</view>
</view>
</view>
</view>
<!-- 局部弹框操作栏 -->
<Tips />
</view>
</template>
<script>
import { mapState, mapMutations, mapGetters, mapActions } from 'vuex';
import Skeleton from '@/components/Skeleton/Skeleton';
import TimeStatus from './TimeStatus.vue';
import TaskTools from './TaskTools.vue';
export default {
name: 'TimeBox',
components: { TimeStatus, Skeleton, TaskTools },
data() {
return { currentComponent: '', styleType: 0 };
},
computed: {
...mapState('role', ['roleId']),
...mapState('task', ['timeUnit', 'tasks', 'taskLoading', 'topEnd', 'bottomEnd', 'showSkeleton']),
...mapGetters('task', ['startTimeFormat']),
},
methods: {
...mapActions('task', ['getGlobal']),
...mapMutations('task', ['setTipsContent', 'setTipsContent']),
//
setHeight(panel) {
if (panel && panel.height) {
return panel.height + 'px';
} else {
return 'auto';
}
},
/**
* 点击了定期任务的面板 更新可变的日常任务
* @param {number} planStart 任务计划开始时间
* @param {string} taskId 任务id
*/
onClickTask(planStart, taskId) {
const param = { roleId: this.roleId, timeNode: planStart, timeUnit: this.timeUnit };
this.getGlobal(param);
this.$t.storage.setStorageSync('taskId', taskId);
this.$t.storage.setStorageSync('roleId', this.roleId);
},
//
getClass(col, row) {
return [`row-span-${row}`, `col-span-${col}`];
},
},
};
</script>
<style scoped lang="scss">
.task-box {
border-radius: 24rpx;
}
.column {
padding: 24px 14px;
}
.task-column {
height: 33px;
}
.plugin {
margin-top: 8px;
margin-bottom: 8px;
margin-left: 15px;
}
/deep/ .ml-2 {
margin-left: 16px;
}
/deep/ .ml-3 {
margin-left: 20px;
}
</style>

211
src/components/TimeLine/component/TimeStatus.vue

@ -1,211 +0,0 @@
<template>
<view class="u-font-14">
<view
class="flex items-center justify-center rounded-full icon-column"
:style="{ color: orderStyle.color }"
@tap="changeStatus($event, task.process)"
>
<!-- 1进行中 2暂停中 3已完成 -->
<u-circle-progress
:percent="+orderStyle.persent"
:active-color="orderStyle.color"
bg-color="rgba(255,255,255,0)"
border-width="4"
:width="task.process !== 4 ? 66 : 50"
v-if="task.process === 1 || task.process === 2 || task.process === 3"
>
<view class="u-progress-content">
<view class="u-progress-dot"></view>
<view class="u-progress-info">
<u-icon :name="orderStyle.icon" v-if="orderStyle.icon" size="15px"></u-icon>
<template v-else>{{ computeDurationText() }}</template>
</view>
</view>
</u-circle-progress>
<!-- 0未开始 4添加任务 -->
<view class="progress-box flex justify-center items-center rounded-full" v-else :class="task.process === 4 ? 'progress-box-4' : ''">
<view class="u-progress-content">
<view class="u-progress-dot"></view>
<view class="u-progress-info">
<span v-if="orderStyle.icon">
<u-icon :name="orderStyle.icon" v-if="task.process !== 4" size="15px"></u-icon>
<u-icon :name="orderStyle.icon" v-else size="15px"></u-icon>
</span>
<template v-else>{{ computeDurationText() }}</template>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import { mapState, mapMutations } from 'vuex';
export default {
name: 'TimeStatus',
props: { task: { type: Object, default: () => {} } },
data() {
return {
time: '',
start: [{ text: '确认开始任务', color: 'blue' }],
pause: [{ text: '继续' }, { text: '重新开始任务', color: 'blue' }, { text: '结束' }],
proceed: [{ text: '暂停' }, { text: '重新开始任务', color: 'blue' }, { text: '结束' }],
again: [{ text: '重新开始任务', color: 'blue' }],
timer: null,
};
},
computed: {
...mapState('task', ['tip']),
status() {
return this.task ? this.task.process : 0;
},
taskName() {
return this.task ? this.task.name : '';
},
taskId() {
return this.task ? this.task.id : '';
},
//
// 0 1 2 3
orderStyle() {
let color = '#9CA3AF';
let icon = 'play-right-fill';
let persent = 100;
switch (this.status) {
case 1: //
color = '#60A5FA';
icon = '';
if (+this.computeCyclePersent() > 100) {
persent = 96;
} else {
persent = this.computeCyclePersent();
}
break;
case 2: //
color = '#F87171';
icon = 'pause';
persent = 50; // TODO:
break;
case 3: //
color = '#34D399';
icon = 'checkmark';
persent = 100;
break;
case 4: //
color = '#60A5FA';
icon = 'plus';
persent = 100;
break;
default:
//
color = '#9CA3AF';
icon = 'play-right';
persent = 100;
break;
}
return { color, icon, persent };
},
},
methods: {
...mapMutations('task', ['setTip']),
/**
* 点击了图标 修改任务状态
* @param {object} event
*/
changeStatus(event, process) {
if (process === 4) {
this.addTask();
return;
}
// return false;
const { status, taskId, taskName, tip } = this;
tip.status = status;
tip.taskId = taskId;
tip.left = event.target.x;
tip.top = event.target.y;
tip.show = true;
tip.text = this.genetateTips(status, taskName);
this.setTip(tip);
},
//
addTask() {
this.$t.ui.showToast('新建任务');
},
//
computeCyclePersent() {
if (!this.task || !this.task.realStart || !this.task.planDuration) return 100;
const { realStart, planDuration } = this.task;
return (((Date.now() - +realStart) * 100) / +planDuration).toFixed(2);
},
/**
* 计算tip的标题内容
*/
genetateTips(status, content) {
switch (status) {
case 0:
return `确认开始任务"${content}"吗?`;
case 1:
return `请选择要执行的操作`;
case 2:
return `请选择要执行的操作`;
case 3:
return `是否要重新开始此任务`;
}
},
//
// = realStart() + planDuration()
// = -
// = realStart + planDuration - Date.now()
computeDurationText() {
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
}
const { realStart, planDuration } = this.task;
const leftTime = +realStart + +planDuration - Date.now(); //
const { num, time } = this.$t.time.computeDurationText(leftTime);
this.$nextTick(() => {
if (!time) return;
this.timer = setTimeout(() => {
this.computeDurationText();
}, time);
});
return num;
},
},
};
</script>
<style scoped lang="scss">
.icon-column {
height: 33px;
width: 33px;
}
.one {
height: 33px;
width: 33px;
}
.progress-box {
background: rgba(255, 255, 255, 0);
width: 33px;
height: 33px;
border: 2px solid #9ca3af;
}
.progress-box-4 {
width: 25px;
height: 25px;
border: 2px solid #60a5fa;
}
</style>

7
src/components/TimeLine/component/Title.vue

@ -1,7 +0,0 @@
<!--
* @Author: aBin
* @email: binbin0314@126.com
* @Date: 2021-07-19 15:40:02
* @LastEditors: aBin
* @LastEditTime: 2021-07-19 15:40:03
-->

94
src/components/Tips/Tips.vue

@ -1,94 +0,0 @@
<template>
<view
class="fixed shadow-2xl"
style="z-index: 1000"
:style="{
left: tip.left + 'px',
top: height - tip.top > 110 ? tip.top + 'px' : '',
bottom: height - tip.top > 110 ? '' : '10px',
}"
id="u-icard"
>
<u-card
:title="title"
style="width: 500rpx; margin: 0 !important"
v-if="tip.show"
titleSize="28"
:headStyle="headStyle"
:footStyle="footStyle"
>
<view class="" slot="body"> {{ tip.text }} </view>
<view class="flex justify-end" slot="foot">
<u-button size="mini" @tap="onCancel">取消</u-button>
<u-button v-if="tip.status === 1" size="mini" @tap="onChangeStatus(1)">暂停</u-button>
<u-button v-if="tip.status === 2" size="mini" @tap="onChangeStatus(2)">继续</u-button>
<u-button v-if="tip.status === 1 || tip.status === 2" size="mini" @tap="onChangeStatus(0)">重新开始</u-button>
<u-button v-if="tip.status === 1 || tip.status === 2" type="primary" size="mini" @tap="onChangeStatus(3)">结束</u-button>
<u-button v-if="tip.status === 0 || tip.status === 3" type="primary" size="mini" @tap="onChangeStatus(0)">确定</u-button>
</view>
</u-card>
</view>
</template>
<script>
import { mapState, mapMutations } from 'vuex';
export default {
name: 'Tips',
props: { title: { default: '提示', type: String } },
computed: mapState('task', ['tip']),
data() {
return {
footStyle: { padding: '4px 15px' },
headStyle: { paddingTop: '8px', paddingBottom: '8px' },
height: 0,
};
},
mounted() {
this.height = window.screen.height;
},
methods: {
...mapMutations('task', ['setTipShow']),
//
onConfirm() {
this.onCancel();
},
/**
* 执行修改任务状态的动作
* @param {number} type 状态码 0开始 1暂停 2继续 3完成 默认0
*/
async onChangeStatus(type) {
try {
const param = { id: this.tip.taskId, type };
// TODO:
await uni.$u.api.updateTaskType(param);
if (type === 0) {
this.$t.ui.showToast('项目已重新开始');
} else if (type === 1) {
this.$t.ui.showToast('项目已暂停');
} else if (type === 2) {
this.$t.ui.showToast('项目继续');
} else if (type === 3) {
this.$t.ui.showToast('项目结束');
}
this.tip.show = false;
// location.reload();
// this.$router.go(0);
} catch (error) {
console.error(error);
this.$t.ui.showToast(error.msg || '操作失败');
}
},
//
onCancel() {
this.setTipShow(false);
},
},
};
</script>

65
src/components/Title/Title.vue

@ -1,65 +0,0 @@
<template>
<view>
<u-navbar :custom-back="onBack" class="overflow-hidden">
<view class="flex justify-start flex-1 px-3 font-bold min-0">
<view class="truncate">{{ project.name }}</view>
</view>
<view class="mr-2" slot="right">
<u-icon class="m-1" name="xuanzhong2" custom-prefix="custom-icon" size="20px" @click="lwbs"></u-icon>
<u-icon class="m-1" name="shuaxin1" custom-prefix="custom-icon" size="20px" @click="projectOverview"></u-icon>
<u-icon class="m-1" name="home" custom-prefix="custom-icon" size="20px" @click="openIndex"></u-icon>
<u-icon class="m-1" name="xuanxiang" custom-prefix="custom-icon" size="20px" @click="operation"></u-icon>
</view>
</u-navbar>
</view>
</template>
<script>
import { mapGetters, mapState } from 'vuex';
export default {
name: 'ProjectTitle',
data() {
return { showBack: false };
},
computed: {
...mapState('project', ['project']),
...mapGetters('user', ['userId']),
},
methods: {
//
onBack() {
// eslint-disable-next-line no-undef
const pages = getCurrentPages(); //
if (pages.length > 1) {
uni.navigateBack();
} else {
this.$u.route('/', { u: this.userId });
}
},
// LWBS
lwbs() {
// this.$t.ui.showToast('LWBS');
},
//
projectOverview() {
// this.$t.ui.showToast('');
},
//
openIndex() {
this.$u.route('/', { u: this.userId });
},
//
operation() {
// this.$t.ui.showToast('');
},
},
};
</script>
<style lang="scss" scoped>
/deep/ .u-slot-content {
min-width: 0;
}
</style>

10
src/components/Upload/Upload.vue

@ -1,6 +1,6 @@
<template>
<view class="upload">
<u-icon name="plus" size="24px" class="flex justify-center w-12 h-12 bg-blue-100 rounded-full shadow-md" @tap="handleUpload"></u-icon>
<u-icon name="plus" size="24px" class="flex justify-center w-12 h-12 bg-blue-100 rounded-full shadow-md" @click="handleUpload"></u-icon>
</view>
</template>
@ -17,8 +17,9 @@ export default {
// WBS
//
this.$emit('success');
data.url && (uni.$t.domain = data.url);
setTimeout(() => {
this.$u.route('/pages/project/project', {
this.$u.route('/pages/project-webview/project-webview', {
u: this.userId,
p: data.id,
pname: data.pname,
@ -39,9 +40,6 @@ export default {
right: 10px;
bottom: 0;
transform: translate3d(0, 50%, 0);
}
/deep/ .uicon-plus {
color: theme('colors.blue.500') !important;
color: $uni-color-primary !important;
}
</style>

6
src/config/app.js

@ -1,8 +1,6 @@
const version = '3.0.0';
export default {
V: version,
version,
V: process.env.VUE_APP_VERSION,
version: process.env.VUE_APP_VERSION,
theme: [],
tokenKey: 'anyringToken', // storage token key
};

3
src/config/db.js

@ -1,3 +0,0 @@
export const db = null; // indexedDB 对象
export const name = 'TALL_indexedDB'; // indexDB name
export const version = 1; // indexDB version

97
src/config/plugin.js

@ -1,97 +0,0 @@
// 定义插件相关信息
/* eslint-disable */
export default {
defaults: [
{
id: 1,
name: 'TASK_NAME',
description: '任务名插件',
component: 'p-task-title',
},
{
id: 2,
name: 'TASK_DESCRIPTION',
description: '任务描述插件',
component: 'p-task-description',
},
{
id: 3,
name: 'TASK_DURATION_DELAY',
description: '任务时长延迟插件(+-1min)时间格式可设置',
component: 'p-task-duration-delay',
},
{
id: 4,
name: 'TASK_START_TIME_DELAY',
description: '任务开始时间延迟插件(+-1hour)',
component: 'p-task-start-time-delay',
},
{
id: 5,
name: 'DELIVERABLE',
description: '交付物插件(人 + 交付物)可配置【仅人】 or 【仅交付物】 or 【人+交付物】',
component: 'p-deliverable',
},
{
id: 6,
name: 'SUBTASKS',
description: '子任务插件:显示子任务',
component: 'p-subtasks',
},
{
id: 7,
name: 'SUB_PROJECT',
description: '子项目插件:显示子项目',
component: 'p-sub-project',
},
{
id: 8,
name: 'TASK_COUNTDOWN',
description: '任务倒计时插件',
component: 'p-task-countdown',
},
{
id: 9,
name: 'MANAGE_PROJECT',
description: '项目信息管理插件',
component: 'p-manage-project',
},
{
id: 10,
name: 'MANAGE_ROLE',
description: '角色信息管理插件',
component: 'p-manage-role',
},
{
id: 11,
name: 'MANAGE_MEMBER',
description: '成员信息管理插件',
component: 'p-manage-member',
},
{
id: 12,
name: 'MANAGE_TASK',
description: '任务信息管理插件',
component: 'p-manage-task',
},
{
id: 13,
name: 'WBS_IMPORT',
description: '导入WBS新建项目',
component: 'p-wbs-import',
},
{
id: 14,
name: 'WBS_IMPORT_UPDATE',
description: '导入WBS更新项目',
component: 'p-wbs-update',
},
{
id: 15,
name: 'DELIVER_CHECK',
description: '交付物检查',
component: 'p-deliver-check',
},
], // 默认插件id列表
};

17
src/config/time.js

@ -1,17 +0,0 @@
export default {
timeUnits: [
// 时间颗粒度
{ id: 0, value: '毫秒', format: 'x', cycle: 'YY-M-D HH:mm:ss', granularity: 'millisecond' },
{ id: 1, value: '秒', format: 'x', cycle: 'YY-M-D HH:mm:ss', granularity: 'second' },
{ id: 2, value: '分', format: 'ss', cycle: 'YY-M-D HH:mm', granularity: 'minute' },
{ id: 3, value: '时', format: 'mm', cycle: 'YY-M-D HH时', granularity: 'hour' },
{ id: 4, value: '天', format: 'D日 HH:mm', cycle: 'YY-M-D', granularity: 'day' },
{ id: 5, value: '周', format: 'D日 HH:mm', cycle: '', granularity: 'week' },
{ id: 6, value: '月', format: 'D日 H:m', cycle: 'YYYY年', granularity: 'month' },
{ id: 7, value: '季度', format: '', cycle: 'YYYY年', granularity: 'quarter' },
{ id: 8, value: '年', format: 'YYYY', cycle: '', granularity: 'year' },
{ id: 9, value: '年代', format: '', cycle: '', granularity: '' },
{ id: 10, value: '世纪', format: '', cycle: '', granularity: '' },
{ id: 11, value: '千年', format: '', cycle: '', granularity: '' },
],
};

43
src/config/user.js

@ -0,0 +1,43 @@
// 用户登录client
export const clients = { mp: 0, h5: 1, android: 2, ios: 3 };
// 用户登录类型
export const types = {
mp: 0,
phone: 1,
email: 2,
username: 3,
wx: 4,
wx_web: 5,
wb: 6,
};
// 小程序获取参数
export const mp = () => {
return new Promise((resolve, reject) => {
uni.login({
provider: 'weixin',
success(res) {
if (res.code) {
const params = {
client: uni.$t.user.clients['mp'],
type: uni.$t.user.types['mp'],
data: { identifier: res.code },
};
resolve(params);
} else {
reject(res.errMsg);
}
},
fail() {
console.log('fail');
reject('微信登录失败');
},
});
});
};
export default {
clients,
types,
};

36
src/main.js

@ -1,19 +1,21 @@
import App from './App';
import Tall from '@/utils/tall';
import Vue from 'vue';
import dayjs from 'dayjs';
import uView from 'uview-ui';
import Tall from '@/utils/tall';
import App from './App';
import './common/styles/index.css';
import request from '@/utils/request.js';
import store from './store';
import tall from '@/apis/tall.js';
import uView from 'uview-ui';
import wbs from '@/apis/wbs.js';
//#ifdef H5
// import './registerServiceWorker';
import AlloyFinger from 'alloyfinger';
import AlloyFingerPlugin from 'alloyfinger/vue/alloy_finger_vue';
Vue.use(AlloyFingerPlugin, { AlloyFinger });
// import AlloyFinger from 'alloyfinger';
// import AlloyFingerPlugin from 'alloyfinger/vue/alloy_finger_vue';
// Vue.use(AlloyFingerPlugin, { AlloyFinger });
// indexedDB
import indexedDB from '@/utils/indexedDB';
Vue.use(indexedDB);
// import indexedDB from '@/utils/indexedDB';
// Vue.use(indexedDB);
//#endif
Vue.config.productionTip = false;
@ -21,28 +23,16 @@ Vue.prototype.$moment = dayjs;
Vue.use(uView);
Vue.use(Tall);
uni.$moment = dayjs;
dayjs.locale('zh-cn');
App.mpType = 'app';
const app = new Vue({ ...App, store });
import request from '@/utils/request.js';
import tall from '@/apis/tall.js';
import project from '@/apis/project.js';
import task from '@/apis/task.js';
import plugin from '@/apis/plugin.js';
import role from '@/apis/role.js';
import wbs from '@/apis/wbs.js';
window.vm = app;
Vue.use(request, app);
Vue.use(tall, app);
Vue.use(project, app);
Vue.use(task, app);
Vue.use(plugin, app);
Vue.use(role, app);
Vue.use(wbs, app);
app.$mount();

21
src/manifest.json

@ -1,6 +1,6 @@
{
"name": "",
"appid": "",
"name": "TALL",
"appid": "wx356e01c7eb01d55d",
"description": "",
"versionName": "1.0.0",
"versionCode": "100",
@ -57,27 +57,16 @@
/* */
},
"mp-weixin": {
/* */ "appid": "",
"appid": "wx356e01c7eb01d55d",
"setting": {
"urlCheck": false
},
"usingComponents": true
},
"mp-alipay": {
"usingComponents": true
},
"mp-baidu": {
"usingComponents": true
},
"mp-toutiao": {
"usingComponents": true
},
"mp-qq": {
"usingComponents": true
},
"h5": {
"router": {
"base": "/tall/v3.0.1"
"base": "/tall/v3.1.0"
},
"title": "时物链条",
"sdkConfigs": {

44
src/mixins/timeline.js

@ -1,44 +0,0 @@
import { mapGetters } from 'vuex';
const mixin = {
computed: mapGetters('task', ['timeGranularity']),
methods: {
/**
* 设置时间轴空数据
* @param {*} startTime
* @param {*} show true 向上加载,false 向下加载
*/
setTime(startTime, show) {
let { timeGranularity } = this;
let arr = [];
let str = {};
if (show) {
for (let i = 10; i > 0; i--) {
str = {
id: this.$u.guid(20, false, 10),
panel: {},
plugins: [],
process: 4,
planStart: this.$t.time.add(startTime, `-${i}` - 0, timeGranularity).valueOf(),
};
arr.push(str);
}
} else {
for (let i = 0; i < 10; i++) {
str = {
id: this.$u.guid(20, false, 10),
panel: {},
plugins: [],
process: 4,
planStart: this.$t.time.add(startTime, i + 1, timeGranularity).valueOf(),
};
arr.push(str);
}
}
return arr;
},
},
};
export default mixin;

62
src/pages.json

@ -1,31 +1,35 @@
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationStyle": "custom" ,
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/project/project",
"style": {
"navigationStyle": "custom" ,
"navigationBarTextStyle": "white"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "TALL",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"easycom": {
"autoscan": true,
"custom": {
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue",
"^p-(.*)": "@/plugins/p-$1/p-$1.vue"
}
}
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarText": "TALL"
}
},
{
"path": "pages/phone-bind/phone-bind",
"style": {
"navigationBarTitleText": "绑定手机号"
}
},
{
"path": "pages/project-webview/project-webview",
"style": {
"navigationBarTitleText": "项目详情页"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "TALL",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"easycom": {
"autoscan": true,
"custom": {
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue",
"^p-(.*)": "@/plugins/p-$1/p-$1.vue"
}
}
}

25
src/pages/index/index.vue

@ -1,6 +1,6 @@
<template>
<view class="flex flex-col h-full bg-gray-50" @touchmove="onMove">
<view class="relative">
<view class="flex flex-col h-full bg-gray-50">
<view class="relative" @touchmove="onMove">
<!-- 日历 -->
<Calendar @selected-change="onDateChange" :show-back="true" ref="calendar" @handleFindPoint="handleFindPoint" />
<!-- 上传 导入wbs -->
@ -8,7 +8,7 @@
</view>
<!-- 项目列表 -->
<Projects class="flex-1 overflow-y-auto" />
<Projects @getProjects="getProjects" class="flex-1 overflow-y-auto" />
<!-- 全局提示框 -->
<u-top-tips ref="uTips"></u-top-tips>
@ -52,13 +52,18 @@ export default {
...mapMutations('project', ['setProjects', 'setDotList']),
//
async getProjects(start = this.$moment().startOf('day').valueOf(), end = this.$moment().endOf('day').valueOf()) {
try {
const data = await this.$u.api.getProjects(start, end);
this.setProjects(data);
} catch (error) {
console.error('error: ', error);
}
getProjects(start = this.$moment().startOf('day').valueOf(), end = this.$moment().endOf('day').valueOf()) {
// const data = await this.$u.api.getProjects(start, end);
this.$t.$q.getProjects(start, end, (err, data) => {
if (err) {
console.error('err: ', err);
} else {
data.forEach(item => {
item.show = false;
});
this.setProjects(data);
}
});
},
/**

189
src/pages/phone-bind/phone-bind.vue

@ -0,0 +1,189 @@
<template>
<view class="wrap">
<u-form :model="model" :rules="rules" ref="uForm" :errorType="errorType">
<!-- 手机号 -->
<u-form-item :rightIconStyle="{ color: '#888', fontSize: '32rpx' }" label="手机号码" prop="phone" label-width="160">
<u-input placeholder="请输入手机号" v-model="model.phone" type="number"></u-input>
</u-form-item>
<u-form-item label="图形验证码" prop="imageValue" label-width="160">
<u-input placeholder="输入计算结果" v-model="model.imageValue" type="number"></u-input>
<ImageCode slot="right" @on-code="codeId = $event" />
</u-form-item>
<u-form-item label="验证码" prop="code" label-width="160">
<u-input placeholder="请输入短信验证码" v-model="model.code" type="number"></u-input>
<u-button slot="right" type="primary" size="mini" @click="getCode">{{ codeTips }}</u-button>
</u-form-item>
</u-form>
<view class="mt-8">
<u-button @click="submit" type="primary">提交</u-button>
</view>
<u-verification-code :seconds="seconds" ref="uCode" @change="codeChange"></u-verification-code>
<u-top-tips ref="uTips"></u-top-tips>
</view>
</template>
<script>
export default {
data() {
return {
model: {
phone: '', //
imageValue: '', //
code: '', //
},
codeId: '', // id
rules: {
phone: [
{
required: true,
message: '请输入手机号',
trigger: ['change', 'blur'],
},
{
validator: (rule, value) => {
return this.$u.test.mobile(value);
},
message: '手机号码不正确',
trigger: ['change', 'blur'],
},
],
code: [
{
required: true,
message: '请输入验证码',
trigger: ['change', 'blur'],
},
{
validator: (rule, value) => {
return this.$u.test.code(value, 4);
},
message: '验证码格式不正确',
trigger: ['change', 'blur'],
},
],
},
seconds: 120, //
codeTips: '',
errorType: ['message'],
};
},
onReady() {
this.$refs.uForm.setRules(this.rules);
},
methods: {
submit() {
this.$refs.uForm.validate(async valid => {
if (valid) {
try {
const { phone, code } = this.model;
const data = await this.$u.api.phoneBind(phone, code);
console.log('data: ', data);
this.$refs.uTips.show({
title: '手机号绑定成功, 即将跳转上一页',
type: 'success',
duration: '3000',
});
setTimeout(() => uni.navigateBack(), 2000);
} catch (error) {
this.$refs.uTips.show({
title: error.msg || '手机号绑定失败',
type: 'error',
duration: '3000',
});
}
} else {
console.log('验证失败');
}
});
},
codeChange(text) {
this.codeTips = text;
},
//
async getCode() {
if (this.$refs.uCode.canGetCode) {
try {
if (!this.validateCodeParams()) return;
const params = {
phone: this.model.phone,
verificationCodeId: this.codeId,
verificationCodeValue: this.model.imageValue,
};
const data = await this.$u.api.getSmsCode(params);
this.seconds = data.expiredInSeconds;
this.$refs.uTips.show({
title: '短信发送成功, 请查收',
type: 'success',
duration: '3000',
});
//
this.$refs.uCode.start();
} catch (error) {
this.$refs.uTips.show({
title: error.msg || '发送失败',
type: 'error',
duration: '3000',
});
}
} else {
this.$u.toast('倒计时结束后再发送');
}
},
//
validateCodeParams() {
if (!this.$u.test.mobile(this.model.phone)) {
this.$refs.uTips.show({
title: '手机号输入不正确',
type: 'error',
duration: '3000',
});
return false;
}
if (!this.codeId) {
this.$refs.uTips.show({
title: '点击刷新图形验证码重试',
type: 'error',
duration: '3000',
});
return false;
}
if (!this.model.imageValue && this.model.imageValue !== 0) {
this.$refs.uTips.show({
title: '请输入图形验证码',
type: 'error',
duration: '3000',
});
return false;
}
return true;
},
},
};
</script>
<style scoped lang="scss">
.wrap {
padding: 30rpx;
}
.agreement {
display: flex;
align-items: center;
margin: 40rpx 0;
.agreement-text {
padding-left: 8rpx;
color: $u-tips-color;
}
}
</style>

35
src/pages/project-webview/project-webview.vue

@ -0,0 +1,35 @@
<template>
<web-view :src="src" />
</template>
<script>
export default {
data() {
return { src: '' };
},
onLoad(options) {
console.log('options: ', options);
if (!options) {
this.$t.ui.showModal('缺少参数, 请返回重试');
} else {
const { p, u, pname, url } = options;
if (pname) {
uni.setNavigationBarTitle({ title: pname });
}
if (!u) {
this.$t.ui.showToast('缺少用户信息, 请登录');
return;
}
if (!p || !url) {
this.$t.ui.showToast('缺少项目信息, 请重新打开');
return;
}
const baseUrl = process.env.VUE_APP_PROJECT_PATH;
this.src = `${baseUrl}/${this.$t.app.version}/#/?u=${u}&p=${p}&url=${url}&pname=${pname}`;
}
},
};
</script>

312
src/pages/project/project.vue

@ -1,312 +0,0 @@
<template>
<view :style="{ height: height }" class="flex flex-col overflow-hidden u-font-14">
<!-- 标题栏 -->
<Title />
<view class="container flex flex-col flex-1 overflow-hidden bg-gray-100" style="margin: auto">
<!-- 角色栏 -->
<Roles />
<!-- 日常任务面板 -->
<Globals />
<!-- 定期任务面板 -->
<TimeLine @getTasks="getTasks" class="flex-1 overflow-hidden" ref="child" />
</view>
</view>
</template>
<script>
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex';
import mixin from '@/mixins/timeline';
export default {
mixins: [mixin],
data() {
return { height: '' };
},
computed: {
...mapState('user', ['user', 'token']),
...mapState('role', ['visibleRoles', 'roleId']),
...mapState('task', ['timeNode', 'timeUnit', 'tasks']),
...mapGetters('task', ['timeGranularity']),
},
onLoad(options) {
this.init(options);
},
watch: {
/**
* 当时间基准点发生变化时
* 重新根据时间和角色查询普通日常任务
* 永久日常任务不发生改变
*/
async timeNode(val) {
if (val && this.roleId) {
//
await this.initTasks();
}
},
/**
* 当角色发生变化时
* 重新查询永久日常任务和普通日常任务
* 注意: 切换角色后 重新设置了时间基准点 时间基准点一定会变
* 所以监听时间基准点获取 可变日常任务即可 这里不用获取 避免重复获取
*/
roleId(val) {
if (val) {
this.setTimeNode(Date.now());
//
this.getPermanent(val);
}
},
},
mounted() {
this.height = window.screen.height + 'px';
},
onUnload() {
this.clearEndFlag();
this.clearTasks();
},
methods: {
...mapActions('user', ['getToken']),
...mapActions('project', ['getProjectById']),
...mapActions('role', ['getRoles']),
...mapActions('task', ['getRegulars', 'getPermanent', 'getGlobal']),
...mapMutations('user', ['setToken']),
...mapMutations('project', ['setProject', 'setProjectName']),
...mapMutations('role', ['setInvisibleRoles', 'setVisibleRoles', 'setRoleId']),
...mapMutations('task', [
'setPermanents',
'setUpTasks',
'setDownTasks',
'setDailyTasks',
'setTimeNode',
'clearTasks',
'clearEndFlag',
'setShowSkeleton',
'setTopEnd',
'setBottomEnd',
]),
/**
* 初始化
* @param {object | null} options
*/
async init(options) {
try {
if (!this.token) {
// tokenuserIdtoken
// token userId
if (!options || !options.u) {
// u (userId)
this.$t.ui.showToast('缺少用户信息参数');
} else {
await this.getToken(options.u);
}
}
//
options && options.pname && this.setProjectName(options.pname);
if (!options || !options.p) {
// id
this.$t.ui.showToast('缺少项目信息参数');
} else {
// id
await this.getProjectById({ projectId: options.p });
// id
await this.getRoles({ projectId: options.p });
this.setInitialRoleId(this.visibleRoles);
}
} catch (error) {
console.error('project init function:', error);
}
},
//
async initTasks() {
//
this.setPermanents([]);
this.setDailyTasks([]);
//
this.clearTasks();
//
//
this.clearEndFlag();
//
this.getGlobalData();
//
this.setPrevTasks();
// storage
const storageTaskId = this.$t.storage.getStorageSync('taskId');
this.$nextTick(() => {
if (!storageTaskId) {
this.$refs.child.setScrollPosition();
}
});
//
this.setNextTasks();
await this.getInitTasks();
// storage
this.$nextTick(() => {
if (storageTaskId) {
this.$refs.child.setScrollPosition();
}
});
},
// ||
async getInitTasks() {
//
await this.getTasks({ queryType: 0 });
await this.getTasks({ queryType: 1 });
//
const detailId = this.tasks.findIndex(task => task.detailId);
if (detailId !== -1) {
this.$nextTick(async () => {
const { tasks, timeGranularity } = this;
await this.getTasks({ timeNode: +tasks[0].planStart, queryType: 0, queryNum: 6 }); //
//
const nextQueryTime = +this.$t.time.add(+tasks[tasks.length - 1].planStart, 1, timeGranularity);
await this.getTasks({ timeNode: nextQueryTime, queryType: 1, queryNum: 6 }); //
});
} else {
//
//
this.setPrevTasks();
//
this.setNextTasks();
}
},
//
setInitialRoleId(visibleList) {
const index = visibleList.findIndex(item => +item.mine === 1);
const currentRole = index > 0 ? visibleList[index] : visibleList[0];
const storageRoleId = this.$t.storage.getStorageSync('roleId');
const currentRoleId = storageRoleId ? storageRoleId : currentRole ? currentRole.id : '';
this.setRoleId(currentRoleId);
// storage
this.$t.storage.setStorageSync('roleId', '');
},
/**
* 根据时间基准点和角色查找定期任务
* @param {object} query
* @param {string} query.roleId 角色id
* @param {string} query.timeNode 时间基准点 默认当前
* @param {string} query.timeUnit 时间颗粒度 默认天
* @param {string} query.queryNum 查找颗粒度数量 默认3个
* @param {string} query.queryType 0向上查找 1向下查找(默认) 下查包含自己上查不包含
*/
async getTasks(query) {
try {
this.setShowSkeleton(true);
const { roleId, timeNode, timeUnit } = this;
const params = {
roleId,
timeNode: query.timeNode || timeNode,
timeUnit: query.timeUnit || timeUnit,
queryNum: query.queryNum || 3,
queryType: query.queryType,
};
const res = await this.getRegulars(params);
this.setShowSkeleton(false);
// 0 -> 1 ->
if (res && res.length) {
this.replacePrevData(res, params.queryType);
} else {
params.queryType === 0 ? this.setPrevTasks() : this.setNextTasks();
}
} catch (error) {
this.setShowSkeleton(false);
console.error('error: ', error);
}
},
//
getGlobalData() {
const { roleId, timeNode, timeUnit } = this;
const param = { roleId, timeNode, timeUnit };
this.getGlobal(param);
},
//
setPrevTasks() {
this.setTopEnd(true);
let sTime = '';
if (!this.tasks || !this.tasks.length) {
sTime = +new Date().getTime();
} else {
sTime = +this.tasks[0].planStart - 0;
}
const initData = this.setTime(sTime, true);
this.setUpTasks(initData);
},
//
setNextTasks() {
this.setBottomEnd(true);
let sTime = '';
if (!this.tasks || !this.tasks.length) {
sTime = +new Date().getTime();
} else {
sTime = +this.tasks[this.tasks.length - 1].planStart - 0;
}
const initData = this.setTime(sTime, false);
this.setDownTasks(initData);
},
//
replacePrevData(data, type) {
let newTasks = [...this.tasks];
for (let i = 0; i < newTasks.length; i++) {
const task = newTasks[i];
let arr = [];
for (let j = 0; j < data.length; j++) {
const item = data[j];
//
if (+newTasks[0].planStart > +data[0].planStart) {
this.setPrevTasks();
newTasks = [...this.tasks];
i--;
break;
} else if (+data[data.length - 1].planStart > +newTasks[newTasks.length - 1].planStart) {
this.setNextTasks();
newTasks = [...this.tasks];
i--;
break;
} else {
//
const taskItem = this.$t.time.isSame(+task.planStart, +item.planStart, this.timeGranularity);
if (taskItem) {
arr.push(item);
if (task.detailId) {
newTasks.splice(i, 0, item);
} else {
if (arr.length === 1) {
newTasks.splice(i, 1, item);
}
if (arr.length > 1) {
newTasks.splice(i, 0, item);
}
}
i++;
}
}
}
}
this.clearTasks();
type === 0 ? this.setUpTasks(newTasks) : this.setDownTasks(newTasks);
},
},
};
</script>

15
src/pages/test/test.vue

@ -1,15 +0,0 @@
<template>
<view class="container p-3">
<u-button type="primary" @click="add">add</u-button>
</view>
</template>
<script>
export default {
methods: {
add() {
this.$db.create('projects', { id: '123' });
},
},
};
</script>

7
src/plugins/p-deliver-check/p-deliver-check.vue

@ -1,7 +0,0 @@
<template>
<view>交付物检查</view>
</template>
<script>
export default {};
</script>

20
src/plugins/p-deliverable/p-deliverable.vue

@ -1,20 +0,0 @@
<template>
<!-- 交付物 -->
<view>交付物</view>
</template>
<script>
export default {
name: 'p-deliverable',
props: { item: { type: Object, default: null } },
data() {
return {};
},
computed: {},
methods: {},
watch: {},
};
</script>
<style></style>

7
src/plugins/p-manage-member/p-manage-member.vue

@ -1,7 +0,0 @@
<template>
<view>成员管理</view>
</template>
<script>
export default {};
</script>

7
src/plugins/p-manage-project/p-manage-project.vue

@ -1,7 +0,0 @@
<template>
<view>项目管理</view>
</template>
<script>
export default {};
</script>

7
src/plugins/p-manage-role/p-manage-role.vue

@ -1,7 +0,0 @@
<template>
<view>角色管理</view>
</template>
<script>
export default {};
</script>

7
src/plugins/p-manage-task/p-manage-task.vue

@ -1,7 +0,0 @@
<template>
<view>任务管理</view>
</template>
<script>
export default {};
</script>

60
src/plugins/p-subproject/p-subproject.vue

@ -1,60 +0,0 @@
<template>
<!-- 子项目插件 -->
<view>
<view v-for="item in sonProject" :key="item.detailId">
<span class="text-xs text-blue-500" @click="openProject(item)">{{ item.name }}</span>
</view>
</view>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
name: 'p-subproject',
props: {
task: {
type: Object,
default: () => {},
},
},
data() {
return { sonProject: [] };
},
computed: mapGetters('project', ['projectId']),
mounted() {
this.getSonProject();
},
methods: {
async getSonProject() {
try {
const data = await this.$u.api.findSonProject({ projectId: this.task.detailId });
this.sonProject = data;
} catch (error) {
console.error('p-subproject.vue getSonProject error: ', error);
}
},
/**
* 打开项目
* @param {object} project 所点击的项目的信息
*/
openProject(project) {
const { name, id, url } = project;
url && (uni.$t.domain = url);
this.$u.route('pages/project/project', {
u: this.userId,
p: id,
pname: name,
url: encodeURIComponent(url),
});
},
},
watch: {},
};
</script>
<style></style>

39
src/plugins/p-subtasks/p-subtasks.vue

@ -1,39 +0,0 @@
<template>
<view>
<view v-for="item in sonTask" :key="item.detailId">
<span class="text-xs text-gray-500">{{ item.name }}</span>
</view>
</view>
</template>
<script>
export default {
name: 'p-subtasks',
props: {
task: {
type: Object,
default: () => {},
},
},
data() {
return { sonTask: [] };
},
created() {
this.getSonTask();
},
methods: {
async getSonTask() {
try {
const data = await this.$u.api.findSonTask({ detailId: this.task.detailId });
this.sonTask = data;
} catch (error) {
console.error('p-subtasks.vue getSonTask error: ', error);
}
},
},
};
</script>
<style></style>

20
src/plugins/p-task-countdown/p-task-countdown.vue

@ -1,20 +0,0 @@
<template>
<!-- 任务倒计时插件 -->
<view>任务倒计时插件</view>
</template>
<script>
export default {
name: 'p-task-countdown',
props: { item: { type: Object, default: null } },
data() {
return {};
},
computed: {},
methods: {},
watch: {},
};
</script>
<style></style>

16
src/plugins/p-task-description/p-task-description.vue

@ -1,16 +0,0 @@
<template>
<!-- 任务描述 -->
<view>{{ task.description }}</view>
</template>
<script>
export default {
name: 'p-task-description',
props: {
task: {
type: Object,
default: () => {},
},
},
};
</script>

34
src/plugins/p-task-duration-delay/p-task-duration-delay.vue

@ -1,34 +0,0 @@
<template>
<view v-if="realDuration && planDuration">
<!-- 任务时长延迟插件 -->
<!-- 超时 -->
<span class="font-bold text-green-500" v-if="+realDuration > +planDuration">
+{{ $t.time.formatDuration(+realDuration - +planDuration) }}
</span>
<!-- 延时 -->
<span class="font-bold text-red-500" v-if="+realDuration < +planDuration">
-{{ $t.time.formatDuration(+planDuration - +realDuration) }}
</span>
</view>
</template>
<script>
export default {
name: 'p-task-duration-delay',
props: {
task: {
type: Object,
default: () => {},
},
},
computed: {
realDuration() {
return this.task.realDuration;
},
planDuration() {
return this.task.planDuration;
},
},
};
</script>

22
src/plugins/p-task-start-time-delay/p-task-start-time-delay.vue

@ -1,22 +0,0 @@
<template>
<view v-if="realStart && planStart">
<!-- 任务开始时间延迟插件 -->
<!-- 超时 -->
<span>{{ $t.time.formatDuration(+realStart - +planStart) }}</span>
</view>
</template>
<script>
export default {
name: 'p-task-start-time-delay',
props: { task: { type: Object, default: () => {} } },
computed: {
realStart() {
return this.task.realStart;
},
planStart() {
return this.task.planStart;
},
},
};
</script>

16
src/plugins/p-task-title/p-task-title.vue

@ -1,16 +0,0 @@
<template>
<!-- 任务名插件 -->
<view>{{ task.name }}</view>
</template>
<script>
export default {
name: 'p-task-title',
props: {
task: {
type: Object,
default: () => {},
},
},
};
</script>

85
src/plugins/p-wbs-import/p-wbs-import.vue

@ -1,85 +0,0 @@
<template>
<view>
<view @tap="handleUpload" v-if="task.name === '导入WBS新建项目'">{{ task.name }}</view>
<view @tap="handleUpdate" v-if="task.name === '导入WBS更新项目'">{{ task.name }}</view>
<!-- 全局提示框 -->
<u-top-tips ref="uTips"></u-top-tips>
</view>
</template>
<script>
import { mapGetters, mapMutations } from 'vuex';
export default {
name: 'p-wbs-import',
props: {
task: {
type: Object,
default: () => {},
},
},
data() {
return {};
},
computed: {
...mapGetters('user', ['userId']),
...mapGetters('project', ['projectId']),
},
methods: {
...mapMutations('project', ['setShowAlert']),
// wbs
async handleUpload() {
try {
const data = await this.$u.api.import();
// WBS
//
this.onUploadSuccess();
setTimeout(() => {
this.$u.route('/pages/project/project', {
u: this.userId,
p: data.id,
pname: data.pname,
url: data.url,
});
}, 2000);
} catch (error) {
this.onUploadError(error);
}
},
//
// TODO:
async handleUpdate() {
try {
await this.$u.api.import({ projectId: this.projectId });
// WBS
//
this.onUploadSuccess();
} catch (error) {
this.onUploadError(error);
}
},
//
onUploadSuccess() {
this.$refs.uTips.show({
title: '导入成功,即将打开新项目',
type: 'success',
duration: '3000',
});
},
//
onUploadError(error) {
this.$refs.uTips.show({
title: error || '导入失败',
type: 'error',
duration: '6000',
});
},
},
};
</script>

BIN
src/static/local_play1.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 853 B

BIN
src/static/logo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

3
src/store/db/actions.js

@ -1,3 +0,0 @@
const actions = {};
export default actions;

3
src/store/db/getters.js

@ -1,3 +0,0 @@
const getters = {};
export default getters;

12
src/store/db/index.js

@ -1,12 +0,0 @@
import state from './state';
import getters from './getters';
import mutations from './mutations';
import actions from './actions';
export default {
namespaced: true,
state,
getters,
mutations,
actions,
};

3
src/store/db/mutations.js

@ -1,3 +0,0 @@
const mutations = {};
export default mutations;

7
src/store/db/state.js

@ -1,7 +0,0 @@
const state = {
db: null, // indexedDB对象
name: 'TALL_indexedDB',
version: 1,
};
export default state;

34
src/store/index.js

@ -1,12 +1,34 @@
import Vue from 'vue';
import Vuex from 'vuex';
import db from './db/index';
import user from './user/index';
import messages from './messages/index';
import socket from './socket/index';
import project from './project/index';
import role from './role/index';
import task from './task/index';
import socket from './socket/index';
import user from './user/index';
// 不属于具体模块的 应用级的 store内容
const state = {
networkConnected: true, // 网络是否连接
forceUseStorage: false, // 强制启用storage
};
const getters = {
// 是否启用本地存储
// 设置了强制启用本地存储 或者 没有网络连接的时候
useStorage({ networkConnected, forceUseStorage }) {
return forceUseStorage || !networkConnected;
},
};
const mutations = {
/**
* 设置网络是否连接的变量
* @param {*} state
* @param {boolean} networkConnected
*/
setNetworkConnected(state, networkConnected) {
state.networkConnected = networkConnected;
},
};
Vue.use(Vuex);
export default new Vuex.Store({ modules: { db, user, messages, socket, project, role, task } });
export default new Vuex.Store({ state, getters, mutations, modules: { user, messages, socket, project } });

1
src/store/messages/mutations.js

@ -1,4 +1,5 @@
import storage from '@/utils/storage';
const { setStorageSync, getStorageSync, removeStorageSync } = storage;
const mutations = {

17
src/store/project/actions.js

@ -1,18 +1,3 @@
const actions = {
/**
* 通过项目id获取项目信息
* @param {any} commit
* @param {object} params 提交的参数
*/
async getProjectById({ commit }, params) {
try {
const data = await uni.$u.api.findProjectById(params);
commit('setProject', data);
return data;
} catch (error) {
throw error || '获取项目信息失败';
}
},
};
const actions = {};
export default actions;

19
src/store/project/mutations.js

@ -12,6 +12,25 @@ const mutations = {
}
},
/**
* 设置子项目收缩展开
* @param { object } state
* @param { object } options options:{ index,show }
*/
setProjectItemShow(state, options) {
if (options.show) {
for (var i = 0; i < state.projects.length; i++) {
if (i === options.index) {
state.projects[i].show = true;
} else {
state.projects[i].show = false;
}
}
} else {
state.projects[options.index].show = false;
}
},
/**
* 设置当前项目信息
* @param { object } state

19
src/store/role/actions.js

@ -1,19 +0,0 @@
const actions = {
/**
* 通过项目id获取角色信息
* @param {any} commit
* @param {object} params 提交的参数
*/
async getRoles({ commit }, params) {
try {
const res = await uni.$u.api.findShowRole(params);
commit('setInvisibleRoles', res.invisibleList);
commit('setVisibleRoles', res.visibleList);
return res;
} catch (error) {
throw error || '获取角色信息失败';
}
},
};
export default actions;

3
src/store/role/getters.js

@ -1,3 +0,0 @@
const getters = {};
export default getters;

12
src/store/role/index.js

@ -1,12 +0,0 @@
import state from './state';
import getters from './getters';
import mutations from './mutations';
import actions from './actions';
export default {
namespaced: true,
state,
getters,
mutations,
actions,
};

30
src/store/role/mutations.js

@ -1,30 +0,0 @@
const mutations = {
/**
* 设置不展示的角色信息
* @param {Object} state
* @param {Array} data 服务端返回的模板数组
*/
setInvisibleRoles(state, data) {
state.invisibleRoles = data || [];
},
/**
* 设置展示的角色信息
* @param {Object} state
* @param {Array} data 服务端返回的模板数组
*/
setVisibleRoles(state, data) {
state.visibleRoles = data || [];
},
/**
* 设置当前角色信息
* @param {Object} state
* @param {string} roleId 当前正在展示的角色的id
*/
setRoleId(state, roleId) {
state.roleId = roleId;
},
};
export default mutations;

7
src/store/role/state.js

@ -1,7 +0,0 @@
const state = {
invisibleRoles: [], // 不展示的角色信息
visibleRoles: [], // 展示的角色信息
roleId: '', // 当前展示查看的角色id
};
export default state;

45
src/store/task/actions.js

@ -1,45 +0,0 @@
const actions = {
/**
* 根据角色查找永久的日常任务
* @param {*} commit
* @param {string} roleId 角色id
*/
async getPermanent({ commit }, roleId) {
try {
const data = await uni.$u.api.getPermanent({ roleId });
commit('setPermanents', data);
} catch (error) {
console.log('task actions getPermanent error: ', error);
}
},
/**
* 根据时间和角色查找日常任务
* @param {*} commit
* @param {object} param 请求参数 roleId, timeNode, timeUnit
*/
async getGlobal({ commit }, param) {
try {
const data = await uni.$u.api.getGlobal(param);
commit('setDailyTasks', data);
} catch (error) {
console.log('task actions getGlobal error: ', error);
}
},
/**
* 根据时间基准点和角色查找定期任务
* @param {object} param 查询参数
* @param {number} param.queryType 必填 0 -> 向上 1 -> 向下
*/
// eslint-disable-next-line
async getRegulars({ commit }, param) {
try {
return await uni.$u.api.getRegularTask(param);
} catch (error) {
throw error || '获取定期任务失败';
}
},
};
export default actions;

23
src/store/task/getters.js

@ -1,23 +0,0 @@
const getters = {
// 所有的日常任务 永久 + 可变 日常任务
globals({ dailyTasks, permanents }) {
return [...permanents, ...dailyTasks];
},
unitConfig({ timeUnit }) {
const target = uni.$t.timeConfig.timeUnits.find(item => item.id === timeUnit);
return target;
},
// 计算任务开始时间的格式
startTimeFormat(state, { unitConfig }) {
return unitConfig.format || 'D日 HH:mm';
},
// 计算颗粒度 对应的 dayjs add 的单位
timeGranularity(state, { unitConfig }) {
return unitConfig.granularity;
},
};
export default getters;

12
src/store/task/index.js

@ -1,12 +0,0 @@
import state from './state';
import getters from './getters';
import mutations from './mutations';
import actions from './actions';
export default {
namespaced: true,
state,
getters,
mutations,
actions,
};

168
src/store/task/mutations.js

@ -1,168 +0,0 @@
const mutations = {
/**
* 记录时间轴向上滚动的距离
* @param { object } state
* @param { number } num
*/
setScrollTop(state, num) {
state.scrollTop = num;
},
/**
* 记录时间轴向上滚动的距离
* @param { object } state
* @param { string } data
*/
setViewId(state, data) {
state.viewId = data;
},
/**
* 设置日常任务当前是否应该处于收缩状态
* @param { object } state
* @param { boolean } data
*/
setShrink(state, data) {
state.isShrink = data;
},
/**
* 设置tip的值
* @param {object} state
* @param {object} data
*/
setTip(state, data) {
if (!data) return;
state.tip = { ...data };
},
/**
* 是否显示tips
* @param { object } state
* @param { boolean } show
*/
setTipShow(state, show) {
state.tip.show = show;
},
/**
* 是否显示tips
* @param { object } state
* @param { number } status
*/
setStatus(state, status) {
state.tip.status = status;
},
/**
* 设置时间基准点
* @param { object } state
* @param { number } data
*/
setTimeNode(state, data) {
state.timeNode = data;
},
/**
* 设置时间颗粒度
* @param { object } state
* @param { number } data
*/
setTimeUnit(state, data) {
state.timeUnit = data;
},
/**
* 设置向上查到的定期任务数据
* @param {Object} state
* @param {Array} data 服务端返回的模板数组
*/
setUpTasks(state, data) {
if (!state.tasks.length) {
state.tasks = [...data];
} else {
state.tasks = [...data.concat(state.tasks)];
}
},
/**
* 设置向下查到的定期任务数据
* @param {Object} state
* @param {Array} data 服务端返回的模板数组
*/
setDownTasks(state, data) {
if (!state.tasks && !state.tasks.length) {
state.tasks = [...data];
} else {
state.tasks = [...state.tasks.concat(data)];
}
},
/**
* 设置日常任务数据
* @param {Object} state
* @param {Array} data 服务端返回的模板数组
*/
setDailyTasks(state, data) {
state.dailyTasks = data || [];
},
/**
* 设置永久固定任务
* @param {object} state
* @param {array} tasks 服务端查询到的永久日常任务书籍
*/
setPermanents(state, tasks) {
state.permanents = tasks || [];
},
/**
* 设置时间轴是否继续向上查任务
* @param {Object} state
* @param {Boolean} show
*/
setTopEnd(state, show) {
state.topEnd = show;
},
/**
* 设置时间轴是否继续向下查任务
* @param {Object} state
* @param {Boolean} show
*/
setBottomEnd(state, show) {
state.bottomEnd = show;
},
// 清空标志位 如切换角色等使用
clearEndFlag(state) {
state.topEnd = false;
state.bottomEnd = false;
},
// 清空定期任务
clearTasks(state) {
state.tasks = [];
},
/**
* 收到消息设置任务状态
* @param {Object} state
* @param {Array} data 服务端返回的模板数组
*/
setTaskStatus(state, data) {
const item = state.tasks.find(i => i.id === data.id);
item.process = data.taskStatus;
},
/**
* 设置骨架屏是否显示
* @param {Object} state
* @param {Boolean} show
*/
setShowSkeleton(state, show) {
state.showSkeleton = show;
},
};
export default mutations;

31
src/store/task/state.js

@ -1,31 +0,0 @@
const state = {
scrollTop: 0,
viewId: '', // 时间轴自动滚动的位置
isShrink: false, // true: 收起, false:展开
tip: {
taskId: '', // 当前正在修改状态的任务的id
show: false,
status: 0, // 所点击任务的当前状态码
text: '',
left: 0, // 鼠标点击位置距离左边的距离
top: 0, // 鼠标点击位置距离上边的距离
},
// client: {
// left: 0, // 鼠标点击位置距离左边的距离
// top: 0, // 鼠标点击位置距离上边的距离
// },
// showTips: false,
// status: 0, // 点击了时间轴上的哪种样式,默认点击了开始
// tipsContent: '', // 提示框内的内容,需要传入
timeNode: new Date().getTime(), // 时间基准点
timeUnit: 4, // 时间颗粒度
topEnd: false, // 时间轴向上查任务到顶了
bottomEnd: false, // 时间轴向下查任务到底了
permanents: [], // 永久日常任务
dailyTasks: [], // 日常任务
// 定期任务
tasks: [],
showSkeleton: false, // 定期任务骨架屏
};
export default state;

8
src/store/user/actions.js

@ -6,10 +6,10 @@ const actions = {
*/
async getToken({ commit }, userId) {
try {
const res = await uni.$u.api.getToken(userId);
commit('setToken', res.token);
commit('setUser', res);
return res;
const data = await uni.$u.api.getToken(userId);
commit('setToken', data.token);
commit('setUser', data);
return data;
} catch (error) {
uni.$t.ui.showToast(error.msg || '获取个人信息失败');
}

2
src/store/user/mutations.js

@ -17,7 +17,7 @@ const mutations = {
setUser(state, user) {
if (!user) return;
state.user = { ...user };
uni.setStorageSync('user', JSON.stringify(user));
uni.$t.storage.setStorageSync('user', JSON.stringify(user));
},
};

46
src/test/util/time.test.js

@ -1,46 +0,0 @@
import Time from '../../utils/time.js';
// 测试计算进行中剩余时长显示数值
describe('utils/time.js computeDurationText function', () => {
const { computeDurationText } = Time;
// const leftTime = +realStart + +planDuration - Date.now(); // 剩余时间
it ('leftTime is 60ms, num=60, time=16', () => {
expect(computeDurationText(60)).toEqual({ num: 60, time: 16 })
})
it ('leftTime is 300ms, num=300, time=16', () => {
expect(computeDurationText(300)).toEqual({ num: 300, time: 16 })
})
it ('leftTime is 10s20ms, num=10, time=1000', () => {
expect(computeDurationText(10*1000 + 20)).toEqual({ num: 10, time: 1000 })
})
it ('leftTime is 8分钟10s20ms, num=8, time=1000', () => {
expect(computeDurationText(8*60*1000 + 10*1000 + 20)).toEqual({ num: 8, time: 1000 })
})
it ('leftTime is 3小时8分钟10s20ms, num=3, time=1000', () => {
expect(computeDurationText(3*60*60*1000 + 8*60*1000 + 10*1000 + 20)).toEqual({ num: 3, time: 1000 })
})
it ('leftTime is 11天3小时8分钟10s20ms, num=11, time=60 * 60 * 1000', () => {
expect(computeDurationText(11*24*60*60*1000 + 3*60*60*1000 + 8*60*1000 + 10*1000 + 20)).toEqual({ num: 11, time: 60 * 60 * 1000 })
})
it ('leftTime is 2个月11天3小时8分钟10s20ms, num=2, time=60 * 60 * 1000', () => {
expect(computeDurationText(2*30*24*60*60*1000 + 11*24*60*60*1000 + 3*60*60*1000 + 8*60*1000 + 10*1000 + 20)).toEqual({ num: 2, time: 60 * 60 * 1000 })
})
it ('leftTime is 7年2个月11天3小时8分钟10s20ms, num=7, time=60 * 60 * 1000', () => {
expect(computeDurationText(7*12*30*24*60*60*1000 + 2*30*24*60*60*1000 + 11*24*60*60*1000 + 3*60*60*1000 + 8*60*1000 + 10*1000 + 20)).toEqual({ num: 7, time: 60 * 60 * 1000 })
})
it ('leftTime <=0, num=0, time=null', () => {
expect(computeDurationText(-10)).toEqual({ num: 0, time: null })
})
it ('leftTime 不是数字, num=0, time=null', () => {
expect(computeDurationText('abc')).toEqual({ num: 0, time: null })
})
})

8
src/uni.scss

@ -12,11 +12,9 @@
* 如果你的项目同样使用了scss预处理你也可以直接在你的 scss 代码中使用如下变量同时无需 import 这个文件
*/
@import 'uview-ui/theme.scss';
/* 颜色变量 */
/* 行为相关颜色 */
$uni-color-primary: #007aff;
@import './common/styles/tailwind.scss';
/* 颜色变量 */ /* 行为相关颜色 */
$uni-color-primary: #0284c7;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;

62
src/utils/cache.js

@ -0,0 +1,62 @@
export const filter = {
/**
* 过滤获取到的数据 根据开始截止时间
* @param {object} data 缓存拿到的数据
* @param {number} start ms
* @param {number} end ms
* @returns
*/
projects(data, start, end) {
if (!data || !data.length) return [];
return data.filter(item => start <= +item.endTime && end >= +item.startTime);
},
};
export default {
/**
* 项目列表某天的 获取
* @param {number} startTime
* @param {number} endTime
* @returns
*/
async getProjectsByDay(startTime, endTime) {
try {
const data = await uni.$t.storage.getStorage('projects');
return filter.projects(JSON.parse(data), startTime, endTime);
} catch (error) {
return [];
}
},
/**
* 项目列表
* @param {array} data
*/
putProjects(data) {
try {
if (!data || !data.length) return; // 服务端没数据不做操作
let value = uni.$t.storage.getStorageSync('projects');
let locals = value ? JSON.parse(value) : [];
if (!locals || !locals.length) {
// 本地没数据
locals = data || [];
} else {
// 本地有数据
data.forEach(item => {
let localData = locals.find(local => item.id === local.id);
if (localData) {
// 有相同数据 就用新的data里的数据
localData = item;
} else {
// 没有就直接存本地
locals.push(item);
}
});
}
uni.$t.storage.setStorage('projects', locals);
} catch (error) {
console.error('error: ', error);
uni.$t.storage.setStorage('projects', []);
}
},
};

190
src/utils/cacheAndRequest.js

@ -0,0 +1,190 @@
import store from '@/store/index';
/**
* 等待token执行api
* 没有token 就延时执行自己 直到有了token在请求
* @param {function} requestFn 执行请求的函数
*/
export const waitTokenRequest = requestFn => {
if (!requestFn || typeof requestFn !== 'function') throw new Error(`requestFn must be a function`);
if (uni.$t.storage.getStorageSync(uni.$t.app.tokenKey)) {
requestFn();
} else {
setTimeout(() => waitTokenRequest(requestFn), 10);
}
};
export default {
/**
* 获取项目列表
* @param {number} startTime 起始时间
* @param {number} endTime 截止时间
*/
getProjects(startTime, endTime, fn) {
let remote = false;
if (store.getters.useStorage) {
// 有缓存 且 服务端数据未返回 就先返回缓存
uni.$t.cache
.getProjectsByDay(startTime, endTime)
.then(data => {
!remote && fn(null, data);
})
.catch(err => !remote && fn(err));
}
waitTokenRequest(() => {
// 拿到api数据后 再用api的数据
uni.$u.api
.getProjects(startTime, endTime)
.then(data => {
remote = true;
fn(null, data);
// 存api到cache里
uni.$t.cache.putProjects(data);
})
.catch(err => fn(err));
});
},
/**
* 通过项目id获取角色信息
* @param {object} params 提交的参数
*/
findShowRole(params, fn) {
let remote = false;
// 有缓存 且 服务端数据未返回 就先返回缓存
uni.$t.cache
.getShowRole(params.projectId)
.then(data => {
!remote && fn(null, data);
})
.catch(err => !remote && fn(err));
waitTokenRequest(() => {
// 拿到api数据后 再用api的数据
uni.$u.api
.findShowRole(params)
.then(data => {
remote = true;
fn(null, data);
// 存api到cache里
uni.$t.cache.putShowRole(params.projectId, data);
})
.catch(err => fn(err));
});
},
/**
* 根据时间基准点和角色查找定期任务
* @param {object} params 提交的参数
*/
getRegularTask(params, fn) {
let remote = false;
// 有缓存 且 服务端数据未返回 就先返回缓存
uni.$t.cache
.getStorageRegularTask(params)
.then(data => {
console.log('cache data: ', data);
!remote && fn(null, data);
})
.catch(err => !remote && fn(err));
waitTokenRequest(() => {
// 拿到api数据后 再用api的数据
uni.$u.api
.getRegularTask(params)
.then(data => {
console.log('api data: ', uni.$u.deepClone(data));
remote = true;
fn(null, uni.$u.deepClone(data));
// 存api到cache里
uni.$t.cache.putStorageRegularTask(params, data);
})
.catch(err => fn(err));
});
},
/**
* 根据角色查找永久的日常任务
* @param {object} params 提交的参数
*/
getPermanent(params, fn) {
let remote = false;
// 有缓存 且 服务端数据未返回 就先返回缓存
uni.$t.cache
.getStoragePermanent(params)
.then(data => {
!remote && fn(null, data);
})
.catch(err => !remote && fn(err));
waitTokenRequest(() => {
// 拿到api数据后 再用api的数据
uni.$u.api
.getPermanent(params)
.then(data => {
remote = true;
fn(null, data);
// 存api到cache里
uni.$t.cache.putStoragePermanent(params, data);
})
.catch(err => fn(err));
});
},
/**
* 根据时间和角色查找日常任务
* @param {object} params 提交的参数
*/
getGlobal(params, fn) {
let remote = false;
// 有缓存 且 服务端数据未返回 就先返回缓存
uni.$t.cache
.getDailyTask(params)
.then(data => {
!remote && fn(null, data);
})
.catch(err => !remote && fn(err));
waitTokenRequest(() => {
// 拿到api数据后 再用api的数据
uni.$u.api
.getGlobal(params)
.then(data => {
remote = true;
fn(null, data);
// 存api到cache里
uni.$t.cache.putDailyTask(params, data);
})
.catch(err => fn(err));
});
},
/**
* 获取插件信息
* @param {object} params 提交的参数
*/
getOtherPlugin(params, fn) {
let remote = false;
// 有缓存 且 服务端数据未返回 就先返回缓存
uni.$t.cache
.getPlugin(params.pluginId)
.then(data => {
!remote && fn(null, data);
})
.catch(err => !remote && fn(err));
waitTokenRequest(() => {
// 拿到api数据后 再用api的数据
uni.$u.api
.getOtherPlugin(params)
.then(data => {
remote = true;
fn(null, data);
// 存api到cache里
uni.$t.cache.putPlugin(params.pluginId, data);
})
.catch(err => fn(err));
});
},
};

185
src/utils/indexedDB.js

@ -1,185 +0,0 @@
import { name } from '@/config/db';
import { curry } from 'lodash';
// 创建表
const createCollection = (Vue, db) => {
// projects项目表
!db.objectStoreNames.contains('projects') && db.createObjectStore('projects', { keyPath: 'id' });
// roles 角色表
!db.objectStoreNames.contains('roles') && db.createObjectStore('roles', { keyPath: 'id' });
// plan_tasks 定期任务
!db.objectStoreNames.contains('plan_tasks') && db.createObjectStore('plan_tasks', { keyPath: 'id' });
// fixed_tasks 固定全局任务
Vue.prototype.$db.fixed_tasks = !db.objectStoreNames.contains('fixed_tasks') && db.createObjectStore('fixed_tasks', { keyPath: 'id' });
// variable_tasks 可变全局任务
Vue.prototype.$db.variable_tasks =
!db.objectStoreNames.contains('variable_tasks') && db.createObjectStore('variable_tasks', { keyPath: 'id' });
// plugins 插件表
Vue.prototype.$db.plugins = !db.objectStoreNames.contains('plugins') && db.createObjectStore('plugins', { keyPath: 'id' });
};
/**
* 新增数据
*
* @param {object} db 数据库database
* @param {string} collection 集合/
* @param {object} data 数据
*/
const create = (db, collection, data) => {
return new Promise((resolve, reject) => {
const request = db.transaction([collection], 'readwrite').objectStore(collection).add(data);
request.onsuccess = event => {
console.log(event);
// FIXME:
resolve(event);
};
request.onerror = event => {
console.log(event);
// FIXME:
reject(event);
};
});
};
/**
* 找到1条数据
*
* @param {object} db 数据库database
* @param {string} collection 集合/
* @param {string} key 索引关键字 一般是id
*/
const findOne = (db, collection, key) => {
return new Promise((resolve, reject) => {
const request = db.transaction([collection]).objectStore(collection).get(key);
request.onerror = event => {
console.log('indexedDB findOne error:', event);
// FIXME:
reject(event);
};
request.onsuccess = event => {
console.log('indexedDB findOne success:', event);
// FIXME:
resolve(event);
};
});
};
/**
* 找到所有数据
*
* @param {object} db 数据库database
* @param {string} collection 集合/
*/
const find = (db, collection) => {
return new Promise((resolve, reject) => {
const request = db.transaction(collection).objectStore(collection).openCursor();
request.onerror = event => {
console.log('indexedDB find error:', event);
reject(event);
};
request.onsuccess = event => {
const cursor = event.target.result;
if (cursor) {
console.log('indexedDB find success:', cursor);
cursor.continue();
// FIXME:
resolve(event.target.result);
} else {
console.log('没有更多数据了');
}
};
});
};
/**
* 更新数据
*
* @param {object} db 数据库database
* @param {string} collection 集合/
* @param {object} newData 新数据
*/
const update = (db, collection, newData) => {
return new Promise((resolve, reject) => {
const request = db.transaction([collection], 'readwrite').objectStore(collection).put(newData);
request.onerror = event => {
console.log('indexedDB UPDATE error:', event);
reject(event);
};
request.onsuccess = event => {
console.log('indexedDB UPDATE success:', event);
// FIXME:
resolve(event);
};
});
};
/**
* 移除数据 通过关键字
*
* @param {object} db 数据库database
* @param {string} collection 集合/
* @param {string} key 关键字
*/
const remove = (db, collection, key) => {
return new Promise((resolve, reject) => {
const request = db.transaction([collection], 'readwrite').objectStore(collection).delete(key);
request.onerror = event => {
console.log('indexedDB REMOVE error:', event);
reject(event);
};
request.onsuccess = event => {
console.log('indexedDB REMOVE success:', event);
resolve(event);
};
});
};
/**
* 创建索引
*
* @param {object} db 数据库database
* @param {string} collection 集合/
* @param {string} field 创建索引的字段名称
* @param {string} key 关键字
*/
const createIndexAndFind = (db, collection, field, key) => {
return new Promise((resolve, reject) => {
const index = db.transaction([collection], 'readonly').objectStore(collection).index(field);
const request = index.get(key);
// FIXME:
request.onerror = event => reject(event);
request.onsuccess = event => resolve(event);
});
};
const curriedCreate = curry(create);
export const curriedFindOne = curry(findOne);
export const curriedFind = curry(find);
export const curriedRemove = curry(remove);
export const curriedUpdate = curry(update);
export const curriedIndex = curry(createIndexAndFind);
const install = Vue => {
Vue.prototype.$db = {};
Vue.prototype.$db.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
const request = Vue.prototype.$db.indexedDB.open(name, Date.now()); // IDBRequest 对象
request.onerror = error => console.error('打开数据库失败', error);
request.onsuccess = event => {
console.log('INDEXED_DB OPEN SUCCESS');
Vue.prototype.$db.db = event.target.result;
};
request.onupgradeneeded = event => {
console.log('INDEXED_DB OPEN onupgradeneeded');
Vue.prototype.$db.db = event.target.result;
// 创建表
createCollection(Vue, Vue.prototype.$db.db);
};
// create
// console.log(curriedCreate(Vue.prototype.$db.db));
Vue.prototype.$db.create = curriedCreate(Vue.prototype.$db.db);
};
export default { install };

5
src/utils/request.js

@ -11,8 +11,9 @@ const install = (Vue, vm) => {
// 请求拦截部分,如配置,每次请求前都会执行
Vue.prototype.$u.http.interceptor.request = config => {
if (vm.$store.state.user.token) {
config.header.Authorization = `Bearer ${vm.$store.state.user.token}`;
const token = vm.$store.state.user.token || uni.$t.storage.getStorageSync(uni.$t.app.tokenKey);
if (token) {
config.header.Authorization = `Bearer ${token}`;
}
return config;

14
src/utils/storage.js

@ -39,6 +39,7 @@ export default {
* @param {*} data
*/
setStorage(key, data) {
uni.$t.storage.checkCapacity();
return new Promise((resolve, reject) => {
const value = typeof data === 'string' ? data : JSON.stringify(data);
uni.setStorage({
@ -67,7 +68,7 @@ export default {
resolve(res.data);
},
fail(error) {
reject(`数据${key}获取失败, error: ${error}`);
reject(`数据${key}获取失败, error: ${error.errMsg}`);
},
});
});
@ -97,4 +98,15 @@ export default {
clearStorage() {
uni.clearStorage();
},
// 检测local Storage容量 超出容量清空数据缓存
checkCapacity() {
/* #ifdef H5 */
const capacity = JSON.stringify(localStorage).length;
let max = 1024 * 1024 * 4;
if (capacity >= max) {
uni.$t.storage.clearStorage();
}
/* #endif */
},
};

12
src/utils/tall.js

@ -1,24 +1,26 @@
import app from '@/config/app.js';
import timeConfig from '@/config/time';
import zIndex from '@/config/zIndex.js';
import plugin from '@/config/plugin.js';
import cache from '@/utils/cache.js';
import cacheAndRequest from '@/utils/cacheAndRequest.js';
import storage from '@/utils/storage.js';
import time from '@/utils/time.js';
import ui from '@/utils/ui.js';
import upload from '@/utils/upload.js';
import user from '@/config/user.js';
import zIndex from '@/config/zIndex.js';
const gateway = process.env.VUE_APP_API_URL;
const $t = {
zIndex, // 定位元素层级
app, // app级别的相关配置
plugin, // 插件相关配置信息
storage, // 本地存储storage封装
time, // 时间处理
timeConfig, // 时间相关配置
ui, // ui界面提示相关
chooseAndUpload: upload.chooseAndUpload, // 选择并上传单个文件相关的封装
domain: `${gateway}/defaultwbs`,
cache, // 本地存储相关
$q: cacheAndRequest,
user, // 用户相关配置
};
uni.$t = $t;

2
src/utils/time.js

@ -82,7 +82,7 @@ const setTimestampToStr = timestamp => {
const day = formatNumber(timeObj.getDate());
const hour = formatNumber(timeObj.getHours());
const minute = formatNumber(timeObj.getMinutes());
const date = `${year}/${month}/${day}`;
const date = `${year}-${month}-${day}`;
const time = `${hour}:${minute}`;
return {
date,

30
tailwind.config.js

@ -1,30 +0,0 @@
const colors = require('tailwindcss/colors');
module.exports = {
// purge: ['./public/index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
colors: {
blue: colors.sky,
gray: colors.blueGray,
red: colors.red,
orange: colors.orange,
yellow: colors.yellow,
green: colors.green,
pink: colors.rose,
white: colors.white,
black: '#333',
transparent: 'transparent',
},
},
variants: { extend: {} },
plugins: [],
corePlugins: {
space: false,
divideWidth: false,
divideColor: false,
divideStyle: false,
divideOpacity: false,
},
};

7
vue.config.js

@ -29,9 +29,8 @@ module.exports = {
},
pluginOptions: {
// mock: { entry: './src/mock/mock.js', debug: true, disable: true },
eruda: {},
webpackBundleAnalyzer: {
openAnalyzer: isPro,
},
// webpackBundleAnalyzer: {
// openAnalyzer: isPro,
// },
},
};

Loading…
Cancel
Save