Browse Source

project (#1)

fix: 交付物+考勤管理

chore: 关掉了treeShaking

Merge remote-tracking branch 'origin/lucky' into project

chore(node-sass): 替换node-sass为sass(dart-sass)

/deep/替换为::deep

fix: 检查交付物传参修改

fix: 检查交付物传参修改

feat: 检查交付物

refactor: puppeteer升级v10

refactor: 重构时间刻度渲染任务

解决了时间刻度未替换的问题;解决重复渲染的问题

feat: 添加内置插件-交付物

fix: 调试定期任务bug;不能合并使用

fix: 滚动id函数优化

feat: network控制本地缓存的使用

network控制本地缓存的使用;删除了projects相关的代码

refactor(tailwindcss): tailwindcss CDN引入;移除相关配置文件及包;开启treeShaking

chore: 删除vuedragable及修改运行端口为9000

refactor: 只保留project内容

feat: 细节调整,添加project-webview

准备分离project

feat(phone-bind): 验证码validate

feat(mp): 兼容小程序,去除window,document等

feat(bind phone): 图形验证码;短信验证码;绑定手机号

Merge remote-tracking branch 'origin/songsong' into temp

feat: 添加项目排序

feat: 绑定手机号

Merge remote-tracking branch 'origin/songsong' into temp

feat: 适配小程序;小程序登录

fix: 定期任务本地缓存和api赋值,未完成

fix(定期任务本地缓存和api赋值,未完成): 定期任务本地缓存和api赋值,未完成

fix: api 存storage

feat: api封装

Merge remote-tracking branch 'origin/lucky' into song

perf: 小红点api缓存修改

feat: 缓存修改

style: indexedDB.js格式整理

feat: cache indexedDB处理

Co-authored-by: song <srf428110@163.com>
Reviewed-on: https://dd.tall.wiki/gitea/wally/tall-mui-3-project/pulls/1
develop
wally 4 years ago
parent
commit
ceca8724a3
  1. 1
      .eslintignore
  2. 350
      CHANGELOG.md
  3. 2
      README.md
  4. 12
      package.json
  5. 19
      postcss.config.js
  6. 1
      public/index.html
  7. 15
      rest/http-client.env.json
  8. 39
      rest/project.http
  9. 11
      src/.hbuilderx/launch.json
  10. 70
      src/App.vue
  11. 6
      src/apis/plugin.js
  12. 4
      src/apis/role.js
  13. 28
      src/apis/tall.js
  14. 6
      src/common/styles/index.css
  15. 473
      src/components/Calendar/Calendar.vue
  16. 136
      src/components/Calendar/generateDates.js
  17. 13
      src/components/Globals/Globals.vue
  18. 35
      src/components/Plugin/Plugin.vue
  19. 7
      src/components/Projects/ProjectItem.vue
  20. 72
      src/components/Projects/Projects.vue
  21. 56
      src/components/Roles/Roles.vue
  22. 7
      src/components/Skeleton/Skeleton.vue
  23. 45
      src/components/Skeleton/view.vue
  24. 1
      src/components/Skeleton/wisdomcar_mobile
  25. 35
      src/components/TimeLine/TimeLine.vue
  26. 15
      src/components/TimeLine/component/TimeBox.vue
  27. 8
      src/components/TimeLine/component/TimeStatus.vue
  28. 17
      src/components/Tips/Tips.vue
  29. 15
      src/components/Title/Title.vue
  30. 4
      src/components/Upload/Upload.vue
  31. 335
      src/components/ld-select/ld-select.vue
  32. 22
      src/components/uni-popup/message.js
  33. 23
      src/components/uni-popup/popup.js
  34. 246
      src/components/uni-popup/uni-popup-dialog.vue
  35. 115
      src/components/uni-popup/uni-popup-message.vue
  36. 171
      src/components/uni-popup/uni-popup-share.vue
  37. 289
      src/components/uni-popup/uni-popup.vue
  38. 276
      src/components/uni-transition/uni-transition.vue
  39. 1
      src/config/app.js
  40. 2
      src/config/task.js
  41. 43
      src/config/user.js
  42. 36
      src/main.js
  43. 76
      src/manifest.json
  44. 44
      src/mixins/timeline.js
  45. 37
      src/package.json
  46. 9
      src/pages.json
  47. 128
      src/pages/index/index.vue
  48. 388
      src/pages/project/project.vue
  49. 15
      src/pages/test/test.vue
  50. 61
      src/plugins/p-deliver-check/p-deliver-check.vue
  51. 20
      src/plugins/p-deliverable/p-deliverable.vue
  52. 140
      src/plugins/p-delivery-history/p-delivery-history.vue
  53. 8
      src/plugins/p-task-duration-delay/p-task-duration-delay.vue
  54. 104
      src/plugins/p-upload-deliverable/p-upload-deliverable.vue
  55. 4
      src/plugins/p-wbs-import/p-wbs-import.vue
  56. BIN
      src/static/local_play1.png
  57. BIN
      src/static/logo.png
  58. 28
      src/store/index.js
  59. 17
      src/store/project/actions.js
  60. 16
      src/store/role/actions.js
  61. 12
      src/store/role/getters.js
  62. 9
      src/store/role/mutations.js
  63. 1
      src/store/role/state.js
  64. 36
      src/store/task/actions.js
  65. 14
      src/store/task/mutations.js
  66. 12
      src/store/task/state.js
  67. 8
      src/store/user/actions.js
  68. 2
      src/store/user/mutations.js
  69. 24
      src/test/util/task.test.js
  70. 344
      src/utils/cache.js
  71. 165
      src/utils/cacheAndRequest.js
  72. 84
      src/utils/indexedDB.js
  73. 5
      src/utils/request.js
  74. 14
      src/utils/storage.js
  75. 12
      src/utils/tall.js
  76. 53
      src/utils/task.js
  77. 9
      src/utils/time.js
  78. 30
      tailwind.config.js
  79. 8
      vue.config.js

1
.eslintignore

@ -10,3 +10,4 @@ postcss.config.js
vue.config.js
src/common/styles/index.css
src/pages.json
src/manifest.json

350
CHANGELOG.md

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

2
README.md

@ -14,7 +14,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

12
package.json

@ -29,12 +29,6 @@
"@dcloudio/uni-h5": "^2.0.0-31920210709003",
"@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",
@ -62,7 +56,6 @@
"@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",
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-vuex": "~4.5.0",
@ -85,17 +78,14 @@
"lint-staged": "^11.0.0",
"mini-types": "*",
"miniprogram-api-typings": "*",
"node-sass": "^4.14.1",
"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,
}),
]
)
],
};

1
public/index.html

@ -14,6 +14,7 @@
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'))
document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<link rel="stylesheet" href="https://unpkg.com/tailwindcss@2.2.7/dist/tailwind.min.css">
<link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" />
</head>

15
rest/http-client.env.json

@ -0,0 +1,15 @@
{
"$shared": {
"version": "v1",
"identifier": "wally",
"credential": "111111"
},
"dev": {
"name": "dev",
"url": "http://192.168.0.99/gateway"
},
"local": {
"version": "v2",
"url": "http://192.168.0.99/gateway"
}
}

39
rest/project.http

@ -0,0 +1,39 @@
### login
# @name login
POST https://test.tall.wiki/gateway/tall/v1.0/users/signin
content-type: application/json;charset=utf-8
{
"client": 1,
"data": {
"credential": "999999",
"identifier": "song"
},
"scene": 0,
"type": 3
}
### 导入插件
# POST http://127.0.0.1:7220/plugin/import
POST http://test.tall.wiki/gateway/pluginshop/plugin/import
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Authorization: Bearer {{login.response.body.$.data.token}}
title
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="param"; filename="插件导入表格.xlsx"
Content-Type: xlsx
< E:\ccsens\plugins\插件导入表格.xlsx
------WebKitFormBoundary7MA4YWxkTrZu0gW--
### 更新redis内的插件信息
POST http://test.tall.wiki/gateway/pluginshop/plugin/updatePluginOfRedis
content-type: application/json;charset=utf-8
Authorization: Bearer {{login.response.body.$.data.token}}

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"
}
}
]
}

70
src/App.vue

@ -1,8 +1,17 @@
<script>
import { mapActions, mapState } from 'vuex';
import { mapActions, mapMutations, mapState, mapGetters } 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 +20,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>

6
src/apis/plugin.js

@ -9,6 +9,12 @@ const install = (Vue, vm) => {
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);
// 提交交付物
vm.$u.api.saveDeliver = param => vm.$u.post(`${uni.$t.domain}/deliver/save`, param);
// 查询任务的交付物历史记录
vm.$u.api.queryDeliverOfTask = param => vm.$u.post(`${uni.$t.domain}/deliver/queryDeliverOfTask`, param);
// 检查交付物
vm.$u.api.checkDeliver = param => vm.$u.post(`${uni.$t.domain}/deliver/checkDeliver`, param);
};
export default { install };

4
src/apis/role.js

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

28
src/apis/tall.js

@ -1,10 +1,36 @@
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 });
// 查询日历是否有小红点

6
src/common/styles/index.css

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

473
src/components/Calendar/Calendar.vue

