Browse Source

Merge branch 'wrr' of dd.tall.wiki:wally/tall-mui-3-project into wrr

disable-role
wally 4 years ago
parent
commit
0561acca5b
  1. 472
      CHANGELOG.md
  2. 3
      package.json
  3. 10
      public/index.html
  4. 4
      rest/project.http
  5. 1
      src/App.vue
  6. 2
      src/apis/plugin.js
  7. 3
      src/apis/project.js
  8. 6
      src/apis/task.js
  9. 149
      src/common/styles/app.scss
  10. 14
      src/components/Globals/Globals.vue
  11. 100
      src/components/InputSearch/InputSearch.vue
  12. 24
      src/components/Plugin/Plugin.vue
  13. 58
      src/components/Roles/Roles.vue
  14. 31
      src/components/TimeLine/TimeLine.vue
  15. 184
      src/components/TimeLine/component/TaskTools.vue
  16. 12
      src/components/TimeLine/component/TimeBox.vue
  17. 46
      src/components/TimeLine/component/TimeStatus.vue
  18. 90
      src/components/Title/Title.vue
  19. 457
      src/components/Title/components/CreateTask.vue
  20. 320
      src/components/Title/components/NewProjects.vue
  21. 115
      src/components/Title/components/ShareProject.vue
  22. 2
      src/components/Upload/Upload.vue
  23. 2
      src/manifest.json
  24. 148
      src/pages/project/project.vue
  25. 2
      src/plugins/p-subproject/p-subproject.vue
  26. 2
      src/plugins/p-subtasks/p-subtasks.vue
  27. 1
      src/plugins/p-task-start-time-delay/p-task-start-time-delay.vue
  28. 47
      src/plugins/p-task-title/p-task-title.vue
  29. 1
      src/store/project/getters.js
  30. 9
      src/store/project/mutations.js
  31. 1
      src/store/project/state.js
  32. 3
      src/store/socket/actions.js
  33. 36
      src/store/task/mutations.js
  34. 2
      src/store/task/state.js
  35. 1
      src/utils/cacheAndRequest.js

472
CHANGELOG.md

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

3
package.json