@ -1,473 +0,0 @@
<template>
<view class="zzx-calendar">
<view class="calendar-heander">
{{ timeStr }}
</view>
<!-- 星期几标题 -->
<view class="calendar-weeks">
<view class="calendar-week" :class="{ 'text-red-500': week === '六' || week === '日' }" v-for="(week, index) in weeks" :key="index">
{{ week }}
</view>
</view>
<view class="calendar-content">
<swiper
class="calendar-swiper"
:style="{
width: '100%',
height: sheight,
}"
:indicator-dots="false"
:autoplay="false"
:duration="duration"
:current="current"
@change="changeSwp"
:circular="true"
>
<swiper-item class="calendar-item" v-for="sitem in swiper" :key="sitem">
<view class="calendar-days">
<!-- 当前的 -->
<template v-if="sitem === current">
<view
class="calendar-day"
v-for="(item, index) in days"
:key="index"
:class="{ 'day-hidden': !item.show }"
@click="clickItem(item)"
>
<view class="date" :class="[item.isToday ? todayClass : '', item.fullDate === selectedDate ? checkedClass : '']">
{{ item.time.getDate() }}
</view>
<view class="dot-show" v-if="item.info === '0'" :style="dotStyle"> </view>
</view>
</template>
<template v-else>
<!-- 下一个月/ -->
<template v-if="current - sitem === 1 || current - sitem === -2">
<view
class="calendar-day"
v-for="(item, index) in predays"
:key="index"
:class="{
'day-hidden': !item.show,
}"
>
<view class="date" :class="[item.isToday ? todayClass : '']">
{{ item.time.getDate() }}
</view>
</view>
</template>
<!-- 上一个月/ -->
<template v-else>
<view
class="calendar-day"
v-for="(item, index) in nextdays"
:key="index"
:class="{
'day-hidden': !item.show,
}"
>
<view class="date" :class="[item.isToday ? todayClass : '']">
{{ item.time.getDate() }}
</view>
</view>
</template>
</template>
</view>
</swiper-item>
</swiper>
<!-- <view class="mode-change" @click="changeMode">
<view :class="weekMode ? 'mode-arrow-bottom' : 'mode-arrow-top'"> </view>
</view> -->
</view>
<view class="flex justify-center u-font-18" style="color: #3b82f6" @click="goToday"> 今日 </view>
</view>
</template>
<script>
import { mapState } from 'vuex';
import { gegerateDates, formatDate } from './generateDates.js';
export default {
props: {
duration: { type: Number, default: 500 },
//
showBack: { type: Boolean, default: false },
// class
todayClass: { type: String, default: 'is-today' },
// class
checkedClass: { type: String, default: 'is-checked' },
//
dotStyle: {
type: Object,
default: () => {
return { background: '#4ade80' };
},
},
},
watch: {
dotList: function (newvalue) {
const days = this.days.slice(0);
const index = days.findIndex(day => day.show);
days.forEach((day, i) => {
newvalue.forEach((item, j) => {
if (i - index === j) {
day.info = item;
}
});
});
this.days = days;
},
},
data() {
return {
weeks: ['日', '一', '二', '三', '四', '五', '六'], //
current: 1,
currentYear: '',
currentMonth: '',
currentDate: '',
days: [],
weekMode: false, // false -> true ->
swiper: [0, 1, 2],
selectedDate: formatDate(new Date(), 'yyyy-MM-dd'), //
start: '',
end: '',
};
},
computed: {
...mapState('project', ['dotList']),
sheight() {
//
//
let h = '35px';
if (!this.weekMode) {
const d = new Date(this.currentYear, this.currentMonth, 0);
const days = d.getDate(); //
let day = new Date(d.setDate(1)).getDay();
// if (day === 0) {
// day = 7;
// }
const pre = 8 - day;
const rows = Math.ceil((days - pre) / 7) + 1;
h = 35 * rows + 'px';
}
return h;
},
//
timeStr() {
let str = '';
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
const y = d.getFullYear();
const m = d.getMonth() + 1 <= 9 ? `0${d.getMonth() + 1}` : d.getMonth() + 1;
str = `${y}${m}`;
return str;
},
// days
predays() {
let pres = [];
if (this.weekMode) {
//
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
d.setDate(d.getDate() - 7);
pres = gegerateDates(d, 'week');
} else {
//
const d = new Date(this.currentYear, this.currentMonth - 2, 1);
pres = gegerateDates(d, 'month');
}
return pres;
},
// days
nextdays() {
let nexts = [];
if (this.weekMode) {
//
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
d.setDate(d.getDate() + 7);
nexts = gegerateDates(d, 'week');
} else {
//
const d = new Date(this.currentYear, this.currentMonth, 1);
nexts = gegerateDates(d, 'month');
}
return nexts;
},
},
created() {
this.initDate();
this.start = this.$moment().startOf('month').valueOf();
this.end = this.$moment().endOf('month').valueOf();
},
methods: {
//
/**
* 滑动切换上下周期
* 根据前一个减去目前的值我们可以判断是下一个月/周还是上一个月/
* current - pre === 1, -2 下一个月/
* current - pre === -1, 2 上一个月或者上一周
*/
changeSwp(e) {
const pre = this.current;
const current = e.target.current;
this.current = current;
if (current - pre === 1 || current - pre === -2) {
//
this.daysNext();
const arr = this.days.filter(s => s.show);
const end = `${arr[arr.length - 1].fullDate} 23:59:59`;
this.start = this.$moment(arr[0].fullDate).valueOf();
this.end = this.$moment(end).valueOf();
this.$emit('handleFindPoint', this.start, this.end);
} else {
//
this.daysPre();
const arr = this.days.filter(s => s.show);
const end = `${arr[arr.length - 1].fullDate} 23:59:59`;
this.start = this.$moment(arr[0].fullDate).valueOf();
this.end = this.$moment(end).valueOf();
this.$emit('handleFindPoint', this.start, this.end);
}
},
//
initDate(cur) {
let date = '';
if (cur) {
date = new Date(cur);
} else {
date = new Date();
}
this.currentDate = date.getDate(); //
this.currentYear = date.getFullYear(); //
this.currentMonth = date.getMonth() + 1; //
this.currentWeek = date.getDay() === 0 ? 7 : date.getDay(); // 1...6,0
// const nowY = new Date().getFullYear(); //
// const nowM = new Date().getMonth() + 1;
// const nowD = new Date().getDate(); //
// const nowW = new Date().getDay();
// this.selectedDate = formatDate(new Date(), 'yyyy-MM-dd')
this.days = [];
let days = [];
if (this.weekMode) {
days = gegerateDates(date, 'week');
// this.selectedDate = days[0].fullDate;
} else {
days = gegerateDates(date, 'month');
// const sel = new Date(this.selectedDate.replace('-', '/').replace('-', '/'));
// const isMonth = sel.getFullYear() === this.currentYear && (sel.getMonth() + 1) === this.currentMonth;
// if(!isMonth) {
// this.selectedDate = formatDate(new Date(this.currentYear, this.currentMonth-1,1), 'yyyy-MM-dd')
// }
}
//
days.forEach((day, i) => {
this.dotList.forEach((item, j) => {
if (i === j) {
day.info = item;
}
});
});
this.days = days;
// ,
let obj = {
start: '',
end: '',
};
if (this.weekMode) {
obj.start = this.days[0].time;
obj.end = this.days[6].time;
} else {
const start = new Date(this.currentYear, this.currentMonth - 1, 1);
const end = new Date(this.currentYear, this.currentMonth, 0);
obj.start = start;
obj.end = end;
}
this.$emit('days-change', obj);
},
//
daysPre() {
if (this.weekMode) {
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
d.setDate(d.getDate() - 7);
this.initDate(d);
} else {
const d = new Date(this.currentYear, this.currentMonth - 2, 1);
this.initDate(d);
}
},
//
daysNext() {
if (this.weekMode) {
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
d.setDate(d.getDate() + 7);
this.initDate(d);
} else {
const d = new Date(this.currentYear, this.currentMonth, 1);
this.initDate(d);
}
},
//
changeMode() {
const premode = this.weekMode;
let isweek = false;
if (premode) {
isweek = !!this.days.find(item => item.fullDate === this.selectedDate);
}
this.weekMode = !this.weekMode;
let d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate);
const sel = new Date(this.selectedDate.replace('-', '/').replace('-', '/'));
const isMonth = sel.getFullYear() === this.currentYear && sel.getMonth() + 1 === this.currentMonth;
if ((this.selectedDate && isMonth) || isweek) {
d = new Date(this.selectedDate.replace('-', '/').replace('-', '/'));
}
this.initDate(d);
},
//
clickItem(e) {
this.selectedDate = e.fullDate;
this.$emit('selected-change', e);
},
//
goToday() {
const d = new Date();
this.initDate(d);
},
},
};
</script>
<style lang="scss" scoped>
.zzx-calendar {
width: 100%;
height: auto;
background-color: #fff;
padding-bottom: 10px;
.calendar-heander {
text-align: center;
padding: 16px 0;
position: relative;
font-size: 15px;
}
.calendar-weeks {
width: 100%;
display: flex;
flex-flow: row nowrap;
margin-bottom: 10px;
justify-content: center;
align-items: center;
font-size: 12px;
color: #9ca3af;
font-weight: bold;
.calendar-week {
width: calc(100% / 7);
height: 100%;
text-align: center;
}
}
swiper {
width: 100%;
height: 60upx;
}
.calendar-content {
min-height: 30px;
}
.calendar-swiper {
min-height: 35px;
transition: height ease-out 0.3s;
}
.calendar-item {
margin: 0;
padding: 0;
height: 100%;
}
.calendar-days {
display: flex;
flex-flow: row wrap;
width: 100%;
height: 100%;
overflow: hidden;
font-size: 14px;
.calendar-day {
width: calc(100% / 7);
height: 35px;
text-align: center;
display: flex;
flex-flow: column nowrap;
justify-content: flex-start;
align-items: center;
position: relative;
}
}
.day-hidden {
visibility: hidden;
}
.mode-change {
display: flex;
justify-content: center;
margin-top: 5px;
.mode-arrow-top {
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 5px solid #ff6633;
}
.mode-arrow-bottom {
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-top: 5px solid #ff6633;
}
}
.is-today {
background: #ffffff;
border: 1upx solid #ff6633;
border-radius: 50%;
color: #ff6633;
}
.is-checked {
background: #ff6633;
color: #ffffff;
}
.date {
width: 25px;
height: 25px;
line-height: 25px;
margin: 0 auto;
border-radius: 25px;
}
.dot-show {
width: 6px;
height: 6px;
// background: red;
border-radius: 5px;
position: absolute;
top: 2px;
right: 10px;
}
}
</style>

136
src/components/Calendar/generateDates.js

@ -1,136 +0,0 @@
/*
*此函数的作用是根据传入的一个日期返回这一周的日期或者这一个月的日期
* 如果是月的话注意还包含上个月和下个月的日期月的话总共数据有 6 * 7 = 42
*
*/
/*
* 时间格式化函数
* 重要提示微信小程序new Date('2020-04-16')在ios中无法获取时间对象
* 解决方式: 建议将时间都格式化成'2020/04/16 00:00:00'的格式
* 函数示例: formatDate(new Date(), 'YYYY/MM/dd hh:mm:ss')
*/
export const formatDate = (date, fmt) => {
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
}
let o = {
'M+': date.getMonth() + 1,
'd+': date.getDate(),
'h+': date.getHours(),
'm+': date.getMinutes(),
's+': date.getSeconds(),
};
for (let k in o) {
if (new RegExp(`(${k})`).test(fmt)) {
let str = o[k] + '';
fmt = fmt.replace(RegExp.$1, RegExp.$1.length === 1 ? str : padLeftZero(str));
}
}
return fmt;
};
const padLeftZero = str => {
return ('00' + str).substr(str.length);
};
// 判断是不是date对象
export const judgeType = s => {
// 函数返回数据的具体类型
return Object.prototype.toString.call(s).slice(8, -1);
};
export const equalDate = (d1, d2) => {
let result = false;
if (d1.getFullYear() === d2.getFullYear() && d1.getMonth() === d2.getMonth() && d1.getDate() === d2.getDate()) {
result = true;
}
return result;
};
/* ,2020-04-04
*/
export const dateEqual = (before, after) => {
before = new Date(before.replace('-', '/').replace('-', '/'));
after = new Date(after.replace('-', '/').replace('-', '/'));
if (before.getTime() - after.getTime() === 0) {
return true;
} else {
return false;
}
};
export const gegerateDates = (date = new Date(), type = 'week') => {
const result = [];
if (judgeType(date) === 'Date') {
// 年,月,日
const y = date.getFullYear();
const m = date.getMonth();
const d = date.getDate();
const days = new Date(y, m + 1, 0).getDate();
// 获取日期是星期几
// let weekIndex = date.getDay() === 0 ? 7 : date.getDay();
let weekIndex = date.getDay();
if (type === 'month') {
const dobj = new Date(y, m, 1);
// weekIndex = dobj.getDay() === 0 ? 7 : dobj.getDay();
weekIndex = dobj.getDay();
}
if (type === 'week') {
for (let i = weekIndex; i > 0; i--) {
const dtemp = new Date(y, m, d);
dtemp.setDate(dtemp.getDate() - i);
result.push({
time: dtemp,
show: true,
fullDate: formatDate(dtemp, 'yyyy-MM-dd'),
isToday: equalDate(new Date(), dtemp),
});
}
for (let i = 0; i <= 7 - weekIndex; i++) {
const dtemp = new Date(y, m, d);
dtemp.setDate(dtemp.getDate() + i);
result.push({
time: dtemp,
show: true,
fullDate: formatDate(dtemp, 'yyyy-MM-dd'),
isToday: equalDate(new Date(), dtemp),
});
}
} else if (type === 'month') {
// 上个月
for (let i = weekIndex; i > 0; i--) {
const dtemp = new Date(y, m, 1);
dtemp.setDate(dtemp.getDate() - i);
result.push({
time: dtemp,
show: false,
fullDate: formatDate(dtemp, 'yyyy-MM-dd'),
isToday: equalDate(new Date(), dtemp),
});
}
// 这个月的日期
for (let i = 0; i < days; i++) {
const dtemp = new Date(y, m, 1);
dtemp.setDate(dtemp.getDate() + i);
result.push({
time: dtemp,
show: true,
fullDate: formatDate(dtemp, 'yyyy-MM-dd'),
isToday: equalDate(new Date(), dtemp),
});
}
const len = 42 - result.length;
// 下个月的日期
for (let i = 1; i <= len; i++) {
const dtemp = new Date(y, m + 1, 0);
dtemp.setDate(dtemp.getDate() + i);
result.push({
time: dtemp,
show: false,
fullDate: formatDate(dtemp, 'yyyy-MM-dd'),
isToday: equalDate(new Date(), dtemp),
});
}
}
}
return result;
};

13
src/components/Globals/Globals.vue

@ -12,12 +12,12 @@
<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">
<block v-for="item in globals" :key="item.id">
<template v-if="item.plugins">
<template v-for="pluginArr in item.plugins">
<block v-for="(pluginArr, i) in item.plugins" :key="i">
<template class="p-0 u-col-between" v-if="pluginArr.length">
<Plugin
:class="getClass(plugin.col, plugin.row)"
:class="[`row-span-${plugin.row}`, `col-span-${plugin.col}`]"
:task="item"
:key="plugin.pluginTaskId"
:plugin-task-id="plugin.pluginTaskId"
@ -26,9 +26,9 @@
v-for="plugin in pluginArr"
/>
</template>
</block>
</template>
</template>
</template>
</block>
</view>
</scroll-view>
</view>
@ -58,9 +58,6 @@ export default {
methods: {
...mapMutations('task', ['setShrink']),
getClass(col, row) {
return [`row-span-${row}`, `col-span-${col}`];
},
//
openCard() {

35
src/components/Plugin/Plugin.vue

@ -2,19 +2,19 @@
<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-param="param"
:data-pdu="task.planDuration"
:data-pid="projectId"
:data-pstart="task.planStart"
:data-rdu="task.realDuration"
:data-rid="roleId"
:data-rstart="task.realStart"
: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"
:data-token="token"
:data-uid="userId"
style="height: 100%"
v-html="pluginContent"
></view>
</view>
@ -26,7 +26,8 @@
<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-upload-deliverable :task="task" v-if="pluginId === '5' && isMine" />
<p-delivery-history :task="task" v-if="pluginId === '5' && !isMine" />
<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'" /> -->
@ -42,10 +43,8 @@
<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 },
@ -64,6 +63,7 @@ export default {
...mapState('user', ['token']),
...mapGetters('user', ['userId']),
...mapGetters('project', ['projectId']),
...mapGetters('role', ['isMine']),
//
// pluginComponent() {
@ -81,10 +81,11 @@ export default {
//
async getPlugin() {
const { pluginId, styleType } = this;
const data = await this.$u.api.getOtherPlugin({
pluginId,
styleType,
});
const params = { pluginId, styleType };
this.$t.$q.getOtherPlugin(params, (err, data) => {
if (err) {
console.error('err: ', err);
} else {
if (!data || !data.id) return;
const reg = /data-root=["|']?(\w+)["|']?/gi;
let uuid = '';
@ -103,6 +104,8 @@ export default {
const str = data.js.replace(new RegExp(uuid, 'g'), `p${this.pluginTaskId}`);
this.handleDom(str);
}
}
});
// if (data.js) {
// if (reg.test(data.js)) {

7
src/components/Projects/ProjectItem.vue

@ -1,7 +0,0 @@
<template>
<view class="flex items-center justify-between">
这是子项目
</template>
<script>
export default {};
</script>

72
src/components/Projects/Projects.vue

@ -1,72 +0,0 @@
<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>
</view>
</template>
<script>
import { mapGetters, mapState } from 'vuex';
export default {
data() {
return {};
},
computed: {
...mapState('project', ['projects']),
...mapGetters('user', ['userId']),
},
methods: {
/**
* 打开项目
* @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),
});
},
},
};
</script>
<style lang="scss" scoped>
.order {
display: flex;
justify-content: center;
align-items: center;
width: 32px;
height: 32px;
font-size: 13px;
}
</style>

56
src/components/Roles/Roles.vue

@ -3,9 +3,25 @@
<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>
<!-- 角色项
default-tab-choice 我的角色 && 当前展示
default-tab-item 我的角色 && 当前不展示
tab-choice 不是我的 && 当前展示
-->
<view
:class="{
'default-tab-choice': item.mine == 1 && roleId === item.id,
'default-tab-item': item.mine == 1 && roleId !== item.id,
'tab-choice': item.mine == 0 && roleId === item.id,
}"
:key="index"
@click="changeRole(item.id, index)"
class="tab-item"
v-for="(item, index) in roles"
>
<view class="tab-children u-skeleton-fillet u-font-14">
{{ item.name }}
</view>
</view>
</view>
</scroll-view>
@ -56,24 +72,29 @@ export default {
},
methods: {
...mapActions('task', ['handleRegularTask', 'getPermanent']),
...mapActions('task', ['handleRegularTask']),
...mapMutations('role', ['setRoleId']),
...mapMutations('task', ['setPermanents', 'clearEndFlag']),
//
setCurrentRole(index) {
console.log('index: ', index);
const data = document.getElementsByClassName('tab-children');
// tabList
const query = uni.createSelectorQuery().in(this);
query
.selectAll('.tab-children')
.boundingClientRect(data => {
data.forEach(item => {
this.tabList.push({
width: item.clientWidth,
left: item.offsetLeft,
width: item.width,
left: item.left,
});
});
//
})
.exec();
const system = uni.getSystemInfoSync(); //
//
let left = 0;
let screenWidth = window.screen.width;
let screenWidth = system.windowWidth;
for (let i = 0; i < index; i++) {
left += this.tabList[i].width + this.tabList[i].left * 2;
}
@ -90,7 +111,7 @@ export default {
this.clearPluginScript();
this.$nextTick(() => {
this.setRoleId(id);
//index
// index
this.setCurrentRole(index);
});
} catch (error) {
@ -110,17 +131,6 @@ export default {
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>

7
src/components/Skeleton/Skeleton.vue

@ -133,10 +133,11 @@ export default {
width: 100%;
height: 16px;
background-color: #f2f3f5;
margin-top: 12px;
}
.row-class:not(:first-child) {
margin-top: 12px;
.row-class:first-child {
margin-top: 0;
}
.row {
@ -147,7 +148,7 @@ export default {
width: calc(100% - 48px);
}
.row-class:nth-last-child(1) {
.row-class:last-child {
width: 60%;
}

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

35
src/components/TimeLine/TimeLine.vue

@ -6,7 +6,7 @@
:lower-threshold="300"
scroll-y="true"
:upper-threshold="300"
:scroll-into-view="viewId"
:scroll-into-view="scrollToTaskId"
@scroll="scroll"
@scrolltolower="handleScrollBottom"
@scrolltoupper="handleScrollTop"
@ -22,13 +22,12 @@
<script>
// import Barrier from './component/Barrier.vue';
import { mapState, mapMutations, mapGetters } from 'vuex';
import { setPlaceholderTasks } from '@/utils/task';
import TimeBox from './component/TimeBox.vue';
import mixin from '@/mixins/timeline';
export default {
name: 'TimeLine',
components: { TimeBox },
mixins: [mixin],
data() {
return { top: 0 };
@ -36,12 +35,12 @@ export default {
computed: {
...mapState('role', ['visibleRoles']),
...mapState('task', ['scrollTop', 'showTips', 'tasks', 'topEnd', 'bottomEnd', 'showSkeleton', 'timeNode', 'viewId']),
...mapState('task', ['scrollTop', 'tasks', 'topEnd', 'bottomEnd', 'showSkeleton', 'timeNode', 'scrollToTaskId']),
...mapGetters('task', ['timeGranularity']),
},
methods: {
...mapMutations('task', ['setScrollTop', 'setShrink', 'setUpTasks', 'setDownTasks', 'setViewId']),
...mapMutations('task', ['setScrollTop', 'setShrink', 'setUpTasks', 'setDownTasks', 'setScrollToTaskId']),
//
scroll(e) {
@ -57,7 +56,7 @@ export default {
if ((this.tasks[0].plugins && this.tasks[0].plugins.length === 0) || this.topEnd) {
//
console.warn('滚动到顶部没有数据时: ');
const addTasks = this.setTime(startTime, true);
const addTasks = setPlaceholderTasks(startTime, true, this.timeGranularity);
this.setUpTasks(addTasks);
} else {
//
@ -79,7 +78,7 @@ export default {
if ((tasks[0].plugins && tasks[0].plugins.length === 0) || this.bottomEnd) {
//
console.warn('滚动到底部没有数据时: ');
const addTasks = this.setTime(startTime, false);
const addTasks = setPlaceholderTasks(startTime, false, this.timeGranularity);
this.setDownTasks(addTasks);
} else {
// =+
@ -96,22 +95,16 @@ export default {
//
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
// storagetaskId id
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;
}
this.setScrollToTaskId(`a${taskId}`);
this.$t.storage.setStorageSync('taskId', ''); //
} else {
// taskId
// 线id 线
const task = this.tasks.find(item => this.$moment(+item.planStart).isSame(this.timeNode, this.timeGranularity));
task && this.setScrollToTaskId(`a${task.id}`); // task id
}
},
},

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

@ -2,7 +2,7 @@
<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 :key="task.id" v-for="task in tasks" :id="`a${task.id}`">
<view class="flex">
<TimeStatus :task="task" />
<view class="flex items-center justify-between flex-1 ml-2 task-column">
@ -32,13 +32,13 @@
</u-card>
<u-card
@click="onClickTask(task.planStart - 0, task.id)"
: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">
@ -46,7 +46,7 @@
<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)"
:class="[`row-span-${plugin.row}`, `col-span-${plugin.col}`]"
:task="task"
:key="plugin.pluginTaskId"
:plugin-task-id="plugin.pluginTaskId"
@ -113,11 +113,6 @@ export default {
this.$t.storage.setStorageSync('taskId', taskId);
this.$t.storage.setStorageSync('roleId', this.roleId);
},
//
getClass(col, row) {
return [`row-span-${row}`, `col-span-${col}`];
},
},
};
</script>
@ -137,11 +132,11 @@ export default {
margin-bottom: 8px;
margin-left: 15px;
}
/deep/ .ml-2 {
::deep .ml-2 {
margin-left: 16px;
}
/deep/ .ml-3 {
::deep .ml-3 {
margin-left: 20px;
}
</style>

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

@ -3,11 +3,11 @@
<view
class="flex items-center justify-center rounded-full icon-column"
:style="{ color: orderStyle.color }"
@tap="changeStatus($event, task.process)"
@click="changeStatus(task.process, $event)"
>
<!-- 1进行中 2暂停中 3已完成 -->
<u-circle-progress
:percent="+orderStyle.persent"
:percent="orderStyle.persent - 0"
:active-color="orderStyle.color"
bg-color="rgba(255,255,255,0)"
border-width="4"
@ -23,7 +23,7 @@
</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="flex items-center justify-center rounded-full progress-box" 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">
@ -117,7 +117,7 @@ export default {
* 点击了图标 修改任务状态
* @param {object} event
*/
changeStatus(event, process) {
changeStatus(process, event) {
if (process === 4) {
this.addTask();
return;

17
src/components/Tips/Tips.vue

@ -19,12 +19,12 @@
>
<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>
<u-button size="mini" @click="onCancel">取消</u-button>
<u-button v-if="tip.status === 1" size="mini" @click="onChangeStatus(1)">暂停</u-button>
<u-button v-if="tip.status === 2" size="mini" @click="onChangeStatus(2)">继续</u-button>
<u-button v-if="tip.status === 1 || tip.status === 2" size="mini" @click="onChangeStatus(0)">重新开始</u-button>
<u-button v-if="tip.status === 1 || tip.status === 2" type="primary" size="mini" @click="onChangeStatus(3)">结束</u-button>
<u-button v-if="tip.status === 0 || tip.status === 3" type="primary" size="mini" @click="onChangeStatus(0)">确定</u-button>
</view>
</u-card>
</view>
@ -48,7 +48,8 @@ export default {
},
mounted() {
this.height = window.screen.height;
const system = uni.getSystemInfoSync();
this.height = system.windowHeight;
},
methods: {
@ -65,7 +66,6 @@ export default {
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('项目已重新开始');
@ -77,6 +77,7 @@ export default {
this.$t.ui.showToast('项目结束');
}
this.tip.show = false;
// TODO:
// location.reload();
// this.$router.go(0);
} catch (error) {

15
src/components/Title/Title.vue

@ -1,6 +1,6 @@
<template>
<view>
<u-navbar :custom-back="onBack" class="overflow-hidden">
<u-navbar class="overflow-hidden" :is-back="false">
<view class="flex justify-start flex-1 px-3 font-bold min-0">
<view class="truncate">{{ project.name }}</view>
</view>
@ -27,17 +27,6 @@ export default {
},
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');
@ -59,7 +48,7 @@ export default {
</script>
<style lang="scss" scoped>
/deep/ .u-slot-content {
::deep .u-slot-content {
min-width: 0;
}
</style>

4
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>
@ -41,7 +41,7 @@ export default {
transform: translate3d(0, 50%, 0);
}
/deep/ .uicon-plus {
::deep .uicon-plus {
color: theme('colors.blue.500') !important;
}
</style>

335
src/components/ld-select/ld-select.vue

@ -0,0 +1,335 @@
<template>
<view class="main">
<view class="input" :style="disabled ? 'background-color:#f5f7fa' : ''">
<input @click="showModal" v-model="_value" :style="disabled ? 'color:#c0c4cc' : ''" :placeholder="placeholder" disabled />
<u-icon v-if="clearable && !disabled && showClearable" @click="empty" name="close-circle-fill" color="#C0C4CC" size="32"></u-icon>
</view>
<view class="select-modal" :class="isShowModal ? 'show' : ''" @tap="hideModal">
<view class="select-dialog" @tap.stop="" :style="{ backgroundColor: bgColor }">
<view class="select-bar bg-white">
<view class="action text-gray" @tap="cancelClick">{{ cancelText }}</view>
<view class="action text-blue" @tap="confirmClick">{{ confirmText }}</view>
</view>
<view class="select-content">
<view
class="select-item"
v-for="(item, index) in list"
:key="index"
:style="valueIndexOf(item) ? 'color:' + selectColor + ';background-color:' + selectBgColor + ';' : 'color:' + color + ';'"
@click="select(item)"
>
<view class="title">{{ getLabelKeyValue(item) }}</view>
<u-icon name="checkbox-mark" v-if="valueIndexOf(item)"></u-icon>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return { isShowModal: false, showClearable: false };
},
props: {
value: {
type: [Number, String, Array, Object],
default: null,
},
placeholder: {
//
default: '',
type: String,
},
multiple: {
//
default: false,
type: Boolean,
},
list: {
default: () => [],
type: Array,
},
valueKey: {
// listvalueKey
default: 'value',
type: String,
},
labelKey: {
// listlabelKey
default: 'label',
type: String,
},
disabled: {
default: false,
type: Boolean,
},
clearable: {
default: false,
type: Boolean,
},
cancelText: {
default: '取消',
type: String,
},
confirmText: {
default: '确定',
type: String,
},
color: {
default: '#000000',
type: String,
},
selectColor: {
default: '#0081ff',
type: String,
},
bgColor: {
default: '#F1F1F1',
type: String,
},
selectBgColor: {
default: '#FFFFFF',
type: String,
},
},
computed: {
_value: {
get() {
return this.get_value(this.value);
},
set(val) {
this.$emit('change', val);
},
},
},
created() {},
methods: {
get_value(val) {
// ,
if (val || val === 0) {
if (Array.isArray(val)) {
if (val.length > 0) {
this.showClearable = true;
} else {
this.showClearable = false;
}
let chooseAttr = [];
val.forEach(item => {
let choose = this.list.find(temp => {
let val_val = this.getValueKeyValue(temp);
return item === val_val;
});
chooseAttr.push(choose);
});
let values = chooseAttr.map(temp => this.getLabelKeyValue(temp)).join(',');
return values;
} else {
let choose = this.list.find(temp => {
let val_val = this.getValueKeyValue(temp);
return val === val_val;
});
return this.getLabelKeyValue(choose);
}
} else {
console.log('val2', val);
return '';
}
},
select(item) {
//
let val = this.getValueKeyValue(item);
if (this.multiple) {
let _value = this.value;
let index = _value.indexOf(val);
if (index != -1) {
_value.splice(index, 1);
this.$emit('change', _value);
} else {
_value.push(val);
this.$emit('change', _value);
}
} else {
this.$emit('change', val);
this.hideModal();
}
},
valueIndexOf(item) {
let val = this.getValueKeyValue(item);
if (Array.isArray(this.value)) {
return this.value.indexOf(val) != -1;
} else {
return this.value === val;
}
},
getLabelKeyValue(item) {
// label
return item[this.labelKey];
},
getValueKeyValue(item) {
// value
return item[this.valueKey];
},
empty() {
//
if (this.multiple) {
this.$emit('change', []);
} else {
this.$emit('change', '');
}
},
cancelClick() {
//
this.$emit('cancel', this._value);
this.hideModal();
},
confirmClick() {
//
this.$emit('confirm', this._value);
this.hideModal();
},
showModal() {
// model
if (!this.disabled) {
this.isShowModal = true;
}
},
hideModal() {
// model
this.isShowModal = false;
},
},
};
</script>
<style>
@font-face {
font-family: 'selectIcon';
src: url('//at.alicdn.com/t/font_1833441_ycfzdhg2u3.eot?t=1590375117208'); /* IE9 */
src: url('//at.alicdn.com/t/font_1833441_ycfzdhg2u3.eot?t=1590375117208#iefix') format('embedded-opentype'),
/* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ url('//at.alicdn.com/t/font_1833441_ycfzdhg2u3.svg?t=1590375117208#selectIcon')
format('svg'); /* iOS 4.1- */
}
.selectIcon {
font-family: 'selectIcon' !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icongou:before {
content: '\e61c';
}
.iconcross:before {
content: '\e61a';
}
</style>
<style lang="scss" scoped>
.main {
font-size: 30rpx;
}
.bg-white {
background-color: #ffffff;
}
.text-blue {
color: #0081ff;
}
.text-green {
color: #39b54a;
}
.input {
display: flex;
align-items: center;
font-size: 28rpx;
height: 60rpx;
padding: 10rpx 20rpx;
border-radius: 8rpx;
border-style: solid;
border-width: 1rpx;
border-color: rgb(220, 223, 230);
input {
flex: 1;
}
}
.select-modal {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 9999;
opacity: 0;
outline: 0;
text-align: center;
-ms-transform: scale(1.185);
transform: scale(1.185);
backface-visibility: hidden;
perspective: 2000rpx;
background: rgba(0, 0, 0, 0.6);
transition: all 0.3s ease-in-out 0s;
pointer-events: none;
margin-bottom: -1000rpx;
&::before {
content: '\200B';
display: inline-block;
height: 100%;
vertical-align: bottom;
}
.select-dialog {
position: relative;
display: inline-block;
margin-left: auto;
margin-right: auto;
background-color: #f8f8f8;
overflow: hidden;
width: 100%;
border-radius: 0;
.select-content {
// background-color: #F1F1F1;
max-height: 420rpx;
overflow: auto;
.select-item {
padding: 20rpx;
display: flex;
.title {
flex: 1;
}
}
}
}
}
.select-modal.show {
opacity: 1;
transition-duration: 0.3s;
-ms-transform: scale(1);
transform: scale(1);
overflow-x: hidden;
overflow-y: auto;
pointer-events: auto;
margin-bottom: 0;
}
.select-bar {
padding: 0 20rpx;
display: flex;
position: relative;
align-items: center;
min-height: 80rpx;
justify-content: space-between;
.action {
display: flex;
align-items: center;
height: 100%;
justify-content: center;
max-width: 100%;
}
}
.uni-input-input,
.uni-input-placeholder {
color: #c0c4cc;
font-size: 28rpx;
}
</style>

22
src/components/uni-popup/message.js

@ -0,0 +1,22 @@
export default {
created() {
if (this.type === 'message') {
// 不显示遮罩
this.maskShow = false;
// 获取子组件对象
this.childrenMsg = null;
}
},
methods: {
customOpen() {
if (this.childrenMsg) {
this.childrenMsg.open();
}
},
customClose() {
if (this.childrenMsg) {
this.childrenMsg.close();
}
},
},
};

23
src/components/uni-popup/popup.js

@ -0,0 +1,23 @@
import message from './message.js';
// 定义 type 类型:弹出类型:top/bottom/center
const config = {
// 顶部弹出
top: 'top',
// 底部弹出
bottom: 'bottom',
// 居中弹出
center: 'center',
// 消息提示
message: 'top',
// 对话框
dialog: 'center',
// 分享
share: 'bottom',
};
export default {
data() {
return { config: config };
},
mixins: [message],
};

246
src/components/uni-popup/uni-popup-dialog.vue

@ -0,0 +1,246 @@
<template>
<view class="uni-popup-dialog">
<view class="uni-dialog-title">
<text class="uni-dialog-title-text" :class="['uni-popup__' + dialogType]">{{ title }}</text>
</view>
<view class="uni-dialog-content">
<text class="uni-dialog-content-text" v-if="mode === 'base'">{{ content }}</text>
<input v-else class="uni-dialog-input" v-model="val" type="text" :placeholder="placeholder" :focus="focus" />
</view>
<view class="uni-dialog-button-group">
<view class="uni-dialog-button" @click="close">
<text class="uni-dialog-button-text">取消</text>
</view>
<view class="uni-dialog-button uni-border-left" @click="onOk">
<text class="uni-dialog-button-text uni-button-color">确定</text>
</view>
</view>
</view>
</template>
<script>
/**
* PopUp 弹出层-对话框样式
* @description 弹出层-对话框样式
* @tutorial https://ext.dcloud.net.cn/plugin?id=329
* @property {String} value input 模式下的默认值
* @property {String} placeholder input 模式下输入提示
* @property {String} type = [success|warning|info|error] 主题样式
* @value success 成功
* @value warning 提示
* @value info 消息
* @value error 错误
* @property {String} mode = [base|input] 模式
* @value base 基础对话框
* @value input 可输入对话框
* @property {String} content 对话框内容
* @property {Boolean} beforeClose 是否拦截取消事件
* @event {Function} confirm 点击确认按钮触发
* @event {Function} close 点击取消按钮触发
*/
export default {
name: 'uniPopupDialog',
props: {
value: {
type: [String, Number],
default: '',
},
placeholder: {
type: [String, Number],
default: '请输入内容',
},
/**
* 对话框主题 success/warning/info/error 默认 success
*/
type: {
type: String,
default: 'error',
},
/**
* 对话框模式 base/input
*/
mode: {
type: String,
default: 'base',
},
/**
* 对话框标题
*/
title: {
type: String,
default: '提示',
},
/**
* 对话框内容
*/
content: {
type: String,
default: '',
},
/**
* 拦截取消事件 如果拦截取消事件必须监听close事件执行 done()
*/
beforeClose: {
type: Boolean,
default: false,
},
},
data() {
return {
dialogType: 'error',
focus: false,
val: '',
};
},
inject: ['popup'],
watch: {
type(val) {
this.dialogType = val;
},
mode(val) {
if (val === 'input') {
this.dialogType = 'info';
}
},
value(val) {
this.val = val;
},
},
created() {
//
this.popup.mkclick = false;
if (this.mode === 'input') {
this.dialogType = 'info';
this.val = this.value;
} else {
this.dialogType = this.type;
}
},
mounted() {
this.focus = true;
},
methods: {
/**
* 点击确认按钮
*/
onOk() {
this.$emit(
'confirm',
() => {
this.popup.close();
if (this.mode === 'input') this.val = this.value;
},
this.mode === 'input' ? this.val : '',
);
},
/**
* 点击取消按钮
*/
close() {
if (this.beforeClose) {
this.$emit('close', () => {
this.popup.close();
});
return;
}
this.popup.close();
},
},
};
</script>
<style lang="scss" scoped>
.uni-popup-dialog {
width: 300px;
border-radius: 15px;
background-color: #fff;
}
.uni-dialog-title {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
padding-top: 15px;
padding-bottom: 5px;
}
.uni-dialog-title-text {
font-size: 16px;
font-weight: 500;
}
.uni-dialog-content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
align-items: center;
padding: 5px 15px 15px 15px;
}
.uni-dialog-content-text {
font-size: 14px;
color: #6e6e6e;
}
.uni-dialog-button-group {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
border-top-color: #f5f5f5;
border-top-style: solid;
border-top-width: 1px;
}
.uni-dialog-button {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
justify-content: center;
align-items: center;
height: 45px;
}
.uni-border-left {
border-left-color: #f0f0f0;
border-left-style: solid;
border-left-width: 1px;
}
.uni-dialog-button-text {
font-size: 14px;
}
.uni-button-color {
color: $uni-color-primary;
}
.uni-dialog-input {
flex: 1;
font-size: 14px;
}
.uni-popup__success {
color: $uni-color-success;
}
.uni-popup__warn {
color: $uni-color-warning;
}
.uni-popup__error {
color: $uni-color-error;
}
.uni-popup__info {
color: #909399;
}
</style>

115
src/components/uni-popup/uni-popup-message.vue

@ -0,0 +1,115 @@
<template>
<view class="uni-popup-message" :class="'uni-popup__' + [type]">
<text class="uni-popup-message-text" :class="'uni-popup__' + [type] + '-text'">{{ message }}</text>
</view>
</template>
<script>
/**
* PopUp 弹出层-消息提示
* @description 弹出层-消息提示
* @tutorial https://ext.dcloud.net.cn/plugin?id=329
* @property {String} type = [success|warning|info|error] 主题样式
* @value success 成功
* @value warning 提示
* @value info 消息
* @value error 错误
* @property {String} message 消息提示文字
* @property {String} duration 显示时间设置为 0 则不会自动关闭
*/
export default {
name: 'UniPopupMessage',
props: {
/**
* 主题 success/warning/info/error 默认 success
*/
type: {
type: String,
default: 'success',
},
/**
* 消息文字
*/
message: {
type: String,
default: '',
},
/**
* 显示时间设置为 0 则不会自动关闭
*/
duration: {
type: Number,
default: 3000,
},
},
inject: ['popup'],
data() {
return {};
},
created() {
this.popup.childrenMsg = this;
},
methods: {
open() {
if (this.duration === 0) return;
clearTimeout(this.popuptimer);
this.popuptimer = setTimeout(() => {
this.popup.close();
}, this.duration);
},
close() {
clearTimeout(this.popuptimer);
},
},
};
</script>
<style lang="scss" scoped>
.uni-popup-message {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
background-color: #e1f3d8;
padding: 10px 15px;
border-color: #eee;
border-style: solid;
border-width: 1px;
}
.uni-popup-message-text {
font-size: 14px;
padding: 0;
}
.uni-popup__success {
background-color: #e1f3d8;
}
.uni-popup__success-text {
color: #67c23a;
}
.uni-popup__warn {
background-color: #faecd8;
}
.uni-popup__warn-text {
color: #e6a23c;
}
.uni-popup__error {
background-color: #fde2e2;
}
.uni-popup__error-text {
color: #f56c6c;
}
.uni-popup__info {
background-color: #f2f6fc;
}
.uni-popup__info-text {
color: #909399;
}
</style>

171
src/components/uni-popup/uni-popup-share.vue

@ -0,0 +1,171 @@
<template>
<view class="uni-popup-share">
<view class="uni-share-title">
<text class="uni-share-title-text">{{ title }}</text>
</view>
<view class="uni-share-content">
<view class="uni-share-content-box">
<view class="uni-share-content-item" v-for="(item, index) in bottomData" :key="index" @click.stop="select(item, index)">
<image class="uni-share-image" :src="item.icon" mode="aspectFill"></image>
<text class="uni-share-text">{{ item.text }}</text>
</view>
</view>
</view>
<view class="uni-share-button-box">
<button class="uni-share-button" @click="close">取消</button>
</view>
</view>
</template>
<script>
export default {
name: 'UniPopupShare',
props: {
title: {
type: String,
default: '分享到',
},
},
inject: ['popup'],
data() {
return {
bottomData: [
{
text: '微信',
icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-2.png',
name: 'wx',
},
{
text: '支付宝',
icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-8.png',
name: 'wx',
},
{
text: 'QQ',
icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/gird-3.png',
name: 'qq',
},
{
text: '新浪',
icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-1.png',
name: 'sina',
},
{
text: '百度',
icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-7.png',
name: 'copy',
},
{
text: '其他',
icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-5.png',
name: 'more',
},
],
};
},
created() {},
methods: {
/**
* 选择内容
*/
select(item, index) {
this.$emit(
'select',
{
item,
index,
},
() => {
this.popup.close();
},
);
},
/**
* 关闭窗口
*/
close() {
this.popup.close();
},
},
};
</script>
<style lang="scss" scoped>
.uni-popup-share {
background-color: #fff;
}
.uni-share-title {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
justify-content: center;
height: 40px;
}
.uni-share-title-text {
font-size: 14px;
color: #666;
}
.uni-share-content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
padding-top: 10px;
}
.uni-share-content-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
flex-wrap: wrap;
width: 360px;
}
.uni-share-content-item {
width: 90px;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
padding: 10px 0;
align-items: center;
}
.uni-share-content-item:active {
background-color: #f5f5f5;
}
.uni-share-image {
width: 30px;
height: 30px;
}
.uni-share-text {
margin-top: 10px;
font-size: 14px;
color: #3b4144;
}
.uni-share-button-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
padding: 10px 15px;
}
.uni-share-button {
flex: 1;
border-radius: 50px;
color: #666;
font-size: 16px;
}
.uni-share-button::after {
border-radius: 50px;
}
</style>

289
src/components/uni-popup/uni-popup.vue

@ -0,0 +1,289 @@
<template>
<view v-if="showPopup" class="uni-popup" :class="[popupstyle]" @touchmove.stop.prevent="clear">
<uni-transition v-if="maskShow" :mode-class="['fade']" :styles="maskClass" :duration="duration" :show="showTrans" @click="onTap" />
<uni-transition :mode-class="ani" :styles="transClass" :duration="duration" :show="showTrans" @click="onTap">
<view class="uni-popup__wrapper-box" @click.stop="clear">
<slot />
</view>
</uni-transition>
</view>
</template>
<script>
import uniTransition from '../uni-transition/uni-transition.vue';
import popup from './popup.js';
/**
* PopUp 弹出层
* @description 弹出层组件为了解决遮罩弹层的问题
* @tutorial https://ext.dcloud.net.cn/plugin?id=329
* @property {String} type = [top|center|bottom] 弹出方式
* @value top 顶部弹出
* @value center 中间弹出
* @value bottom 底部弹出
* @value message 消息提示
* @value dialog 对话框
* @value share 底部分享示例
* @property {Boolean} animation = [ture|false] 是否开启动画
* @property {Boolean} maskClick = [ture|false] 蒙版点击是否关闭弹窗
* @event {Function} change 打开关闭弹窗触发e={show: false}
*/
export default {
name: 'UniPopup',
components: { uniTransition },
props: {
//
animation: {
type: Boolean,
default: true,
},
// top: bottomcenter
// message: ; dialog :
type: {
type: String,
default: 'center',
},
// maskClick
maskClick: {
type: Boolean,
default: true,
},
},
provide() {
return { popup: this };
},
mixins: [popup],
watch: {
/**
* 监听type类型
*/
type: {
handler: function (newVal) {
this[this.config[newVal]]();
},
immediate: true,
},
/**
* 监听遮罩是否可点击
* @param {Object} val
*/
maskClick(val) {
this.mkclick = val;
},
},
data() {
return {
duration: 300,
ani: [],
showPopup: false,
showTrans: false,
maskClass: {
position: 'fixed',
bottom: 0,
top: 0,
left: 0,
right: 0,
backgroundColor: 'rgba(0, 0, 0, 0.4)',
},
transClass: {
position: 'fixed',
left: 0,
right: 0,
},
maskShow: true,
mkclick: true,
popupstyle: 'top',
};
},
created() {
this.mkclick = this.maskClick;
if (this.animation) {
this.duration = 300;
} else {
this.duration = 0;
}
},
methods: {
clear(e) {
// TODO nvue
e.stopPropagation();
},
open() {
this.showPopup = true;
this.$nextTick(() => {
new Promise(resolve => {
clearTimeout(this.timer);
this.timer = setTimeout(() => {
this.showTrans = true;
// fixed by mehaotian app
this.$nextTick(() => {
resolve();
});
}, 50);
}).then(res => {
console.log('res: ', res);
//
clearTimeout(this.msgtimer);
this.msgtimer = setTimeout(() => {
this.customOpen && this.customOpen();
}, 100);
this.$emit('change', {
show: true,
type: this.type,
});
});
});
},
close(type) {
this.showTrans = false;
this.$nextTick(() => {
this.$emit('change', {
show: false,
type,
});
clearTimeout(this.timer);
//
this.customOpen && this.customClose();
this.timer = setTimeout(() => {
this.showPopup = false;
}, 300);
});
},
onTap() {
if (!this.mkclick) return;
this.close();
},
/**
* 顶部弹出样式处理
*/
top() {
this.popupstyle = 'top';
this.ani = ['slide-top'];
this.transClass = {
position: 'fixed',
left: 0,
right: 0,
};
},
/**
* 底部弹出样式处理
*/
bottom() {
this.popupstyle = 'bottom';
this.ani = ['slide-bottom'];
this.transClass = {
position: 'fixed',
left: 0,
right: 0,
bottom: 0,
};
},
/**
* 中间弹出样式处理
*/
center() {
this.popupstyle = 'center';
this.ani = ['zoom-out', 'fade'];
this.transClass = {
position: 'fixed',
/* #ifndef APP-NVUE */
display: 'flex',
flexDirection: 'column',
/* #endif */
bottom: 0,
left: 0,
right: 0,
top: 0,
justifyContent: 'center',
alignItems: 'center',
};
},
},
};
</script>
<style lang="scss" scoped>
.uni-popup {
position: fixed;
/* #ifndef APP-NVUE */
z-index: 99;
/* #endif */
}
.uni-popup__mask {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: $uni-bg-color-mask;
opacity: 0;
}
.mask-ani {
transition-property: opacity;
transition-duration: 0.2s;
}
.uni-top-mask {
opacity: 1;
}
.uni-bottom-mask {
opacity: 1;
}
.uni-center-mask {
opacity: 1;
}
.uni-popup__wrapper {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
position: absolute;
}
.top {
/* #ifdef H5 */
top: var(--window-top);
/* #endif */
/* #ifndef H5 */
top: 0;
/* #endif */
}
.bottom {
bottom: 0;
}
.uni-popup__wrapper-box {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
position: relative;
/* iphonex 等安全区设置,底部安全区适配 */
/* #ifndef APP-NVUE */
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
/* #endif */
}
.content-ani {
// transition: transform 0.3s;
transition-property: transform, opacity;
transition-duration: 0.2s;
}
.uni-top-content {
transform: translateY(0);
}
.uni-bottom-content {
transform: translateY(0);
}
.uni-center-content {
transform: scale(1);
opacity: 1;
}
</style>

276
src/components/uni-transition/uni-transition.vue

@ -0,0 +1,276 @@
<template>
<view
v-if="isShow"
ref="ani"
class="uni-transition"
:class="[ani.in]"
:style="'transform:' + transform + ';' + stylesObject"
@click="change"
>
<slot></slot>
</view>
</template>
<script>
// #ifdef APP-NVUE
const animation = uni.requireNativePlugin('animation');
// #endif
/**
* Transition 过渡动画
* @description 简单过渡动画组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=985
* @property {Boolean} show = [false|true] 控制组件显示或隐藏
* @property {Array} modeClass = [fade|slide-top|slide-right|slide-bottom|slide-left|zoom-in|zoom-out] 过渡动画类型
* @value fade 渐隐渐出过渡
* @value slide-top 由上至下过渡
* @value slide-right 由右至左过渡
* @value slide-bottom 由下至上过渡
* @value slide-left 由左至右过渡
* @value zoom-in 由小到大过渡
* @value zoom-out 由大到小过渡
* @property {Number} duration 过渡动画持续时间
* @property {Object} styles 组件样式 css 样式注意带-连接符的属性需要使用小驼峰写法如`backgroundColor:red`
*/
export default {
name: 'uniTransition',
props: {
show: {
type: Boolean,
default: false,
},
modeClass: {
type: Array,
default() {
return [];
},
},
duration: {
type: Number,
default: 300,
},
styles: {
type: Object,
default() {
return {};
},
},
},
data() {
return {
isShow: false,
transform: '',
ani: { in: '', active: '' },
};
},
watch: {
show: {
handler(newVal) {
if (newVal) {
this.open();
} else {
this.close();
}
},
immediate: true,
},
},
computed: {
stylesObject() {
let styles = {
...this.styles,
'transition-duration': this.duration / 1000 + 's',
};
let transfrom = '';
for (let i in styles) {
let line = this.toLine(i);
transfrom += line + ':' + styles[i] + ';';
}
return transfrom;
},
},
created() {
// this.timer = null
// this.nextTick = (time = 50) => new Promise(resolve => {
// clearTimeout(this.timer)
// this.timer = setTimeout(resolve, time)
// return this.timer
// });
},
methods: {
change() {
this.$emit('click', { detail: this.isShow });
},
open() {
clearTimeout(this.timer);
this.isShow = true;
this.transform = '';
this.ani.in = '';
for (let i in this.getTranfrom(false)) {
if (i === 'opacity') {
this.ani.in = 'fade-in';
} else {
this.transform += `${this.getTranfrom(false)[i]} `;
}
}
this.$nextTick(() => {
setTimeout(() => {
this._animation(true);
}, 50);
});
},
close() {
clearTimeout(this.timer);
this._animation(false);
},
_animation(type) {
let styles = this.getTranfrom(type);
// #ifdef APP-NVUE
if (!this.$refs['ani']) return;
animation.transition(
this.$refs['ani'].ref,
{
styles,
duration: this.duration, //ms
timingFunction: 'ease',
needLayout: false,
delay: 0, //ms
},
() => {
if (!type) {
this.isShow = false;
}
this.$emit('change', { detail: this.isShow });
},
);
// #endif
// #ifndef APP-NVUE
this.transform = '';
for (let i in styles) {
if (i === 'opacity') {
this.ani.in = `fade-${type ? 'out' : 'in'}`;
} else {
this.transform += `${styles[i]} `;
}
}
this.timer = setTimeout(() => {
if (!type) {
this.isShow = false;
}
this.$emit('change', { detail: this.isShow });
}, this.duration);
// #endif
},
getTranfrom(type) {
let styles = { transform: '' };
this.modeClass.forEach(mode => {
switch (mode) {
case 'fade':
styles.opacity = type ? 1 : 0;
break;
case 'slide-top':
styles.transform += `translateY(${type ? '0' : '-100%'}) `;
break;
case 'slide-right':
styles.transform += `translateX(${type ? '0' : '100%'}) `;
break;
case 'slide-bottom':
styles.transform += `translateY(${type ? '0' : '100%'}) `;
break;
case 'slide-left':
styles.transform += `translateX(${type ? '0' : '-100%'}) `;
break;
case 'zoom-in':
styles.transform += `scale(${type ? 1 : 0.8}) `;
break;
case 'zoom-out':
styles.transform += `scale(${type ? 1 : 1.2}) `;
break;
}
});
return styles;
},
_modeClassArr(type) {
let mode = this.modeClass;
if (typeof mode !== 'string') {
let modestr = '';
mode.forEach(item => {
modestr += item + '-' + type + ',';
});
return modestr.substr(0, modestr.length - 1);
} else {
return mode + '-' + type;
}
},
// getEl(el) {
// console.log(el || el.ref || null);
// return el || el.ref || null
// },
toLine(name) {
return name.replace(/([A-Z])/g, '-$1').toLowerCase();
},
},
};
</script>
<style>
.uni-transition {
transition-timing-function: ease;
transition-duration: 0.3s;
transition-property: transform, opacity;
}
.fade-in {
opacity: 0;
}
.fade-active {
opacity: 1;
}
.slide-top-in {
/* transition-property: transform, opacity; */
transform: translateY(-100%);
}
.slide-top-active {
transform: translateY(0);
/* opacity: 1; */
}
.slide-right-in {
transform: translateX(100%);
}
.slide-right-active {
transform: translateX(0);
}
.slide-bottom-in {
transform: translateY(100%);
}
.slide-bottom-active {
transform: translateY(0);
}
.slide-left-in {
transform: translateX(-100%);
}
.slide-left-active {
transform: translateX(0);
opacity: 1;
}
.zoom-in-in {
transform: scale(0.8);
}
.zoom-out-active {
transform: scale(1);
}
.zoom-out-in {
transform: scale(1.2);
}
</style>

1
src/config/app.js

@ -1,3 +1,4 @@
// TODO: 环境变量设置
const version = '3.0.0';
export default {

2
src/config/task.js

@ -0,0 +1,2 @@
// 每页加载颗粒度的个数
export default { pageCount: 10 };

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,25 @@
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 plugin from '@/apis/plugin.js';
import project from '@/apis/project.js';
import request from '@/utils/request.js';
import role from '@/apis/role.js';
import store from './store';
import tall from '@/apis/tall.js';
import task from '@/apis/task.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,22 +27,14 @@ 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);

76
src/manifest.json

@ -1,83 +1,13 @@
{
"name": "",
"appid": "",
"name": "TALL",
"appid": "wx356e01c7eb01d55d",
"description": "",
"versionName": "1.0.0",
"versionCode": "100",
"transformPx": false,
"app-plus": {
/* 5+App */ "usingComponents": true,
"splashscreen": {
"alwaysShowBeforeRender": true,
"waiting": true,
"autoclose": true,
"delay": 0
},
"modules": {
/* */
},
"distribute": {
/* */
"android": {
/* android */
"permissions": [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
"ios": {
/* ios */
},
"sdkConfigs": {
/* SDK */
}
}
},
"quickapp": {
/* */
},
"mp-weixin": {
/* */ "appid": "",
"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-project/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;

37
src/package.json

@ -0,0 +1,37 @@
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationStyle": "custom" ,
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/project/project",
"style": {
"navigationStyle": "custom" ,
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/test/test",
"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"
}
}
}

9
src/pages.json

@ -1,16 +1,9 @@
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationStyle": "custom" ,
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/project/project",
"style": {
"navigationStyle": "custom" ,
"navigationStyle": "custom",
"navigationBarTextStyle": "white"
}
}

128
src/pages/index/index.vue

@ -1,128 +0,0 @@
<template>
<view class="flex flex-col h-full bg-gray-50" @touchmove="onMove">
<view class="relative">
<!-- 日历 -->
<Calendar @selected-change="onDateChange" :show-back="true" ref="calendar" @handleFindPoint="handleFindPoint" />
<!-- 上传 导入wbs -->
<Upload @success="onUploadSuccess" @error="onUploadError" />
</view>
<!-- 项目列表 -->
<Projects class="flex-1 overflow-y-auto" />
<!-- 全局提示框 -->
<u-top-tips ref="uTips"></u-top-tips>
</view>
</template>
<script>
import { mapState, mapMutations } from 'vuex';
let prevY = 0;
export default {
data() {
return {
calendar: null,
days: [],
};
},
computed: mapState('user', ['token']),
watch: {
token(value) {
if (!value) return;
this.getProjects();
this.handleFindPoint();
},
},
onShow() {
if (!this.token) return;
this.getProjects();
this.handleFindPoint();
},
onReady() {
this.calendar = this.$refs.calendar;
},
methods: {
...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);
}
},
/**
* 查询小红点
* @param { string } endTime 结束时间
* @param { string } startTime 开始时间
*/
async handleFindPoint(start, end) {
try {
const startTime = start || this.$moment().startOf('month').valueOf();
const endTime = end || this.$moment().endOf('month').valueOf();
const data = await this.$u.api.findRedPoint(startTime, endTime);
this.setDotList(data);
} catch (error) {
console.log('error: ', error);
}
},
//
onDateChange(event) {
const day = this.$moment(event.fullDate);
const start = day.startOf('date').valueOf();
const end = day.endOf('date').valueOf();
this.getProjects(start, end);
},
// /
onMove(event) {
const y = event.changedTouches[0].pageY;
if (y - prevY > 0) {
// weekMode=true weekMode=false
this.calendar.weekMode && (this.calendar.weekMode = false);
} else if (y - prevY < 0) {
// weekMode=false weekMode=true
!this.calendar.weekMode && (this.calendar.weekMode = true);
}
prevY = y;
this.calendar.initDate();
},
//
onUploadSuccess() {
this.$refs.uTips.show({
title: '导入成功,即将打开新项目',
type: 'success',
duration: '3000',
});
},
//
onUploadError(error) {
this.$refs.uTips.show({
title: error || '导入失败',
type: 'error',
duration: '6000',
});
},
},
};
</script>
<style lang="scss" scoped>
page {
height: 100%;
overflow: hidden;
}
</style>

388
src/pages/project/project.vue

@ -3,7 +3,7 @@
<!-- 标题栏 -->
<Title />
<view class="container flex flex-col flex-1 overflow-hidden bg-gray-100" style="margin: auto">
<view class="container flex flex-col flex-1 mx-auto overflow-hidden bg-gray-100">
<!-- 角色栏 -->
<Roles />
@ -11,26 +11,28 @@
<Globals />
<!-- 定期任务面板 -->
<TimeLine @getTasks="getTasks" class="flex-1 overflow-hidden" ref="child" />
<TimeLine @getTasks="getTasks" class="flex-1 overflow-hidden" ref="timeLine" />
</view>
</view>
</template>
<script>
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex';
import mixin from '@/mixins/timeline';
import { setPlaceholderTasks, computeFillPlaceholderTaskCount } from '@/utils/task';
import { flatten } from 'lodash';
export default {
mixins: [mixin],
data() {
return { height: '' };
return { height: '', show: false };
},
computed: {
...mapState('user', ['user', 'token']),
...mapState('role', ['visibleRoles', 'roleId']),
...mapState('task', ['timeNode', 'timeUnit', 'tasks']),
...mapState('task', ['timeNode', 'timeUnit', 'tasks', 'regularTask']),
...mapState('project', ['project']),
...mapGetters('task', ['timeGranularity']),
...mapGetters('project', ['projectId']),
},
onLoad(options) {
@ -43,10 +45,11 @@ export default {
* 重新根据时间和角色查询普通日常任务
* 永久日常任务不发生改变
*/
async timeNode(val) {
timeNode(val) {
if (val && this.roleId) {
//
await this.initTasks();
this.clearTasksData();
this.getGlobalData(); //
this.initPlanTasks(); //
}
},
@ -60,25 +63,26 @@ export default {
if (val) {
this.setTimeNode(Date.now());
//
this.getPermanent(val);
const params = { roleId: val, projectId: this.projectId };
this.getPermanent(params);
}
},
},
mounted() {
this.height = window.screen.height + 'px';
const system = uni.getSystemInfoSync();
this.height = system.windowHeight + 'px';
},
onUnload() {
this.clearEndFlag();
this.clearTasks();
this.clearTasksData();
this.setRoleId('');
},
methods: {
...mapActions('user', ['getToken']),
...mapActions('project', ['getProjectById']),
...mapActions('role', ['getRoles']),
...mapActions('task', ['getRegulars', 'getPermanent', 'getGlobal']),
...mapActions('role', ['getAllMembers']),
...mapMutations('user', ['setToken']),
...mapMutations('project', ['setProject', 'setProjectName']),
...mapMutations('role', ['setInvisibleRoles', 'setVisibleRoles', 'setRoleId']),
@ -95,107 +99,45 @@ export default {
'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);
}
}
//
async initPlanTasks() {
this.setPrevPlaceholderTasks(); //
this.setNextPlaceholderTasks(); //
this.$nextTick(() => this.$refs.timeLine.setScrollPosition()); //
//
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();
}
});
await this.getInitTasks(); //
this.$nextTick(() => this.$refs.timeLine.setScrollPosition()); //
},
// ||
async getInitTasks() {
//
await this.getTasks({ queryType: 0 });
await this.getTasks({ queryType: 1 });
getInitTasks() {
//
const detailId = this.tasks.findIndex(task => task.detailId);
function preloadFn(that) {
const detailId = that.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 }); //
// 1
const { pageCount } = that.$t.task;
that.$nextTick(() => {
//
const { tasks, timeGranularity } = that;
that.getTasks({ timeNode: +tasks[0].planStart, queryType: 0, queryNum: pageCount });
//
const nextQueryTime = +that.$t.time.add(+tasks[tasks.length - 1].planStart, 1, timeGranularity);
that.getTasks({ timeNode: nextQueryTime, queryType: 1, queryNum: pageCount });
});
} else {
//
//
this.setPrevTasks();
//
this.setNextTasks();
// that.setPrevPlaceholderTasks();
// //
// that.setNextPlaceholderTasks();
}
},
}
//
this.getTasks({ queryType: 0 }); //
//
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', '');
// id
this.getTasks({ queryType: 1 }, preloadFn); //
},
/**
@ -205,107 +147,209 @@ export default {
* @param {string} query.timeNode 时间基准点 默认当前
* @param {string} query.timeUnit 时间颗粒度 默认天
* @param {string} query.queryNum 查找颗粒度数量 默认3个
* @param {string} query.queryType 0向上查找 1向下查找(默认) 下查包含自己上查不包含
* @param {number} query.queryType 0向上查找 1向下查找(默认) 下查包含自己上查不包含
*/
async getTasks(query) {
try {
getTasks(query, fn) {
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);
const params = this.generateGetTaskParam(query);
this.$t.$q.getRegularTask(params, (err, data) => {
this.setShowSkeleton(false);
// 0 -> 1 ->
if (res && res.length) {
this.replacePrevData(res, params.queryType);
if (err) {
// TODO:
console.error('err: ', err);
} else {
params.queryType === 0 ? this.setPrevTasks() : this.setNextTasks();
//
//
if (data && data.length) {
this.replacePrevData(data, params.queryType);
}
} catch (error) {
this.setShowSkeleton(false);
console.error('error: ', error);
// else {
// TODO: 0 -> 1 ->
// params.queryType === 0 ? this.setPrevPlaceholderTasks() : this.setNextPlaceholderTasks();
// }
if (this.tasks.length && fn) {
fn(this);
}
}
});
},
//
getGlobalData() {
const { roleId, timeNode, timeUnit } = this;
const param = { roleId, timeNode, timeUnit };
this.getGlobal(param);
/**
* 生成getTasks所用的参数
* @param {object} query getTasks传递的参数
*/
generateGetTaskParam(query) {
const { roleId, timeNode, timeUnit, projectId } = this;
return {
roleId,
timeNode: query.timeNode || timeNode,
timeUnit: query.timeUnit || timeUnit,
queryNum: query.queryNum || 3,
queryType: query.queryType,
projectId,
};
},
//
setPrevTasks() {
setPrevPlaceholderTasks() {
this.setTopEnd(true);
let sTime = '';
if (!this.tasks || !this.tasks.length) {
sTime = +new Date().getTime();
let startTime = '';
const { tasks } = this;
if (!tasks || !tasks.length) {
startTime = Date.now(); //
} else {
sTime = +this.tasks[0].planStart - 0;
startTime = tasks[0].planStart - 0; //
}
const initData = this.setTime(sTime, true);
this.setUpTasks(initData);
const placeholderTasks = setPlaceholderTasks(startTime, true, this.timeGranularity);
this.setUpTasks(placeholderTasks);
},
//
setNextTasks() {
setNextPlaceholderTasks() {
this.setBottomEnd(true);
let sTime = '';
let startTime = '';
if (!this.tasks || !this.tasks.length) {
sTime = +new Date().getTime();
startTime = Date.now();
} else {
sTime = +this.tasks[this.tasks.length - 1].planStart - 0;
startTime = +this.tasks[this.tasks.length - 1].planStart;
}
const initData = this.setTime(sTime, false);
const initData = setPlaceholderTasks(startTime, false, this.timeGranularity);
this.setDownTasks(initData);
},
//
/**
* 用拿到的新数据 替换 时间刻度/旧数据
* 先对比 新旧数据的 始末时间 补齐刻度
* 再遍历对比 用任务替换刻度
* @param {array} data 服务端返回的新数据 上边已经处理过空值
* @param {number} type 0 -> 向上 1->向下
*/
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);
const { timeGranularity } = this;
let oldTasks = this.fillPlaceholderTask({ tasks: this.tasks, data, timeGranularity }); //
//
// TODO: tasks
oldTasks.forEach((taskItem, index) => {
const arr = data.filter(dataItem => this.$moment(+dataItem.planStart).isSame(+taskItem.planStart, timeGranularity));
if (arr && arr.length) {
oldTasks.splice(index, 1, [...arr]); // array, [{},{},[],[],{}]
}
if (arr.length > 1) {
newTasks.splice(i, 0, item);
});
oldTasks = flatten(oldTasks); // 1
this.clearTasks(); // setUpTasks setUpTasks
type === 0 ? this.setUpTasks(oldTasks) : this.setUpTasks(oldTasks);
},
/**
* 超出旧数据上下限 补齐时间刻度到新数据的起始时间颗粒度
*/
fillPlaceholderTask({ tasks, data, timeGranularity }) {
const { prev, next } = computeFillPlaceholderTaskCount({ tasks, data, timeGranularity });
if (prev) {
const newTasks = setPlaceholderTasks(+tasks[0].planStart, true, timeGranularity, prev);
this.setUpTasks(newTasks);
}
if (next) {
const newTasks = setPlaceholderTasks(+tasks[tasks.length - 1].planStart, false, timeGranularity, next);
this.setDownTasks(newTasks);
}
i++;
return this.tasks;
},
/**
* 初始化
* @param {object | null} options
*/
init(options) {
if (!this.token) {
// tokenuserIdtoken
// token userId
if (!options || !options.u) {
this.$t.ui.showToast('缺少用户信息参数'); // u (userId)
} else {
this.getToken(options.u);
}
}
//
options && options.pname && this.setProjectName(options.pname);
if (!options || !options.p) {
this.$t.ui.showToast('缺少项目信息参数'); // id
} else {
this.getProjectById({ projectId: options.p }); // id
}
},
/**
* 通过项目id获取项目信息
* @param {object} params 提交的参数
*/
async getProjectById(params) {
try {
const data = await uni.$u.api.findProjectById(params);
this.setProject(data);
// id
this.getRoles(params);
// id
this.getAllMembers(params);
} catch (error) {
console.log('error: ', error || '获取项目信息失败');
}
},
/**
* 通过项目id获取角色信息
* @param {string} projectId
* @param {object} params 提交的参数
*/
getRoles(params) {
this.$t.$q.findShowRole(params, (err, data) => {
if (err) {
console.error('err: ', err || '获取角色信息失败');
} else {
this.setInvisibleRoles(data ? data.invisibleList : []);
this.setVisibleRoles(data ? data.visibleList : []);
this.setInitialRoleId(data ? data.visibleList : []);
}
});
},
//
setInitialRoleId(visibleList) {
if (!visibleList || !visibleList.length) return;
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', '');
},
//
getGlobalData() {
const { roleId, timeNode, timeUnit, projectId } = this;
const param = { roleId, timeNode, timeUnit, projectId };
this.getGlobal(param);
},
//
clearTasksData() {
//
this.setPermanents([]);
this.setDailyTasks([]);
//
this.clearTasks();
type === 0 ? this.setUpTasks(newTasks) : this.setDownTasks(newTasks);
//
//
this.clearEndFlag();
},
},
};

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>

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

@ -1,7 +1,64 @@
<template>
<view>交付物检查</view>
<!-- 上传交付物 -->
<view class="px-3 py-6 bg-white">
<u-input :auto-height="autoHeight" :border="border" :height="height" :type="type" placeholder="输入备注" v-model="remark" />
<view class="flex flex-row-reverse text-xs text-gray-400 mt-2">{{ wordNum }}/140</view>
<!-- 评分 -->
<view class="flex justify-between mt-3">
<slider :value="score" @change="sliderChange" max="100" min="0" show-value style="width: 60%" />
<u-input :border="border" :type="type1" @input="changeNumber" maxlength="100" placeholder="输入分数" v-model="score" />
</view>
<view class="flex flex-col justify-center mt-5">
<u-button @click="submit" size="medium" type="primary">提交</u-button>
<u-button @click="$emit('closeScore')" class="mt-2" size="medium">取消</u-button>
</view>
</view>
</template>
<script>
export default {};
export default {
name: 'p-deliver-check',
data() {
return {
remark: '',
type: 'textarea',
border: true,
height: 100,
autoHeight: true,
wordNum: 0,
score: 0,
type1: 'number',
};
},
watch: {
remark(val) {
this.wordNum = val.length;
},
score(val) {
this.score1 = val;
},
},
methods: {
//
submit() {
this.$emit('submit', this.remark, this.score);
},
sliderChange(e) {
this.score = e.detail.value;
},
changeNumber(e) {
if (e > 100) {
this.score = 100;
}
},
},
};
</script>
<style></style>

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>

140
src/plugins/p-delivery-history/p-delivery-history.vue

@ -0,0 +1,140 @@
<template>
<!-- 交付物 -->
<view class="mt-3">
<view v-if="lists && lists.length">
<view :key="list.id" v-for="list in lists">
<view class="p-3 mt-3 shadow">
<view class="text-gray-400 pb-2">
<span class="mr-4">{{ list.name }}</span>
<span>{{ $moment(+list.time).format('YYYY-MM-DD HH:mm:ss') }}</span>
</view>
<view class="pb-2 flex flex-wrap overflow-hidden" v-if="list.content">
<a :href="list.content" class="text-blue-500" target="_blank" v-if="CheckUrl(list.content)">{{ list.content }}</a>
<span v-else>{{ list.content }}</span>
</view>
<view :key="checker.checkerId" v-for="checker in list.checkerList">
<view class="flex justify-between">
<view class="font-bold">
{{ checker.checkerName }}
<span v-if="checker.isMine">()</span>
</view>
<view>
<span class="text-blue-500" v-if="checker.status === 1">通过</span>
<span class="text-red-500" v-if="checker.status === 2">驳回</span>
<span class="ml-4" v-if="checker.status !== 0">{{ checker.score }}</span>
<span class="text-gray-400" v-if="checker.status === 0 && !checker.isMine">未审核</span>
<view v-if="checker.status === 0 && checker.isMine">
<u-button @click="showScore(checker.checkId, 2)" class="mr-3" plain size="mini" type="error">驳回</u-button>
<u-button @click="showScore(checker.checkId, 1)" plain size="mini" type="primary">通过</u-button>
</view>
</view>
</view>
<view class="text-gray-400 text-xs mt-1">{{ checker.remark }}</view>
</view>
</view>
</view>
</view>
<u-empty icon-size="90" mode="history" text="暂未上传交付物" v-else></u-empty>
<!-- 评分 -->
<uni-popup :maskClick="false" background-color="#fff" ref="popup" type="bottom">
<PDeliverCheck @closeScore="closeScore" @submit="submit"></PDeliverCheck>
</uni-popup>
</view>
</template>
<script>
import { mapGetters } from 'vuex';
import UniPopup from '../../components/uni-popup/uni-popup.vue';
import PDeliverCheck from '../p-deliver-check/p-deliver-check.vue';
export default {
name: 'p-delivery-history',
props: { task: { type: Object, default: null } },
components: { PDeliverCheck, UniPopup },
data() {
return {
lists: [],
show: false,
options: null,
loading: true, //
};
},
computed: mapGetters('project', ['projectId']),
mounted() {
this.getDeliverOfTask();
},
methods: {
async getDeliverOfTask() {
try {
const { projectId, task } = this;
const params = { projectId, taskSubId: task.id };
const data = await this.$u.api.queryDeliverOfTask(params);
this.lists = data;
} catch (error) {
console.error('p-delivery-history.vue getDeliverOfTask error: ', error);
this.$t.ui.showToast(error.msg || '提交失败');
}
},
showScore(checkId, status) {
// refuni-popup , type ['top','left','bottom','right','center']
this.$refs.popup.open('bottom');
this.options = { checkId, status };
},
closeScore() {
this.$refs.popup.close('bottom');
},
async submit(remark, score) {
try {
await this.checkDeliver(remark, score);
this.closeScore();
} catch (error) {
console.error('error: ', error);
}
},
/**
* 检查交付物
* @param {string} checkId 检查记录id
* @param {string} projectId 项目id
* @param {string} remark 评论
* @param {number} score 分数
* @param {number} status 检查状态(1-通过,2-驳回)
*/
async checkDeliver(remark, score) {
try {
this.show = true;
const { projectId, options } = this;
const { checkId, status } = options;
const params = { checkId, projectId, status, remark, score };
await this.$u.api.checkDeliver(params);
this.$t.ui.showToast('交付物检查成功');
this.options = null;
this.getDeliverOfTask();
} catch (error) {
console.error('p-delivery-history.vue checkDeliver error: ', error);
this.$t.ui.showToast('交付物检查失败,请稍后重试');
this.options = null;
}
},
//
CheckUrl(url) {
var reg = /^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)(.)+$/;
if (!reg.test(url)) {
return false;
} else {
return true;
}
},
},
};
</script>
<style></style>

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

@ -2,12 +2,12 @@
<view v-if="realDuration && planDuration">
<!-- 任务时长延迟插件 -->
<!-- 超时 -->
<span class="font-bold text-green-500" v-if="+realDuration > +planDuration">
+{{ $t.time.formatDuration(+realDuration - +planDuration) }}
<span class="font-bold text-green-500" v-if="realDuration - 0 > planDuration - 0">
+{{ $t.time.formatDuration(realDuration - planDuration) }}
</span>
<!-- 延时 -->
<span class="font-bold text-red-500" v-if="+realDuration < +planDuration">
-{{ $t.time.formatDuration(+planDuration - +realDuration) }}
<span class="font-bold text-red-500" v-if="realDuration - 0 < planDuration - 0">
-{{ $t.time.formatDuration(planDuration - realDuration) }}
</span>
</view>
</template>

104
src/plugins/p-upload-deliverable/p-upload-deliverable.vue

@ -0,0 +1,104 @@
<template>
<!-- 上传交付物 -->
<view class="py-2">
<u-input :auto-height="autoHeight" :border="border" :height="height" :type="type" v-model="content" width="100" />
<view class="flex flex-row-reverse text-xs text-gray-400 mt-2">{{ wordNum }}/140</view>
<ld-select
:list="checkers"
:multiple="true"
@change="selectChange2"
class="my-3"
clearable
label-key="label"
placeholder="选择检查人"
v-model="checkerList"
value-key="value"
></ld-select>
<view class="flex justify-between">
<u-button @click="submit" class="m-0" size="mini" type="primary">提交</u-button>
<u-icon @click="changeShowHistory" name="arrow-up" v-if="showHistory"></u-icon>
<u-icon @click="changeShowHistory" name="arrow-down" v-else></u-icon>
</view>
<p-delivery-history :task="task" v-if="showHistory" />
</view>
</template>
<script>
import ldSelect from '@/components/ld-select/ld-select.vue';
import { mapState, mapGetters } from 'vuex';
export default {
name: 'p-upload-deliverable',
components: { ldSelect },
props: { task: { type: Object, default: null } },
data() {
return {
content: '',
type: 'textarea',
border: true,
height: 30,
autoHeight: true,
wordNum: 0,
checkerList: [],
showHistory: false, //
};
},
computed: {
...mapState('role', ['members']),
...mapGetters('project', ['projectId']),
checkers() {
const arr = [];
if (this.members.length) {
this.members.forEach(member => {
const item = { value: member.memberId, label: member.name };
arr.push(item);
});
}
return arr;
},
},
watch: {
content(val) {
this.wordNum = val.length;
},
},
methods: {
selectChange2(val) {
this.checkerList = val;
},
//
changeShowHistory() {
this.showHistory = !this.showHistory;
},
//
async submit() {
try {
const { content, checkerList, projectId, task } = this;
if (!this.checkerList.length) {
this.$t.ui.showToast('请选择检查人');
return;
}
const params = { content, checkerList, projectId, taskSubId: task.id };
await this.$u.api.saveDeliver(params);
this.$t.ui.showToast('交付物提交成功');
this.content = '';
this.checkerList = [];
} catch (error) {
console.error('p-upload-deliverable.vue submit error: ', error);
this.$t.ui.showToast('交付物提交失败,请稍后重试');
}
},
},
};
</script>
<style></style>

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

@ -1,7 +1,7 @@
<template>
<view>
<view @tap="handleUpload" v-if="task.name === '导入WBS新建项目'">{{ task.name }}</view>
<view @tap="handleUpdate" v-if="task.name === '导入WBS更新项目'">{{ task.name }}</view>
<view @click="handleUpload" v-if="task.name === '导入WBS新建项目'">{{ task.name }}</view>
<view @click="handleUpdate" v-if="task.name === '导入WBS更新项目'">{{ task.name }}</view>
<!-- 全局提示框 -->
<u-top-tips ref="uTips"></u-top-tips>
</view>

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

28
src/store/index.js

@ -1,6 +1,5 @@
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';
@ -8,5 +7,30 @@ import project from './project/index';
import role from './role/index';
import task from './task/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, role, task } });

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;

16
src/store/role/actions.js

@ -1,17 +1,15 @@
const actions = {
/**
* 通过项目id获取角色信息
* @param {any} commit
* @param {object} params 提交的参数
* 根据项目id查找所有成员信息
* @param {*} commit
* @param {object} params
*/
async getRoles({ commit }, params) {
async getAllMembers({ commit }, params) {
try {
const res = await uni.$u.api.findShowRole(params);
commit('setInvisibleRoles', res.invisibleList);
commit('setVisibleRoles', res.visibleList);
return res;
const data = await uni.$u.api.queryChecker(params);
commit('setMembers', data);
} catch (error) {
throw error || '获取角色信息失败';
uni.$t.ui.showToast(error.msg || '成员查询失败');
}
},
};

12
src/store/role/getters.js

@ -1,3 +1,13 @@
const getters = {};
const getters = {
// 是不是负责人
isMine({ roleId, invisibleRoles, visibleRoles }) {
if (!visibleRoles || !visibleRoles.length) return false;
const visible = visibleRoles.find(visible => visible.id === roleId);
if (visible) return visible.mine;
const invisible = invisibleRoles.find(invisible => invisible.id === roleId);
if (invisible) return visible.mine;
return false;
},
};
export default getters;

9
src/store/role/mutations.js

@ -25,6 +25,15 @@ const mutations = {
setRoleId(state, roleId) {
state.roleId = roleId;
},
/**
* 设置项目下所有成员信息
* @param {Object} state
* @param {Array} data 服务端返回的模板数组
*/
setMembers(state, data) {
state.members = data || [];
},
};
export default mutations;

1
src/store/role/state.js

@ -2,6 +2,7 @@ const state = {
invisibleRoles: [], // 不展示的角色信息
visibleRoles: [], // 展示的角色信息
roleId: '', // 当前展示查看的角色id
members: [], // 项目下所有成员
};
export default state;

36
src/store/task/actions.js

@ -4,13 +4,14 @@ const actions = {
* @param {*} commit
* @param {string} roleId 角色id
*/
async getPermanent({ commit }, roleId) {
try {
const data = await uni.$u.api.getPermanent({ roleId });
getPermanent({ commit }, param) {
uni.$t.$q.getPermanent(param, (err, data) => {
if (err) {
console.error('err: ', err);
} else {
commit('setPermanents', data);
} catch (error) {
console.log('task actions getPermanent error: ', error);
}
});
},
/**
@ -18,27 +19,14 @@ const actions = {
* @param {*} commit
* @param {object} param 请求参数 roleId, timeNode, timeUnit
*/
async getGlobal({ commit }, param) {
try {
const data = await uni.$u.api.getGlobal(param);
getGlobal({ commit }, param) {
uni.$t.$q.getGlobal(param, (err, data) => {
if (err) {
console.error('err: ', err);
} else {
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 || '获取定期任务失败';
}
});
},
};

14
src/store/task/mutations.js

@ -11,10 +11,10 @@ const mutations = {
/**
* 记录时间轴向上滚动的距离
* @param { object } state
* @param { string } data
* @param {string} taskId
*/
setViewId(state, data) {
state.viewId = data;
setScrollToTaskId(state, taskId) {
state.scrollToTaskId = taskId;
},
/**
@ -79,9 +79,10 @@ const mutations = {
*/
setUpTasks(state, data) {
if (!state.tasks.length) {
state.tasks = [...data];
state.tasks = [...data]; // 原来没有数据
} else {
state.tasks = [...data.concat(state.tasks)];
state.tasks = [...data, ...state.tasks];
// state.tasks = [...data.concat(state.tasks)];
}
},
@ -94,7 +95,8 @@ const mutations = {
if (!state.tasks && !state.tasks.length) {
state.tasks = [...data];
} else {
state.tasks = [...state.tasks.concat(data)];
state.tasks = [...state.tasks, ...data];
// state.tasks = [...state.tasks.concat(data)];
}
},

12
src/store/task/state.js

@ -1,6 +1,6 @@
const state = {
scrollTop: 0,
viewId: '', // 时间轴自动滚动的位置
scrollToTaskId: '', // 时间轴自动滚动的位置
isShrink: false, // true: 收起, false:展开
tip: {
taskId: '', // 当前正在修改状态的任务的id
@ -10,21 +10,13 @@ const state = {
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: [],
tasks: [], // 所有的定期任务
showSkeleton: false, // 定期任务骨架屏
};

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));
},
};

24
src/test/util/task.test.js

@ -0,0 +1,24 @@
import { computeFillPlaceholderTaskCount } from '../../utils/task';
describe('computeFillPlaceholderTaskCount', () => {
// 2021/8/17 ~ 2021/8/21
const tasks = [
{ id: '99724910037144221455', panel: {}, plugins: [], process: 4, planStart: 1629169800242 },
{ id: '65053357415671253512', panel: {}, plugins: [], process: 4, planStart: 1629256200242 },
{ id: '38735454515347179194', panel: {}, plugins: [], process: 4, planStart: 1629342600242 },
{ id: '49602681534756706607', panel: {}, plugins: [], process: 4, planStart: 1629429000242 },
{ id: '98860265376222512018', panel: {}, plugins: [], process: 4, planStart: 1629515400242 },
{ id: '44419041575700334936', panel: {}, plugins: [], process: 4, planStart: 1629601800242 },
];
const timeGranularity = 'day';
it('超出上限 补齐', () => {
const data = [{ planStart: `${new Date('2021/8/10').getTime()}` }, { planStart: `${new Date('2021/8/11').getTime()}` }];
expect(computeFillPlaceholderTaskCount({ tasks, data, timeGranularity }).prev.toString()).toMatch(/(7|8)/);
});
it('超出下限 补齐', () => {
const data = [{ planStart: `${new Date('2021/8/10').getTime()}` }, { planStart: `${new Date('2021/8/22').getTime()}` }];
expect(computeFillPlaceholderTaskCount({ tasks, data, timeGranularity }).next.toString()).toMatch(/(1|2)/);
});
});

344
src/utils/cache.js

@ -0,0 +1,344 @@
export const filter = {
/**
* 角色 过滤获取到的数据 根据开始截止时间
* @param {object} data 缓存拿到的数据
* @returns
*/
roles(data) {
if (!data || !data.length) return [];
return data;
},
/**
* 定期任务 过滤获取到的数据 根据开始截止时间
* @param {object} data 缓存拿到的数据
* @param {number} timeNode 时间基准点 ms
* @param {number} queryNum 颗粒度数量
* @param {number} timeUnit 时间颗粒度
* @param {number} queryType 0向上查找 1向下查找(默认) 下查包含自己上查不包含
* @returns
*/
planTask(data, timeNode, queryNum, timeUnit, queryType) {
if (!data || !data.length) return [];
if (queryType === 0) {
// 计算颗粒度 对应的 dayjs add 的单位
let target = uni.$t.timeConfig.timeUnits.find(item => item.id === timeUnit);
// TODO: 缺少通过时间颗粒度筛选数据 任务没有返回时间颗粒度标签
let start = uni.$t.time.add(+timeNode, -queryNum, target.granularity).valueOf();
let arr = [];
arr = data.filter(item => start <= +item.planStart && +timeNode > +item.planEnd);
if (!arr || !arr.length) {
// 开始时间往前推
let resultS = [];
let againStart = uni.$t.time.add(start, -1, target.granularity).valueOf();
let againArr = data.filter(item => againStart >= +item.planStart);
if (againArr && againArr.length) {
let sTime = uni.$t.time.setTimestampToStr(+againArr[0].planStart);
data.forEach(item => {
if (uni.$t.time.isSame(uni.$moment(sTime.date).valueOf(), +item.planStart, target.granularity)) {
resultS.push(item);
}
});
}
return resultS;
} else {
return arr;
}
} else {
// 计算颗粒度 对应的 dayjs add 的单位
let target = uni.$t.timeConfig.timeUnits.find(item => item.id === timeUnit);
// TODO: 缺少通过时间颗粒度筛选数据 任务没有返回时间颗粒度标签
let end = uni.$t.time.add(timeNode, +queryNum - 1, target.granularity).valueOf();
let arr = [];
arr = data.filter(item => end >= +item.planEnd && +timeNode <= +item.planStart);
if (!arr || !arr.length) {
// 结束时间往后推
let resultE = [];
let againEnd = uni.$t.time.add(end, 1, target.granularity).valueOf();
let againEndArr = data.filter(item => againEnd <= +item.planStart);
if (againEndArr) {
let eTime = uni.$t.time.setTimestampToStr(+againEndArr[againEndArr.length - 1].planStart);
data.forEach(item => {
if (uni.$t.time.isSame(uni.$moment(eTime.date).valueOf(), +item.planEnd, target.granularity)) {
resultE.push(item);
}
});
}
return resultE;
} else {
return arr;
}
}
},
/**
* 永久日常任务 过滤获取到的数据 根据开始截止时间
* @param {object} data 缓存拿到的数据
* @returns
*/
fixedTasks(data) {
if (!data || !data.length) return [];
return data;
},
/**
* 日常任务 过滤获取到的数据 根据开始截止时间
* @param {object} data 缓存拿到的数据
* @param {number} timeNode 时间基准点 ms
* @returns
*/
dailyTask(data, timeNode) {
if (!data || !data.length) return [];
// TODO: 缺少通过时间颗粒度筛选数据 任务没有返回时间颗粒度标签
return data.filter(item => timeNode <= +item.endTime && timeNode >= +item.startTime);
},
/**
* 插件 过滤获取到的数据 根据插件id
* @param {object} data 缓存拿到的数据
* @returns
*/
plugin(data) {
if (!data || !data.id) return null;
return data;
},
};
export default {
/**
* 当前显示的角色信息 获取
* @param {object} params
* @returns
*/
async getShowRole(projectId) {
try {
const data = await uni.$t.storage.getStorage(`roles_${projectId}`);
return filter.roles(JSON.parse(data));
} catch (error) {
return null;
}
},
/**
* 当前显示的角色信息
* @param {array} data
*/
putShowRole(projectId, data) {
try {
if (!data || !data.visibleList || !data.visibleList.length) return; // 服务端没数据不做操作
let value = uni.$t.storage.getStorageSync(`roles_${projectId}`);
let locals = value ? JSON.parse(value) : null;
if (!locals || !locals.length) {
// 本地没数据
locals = data || null;
} else {
// 本地有数据
data.invisibleList.forEach(item => {
let invisibleListLocalData = locals.invisibleList.find(local => item.id === local.id);
if (invisibleListLocalData) {
// 有相同数据 就用新的data里的数据
invisibleListLocalData = item;
} else {
// 没有就直接存本地
locals.invisibleList.push(item);
}
});
data.visibleList.forEach(item => {
let localData = locals.visibleList.find(local => item.id === local.id);
if (localData) {
// 有相同数据 就用新的data里的数据
localData = item;
} else {
// 没有就直接存本地
locals.visibleList.push(item);
}
});
}
uni.$t.storage.setStorage(`roles_${projectId}`, locals);
} catch (error) {
console.error('error: ', error);
uni.$t.storage.setStorage(`roles_${projectId}`, []);
}
},
/**
* 定期任务 获取
* @param {number} startTime
* @param {number} endTime
* @returns
*/
async getStorageRegularTask(params) {
try {
const data = await uni.$t.storage.getStorage(`plan_task_${params.projectId}_${params.roleId}`);
return filter.planTask(JSON.parse(data), params.timeNode, params.queryNum, params.timeUnit, params.queryType);
} catch (error) {
return [];
}
},
/**
* 定期任务
* @param {array} data
*/
putStorageRegularTask(params, data) {
try {
if (!data || !data.length) return; // 服务端没数据不做操作
let value = uni.$t.storage.getStorageSync(`plan_task_${params.projectId}_${params.roleId}`);
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(`plan_task_${params.projectId}_${params.roleId}`, locals);
} catch (error) {
console.error('error: ', error);
uni.$t.storage.setStorage(`plan_task_${params.projectId}_${params.roleId}`, []);
}
},
/**
* 永久的日常任务 获取
* @param {number} startTime
* @param {number} endTime
* @returns
*/
async getStoragePermanent(params) {
try {
const data = await uni.$t.storage.getStorage(`fixed_tasks_${params.projectId}_${params.roleId}`);
return filter.fixedTasks(JSON.parse(data));
} catch (error) {
return [];
}
},
/**
* 永久的日常任务
* @param {array} data
*/
putStoragePermanent(params, data) {
try {
if (!data || !data.length) return; // 服务端没数据不做操作
let value = uni.$t.storage.getStorageSync(`fixed_tasks_${params.projectId}_${params.roleId}`);
let locals = value ? JSON.parse(value) : [];
if (!locals || !locals.length) {
// 本地没数据
locals = data || [];
} else {
// 本地有数据
data.forEach((item, index) => {
let localData = locals.find(local => item.detailId === local.detailId);
if (localData) {
// 有相同数据 就用新的data里的数据
localData = item;
} else {
locals.splice(index, 1);
// 没有就直接存本地
locals.push(item);
}
});
}
uni.$t.storage.setStorage(`fixed_tasks_${params.projectId}_${params.roleId}`, locals);
} catch (error) {
console.error('error: ', error);
uni.$t.storage.setStorage(`fixed_tasks_${params.projectId}_${params.roleId}`, []);
}
},
/**
* 日常任务 获取
* @param {number} timeNode
* @returns
*/
async getDailyTask(params) {
try {
const data = await uni.$t.storage.getStorage(`variable_tasks_${params.projectId}_${params.roleId}`);
return filter.dailyTask(JSON.parse(data), params.timeNode);
} catch (error) {
return [];
}
},
/**
* 日常任务
* @param {array} data
*/
putDailyTask(params, data) {
try {
if (!data || !data.length) return; // 服务端没数据不做操作
let value = uni.$t.storage.getStorageSync(`variable_tasks_${params.projectId}_${params.roleId}`);
let locals = value ? JSON.parse(value) : [];
if (!locals || !locals.length) {
// 本地没数据
locals = data || [];
} else {
// 本地有数据
data.forEach(item => {
let localData = locals.find(local => item.detailId === local.detailId);
if (localData) {
// 有相同数据 就用新的data里的数据
localData = item;
} else {
// 没有就直接存本地
locals.push(item);
}
});
}
uni.$t.storage.setStorage(`variable_tasks_${params.projectId}_${params.roleId}`, locals);
} catch (error) {
console.error('error: ', error);
uni.$t.storage.setStorage(`variable_tasks_${params.projectId}_${params.roleId}`, []);
}
},
/**
* 插件信息 获取
* @param {string} pluginId
* @returns
*/
async getPlugin(pluginId) {
try {
const data = await uni.$t.storage.getStorage(`plugin_${pluginId}`);
return filter.plugin(JSON.parse(data));
} catch (error) {
return null;
}
},
/**
* 插件信息
* @param {string} pluginId
* @param {object} data
*/
putPlugin(pluginId, data) {
try {
if (!data || !data.id) return; // 服务端没数据不做操作
let value = uni.$t.storage.getStorageSync(`plugin_${pluginId}`);
let locals = value ? JSON.parse(value) : null;
if (!locals || !locals.length) {
// 本地没数据
locals = data || null;
} else {
// 本地有数据
locals = data;
}
uni.$t.storage.setStorage(`plugin_${pluginId}`, locals);
} catch (error) {
console.error('error: ', error);
uni.$t.storage.setStorage(`plugin_${pluginId}`, null);
}
},
};

165
src/utils/cacheAndRequest.js

@ -0,0 +1,165 @@
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 {
/**
* 通过项目id获取角色信息
* @param {object} params 提交的参数
*/
findShowRole(params, fn) {
let remote = false;
if (store.getters.useStorage) {
// 有缓存 且 服务端数据未返回 就先返回缓存
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;
if (store.getters.useStorage) {
// 有缓存 且 服务端数据未返回 就先返回缓存
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;
if (store.getters.useStorage) {
// 有缓存 且 服务端数据未返回 就先返回缓存
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;
if (store.getters.useStorage) {
// 有缓存 且 服务端数据未返回 就先返回缓存
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;
if (store.getters.useStorage) {
// 有缓存 且 服务端数据未返回 就先返回缓存
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));
});
},
};

84
src/utils/indexedDB.js

@ -28,17 +28,15 @@ const createCollection = (Vue, db) => {
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.onsuccess = () => resolve();
request.onerror = event => {
console.log(event);
// FIXME:
reject(event);
const { name, message } = event.target.error;
if (name === 'ConstraintError') {
reject('数据已存在');
} else {
reject(message);
}
};
});
};
@ -53,16 +51,8 @@ const create = (db, collection, data) => {
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);
};
request.onerror = event => reject(event.target.error.message);
request.onsuccess = event => resolve(event.target.result);
});
};
@ -75,19 +65,16 @@ const findOne = (db, collection, key) => {
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);
};
let result = [];
request.onerror = event => reject(event.target.error.message);
request.onsuccess = event => {
const cursor = event.target.result;
if (cursor) {
console.log('indexedDB find success:', cursor);
result.push(cursor.value);
cursor.continue();
// FIXME:
resolve(event.target.result);
} else {
console.log('没有更多数据了');
resolve(result);
}
};
});
@ -103,15 +90,8 @@ const find = (db, collection) => {
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);
};
request.onerror = event => reject(event.target.error.message);
request.onsuccess = () => resolve(newData);
});
};
@ -125,14 +105,8 @@ const update = (db, collection, newData) => {
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);
};
request.onerror = event => reject(event.target.error.message);
request.onsuccess = () => resolve();
});
};
@ -146,11 +120,12 @@ const remove = (db, collection, key) => {
*/
const createIndexAndFind = (db, collection, field, key) => {
return new Promise((resolve, reject) => {
const index = db.transaction([collection], 'readonly').objectStore(collection).index(field);
const store = db.transaction([collection], 'readonly').objectStore(collection);
store.createIndex(field, field);
const index = store.index(field);
const request = index.get(key);
// FIXME:
request.onerror = event => reject(event);
request.onsuccess = event => resolve(event);
request.onerror = event => reject(event.target.error.message);
request.onsuccess = event => resolve(event.target.result);
});
};
@ -162,7 +137,7 @@ export const curriedUpdate = curry(update);
export const curriedIndex = curry(createIndexAndFind);
const install = Vue => {
Vue.prototype.$db = {};
uni.$db = 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);
@ -175,11 +150,14 @@ const install = Vue => {
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);
Vue.prototype.$db.create = curriedCreate(Vue.prototype.$db.db); // create 新增数据,颗粒化以后就不用再传db数据了
Vue.prototype.$db.findOne = curriedFindOne(Vue.prototype.$db.db); // 查一条
Vue.prototype.$db.find = curriedFind(Vue.prototype.$db.db); // 查集合里的所有数据
Vue.prototype.$db.update = curriedUpdate(Vue.prototype.$db.db); // 更新某条数据
Vue.prototype.$db.remove = curriedRemove(Vue.prototype.$db.db); // 删除某条数据
// Vue.prototype.$db.createIndex = curriedIndex(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,11 +1,15 @@
import app from '@/config/app.js';
import timeConfig from '@/config/time';
import zIndex from '@/config/zIndex.js';
import cache from '@/utils/cache.js';
import cacheAndRequest from '@/utils/cacheAndRequest.js';
import plugin from '@/config/plugin.js';
import storage from '@/utils/storage.js';
import time from '@/utils/time.js';
import timeConfig from '@/config/time';
import ui from '@/utils/ui.js';
import upload from '@/utils/upload.js';
import user from '@/config/user.js';
import zIndex from '@/config/zIndex.js';
import task from '@/config/task.js';
const gateway = process.env.VUE_APP_API_URL;
@ -19,6 +23,10 @@ const $t = {
ui, // ui界面提示相关
chooseAndUpload: upload.chooseAndUpload, // 选择并上传单个文件相关的封装
domain: `${gateway}/defaultwbs`,
cache, // 本地存储相关
$q: cacheAndRequest,
user, // 用户相关配置
task, // 任务相关配置
};
uni.$t = $t;

53
src/utils/task.js

@ -0,0 +1,53 @@
import dayjs from 'dayjs';
/**
* 设置时间轴空数据
* @param {number} startTime
* @param {boolean} isUp true 向上加载,false 向下加载
* @param {string} timeGranularity 颗粒度
* @param {number} pageCount 加载的颗粒度数量 默认值是10
*/
export const setPlaceholderTasks = (startTime, isUp, timeGranularity, pageCount) => {
let result = [];
pageCount = pageCount || uni.$t.task.pageCount;
for (let i = 0; i < pageCount; i++) {
const delta = isUp ? `-${i + 1}` - 0 : i + 1;
let item = {
id: uni.$u.guid(20, false, 10),
panel: {},
plugins: [],
process: 4,
planStart: uni.$moment(startTime).add(delta, timeGranularity).valueOf(),
};
// console.log('isup: ', isUp, 'result:', new Date(item.planStart).toLocaleDateString());
isUp ? result.unshift(item) : result.push(item);
}
return result;
};
/**
* 超出旧数据上下限 补齐时间刻度到新数据的起始时间颗粒度
* @param {object} option
* @param {array} option.tasks 旧的已有的任务书籍
* @param {array} option.data 新拿到的任务数据 空值已经过滤过了
* @param {string} option.timeGranularity 颗粒度
*/
export const computeFillPlaceholderTaskCount = ({ tasks, data, timeGranularity }) => {
const result = { prev: 0, next: 0 };
// 新数据的开始时间 < 旧数据的开始时间
// 超出了上限 补上限的时间刻度
// 补上 新数据开始时间 到 旧数据开始时间 的刻度
if (+data[0].planStart < +tasks[0].planStart) {
// 找出来需要补几组颗粒度
result.prev = dayjs(+tasks[0].planStart).diff(+data[0].planStart, timeGranularity) + 1;
}
// 新数据的结束时间 > 旧数据的结束时间
// 超出了下线 补下限的时间刻度
// 补上 旧数据截止时间 到 新数据截止时间 的刻度
if (+data[data.length - 1].planStart > +tasks[tasks.length - 1].planStart) {
result.next = dayjs(+data[data.length - 1].planStart).diff(+tasks[tasks.length - 1].planStart, timeGranularity) + 1;
}
return result;
};

9
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,
@ -104,12 +104,9 @@ const validateTimeIsToday = time => {
* 检测两个日期是否相同
* @param {number | date} time
* @param {number | date} value
* @param {string} cycle 传入 day 将会比较 day month和 year
* @param {string} cycle 传入 day 将会比较 day month和 year 一般是时间颗粒度
*/
const isSame = (time, value, cycle) => {
const str = dayjs(time).isSame(value, cycle);
return str;
};
const isSame = (time, value, cycle) => dayjs(time).isSame(value, cycle);
/**
* 格式化开始时间

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,
},
};

8
vue.config.js

@ -10,6 +10,7 @@ module.exports = {
devServer: {
// open: true,
// host: '127.0.0.1',
port: 9000,
overlay: { warnings: false, errors: true },
// proxy: {}
},
@ -29,9 +30,8 @@ module.exports = {
},
pluginOptions: {
// mock: { entry: './src/mock/mock.js', debug: true, disable: true },
eruda: {},
webpackBundleAnalyzer: {
openAnalyzer: isPro,
},
// webpackBundleAnalyzer: {
// openAnalyzer: isPro,
// },
},
};

Loading…
Cancel
Save