@ -26,6 +26,7 @@
},
"dependencies": {
"@dcloudio/uni-app-plus": "^2.0.0-31920210709003",
"@dcloudio/uni-cli-i18n": "^2.0.0-32920210927002",
"@dcloudio/uni-h5": "^2.0.0-31920210709003",
"@dcloudio/uni-helper-json": "*",
"@dcloudio/uni-i18n": "^2.0.0-31920210709003",
@ -82,7 +83,7 @@
"postcss-comment": "^2.0.0",
"prettier": "^2.2.1",
"right-pad": "^1.0.1",
"sass": "^1.38.2",
"sass": "^1.39.0",
"sass-loader": "^8.0.2",
"vue-cli-plugin-commitlint": "~1.0.12",
"vue-template-compiler": "^2.6.11"

10
public/index.html

@ -16,6 +16,12 @@
</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" />
<!-- <script src="https://cdn.bootcdn.net/ajax/libs/vConsole/3.9.0/vconsole.min.js"></script>
<script>
var vConsole = new VConsole();
console.log('Hello world');
</script> -->
</head>
<body>
@ -25,5 +31,7 @@
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
<script src="https://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
<!-- uni 的 SDK -->
<script type="text/javascript" src="https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.1.5.2.js"></script>
</html>

4
rest/project.http

@ -7,8 +7,8 @@ content-type: application/json;charset=utf-8
{
"client": 1,
"data": {
"credential": "999999",
"identifier": "song"
"credential": "123456",
"identifier": "zb11"
},
"scene": 0,
"type": 3

1
src/App.vue

@ -3,7 +3,6 @@ import { mapActions, mapMutations, mapState, mapGetters } from 'vuex';
export default {
async onLaunch(options) {
console.log('options: ', options);
this.checkNetwork(); //
/* #ifdef MP-WEIXIN */

2
src/apis/plugin.js

@ -4,7 +4,7 @@ const url = process.env.VUE_APP_API_URL;
const install = (Vue, vm) => {
vm.$u.api = { ...vm.$u.api } || {};
// 获取插件信息
vm.$u.api.getOtherPlugin = param => vm.$u.post(`${url}/pluginshop/plugin/query`, param);
vm.$u.api.getOtherPlugin = param => vm.$u.post(`${url}/pluginshop/plugin/query?pluginId=${param.pluginId}&styleType=${param.styleType}`);
// 查询子任务
vm.$u.api.findSonTask = param => vm.$u.post(`${uni.$t.domain}/task/findSonTask`, param);
// 查询子项目

3
src/apis/project.js

@ -8,6 +8,9 @@ const install = (Vue, vm) => {
//点击分享连接
vm.$u.api.clickShare = param => vm.$u.post(`${uni.$t.domain}/share/click`, param);
//查询医院是否填写了调查问卷
vm.$u.api.queryNotWrite = param => vm.$u.post(`${uni.$t.domain}/questionnaire/queryNotWrite`, param);
};
export default { install };

6
src/apis/task.js

@ -6,6 +6,12 @@ const install = (Vue, vm) => {
vm.$u.api.getRegularTask = param => vm.$u.post(`${uni.$t.domain}/task/regular`, param);
//修改任务状态
vm.$u.api.updateTaskType = param => vm.$u.post(`${uni.$t.domain}/task/type`, param);
//新建任务
vm.$u.api.saveTask = param => vm.$u.post(`${uni.$t.domain}/task/save`, param);
//克隆任务
vm.$u.api.cloneTask = param => vm.$u.post(`${uni.$t.domain}/task/clone`, param);
//模糊查询 查找项目下的任务
vm.$u.api.queryTaskOfProject = param => vm.$u.post(`${uni.$t.domain}/task/queryTaskOfProject`, param);
};
export default { install };

149
src/common/styles/app.scss

@ -4,3 +4,152 @@
.border-b-1 {
border-bottom-width: 1px;
}
/* 列表 */
.uni-list {
background-color: #ffffff;
position: relative;
width: 100%;
display: flex;
flex-direction: column;
border: 1px solid #afbed1;
height: 80rpx;
line-height: 80rpx;
}
.uni-list-cell {
position: relative;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.uni-list-cell-hover {
background-color: #eee;
}
.uni-list-cell-pd {
padding: 22rpx 30rpx;
}
.uni-list-cell-left {
white-space: nowrap;
font-size: 28rpx;
padding: 0 30rpx;
}
.uni-list-cell-db,
.uni-list-cell-right {
flex: 1;
}
.uni-list-cell::after {
position: absolute;
z-index: 3;
right: 0;
bottom: 0;
left: 30rpx;
height: 1px;
content: '';
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
background-color: #c8c7cc;
}
.uni-list .uni-list-cell:last-child::after {
height: 0rpx;
}
.uni-list-cell-last.uni-list-cell::after {
height: 0rpx;
}
.uni-list-cell-divider {
position: relative;
display: flex;
color: #999;
background-color: #f7f7f7;
padding: 15rpx 20rpx;
}
.uni-list-cell-divider::before {
position: absolute;
right: 0;
top: 0;
left: 0;
height: 1px;
content: '';
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
background-color: #c8c7cc;
}
.uni-list-cell-divider::after {
position: absolute;
right: 0;
bottom: 0;
left: 0rpx;
height: 1px;
content: '';
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
background-color: #c8c7cc;
}
.uni-list-cell-navigate {
font-size: 30rpx;
padding: 22rpx 30rpx;
line-height: 48rpx;
position: relative;
display: flex;
box-sizing: border-box;
width: 100%;
flex: 1;
justify-content: space-between;
align-items: center;
}
.uni-list-cell-navigate {
padding-right: 36rpx;
}
.uni-navigate-badge {
padding-right: 50rpx;
}
.uni-list-cell-navigate.uni-navigate-right:after {
font-family: uniicons;
content: '\e583';
position: absolute;
right: 24rpx;
top: 50%;
color: #bbb;
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
}
.uni-list-cell-navigate.uni-navigate-bottom:after {
font-family: uniicons;
content: '\e581';
position: absolute;
right: 24rpx;
top: 50%;
color: #bbb;
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
}
.uni-list-cell-navigate.uni-navigate-bottom.uni-active::after {
font-family: uniicons;
content: '\e580';
position: absolute;
right: 24rpx;
top: 50%;
color: #bbb;
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
}
.uni-collapse.uni-list-cell {
flex-direction: column;
}
.uni-list-cell-navigate.uni-active {
background: #eee;
}
.uni-list.uni-collapse {
box-sizing: border-box;
height: 0;
overflow: hidden;
}
.uni-collapse .uni-list-cell {
padding-left: 20rpx;
}
.uni-collapse .uni-list-cell::after {
left: 52rpx;
}
.uni-list.uni-active {
height: auto;
}

14
src/components/Globals/Globals.vue

@ -1,15 +1,10 @@
<template>
<view class="m-2" v-if="globals && globals.length">
<u-card
@click="openCard"
:show-foot="false"
:show-head="false"
:style="{ 'max-height': isShrink ? '106rpx' : '340rpx' }"
border-radius="25"
margin="0"
>
<u-card @click="openCard" :show-foot="false" :show-head="false" style="max-height: 340rpx" border-radius="25" margin="0">
<!-- :style="{ 'max-height': isShrink ? '106rpx' : '340rpx' }" -->
<view slot="body">
<scroll-view :scrollY="true" :style="{ 'max-height': isShrink ? '50rpx' : '280rpx' }">
<scroll-view :scrollY="true" style="max-height: 280rpx">
<!-- <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">
<block v-for="item in globals" :key="item.id">
@ -22,6 +17,7 @@
:key="plugin.pluginTaskId"
:plugin-task-id="plugin.pluginTaskId"
:plugin-id="plugin.pluginId"
:param="plugin.param"
:style-type="plugin.styleType || 0"
v-for="plugin in pluginArr"
/>

100
src/components/InputSearch/InputSearch.vue

@ -0,0 +1,100 @@
<template>
<view class="input-group flex-1">
<input :placeholder="placeholder" @input="search" @blur="hideList" v-model="backName" />
<view class="ul">
<view class="li" v-for="(item, index) in dataSource" :key="index" @tap="select(item)">{{ item.name }}</view>
</view>
</view>
</template>
<script>
export default {
props: {
placeholder: String, //
searchKey: String, //key
dataSource: {
type: Array,
default: function () {
//
return [];
},
},
},
data() {
return {
list: [],
name: '',
backName: '',
};
},
destroyed() {
clearTimeout(this.t);
},
methods: {
search(e) {
let val = e.detail.value;
this.$emit('searchPrevTask', val);
// let arr = [];
// for (let i = 0; i < dataSource.length; i++) {
// if (dataSource[i].name.indexOf(val) !== -1) {
// arr.push(dataSource[i]);
// }
// }
// if (!val) {
// this.list = [];
// } else {
// this.list = arr;
// }
},
select(item) {
console.log('item: ', item);
this.backName = item.name;
this.$emit('select', item);
},
hideList() {
setTimeout(() => {
this.$emit('clearAllTasks');
}, 200);
},
},
};
</script>
<style lang="scss" scoped>
.input-group {
position: relative;
input {
border-bottom: 1upx solid #dcdfe6;
height: 90upx;
padding-left: 10upx;
font-size: 30upx;
box-sizing: border-box;
}
.uni-input-placeholder {
color: rgb(192, 196, 204);
font-size: 28upx;
}
.ul {
position: absolute;
left: 0;
top: 100%;
width: 100%;
z-index: 999;
background: #fff;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
max-height: 100px;
overflow-y: auto;
.li {
border-bottom: 1upx solid #f1f1f1;
padding: 16upx;
}
}
}
</style>

24
src/components/Plugin/Plugin.vue

@ -1,6 +1,6 @@
<template>
<view class="u-font-14" style="height: 100%">
<view v-if="pluginContent">
<view v-if="pluginContent" @click="setStorage">
<view
:data-did="task.detailId"
:data-param="param"
@ -9,20 +9,20 @@
:data-pstart="task.planStart"
:data-rdu="task.realDuration"
:data-rid="roleId"
:data-rstart="task.realStart"
:data-tid="task.id"
:data-tname="task.name"
:data-token="token"
:data-rstart="task.realStart"
:data-uid="userId"
style="height: 100%"
v-html="pluginContent"
></view>
</view>
<view v-else>
<view v-else @click="setStorage">
<!-- <plugin-default /> -->
<!-- <component :task="task" :is="pluginComponent"></component> -->
<p-task-title :task="task" v-if="pluginId === '1'" />
<p-task-title :task="task" :param="param" v-if="pluginId === '1'" />
<p-task-description :task="task" v-if="pluginId === '2'" />
<p-task-duration-delay :task="task" v-if="pluginId === '3'" />
<p-task-start-time-delay :task="task" v-if="pluginId === '4'" />
@ -42,7 +42,7 @@
</template>
<script>
import { mapGetters, mapState } from 'vuex';
import { mapGetters, mapState, mapActions } from 'vuex';
export default {
name: 'Plugin',
@ -73,11 +73,16 @@ export default {
// },
},
created() {
this.getPlugin();
async created() {
if (this.pluginId === '5') {
// id
await this.getAllMembers({ projectId: this.projectId });
}
await this.getPlugin();
},
methods: {
...mapActions('role', ['getAllMembers']),
//
async getPlugin() {
const { pluginId, styleType } = this;
@ -134,6 +139,11 @@ export default {
document.body.append(scriptDom);
});
},
// storage
setStorage() {
this.$t.storage.setStorageSync('roleId', this.roleId);
},
},
};
</script>

58
src/components/Roles/Roles.vue

@ -1,7 +1,7 @@
<template>
<view class="px-2 bg-white wrap">
<view class="home-box u-skeleton">
<scroll-view :enable-flex="true" :scroll-left="scrollLeft" :throttle="false" scroll-with-animation scroll-x>
<scroll-view :enable-flex="true" :scroll-left="scrollLeft" :throttle="false" scroll-with-animation scroll-x @scroll="scroll">
<view class="tab-box">
<!-- 角色项
default-tab-choice 我的角色 && 当前展示
@ -23,9 +23,24 @@
{{ item.name }}
</view>
</view>
<view class="tab-item text-gray-400 text-bold">
<view class="tab-children u-skeleton-fillet u-font-14" @click="open"> 禁用 </view>
</view>
</view>
</scroll-view>
</view>
<u-modal v-model="show" :show-title="false" :show-confirm-button="false" :show-cancel-button="false">
<view class="m-5">
<view class="flex items-start">
<u-icon name="error-circle-fill" color="#f59e0b" size="46" class="mr-3"></u-icon>
您没有查看禁用角色的权限是否向项目经理申请权限
</view>
<view class="flex flex-row-reverse mt-6">
<u-button class="ml-5 mr-0" size="mini" type="primary" @click="show = false">申请</u-button>
<u-button class="m-0" size="mini" @click="show = false">取消</u-button>
</view>
</view>
</u-modal>
<!-- 骨架屏 -->
<u-skeleton :animation="true" :loading="loading" bg-color="#fff"></u-skeleton>
</view>
@ -46,6 +61,8 @@ export default {
{ id: 1, name: '项目经理', mine: 0, pm: 1, sequence: 1 },
{ id: 2, name: '运维', mine: 0, pm: 0, sequence: 2 },
],
roleLeft: 0,
show: false,
};
},
@ -69,6 +86,16 @@ export default {
} else {
this.roles = [...this.visibleRoles];
}
this.$nextTick(() => {
const query = uni.createSelectorQuery().in(this);
query
.selectAll('.tab-children')
.boundingClientRect(data => {
this.roleLeft = data[0].left;
})
.exec();
});
},
methods: {
@ -76,6 +103,14 @@ export default {
...mapMutations('role', ['setRoleId']),
...mapMutations('task', ['setPermanents', 'clearEndFlag']),
open() {
this.show = true;
},
scroll(e) {
this.scrollLeft = e.detail.scrollLeft;
},
//
setCurrentRole(index) {
const query = uni.createSelectorQuery().in(this);
@ -83,23 +118,28 @@ export default {
.selectAll('.tab-children')
.boundingClientRect(data => {
data.forEach(item => {
this.tabList.push({
width: item.width,
left: item.left,
});
this.tabList.push({ width: item.width });
});
})
.exec();
const system = uni.getSystemInfoSync(); //
//
let screenWidth = system.windowWidth;
//
let left = 0;
let screenWidth = system.windowWidth;
for (let i = 0; i < index; i++) {
left += this.tabList[i].width + this.tabList[i].left * 2;
left += this.tabList[i].width + (this.roleLeft - 8) * 2;
}
left += (this.tabList[index].width + (this.roleLeft - 8) * 2) / 2;
if (left > screenWidth) {
this.scrollLeft = left - screenWidth + screenWidth / 2;
} else if (left > screenWidth / 2) {
this.scrollLeft = left - screenWidth / 2;
} else if (left < screenWidth / 2) {
this.scrollLeft = 0;
}
left += this.tabList[index].width;
this.scrollLeft = left - screenWidth / 2;
},
//

31
src/components/TimeLine/TimeLine.vue

@ -53,7 +53,7 @@ export default {
async handleScrollTop() {
if (!this.tasks || !this.tasks.length || this.showSkeleton) return;
const startTime = this.tasks[0].planStart - 0;
if ((this.tasks[0].plugins && this.tasks[0].plugins.length === 0) || this.topEnd) {
if (this.topEnd) {
//
console.warn('滚动到顶部没有数据时: ');
const addTasks = setPlaceholderTasks(startTime, true, this.timeGranularity);
@ -61,8 +61,10 @@ export default {
} else {
//
console.warn('滚动到顶部有数据时: ');
const detailId = this.tasks.findIndex(task => task.detailId);
const timeNode = this.tasks[detailId].planStart - 0;
const upQuery = {
timeNode: startTime,
timeNode,
queryType: 0,
queryNum: 6,
};
@ -75,7 +77,7 @@ export default {
if (!this.tasks || !this.tasks.length || this.showSkeleton) return;
const { tasks, timeGranularity } = this;
const startTime = tasks[tasks.length - 1].planStart - 0;
if ((tasks[0].plugins && tasks[0].plugins.length === 0) || this.bottomEnd) {
if (this.bottomEnd) {
//
console.warn('滚动到底部没有数据时: ');
const addTasks = setPlaceholderTasks(startTime, false, this.timeGranularity);
@ -83,9 +85,15 @@ export default {
} else {
// =+
console.warn('滚动到底部有数据时: ');
const timeNode = this.$t.time.add(startTime, 1, timeGranularity).valueOf();
const arr = [];
this.tasks.forEach(task => {
if (task.detailId) {
arr.push(task);
}
});
const nextQueryTime = +this.$t.time.add(+arr[arr.length - 1].planStart, 1, timeGranularity);
const downQuery = {
timeNode,
timeNode: nextQueryTime,
queryType: 1,
queryNum: 6,
};
@ -101,10 +109,15 @@ export default {
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
const item = this.tasks.find(task => task.detailId);
if (item) {
this.setScrollToTaskId(`a${item.id}`);
} 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
}
}
},
},

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

@ -1,11 +1,185 @@
<template>
<view class="flex justify-between" style="min-width: 90px">
<u-icon custom-prefix="custom-icon" name="C-bxl-redux" size="17px"></u-icon>
<u-icon custom-prefix="custom-icon" name="attachment" size="21px"></u-icon>
<u-icon custom-prefix="custom-icon" name="moneycollect" size="20px"></u-icon>
<view>
<view class="flex justify-between" style="min-width: 90px; position: relative">
<u-icon custom-prefix="custom-icon" name="C-bxl-redux" size="17px"></u-icon>
<u-icon custom-prefix="custom-icon" name="attachment" size="21px"></u-icon>
<!-- <u-icon custom-prefix="custom-icon" name="moneycollect" size="20px"></u-icon> -->
<u-icon name="xuanxiang" custom-prefix="custom-icon" size="21px" @click="operation"></u-icon>
<!-- 右上角 ... 弹窗 -->
<view class="popup border shadow-md" v-if="show">
<view class="flex justify-center pb-3 border-b-1">
<span @click="createTask">新建任务</span>
</view>
<view class="flex pt-3 justify-center">
<span>克隆任务</span>
</view>
</view>
</view>
<!-- 遮罩 -->
<view class="mask" v-if="maskShow" @click="closeMask"></view>
<!-- 新建任务弹窗 -->
<CreateTask
:startTime="startTime"
:endTime="endTime"
:task="task"
@showTime="showTime"
@closeMask="closeMask"
class="thirdPopup flex transition-transform"
v-if="createTaskShow"
/>
<u-picker title="开始时间" mode="time" v-model="showStart" :params="params" @confirm="confirmStartTime"></u-picker>
<u-picker title="结束时间" mode="time" v-model="showEnd" :params="params" @confirm="confirmEndTime"></u-picker>
</view>
</template>
<script>
export default {};
import CreateTask from '../../Title/components/CreateTask.vue';
export default {
components: { CreateTask },
props: {
task: {
type: Object,
default: () => {},
},
},
data() {
return {
show: false, // ...
createTaskShow: false, //
secondShow: false, //
maskShow: false, //
showStart: false,
showEnd: false,
startTime: '', //
endTime: '', //
params: {
year: true,
month: true,
day: true,
hour: true,
minute: true,
second: true,
},
};
},
methods: {
//
operation() {
// this.$t.ui.showToast('');
this.show = !this.show;
},
//
createTask() {
// ...
this.show = false;
//
this.maskShow = true;
//
this.createTaskShow = true;
},
//
closeMask() {
//
this.maskShow = false;
//
this.secondShow = false;
//
this.createTaskShow = false;
},
showTime() {
this.showStart = !this.showStart;
},
//
confirmStartTime(e) {
this.startTime = `${e.year}-${e.month}-${e.day} ${e.hour}:${e.minute}:${e.second}`;
this.showEnd = true;
},
//
confirmEndTime(e) {
this.endTime = `${e.year}-${e.month}-${e.day} ${e.hour}:${e.minute}:${e.second}`;
},
},
};
</script>
<style lang="scss" scoped>
.mask {
width: 100%;
height: 100vh;
z-index: 21;
position: fixed;
top: 0;
left: 0;
background: rgba(0, 0, 0, 0.3);
}
.thirdPopup {
background: #ffffff;
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
z-index: 33;
border-radius: 5px;
width: 90%;
}
.popup {
width: 110px;
background: #fff;
position: absolute;
right: 0;
top: 35px;
z-index: 99;
padding: 15px 0;
color: black;
animation: opacity 1s ease-in;
}
@keyframes opacity {
0% {
opacity: 0;
}
50% {
opacity: 0.8;
}
100% {
opacity: 1;
}
}
::v-deep .u-slot-content {
min-width: 0;
}
::v-deep .u-dropdown__content {
min-height: 120px !important;
height: auto !important;
overflow-y: auto;
background: #fff !important;
transition: none !important;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}
::v-deep .u-dropdown__menu__item .u-flex {
justify-content: space-between;
width: 100%;
height: 100%;
flex-wrap: nowrap;
border: 1px solid #afbed1;
padding: 0 8px;
}
::v-deep .u-dropdown__content__mask {
display: none;
}
</style>

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

@ -10,7 +10,7 @@
<view v-else>{{ $moment(+task.planStart).format('D日') }}</view>
<!-- 任务功能菜单 -->
<TaskTools v-if="task.process !== 4" />
<TaskTools v-if="task.process !== 4" :task="task" />
</view>
</view>
<view class="border-l-2 border-gray-300 plugin">
@ -48,12 +48,12 @@
<Plugin
:class="[`row-span-${plugin.row}`, `col-span-${plugin.col}`]"
:task="task"
:key="plugin.pluginTaskId"
:key="pluginIndex"
:plugin-task-id="plugin.pluginTaskId"
:plugin-id="plugin.pluginId"
:param="plugin.param"
:style-type="styleType || 0"
v-for="plugin in row"
v-for="(plugin, pluginIndex) in row"
/>
</view>
</view>
@ -85,7 +85,7 @@ export default {
computed: {
...mapState('role', ['roleId']),
...mapState('task', ['timeUnit', 'tasks', 'taskLoading', 'topEnd', 'bottomEnd', 'showSkeleton']),
...mapState('task', ['timeUnit', 'tasks', 'taskLoading', 'showSkeleton']),
...mapGetters('task', ['startTimeFormat']),
},
@ -132,11 +132,11 @@ export default {
margin-bottom: 8px;
margin-left: 15px;
}
::deep .ml-2 {
::v-deep .ml-2 {
margin-left: 16px;
}
::deep .ml-3 {
::v-deep .ml-3 {
margin-left: 20px;
}
</style>

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

@ -18,7 +18,7 @@
<view class="u-progress-dot"></view>
<view class="u-progress-info">
<u-icon :name="orderStyle.icon" v-if="orderStyle.icon" size="15px"></u-icon>
<template v-else>{{ computeDurationText() }}</template>
<template v-else>{{ durationText }}</template>
</view>
</view>
</u-circle-progress>
@ -31,7 +31,7 @@
<u-icon :name="orderStyle.icon" v-if="task.process !== 4" size="15px"></u-icon>
<u-icon :name="orderStyle.icon" v-else size="15px"></u-icon>
</span>
<template v-else>{{ computeDurationText() }}</template>
<template v-else>{{ durationText }}</template>
</view>
</view>
</view>
@ -54,6 +54,7 @@ export default {
proceed: [{ text: '暂停' }, { text: '重新开始任务', color: 'blue' }, { text: '结束' }],
again: [{ text: '重新开始任务', color: 'blue' }],
timer: null,
durationText: 0,
};
},
@ -110,6 +111,19 @@ export default {
},
},
mounted() {
// TODO:
const time = this.computeDurationText();
this.updateDurationText(time);
},
destroyed() {
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
},
methods: {
...mapMutations('task', ['setTip']),
@ -167,20 +181,26 @@ export default {
// = -
// = realStart + planDuration - Date.now()
computeDurationText() {
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
}
const { realStart, planDuration } = this.task;
const leftTime = +realStart + +planDuration - Date.now(); //
const { num, time } = this.$t.time.computeDurationText(leftTime);
this.$nextTick(() => {
if (!time) return;
this.timer = setTimeout(() => {
this.computeDurationText();
}, time);
});
return num;
if (num <= 0) {
clearInterval(this.timer);
this.timer = null;
}
this.durationText = num;
return time;
},
updateDurationText(time) {
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
if (!time) return;
setInterval(() => {
this.computeDurationText();
}, time);
},
},
};

90
src/components/Title/Title.vue

@ -1,5 +1,6 @@
<template>
<view>
<!-- :is-back="false" -->
<u-navbar :custom-back="onBack" class="overflow-hidden">
<view class="flex justify-start flex-1 px-3 font-bold min-0">
<view class="truncate">{{ project.name }}</view>
@ -21,7 +22,8 @@
<view class="popup border shadow-md" v-if="show">
<view class="flex pb-3 border-b-1">
<u-icon name="plus-circle" size="36" style="margin: 0 15px 3px 0"></u-icon>
<view @click="newprojects">新建任务</view>
<!-- <view @click="createTask">新建任务</view> -->
<view>新建任务</view>
</view>
<view class="flex pt-3">
<u-icon name="share" size="32" style="margin: 0 15px 3px 0"></u-icon>
@ -29,40 +31,81 @@
</view>
</view>
<!-- 分享项目弹窗 -->
<ShareProject v-if="secondShow" class="secondPopup" />
<!-- 新建项目弹窗 -->
<NewProjects @closeMask="closeMask" class="thirdPopup flex transition-transform" v-if="newProjectsShow" />
<ShareProject v-if="secondShow" class="second-popup" />
<!-- 新建任务弹窗 -->
<CreateTask
:startTime="startTime"
:endTime="endTime"
@showTime="showTime"
@closeMask="closeMask"
class="third-popup flex transition-transform"
v-if="createTaskShow"
/>
<u-picker title="开始时间" mode="time" v-model="showStart" :params="params" @confirm="confirmStartTime"></u-picker>
<u-picker title="结束时间" mode="time" v-model="showEnd" :params="params" @confirm="confirmEndTime"></u-picker>
</view>
</template>
<script>
import { mapGetters, mapState } from 'vuex';
import NewProjects from './components/NewProjects.vue';
import CreateTask from './components/CreateTask.vue';
import ShareProject from './components/ShareProject.vue';
export default {
name: 'ProjectTitle',
components: { NewProjects },
components: { CreateTask, ShareProject },
data() {
return {
show: false, // ...
newProjectsShow: false, //
createTaskShow: false, //
secondShow: false, //
maskShow: false, //
showStart: false,
showEnd: false,
startTime: '', //
endTime: '', //
params: {
year: true,
month: true,
day: true,
hour: true,
minute: true,
second: true,
},
};
},
computed: {
...mapState('project', ['project']),
...mapGetters('user', ['userId']),
},
methods: {
showTime() {
this.showStart = !this.showStart;
},
//
confirmStartTime(e) {
this.startTime = `${e.year}-${e.month}-${e.day} ${e.hour}:${e.minute}:${e.second}`;
this.showEnd = true;
},
//
confirmEndTime(e) {
this.endTime = `${e.year}-${e.month}-${e.day} ${e.hour}:${e.minute}:${e.second}`;
},
//
onBack() {
// eslint-disable-next-line no-undef
const pages = getCurrentPages(); //
if (pages.length > 1) {
uni.navigateBack();
uni.webView.navigateBack();
} else {
this.$u.route('/', { u: this.userId });
// this.$u.route('/', { u: this.userId });
uni.webView.reLaunch({ url: `/pages/index/index?u=${this.userId}` });
}
},
@ -76,8 +119,9 @@ export default {
},
//
openIndex() {
this.$u.route('/', { u: this.userId });
uni.webView.reLaunch({ url: `/pages/index/index?u=${this.userId}` });
},
//
operation() {
// this.$t.ui.showToast('');
@ -85,13 +129,13 @@ export default {
},
//
newprojects() {
createTask() {
// ...
this.show = false;
//
this.maskShow = true;
//
this.newProjectsShow = true;
this.createTaskShow = true;
},
//
@ -111,14 +155,14 @@ export default {
//
this.secondShow = false;
//
this.newProjectsShow = false;
this.createTaskShow = false;
},
},
};
</script>
<style lang="scss" scoped>
.secondPopup {
.second-popup {
background: #ffffff;
position: fixed;
left: 50%;
@ -126,9 +170,10 @@ export default {
transform: translate(-50%, -50%);
z-index: 33;
border-radius: 5px;
width: 90%;
}
.thirdPopup {
.third-popup {
background: #ffffff;
position: fixed;
left: 50%;
@ -136,6 +181,7 @@ export default {
transform: translate(-50%, -50%);
z-index: 33;
border-radius: 5px;
width: 90%;
}
.popup {
@ -146,7 +192,7 @@ export default {
z-index: 99;
padding: 15px;
color: black;
animation: opacity 1s ease-in;
animation: opacity 0.5s ease-in;
}
@keyframes opacity {
@ -161,16 +207,18 @@ export default {
}
}
::deep .u-slot-content {
::v-deep .u-slot-content {
min-width: 0;
}
::deep .u-dropdown__content {
height: 160px !important;
::v-deep .u-dropdown__content {
min-height: 120px !important;
height: auto !important;
overflow-y: auto;
background: #fff !important;
transition: none !important;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}
::deep .u-dropdown__menu__item .u-flex {
::v-deep .u-dropdown__menu__item .u-flex {
justify-content: space-between;
width: 100%;
height: 100%;
@ -178,7 +226,7 @@ export default {
border: 1px solid #afbed1;
padding: 0 8px;
}
::deep .u-dropdown__content__mask {
::v-deep .u-dropdown__content__mask {
display: none;
}
</style>

457
src/components/Title/components/CreateTask.vue

@ -0,0 +1,457 @@
<template>
<div class="new-projects-box">
<div class="form">
<!-- 项目名称 -->
<view class="mb-3 font-bold text-base flex justify-center">新建任务</view>
<div class="flex items-center mb-2">
<div>名称<span class="text-red-500">*</span></div>
<u-input max-length="5" v-model="name" :type="type" :border="border" />
</div>
<!-- 起止时间 -->
<div class="mb-2">
<div>起止时间</div>
<u-input placeholder="请选择起止时间" v-model="timeValue" :type="type" :border="border" @click="$emit('showTime')" />
</div>
<!-- 多选框 -->
<div class="flex justify-between items-center">
<div>负责人<span class="text-red-500">*</span></div>
<div class="flex-1" v-if="hasRole">{{ roleName }}</div>
<div label="负责人" class="flex-1" v-else>
<u-dropdown disabled ref="uDropdown" placeholder="请选择负责人">
<u-dropdown-item :title="roleList">
<view class="slot-content bg-white">
<div
class="flex flex-row justify-between mb-1 drop-item"
v-for="(role, roleIndex) in roleOptions"
:key="roleIndex"
@click="change(roleIndex)"
>
<view v-model="role.id">{{ role.name }}</view>
<u-icon v-if="role.dropdownShow" name="checkbox-mark" color="#2979ff" size="28"></u-icon>
</div>
</view>
</u-dropdown-item>
</u-dropdown>
</div>
</div>
<!-- 下拉图标 -->
<div class="flex justify-center my-6">
<u-icon v-if="arrow" name="arrow-down" size="28" @click="openDropdown"></u-icon>
<u-icon v-else name="arrow-up" size="28" @click="closeSecondDropdown"></u-icon>
</div>
<!-- 下拉框的内容 -->
<div v-if="show" class="mb-6">
<!-- 描述 -->
<div class="flex items-center mb-2">
<div>描述</div>
<u-input v-model="description" max-length="48" type="textarea" height="36" auto-height :border="border" />
</div>
<!-- 所属项目 -->
<div class="w flex items-center mb-2">
<div>所属项目<span class="text-red-500">*</span></div>
<div>{{ project.name }}</div>
</div>
<!-- 所属任务 -->
<div class="w flex items-center mb-2" v-if="task && task.id">
<div>所属任务</div>
<div>{{ task.name }}</div>
</div>
<!-- 上道工序 -->
<div class="flex items-center mb-2">
<div>上道工序</div>
<InputSearch
@searchPrevTask="searchPrevTask"
:dataSource="allTasks"
@select="handleChange"
@clearAllTasks="clearAllTasks"
placeholder="请输入上道工序"
/>
</div>
<!-- 检查人多选框 -->
<div class="flex justify-between items-center">
<div>检查人<span class="text-red-500">*</span></div>
<div label="检查人" class="flex-1">
<u-dropdown ref="dropdown">
<u-dropdown-item :title="checkerList">
<view class="slot-content bg-white">
<div
class="flex flex-row justify-between mb-1 drop-item"
v-for="(checkoutOption, Index) in checkoutOptions"
:key="Index"
@click="choose(Index)"
>
<view v-model="checkoutOption.value">{{ checkoutOption.name }}</view>
<u-icon v-if="checkoutOption.dropdownShow" name="checkbox-mark" color="#2979ff" size="28"></u-icon>
</div>
</view>
</u-dropdown-item>
</u-dropdown>
</div>
</div>
<!-- 是否是日常任务 -->
<div class="flex justify-between items-center mt-6">
是否是日常任务
<u-switch v-model="isGlobal" size="28"></u-switch>
</div>
<div class="mt-6">
<div>交付物</div>
<div v-for="(sort, sortIndex) in deliverSort" :key="sortIndex">
<u-input
@blur="addDeliverInput"
v-model="sort.name"
:placeholder="`交付物名称${sortIndex + 1}`"
:type="type"
:border="border"
/>
</div>
</div>
</div>
<div class="flex items-center mb-6">
<u-button type="primary" size="medium" @click="setParameters">提交</u-button>
</div>
</div>
</div>
</template>
<script>
import { mapState, mapGetters, mapMutations } from 'vuex';
export default {
props: {
startTime: {
type: String,
default: '',
},
endTime: {
type: String,
default: '',
},
task: {
type: Object,
default: null,
},
},
data() {
return {
arrow: true,
show: false,
isGlobal: false, //
name: '', //
showChooseTime: false,
timeValue: '', //
description: '', //
projectShow: false, //
processTaskId: '', //
type: 'text',
border: true,
roleList: undefined, //
checkerList: undefined, //
roleOptions: [], //
checkoutOptions: [], //
roleIdList: [], // id
checkerIdList: [], // id
deliverables: [], //
deliverSort: [{ name: '' }], //
allTasks: [],
roleName: '', //
hasRole: false, //
};
},
computed: {
...mapState('role', ['visibleRoles', 'roleId']),
...mapState('project', ['project']),
...mapState('task', ['tasks']),
...mapGetters('project', ['projectId']),
},
watch: {
endTime(val) {
if (val) {
this.timeValue = this.startTime + ' 至 ' + val;
}
},
},
mounted() {
//
if (this.visibleRoles.length) {
this.visibleRoles.forEach(role => {
role.dropdownShow = false;
role.status = false;
});
}
this.roleOptions = this.$u.deepClone(this.visibleRoles);
this.checkoutOptions = this.$u.deepClone(this.visibleRoles);
//
if (this.roleId) {
const item = this.visibleRoles.find(r => r.id === this.roleId);
if (item) {
this.roleName = item.name;
this.hasRole = true;
}
}
},
methods: {
...mapMutations('task', ['updateTasks']),
//
change(index) {
let arr = [...this.roleOptions];
//
arr[index].dropdownShow = !arr[index].dropdownShow;
//
this.roleList = arr[index].name;
let shows = '';
// arr
arr.map(val => {
if (val.dropdownShow === true) {
shows += val.name + ',';
this.roleIdList.push(val.id);
}
});
this.roleOptions = [...arr];
// ','
this.roleList = shows.slice(0, shows.length - 1);
},
//
choose(index) {
let arr = [...this.checkoutOptions];
//
arr[index].dropdownShow = !arr[index].dropdownShow;
//
this.checkerList = arr[index].name;
let shows = '';
// arr
arr.map(val => {
if (val.dropdownShow === true) {
shows += val.name + ',';
this.checkerIdList.push(val.id);
}
});
this.checkoutOptions = [...arr];
// ','
this.checkerList = shows.slice(0, shows.length - 1);
// this.roleList = arr[value - 1].name;
},
//
openDropdown() {
this.arrow = !this.arrow;
this.show = true;
},
//
closeSecondDropdown() {
this.arrow = !this.arrow;
this.show = false;
},
/**
* 模糊查询 查找项目下的任务
* @param name 任务名
* @param projectId 项目id
*/
async searchPrevTask(val) {
try {
const params = { name: val, projectId: this.projectId };
const data = await this.$u.api.queryTaskOfProject(params);
this.allTasks = data;
return data;
} catch (error) {
console.error('error: ', error);
}
},
//
handleChange(data) {
this.processTaskId = data.detailId;
},
//
clearAllTasks() {
this.allTasks = [];
},
//
addDeliverInput() {
if (this.deliverSort[this.deliverSort.length - 1].name) {
this.deliverSort.push({ name: '' });
}
},
//
async setParameters() {
const {
projectId,
task,
name,
startTime,
endTime,
hasRole,
roleIdList,
roleId,
description,
processTaskId,
checkerIdList,
isGlobal,
} = this;
if (!name) {
this.$t.ui.showToast('请输入名称');
return;
}
if ((!roleIdList || !roleIdList.length) && !hasRole) {
this.$t.ui.showToast('请选择负责人');
return;
}
if (!checkerIdList || !checkerIdList.length) {
this.$t.ui.showToast('请选择检查人');
return;
}
const deliverList = [];
this.deliverSort.forEach(item => {
if (item.name) {
deliverList.push(item.name);
}
});
const params = {
name,
startTime: startTime ? this.$moment(startTime).format('x') - 0 : '',
endTime: endTime ? this.$moment(endTime).format('x') - 0 : '',
roleIdList: hasRole ? [roleId] : roleIdList,
description,
projectId,
parentTaskId: task && task.id ? task.id : '', //
processTaskId, // TODO
checkerIdList,
global: isGlobal ? 1 : 0,
deliverList,
};
await this.handleSubmit(params);
},
/**
* 新建任务
* @param name 任务名
* @param startTime 开始时间
* @param endTime 结束时间
* @param roleIdList 负责人id数组
* @param description 描述
* @param projectId 所属项目id
* @param parentTaskId 所属任务id
* @param processTaskId 上道工序任务id
* @param checkerIdList 检查人id数组
* @param global 是否日常任务 0 1
* @param deliverList 交付物名字数组
*/
async handleSubmit(params) {
try {
const data = await this.$u.api.saveTask(params);
// TODO or
this.$emit('closeMask');
const newTasks = {
data: data[0],
processTaskId: params.processTaskId,
};
// store
//
if (!this.task || !this.task.id) {
this.addNewTasks(newTasks);
}
} catch (error) {
this.$emit('closeMask');
console.error('error: ', error);
}
},
// tasks
addNewTasks(data) {
const oldTasks = this.$u.deepClone(this.tasks);
let res = data.data;
//
if (data.processTaskId) {
const index = oldTasks.find(item => item.detailId === data.processTaskId);
if (index) {
oldTasks.splice(index + 1, 0, res);
}
} else {
this.setAddPosition(res, oldTasks);
}
},
//
setAddPosition(res, oldTasks) {
if (res.planStart - 0 < oldTasks[0].planStart - 0) {
//
oldTasks.splice(0, 0, res);
} else if (res.planStart - 0 === oldTasks[0].planStart - 0) {
//
oldTasks.splice(1, 0, res);
} else if (res.planStart - 0 >= oldTasks[oldTasks.length - 1].planStart - 0) {
//
oldTasks.splice(-1, 0, res);
} else {
//
for (let i = 0; i < oldTasks.length; i++) {
const item = oldTasks[i];
if (res.planStart - 0 > item.planStart - 0) {
if (res.planStart - 0 <= oldTasks[i + 1].planStart - 0) {
oldTasks.splice(i + 1, 0, res);
return;
}
}
}
}
// TODO:
this.updateTasks([...oldTasks]);
},
},
};
</script>
<style lang="scss" scoped>
.form {
display: flex;
flex-direction: column;
width: 100%;
max-height: 400px;
overflow-y: scroll;
}
.drop-item {
border-bottom: 1px solid #f1f1f1;
padding: 16rpx;
}
::v-deep.u-input--border {
border: none;
border-radius: 0;
}
::v-deep.u-dropdown__menu__item > uni-view {
border: none !important;
padding: 5px;
}
.u-input {
border-bottom: 1px solid #dcdfe6;
}
.new-projects-box {
margin-top: 20px;
padding: 15px;
width: 100%;
overflow: hidden;
}
.w {
width: 300px;
height: 39px;
}
::v-deep .u-dropdown__menu__item .u-flex {
border: 0 !important;
border-bottom: 1px solid #dcdfe6 !important;
padding: 0 20rpx;
}
</style>

320
src/components/Title/components/NewProjects.vue

@ -1,320 +0,0 @@
<template>
<div class="new-projects-box" :style="{ height: arrow ? '330px' : '580px' }">
<div class="form">
<!-- 项目名称 -->
<view class="popupTitle flex justify-center">新建任务</view>
<div class="flex items-center">
<div>名称</div>
<u-input v-model="nameValue" :type="type" :border="border" />
</div>
<!-- 起止时间 -->
<div class="flex items-center">
<div>起止-截止时间</div>
<u-input v-model="timeValue" :type="type" :border="border" />
</div>
<!-- 多选框 -->
<div class="flex justify-between items-center">
<div>负责人</div>
<div label="负责人" style="width: 85%">
<u-dropdown ref="uDropdown">
<u-dropdown-item :title="dropTitle">
<view class="slot-content bg-white">
<div
class="multiple-choice flex flex-row justify-between mb-1"
v-for="(option, optionIndex) in options"
:key="optionIndex"
@click="change(optionIndex)"
>
<view v-model="option.value">{{ option.label }}</view>
<u-icon v-if="option.dropdownShow" name="checkbox-mark" color="#2979ff" size="28"></u-icon>
</div>
</view>
</u-dropdown-item>
</u-dropdown>
</div>
</div>
<!-- 下拉图标 -->
<div class="flex justify-center" style="margin-top: 20px">
<u-icon v-if="arrow" name="arrow-down" size="28" @click="openDropdown"></u-icon>
<u-icon v-else name="arrow-up" size="28" @click="closeSecondDropdown"></u-icon>
</div>
<!-- 下拉框的内容 -->
<div v-if="show">
<!-- 描述 -->
<div class="flex items-center">
<div>描述</div>
<u-input v-model="decripeValue" :type="type" :border="border" />
</div>
<!-- 所属项目 -->
<div class="w flex items-center">
<div>所属项目</div>
<div class="xiangmu" style="position: relative; background: #fff">当前项目</div>
</div>
<!-- 所属任务 -->
<div class="w flex items-center">
<div>所属任务</div>
<div class="renwu">当前任务</div>
</div>
<!-- 上道工序 -->
<div class="flex items-center">
<div>上道工序</div>
<u-input v-model="lastValue" :type="type" :border="border" />
</div>
<!-- 检查人多选框 -->
<div class="flex justify-between items-center">
<div>检查人</div>
<div class="" label="检查人" style="width: 85%">
<u-dropdown ref="dropdown">
<u-dropdown-item :title="secondDropTitle" style="border: none">
<view class="slot-content bg-white">
<div
class="mb-1 multiple-choice flex flex-row justify-between"
v-for="(checkoutOption, Index) in checkoutOptions"
:key="Index"
@click="choose(Index)"
>
<view v-model="checkoutOption.value">{{ checkoutOption.label }}</view>
<u-icon v-if="checkoutOption.dropdownShow" name="checkbox-mark" color="#2979ff" size="28"></u-icon>
</div>
</view>
</u-dropdown-item>
</u-dropdown>
</div>
</div>
<!-- 是否是日常任务 -->
<div class="flex justify-between items-center" style="padding: 25px 0; border-bottom: 1px solid #adadad">
<div>是否日常任务</div>
<u-switch v-model="checked" size="28"></u-switch>
</div>
<div style="padding-top: 25px">
<div>交付物</div>
<u-input style="border-bottom: 1px solid #dcdfe6" placeholder="交付物名称1" :type="type" :border="border" />
<u-input style="border-bottom: 1px solid #dcdfe6" placeholder="交付物名称2" :type="type" :border="border" />
</div>
</div>
<div class="flex justify-between items-center btns">
<u-button class="btn flex justify-center" type="primary" shape="circle" size="medium" @click="$emit('closeMask')">提交</u-button>
<u-button class="btn flex justify-center" shape="circle" size="medium" @click="$emit('closeMask')">取消</u-button>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
projects: ['我是睡', '我叫什么', '我的名字是'],
title: 'tall1',
arrow: true,
show: false,
checked: false, //
nameValue: '', //
timeValue: '', //
decripeValue: '', //
projectValue: '', //
projectShow: false, //
taskValue: '', //
lastValue: '', //
type: 'text',
border: true,
dropTitle: '观众,干系人', //
secondDropTitle: '干系人', //
//
options: [
{
label: '观众',
value: 1,
dropdownShow: false,
status: false,
},
{
label: '距离优先',
value: 2,
dropdownShow: false,
status: false,
},
{
label: '价格优先',
value: 3,
dropdownShow: false,
status: false,
},
],
//
checkoutOptions: [
{
label: '观众',
value: 1,
dropdownShow: false,
status: false,
},
{
label: '距离优先',
value: 2,
dropdownShow: false,
status: false,
},
{
label: '价格优先',
value: 3,
dropdownShow: false,
status: false,
},
],
//
diliverables: [],
//
projectOptions: [
{
label: 'tall1',
value: 1,
},
{
label: 'tall2',
value: 2,
},
{
label: 'tall3',
value: 3,
},
],
};
},
methods: {
isProjectShow($event) {
console.log(this.projectValue);
console.log($event);
this.projectShow = true;
},
//
closeDropdown() {
this.$refs.uDropdown.close();
},
//
dropdownClosed() {
this.$refs.dropdown.close();
},
//
change(index) {
console.log(index);
let arr = [...this.options];
//
arr[index].dropdownShow = !arr[index].dropdownShow;
//
this.dropTitle = arr[index].label;
let shows = '';
// arr
arr.map(val => {
if (val.dropdownShow === true) {
shows += val.label + ',';
}
});
this.options = [...arr];
// ','
this.dropTitle = shows.slice(0, shows.length - 1);
console.log(this.dropTitle);
},
//
choose(index) {
console.log(index);
let arr = [...this.checkoutOptions];
//
arr[index].dropdownShow = !arr[index].dropdownShow;
//
this.secondDropTitle = arr[index].label;
let shows = '';
// arr
arr.map(val => {
if (val.dropdownShow === true) {
shows += val.label + ',';
}
});
this.checkoutOptions = [...arr];
// ','
this.secondDropTitle = shows.slice(0, shows.length - 1);
console.log(this.secondDropTitle);
// this.dropTitle = arr[value - 1].label;
},
//
// project(value) {
// console.log(value);
// this.title = this.projectOptions[value - 1].label;
// },
//
openDropdown() {
this.arrow = !this.arrow;
this.show = true;
},
//
closeSecondDropdown() {
this.arrow = !this.arrow;
this.show = false;
},
},
};
</script>
<style lang="scss" scoped>
.projectBelong {
height: auto;
background: #fff;
padding: 0 10px;
color: #c0c4cc;
position: absolute;
z-index: 55;
}
.form {
display: flex;
flex-direction: column;
width: 100%;
height: 550px;
overflow-y: scroll;
}
::deep.u-input--border {
border: none;
border-radius: 0;
}
::deep.u-dropdown__menu__item > uni-view {
border: none !important;
padding: 5px;
}
.u-input {
border-bottom: 1px solid #ccc;
}
.btn {
margin-top: 20px;
}
.popupTitle {
font-size: 16px;
font-weight: bold;
margin-bottom: 5px;
}
.new-projects-box {
margin-top: 20px;
padding: 15px;
width: 330px;
overflow: hidden;
}
.btns {
padding: 0 30px;
}
.xiangmu {
margin-left: 11px;
color: rgb(192, 196, 204);
}
.renwu {
margin-left: 11px;
color: rgb(192, 196, 204);
}
.w {
width: 300px;
height: 39px;
}
</style>

115
src/components/ShareProject/ShareProject.vue → src/components/Title/components/ShareProject.vue

@ -1,28 +1,33 @@
<template>
<view class="secondPopup flex justify-center">
<view class="flex justify-center">
<view class="content p-3 pb-8">
<view class="mb-3 font-bold text-base flex justify-center">创建分享链接</view>
<view class="flex flex-col">
<view class="mb-1">用户以什么角色加入项目</view>
<!-- 下拉多选 -->
<u-dropdown>
<u-dropdown-item v-model="roleValue" :title="roleValue" :options="allRoles" @change="changeRole"></u-dropdown-item>
</u-dropdown>
<view class="uni-list">
<view class="uni-list-cell">
<view class="uni-list-cell-db ml-2" v-if="rolesArray.length">
<picker @change="changeRole" :value="index" :range="rolesArray">
<view class="uni-input">{{ allRolesName[index].name }}</view>
</picker>
</view>
</view>
</view>
<!-- 复制链接 -->
<view class="link flex items-center mt-4">
<view class="link-url">{{ links }}</view>
<!-- <u-button style="border-radius: 0" type="primary" @click="copyPasteboard">复制链接</u-button> -->
<u-button
style="border-radius: 0"
style="border-radius: 0; height: 100%"
type="primary"
v-clipboard:copy="links"
v-clipboard:copy="copyText"
v-clipboard:success="copySuccess"
v-clipboard:error="copyError"
>
复制链接
</u-button>
</view>
<view @click="select">
<!-- 全选按钮 -->
<!-- <view class="flex mt-4">
@ -59,9 +64,13 @@ import { mapGetters, mapState } from 'vuex';
export default {
data() {
return {
roleValue: '观众',
links: 'https://kdocs.cn/l/cbs', //
rolesArray: [],
allRolesName: [],
index: 0,
links: '', //
copyText: '',
checked: false, //
roleName: '观众',
//
list: [
{
@ -96,40 +105,40 @@ export default {
computed: {
...mapState('role', ['visibleRoles', 'invisibleRoles']),
...mapState('project', ['project']),
...mapGetters('project', ['projectId']),
allRoles() {
let newArr = [];
if (this.visibleRoles.length || this.invisibleRoles.length) {
const arr = this.visibleRoles.concat(this.invisibleRoles);
arr.forEach(role => {
let item = { value: '', label: '' };
item.id = role.id;
item.value = role.name;
item.label = role.name;
newArr.push(item);
});
const firstItem = { id: '0', value: '观众', label: '观众' };
newArr.unshift(firstItem);
}
return newArr;
},
},
async created() {
this.path = window.location.href.split('?')[0];
const { path, projectId } = this;
const params = { path: `${path}share=1`, projectId, roleId: '0' };
await this.creatShare(params);
mounted() {
this.$nextTick(() => {
this.path = window.location.href.split('?')[0];
const { path, projectId } = this;
const params = { path: `${path}`, projectId, roleId: '0' };
this.creatShare(params);
});
if (this.visibleRoles.length || this.invisibleRoles.length) {
const arr = this.visibleRoles.concat(this.invisibleRoles);
arr.forEach(role => {
let item = { id: '', name: '' };
item.id = role.id;
item.name = role.name;
this.allRolesName.push(item);
this.rolesArray.push(role.name);
});
const firstItem = { id: '0', name: '观众' };
this.allRolesName.unshift(firstItem);
this.rolesArray.unshift('观众');
}
},
methods: {
//
async changeRole(value) {
this.roleValue = value;
const role = this.allRoles.find(item => item.value == value);
async changeRole(e) {
this.index = e.target.value;
this.roleName = this.allRolesName[this.index].name;
const { path, projectId } = this;
const params = { path, projectId, roleId: role.id };
const params = { path, projectId, roleId: this.allRolesName[this.index].id };
await this.creatShare(params);
},
@ -152,21 +161,12 @@ export default {
try {
const data = await this.$u.api.createShare(params);
this.links = data.path;
this.copyText = `邀请您加入${this.project.name}的项目,角色为${this.roleName},链接为${data.path}&url=${this.$t.domain}`;
} catch (error) {
console.error('error: ', error);
}
},
//
copyPasteboard() {
uni.setClipboardData({
data: this.links,
success: function (res) {
console.log('链接复制成功', res.data);
},
});
},
//
select() {
this.quantity = 0;
@ -189,7 +189,7 @@ export default {
<style lang="scss" scoped>
.content {
width: 330px;
width: 100%;
max-height: 400px;
}
@ -207,25 +207,4 @@ export default {
white-space: nowrap;
text-overflow: ellipsis;
}
::deep .u-slot-content {
min-width: 0;
}
::deep .u-dropdown__content {
height: 160px !important;
overflow-y: auto;
background: #fff !important;
transition: none !important;
}
::deep.u-dropdown__menu__item .u-flex {
justify-content: space-between;
width: 100%;
height: 100%;
flex-wrap: nowrap;
border: 1px solid #afbed1;
padding: 0 8px;
}
::deep.u-dropdown__content__mask {
display: none;
}
</style>

2
src/components/Upload/Upload.vue

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

2
src/manifest.json

@ -7,7 +7,7 @@
"transformPx": false,
"h5": {
"router": {
"base": "/tall-project/v3.1.0"
"base": "/tall-project/v3.2.0"
},
"title": "时物链条",
"sdkConfigs": {

148
src/pages/project/project.vue

@ -12,6 +12,35 @@
<!-- 定期任务面板 -->
<TimeLine @getTasks="getTasks" class="flex-1 overflow-hidden" ref="timeLine" />
<!-- 医院项目的问卷悬浮按钮 -->
<view class="absolute bottom-10 right-5" v-if="showQuestion">
<view
@click="openQuestionnaire(false)"
class="relative text-white bg-blue-400 flex justify-center items-center w-12 h-12 rounded-full shadow-2xl"
>
问卷
<u-badge type="error" :count="count" :offset="[-8, -8]"></u-badge>
</view>
<u-popup v-model="showQuestionList" mode="bottom" border-radius="14">
<view class="h-64">
<view class="text-center font-bold fixed bg-white py-3 top-0 w-full">请选择</view>
<view class="flex flex-col mx-3 pt-10 pb-6 h-full overflow-y-auto" :class="questionnaires.length < 5 ? 'justify-center' : ''">
<view
v-for="(item, index) in questionnaires"
:key="item.id"
class="p-2 text-center"
@click="openQuestionnaire(true)"
:class="index === questionnaires.length - 1 ? '' : 'border-b'"
>
<view class="text-gray-500">{{ item.questionnaireName }}</view>
</view>
</view>
<view class="fixed bottom-0 bg-white h-6 w-full"></view>
</view>
</u-popup>
</view>
</view>
</view>
</template>
@ -23,24 +52,24 @@ import { flatten } from 'lodash';
export default {
data() {
return { height: '', show: false };
return { height: '', show: false, showQuestion: false, questionnaires: [], count: 0, showQuestionList: false, chooseItem: false };
},
computed: {
...mapState('user', ['user', 'token']),
...mapState('role', ['visibleRoles', 'roleId']),
...mapState('task', ['timeNode', 'timeUnit', 'tasks', 'regularTask']),
...mapState('task', ['timeNode', 'timeUnit', 'tasks', 'regularTask', 'newProjectInfo', 'showSkeleton', 'showScrollTo']),
...mapState('project', ['project']),
...mapGetters('task', ['timeGranularity']),
...mapGetters('project', ['projectId']),
...mapGetters('user', ['userId']),
},
onLoad(options) {
console.log('options: ', options);
if (options.share && options.share === '1') {
console.log('是分享来的');
this.shareInit(options);
} else {
console.log('不是分享来的');
this.init(options);
}
},
@ -73,6 +102,29 @@ export default {
this.getPermanent(params);
}
},
//
newProjectInfo(val) {
if (val && val.projectId && val.url) {
this.$u.route('/', { u: this.userId, p: val.projectId, url: val.url });
this.clearTasksData();
this.setRoleId('');
const options = this.$route.query;
this.init(options);
}
},
//
questionnaires(val) {
if (val && val.length) {
this.showQuestion = true;
val.forEach(item => {
if (item.isWrite === 0 || item.isWrite === -1) {
this.count += 1;
}
});
}
},
},
mounted() {
@ -88,9 +140,8 @@ export default {
methods: {
...mapActions('user', ['getToken']),
...mapActions('task', ['getRegulars', 'getPermanent', 'getGlobal']),
...mapActions('role', ['getAllMembers']),
...mapMutations('user', ['setToken']),
...mapMutations('project', ['setProject', 'setProjectName']),
...mapMutations('project', ['setProject', 'setProjectName', 'setOpenFirstTask']),
...mapMutations('role', ['setInvisibleRoles', 'setVisibleRoles', 'setRoleId']),
...mapMutations('task', [
'setPermanents',
@ -103,16 +154,28 @@ export default {
'setShowSkeleton',
'setTopEnd',
'setBottomEnd',
'setShowScrollTo',
]),
//
async initPlanTasks() {
this.setPrevPlaceholderTasks(); //
this.setNextPlaceholderTasks(); //
this.$nextTick(() => this.$refs.timeLine.setScrollPosition()); //
await this.getInitTasks(); //
this.$nextTick(() => this.$refs.timeLine.setScrollPosition()); //
//
let timer = null;
timer = setInterval(() => {
if (this.showScrollTo) {
clearInterval(timer);
this.$nextTick(() => this.$refs.timeLine.setScrollPosition());
//
if (this.project.name === '智能大气腐蚀检测平台') {
this.setOpenFirstTask(true);
}
}
}, 500);
},
// ||
@ -120,15 +183,21 @@ export default {
//
function preloadFn(that) {
const detailId = that.tasks.findIndex(task => task.detailId);
const arr = [];
that.tasks.forEach(task => {
if (task.detailId) {
arr.push(task);
}
});
if (detailId !== -1) {
// 1
const { pageCount } = that.$t.task;
that.$nextTick(() => {
//
const { tasks, timeGranularity } = that;
that.getTasks({ timeNode: +tasks[0].planStart, queryType: 0, queryNum: pageCount });
that.getTasks({ timeNode: +tasks[detailId].planStart, queryType: 0, queryNum: pageCount });
//
const nextQueryTime = +that.$t.time.add(+tasks[tasks.length - 1].planStart, 1, timeGranularity);
const nextQueryTime = +that.$t.time.add(+arr[arr.length - 1].planStart, 1, timeGranularity);
that.getTasks({ timeNode: nextQueryTime, queryType: 1, queryNum: pageCount });
});
} else {
@ -165,17 +234,16 @@ export default {
// TODO:
console.error('err: ', err);
} else {
this.setShowScrollTo(true);
//
//
if (data && data.length) {
this.replacePrevData(data, params.queryType);
params.queryType === 0 ? this.setTopEnd(false) : this.setBottomEnd(false);
} else {
// TODO: 0 -> 1 ->
params.queryType === 0 ? this.setPrevPlaceholderTasks() : this.setNextPlaceholderTasks();
}
// else {
// TODO: 0 -> 1 ->
// params.queryType === 0 ? this.setPrevPlaceholderTasks() : this.setNextPlaceholderTasks();
// }
if (this.tasks.length && fn) {
fn(this);
}
@ -249,7 +317,7 @@ export default {
oldTasks = flatten(oldTasks); // 1
this.clearTasks(); // setUpTasks setUpTasks
type === 0 ? this.setUpTasks(oldTasks) : this.setUpTasks(oldTasks);
type === 0 ? this.setUpTasks(oldTasks) : this.setDownTasks(oldTasks);
},
/**
@ -289,13 +357,20 @@ export default {
if (!options || !options.p) {
this.$t.ui.showToast('缺少项目信息参数'); // id
} else {
this.getProjectById({ projectId: options.p }); // id
if (options.p !== this.$t.storage.getStorageSync('projectId')) {
this.$t.storage.setStorageSync('roleId', '');
}
// TODO
this.getProjectById({ projectId: options.p, num: 0 }); // id
//
this.handleQueryNotWrite(options.p);
}
},
//
async shareInit(options) {
const user = JSON.parse(this.$t.storage.getStorageSync('user'));
const storageUser = this.$t.storage.getStorageSync('user');
const user = storageUser ? JSON.parse(storageUser) : null;
if (user && user.id) {
await this.getToken(user.id);
const res = await this.clickShare({ code: options.shareId });
@ -337,8 +412,6 @@ export default {
this.setProject(data);
// id
this.getRoles(params);
// id
this.getAllMembers(params);
} catch (error) {
console.log('error: ', error || '获取项目信息失败');
}
@ -391,6 +464,37 @@ export default {
//
this.clearEndFlag();
},
/**
* 查询医院是否填写了调查问卷
* @param {string} projectId 项目id
*/
async handleQueryNotWrite(projectId) {
try {
const param = { projectId };
const data = await this.$u.api.queryNotWrite(param);
console.log('data: ', data);
this.questionnaires = data;
} catch (error) {
console.error('error: ', error);
}
},
//
openQuestionnaire(value) {
this.chooseItem = value;
if (this.count === 1 || this.chooseItem) {
window.location.href = 'https://www.baidu.com/';
} else {
this.showQuestionList = true;
}
},
},
};
</script>
<style lang="scss" scoped>
.border-b {
border-bottom: 1px solid #e4e7ed;
}
</style>

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

@ -1,7 +1,7 @@
<template>
<!-- 子项目插件 -->
<view>
<view v-for="item in sonProject" :key="item.detailId">
<view v-for="(item, index) in sonProject" :key="index">
<span class="text-xs text-blue-500" @click="openProject(item)">{{ item.name }}</span>
</view>
</view>

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

@ -1,6 +1,6 @@
<template>
<view>
<view v-for="item in sonTask" :key="item.detailId">
<view v-for="(item, index) in sonTask" :key="index">
<span class="text-xs text-gray-500">{{ item.name }}</span>
</view>
</view>

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

@ -1,4 +1,5 @@
<template>
<!-- <view>任务开始时间延迟插件</view> -->
<view v-if="realStart && planStart">
<!-- 任务开始时间延迟插件 -->
<!-- 超时 -->

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

@ -1,9 +1,15 @@
<template>
<!-- 任务名插件 -->
<view>{{ task.name }}</view>
<!-- <view>{{ task.name }}</view> -->
<view class="flex justify-between items-center" @click="postMsg(param)">
<view class="flex-1">{{ task.name }}</view>
<img style="height: 16px" src="https://www.tall.wiki/staticrec/photos/right.png" />
</view>
</template>
<script>
import { mapState, mapGetters } from 'vuex';
export default {
name: 'p-task-title',
props: {
@ -11,6 +17,45 @@ export default {
type: Object,
default: () => {},
},
param: { type: String, default: '' },
},
computed: {
...mapGetters('user', ['userId']),
...mapGetters('project', ['projectId']),
...mapState('project', ['openFirstTask']),
...mapState('task', ['permanents']),
},
watch: {
//
openFirstTask(val) {
if (val) {
if (this.permanents.length && this.permanents[0].name === this.task.name) {
this.postMsg(this.param);
}
}
},
},
methods: {
// PC
postMsg(param) {
/* #ifdef H5 */
if (param) {
const data = JSON.parse(param);
if (data && data.url) {
const url = `${data.url}?u=${this.userId}&p=${this.projectId}&t=${this.task.id}`;
console.log('发消息: ', url);
const msg = {
event: 'openDetail',
data: url,
};
top.postMessage(msg, '*');
}
}
/* #endif */
},
},
};
</script>

1
src/store/project/getters.js

@ -4,6 +4,7 @@ const getters = {
* @param {object} project
*/
projectId({ project }) {
uni.$t.storage.setStorageSync('projectId', project.id);
return project.id;
},
};

9
src/store/project/mutations.js

@ -38,6 +38,15 @@ const mutations = {
setDotList(state, data) {
state.dotList = data;
},
/**
* 设置是否自动打开第一个任务
* @param { object } state
* @param { string } show
*/
setOpenFirstTask(state, show) {
state.openFirstTask = show;
},
};
export default mutations;

1
src/store/project/state.js

@ -3,6 +3,7 @@ const state = {
project: { name: '加载中...' }, // 当前项目信息
projects: [], // 项目列表
dotList: [], // 小红点
openFirstTask: false, // 是否自动打开第一个任务
};
export default state;

3
src/store/socket/actions.js

@ -62,6 +62,9 @@ const actions = {
case 'taskStatus': // 任务状态修改相关消息
commit('task/setTaskStatus', data.data, { root: true });
break;
case 'switchoverProject': // 打开新项目消息
commit('task/setNewProjectInfo', data.data, { root: true });
break;
// case 'Chrome': // !收到开始游戏的消息
// console.log('handleMessagesData', data);
// // @ts-ignore

36
src/store/task/mutations.js

@ -100,6 +100,24 @@ const mutations = {
}
},
/**
* 添加任务后更新tasks
* @param {Object} state
* @param {Array} data 新添加的task
*/
updateTasks(state, data) {
state.tasks = [...data];
},
/**
* 设置添加任务的位置
* @param {*} state
* @param {*} data
*/
setAddPosition(state, data) {
console.log('data: ', data);
},
/**
* 设置日常任务数据
* @param {Object} state
@ -157,6 +175,15 @@ const mutations = {
item.process = data.taskStatus;
},
/**
* 收到打开新项目消息状态
* @param {Object} state
* @param {Array} data 服务端返回的模板数组
*/
setNewProjectInfo(state, data) {
state.newProjectInfo = data;
},
/**
* 设置骨架屏是否显示
* @param {Object} state
@ -165,6 +192,15 @@ const mutations = {
setShowSkeleton(state, show) {
state.showSkeleton = show;
},
/**
* 是否设置时间轴自动滚动的位置
* @param {Object} state
* @param {Boolean} show
*/
setShowScrollTo(state, show) {
state.showScrollTo = show;
},
};
export default mutations;

2
src/store/task/state.js

@ -18,6 +18,8 @@ const state = {
dailyTasks: [], // 日常任务
tasks: [], // 所有的定期任务
showSkeleton: false, // 定期任务骨架屏
newProjectInfo: {},
showScrollTo: false, // 是否可以设置时间轴自动滚动的位置
};
export default state;

1
src/utils/cacheAndRequest.js

@ -65,7 +65,6 @@ export default {
uni.$u.api
.getRegularTask(params)
.then(data => {
console.log('api data: ', uni.$u.deepClone(data));
remote = true;
fn(null, uni.$u.deepClone(data));

Loading…
Cancel
Save