97 changed files with 6164 additions and 3411 deletions
@ -1,204 +1,230 @@ |
|||
# 0.1.0 (2021-08-18) |
|||
# 0.1.0 (2021-08-31) |
|||
|
|||
### 🌟 新功能 |
|||
范围|描述|commitId |
|||
--|--|-- |
|||
calendar, tall.js | 上下滑动切换日历的模式,tall.js中domain根据环境变量切换 | [364e25d](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/364e25d) |
|||
- | db store | [6414c4f](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/6414c4f) |
|||
default plugin | 添加默认插件;项目列表;全局项目最大高度设置 | [ed1d87b](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/ed1d87b) |
|||
- | indexedDB | [687394e](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/687394e) |
|||
pinch | alloy finger实现图片的pinch放大缩小 | [de01343](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/de01343) |
|||
plugin | 插件添加了token及param参数 | [aeb0292](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/aeb0292) |
|||
- | post 封装 | [da52e94](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/da52e94) |
|||
- | tall插件封装 | [1bcb920](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/1bcb920) |
|||
task status | 任务状态切换未完 | [7ffd135](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/7ffd135) |
|||
- | ws storage | [21b3a06](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/21b3a06) |
|||
- | 上传逻辑变化 | [3ff1dc2](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/3ff1dc2) |
|||
- | 任务状态时间显示 | [56f5183](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/56f5183) |
|||
- | 任务进行中状态数字 | [27b7326](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/27b7326) |
|||
- | 全局插件及默认插件位置修改 | [6c80d08](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/6c80d08) |
|||
- | 向右箭头图标变化 | [8e9ca55](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/8e9ca55) |
|||
- | 字体大小更改 | [82cfdd4](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/82cfdd4) |
|||
- | 存token | [b8a178d](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/b8a178d) |
|||
- | 定期任务面板骨架屏添加 | [b2698c0](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/b2698c0) |
|||
富文本插件 | 富文本插件demo测试 | [ed3d644](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/ed3d644) |
|||
- | 导入wbs | [1224fcb](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/1224fcb) |
|||
- | 导入项目,更新项目 | [5e06adf](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/5e06adf) |
|||
- | 导入项目后提示并打开项目详情页 | [410f527](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/410f527) |
|||
- | 引入dayjs | [29b8b93](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/29b8b93) |
|||
- | 提交到本地 | [9cbe411](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/9cbe411) |
|||
- | 插件参数处理调整 | [a3e68d3](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/a3e68d3) |
|||
- | 插件数据获取 | [5b91bdc](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/5b91bdc) |
|||
- | 日历定位;合并 | [ea3f937](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/ea3f937) |
|||
- | 日常任务插件调整 | [c1881f9](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/c1881f9) |
|||
- | 时间基准线,默认插件 | [a33ba1e](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/a33ba1e) |
|||
- | 时间轴修改状态时提示框增加 | [e841392](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/e841392) |
|||
- | 时间轴界面 | [33927e9](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/33927e9) |
|||
- | 标题栏变化 | [3898cfe](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/3898cfe) |
|||
- | 标题栏变化 | [c0fcd9d](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/c0fcd9d) |
|||
- | 标题栏角色栏全局任务组件新建 | [0500cb4](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/0500cb4) |
|||
- | 模拟接口测试 | [69e7931](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/69e7931) |
|||
- | 添加时间轴上下滚动 | [2b81bbc](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/2b81bbc) |
|||
- | 点击日历日期查询项目列表 | [c458385](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/c458385) |
|||
- | 角色栏实现 | [94cd671](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/94cd671) |
|||
- | 设置小红点 | [9316bcb](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/9316bcb) |
|||
- | 距调整pc端 | [5069aa1](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/5069aa1) |
|||
- | 配置默认插件接口 | [f0c177d](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/f0c177d) |
|||
- | 面变化首页变化 | [5e860f1](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/5e860f1) |
|||
- | 项目api url设置 | [6cd5245](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/6cd5245) |
|||
- | 项目列表, 项目url | [32e005b](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/32e005b) |
|||
- | 首页项目样式改变 | [8514c85](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/8514c85) |
|||
- | api封装 | 7d4edfc |
|||
bind phone | 图形验证码;短信验证码;绑定手机号 | 93ffea2 |
|||
- | cache indexedDB处理 | 3388967 |
|||
calendar, tall.js | 上下滑动切换日历的模式,tall.js中domain根据环境变量切换 | 364e25d |
|||
- | db store | 6414c4f |
|||
default plugin | 添加默认插件;项目列表;全局项目最大高度设置 | ed1d87b |
|||
- | indexedDB | 687394e |
|||
modules update;network | npm包升级;网络判断,网络不好才开启本地存储 | ebf7bdc |
|||
mp | 兼容小程序,去除window,document等 | 9178255 |
|||
phone-bind | 验证码validate | a427250 |
|||
pinch | alloy finger实现图片的pinch放大缩小 | de01343 |
|||
plugin | 插件添加了token及param参数 | aeb0292 |
|||
- | post 封装 | da52e94 |
|||
- | tailwindcss添加部分属性 | 5b46b6d |
|||
- | tall插件封装 | 1bcb920 |
|||
task status | 任务状态切换未完 | 7ffd135 |
|||
- | ws storage | 21b3a06 |
|||
- | 上传逻辑变化 | 3ff1dc2 |
|||
- | 任务状态时间显示 | 56f5183 |
|||
- | 任务进行中状态数字 | 27b7326 |
|||
- | 全局插件及默认插件位置修改 | 6c80d08 |
|||
- | 升级版本v3.1.0;tailwindcss添加class | 9ef05e1 |
|||
- | 向右箭头图标变化 | 8e9ca55 |
|||
- | 字体大小更改 | 82cfdd4 |
|||
- | 存token | b8a178d |
|||
- | 定期任务面板骨架屏添加 | b2698c0 |
|||
富文本插件 | 富文本插件demo测试 | ed3d644 |
|||
- | 导入wbs | 1224fcb |
|||
- | 导入项目,更新项目 | 5e06adf |
|||
- | 导入项目后提示并打开项目详情页 | 410f527 |
|||
- | 引入dayjs | 29b8b93 |
|||
- | 提交到本地 | 9cbe411 |
|||
- | 插件参数处理调整 | a3e68d3 |
|||
- | 插件数据获取 | 5b91bdc |
|||
- | 日历定位;合并 | ea3f937 |
|||
- | 日常任务插件调整 | c1881f9 |
|||
- | 时间基准线,默认插件 | a33ba1e |
|||
- | 时间轴修改状态时提示框增加 | e841392 |
|||
- | 时间轴界面 | 33927e9 |
|||
- | 标题栏变化 | 3898cfe |
|||
- | 标题栏变化 | c0fcd9d |
|||
- | 标题栏角色栏全局任务组件新建 | 0500cb4 |
|||
- | 模拟接口测试 | 69e7931 |
|||
- | 添加 环境变量,动态控制webview project的path | 8a40481 |
|||
- | 添加子任务插件 子项目插件 | 7bda7e2 |
|||
- | 添加时间轴上下滚动 | 2b81bbc |
|||
- | 添加项目排序 | a0b491b |
|||
- | 点击日历日期查询项目列表 | c458385 |
|||
- | 细节调整,添加project-webview | 4d9050b |
|||
- | 绑定手机号 | 52e0352 |
|||
- | 缓存修改 | 63e1f0d |
|||
- | 角色栏实现 | 94cd671 |
|||
- | 设置小红点 | 9316bcb |
|||
- | 距调整pc端 | 5069aa1 |
|||
- | 适配小程序;小程序登录 | cefc0eb |
|||
- | 配置默认插件接口 | f0c177d |
|||
- | 面变化首页变化 | 5e860f1 |
|||
- | 项目api url设置 | 6cd5245 |
|||
- | 项目列表, 项目url | 32e005b |
|||
- | 项目列表排序 | 224c58b |
|||
- | 首页项目样式改变 | 8514c85 |
|||
|
|||
|
|||
### 🎨 代码样式 |
|||
范围|描述|commitId |
|||
--|--|-- |
|||
- | calendar注释 | [a2ec112](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/a2ec112) |
|||
- | 代码审查 | [d75134c](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/d75134c) |
|||
- | 代码格式细节调整 | [cb2532b](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/cb2532b) |
|||
- | 任务快捷方式图标增加 | [4aba872](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/4aba872) |
|||
- | 修改角色样式 | [73e268e](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/73e268e) |
|||
- | 删除calendar中多余的console | [e339eec](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/e339eec) |
|||
- | 删除console.log | [5064a38](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/5064a38) |
|||
- | 删除index中没用的alert代码 | [9c9eec7](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/9c9eec7) |
|||
- | 删除mock,console;upload添加loading | [99d42e2](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/99d42e2) |
|||
- | 删除多余字段 | [5ae3973](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/5ae3973) |
|||
- | 删除插件携带的多余文件 | [0f392bb](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/0f392bb) |
|||
- | 删除没用代码 | [34b20e1](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/34b20e1) |
|||
- | 图标修改 | [54bca09](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/54bca09) |
|||
- | 无基本变化 | [21ac4bb](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/21ac4bb) |
|||
- | 日常任务修改 | [dfa7ee2](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/dfa7ee2) |
|||
- | 更新代码 | [8c27e68](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/8c27e68) |
|||
- | 更新代码 | [1f40a76](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/1f40a76) |
|||
- | 格式细节调整 | [b907a03](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/b907a03) |
|||
- | 添加插件数据 | [2f11b42](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/2f11b42) |
|||
- | 组件新建 | [89c0035](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/89c0035) |
|||
- | 细节调整 | [2cfc09a](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/2cfc09a) |
|||
- | calendar注释 | a2ec112 |
|||
- | indexedDB.js格式整理 | b0d3a36 |
|||
- | 代码审查 | d75134c |
|||
- | 代码格式细节调整 | cb2532b |
|||
- | 任务快捷方式图标增加 | 4aba872 |
|||
- | 修改角色样式 | 73e268e |
|||
- | 删除calendar中多余的console | e339eec |
|||
- | 删除console.log | 5064a38 |
|||
- | 删除index中没用的alert代码 | 9c9eec7 |
|||
- | 删除mock,console;upload添加loading | 99d42e2 |
|||
- | 删除多余字段 | 5ae3973 |
|||
- | 删除插件携带的多余文件 | 0f392bb |
|||
- | 删除没用代码 | 34b20e1 |
|||
- | 图标修改 | 54bca09 |
|||
- | 无基本变化 | 21ac4bb |
|||
- | 日常任务修改 | dfa7ee2 |
|||
- | 更新代码 | 8c27e68 |
|||
- | 更新代码 | 1f40a76 |
|||
- | 格式细节调整 | b907a03 |
|||
- | 添加插件数据 | 2f11b42 |
|||
- | 组件新建 | 89c0035 |
|||
- | 细节调整 | 2cfc09a |
|||
|
|||
|
|||
### 🐛 Bug 修复 |
|||
范围|描述|commitId |
|||
--|--|-- |
|||
- | 1.时间轴数据渲染 2.时间基准线 | [d643af2](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/d643af2) |
|||
ID1000343 | 解决向下预加载查询参数时间没+1颗粒度;以及滚动加载颗粒度写死的问题 | [940603a](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/940603a), closes [#ID1000343](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/issues/ID1000343) |
|||
plugin | 插件解析机制完善 | [0f5a27d](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/0f5a27d) |
|||
project title | 项目标题修改; 切换角色移除script | [5c20017](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/5c20017) |
|||
roles | 修复默认显示不是我的角色的问题 | [b69f94f](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/b69f94f) |
|||
role | 切换角色的逻辑修正完善 | [4ae534f](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/4ae534f) |
|||
task任务逻辑完善 | 减少初始global及regular的不必要请求 | [bd4bd38](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/bd4bd38) |
|||
- | title.vue根据页面栈显示返回按钮;标题文本超出显示... | [0cbacf4](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/0cbacf4) |
|||
- | 上下滑动加载定期任务 | [4090d89](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/4090d89) |
|||
- | 上下滚动时间轴 | [d533a01](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/d533a01) |
|||
- | 下拉加载定期任务传参,时间格式化修改 | [0b95a0e](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/0b95a0e) |
|||
- | 任务开始时间延迟插件 | [992a313](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/992a313) |
|||
- | 修改main | [749ae9a](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/749ae9a) |
|||
- | 修改定期任务状态0和4时不加载圆圈 | [30e352f](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/30e352f) |
|||
- | 修改小红点传参 | [87b20fd](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/87b20fd) |
|||
- | 修改报错 | [531c14d](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/531c14d) |
|||
- | 修改接口路径 | [df6acf2](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/df6acf2) |
|||
- | 修改角色栏组件 | [a54c601](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/a54c601) |
|||
- | 切换到默认项目角色没有激活状态的bug | [438d448](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/438d448) |
|||
- | 切换日历时查询小红点 | [7091789](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/7091789) |
|||
- | 初始展示角色修改 | [2ac4053](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/2ac4053) |
|||
- | 定期任务key值修改 | [c6688db](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/c6688db) |
|||
- | 定期任务接口 | [aa4981c](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/aa4981c) |
|||
- | 定期任务插件 | [92b3254](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/92b3254) |
|||
- | 定期任务未加载时,显示空的时间轴并能上下滑动 | [ce38093](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/ce38093) |
|||
- | 定期任务骨架屏修改 | [8ff72dd](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/8ff72dd) |
|||
- | 平车演示临时去掉项目快捷方式的toast提示 | [e0b2c23](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/e0b2c23) |
|||
- | 手动展开日常任务 | [0a4a622](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/0a4a622) |
|||
- | 提示信息显示bug及日常任务收缩问题 | [f2f06c5](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/f2f06c5) |
|||
- | 插件bug解决 | [41257eb](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/41257eb) |
|||
- | 收到消息修改任务状态 | [c378063](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/c378063) |
|||
- | 日历无任务时添加小绿点,时间轴刻度无任务不显示时分 | [0f90868](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/0f90868) |
|||
- | 日常任务html数据查验 | [880ce5c](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/880ce5c) |
|||
- | 日常任务插件遍历时的key值修改 | [cd26285](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/cd26285) |
|||
- | 日常任务插件面板高度修改 | [249f9e4](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/249f9e4) |
|||
- | 时间轴上下滑动 | [4d0ae46](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/4d0ae46) |
|||
- | 时间轴上下滚动数据加载bug修改 | [e82ede4](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/e82ede4) |
|||
- | 时间轴插件 | [225d3cc](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/225d3cc) |
|||
- | 时间轴无任务时时间刻度加载修改 | [4921672](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/4921672) |
|||
- | 时间轴滚动位置修改 | [551da63](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/551da63) |
|||
- | 时间轴骨架屏修改 | [ca78d02](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/ca78d02) |
|||
- | 监听时间基本点 | [033fca0](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/033fca0) |
|||
- | 角色显示状态修改 | [7d3b906](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/7d3b906) |
|||
- | 角色栏修改 | [19228d6](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/19228d6) |
|||
- | 解决时间轴报错 | [da1eece](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/da1eece) |
|||
- | 设置时间轴自动滚动到当前位置 | [a3474f8](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/a3474f8) |
|||
- | 跳转详情页返回路径修改 | [c5e17c0](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/c5e17c0) |
|||
- | 骨架屏替换 | [e9fdd71](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/e9fdd71) |
|||
- | 1.时间轴数据渲染 2.时间基准线 | d643af2 |
|||
- | api 存storage | 81032ba |
|||
ID1000343 | 解决向下预加载查询参数时间没+1颗粒度;以及滚动加载颗粒度写死的问题 | 940603a, closes #ID1000343 |
|||
plugin | 插件解析机制完善 | 0f5a27d |
|||
project title | 项目标题修改; 切换角色移除script | 5c20017 |
|||
roles | 修复默认显示不是我的角色的问题 | b69f94f |
|||
role | 切换角色的逻辑修正完善 | 4ae534f |
|||
task任务逻辑完善 | 减少初始global及regular的不必要请求 | bd4bd38 |
|||
- | title.vue根据页面栈显示返回按钮;标题文本超出显示... | 0cbacf4 |
|||
- | 上下滑动加载定期任务 | 4090d89 |
|||
- | 上下滚动时间轴 | d533a01 |
|||
- | 下拉加载定期任务传参,时间格式化修改 | 0b95a0e |
|||
- | 任务开始时间延迟插件 | 992a313 |
|||
- | 修改main | 749ae9a |
|||
- | 修改定期任务状态0和4时不加载圆圈 | 30e352f |
|||
- | 修改小红点传参 | 87b20fd |
|||
- | 修改报错 | 531c14d |
|||
- | 修改接口路径 | df6acf2 |
|||
- | 修改角色栏组件 | a54c601 |
|||
- | 切换到默认项目角色没有激活状态的bug | 438d448 |
|||
- | 切换日历时查询小红点 | 7091789 |
|||
- | 初始展示角色修改 | 2ac4053 |
|||
- | 定期任务key值修改 | c6688db |
|||
- | 定期任务接口 | aa4981c |
|||
- | 定期任务插件 | 92b3254 |
|||
- | 定期任务未加载时,显示空的时间轴并能上下滑动 | ce38093 |
|||
- | 定期任务本地缓存和api赋值,未完成 | 5a10856 |
|||
定期任务本地缓存和api赋值,未完成 | 定期任务本地缓存和api赋值,未完成 | b22a366 |
|||
- | 定期任务骨架屏修改 | 8ff72dd |
|||
- | 平车演示临时去掉项目快捷方式的toast提示 | e0b2c23 |
|||
- | 手动展开日常任务 | 0a4a622 |
|||
- | 提示信息显示bug及日常任务收缩问题 | f2f06c5 |
|||
- | 插件bug解决 | 41257eb |
|||
- | 收到消息修改任务状态 | c378063 |
|||
- | 日历无任务时添加小绿点,时间轴刻度无任务不显示时分 | 0f90868 |
|||
- | 日常任务html数据查验 | 880ce5c |
|||
- | 日常任务插件遍历时的key值修改 | cd26285 |
|||
- | 日常任务插件面板高度修改 | 249f9e4 |
|||
- | 时间轴上下滑动 | 4d0ae46 |
|||
- | 时间轴上下滚动数据加载bug修改 | e82ede4 |
|||
- | 时间轴插件 | 225d3cc |
|||
- | 时间轴无任务时时间刻度加载修改 | 4921672 |
|||
- | 时间轴滚动位置修改 | 551da63 |
|||
- | 时间轴骨架屏修改 | ca78d02 |
|||
- | 监听时间基本点 | 033fca0 |
|||
- | 角色显示状态修改 | 7d3b906 |
|||
- | 角色栏修改 | 19228d6 |
|||
- | 解决时间轴报错 | da1eece |
|||
- | 设置时间轴自动滚动到当前位置 | a3474f8 |
|||
- | 跳转详情页返回路径修改 | c5e17c0 |
|||
- | 项目列表排序修改 | fd3c3ac |
|||
- | 项目列表排序修改 | 59f4c21 |
|||
项目列表排序 | 项目列表排序 | 402c563 |
|||
- | 骨架屏替换 | e9fdd71 |
|||
|
|||
|
|||
### 📝 文档 |
|||
范围|描述|commitId |
|||
--|--|-- |
|||
- | README.md | [ab0eb05](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/ab0eb05) |
|||
- | README.md | ab0eb05 |
|||
|
|||
|
|||
### 🔧 测试 |
|||
范围|描述|commitId |
|||
--|--|-- |
|||
- | 暂时移除了jest浏览器配置 | [5088d01](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/5088d01) |
|||
- | 添加测试,测试utils/time.js的computeDurationText | [e758010](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/e758010) |
|||
- | 禁用任务开始操作 | [b5425db](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/b5425db) |
|||
- | 暂时移除了jest浏览器配置 | 5088d01 |
|||
- | 添加测试,测试utils/time.js的computeDurationText | e758010 |
|||
- | 禁用任务开始操作 | b5425db |
|||
|
|||
|
|||
### 🔨 代码重构 |
|||
范围|描述|commitId |
|||
--|--|-- |
|||
calendar | 日历细节调整 | [1a8d6bf](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/1a8d6bf) |
|||
- | project 代码健壮性完善 | [a3202c5](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/a3202c5) |
|||
store/home | 删除store/home | [db8a3b4](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/db8a3b4) |
|||
task beginTime | 格式化任务开始时间 | [fbc0301](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/fbc0301) |
|||
template | eslint prettier sass uview tailwindcss | [9c966a1](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/9c966a1) |
|||
tips | 修改任务状态方法重构 | [b57d3ac](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/b57d3ac) |
|||
tip | 任务状态显示及tip组件数据的重构 | [78a5750](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/78a5750) |
|||
title.vue | 移除测试的repeat; 样式细节调整 | [c32d2bd](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/c32d2bd) |
|||
- | 下滑时间轴添加备注 | [4fd20e3](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/4fd20e3) |
|||
- | 任务状态重构 | [4693655](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/4693655) |
|||
- | 删除多余的weekmode store里的东西 | [0841fe0](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/0841fe0) |
|||
- | 删除多余的技术验证界面 | [542ae5b](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/542ae5b) |
|||
- | 界面样式调整 | [4367249](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/4367249) |
|||
- | 重构store分层 | [5f6fff8](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/5f6fff8) |
|||
calendar | 日历细节调整 | 1a8d6bf |
|||
- | project 代码健壮性完善 | a3202c5 |
|||
store/home | 删除store/home | db8a3b4 |
|||
task beginTime | 格式化任务开始时间 | fbc0301 |
|||
template | eslint prettier sass uview tailwindcss | 9c966a1 |
|||
tips | 修改任务状态方法重构 | b57d3ac |
|||
tip | 任务状态显示及tip组件数据的重构 | 78a5750 |
|||
title.vue | 移除测试的repeat; 样式细节调整 | c32d2bd |
|||
- | 下滑时间轴添加备注 | 4fd20e3 |
|||
- | 任务状态重构 | 4693655 |
|||
- | 删除多余的weekmode store里的东西 | 0841fe0 |
|||
- | 删除多余的技术验证界面 | 542ae5b |
|||
- | 去掉tailwindcss | 4bed47e |
|||
- | 界面样式调整 | 4367249 |
|||
- | 重构store分层 | 5f6fff8 |
|||
|
|||
|
|||
### 🚀 性能优化 |
|||
范围|描述|commitId |
|||
--|--|-- |
|||
- | 1.时间轴筛选相同的时间替换数据 2.整理代码 | [e082ccb](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/e082ccb) |
|||
- | 修改代码格式 | [14123d7](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/14123d7) |
|||
- | 修改定期任务骨架屏高度 | [909a734](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/909a734) |
|||
- | 插件查询及展示 | [4dba770](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/4dba770) |
|||
- | 整理代码 | [7a55315](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/7a55315) |
|||
- | 日历的更改 | [7353ac8](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/7353ac8) |
|||
- | 测试接口 | [215e074](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/215e074) |
|||
- | 组件文件夹新建 | [22bfe7b](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/22bfe7b) |
|||
- | 组件文件夹新建 | [17bb8c9](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/17bb8c9) |
|||
- | 组件文件夹新建 | [1421504](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/1421504) |
|||
- | 角色栏文字颜色修改 | [215c6b3](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/215c6b3) |
|||
- | 解决警告 | [c932b09](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/c932b09) |
|||
- | 1.时间轴筛选相同的时间替换数据 2.整理代码 | e082ccb |
|||
- | 修改代码格式 | 14123d7 |
|||
- | 修改定期任务骨架屏高度 | 909a734 |
|||
- | 小红点api缓存修改 | e992343 |
|||
- | 插件查询及展示 | 4dba770 |
|||
- | 整理代码 | 7a55315 |
|||
- | 日历的更改 | 7353ac8 |
|||
- | 测试接口 | 215e074 |
|||
- | 组件文件夹新建 | 22bfe7b |
|||
- | 组件文件夹新建 | 17bb8c9 |
|||
- | 组件文件夹新建 | 1421504 |
|||
- | 角色栏文字颜色修改 | 215c6b3 |
|||
- | 解决警告 | c932b09 |
|||
|
|||
|
|||
### chore |
|||
范围|描述|commitId |
|||
--|--|-- |
|||
- | api 封装 | [8dcb8a2](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/8dcb8a2) |
|||
- | env host修改 | [a79a4a5](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/a79a4a5) |
|||
- | merge globals | [b0957cc](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/b0957cc) |
|||
- | merge wrr | [5ccc7a5](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/5ccc7a5) |
|||
- | mock | [51c24a5](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/51c24a5) |
|||
package manifest | 去掉了摇树 | [f7c1dd4](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/f7c1dd4) |
|||
pwa 小程序 | 移除了pwa,alloyFinger添加平台判断 | [875fab4](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/875fab4) |
|||
- | uview-ui | [a9ea34b](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/a9ea34b) |
|||
v3.0.1 | tall api 地址从1.0改成了3.0 | [db5afd5](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/db5afd5) |
|||
信息配置 | 配置eslint等配置 | [7421443](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/7421443) |
|||
- | 修复不能build的问题 | [0b7b91e](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/0b7b91e) |
|||
- | 删除多余的构建的命令 | [3f4eb2f](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/3f4eb2f) |
|||
- | api 封装 | 8dcb8a2 |
|||
- | dart-sass替换node-sass;删除多余的uni平台包 | 519f28b |
|||
- | env host修改 | a79a4a5 |
|||
- | merge globals | b0957cc |
|||
- | merge wrr | 5ccc7a5 |
|||
- | mock | 51c24a5 |
|||
package manifest | 去掉了摇树 | f7c1dd4 |
|||
pwa 小程序 | 移除了pwa,alloyFinger添加平台判断 | 875fab4 |
|||
- | uview-ui | a9ea34b |
|||
v3.0.1 | tall api 地址从1.0改成了3.0 | db5afd5 |
|||
信息配置 | 配置eslint等配置 | 7421443 |
|||
- | 修复不能build的问题 | 0b7b91e |
|||
- | 删除多余的构建的命令 | 3f4eb2f |
|||
|
|||
|
|||
范围|描述|commitId |
|||
--|--|-- |
|||
- | style:index | [978f272](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/978f272) |
|||
- | !2 基础模板v1.1.0 | [f5e61dd](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/f5e61dd) |
|||
- | init | [c0f1deb](https://dd.tall.wiki/gitea/ccsens_fe/TALL-MUI-3/commits/c0f1deb) |
|||
- | style:index | 978f272 |
|||
- | !2 基础模板v1.1.0 | f5e61dd |
|||
- | init | c0f1deb |
|||
|
|||
|
@ -1,11 +0,0 @@ |
|||
{ // launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/ |
|||
// launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数 |
|||
"version": "0.0", |
|||
"configurations": [{ |
|||
"type": "uniCloud", |
|||
"default": { |
|||
"launchtype": "local" |
|||
} |
|||
} |
|||
] |
|||
} |
@ -1,14 +0,0 @@ |
|||
// 插件的地址是固定的
|
|||
const url = process.env.VUE_APP_API_URL; |
|||
|
|||
const install = (Vue, vm) => { |
|||
vm.$u.api = { ...vm.$u.api } || {}; |
|||
// 获取插件信息
|
|||
vm.$u.api.getOtherPlugin = param => vm.$u.post(`${url}/pluginshop/plugin/query`, param); |
|||
// 查询子任务
|
|||
vm.$u.api.findSonTask = param => vm.$u.post(`${uni.$t.domain}/task/findSonTask`, param); |
|||
// 查询子项目
|
|||
vm.$u.api.findSonProject = param => vm.$u.post(`${uni.$t.domain}/project/findSonProject`, param); |
|||
}; |
|||
|
|||
export default { install }; |
@ -1,7 +0,0 @@ |
|||
const install = (Vue, vm) => { |
|||
vm.$u.api = { ...vm.$u.api } || {}; |
|||
//根据id获取项目信息
|
|||
vm.$u.api.findProjectById = param => vm.$u.post(`${uni.$t.domain}/project/findProjectById`, param); |
|||
}; |
|||
|
|||
export default { install }; |
@ -1,7 +0,0 @@ |
|||
const install = (Vue, vm) => { |
|||
vm.$u.api = { ...vm.$u.api } || {}; |
|||
//根据时间基准点和角色查找定期任务
|
|||
vm.$u.api.findShowRole = param => vm.$u.post(`${uni.$t.domain}/role/show`, param); |
|||
}; |
|||
|
|||
export default { install }; |
@ -1,14 +1,44 @@ |
|||
const apiUrl = process.env.VUE_APP_API_URL; |
|||
const tall = `${apiUrl}/tall3/v3.0`; |
|||
export const tall = `${apiUrl}/tall3/v3.0`; |
|||
|
|||
import { mp } from '@/config/user.js'; |
|||
|
|||
// 登录
|
|||
export const login = { |
|||
async index(params) { |
|||
try { |
|||
/* #ifdef MP-WEIXIN */ |
|||
params = await mp(); |
|||
/* #endif */ |
|||
const data = await uni.$u.http.post(`${tall}/users/signin`, params); |
|||
return data; |
|||
} catch (error) { |
|||
throw new Error(error); |
|||
} |
|||
}, |
|||
}; |
|||
|
|||
const install = (Vue, vm) => { |
|||
vm.$u.api = { ...vm.$u.api } || {}; |
|||
// 登录
|
|||
vm.$u.api.signin = params => login.index(params); |
|||
// 获取图片验证码
|
|||
vm.$u.api.getImageCode = () => vm.$u.get(`${tall}/users/code`); |
|||
// 获取短信验证码
|
|||
vm.$u.api.getSmsCode = params => vm.$u.get(`${tall}/users/smscode`, params); |
|||
// 根据userId获取token
|
|||
vm.$u.api.getToken = userId => vm.$u.get(`${tall}/users/userId`, { userId }); |
|||
// 绑定手机号
|
|||
vm.$u.api.phoneBind = (phone, smsCode) => vm.$u.http.post(`${tall}/users/binding`, { phone, smsCode }); |
|||
|
|||
// 获取项目列表
|
|||
vm.$u.api.getProjects = (startTime, endTime) => vm.$u.post(`${tall}/project/query`, { startTime, endTime }); |
|||
// 查询日历是否有小红点
|
|||
vm.$u.api.findRedPoint = (startTime, endTime) => vm.$u.post(`${tall}/project/day`, { startTime, endTime }); |
|||
// 设置项目顺序
|
|||
vm.$u.api.setProjectSort = params => vm.$u.post(`${tall}/project/setProjectSort`, params); |
|||
// 设置项目父子结构
|
|||
vm.$u.api.setProjectRelation = params => vm.$u.post(`${tall}/project/setProjectRelation`, params); |
|||
}; |
|||
|
|||
export default { install }; |
|||
|
@ -1,11 +0,0 @@ |
|||
const install = (Vue, vm) => { |
|||
vm.$u.api = { ...vm.$u.api } || {}; |
|||
vm.$u.api.getGlobal = param => vm.$u.post(`${uni.$t.domain}/task/global`, param); |
|||
vm.$u.api.getPermanent = param => vm.$u.post(`${uni.$t.domain}/task/permanent`, param); |
|||
//根据时间基准点和角色查找定期任务
|
|||
vm.$u.api.getRegularTask = param => vm.$u.post(`${uni.$t.domain}/task/regular`, param); |
|||
//修改任务状态
|
|||
vm.$u.api.updateTaskType = param => vm.$u.post(`${uni.$t.domain}/task/type`, param); |
|||
}; |
|||
|
|||
export default { install }; |
@ -1,6 +0,0 @@ |
|||
/* ./src/common/styles/index.css */ |
|||
|
|||
/*! @import */ |
|||
@tailwind base; |
|||
@tailwind components; |
|||
@tailwind utilities; |
File diff suppressed because it is too large
@ -1,94 +0,0 @@ |
|||
<template> |
|||
<view class="m-2" v-if="globals && globals.length"> |
|||
<u-card |
|||
@click="openCard" |
|||
:show-foot="false" |
|||
:show-head="false" |
|||
:style="{ 'max-height': isShrink ? '106rpx' : '340rpx' }" |
|||
border-radius="25" |
|||
margin="0" |
|||
> |
|||
<view slot="body"> |
|||
<scroll-view :scrollY="true" :style="{ 'max-height': isShrink ? '50rpx' : '280rpx' }"> |
|||
<skeleton :banner="false" :loading="!globals.length" :row="4" animate class="u-line-2 skeleton"></skeleton> |
|||
<view class="grid gap-2"> |
|||
<template v-for="item in globals"> |
|||
<template v-if="item.plugins"> |
|||
<template v-for="pluginArr in item.plugins"> |
|||
<template class="p-0 u-col-between" v-if="pluginArr.length"> |
|||
<Plugin |
|||
:class="getClass(plugin.col, plugin.row)" |
|||
:task="item" |
|||
:key="plugin.pluginTaskId" |
|||
:plugin-task-id="plugin.pluginTaskId" |
|||
:plugin-id="plugin.pluginId" |
|||
:style-type="plugin.styleType || 0" |
|||
v-for="plugin in pluginArr" |
|||
/> |
|||
</template> |
|||
</template> |
|||
</template> |
|||
</template> |
|||
</view> |
|||
</scroll-view> |
|||
</view> |
|||
</u-card> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapGetters, mapMutations, mapState } from 'vuex'; |
|||
import Skeleton from '@/components/Skeleton/Skeleton'; |
|||
|
|||
export default { |
|||
name: 'Global', |
|||
components: { Skeleton }, |
|||
|
|||
data() { |
|||
return { |
|||
// loading: true, |
|||
task: null, |
|||
}; |
|||
}, |
|||
|
|||
computed: { |
|||
...mapState('task', ['isShrink']), |
|||
...mapGetters('task', ['globals']), |
|||
}, |
|||
|
|||
methods: { |
|||
...mapMutations('task', ['setShrink']), |
|||
getClass(col, row) { |
|||
return [`row-span-${row}`, `col-span-${col}`]; |
|||
}, |
|||
|
|||
// 手动展开日常任务 |
|||
openCard() { |
|||
if (this.isShrink) { |
|||
this.setShrink(false); |
|||
} |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped lang="scss"> |
|||
.u-card-wrap { |
|||
background-color: $u-bg-color; |
|||
padding: 1px; |
|||
} |
|||
|
|||
.u-body-item { |
|||
font-size: 32rpx; |
|||
color: #333; |
|||
padding: 20rpx 10rpx; |
|||
} |
|||
|
|||
.u-body-item image { |
|||
width: 120rpx; |
|||
flex: 0 0 120rpx; |
|||
height: 120rpx; |
|||
border-radius: 8rpx; |
|||
margin-left: 12rpx; |
|||
} |
|||
</style> |
@ -0,0 +1,37 @@ |
|||
<template> |
|||
<!-- TODO: 设置默认图片 --> |
|||
<image :src="src" mode="aspectFit" class="image" @click="getCode"></image> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { src: '' }; |
|||
}, |
|||
|
|||
created() { |
|||
this.getCode(); |
|||
}, |
|||
|
|||
methods: { |
|||
// 获取图形验证码 |
|||
async getCode() { |
|||
try { |
|||
const data = await this.$u.api.getImageCode(); |
|||
const { imageBase64, verificationCodeId } = data; |
|||
this.src = imageBase64; |
|||
this.$emit('on-code', verificationCodeId); |
|||
} catch (error) { |
|||
console.error('error: ', error); |
|||
} |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.image { |
|||
width: 100px !important; |
|||
height: 35px !important; |
|||
} |
|||
</style> |
@ -1,136 +0,0 @@ |
|||
<template> |
|||
<view class="u-font-14" style="height: 100%"> |
|||
<view v-if="pluginContent"> |
|||
<view |
|||
style="height: 100%" |
|||
:data-uid="userId" |
|||
:data-token="token" |
|||
:data-pid="projectId" |
|||
:data-did="task.detailId" |
|||
:data-rid="roleId" |
|||
:data-tid="task.id" |
|||
:data-tname="task.name" |
|||
:data-pstart="task.planStart" |
|||
:data-rstart="task.realStart" |
|||
:data-pdu="task.planDuration" |
|||
:data-rdu="task.realDuration" |
|||
:data-param="param" |
|||
v-html="pluginContent" |
|||
></view> |
|||
</view> |
|||
|
|||
<view v-else> |
|||
<!-- <plugin-default /> --> |
|||
<!-- <component :task="task" :is="pluginComponent"></component> --> |
|||
<p-task-title :task="task" v-if="pluginId === '1'" /> |
|||
<p-task-description :task="task" v-if="pluginId === '2'" /> |
|||
<p-task-duration-delay :task="task" v-if="pluginId === '3'" /> |
|||
<p-task-start-time-delay :task="task" v-if="pluginId === '4'" /> |
|||
<!-- <p-deliverable :task="task" v-if="pluginId === '5'" /> --> |
|||
<p-subtasks :task="task" v-if="pluginId === '6'" /> |
|||
<p-subproject :task="task" v-if="pluginId === '7'" /> |
|||
<!-- <p-task-countdown :task="task" v-if="pluginId === '8'" /> --> |
|||
<p-manage-project :task="task" v-if="pluginId === '9'" /> |
|||
<p-manage-role :task="task" v-if="pluginId === '10'" /> |
|||
<p-manage-member :task="task" v-if="pluginId === '11'" /> |
|||
<p-manage-task :task="task" v-if="pluginId === '12'" /> |
|||
<p-wbs-import :task="task" v-if="pluginId === '13' || pluginId === '14'" /> |
|||
<p-deliver-check :task="task" v-if="pluginId === '15'" /> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapGetters, mapState } from 'vuex'; |
|||
import pManageProject from '../../plugins/p-manage-project/p-manage-project.vue'; |
|||
|
|||
export default { |
|||
components: { pManageProject }, |
|||
name: 'Plugin', |
|||
props: { |
|||
task: { default: () => {}, type: Object }, |
|||
pluginId: { default: '1', type: String }, |
|||
styleType: { default: 0, type: Number }, |
|||
pluginTaskId: { default: '', type: String }, |
|||
param: { type: String, default: '' }, |
|||
}, |
|||
|
|||
data() { |
|||
return { pluginContent: null }; |
|||
}, |
|||
|
|||
computed: { |
|||
...mapState('role', ['roleId']), |
|||
...mapState('user', ['token']), |
|||
...mapGetters('user', ['userId']), |
|||
...mapGetters('project', ['projectId']), |
|||
|
|||
// 插件名称 |
|||
// pluginComponent() { |
|||
// const target = this.$t.plugin.defaults.find(item => item.id === +this.pluginId); |
|||
// if (!target) return ''; |
|||
// return target.component; |
|||
// }, |
|||
}, |
|||
|
|||
created() { |
|||
this.getPlugin(); |
|||
}, |
|||
|
|||
methods: { |
|||
// 获取插件信息 |
|||
async getPlugin() { |
|||
const { pluginId, styleType } = this; |
|||
const data = await this.$u.api.getOtherPlugin({ |
|||
pluginId, |
|||
styleType, |
|||
}); |
|||
if (!data || !data.id) return; |
|||
const reg = /data-root=["|']?(\w+)["|']?/gi; |
|||
let uuid = ''; |
|||
// FIXME: 没有兼容 只有js, 没有html的情况 |
|||
if (data.html) { |
|||
// 查有没有data-root=“xxx” 有的话 将xxx替换为 pluginTaskId |
|||
|
|||
if (reg.test(data.html)) { |
|||
uuid = RegExp.$1; |
|||
const str = data.html.replace(new RegExp(uuid, 'g'), `p${this.pluginTaskId}`); |
|||
this.pluginContent = str; |
|||
} else { |
|||
this.pluginContent = data.html; |
|||
} |
|||
|
|||
const str = data.js.replace(new RegExp(uuid, 'g'), `p${this.pluginTaskId}`); |
|||
this.handleDom(str); |
|||
} |
|||
|
|||
// if (data.js) { |
|||
// if (reg.test(data.js)) { |
|||
// const uuid = RegExp.$1; |
|||
// const str = data.js.replace(new RegExp(uuid, 'g'), `p${this.pluginTaskId}`); |
|||
// this.handleDom(str); |
|||
// } else { |
|||
// this.handleDom(data.js); |
|||
// } |
|||
// } |
|||
}, |
|||
|
|||
// 创建script dom |
|||
handleDom(js) { |
|||
const { pluginTaskId } = this; |
|||
let domList = Array.from(document.getElementsByTagName('script')); |
|||
const index = domList.findIndex(item => item.id === `p${pluginTaskId}`); |
|||
if (index >= 0) { |
|||
document.body.removeChild(document.getElementById(`p${pluginTaskId}`)); |
|||
} |
|||
const scriptDom = document.createElement('script'); |
|||
scriptDom.id = `p${pluginTaskId}`; |
|||
scriptDom.setAttribute('data-type', 'plugin'); |
|||
scriptDom.innerHTML = js; |
|||
this.$nextTick(() => { |
|||
document.body.append(scriptDom); |
|||
}); |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
@ -0,0 +1,480 @@ |
|||
<template> |
|||
<view> |
|||
<scroll-view scroll-y="true"> |
|||
<view v-if="!changeEvent"> |
|||
<view :id="'cu-' + index" :key="item.id" class="cu-item flex-col" v-for="(item, index) in itemList"> |
|||
<ProjectItem |
|||
class="w-full" |
|||
:index="index" |
|||
:item="item" |
|||
:menuList="menuList" |
|||
@chooseAction="chooseAction" |
|||
@openSubProject="openSubProject" |
|||
/> |
|||
</view> |
|||
</view> |
|||
<view v-else> |
|||
<view |
|||
:id="'cu-' + index" |
|||
:key="index" |
|||
:style="{ 'background-color': item.color }" |
|||
@touchend="stops($event, index)" |
|||
@touchmove.stop.prevent="move" |
|||
@touchstart="start($event, index)" |
|||
class="cu-item flex-col" |
|||
v-for="(item, index) in itemList" |
|||
> |
|||
<view class="border-100 bg-blue-500" v-if="item.showTopBorder"></view> |
|||
<!-- 内容区 --> |
|||
<!-- 父项目 --> |
|||
<view class="w-full"> |
|||
<view class="flex items-center justify-between p-3"> |
|||
<u-icon class="mover" name="https://www.tall.wiki/staticrec/drag.svg" size="48"></u-icon> |
|||
|
|||
<view class="flex-1 px-3"> |
|||
<view class="flex items-center mb-1"> |
|||
<view class="mr-2">{{ item.name }}</view> |
|||
<!-- 状态 TODO:--> |
|||
<view class="px-2 text-xs text-green-400 bg-green-100 rounded-full">进行中</view> |
|||
</view> |
|||
|
|||
<view class="flex items-center text-xs text-gray-400"> |
|||
<view class="pr-2">{{ $moment(+item.startTime).format('MM-DD HH:mm') }}</view> |
|||
至 |
|||
<view class="pl-2">{{ $moment(+item.endTime).format('MM-DD HH:mm') }}</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 箭头 --> |
|||
<view v-if="item.sonProjectList && item.sonProjectList.length"> |
|||
<u-icon |
|||
@click="openSubProject(item.sonProjectList.length, index)" |
|||
class="text-gray-400" |
|||
name="arrow-up" |
|||
size="14px" |
|||
v-if="item.show" |
|||
></u-icon> |
|||
<u-icon |
|||
@click="openSubProject(item.sonProjectList.length, index)" |
|||
class="text-gray-400" |
|||
name="arrow-down" |
|||
size="14px" |
|||
v-else |
|||
></u-icon> |
|||
</view> |
|||
<u-icon class="text-gray-400" name="arrow-right" size="14px" v-else></u-icon> |
|||
</view> |
|||
<!-- 父项目 end --> |
|||
<!-- 子项目 --> |
|||
<view class="ml-8" v-if="item.show"> |
|||
<view |
|||
:id="'cu-' + index + '-' + subIndex" |
|||
:key="subIndex" |
|||
@touchend.stop.prevent="stops($event, index + '-' + subIndex, item.sonProjectList.length)" |
|||
@touchmove.stop.prevent="move($event, item.sonProjectList.length)" |
|||
@touchstart.stop.prevent="start($event, index + '-' + subIndex)" |
|||
class="cu-item flex-col" |
|||
v-for="(subItem, subIndex) in item.sonProjectList" |
|||
> |
|||
<view class="flex items-center justify-between p-3 w-full"> |
|||
<u-icon class="mover" name="https://www.tall.wiki/staticrec/drag.svg" size="48"></u-icon> |
|||
|
|||
<view class="flex-1 px-3"> |
|||
<view class="flex items-center"> |
|||
<view class="mr-2">{{ subItem.name }}</view> |
|||
<!-- 状态 --> |
|||
<view |
|||
:class=" |
|||
subItem.status === 0 |
|||
? 'text-blue-400 bg-blue-100' |
|||
: subItem.status === 1 |
|||
? 'text-green-400 bg-green-100' |
|||
: subItem.status === 2 |
|||
? 'text-red-400 bg-red-100' |
|||
: 'text-gray-400 bg-gray-100' |
|||
" |
|||
class="px-2 text-xs text-gray-400 bg-gray-100 rounded-full" |
|||
> |
|||
{{ subItem.status === 0 ? '未开始' : subItem.status === 1 ? '进行中' : subItem.status === 2 ? '暂停' : '已完成' }} |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 箭头 --> |
|||
<u-icon class="text-gray-400" name="arrow-right" size="14px"></u-icon> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- 内容区 end --> |
|||
<view class="border-100 bg-blue-500" v-if="item.showBorder"></view> |
|||
<view class="border-80 bg-blue-500" v-if="item.showSubBorder"></view> |
|||
</view> |
|||
</view> |
|||
</scroll-view> |
|||
<!-- 移动悬浮 begin --> |
|||
<view v-if="showMoveImage"> |
|||
<view :style="{ left: moveLeft + 'px', top: moveTop + 'px' }" class="cu-item absolute"> |
|||
<ProjectItem class="w-full" :item="moveItem" /> |
|||
</view> |
|||
</view> |
|||
<!-- 移动悬浮 end --> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import ProjectItem from '../Projects/ProjectItem.vue'; |
|||
import { mapState, mapGetters, mapMutations } from 'vuex'; |
|||
|
|||
export default { |
|||
components: { ProjectItem }, |
|||
name: 'exchange', |
|||
model: { prop: 'showPop', event: 'change' }, |
|||
|
|||
data() { |
|||
return { |
|||
itemTop: 0, |
|||
itemLeft: 0, |
|||
itemHeight: 0, // 移动元素的高度 |
|||
subItemHeight: 0, // 移动子元素的高度 |
|||
itemWidth: 0, // 移动元素的宽度 |
|||
showMoveImage: false, |
|||
moveItem: '', |
|||
moveLeft: 0, |
|||
moveTop: 0, |
|||
deltaLeft: 0, |
|||
deltaTop: 0, |
|||
beginleft: 0, |
|||
begintop: 0, |
|||
itemList: [], |
|||
setSubItem: false, |
|||
changeEvent: false, |
|||
|
|||
showMenu: false, |
|||
tips: { |
|||
text: '', |
|||
color: '#909399', |
|||
fontSize: 28, |
|||
}, |
|||
menuList: [{ text: '复制' }, { text: '编辑' }, { text: '删除' }, { text: '置顶' }, { text: '排序' }], |
|||
// show: false, |
|||
border: 'border border-blue-500 shadow rounded-md', |
|||
showBorder: false, |
|||
showItemIndex: undefined, |
|||
}; |
|||
}, |
|||
|
|||
computed: { |
|||
...mapGetters('user', ['userId']), |
|||
...mapState('project', ['projects']), |
|||
|
|||
eventName() { |
|||
if (this.changeEvent) { |
|||
return 'move.stop.prevent'; |
|||
} else { |
|||
return 'move'; |
|||
} |
|||
}, |
|||
}, |
|||
|
|||
mounted() { |
|||
this.$nextTick(function () { |
|||
this.itemList = this.projects; |
|||
this.itemList.forEach(item => { |
|||
item.showBorder = false; |
|||
item.showSubBorder = false; |
|||
item.showTopBorder = false; |
|||
}); |
|||
}); |
|||
}, |
|||
|
|||
watch: { |
|||
projects(val) { |
|||
this.itemList = val; |
|||
this.itemList.forEach(item => { |
|||
item.showBorder = false; |
|||
item.showSubBorder = false; |
|||
item.showTopBorder = false; |
|||
}); |
|||
}, |
|||
}, |
|||
|
|||
methods: { |
|||
...mapMutations('project', ['setProjectItemShow']), |
|||
// 展开子项目 |
|||
openSubProject(length, index) { |
|||
this.setProjectItemShow({ index, show: this.itemList[index].show ? false : true }); |
|||
if (length && index) { |
|||
this.$emit('changeHeight', length, index); |
|||
} |
|||
this.showItemIndex = index; |
|||
}, |
|||
|
|||
// 获取项目列表距离顶部的距离 |
|||
getDate() { |
|||
const query = uni.createSelectorQuery().in(this); |
|||
query |
|||
.select(`#cu-0`) |
|||
.boundingClientRect(data => { |
|||
console.log('data: ', data); |
|||
this.begintop = data.top; |
|||
this.beginleft = data.left; |
|||
}) |
|||
.exec(); |
|||
}, |
|||
|
|||
// 操作 |
|||
chooseAction(index) { |
|||
if (this.menuList[index].text === '排序') { |
|||
this.changeEvent = true; |
|||
this.$t.ui.showToast('请移动进行排序'); |
|||
} |
|||
|
|||
if (this.showItemIndex !== undefined) { |
|||
this.setProjectItemShow({ index: this.showItemIndex, show: true }); |
|||
} |
|||
}, |
|||
|
|||
isNumber(val) { |
|||
return val === +val; |
|||
}, |
|||
|
|||
start(e, index) { |
|||
console.log('开始', e); |
|||
setTimeout(() => { |
|||
this.getDate(); |
|||
}, 300); |
|||
|
|||
if (this.isNumber(index)) { |
|||
this.setSubItem = false; |
|||
const query = uni.createSelectorQuery().in(this); |
|||
query |
|||
.select(`#cu-${index}`) |
|||
.boundingClientRect(data => { |
|||
this.moveTop = data.top; |
|||
this.moveLeft = data.left; |
|||
this.moveItem = this.itemList[index]; |
|||
this.itemWidth = data.width; |
|||
this.itemHeight = data.height; |
|||
}) |
|||
.exec(); |
|||
} else { |
|||
let arr = index.split('-'); |
|||
this.setSubItem = true; |
|||
const query = uni.createSelectorQuery().in(this); |
|||
query |
|||
.select(`#cu-${arr[0] - 0}`) |
|||
.boundingClientRect(data => { |
|||
this.itemHeight = data.height; |
|||
}) |
|||
.exec(); |
|||
|
|||
query |
|||
.select(`#cu-${index}`) |
|||
.boundingClientRect(data => { |
|||
this.moveTop = data.top; |
|||
this.moveLeft = data.left; |
|||
this.moveItem = this.itemList[arr[0] - 0].sonProjectList[arr[1] - 0]; |
|||
this.itemWidth = data.width; |
|||
this.subItemHeight = data.height; |
|||
}) |
|||
.exec(); |
|||
} |
|||
}, |
|||
|
|||
move(e, length) { |
|||
console.log('移动'); |
|||
this.showMoveImage = true; //悬浮开始 |
|||
const touch = e.touches[0]; |
|||
if (this.deltaLeft == 0) { |
|||
// 获得本身的移动 |
|||
this.deltaLeft = touch.pageX - this.moveLeft; |
|||
this.deltaTop = touch.pageY - this.moveTop; |
|||
} |
|||
this.moveLeft = touch.pageX - this.deltaLeft; |
|||
this.moveTop = touch.pageY - this.deltaTop; |
|||
|
|||
let lastIndex = (lastIndex = this.findOverIndex(touch.pageY, length)); |
|||
// 显示下划线 |
|||
for (let i = 0; i < this.itemList.length; i++) { |
|||
if (this.moveLeft > 35) { |
|||
this.itemList[i].showBorder = false; |
|||
this.itemList[i].showTopBorder = false; |
|||
if (i === lastIndex) { |
|||
this.itemList[i].showSubBorder = true; |
|||
} else { |
|||
this.itemList[i].showSubBorder = false; |
|||
} |
|||
} else { |
|||
if (lastIndex === -1) { |
|||
this.itemList[0].showTopBorder = true; |
|||
this.itemList[i].showSubBorder = false; |
|||
this.itemList[i].showBorder = false; |
|||
} else { |
|||
this.itemList[i].showSubBorder = false; |
|||
this.itemList[i].showTopBorder = false; |
|||
if (i === lastIndex) { |
|||
this.itemList[i].showBorder = true; |
|||
} else { |
|||
this.itemList[i].showBorder = false; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
|
|||
stops(e, index, length) { |
|||
console.log('结束'); |
|||
const touch = e.mp.changedTouches[0]; |
|||
let lastIndex = (lastIndex = this.findOverIndex(touch.pageY, length)); |
|||
|
|||
// 交换两个值 |
|||
for (let i = 0; i < this.itemList.length; i++) { |
|||
// 插入顶部 |
|||
if (this.itemList[i].showTopBorder) { |
|||
if (this.isNumber(index)) { |
|||
let Value = this.itemList[index]; |
|||
this.itemList.unshift(Value); |
|||
this.itemList.splice(index + 1, 1); |
|||
} else { |
|||
let arr = index.split('-'); |
|||
let Value = this.itemList[arr[0] - 0].sonProjectList[arr[1] - 0]; |
|||
this.itemList.unshift(Value); |
|||
this.itemList[arr[0] - 0].sonProjectList.splice([arr[1] - 0], 1); |
|||
const options = { |
|||
id: Value.id, |
|||
parentId: 0, |
|||
}; |
|||
this.$emit('change', options); |
|||
} |
|||
// 清空 |
|||
this.clearSet(i); |
|||
this.$emit('change', this.itemList); |
|||
return; |
|||
} |
|||
// 插入一级项目 |
|||
if (this.itemList[i].showBorder) { |
|||
if (this.isNumber(index)) { |
|||
let Value = this.itemList[index]; |
|||
this.itemList.splice(i + 1, 0, Value); |
|||
if (i < index) { |
|||
this.itemList.splice(index + 1, 1); |
|||
} else { |
|||
this.itemList.splice(index, 1); |
|||
} |
|||
} else { |
|||
let arr = index.split('-'); |
|||
let Value = this.itemList[arr[0] - 0].sonProjectList[arr[1] - 0]; |
|||
this.itemList.splice(i + 1, 0, Value); |
|||
this.itemList[arr[0] - 0].sonProjectList.splice([arr[1] - 0], 1); |
|||
const options = { |
|||
id: Value.id, |
|||
parentId: 0, |
|||
}; |
|||
this.$emit('change', options); |
|||
} |
|||
// 清空 |
|||
this.clearSet(i); |
|||
this.$emit('change', this.itemList); |
|||
return; |
|||
} |
|||
// 插入二级项目 |
|||
if (this.itemList[i].showSubBorder) { |
|||
if (this.isNumber(index)) { |
|||
let Value = this.itemList[index]; |
|||
if (this.itemList[lastIndex - 1].sonProjectList && this.itemList[lastIndex - 1].sonProjectList.length) { |
|||
this.itemList[lastIndex - 1].sonProjectList.push(Value); |
|||
} else { |
|||
this.itemList[lastIndex].sonProjectList = [Value]; |
|||
} |
|||
this.itemList.splice(index, 1); |
|||
// 清空 |
|||
this.clearSet(i); |
|||
const options = { |
|||
id: Value.id, |
|||
parentId: this.itemList[lastIndex - 1].id, |
|||
}; |
|||
this.$emit('change', options); |
|||
} else { |
|||
let arr = index.split('-'); |
|||
let Value = this.itemList[arr[0] - 0].sonProjectList[arr[1] - 0]; |
|||
if (this.itemList[lastIndex].sonProjectList && this.itemList[lastIndex].sonProjectList.length) { |
|||
this.itemList[lastIndex].sonProjectList.push(Value); |
|||
} else { |
|||
this.itemList[lastIndex].sonProjectList = [Value]; |
|||
} |
|||
this.itemList[arr[0] - 0].sonProjectList.splice([arr[1] - 0], 1); |
|||
// 清空 |
|||
this.clearSet(i); |
|||
const options = { |
|||
id: Value.id, |
|||
parentId: this.itemList[lastIndex].id, |
|||
}; |
|||
this.$emit('change', options); |
|||
|
|||
const options1 = { |
|||
id: Value.id, |
|||
parentId: 0, |
|||
}; |
|||
this.$emit('change', options1); |
|||
} |
|||
return; |
|||
} |
|||
} |
|||
}, |
|||
|
|||
// 还原初始数据 |
|||
clearSet(i) { |
|||
this.itemList[i].showBorder = false; |
|||
this.itemList[i].showSubBorder = false; |
|||
this.itemList[i].showTopBorder = false; |
|||
this.deltaLeft == 0; |
|||
this.showMoveImage = false; |
|||
this.setSubItem = false; |
|||
this.changeEvent = false; |
|||
this.showItemIndex = undefined; |
|||
}, |
|||
|
|||
// 找到停下的元素的下标 |
|||
findOverIndex(posY) { |
|||
// 如果有子项目展开着 |
|||
let leng = this.itemList.length * this.itemHeight; // 最后一个元素距离顶部的距离 |
|||
if (posY < this.begintop) { |
|||
return -1; |
|||
} |
|||
for (var i = 0; i < this.itemList.length; i++) { |
|||
let begin = this.itemHeight * i + this.begintop; |
|||
let end = this.itemHeight * i + this.begintop + this.itemHeight; |
|||
if (begin <= posY && end >= posY) { |
|||
return i; |
|||
} |
|||
} |
|||
if (posY > leng) { |
|||
// 交换最后一个 |
|||
return this.itemList.length - 1; |
|||
} else if (posY < this.begintop) { |
|||
return 0; |
|||
} |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.cu-item { |
|||
width: 100%; |
|||
display: flex; |
|||
align-items: center; |
|||
font-size: 14px; |
|||
} |
|||
|
|||
.border-100 { |
|||
width: 92%; |
|||
height: 4rpx; |
|||
} |
|||
.border-80 { |
|||
width: 84%; |
|||
height: 2px; |
|||
margin-left: 30px; |
|||
} |
|||
</style> |
@ -1,7 +1,150 @@ |
|||
<template> |
|||
<view class="flex items-center justify-between"> |
|||
这是子项目 |
|||
</template> |
|||
<script> |
|||
export default {}; |
|||
</script> |
|||
<template> |
|||
<view class="w-full"> |
|||
<!-- 有子项目 --> |
|||
<view class="flex items-center justify-between p-3"> |
|||
<u-icon @click="openMenu(item)" class="mover" name="https://www.tall.wiki/staticrec/drag.svg" size="48"></u-icon> |
|||
|
|||
<view @click="openProject(item)" class="flex-1 px-3"> |
|||
<view class="flex items-center mb-1"> |
|||
<view class="mr-2">{{ item.name }}</view> |
|||
<!-- 状态 TODO:--> |
|||
<view class="px-2 text-xs text-green-400 bg-green-100 rounded-full">进行中</view> |
|||
</view> |
|||
|
|||
<view class="flex items-center text-xs text-gray-400"> |
|||
<view class="pr-2">{{ $moment(+item.startTime).format('MM-DD HH:mm') }}</view> |
|||
至 |
|||
<view class="pl-2">{{ $moment(+item.endTime).format('MM-DD HH:mm') }}</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 箭头 --> |
|||
<view v-if="item.sonProjectList && item.sonProjectList.length"> |
|||
<u-icon |
|||
@click="$emit('openSubProject', item.sonProjectList.length, index)" |
|||
class="text-gray-400" |
|||
name="arrow-up" |
|||
size="14px" |
|||
v-if="item.show" |
|||
></u-icon> |
|||
<u-icon |
|||
@click="$emit('openSubProject', item.sonProjectList.length, index)" |
|||
class="text-gray-400" |
|||
name="arrow-down" |
|||
size="14px" |
|||
v-else |
|||
></u-icon> |
|||
</view> |
|||
<u-icon @click="openProject(item)" class="text-gray-400" name="arrow-right" size="14px" v-else></u-icon> |
|||
</view> |
|||
<!-- 有子项目 --> |
|||
<view class="ml-8" v-if="item.show"> |
|||
<view |
|||
:id="'cu-' + index + '-' + subIndex" |
|||
:key="subIndex" |
|||
class="cu-item flex-col" |
|||
v-for="(subItem, subIndex) in item.sonProjectList" |
|||
> |
|||
<!-- <view :key="subItem.id" v-for="subItem in item.sonProjectList"> --> |
|||
<view class="flex items-center justify-between p-3"> |
|||
<u-icon @click="openMenu(subItem)" class="mover" name="https://www.tall.wiki/staticrec/drag.svg" size="48"></u-icon> |
|||
|
|||
<view @click="openProject(subItem)" class="flex-1 px-3"> |
|||
<view class="flex items-center"> |
|||
<view class="mr-2">{{ subItem.name }}</view> |
|||
<!-- 状态 --> |
|||
<view |
|||
:class=" |
|||
subItem.status === 0 |
|||
? 'text-blue-400 bg-blue-100' |
|||
: subItem.status === 1 |
|||
? 'text-green-400 bg-green-100' |
|||
: subItem.status === 2 |
|||
? 'text-red-400 bg-red-100' |
|||
: 'text-gray-400 bg-gray-100' |
|||
" |
|||
class="px-2 text-xs text-gray-400 bg-gray-100 rounded-full" |
|||
> |
|||
{{ subItem.status === 0 ? '未开始' : subItem.status === 1 ? '进行中' : subItem.status === 2 ? '暂停' : '已完成' }} |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 箭头 --> |
|||
<u-icon @click="openProject(subItem)" class="text-gray-400" name="arrow-right" size="14px"></u-icon> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- 项目操作面板 --> |
|||
<u-action-sheet :list="menuList" :tips="tips" @click="$emit('chooseAction', $event)" v-model="showMenu"></u-action-sheet> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapGetters } from 'vuex'; |
|||
|
|||
export default { |
|||
props: { |
|||
item: { |
|||
type: Object, |
|||
default: () => {}, |
|||
}, |
|||
index: { |
|||
type: Number, |
|||
default: 0, |
|||
}, |
|||
menuList: { |
|||
type: Array, |
|||
default: () => [], |
|||
}, |
|||
}, |
|||
data() { |
|||
return { |
|||
showMenu: false, |
|||
tips: { |
|||
text: '', |
|||
color: '#909399', |
|||
fontSize: 28, |
|||
}, |
|||
show: false, |
|||
border: 'border border-blue-500 shadow rounded-md', |
|||
showBorder: false, |
|||
}; |
|||
}, |
|||
|
|||
computed: mapGetters('user', ['userId']), |
|||
|
|||
methods: { |
|||
// 打开项目详情 |
|||
openProject(project) { |
|||
const { name, id, url } = project; |
|||
url && (uni.$t.domain = url); |
|||
this.$u.route('pages/project-webview/project-webview', { |
|||
u: this.userId, |
|||
p: id, |
|||
pname: name, |
|||
url: encodeURIComponent(url), |
|||
}); |
|||
}, |
|||
|
|||
/** |
|||
* 弹出项目操作面板 |
|||
*/ |
|||
openMenu(project) { |
|||
this.showMenu = true; |
|||
this.tips.text = project.name; |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.border-100 { |
|||
height: 4rpx; |
|||
margin: 0 20rpx; |
|||
} |
|||
.border-80 { |
|||
height: 4rpx; |
|||
margin: 0 20rpx 0 90rpx; |
|||
} |
|||
</style> |
|||
|
@ -1,222 +0,0 @@ |
|||
<template> |
|||
<view class="px-2 bg-white wrap"> |
|||
<view class="home-box u-skeleton"> |
|||
<scroll-view :enable-flex="true" :scroll-left="scrollLeft" :throttle="false" scroll-with-animation scroll-x> |
|||
<view class="tab-box"> |
|||
<!-- 角色项 --> |
|||
<view :key="index" @click="changeRole(item.id, index)" class="tab-item" v-for="(item, index) in roles"> |
|||
<view :class="setColor(item.mine, item.id)" class="tab-children u-skeleton-fillet u-font-14">{{ item.name }}</view> |
|||
</view> |
|||
</view> |
|||
</scroll-view> |
|||
</view> |
|||
<!-- 骨架屏 --> |
|||
<u-skeleton :animation="true" :loading="loading" bg-color="#fff"></u-skeleton> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapState, mapMutations, mapActions } from 'vuex'; |
|||
|
|||
export default { |
|||
name: 'Roles', |
|||
data() { |
|||
return { |
|||
tabIndex: 0, // 当前访问的 index 默认为0 |
|||
tabList: [], // tab dom节点集合 |
|||
scrollLeft: 0, // scrollview需要滚动的距离 |
|||
loading: false, // 是否显示骨架屏组件 |
|||
roles: [ |
|||
{ id: 1, name: '项目经理', mine: 0, pm: 1, sequence: 1 }, |
|||
{ id: 2, name: '运维', mine: 0, pm: 0, sequence: 2 }, |
|||
], |
|||
}; |
|||
}, |
|||
|
|||
computed: { |
|||
...mapState('role', ['visibleRoles', 'roleId']), |
|||
...mapState('task', ['tasks']), |
|||
}, |
|||
|
|||
watch: { |
|||
visibleRoles(val) { |
|||
if (val && val.length) { |
|||
this.roles = [...this.visibleRoles]; |
|||
this.loading = false; |
|||
} |
|||
}, |
|||
}, |
|||
|
|||
mounted() { |
|||
if (!this.visibleRoles || !this.visibleRoles.length) { |
|||
this.loading = true; |
|||
} else { |
|||
this.roles = [...this.visibleRoles]; |
|||
} |
|||
}, |
|||
|
|||
methods: { |
|||
...mapActions('task', ['handleRegularTask', 'getPermanent']), |
|||
...mapMutations('role', ['setRoleId']), |
|||
...mapMutations('task', ['setPermanents', 'clearEndFlag']), |
|||
|
|||
// 设置滚动位置 |
|||
setCurrentRole(index) { |
|||
console.log('index: ', index); |
|||
const data = document.getElementsByClassName('tab-children'); |
|||
// 获取当前所有子元素 并插入到 tabList 列表中 |
|||
data.forEach(item => { |
|||
this.tabList.push({ |
|||
width: item.clientWidth, |
|||
left: item.offsetLeft, |
|||
}); |
|||
}); |
|||
//当前滚动的位置 |
|||
let left = 0; |
|||
let screenWidth = window.screen.width; |
|||
for (let i = 0; i < index; i++) { |
|||
left += this.tabList[i].width + this.tabList[i].left * 2; |
|||
} |
|||
left += this.tabList[index].width; |
|||
this.scrollLeft = left - screenWidth / 2; |
|||
}, |
|||
|
|||
// 切换角色 |
|||
// 查任务这里不用管 project监听了roleId的变化 |
|||
// 时间基准点不用管 project监听了roleId 里处理了 |
|||
changeRole(id, index) { |
|||
try { |
|||
// 清除多余的script |
|||
this.clearPluginScript(); |
|||
this.$nextTick(() => { |
|||
this.setRoleId(id); |
|||
//改变index 即手动点击切换 我在此时将当前元素赋值给左边距 实现自动滚动 |
|||
this.setCurrentRole(index); |
|||
}); |
|||
} catch (error) { |
|||
console.error('role.vue changeRole error: ', error); |
|||
} |
|||
}, |
|||
|
|||
// 清除插件script |
|||
clearPluginScript() { |
|||
try { |
|||
const scripts = document.querySelectorAll('script[data-type=plugin]'); |
|||
|
|||
for (let i = 0; i < scripts.length; i++) { |
|||
document.body.removeChild(scripts[i]); |
|||
} |
|||
} catch (error) { |
|||
console.error('clearPluginScript error: ', error); |
|||
} |
|||
}, |
|||
|
|||
// 设置文字颜色 |
|||
setColor(mine, id) { |
|||
const { roleId } = this; |
|||
// 是 我的角色 && 当前展示 |
|||
if (+mine === 1 && roleId === id) return 'default-tab-choice'; |
|||
// 是 我的角色 && 当前不展示 |
|||
if (+mine === 1 && roleId !== id) return 'default-tab-item'; |
|||
// 不是我的 && 当前展示 |
|||
if (+mine === 0 && roleId === id) return 'tab-choice'; |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.home-box { |
|||
// 对此盒子进行 sticky 粘性定位 |
|||
position: sticky; |
|||
top: 0; |
|||
background: #fff; // 设置背景 否则会透明 |
|||
|
|||
/* #ifdef H5 */ |
|||
//粘性定位 在h5下 加 原生头部高度 44px |
|||
top: 88rpx; |
|||
/* #endif */ |
|||
|
|||
.tab-box { |
|||
position: relative; |
|||
white-space: nowrap; |
|||
// height: 84rpx; |
|||
|
|||
.tab-item { |
|||
// width: 20%; |
|||
// height: 84rpx; |
|||
padding: 20rpx 24rpx; |
|||
position: relative; |
|||
display: inline-block; |
|||
text-align: center; |
|||
font-size: 30rpx; |
|||
transition-property: background-color, width; |
|||
} |
|||
|
|||
.default-tab-item { |
|||
color: $roleChoiceColor; |
|||
} |
|||
|
|||
.default-tab-choice { |
|||
//当前选中 基于此类名给与底部选中框 |
|||
position: relative; |
|||
color: $roleChoiceColor; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.default-tab-choice:before { |
|||
content: ''; |
|||
position: absolute; |
|||
left: 0; |
|||
bottom: -20rpx; |
|||
width: 100%; |
|||
height: 6rpx; |
|||
border-radius: 2rpx; |
|||
background: $roleChoiceColor; |
|||
} |
|||
|
|||
.tab-choice { |
|||
//当前选中 基于此类名给与底部选中框 |
|||
position: relative; |
|||
color: $uni-color-primary; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.tab-choice:before { |
|||
content: ''; |
|||
position: absolute; |
|||
left: 0; |
|||
bottom: -20rpx; |
|||
width: 100%; |
|||
height: 6rpx; |
|||
border-radius: 2rpx; |
|||
background: $uni-color-primary; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// // 删除 底部滚动条 |
|||
/* #ifndef APP-NVUE */ |
|||
::-webkit-scrollbar, |
|||
::-webkit-scrollbar, |
|||
::-webkit-scrollbar { |
|||
display: none; |
|||
width: 0 !important; |
|||
height: 0 !important; |
|||
-webkit-appearance: none; |
|||
background: transparent; |
|||
} |
|||
|
|||
/* #endif */ |
|||
/* #ifdef H5 */ |
|||
// 通过样式穿透,隐藏H5下,scroll-view下的滚动条 |
|||
scroll-view ::v-deep ::-webkit-scrollbar { |
|||
display: none; |
|||
} |
|||
|
|||
/* #endif */ |
|||
|
|||
.skeleton { |
|||
height: 44rpx; |
|||
} |
|||
</style> |
@ -1,84 +0,0 @@ |
|||
# skeleton组件 |
|||
|
|||
### 1.描述 |
|||
> 此组件用于加载数据时占位图显示,跟vant-ui骨架屏用法相似,但比vant-ui更灵活 |
|||
|
|||
|
|||
|
|||
### 2.用法 |
|||
|
|||
- 基本用法 |
|||
|
|||
代码: |
|||
```vue |
|||
//基本用法 |
|||
<skeleton :row="3" animate :loading="loading" > |
|||
<view> |
|||
content |
|||
</view> |
|||
</skeleton> |
|||
``` |
|||
|
|||
|
|||
- **显示 title ——通过 **title 属性显示title占位图 |
|||
|
|||
代码: |
|||
```vue |
|||
//显示 title——通过 title 属性显示title占位图 |
|||
<skeleton :row="3" title animate :loading="loading"> |
|||
<view> |
|||
content |
|||
</view> |
|||
</skeleton> |
|||
``` |
|||
|
|||
|
|||
- 显示头像(上面)——通过avatar=‘top’让头像的占位图上面显示 |
|||
|
|||
代码: |
|||
```vue |
|||
<skeleton :avatar="top" avatarAlign="left" :row="3" animate :loading="loading" style="margin-top:24rpx;"> |
|||
<view> |
|||
content |
|||
</view> |
|||
</skeleton> |
|||
``` |
|||
|
|||
|
|||
- 显示头像(左边)——通过avatar=‘left’让头像的占位图左边显示 |
|||
|
|||
代码: |
|||
```vue |
|||
<skeleton title :avatar="left" :row="3" animate :loading="loading" style="margin-top:24rpx;"> |
|||
<view> |
|||
content |
|||
</view> |
|||
</skeleton> |
|||
``` |
|||
|
|||
|
|||
- 显示banner**——通过 **banner属性显示banner占位图(只显示banner,不显示内容占位图时设置row="0") |
|||
|
|||
代码: |
|||
```vue |
|||
<skeleton banner :row="0" animate :loading="loading" style="margin-top:24rpx;"> |
|||
<view> |
|||
content |
|||
</view> |
|||
</skeleton> |
|||
``` |
|||
### |
|||
### 3. API |
|||
### Props |
|||
| **属性名** | **说明** | **类型** | **默认值** | 可取值 | |
|||
| --- | --- | --- | --- | --- | |
|||
| loading | 是否显示骨架屏 | Boolean | true | true/false | |
|||
| row | 段落行数 | Number | String | 3 | 0表示不展现 | |
|||
| rowWidth | 段落行宽度 | Boolean | Number | '100%' | | |
|||
| title | 是否显示标题 | Boolean | String | false | | |
|||
| banner | 是否显示banner | Boolean | String | false | | |
|||
| animate | 是否开启动画 | Boolean | String | false | | |
|||
| avatar | 头像位置 | Boolean | String | ''空 | left/top | |
|||
| avatarSize | 头像大小 | String | - | | |
|||
| avatarShape | 头像形状 | String | circle | circle/round | |
|||
|
@ -1,186 +0,0 @@ |
|||
<template> |
|||
<view> |
|||
<view :class="[avatarClass, animationClass]" class="lx-skeleton" v-show="loading"> |
|||
<view :class="[avatarShapeClass, bannerClass]" :style="{ width: avatarSize, height: avatarSize }" class="avatar-class"></view> |
|||
<view :style="{ width: rowWidth }" class="row"> |
|||
<view class="row-class lx-skeleton_title" v-if="title"></view> |
|||
<view :key="index" class="row-class" v-for="(item, index) in row"></view> |
|||
</view> |
|||
</view> |
|||
<slot v-if="!loading"></slot> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
/** |
|||
* skeleton 骨架屏 |
|||
* @description 用于加载数据时占位图显示,跟Vant-UI用法相似,但比Vant-UI更灵活 |
|||
* @property {Boolean} loading 是否显示骨架屏,默认为true |
|||
* @property {Number | String} row 段落行数,默认为3 |
|||
* @property {Boolean | Number} rowWidth 段落行宽度,默认为100% |
|||
* @property {Boolean | String} title 是否显示标题,默认为false |
|||
* @property {Boolean | String} banner 是否显示banner,默认为false |
|||
* @property {Boolean | String} animate 是否开启动画,默认为false |
|||
* @property {Boolean | String} avatar 头像位置 |
|||
* @property {String} avatarSize 头像大小 |
|||
* @property {String} avatarShape 头像形状,默认为circle |
|||
* |
|||
* */ |
|||
export default { |
|||
props: { |
|||
loading: { |
|||
type: Boolean, |
|||
default: true, |
|||
}, |
|||
row: { |
|||
type: Number, |
|||
default: 3, |
|||
}, |
|||
title: { |
|||
type: String, |
|||
default: '', |
|||
}, |
|||
avatar: { |
|||
type: String, |
|||
default: '', |
|||
}, |
|||
animate: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
avatarSize: { type: String }, |
|||
rowWidth: { |
|||
type: String, |
|||
default: '100%', |
|||
}, |
|||
avatarShape: { |
|||
type: String, |
|||
default: 'circle', |
|||
}, |
|||
banner: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
// avator-size:{ |
|||
// type: String, |
|||
// defualt: '32px' |
|||
// } |
|||
}, |
|||
computed: { |
|||
avatarClass() { |
|||
if (this.avatar == 'top') { |
|||
return ['lx-skeleton_avator__top']; |
|||
} else if (this.avatar == 'left') { |
|||
return ['lx-skeleton_avator__left']; |
|||
} else { |
|||
return ''; |
|||
} |
|||
}, |
|||
animationClass() { |
|||
return [this.animate ? 'lx-skeleton_animation' : '']; |
|||
}, |
|||
slotClass() { |
|||
return [!this.loading ? 'show' : 'hide']; |
|||
}, |
|||
avatarShapeClass() { |
|||
return [this.avatarShape == 'round' ? 'lx-skeleton_avator__round' : '']; |
|||
}, |
|||
bannerClass() { |
|||
return [this.banner ? 'lx-skeleton_banner' : '']; |
|||
}, |
|||
}, |
|||
data() { |
|||
return {}; |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.lx-skeleton { |
|||
background-color: #fff; |
|||
padding: 12px; |
|||
} |
|||
|
|||
.lx-skeleton_avator__left { |
|||
display: flex; |
|||
width: 100%; |
|||
} |
|||
|
|||
.lx-skeleton_avator__left .avatar-class, |
|||
.lx-skeleton_avator__top .avatar-class { |
|||
background-color: #f2f3f5; |
|||
border-radius: 50%; |
|||
width: 32px; |
|||
height: 32px; |
|||
} |
|||
|
|||
.lx-skeleton_avator__left .avatar-class.lx-skeleton_avator__round, |
|||
.lx-skeleton_avator__top .avatar-class.lx-skeleton_avator__round { |
|||
border-radius: 0; |
|||
width: 32px; |
|||
height: 32px; |
|||
} |
|||
|
|||
.lx-skeleton_avator__left .avatar-class { |
|||
margin-right: 16px; |
|||
} |
|||
|
|||
.lx-skeleton_avator__top .avatar-class { |
|||
margin: 0 auto 12px auto; |
|||
} |
|||
|
|||
.row-class { |
|||
width: 100%; |
|||
height: 16px; |
|||
background-color: #f2f3f5; |
|||
} |
|||
|
|||
.row-class:not(:first-child) { |
|||
margin-top: 12px; |
|||
} |
|||
|
|||
.row { |
|||
flex: 1; |
|||
} |
|||
|
|||
.lx-skeleton_avator__left .row { |
|||
width: calc(100% - 48px); |
|||
} |
|||
|
|||
.row-class:nth-last-child(1) { |
|||
width: 60%; |
|||
} |
|||
|
|||
.lx-skeleton_animation .row-class { |
|||
animation-duration: 1.5s; |
|||
animation-name: blink; |
|||
animation-timing-function: ease-in-out; |
|||
animation-iteration-count: infinite; |
|||
} |
|||
|
|||
@keyframes blink { |
|||
50% { |
|||
opacity: 0.6; |
|||
} |
|||
} |
|||
|
|||
.lx-skeleton_title { |
|||
width: 40%; |
|||
} |
|||
|
|||
.show { |
|||
display: block; |
|||
} |
|||
|
|||
.hide { |
|||
display: none; |
|||
} |
|||
|
|||
.lx-skeleton .lx-skeleton_banner { |
|||
width: 92%; |
|||
margin: 10px auto; |
|||
height: 64px; |
|||
border-radius: 0; |
|||
background-color: #f2f3f5; |
|||
} |
|||
</style> |
@ -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 +0,0 @@ |
|||
Subproject commit 2603a0bc8b5036c399a5f28b93586072c4850c4b |
@ -1,119 +0,0 @@ |
|||
<template> |
|||
<!-- 时间间隔栏 --> |
|||
<!-- <Barrier /> --> |
|||
|
|||
<scroll-view |
|||
:lower-threshold="300" |
|||
scroll-y="true" |
|||
:upper-threshold="300" |
|||
:scroll-into-view="viewId" |
|||
@scroll="scroll" |
|||
@scrolltolower="handleScrollBottom" |
|||
@scrolltoupper="handleScrollTop" |
|||
id="scroll" |
|||
> |
|||
<!-- 时间轴 --> |
|||
<!-- <u-divider bg-color="#f3f4f6" class="pt-5" fontSize="14px" v-if="topEnd">到顶啦</u-divider> --> |
|||
<TimeBox /> |
|||
<!-- <u-divider bg-color="#f3f4f6" class="pb-5" fontSize="14px" v-if="bottomEnd">到底啦</u-divider> --> |
|||
</scroll-view> |
|||
</template> |
|||
|
|||
<script> |
|||
// import Barrier from './component/Barrier.vue'; |
|||
import { mapState, mapMutations, mapGetters } from 'vuex'; |
|||
import TimeBox from './component/TimeBox.vue'; |
|||
import mixin from '@/mixins/timeline'; |
|||
|
|||
export default { |
|||
name: 'TimeLine', |
|||
components: { TimeBox }, |
|||
mixins: [mixin], |
|||
|
|||
data() { |
|||
return { top: 0 }; |
|||
}, |
|||
|
|||
computed: { |
|||
...mapState('role', ['visibleRoles']), |
|||
...mapState('task', ['scrollTop', 'showTips', 'tasks', 'topEnd', 'bottomEnd', 'showSkeleton', 'timeNode', 'viewId']), |
|||
...mapGetters('task', ['timeGranularity']), |
|||
}, |
|||
|
|||
methods: { |
|||
...mapMutations('task', ['setScrollTop', 'setShrink', 'setUpTasks', 'setDownTasks', 'setViewId']), |
|||
|
|||
// 滚动 |
|||
scroll(e) { |
|||
this.top = e.detail.scrollTop; |
|||
this.setShrink(this.top > this.scrollTop); |
|||
this.setScrollTop(this.top); |
|||
}, |
|||
|
|||
// 滚动到顶部 |
|||
async handleScrollTop() { |
|||
if (!this.tasks || !this.tasks.length || this.showSkeleton) return; |
|||
const startTime = this.tasks[0].planStart - 0; |
|||
if ((this.tasks[0].plugins && this.tasks[0].plugins.length === 0) || this.topEnd) { |
|||
// 没有数据时 自动加载数据 |
|||
console.warn('滚动到顶部没有数据时: '); |
|||
const addTasks = this.setTime(startTime, true); |
|||
this.setUpTasks(addTasks); |
|||
} else { |
|||
// 有数据时 |
|||
console.warn('滚动到顶部有数据时: '); |
|||
const upQuery = { |
|||
timeNode: startTime, |
|||
queryType: 0, |
|||
queryNum: 6, |
|||
}; |
|||
await this.$emit('getTasks', upQuery); |
|||
} |
|||
}, |
|||
|
|||
// 滚动到底部 |
|||
async handleScrollBottom() { |
|||
if (!this.tasks || !this.tasks.length || this.showSkeleton) return; |
|||
const { tasks, timeGranularity } = this; |
|||
const startTime = tasks[tasks.length - 1].planStart - 0; |
|||
if ((tasks[0].plugins && tasks[0].plugins.length === 0) || this.bottomEnd) { |
|||
// 没有数据时 自动加载数据 |
|||
console.warn('滚动到底部没有数据时: '); |
|||
const addTasks = this.setTime(startTime, false); |
|||
this.setDownTasks(addTasks); |
|||
} else { |
|||
// 时间基准点=最后一个任务的开始时间+当前时间颗粒度 |
|||
console.warn('滚动到底部有数据时: '); |
|||
const timeNode = this.$t.time.add(startTime, 1, timeGranularity).valueOf(); |
|||
const downQuery = { |
|||
timeNode, |
|||
queryType: 1, |
|||
queryNum: 6, |
|||
}; |
|||
await this.$emit('getTasks', downQuery); |
|||
} |
|||
}, |
|||
|
|||
// 设置自动滚动位置 |
|||
setScrollPosition() { |
|||
const { tasks, timeNode } = this; |
|||
for (let i = 0; i < tasks.length; i++) { |
|||
const item = tasks[i]; |
|||
const show = this.$t.time.isSame(+item.planStart, +timeNode, this.timeGranularity); |
|||
// 如果storage里有timeNode,修改store里的timeNode |
|||
const taskId = this.$t.storage.getStorageSync('taskId'); |
|||
// 清空storage |
|||
if (taskId) { |
|||
this.setViewId(`a${taskId}`); |
|||
this.$t.storage.setStorageSync('taskId', ''); |
|||
return; |
|||
} |
|||
if (show) { |
|||
this.setViewId(`a${item.id}`); |
|||
return; |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
@ -1,42 +0,0 @@ |
|||
<!-- |
|||
* @Author: aBin |
|||
* @email: binbin0314@126.com |
|||
* @Date: 2021-07-19 14:22:54 |
|||
* @LastEditors: aBin |
|||
* @LastEditTime: 2021-07-20 11:46:04 |
|||
--> |
|||
<template> |
|||
<view class> |
|||
<!-- :class="{ active: cycleTasks.time.start === filter.startTime }" --> |
|||
<view class="cycle-time active"> |
|||
<!-- {{ $util.formatStartTimeToCycleTime(filter.time, cycleTasks.time.start) }} --> |
|||
2021年30周 |
|||
</view> |
|||
</view> |
|||
</template> |
|||
<script> |
|||
export default { |
|||
name: 'Barrier', |
|||
data() { |
|||
return {}; |
|||
}, |
|||
}; |
|||
</script> |
|||
<style scoped lang="scss"> |
|||
.cycle-time { |
|||
padding: 8rpx 16rpx; |
|||
margin-bottom: 16rpx; |
|||
background: #fafafc; |
|||
color: $uni-text-color; |
|||
font-size: 28rpx; |
|||
position: sticky; |
|||
top: -1px; |
|||
left: 0; |
|||
z-index: 99; |
|||
|
|||
&.active { |
|||
background: $uni-color-primary; |
|||
color: $uni-text-color-inverse; |
|||
} |
|||
} |
|||
</style> |
@ -1,11 +0,0 @@ |
|||
<template> |
|||
<view class="flex justify-between" style="min-width: 90px"> |
|||
<u-icon custom-prefix="custom-icon" name="C-bxl-redux" size="17px"></u-icon> |
|||
<u-icon custom-prefix="custom-icon" name="attachment" size="21px"></u-icon> |
|||
<u-icon custom-prefix="custom-icon" name="moneycollect" size="20px"></u-icon> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default {}; |
|||
</script> |
@ -1,147 +0,0 @@ |
|||
<template> |
|||
<view class="column"> |
|||
<!-- v-if="tasks && tasks.length" --> |
|||
<view> |
|||
<view :key="task.id" v-for="task in tasks" class="ssssss" :id="`a${task.id}`"> |
|||
<view class="flex"> |
|||
<TimeStatus :task="task" /> |
|||
<view class="flex items-center justify-between flex-1 ml-2 task-column"> |
|||
<view v-if="task.process !== 4">{{ $moment(+task.planStart).format(startTimeFormat) }}</view> |
|||
<view v-else>{{ $moment(+task.planStart).format('D日') }}</view> |
|||
|
|||
<!-- 任务功能菜单 --> |
|||
<TaskTools v-if="task.process !== 4" /> |
|||
</view> |
|||
</view> |
|||
<view class="border-l-2 border-gray-300 plugin"> |
|||
<view class="h-3" v-if="task.process === 4"></view> |
|||
<view class="ml-3 overflow-hidden shadow-lg task-box"> |
|||
<u-card |
|||
:show-foot="false" |
|||
:show-head="false" |
|||
:style="{ height: setHeight(task.panel) }" |
|||
class="h-16" |
|||
margin="0" |
|||
v-if="showSkeleton" |
|||
> |
|||
<view slot="body"> |
|||
<view> |
|||
<skeleton :banner="false" :loading="true" :row="4" animate class="mt-2 u-line-2 skeleton"></skeleton> |
|||
</view> |
|||
</view> |
|||
</u-card> |
|||
|
|||
<u-card |
|||
:show-foot="false" |
|||
:show-head="false" |
|||
:style="{ height: setHeight(task.panel) }" |
|||
class="h-16" |
|||
margin="0" |
|||
v-if="tasks && tasks.length && task.process !== 4 && !showSkeleton" |
|||
@click="onClickTask(+task.planStart, task.id)" |
|||
> |
|||
<!-- 任务面板插件 --> |
|||
<view slot="body"> |
|||
<view class="p-0 u-col-between"> |
|||
<view :key="pIndex" v-for="(row, pIndex) in task.plugins"> |
|||
<view class="grid gap-2" v-if="row.length"> |
|||
<Plugin |
|||
:class="getClass(plugin.col, plugin.row)" |
|||
:task="task" |
|||
:key="plugin.pluginTaskId" |
|||
:plugin-task-id="plugin.pluginTaskId" |
|||
:plugin-id="plugin.pluginId" |
|||
:param="plugin.param" |
|||
:style-type="styleType || 0" |
|||
v-for="plugin in row" |
|||
/> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</u-card> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- 局部弹框操作栏 --> |
|||
<Tips /> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapState, mapMutations, mapGetters, mapActions } from 'vuex'; |
|||
import Skeleton from '@/components/Skeleton/Skeleton'; |
|||
import TimeStatus from './TimeStatus.vue'; |
|||
import TaskTools from './TaskTools.vue'; |
|||
|
|||
export default { |
|||
name: 'TimeBox', |
|||
components: { TimeStatus, Skeleton, TaskTools }, |
|||
|
|||
data() { |
|||
return { currentComponent: '', styleType: 0 }; |
|||
}, |
|||
|
|||
computed: { |
|||
...mapState('role', ['roleId']), |
|||
...mapState('task', ['timeUnit', 'tasks', 'taskLoading', 'topEnd', 'bottomEnd', 'showSkeleton']), |
|||
...mapGetters('task', ['startTimeFormat']), |
|||
}, |
|||
|
|||
methods: { |
|||
...mapActions('task', ['getGlobal']), |
|||
...mapMutations('task', ['setTipsContent', 'setTipsContent']), |
|||
|
|||
// 设置任务面板高度 |
|||
setHeight(panel) { |
|||
if (panel && panel.height) { |
|||
return panel.height + 'px'; |
|||
} else { |
|||
return 'auto'; |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 点击了定期任务的面板 更新可变的日常任务 |
|||
* @param {number} planStart 任务计划开始时间 |
|||
* @param {string} taskId 任务id |
|||
*/ |
|||
onClickTask(planStart, taskId) { |
|||
const param = { roleId: this.roleId, timeNode: planStart, timeUnit: this.timeUnit }; |
|||
this.getGlobal(param); |
|||
this.$t.storage.setStorageSync('taskId', taskId); |
|||
this.$t.storage.setStorageSync('roleId', this.roleId); |
|||
}, |
|||
|
|||
// 设置网格布局 |
|||
getClass(col, row) { |
|||
return [`row-span-${row}`, `col-span-${col}`]; |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped lang="scss"> |
|||
.task-box { |
|||
border-radius: 24rpx; |
|||
} |
|||
.column { |
|||
padding: 24px 14px; |
|||
} |
|||
.task-column { |
|||
height: 33px; |
|||
} |
|||
.plugin { |
|||
margin-top: 8px; |
|||
margin-bottom: 8px; |
|||
margin-left: 15px; |
|||
} |
|||
/deep/ .ml-2 { |
|||
margin-left: 16px; |
|||
} |
|||
|
|||
/deep/ .ml-3 { |
|||
margin-left: 20px; |
|||
} |
|||
</style> |
@ -1,211 +0,0 @@ |
|||
<template> |
|||
<view class="u-font-14"> |
|||
<view |
|||
class="flex items-center justify-center rounded-full icon-column" |
|||
:style="{ color: orderStyle.color }" |
|||
@tap="changeStatus($event, task.process)" |
|||
> |
|||
<!-- 1进行中 2暂停中 3已完成 --> |
|||
<u-circle-progress |
|||
:percent="+orderStyle.persent" |
|||
:active-color="orderStyle.color" |
|||
bg-color="rgba(255,255,255,0)" |
|||
border-width="4" |
|||
:width="task.process !== 4 ? 66 : 50" |
|||
v-if="task.process === 1 || task.process === 2 || task.process === 3" |
|||
> |
|||
<view class="u-progress-content"> |
|||
<view class="u-progress-dot"></view> |
|||
<view class="u-progress-info"> |
|||
<u-icon :name="orderStyle.icon" v-if="orderStyle.icon" size="15px"></u-icon> |
|||
<template v-else>{{ computeDurationText() }}</template> |
|||
</view> |
|||
</view> |
|||
</u-circle-progress> |
|||
<!-- 0未开始 4添加任务 --> |
|||
<view class="progress-box flex justify-center items-center rounded-full" v-else :class="task.process === 4 ? 'progress-box-4' : ''"> |
|||
<view class="u-progress-content"> |
|||
<view class="u-progress-dot"></view> |
|||
<view class="u-progress-info"> |
|||
<span v-if="orderStyle.icon"> |
|||
<u-icon :name="orderStyle.icon" v-if="task.process !== 4" size="15px"></u-icon> |
|||
<u-icon :name="orderStyle.icon" v-else size="15px"></u-icon> |
|||
</span> |
|||
<template v-else>{{ computeDurationText() }}</template> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapState, mapMutations } from 'vuex'; |
|||
|
|||
export default { |
|||
name: 'TimeStatus', |
|||
props: { task: { type: Object, default: () => {} } }, |
|||
|
|||
data() { |
|||
return { |
|||
time: '', |
|||
start: [{ text: '确认开始任务', color: 'blue' }], |
|||
pause: [{ text: '继续' }, { text: '重新开始任务', color: 'blue' }, { text: '结束' }], |
|||
proceed: [{ text: '暂停' }, { text: '重新开始任务', color: 'blue' }, { text: '结束' }], |
|||
again: [{ text: '重新开始任务', color: 'blue' }], |
|||
timer: null, |
|||
}; |
|||
}, |
|||
|
|||
computed: { |
|||
...mapState('task', ['tip']), |
|||
status() { |
|||
return this.task ? this.task.process : 0; |
|||
}, |
|||
taskName() { |
|||
return this.task ? this.task.name : ''; |
|||
}, |
|||
taskId() { |
|||
return this.task ? this.task.id : ''; |
|||
}, |
|||
// 图标文本颜色 |
|||
// 任务状态 0未开始 1进行中 2暂停中 3已完成 |
|||
orderStyle() { |
|||
let color = '#9CA3AF'; |
|||
let icon = 'play-right-fill'; |
|||
let persent = 100; |
|||
switch (this.status) { |
|||
case 1: // 进行中 |
|||
color = '#60A5FA'; |
|||
icon = ''; |
|||
if (+this.computeCyclePersent() > 100) { |
|||
persent = 96; |
|||
} else { |
|||
persent = this.computeCyclePersent(); |
|||
} |
|||
break; |
|||
case 2: // 暂停中 |
|||
color = '#F87171'; |
|||
icon = 'pause'; |
|||
persent = 50; // TODO: 暂时这样 暂停状态没有计算剩余多少时间 |
|||
break; |
|||
case 3: // 已结束 |
|||
color = '#34D399'; |
|||
icon = 'checkmark'; |
|||
persent = 100; |
|||
break; |
|||
case 4: // 添加任务 |
|||
color = '#60A5FA'; |
|||
icon = 'plus'; |
|||
persent = 100; |
|||
break; |
|||
default: |
|||
// 未开始 |
|||
color = '#9CA3AF'; |
|||
icon = 'play-right'; |
|||
persent = 100; |
|||
break; |
|||
} |
|||
return { color, icon, persent }; |
|||
}, |
|||
}, |
|||
|
|||
methods: { |
|||
...mapMutations('task', ['setTip']), |
|||
|
|||
/** |
|||
* 点击了图标 修改任务状态 |
|||
* @param {object} event |
|||
*/ |
|||
changeStatus(event, process) { |
|||
if (process === 4) { |
|||
this.addTask(); |
|||
return; |
|||
} |
|||
// return false; |
|||
const { status, taskId, taskName, tip } = this; |
|||
tip.status = status; |
|||
tip.taskId = taskId; |
|||
tip.left = event.target.x; |
|||
tip.top = event.target.y; |
|||
tip.show = true; |
|||
tip.text = this.genetateTips(status, taskName); |
|||
|
|||
this.setTip(tip); |
|||
}, |
|||
|
|||
// 新建任务 |
|||
addTask() { |
|||
this.$t.ui.showToast('新建任务'); |
|||
}, |
|||
|
|||
// 计算圆环的弧度百分比 |
|||
computeCyclePersent() { |
|||
if (!this.task || !this.task.realStart || !this.task.planDuration) return 100; |
|||
const { realStart, planDuration } = this.task; |
|||
return (((Date.now() - +realStart) * 100) / +planDuration).toFixed(2); |
|||
}, |
|||
|
|||
/** |
|||
* 计算tip的标题内容 |
|||
*/ |
|||
genetateTips(status, content) { |
|||
switch (status) { |
|||
case 0: |
|||
return `确认开始任务"${content}"吗?`; |
|||
case 1: |
|||
return `请选择要执行的操作`; |
|||
case 2: |
|||
return `请选择要执行的操作`; |
|||
case 3: |
|||
return `是否要重新开始此任务`; |
|||
} |
|||
}, |
|||
|
|||
// 计算进行中状态剩余时间 |
|||
// 预计结束时间 = realStart(实际开始) + planDuration(计划时长) |
|||
// 剩余时间 = 预计结束时间 - 当前时间 |
|||
// 剩余时间 = realStart + planDuration - Date.now() |
|||
computeDurationText() { |
|||
if (this.timer) { |
|||
clearTimeout(this.timer); |
|||
this.timer = null; |
|||
} |
|||
const { realStart, planDuration } = this.task; |
|||
const leftTime = +realStart + +planDuration - Date.now(); // 剩余时间 |
|||
const { num, time } = this.$t.time.computeDurationText(leftTime); |
|||
this.$nextTick(() => { |
|||
if (!time) return; |
|||
this.timer = setTimeout(() => { |
|||
this.computeDurationText(); |
|||
}, time); |
|||
}); |
|||
return num; |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped lang="scss"> |
|||
.icon-column { |
|||
height: 33px; |
|||
width: 33px; |
|||
} |
|||
.one { |
|||
height: 33px; |
|||
width: 33px; |
|||
} |
|||
|
|||
.progress-box { |
|||
background: rgba(255, 255, 255, 0); |
|||
width: 33px; |
|||
height: 33px; |
|||
border: 2px solid #9ca3af; |
|||
} |
|||
|
|||
.progress-box-4 { |
|||
width: 25px; |
|||
height: 25px; |
|||
border: 2px solid #60a5fa; |
|||
} |
|||
</style> |
@ -1,7 +0,0 @@ |
|||
<!-- |
|||
* @Author: aBin |
|||
* @email: binbin0314@126.com |
|||
* @Date: 2021-07-19 15:40:02 |
|||
* @LastEditors: aBin |
|||
* @LastEditTime: 2021-07-19 15:40:03 |
|||
--> |
@ -1,94 +0,0 @@ |
|||
<template> |
|||
<view |
|||
class="fixed shadow-2xl" |
|||
style="z-index: 1000" |
|||
:style="{ |
|||
left: tip.left + 'px', |
|||
top: height - tip.top > 110 ? tip.top + 'px' : '', |
|||
bottom: height - tip.top > 110 ? '' : '10px', |
|||
}" |
|||
id="u-icard" |
|||
> |
|||
<u-card |
|||
:title="title" |
|||
style="width: 500rpx; margin: 0 !important" |
|||
v-if="tip.show" |
|||
titleSize="28" |
|||
:headStyle="headStyle" |
|||
:footStyle="footStyle" |
|||
> |
|||
<view class="" slot="body"> {{ tip.text }} </view> |
|||
<view class="flex justify-end" slot="foot"> |
|||
<u-button size="mini" @tap="onCancel">取消</u-button> |
|||
<u-button v-if="tip.status === 1" size="mini" @tap="onChangeStatus(1)">暂停</u-button> |
|||
<u-button v-if="tip.status === 2" size="mini" @tap="onChangeStatus(2)">继续</u-button> |
|||
<u-button v-if="tip.status === 1 || tip.status === 2" size="mini" @tap="onChangeStatus(0)">重新开始</u-button> |
|||
<u-button v-if="tip.status === 1 || tip.status === 2" type="primary" size="mini" @tap="onChangeStatus(3)">结束</u-button> |
|||
<u-button v-if="tip.status === 0 || tip.status === 3" type="primary" size="mini" @tap="onChangeStatus(0)">确定</u-button> |
|||
</view> |
|||
</u-card> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapState, mapMutations } from 'vuex'; |
|||
|
|||
export default { |
|||
name: 'Tips', |
|||
props: { title: { default: '提示', type: String } }, |
|||
|
|||
computed: mapState('task', ['tip']), |
|||
|
|||
data() { |
|||
return { |
|||
footStyle: { padding: '4px 15px' }, |
|||
headStyle: { paddingTop: '8px', paddingBottom: '8px' }, |
|||
height: 0, |
|||
}; |
|||
}, |
|||
|
|||
mounted() { |
|||
this.height = window.screen.height; |
|||
}, |
|||
|
|||
methods: { |
|||
...mapMutations('task', ['setTipShow']), |
|||
// 点击了确认 |
|||
onConfirm() { |
|||
this.onCancel(); |
|||
}, |
|||
|
|||
/** |
|||
* 执行修改任务状态的动作 |
|||
* @param {number} type 状态码 0开始 1暂停 2继续 3完成 默认0 |
|||
*/ |
|||
async onChangeStatus(type) { |
|||
try { |
|||
const param = { id: this.tip.taskId, type }; |
|||
// TODO: 发请求 |
|||
await uni.$u.api.updateTaskType(param); |
|||
if (type === 0) { |
|||
this.$t.ui.showToast('项目已重新开始'); |
|||
} else if (type === 1) { |
|||
this.$t.ui.showToast('项目已暂停'); |
|||
} else if (type === 2) { |
|||
this.$t.ui.showToast('项目继续'); |
|||
} else if (type === 3) { |
|||
this.$t.ui.showToast('项目结束'); |
|||
} |
|||
this.tip.show = false; |
|||
// location.reload(); |
|||
// this.$router.go(0); |
|||
} catch (error) { |
|||
console.error(error); |
|||
this.$t.ui.showToast(error.msg || '操作失败'); |
|||
} |
|||
}, |
|||
|
|||
// 点击了取消 |
|||
onCancel() { |
|||
this.setTipShow(false); |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
@ -1,65 +0,0 @@ |
|||
<template> |
|||
<view> |
|||
<u-navbar :custom-back="onBack" class="overflow-hidden"> |
|||
<view class="flex justify-start flex-1 px-3 font-bold min-0"> |
|||
<view class="truncate">{{ project.name }}</view> |
|||
</view> |
|||
<view class="mr-2" slot="right"> |
|||
<u-icon class="m-1" name="xuanzhong2" custom-prefix="custom-icon" size="20px" @click="lwbs"></u-icon> |
|||
<u-icon class="m-1" name="shuaxin1" custom-prefix="custom-icon" size="20px" @click="projectOverview"></u-icon> |
|||
<u-icon class="m-1" name="home" custom-prefix="custom-icon" size="20px" @click="openIndex"></u-icon> |
|||
<u-icon class="m-1" name="xuanxiang" custom-prefix="custom-icon" size="20px" @click="operation"></u-icon> |
|||
</view> |
|||
</u-navbar> |
|||
</view> |
|||
</template> |
|||
<script> |
|||
import { mapGetters, mapState } from 'vuex'; |
|||
|
|||
export default { |
|||
name: 'ProjectTitle', |
|||
data() { |
|||
return { showBack: false }; |
|||
}, |
|||
computed: { |
|||
...mapState('project', ['project']), |
|||
...mapGetters('user', ['userId']), |
|||
}, |
|||
|
|||
methods: { |
|||
// 点击返回按钮 |
|||
onBack() { |
|||
// eslint-disable-next-line no-undef |
|||
const pages = getCurrentPages(); // 获取页面栈数组 |
|||
if (pages.length > 1) { |
|||
uni.navigateBack(); |
|||
} else { |
|||
this.$u.route('/', { u: this.userId }); |
|||
} |
|||
}, |
|||
|
|||
// LWBS提示 |
|||
lwbs() { |
|||
// this.$t.ui.showToast('LWBS'); |
|||
}, |
|||
//项目概览 |
|||
projectOverview() { |
|||
// this.$t.ui.showToast('项目概览'); |
|||
}, |
|||
// 回到首页 |
|||
openIndex() { |
|||
this.$u.route('/', { u: this.userId }); |
|||
}, |
|||
//操作 |
|||
operation() { |
|||
// this.$t.ui.showToast('操作'); |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
/deep/ .u-slot-content { |
|||
min-width: 0; |
|||
} |
|||
</style> |
@ -1,8 +1,6 @@ |
|||
const version = '3.0.0'; |
|||
|
|||
export default { |
|||
V: version, |
|||
version, |
|||
V: process.env.VUE_APP_VERSION, |
|||
version: process.env.VUE_APP_VERSION, |
|||
theme: [], |
|||
tokenKey: 'anyringToken', // storage token key
|
|||
}; |
|||
|
@ -1,3 +0,0 @@ |
|||
export const db = null; // indexedDB 对象
|
|||
export const name = 'TALL_indexedDB'; // indexDB name
|
|||
export const version = 1; // indexDB version
|
@ -1,97 +0,0 @@ |
|||
// 定义插件相关信息
|
|||
/* eslint-disable */ |
|||
export default { |
|||
defaults: [ |
|||
{ |
|||
id: 1, |
|||
name: 'TASK_NAME', |
|||
description: '任务名插件', |
|||
component: 'p-task-title', |
|||
}, |
|||
{ |
|||
id: 2, |
|||
name: 'TASK_DESCRIPTION', |
|||
description: '任务描述插件', |
|||
component: 'p-task-description', |
|||
}, |
|||
{ |
|||
id: 3, |
|||
name: 'TASK_DURATION_DELAY', |
|||
description: '任务时长延迟插件(+-1min)时间格式可设置', |
|||
component: 'p-task-duration-delay', |
|||
}, |
|||
{ |
|||
id: 4, |
|||
name: 'TASK_START_TIME_DELAY', |
|||
description: '任务开始时间延迟插件(+-1hour)', |
|||
component: 'p-task-start-time-delay', |
|||
}, |
|||
{ |
|||
id: 5, |
|||
name: 'DELIVERABLE', |
|||
description: '交付物插件(人 + 交付物)可配置【仅人】 or 【仅交付物】 or 【人+交付物】', |
|||
component: 'p-deliverable', |
|||
}, |
|||
{ |
|||
id: 6, |
|||
name: 'SUBTASKS', |
|||
description: '子任务插件:显示子任务', |
|||
component: 'p-subtasks', |
|||
}, |
|||
{ |
|||
id: 7, |
|||
name: 'SUB_PROJECT', |
|||
description: '子项目插件:显示子项目', |
|||
component: 'p-sub-project', |
|||
}, |
|||
{ |
|||
id: 8, |
|||
name: 'TASK_COUNTDOWN', |
|||
description: '任务倒计时插件', |
|||
component: 'p-task-countdown', |
|||
}, |
|||
{ |
|||
id: 9, |
|||
name: 'MANAGE_PROJECT', |
|||
description: '项目信息管理插件', |
|||
component: 'p-manage-project', |
|||
}, |
|||
|
|||
{ |
|||
id: 10, |
|||
name: 'MANAGE_ROLE', |
|||
description: '角色信息管理插件', |
|||
component: 'p-manage-role', |
|||
}, |
|||
{ |
|||
id: 11, |
|||
name: 'MANAGE_MEMBER', |
|||
description: '成员信息管理插件', |
|||
component: 'p-manage-member', |
|||
}, |
|||
{ |
|||
id: 12, |
|||
name: 'MANAGE_TASK', |
|||
description: '任务信息管理插件', |
|||
component: 'p-manage-task', |
|||
}, |
|||
{ |
|||
id: 13, |
|||
name: 'WBS_IMPORT', |
|||
description: '导入WBS新建项目', |
|||
component: 'p-wbs-import', |
|||
}, |
|||
{ |
|||
id: 14, |
|||
name: 'WBS_IMPORT_UPDATE', |
|||
description: '导入WBS更新项目', |
|||
component: 'p-wbs-update', |
|||
}, |
|||
{ |
|||
id: 15, |
|||
name: 'DELIVER_CHECK', |
|||
description: '交付物检查', |
|||
component: 'p-deliver-check', |
|||
}, |
|||
], // 默认插件id列表
|
|||
}; |
@ -1,17 +0,0 @@ |
|||
export default { |
|||
timeUnits: [ |
|||
// 时间颗粒度
|
|||
{ id: 0, value: '毫秒', format: 'x', cycle: 'YY-M-D HH:mm:ss', granularity: 'millisecond' }, |
|||
{ id: 1, value: '秒', format: 'x', cycle: 'YY-M-D HH:mm:ss', granularity: 'second' }, |
|||
{ id: 2, value: '分', format: 'ss', cycle: 'YY-M-D HH:mm', granularity: 'minute' }, |
|||
{ id: 3, value: '时', format: 'mm', cycle: 'YY-M-D HH时', granularity: 'hour' }, |
|||
{ id: 4, value: '天', format: 'D日 HH:mm', cycle: 'YY-M-D', granularity: 'day' }, |
|||
{ id: 5, value: '周', format: 'D日 HH:mm', cycle: '', granularity: 'week' }, |
|||
{ id: 6, value: '月', format: 'D日 H:m', cycle: 'YYYY年', granularity: 'month' }, |
|||
{ id: 7, value: '季度', format: '', cycle: 'YYYY年', granularity: 'quarter' }, |
|||
{ id: 8, value: '年', format: 'YYYY', cycle: '', granularity: 'year' }, |
|||
{ id: 9, value: '年代', format: '', cycle: '', granularity: '' }, |
|||
{ id: 10, value: '世纪', format: '', cycle: '', granularity: '' }, |
|||
{ id: 11, value: '千年', format: '', cycle: '', granularity: '' }, |
|||
], |
|||
}; |
@ -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, |
|||
}; |
@ -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; |
@ -1,31 +1,35 @@ |
|||
{ |
|||
"pages": [ |
|||
{ |
|||
"path": "pages/index/index", |
|||
"style": { |
|||
"navigationStyle": "custom" , |
|||
"navigationBarTextStyle": "white" |
|||
} |
|||
}, |
|||
{ |
|||
"path": "pages/project/project", |
|||
"style": { |
|||
"navigationStyle": "custom" , |
|||
"navigationBarTextStyle": "white" |
|||
} |
|||
} |
|||
], |
|||
"globalStyle": { |
|||
"navigationBarTextStyle": "black", |
|||
"navigationBarTitleText": "TALL", |
|||
"navigationBarBackgroundColor": "#F8F8F8", |
|||
"backgroundColor": "#F8F8F8" |
|||
}, |
|||
"easycom": { |
|||
"autoscan": true, |
|||
"custom": { |
|||
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue", |
|||
"^p-(.*)": "@/plugins/p-$1/p-$1.vue" |
|||
} |
|||
} |
|||
"pages": [ |
|||
{ |
|||
"path": "pages/index/index", |
|||
"style": { |
|||
"navigationBarText": "TALL" |
|||
} |
|||
}, |
|||
{ |
|||
"path": "pages/phone-bind/phone-bind", |
|||
"style": { |
|||
"navigationBarTitleText": "绑定手机号" |
|||
} |
|||
}, |
|||
{ |
|||
"path": "pages/project-webview/project-webview", |
|||
"style": { |
|||
"navigationBarTitleText": "项目详情页" |
|||
} |
|||
} |
|||
], |
|||
"globalStyle": { |
|||
"navigationBarTextStyle": "black", |
|||
"navigationBarTitleText": "TALL", |
|||
"navigationBarBackgroundColor": "#F8F8F8", |
|||
"backgroundColor": "#F8F8F8" |
|||
}, |
|||
"easycom": { |
|||
"autoscan": true, |
|||
"custom": { |
|||
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue", |
|||
"^p-(.*)": "@/plugins/p-$1/p-$1.vue" |
|||
} |
|||
} |
|||
} |
|||
|
@ -0,0 +1,189 @@ |
|||
<template> |
|||
<view class="wrap"> |
|||
<u-form :model="model" :rules="rules" ref="uForm" :errorType="errorType"> |
|||
<!-- 手机号 --> |
|||
<u-form-item :rightIconStyle="{ color: '#888', fontSize: '32rpx' }" label="手机号码" prop="phone" label-width="160"> |
|||
<u-input placeholder="请输入手机号" v-model="model.phone" type="number"></u-input> |
|||
</u-form-item> |
|||
|
|||
<u-form-item label="图形验证码" prop="imageValue" label-width="160"> |
|||
<u-input placeholder="输入计算结果" v-model="model.imageValue" type="number"></u-input> |
|||
<ImageCode slot="right" @on-code="codeId = $event" /> |
|||
</u-form-item> |
|||
|
|||
<u-form-item label="验证码" prop="code" label-width="160"> |
|||
<u-input placeholder="请输入短信验证码" v-model="model.code" type="number"></u-input> |
|||
<u-button slot="right" type="primary" size="mini" @click="getCode">{{ codeTips }}</u-button> |
|||
</u-form-item> |
|||
</u-form> |
|||
|
|||
<view class="mt-8"> |
|||
<u-button @click="submit" type="primary">提交</u-button> |
|||
</view> |
|||
<u-verification-code :seconds="seconds" ref="uCode" @change="codeChange"></u-verification-code> |
|||
|
|||
<u-top-tips ref="uTips"></u-top-tips> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
model: { |
|||
phone: '', // 手机号 |
|||
imageValue: '', // 图形验证码计算结果 |
|||
code: '', // 短信验证码 |
|||
}, |
|||
codeId: '', // 图形验证码的id |
|||
|
|||
rules: { |
|||
phone: [ |
|||
{ |
|||
required: true, |
|||
message: '请输入手机号', |
|||
trigger: ['change', 'blur'], |
|||
}, |
|||
{ |
|||
validator: (rule, value) => { |
|||
return this.$u.test.mobile(value); |
|||
}, |
|||
message: '手机号码不正确', |
|||
trigger: ['change', 'blur'], |
|||
}, |
|||
], |
|||
code: [ |
|||
{ |
|||
required: true, |
|||
message: '请输入验证码', |
|||
trigger: ['change', 'blur'], |
|||
}, |
|||
{ |
|||
validator: (rule, value) => { |
|||
return this.$u.test.code(value, 4); |
|||
}, |
|||
message: '验证码格式不正确', |
|||
trigger: ['change', 'blur'], |
|||
}, |
|||
], |
|||
}, |
|||
seconds: 120, // 验证码倒计时时长 |
|||
codeTips: '', |
|||
errorType: ['message'], |
|||
}; |
|||
}, |
|||
|
|||
onReady() { |
|||
this.$refs.uForm.setRules(this.rules); |
|||
}, |
|||
methods: { |
|||
submit() { |
|||
this.$refs.uForm.validate(async valid => { |
|||
if (valid) { |
|||
try { |
|||
const { phone, code } = this.model; |
|||
const data = await this.$u.api.phoneBind(phone, code); |
|||
console.log('data: ', data); |
|||
this.$refs.uTips.show({ |
|||
title: '手机号绑定成功, 即将跳转上一页', |
|||
type: 'success', |
|||
duration: '3000', |
|||
}); |
|||
setTimeout(() => uni.navigateBack(), 2000); |
|||
} catch (error) { |
|||
this.$refs.uTips.show({ |
|||
title: error.msg || '手机号绑定失败', |
|||
type: 'error', |
|||
duration: '3000', |
|||
}); |
|||
} |
|||
} else { |
|||
console.log('验证失败'); |
|||
} |
|||
}); |
|||
}, |
|||
|
|||
codeChange(text) { |
|||
this.codeTips = text; |
|||
}, |
|||
// 获取验证码 |
|||
async getCode() { |
|||
if (this.$refs.uCode.canGetCode) { |
|||
try { |
|||
if (!this.validateCodeParams()) return; |
|||
const params = { |
|||
phone: this.model.phone, |
|||
verificationCodeId: this.codeId, |
|||
verificationCodeValue: this.model.imageValue, |
|||
}; |
|||
const data = await this.$u.api.getSmsCode(params); |
|||
this.seconds = data.expiredInSeconds; |
|||
this.$refs.uTips.show({ |
|||
title: '短信发送成功, 请查收', |
|||
type: 'success', |
|||
duration: '3000', |
|||
}); |
|||
// 通知验证码组件内部开始倒计时 |
|||
this.$refs.uCode.start(); |
|||
} catch (error) { |
|||
this.$refs.uTips.show({ |
|||
title: error.msg || '发送失败', |
|||
type: 'error', |
|||
duration: '3000', |
|||
}); |
|||
} |
|||
} else { |
|||
this.$u.toast('倒计时结束后再发送'); |
|||
} |
|||
}, |
|||
|
|||
// 验证发送短信验证码的参数 |
|||
validateCodeParams() { |
|||
if (!this.$u.test.mobile(this.model.phone)) { |
|||
this.$refs.uTips.show({ |
|||
title: '手机号输入不正确', |
|||
type: 'error', |
|||
duration: '3000', |
|||
}); |
|||
return false; |
|||
} |
|||
|
|||
if (!this.codeId) { |
|||
this.$refs.uTips.show({ |
|||
title: '点击刷新图形验证码重试', |
|||
type: 'error', |
|||
duration: '3000', |
|||
}); |
|||
return false; |
|||
} |
|||
|
|||
if (!this.model.imageValue && this.model.imageValue !== 0) { |
|||
this.$refs.uTips.show({ |
|||
title: '请输入图形验证码', |
|||
type: 'error', |
|||
duration: '3000', |
|||
}); |
|||
return false; |
|||
} |
|||
return true; |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped lang="scss"> |
|||
.wrap { |
|||
padding: 30rpx; |
|||
} |
|||
|
|||
.agreement { |
|||
display: flex; |
|||
align-items: center; |
|||
margin: 40rpx 0; |
|||
|
|||
.agreement-text { |
|||
padding-left: 8rpx; |
|||
color: $u-tips-color; |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,35 @@ |
|||
<template> |
|||
<web-view :src="src" /> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { src: '' }; |
|||
}, |
|||
|
|||
onLoad(options) { |
|||
console.log('options: ', options); |
|||
if (!options) { |
|||
this.$t.ui.showModal('缺少参数, 请返回重试'); |
|||
} else { |
|||
const { p, u, pname, url } = options; |
|||
if (pname) { |
|||
uni.setNavigationBarTitle({ title: pname }); |
|||
} |
|||
if (!u) { |
|||
this.$t.ui.showToast('缺少用户信息, 请登录'); |
|||
return; |
|||
} |
|||
|
|||
if (!p || !url) { |
|||
this.$t.ui.showToast('缺少项目信息, 请重新打开'); |
|||
return; |
|||
} |
|||
|
|||
const baseUrl = process.env.VUE_APP_PROJECT_PATH; |
|||
this.src = `${baseUrl}/${this.$t.app.version}/#/?u=${u}&p=${p}&url=${url}&pname=${pname}`; |
|||
} |
|||
}, |
|||
}; |
|||
</script> |
@ -1,312 +0,0 @@ |
|||
<template> |
|||
<view :style="{ height: height }" class="flex flex-col overflow-hidden u-font-14"> |
|||
<!-- 标题栏 --> |
|||
<Title /> |
|||
|
|||
<view class="container flex flex-col flex-1 overflow-hidden bg-gray-100" style="margin: auto"> |
|||
<!-- 角色栏 --> |
|||
<Roles /> |
|||
|
|||
<!-- 日常任务面板 --> |
|||
<Globals /> |
|||
|
|||
<!-- 定期任务面板 --> |
|||
<TimeLine @getTasks="getTasks" class="flex-1 overflow-hidden" ref="child" /> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'; |
|||
import mixin from '@/mixins/timeline'; |
|||
|
|||
export default { |
|||
mixins: [mixin], |
|||
data() { |
|||
return { height: '' }; |
|||
}, |
|||
|
|||
computed: { |
|||
...mapState('user', ['user', 'token']), |
|||
...mapState('role', ['visibleRoles', 'roleId']), |
|||
...mapState('task', ['timeNode', 'timeUnit', 'tasks']), |
|||
...mapGetters('task', ['timeGranularity']), |
|||
}, |
|||
|
|||
onLoad(options) { |
|||
this.init(options); |
|||
}, |
|||
|
|||
watch: { |
|||
/** |
|||
* 当时间基准点发生变化时 |
|||
* 重新根据时间和角色查询普通日常任务 |
|||
* 永久日常任务不发生改变 |
|||
*/ |
|||
async timeNode(val) { |
|||
if (val && this.roleId) { |
|||
// 根据时间和角色查找日常任务 |
|||
await this.initTasks(); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 当角色发生变化时 |
|||
* 重新查询永久日常任务和普通日常任务 |
|||
* 注意: 切换角色后 重新设置了时间基准点 时间基准点一定会变 |
|||
* 所以监听时间基准点获取 可变日常任务即可 这里不用获取 避免重复获取 |
|||
*/ |
|||
roleId(val) { |
|||
if (val) { |
|||
this.setTimeNode(Date.now()); |
|||
// 根据角色查找永久的日常任务 |
|||
this.getPermanent(val); |
|||
} |
|||
}, |
|||
}, |
|||
|
|||
mounted() { |
|||
this.height = window.screen.height + 'px'; |
|||
}, |
|||
|
|||
onUnload() { |
|||
this.clearEndFlag(); |
|||
this.clearTasks(); |
|||
}, |
|||
|
|||
methods: { |
|||
...mapActions('user', ['getToken']), |
|||
...mapActions('project', ['getProjectById']), |
|||
...mapActions('role', ['getRoles']), |
|||
...mapActions('task', ['getRegulars', 'getPermanent', 'getGlobal']), |
|||
...mapMutations('user', ['setToken']), |
|||
...mapMutations('project', ['setProject', 'setProjectName']), |
|||
...mapMutations('role', ['setInvisibleRoles', 'setVisibleRoles', 'setRoleId']), |
|||
...mapMutations('task', [ |
|||
'setPermanents', |
|||
'setUpTasks', |
|||
'setDownTasks', |
|||
'setDailyTasks', |
|||
'setTimeNode', |
|||
'clearTasks', |
|||
'clearEndFlag', |
|||
'setShowSkeleton', |
|||
'setTopEnd', |
|||
'setBottomEnd', |
|||
]), |
|||
|
|||
/** |
|||
* 初始化 |
|||
* @param {object | null} options |
|||
*/ |
|||
async init(options) { |
|||
try { |
|||
if (!this.token) { |
|||
// 不论有没有token都直接从userId获取token |
|||
// token有过期时间 从本地获取可能是过期 干脆直接从userId获取 |
|||
if (!options || !options.u) { |
|||
// 参数里没有u (userId)提示 |
|||
this.$t.ui.showToast('缺少用户信息参数'); |
|||
} else { |
|||
await this.getToken(options.u); |
|||
} |
|||
} |
|||
|
|||
// 参数里有项目名称 就设置标题里的项目名称 |
|||
options && options.pname && this.setProjectName(options.pname); |
|||
|
|||
if (!options || !options.p) { |
|||
// 没有项目id参数 |
|||
this.$t.ui.showToast('缺少项目信息参数'); |
|||
} else { |
|||
// 根据项目id获取项目信息 |
|||
await this.getProjectById({ projectId: options.p }); |
|||
// 根据项目id获取角色列表 |
|||
await this.getRoles({ projectId: options.p }); |
|||
this.setInitialRoleId(this.visibleRoles); |
|||
} |
|||
} catch (error) { |
|||
console.error('project init function:', error); |
|||
} |
|||
}, |
|||
|
|||
// 初始化 时间轴 |
|||
async initTasks() { |
|||
// 清空日常任务的数据 |
|||
this.setPermanents([]); |
|||
this.setDailyTasks([]); |
|||
// 清空定期任务数据 |
|||
this.clearTasks(); |
|||
// 到顶的标志复位 |
|||
// 到底的标志复位 |
|||
this.clearEndFlag(); |
|||
// 根据时间和角色查找日常任务 |
|||
this.getGlobalData(); |
|||
// 向上加载空数据 |
|||
this.setPrevTasks(); |
|||
// storage没有存储值就跳转到当前时间位置 |
|||
const storageTaskId = this.$t.storage.getStorageSync('taskId'); |
|||
this.$nextTick(() => { |
|||
if (!storageTaskId) { |
|||
this.$refs.child.setScrollPosition(); |
|||
} |
|||
}); |
|||
// 向下加载空数据 |
|||
this.setNextTasks(); |
|||
await this.getInitTasks(); |
|||
// 从详情页返回时跳转到之前的位置 storage有存储值 |
|||
this.$nextTick(() => { |
|||
if (storageTaskId) { |
|||
this.$refs.child.setScrollPosition(); |
|||
} |
|||
}); |
|||
}, |
|||
|
|||
// 切换了 颗粒度 || 角色时候 获取初始定期任务 |
|||
async getInitTasks() { |
|||
// 根据时间基准点和角色查找定期任务 |
|||
await this.getTasks({ queryType: 0 }); |
|||
await this.getTasks({ queryType: 1 }); |
|||
|
|||
// 预加载 上下的定期任务 |
|||
const detailId = this.tasks.findIndex(task => task.detailId); |
|||
if (detailId !== -1) { |
|||
this.$nextTick(async () => { |
|||
const { tasks, timeGranularity } = this; |
|||
await this.getTasks({ timeNode: +tasks[0].planStart, queryType: 0, queryNum: 6 }); // 向上拿数据 |
|||
// 向下查的时候要再最后一个任务的开始时间的基础上 多加一个时间颗粒度 |
|||
const nextQueryTime = +this.$t.time.add(+tasks[tasks.length - 1].planStart, 1, timeGranularity); |
|||
await this.getTasks({ timeNode: nextQueryTime, queryType: 1, queryNum: 6 }); // 向下拿数据 |
|||
}); |
|||
} else { |
|||
// 没有任务 上下显示时间刻度 |
|||
// 向上加载 |
|||
this.setPrevTasks(); |
|||
// 向下加载 |
|||
this.setNextTasks(); |
|||
} |
|||
}, |
|||
|
|||
// 设置 初始显示角色信息 |
|||
setInitialRoleId(visibleList) { |
|||
const index = visibleList.findIndex(item => +item.mine === 1); |
|||
const currentRole = index > 0 ? visibleList[index] : visibleList[0]; |
|||
const storageRoleId = this.$t.storage.getStorageSync('roleId'); |
|||
const currentRoleId = storageRoleId ? storageRoleId : currentRole ? currentRole.id : ''; |
|||
this.setRoleId(currentRoleId); |
|||
// 清空storage |
|||
this.$t.storage.setStorageSync('roleId', ''); |
|||
}, |
|||
|
|||
/** |
|||
* 根据时间基准点和角色查找定期任务 |
|||
* @param {object} query |
|||
* @param {string} query.roleId 角色id |
|||
* @param {string} query.timeNode 时间基准点 默认当前 |
|||
* @param {string} query.timeUnit 时间颗粒度 默认天 |
|||
* @param {string} query.queryNum 查找颗粒度数量 默认3个 |
|||
* @param {string} query.queryType 0向上查找 1向下查找(默认) 下查包含自己,上查不包含 |
|||
*/ |
|||
async getTasks(query) { |
|||
try { |
|||
this.setShowSkeleton(true); |
|||
const { roleId, timeNode, timeUnit } = this; |
|||
const params = { |
|||
roleId, |
|||
timeNode: query.timeNode || timeNode, |
|||
timeUnit: query.timeUnit || timeUnit, |
|||
queryNum: query.queryNum || 3, |
|||
queryType: query.queryType, |
|||
}; |
|||
const res = await this.getRegulars(params); |
|||
this.setShowSkeleton(false); |
|||
// 0 -> 向上 1 -> 向下 |
|||
if (res && res.length) { |
|||
this.replacePrevData(res, params.queryType); |
|||
} else { |
|||
params.queryType === 0 ? this.setPrevTasks() : this.setNextTasks(); |
|||
} |
|||
} catch (error) { |
|||
this.setShowSkeleton(false); |
|||
console.error('error: ', error); |
|||
} |
|||
}, |
|||
|
|||
// 获取可变全局任务 |
|||
getGlobalData() { |
|||
const { roleId, timeNode, timeUnit } = this; |
|||
const param = { roleId, timeNode, timeUnit }; |
|||
this.getGlobal(param); |
|||
}, |
|||
|
|||
// 设置时间轴向上的空数据 |
|||
setPrevTasks() { |
|||
this.setTopEnd(true); |
|||
let sTime = ''; |
|||
if (!this.tasks || !this.tasks.length) { |
|||
sTime = +new Date().getTime(); |
|||
} else { |
|||
sTime = +this.tasks[0].planStart - 0; |
|||
} |
|||
const initData = this.setTime(sTime, true); |
|||
this.setUpTasks(initData); |
|||
}, |
|||
|
|||
// 设置时间轴向下的空数据 |
|||
setNextTasks() { |
|||
this.setBottomEnd(true); |
|||
let sTime = ''; |
|||
if (!this.tasks || !this.tasks.length) { |
|||
sTime = +new Date().getTime(); |
|||
} else { |
|||
sTime = +this.tasks[this.tasks.length - 1].planStart - 0; |
|||
} |
|||
const initData = this.setTime(sTime, false); |
|||
this.setDownTasks(initData); |
|||
}, |
|||
|
|||
// 筛选相同的时间替换数据 |
|||
replacePrevData(data, type) { |
|||
let newTasks = [...this.tasks]; |
|||
for (let i = 0; i < newTasks.length; i++) { |
|||
const task = newTasks[i]; |
|||
let arr = []; |
|||
for (let j = 0; j < data.length; j++) { |
|||
const item = data[j]; |
|||
// 查找有没有超出时间刻度的时间 |
|||
if (+newTasks[0].planStart > +data[0].planStart) { |
|||
this.setPrevTasks(); |
|||
newTasks = [...this.tasks]; |
|||
i--; |
|||
break; |
|||
} else if (+data[data.length - 1].planStart > +newTasks[newTasks.length - 1].planStart) { |
|||
this.setNextTasks(); |
|||
newTasks = [...this.tasks]; |
|||
i--; |
|||
break; |
|||
} else { |
|||
// 筛选相同的时间替换数据 |
|||
const taskItem = this.$t.time.isSame(+task.planStart, +item.planStart, this.timeGranularity); |
|||
if (taskItem) { |
|||
arr.push(item); |
|||
if (task.detailId) { |
|||
newTasks.splice(i, 0, item); |
|||
} else { |
|||
if (arr.length === 1) { |
|||
newTasks.splice(i, 1, item); |
|||
} |
|||
if (arr.length > 1) { |
|||
newTasks.splice(i, 0, item); |
|||
} |
|||
} |
|||
i++; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
this.clearTasks(); |
|||
type === 0 ? this.setUpTasks(newTasks) : this.setDownTasks(newTasks); |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
@ -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> |
@ -1,7 +0,0 @@ |
|||
<template> |
|||
<view>交付物检查</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default {}; |
|||
</script> |
@ -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> |
@ -1,7 +0,0 @@ |
|||
<template> |
|||
<view>成员管理</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default {}; |
|||
</script> |
@ -1,7 +0,0 @@ |
|||
<template> |
|||
<view>项目管理</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default {}; |
|||
</script> |
@ -1,7 +0,0 @@ |
|||
<template> |
|||
<view>角色管理</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default {}; |
|||
</script> |
@ -1,7 +0,0 @@ |
|||
<template> |
|||
<view>任务管理</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default {}; |
|||
</script> |
@ -1,60 +0,0 @@ |
|||
<template> |
|||
<!-- 子项目插件 --> |
|||
<view> |
|||
<view v-for="item in sonProject" :key="item.detailId"> |
|||
<span class="text-xs text-blue-500" @click="openProject(item)">{{ item.name }}</span> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapGetters } from 'vuex'; |
|||
|
|||
export default { |
|||
name: 'p-subproject', |
|||
props: { |
|||
task: { |
|||
type: Object, |
|||
default: () => {}, |
|||
}, |
|||
}, |
|||
data() { |
|||
return { sonProject: [] }; |
|||
}, |
|||
|
|||
computed: mapGetters('project', ['projectId']), |
|||
|
|||
mounted() { |
|||
this.getSonProject(); |
|||
}, |
|||
|
|||
methods: { |
|||
async getSonProject() { |
|||
try { |
|||
const data = await this.$u.api.findSonProject({ projectId: this.task.detailId }); |
|||
this.sonProject = data; |
|||
} catch (error) { |
|||
console.error('p-subproject.vue getSonProject error: ', error); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 打开项目 |
|||
* @param {object} project 所点击的项目的信息 |
|||
*/ |
|||
openProject(project) { |
|||
const { name, id, url } = project; |
|||
url && (uni.$t.domain = url); |
|||
this.$u.route('pages/project/project', { |
|||
u: this.userId, |
|||
p: id, |
|||
pname: name, |
|||
url: encodeURIComponent(url), |
|||
}); |
|||
}, |
|||
}, |
|||
watch: {}, |
|||
}; |
|||
</script> |
|||
|
|||
<style></style> |
@ -1,39 +0,0 @@ |
|||
<template> |
|||
<view> |
|||
<view v-for="item in sonTask" :key="item.detailId"> |
|||
<span class="text-xs text-gray-500">{{ item.name }}</span> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'p-subtasks', |
|||
props: { |
|||
task: { |
|||
type: Object, |
|||
default: () => {}, |
|||
}, |
|||
}, |
|||
data() { |
|||
return { sonTask: [] }; |
|||
}, |
|||
|
|||
created() { |
|||
this.getSonTask(); |
|||
}, |
|||
|
|||
methods: { |
|||
async getSonTask() { |
|||
try { |
|||
const data = await this.$u.api.findSonTask({ detailId: this.task.detailId }); |
|||
this.sonTask = data; |
|||
} catch (error) { |
|||
console.error('p-subtasks.vue getSonTask error: ', error); |
|||
} |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style></style> |
@ -1,20 +0,0 @@ |
|||
<template> |
|||
<!-- 任务倒计时插件 --> |
|||
<view>任务倒计时插件</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'p-task-countdown', |
|||
props: { item: { type: Object, default: null } }, |
|||
data() { |
|||
return {}; |
|||
}, |
|||
|
|||
computed: {}, |
|||
methods: {}, |
|||
watch: {}, |
|||
}; |
|||
</script> |
|||
|
|||
<style></style> |
@ -1,16 +0,0 @@ |
|||
<template> |
|||
<!-- 任务描述 --> |
|||
<view>{{ task.description }}</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'p-task-description', |
|||
props: { |
|||
task: { |
|||
type: Object, |
|||
default: () => {}, |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
@ -1,34 +0,0 @@ |
|||
<template> |
|||
<view v-if="realDuration && planDuration"> |
|||
<!-- 任务时长延迟插件 --> |
|||
<!-- 超时 --> |
|||
<span class="font-bold text-green-500" v-if="+realDuration > +planDuration"> |
|||
+{{ $t.time.formatDuration(+realDuration - +planDuration) }} |
|||
</span> |
|||
<!-- 延时 --> |
|||
<span class="font-bold text-red-500" v-if="+realDuration < +planDuration"> |
|||
-{{ $t.time.formatDuration(+planDuration - +realDuration) }} |
|||
</span> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'p-task-duration-delay', |
|||
props: { |
|||
task: { |
|||
type: Object, |
|||
default: () => {}, |
|||
}, |
|||
}, |
|||
|
|||
computed: { |
|||
realDuration() { |
|||
return this.task.realDuration; |
|||
}, |
|||
planDuration() { |
|||
return this.task.planDuration; |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
@ -1,22 +0,0 @@ |
|||
<template> |
|||
<view v-if="realStart && planStart"> |
|||
<!-- 任务开始时间延迟插件 --> |
|||
<!-- 超时 --> |
|||
<span>{{ $t.time.formatDuration(+realStart - +planStart) }}</span> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'p-task-start-time-delay', |
|||
props: { task: { type: Object, default: () => {} } }, |
|||
computed: { |
|||
realStart() { |
|||
return this.task.realStart; |
|||
}, |
|||
planStart() { |
|||
return this.task.planStart; |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
@ -1,16 +0,0 @@ |
|||
<template> |
|||
<!-- 任务名插件 --> |
|||
<view>{{ task.name }}</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'p-task-title', |
|||
props: { |
|||
task: { |
|||
type: Object, |
|||
default: () => {}, |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
@ -1,85 +0,0 @@ |
|||
<template> |
|||
<view> |
|||
<view @tap="handleUpload" v-if="task.name === '导入WBS新建项目'">{{ task.name }}</view> |
|||
<view @tap="handleUpdate" v-if="task.name === '导入WBS更新项目'">{{ task.name }}</view> |
|||
<!-- 全局提示框 --> |
|||
<u-top-tips ref="uTips"></u-top-tips> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapGetters, mapMutations } from 'vuex'; |
|||
|
|||
export default { |
|||
name: 'p-wbs-import', |
|||
props: { |
|||
task: { |
|||
type: Object, |
|||
default: () => {}, |
|||
}, |
|||
}, |
|||
data() { |
|||
return {}; |
|||
}, |
|||
|
|||
computed: { |
|||
...mapGetters('user', ['userId']), |
|||
...mapGetters('project', ['projectId']), |
|||
}, |
|||
|
|||
methods: { |
|||
...mapMutations('project', ['setShowAlert']), |
|||
|
|||
// 导入wbs |
|||
async handleUpload() { |
|||
try { |
|||
const data = await this.$u.api.import(); |
|||
// 导入WBS成功后 |
|||
// 直接打开导入的项目 |
|||
this.onUploadSuccess(); |
|||
setTimeout(() => { |
|||
this.$u.route('/pages/project/project', { |
|||
u: this.userId, |
|||
p: data.id, |
|||
pname: data.pname, |
|||
url: data.url, |
|||
}); |
|||
}, 2000); |
|||
} catch (error) { |
|||
this.onUploadError(error); |
|||
} |
|||
}, |
|||
|
|||
// 更新项目 |
|||
// TODO: 更新接口没写完 |
|||
async handleUpdate() { |
|||
try { |
|||
await this.$u.api.import({ projectId: this.projectId }); |
|||
// 导入WBS成功后 |
|||
// 直接打开导入的项目 |
|||
this.onUploadSuccess(); |
|||
} catch (error) { |
|||
this.onUploadError(error); |
|||
} |
|||
}, |
|||
|
|||
// 导入成功 |
|||
onUploadSuccess() { |
|||
this.$refs.uTips.show({ |
|||
title: '导入成功,即将打开新项目', |
|||
type: 'success', |
|||
duration: '3000', |
|||
}); |
|||
}, |
|||
|
|||
// 导入失败 |
|||
onUploadError(error) { |
|||
this.$refs.uTips.show({ |
|||
title: error || '导入失败', |
|||
type: 'error', |
|||
duration: '6000', |
|||
}); |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
Before Width: | Height: | Size: 853 B |
Before Width: | Height: | Size: 3.9 KiB |
@ -1,3 +0,0 @@ |
|||
const actions = {}; |
|||
|
|||
export default actions; |
@ -1,3 +0,0 @@ |
|||
const getters = {}; |
|||
|
|||
export default getters; |
@ -1,12 +0,0 @@ |
|||
import state from './state'; |
|||
import getters from './getters'; |
|||
import mutations from './mutations'; |
|||
import actions from './actions'; |
|||
|
|||
export default { |
|||
namespaced: true, |
|||
state, |
|||
getters, |
|||
mutations, |
|||
actions, |
|||
}; |
@ -1,3 +0,0 @@ |
|||
const mutations = {}; |
|||
|
|||
export default mutations; |
@ -1,7 +0,0 @@ |
|||
const state = { |
|||
db: null, // indexedDB对象
|
|||
name: 'TALL_indexedDB', |
|||
version: 1, |
|||
}; |
|||
|
|||
export default state; |
@ -1,12 +1,34 @@ |
|||
import Vue from 'vue'; |
|||
import Vuex from 'vuex'; |
|||
import db from './db/index'; |
|||
import user from './user/index'; |
|||
import messages from './messages/index'; |
|||
import socket from './socket/index'; |
|||
import project from './project/index'; |
|||
import role from './role/index'; |
|||
import task from './task/index'; |
|||
import socket from './socket/index'; |
|||
import user from './user/index'; |
|||
|
|||
// 不属于具体模块的 应用级的 store内容
|
|||
const state = { |
|||
networkConnected: true, // 网络是否连接
|
|||
forceUseStorage: false, // 强制启用storage
|
|||
}; |
|||
|
|||
const getters = { |
|||
// 是否启用本地存储
|
|||
// 设置了强制启用本地存储 或者 没有网络连接的时候
|
|||
useStorage({ networkConnected, forceUseStorage }) { |
|||
return forceUseStorage || !networkConnected; |
|||
}, |
|||
}; |
|||
|
|||
const mutations = { |
|||
/** |
|||
* 设置网络是否连接的变量 |
|||
* @param {*} state |
|||
* @param {boolean} networkConnected |
|||
*/ |
|||
setNetworkConnected(state, networkConnected) { |
|||
state.networkConnected = networkConnected; |
|||
}, |
|||
}; |
|||
|
|||
Vue.use(Vuex); |
|||
export default new Vuex.Store({ modules: { db, user, messages, socket, project, role, task } }); |
|||
export default new Vuex.Store({ state, getters, mutations, modules: { user, messages, socket, project } }); |
|||
|
@ -1,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; |
|||
|
@ -1,19 +0,0 @@ |
|||
const actions = { |
|||
/** |
|||
* 通过项目id获取角色信息 |
|||
* @param {any} commit |
|||
* @param {object} params 提交的参数 |
|||
*/ |
|||
async getRoles({ commit }, params) { |
|||
try { |
|||
const res = await uni.$u.api.findShowRole(params); |
|||
commit('setInvisibleRoles', res.invisibleList); |
|||
commit('setVisibleRoles', res.visibleList); |
|||
return res; |
|||
} catch (error) { |
|||
throw error || '获取角色信息失败'; |
|||
} |
|||
}, |
|||
}; |
|||
|
|||
export default actions; |
@ -1,3 +0,0 @@ |
|||
const getters = {}; |
|||
|
|||
export default getters; |
@ -1,12 +0,0 @@ |
|||
import state from './state'; |
|||
import getters from './getters'; |
|||
import mutations from './mutations'; |
|||
import actions from './actions'; |
|||
|
|||
export default { |
|||
namespaced: true, |
|||
state, |
|||
getters, |
|||
mutations, |
|||
actions, |
|||
}; |
@ -1,30 +0,0 @@ |
|||
const mutations = { |
|||
/** |
|||
* 设置不展示的角色信息 |
|||
* @param {Object} state |
|||
* @param {Array} data 服务端返回的模板数组 |
|||
*/ |
|||
setInvisibleRoles(state, data) { |
|||
state.invisibleRoles = data || []; |
|||
}, |
|||
|
|||
/** |
|||
* 设置展示的角色信息 |
|||
* @param {Object} state |
|||
* @param {Array} data 服务端返回的模板数组 |
|||
*/ |
|||
setVisibleRoles(state, data) { |
|||
state.visibleRoles = data || []; |
|||
}, |
|||
|
|||
/** |
|||
* 设置当前角色信息 |
|||
* @param {Object} state |
|||
* @param {string} roleId 当前正在展示的角色的id |
|||
*/ |
|||
setRoleId(state, roleId) { |
|||
state.roleId = roleId; |
|||
}, |
|||
}; |
|||
|
|||
export default mutations; |
@ -1,7 +0,0 @@ |
|||
const state = { |
|||
invisibleRoles: [], // 不展示的角色信息
|
|||
visibleRoles: [], // 展示的角色信息
|
|||
roleId: '', // 当前展示查看的角色id
|
|||
}; |
|||
|
|||
export default state; |
@ -1,45 +0,0 @@ |
|||
const actions = { |
|||
/** |
|||
* 根据角色查找永久的日常任务 |
|||
* @param {*} commit |
|||
* @param {string} roleId 角色id |
|||
*/ |
|||
async getPermanent({ commit }, roleId) { |
|||
try { |
|||
const data = await uni.$u.api.getPermanent({ roleId }); |
|||
commit('setPermanents', data); |
|||
} catch (error) { |
|||
console.log('task actions getPermanent error: ', error); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 根据时间和角色查找日常任务 |
|||
* @param {*} commit |
|||
* @param {object} param 请求参数 roleId, timeNode, timeUnit |
|||
*/ |
|||
async getGlobal({ commit }, param) { |
|||
try { |
|||
const data = await uni.$u.api.getGlobal(param); |
|||
commit('setDailyTasks', data); |
|||
} catch (error) { |
|||
console.log('task actions getGlobal error: ', error); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 根据时间基准点和角色查找定期任务 |
|||
* @param {object} param 查询参数 |
|||
* @param {number} param.queryType 必填 0 -> 向上 1 -> 向下 |
|||
*/ |
|||
// eslint-disable-next-line
|
|||
async getRegulars({ commit }, param) { |
|||
try { |
|||
return await uni.$u.api.getRegularTask(param); |
|||
} catch (error) { |
|||
throw error || '获取定期任务失败'; |
|||
} |
|||
}, |
|||
}; |
|||
|
|||
export default actions; |
@ -1,23 +0,0 @@ |
|||
const getters = { |
|||
// 所有的日常任务 永久 + 可变 日常任务
|
|||
globals({ dailyTasks, permanents }) { |
|||
return [...permanents, ...dailyTasks]; |
|||
}, |
|||
|
|||
unitConfig({ timeUnit }) { |
|||
const target = uni.$t.timeConfig.timeUnits.find(item => item.id === timeUnit); |
|||
return target; |
|||
}, |
|||
|
|||
// 计算任务开始时间的格式
|
|||
startTimeFormat(state, { unitConfig }) { |
|||
return unitConfig.format || 'D日 HH:mm'; |
|||
}, |
|||
|
|||
// 计算颗粒度 对应的 dayjs add 的单位
|
|||
timeGranularity(state, { unitConfig }) { |
|||
return unitConfig.granularity; |
|||
}, |
|||
}; |
|||
|
|||
export default getters; |
@ -1,12 +0,0 @@ |
|||
import state from './state'; |
|||
import getters from './getters'; |
|||
import mutations from './mutations'; |
|||
import actions from './actions'; |
|||
|
|||
export default { |
|||
namespaced: true, |
|||
state, |
|||
getters, |
|||
mutations, |
|||
actions, |
|||
}; |
@ -1,168 +0,0 @@ |
|||
const mutations = { |
|||
/** |
|||
* 记录时间轴向上滚动的距离 |
|||
* @param { object } state |
|||
* @param { number } num |
|||
*/ |
|||
setScrollTop(state, num) { |
|||
state.scrollTop = num; |
|||
}, |
|||
|
|||
/** |
|||
* 记录时间轴向上滚动的距离 |
|||
* @param { object } state |
|||
* @param { string } data |
|||
*/ |
|||
setViewId(state, data) { |
|||
state.viewId = data; |
|||
}, |
|||
|
|||
/** |
|||
* 设置日常任务当前是否应该处于收缩状态 |
|||
* @param { object } state |
|||
* @param { boolean } data |
|||
*/ |
|||
setShrink(state, data) { |
|||
state.isShrink = data; |
|||
}, |
|||
|
|||
/** |
|||
* 设置tip的值 |
|||
* @param {object} state |
|||
* @param {object} data |
|||
*/ |
|||
setTip(state, data) { |
|||
if (!data) return; |
|||
state.tip = { ...data }; |
|||
}, |
|||
|
|||
/** |
|||
* 是否显示tips |
|||
* @param { object } state |
|||
* @param { boolean } show |
|||
*/ |
|||
setTipShow(state, show) { |
|||
state.tip.show = show; |
|||
}, |
|||
|
|||
/** |
|||
* 是否显示tips |
|||
* @param { object } state |
|||
* @param { number } status |
|||
*/ |
|||
setStatus(state, status) { |
|||
state.tip.status = status; |
|||
}, |
|||
|
|||
/** |
|||
* 设置时间基准点 |
|||
* @param { object } state |
|||
* @param { number } data |
|||
*/ |
|||
setTimeNode(state, data) { |
|||
state.timeNode = data; |
|||
}, |
|||
|
|||
/** |
|||
* 设置时间颗粒度 |
|||
* @param { object } state |
|||
* @param { number } data |
|||
*/ |
|||
setTimeUnit(state, data) { |
|||
state.timeUnit = data; |
|||
}, |
|||
|
|||
/** |
|||
* 设置向上查到的定期任务数据 |
|||
* @param {Object} state |
|||
* @param {Array} data 服务端返回的模板数组 |
|||
*/ |
|||
setUpTasks(state, data) { |
|||
if (!state.tasks.length) { |
|||
state.tasks = [...data]; |
|||
} else { |
|||
state.tasks = [...data.concat(state.tasks)]; |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 设置向下查到的定期任务数据 |
|||
* @param {Object} state |
|||
* @param {Array} data 服务端返回的模板数组 |
|||
*/ |
|||
setDownTasks(state, data) { |
|||
if (!state.tasks && !state.tasks.length) { |
|||
state.tasks = [...data]; |
|||
} else { |
|||
state.tasks = [...state.tasks.concat(data)]; |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 设置日常任务数据 |
|||
* @param {Object} state |
|||
* @param {Array} data 服务端返回的模板数组 |
|||
*/ |
|||
setDailyTasks(state, data) { |
|||
state.dailyTasks = data || []; |
|||
}, |
|||
|
|||
/** |
|||
* 设置永久固定任务 |
|||
* @param {object} state |
|||
* @param {array} tasks 服务端查询到的永久日常任务书籍 |
|||
*/ |
|||
setPermanents(state, tasks) { |
|||
state.permanents = tasks || []; |
|||
}, |
|||
|
|||
/** |
|||
* 设置时间轴是否继续向上查任务 |
|||
* @param {Object} state |
|||
* @param {Boolean} show |
|||
*/ |
|||
setTopEnd(state, show) { |
|||
state.topEnd = show; |
|||
}, |
|||
|
|||
/** |
|||
* 设置时间轴是否继续向下查任务 |
|||
* @param {Object} state |
|||
* @param {Boolean} show |
|||
*/ |
|||
setBottomEnd(state, show) { |
|||
state.bottomEnd = show; |
|||
}, |
|||
|
|||
// 清空标志位 如切换角色等使用
|
|||
clearEndFlag(state) { |
|||
state.topEnd = false; |
|||
state.bottomEnd = false; |
|||
}, |
|||
|
|||
// 清空定期任务
|
|||
clearTasks(state) { |
|||
state.tasks = []; |
|||
}, |
|||
|
|||
/** |
|||
* 收到消息设置任务状态 |
|||
* @param {Object} state |
|||
* @param {Array} data 服务端返回的模板数组 |
|||
*/ |
|||
setTaskStatus(state, data) { |
|||
const item = state.tasks.find(i => i.id === data.id); |
|||
item.process = data.taskStatus; |
|||
}, |
|||
|
|||
/** |
|||
* 设置骨架屏是否显示 |
|||
* @param {Object} state |
|||
* @param {Boolean} show |
|||
*/ |
|||
setShowSkeleton(state, show) { |
|||
state.showSkeleton = show; |
|||
}, |
|||
}; |
|||
|
|||
export default mutations; |
@ -1,31 +0,0 @@ |
|||
const state = { |
|||
scrollTop: 0, |
|||
viewId: '', // 时间轴自动滚动的位置
|
|||
isShrink: false, // true: 收起, false:展开
|
|||
tip: { |
|||
taskId: '', // 当前正在修改状态的任务的id
|
|||
show: false, |
|||
status: 0, // 所点击任务的当前状态码
|
|||
text: '', |
|||
left: 0, // 鼠标点击位置距离左边的距离
|
|||
top: 0, // 鼠标点击位置距离上边的距离
|
|||
}, |
|||
// client: {
|
|||
// left: 0, // 鼠标点击位置距离左边的距离
|
|||
// top: 0, // 鼠标点击位置距离上边的距离
|
|||
// },
|
|||
// showTips: false,
|
|||
// status: 0, // 点击了时间轴上的哪种样式,默认点击了开始
|
|||
// tipsContent: '', // 提示框内的内容,需要传入
|
|||
timeNode: new Date().getTime(), // 时间基准点
|
|||
timeUnit: 4, // 时间颗粒度
|
|||
topEnd: false, // 时间轴向上查任务到顶了
|
|||
bottomEnd: false, // 时间轴向下查任务到底了
|
|||
permanents: [], // 永久日常任务
|
|||
dailyTasks: [], // 日常任务
|
|||
// 定期任务
|
|||
tasks: [], |
|||
showSkeleton: false, // 定期任务骨架屏
|
|||
}; |
|||
|
|||
export default state; |
@ -1,46 +0,0 @@ |
|||
import Time from '../../utils/time.js'; |
|||
|
|||
// 测试计算进行中剩余时长显示数值
|
|||
describe('utils/time.js computeDurationText function', () => { |
|||
const { computeDurationText } = Time; |
|||
// const leftTime = +realStart + +planDuration - Date.now(); // 剩余时间
|
|||
it ('leftTime is 60ms, num=60, time=16', () => { |
|||
expect(computeDurationText(60)).toEqual({ num: 60, time: 16 }) |
|||
}) |
|||
|
|||
it ('leftTime is 300ms, num=300, time=16', () => { |
|||
expect(computeDurationText(300)).toEqual({ num: 300, time: 16 }) |
|||
}) |
|||
|
|||
it ('leftTime is 10s20ms, num=10, time=1000', () => { |
|||
expect(computeDurationText(10*1000 + 20)).toEqual({ num: 10, time: 1000 }) |
|||
}) |
|||
|
|||
it ('leftTime is 8分钟10s20ms, num=8, time=1000', () => { |
|||
expect(computeDurationText(8*60*1000 + 10*1000 + 20)).toEqual({ num: 8, time: 1000 }) |
|||
}) |
|||
|
|||
it ('leftTime is 3小时8分钟10s20ms, num=3, time=1000', () => { |
|||
expect(computeDurationText(3*60*60*1000 + 8*60*1000 + 10*1000 + 20)).toEqual({ num: 3, time: 1000 }) |
|||
}) |
|||
|
|||
it ('leftTime is 11天3小时8分钟10s20ms, num=11, time=60 * 60 * 1000', () => { |
|||
expect(computeDurationText(11*24*60*60*1000 + 3*60*60*1000 + 8*60*1000 + 10*1000 + 20)).toEqual({ num: 11, time: 60 * 60 * 1000 }) |
|||
}) |
|||
|
|||
it ('leftTime is 2个月11天3小时8分钟10s20ms, num=2, time=60 * 60 * 1000', () => { |
|||
expect(computeDurationText(2*30*24*60*60*1000 + 11*24*60*60*1000 + 3*60*60*1000 + 8*60*1000 + 10*1000 + 20)).toEqual({ num: 2, time: 60 * 60 * 1000 }) |
|||
}) |
|||
|
|||
it ('leftTime is 7年2个月11天3小时8分钟10s20ms, num=7, time=60 * 60 * 1000', () => { |
|||
expect(computeDurationText(7*12*30*24*60*60*1000 + 2*30*24*60*60*1000 + 11*24*60*60*1000 + 3*60*60*1000 + 8*60*1000 + 10*1000 + 20)).toEqual({ num: 7, time: 60 * 60 * 1000 }) |
|||
}) |
|||
|
|||
it ('leftTime <=0, num=0, time=null', () => { |
|||
expect(computeDurationText(-10)).toEqual({ num: 0, time: null }) |
|||
}) |
|||
|
|||
it ('leftTime 不是数字, num=0, time=null', () => { |
|||
expect(computeDurationText('abc')).toEqual({ num: 0, time: null }) |
|||
}) |
|||
}) |
@ -0,0 +1,62 @@ |
|||
export const filter = { |
|||
/** |
|||
* 过滤获取到的数据 根据开始截止时间 |
|||
* @param {object} data 缓存拿到的数据 |
|||
* @param {number} start ms |
|||
* @param {number} end ms |
|||
* @returns |
|||
*/ |
|||
projects(data, start, end) { |
|||
if (!data || !data.length) return []; |
|||
return data.filter(item => start <= +item.endTime && end >= +item.startTime); |
|||
}, |
|||
}; |
|||
|
|||
export default { |
|||
/** |
|||
* 项目列表某天的 获取 |
|||
* @param {number} startTime |
|||
* @param {number} endTime |
|||
* @returns |
|||
*/ |
|||
async getProjectsByDay(startTime, endTime) { |
|||
try { |
|||
const data = await uni.$t.storage.getStorage('projects'); |
|||
return filter.projects(JSON.parse(data), startTime, endTime); |
|||
} catch (error) { |
|||
return []; |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 项目列表 存 |
|||
* @param {array} data |
|||
*/ |
|||
putProjects(data) { |
|||
try { |
|||
if (!data || !data.length) return; // 服务端没数据不做操作
|
|||
let value = uni.$t.storage.getStorageSync('projects'); |
|||
let locals = value ? JSON.parse(value) : []; |
|||
if (!locals || !locals.length) { |
|||
// 本地没数据
|
|||
locals = data || []; |
|||
} else { |
|||
// 本地有数据
|
|||
data.forEach(item => { |
|||
let localData = locals.find(local => item.id === local.id); |
|||
if (localData) { |
|||
// 有相同数据 就用新的data里的数据
|
|||
localData = item; |
|||
} else { |
|||
// 没有就直接存本地
|
|||
locals.push(item); |
|||
} |
|||
}); |
|||
} |
|||
uni.$t.storage.setStorage('projects', locals); |
|||
} catch (error) { |
|||
console.error('error: ', error); |
|||
uni.$t.storage.setStorage('projects', []); |
|||
} |
|||
}, |
|||
}; |
@ -0,0 +1,190 @@ |
|||
import store from '@/store/index'; |
|||
|
|||
/** |
|||
* 等待token执行api |
|||
* 没有token 就延时执行自己 直到有了token在请求 |
|||
* @param {function} requestFn 执行请求的函数 |
|||
*/ |
|||
export const waitTokenRequest = requestFn => { |
|||
if (!requestFn || typeof requestFn !== 'function') throw new Error(`requestFn must be a function`); |
|||
if (uni.$t.storage.getStorageSync(uni.$t.app.tokenKey)) { |
|||
requestFn(); |
|||
} else { |
|||
setTimeout(() => waitTokenRequest(requestFn), 10); |
|||
} |
|||
}; |
|||
|
|||
export default { |
|||
/** |
|||
* 获取项目列表 |
|||
* @param {number} startTime 起始时间 |
|||
* @param {number} endTime 截止时间 |
|||
*/ |
|||
getProjects(startTime, endTime, fn) { |
|||
let remote = false; |
|||
if (store.getters.useStorage) { |
|||
// 有缓存 且 服务端数据未返回 就先返回缓存
|
|||
uni.$t.cache |
|||
.getProjectsByDay(startTime, endTime) |
|||
.then(data => { |
|||
!remote && fn(null, data); |
|||
}) |
|||
.catch(err => !remote && fn(err)); |
|||
} |
|||
waitTokenRequest(() => { |
|||
// 拿到api数据后 再用api的数据
|
|||
uni.$u.api |
|||
.getProjects(startTime, endTime) |
|||
.then(data => { |
|||
remote = true; |
|||
fn(null, data); |
|||
// 存api到cache里
|
|||
uni.$t.cache.putProjects(data); |
|||
}) |
|||
.catch(err => fn(err)); |
|||
}); |
|||
}, |
|||
|
|||
/** |
|||
* 通过项目id获取角色信息 |
|||
* @param {object} params 提交的参数 |
|||
*/ |
|||
findShowRole(params, fn) { |
|||
let remote = false; |
|||
// 有缓存 且 服务端数据未返回 就先返回缓存
|
|||
uni.$t.cache |
|||
.getShowRole(params.projectId) |
|||
.then(data => { |
|||
!remote && fn(null, data); |
|||
}) |
|||
.catch(err => !remote && fn(err)); |
|||
|
|||
waitTokenRequest(() => { |
|||
// 拿到api数据后 再用api的数据
|
|||
uni.$u.api |
|||
.findShowRole(params) |
|||
.then(data => { |
|||
remote = true; |
|||
fn(null, data); |
|||
// 存api到cache里
|
|||
uni.$t.cache.putShowRole(params.projectId, data); |
|||
}) |
|||
.catch(err => fn(err)); |
|||
}); |
|||
}, |
|||
|
|||
/** |
|||
* 根据时间基准点和角色查找定期任务 |
|||
* @param {object} params 提交的参数 |
|||
*/ |
|||
getRegularTask(params, fn) { |
|||
let remote = false; |
|||
// 有缓存 且 服务端数据未返回 就先返回缓存
|
|||
uni.$t.cache |
|||
.getStorageRegularTask(params) |
|||
.then(data => { |
|||
console.log('cache data: ', data); |
|||
!remote && fn(null, data); |
|||
}) |
|||
.catch(err => !remote && fn(err)); |
|||
|
|||
waitTokenRequest(() => { |
|||
// 拿到api数据后 再用api的数据
|
|||
uni.$u.api |
|||
.getRegularTask(params) |
|||
.then(data => { |
|||
console.log('api data: ', uni.$u.deepClone(data)); |
|||
remote = true; |
|||
|
|||
fn(null, uni.$u.deepClone(data)); |
|||
// 存api到cache里
|
|||
uni.$t.cache.putStorageRegularTask(params, data); |
|||
}) |
|||
.catch(err => fn(err)); |
|||
}); |
|||
}, |
|||
|
|||
/** |
|||
* 根据角色查找永久的日常任务 |
|||
* @param {object} params 提交的参数 |
|||
*/ |
|||
getPermanent(params, fn) { |
|||
let remote = false; |
|||
// 有缓存 且 服务端数据未返回 就先返回缓存
|
|||
uni.$t.cache |
|||
.getStoragePermanent(params) |
|||
.then(data => { |
|||
!remote && fn(null, data); |
|||
}) |
|||
.catch(err => !remote && fn(err)); |
|||
|
|||
waitTokenRequest(() => { |
|||
// 拿到api数据后 再用api的数据
|
|||
uni.$u.api |
|||
.getPermanent(params) |
|||
.then(data => { |
|||
remote = true; |
|||
fn(null, data); |
|||
// 存api到cache里
|
|||
uni.$t.cache.putStoragePermanent(params, data); |
|||
}) |
|||
.catch(err => fn(err)); |
|||
}); |
|||
}, |
|||
|
|||
/** |
|||
* 根据时间和角色查找日常任务 |
|||
* @param {object} params 提交的参数 |
|||
*/ |
|||
getGlobal(params, fn) { |
|||
let remote = false; |
|||
// 有缓存 且 服务端数据未返回 就先返回缓存
|
|||
uni.$t.cache |
|||
.getDailyTask(params) |
|||
.then(data => { |
|||
!remote && fn(null, data); |
|||
}) |
|||
.catch(err => !remote && fn(err)); |
|||
|
|||
waitTokenRequest(() => { |
|||
// 拿到api数据后 再用api的数据
|
|||
uni.$u.api |
|||
.getGlobal(params) |
|||
.then(data => { |
|||
remote = true; |
|||
fn(null, data); |
|||
// 存api到cache里
|
|||
uni.$t.cache.putDailyTask(params, data); |
|||
}) |
|||
.catch(err => fn(err)); |
|||
}); |
|||
}, |
|||
|
|||
/** |
|||
* 获取插件信息 |
|||
* @param {object} params 提交的参数 |
|||
*/ |
|||
getOtherPlugin(params, fn) { |
|||
let remote = false; |
|||
// 有缓存 且 服务端数据未返回 就先返回缓存
|
|||
uni.$t.cache |
|||
.getPlugin(params.pluginId) |
|||
.then(data => { |
|||
!remote && fn(null, data); |
|||
}) |
|||
.catch(err => !remote && fn(err)); |
|||
|
|||
waitTokenRequest(() => { |
|||
// 拿到api数据后 再用api的数据
|
|||
uni.$u.api |
|||
.getOtherPlugin(params) |
|||
.then(data => { |
|||
remote = true; |
|||
fn(null, data); |
|||
// 存api到cache里
|
|||
uni.$t.cache.putPlugin(params.pluginId, data); |
|||
}) |
|||
.catch(err => fn(err)); |
|||
}); |
|||
}, |
|||
}; |
@ -1,185 +0,0 @@ |
|||
import { name } from '@/config/db'; |
|||
import { curry } from 'lodash'; |
|||
|
|||
// 创建表
|
|||
const createCollection = (Vue, db) => { |
|||
// projects项目表
|
|||
!db.objectStoreNames.contains('projects') && db.createObjectStore('projects', { keyPath: 'id' }); |
|||
// roles 角色表
|
|||
!db.objectStoreNames.contains('roles') && db.createObjectStore('roles', { keyPath: 'id' }); |
|||
// plan_tasks 定期任务
|
|||
!db.objectStoreNames.contains('plan_tasks') && db.createObjectStore('plan_tasks', { keyPath: 'id' }); |
|||
// fixed_tasks 固定全局任务
|
|||
Vue.prototype.$db.fixed_tasks = !db.objectStoreNames.contains('fixed_tasks') && db.createObjectStore('fixed_tasks', { keyPath: 'id' }); |
|||
// variable_tasks 可变全局任务
|
|||
Vue.prototype.$db.variable_tasks = |
|||
!db.objectStoreNames.contains('variable_tasks') && db.createObjectStore('variable_tasks', { keyPath: 'id' }); |
|||
// plugins 插件表
|
|||
Vue.prototype.$db.plugins = !db.objectStoreNames.contains('plugins') && db.createObjectStore('plugins', { keyPath: 'id' }); |
|||
}; |
|||
|
|||
/** |
|||
* 新增数据 |
|||
* |
|||
* @param {object} db 数据库database |
|||
* @param {string} collection 集合/表 |
|||
* @param {object} data 数据 |
|||
*/ |
|||
const create = (db, collection, data) => { |
|||
return new Promise((resolve, reject) => { |
|||
const request = db.transaction([collection], 'readwrite').objectStore(collection).add(data); |
|||
|
|||
request.onsuccess = event => { |
|||
console.log(event); |
|||
// FIXME:
|
|||
resolve(event); |
|||
}; |
|||
|
|||
request.onerror = event => { |
|||
console.log(event); |
|||
// FIXME:
|
|||
reject(event); |
|||
}; |
|||
}); |
|||
}; |
|||
|
|||
/** |
|||
* 找到1条数据 |
|||
* |
|||
* @param {object} db 数据库database |
|||
* @param {string} collection 集合/表 |
|||
* @param {string} key 索引关键字 一般是id |
|||
*/ |
|||
const findOne = (db, collection, key) => { |
|||
return new Promise((resolve, reject) => { |
|||
const request = db.transaction([collection]).objectStore(collection).get(key); |
|||
request.onerror = event => { |
|||
console.log('indexedDB findOne error:', event); |
|||
// FIXME:
|
|||
reject(event); |
|||
}; |
|||
request.onsuccess = event => { |
|||
console.log('indexedDB findOne success:', event); |
|||
// FIXME:
|
|||
resolve(event); |
|||
}; |
|||
}); |
|||
}; |
|||
|
|||
/** |
|||
* 找到所有数据 |
|||
* |
|||
* @param {object} db 数据库database |
|||
* @param {string} collection 集合/表 |
|||
*/ |
|||
const find = (db, collection) => { |
|||
return new Promise((resolve, reject) => { |
|||
const request = db.transaction(collection).objectStore(collection).openCursor(); |
|||
request.onerror = event => { |
|||
console.log('indexedDB find error:', event); |
|||
reject(event); |
|||
}; |
|||
request.onsuccess = event => { |
|||
const cursor = event.target.result; |
|||
if (cursor) { |
|||
console.log('indexedDB find success:', cursor); |
|||
cursor.continue(); |
|||
// FIXME:
|
|||
resolve(event.target.result); |
|||
} else { |
|||
console.log('没有更多数据了'); |
|||
} |
|||
}; |
|||
}); |
|||
}; |
|||
|
|||
/** |
|||
* 更新数据 |
|||
* |
|||
* @param {object} db 数据库database |
|||
* @param {string} collection 集合/表 |
|||
* @param {object} newData 新数据 |
|||
*/ |
|||
const update = (db, collection, newData) => { |
|||
return new Promise((resolve, reject) => { |
|||
const request = db.transaction([collection], 'readwrite').objectStore(collection).put(newData); |
|||
request.onerror = event => { |
|||
console.log('indexedDB UPDATE error:', event); |
|||
reject(event); |
|||
}; |
|||
request.onsuccess = event => { |
|||
console.log('indexedDB UPDATE success:', event); |
|||
// FIXME:
|
|||
resolve(event); |
|||
}; |
|||
}); |
|||
}; |
|||
|
|||
/** |
|||
* 移除数据 通过关键字 |
|||
* |
|||
* @param {object} db 数据库database |
|||
* @param {string} collection 集合/表 |
|||
* @param {string} key 关键字 |
|||
*/ |
|||
const remove = (db, collection, key) => { |
|||
return new Promise((resolve, reject) => { |
|||
const request = db.transaction([collection], 'readwrite').objectStore(collection).delete(key); |
|||
request.onerror = event => { |
|||
console.log('indexedDB REMOVE error:', event); |
|||
reject(event); |
|||
}; |
|||
request.onsuccess = event => { |
|||
console.log('indexedDB REMOVE success:', event); |
|||
resolve(event); |
|||
}; |
|||
}); |
|||
}; |
|||
|
|||
/** |
|||
* 创建索引 |
|||
* |
|||
* @param {object} db 数据库database |
|||
* @param {string} collection 集合/表 |
|||
* @param {string} field 创建索引的字段名称 |
|||
* @param {string} key 关键字 |
|||
*/ |
|||
const createIndexAndFind = (db, collection, field, key) => { |
|||
return new Promise((resolve, reject) => { |
|||
const index = db.transaction([collection], 'readonly').objectStore(collection).index(field); |
|||
const request = index.get(key); |
|||
// FIXME:
|
|||
request.onerror = event => reject(event); |
|||
request.onsuccess = event => resolve(event); |
|||
}); |
|||
}; |
|||
|
|||
const curriedCreate = curry(create); |
|||
export const curriedFindOne = curry(findOne); |
|||
export const curriedFind = curry(find); |
|||
export const curriedRemove = curry(remove); |
|||
export const curriedUpdate = curry(update); |
|||
export const curriedIndex = curry(createIndexAndFind); |
|||
|
|||
const install = Vue => { |
|||
Vue.prototype.$db = {}; |
|||
Vue.prototype.$db.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; |
|||
const request = Vue.prototype.$db.indexedDB.open(name, Date.now()); // IDBRequest 对象
|
|||
request.onerror = error => console.error('打开数据库失败', error); |
|||
request.onsuccess = event => { |
|||
console.log('INDEXED_DB OPEN SUCCESS'); |
|||
Vue.prototype.$db.db = event.target.result; |
|||
}; |
|||
request.onupgradeneeded = event => { |
|||
console.log('INDEXED_DB OPEN onupgradeneeded'); |
|||
Vue.prototype.$db.db = event.target.result; |
|||
// 创建表
|
|||
createCollection(Vue, Vue.prototype.$db.db); |
|||
}; |
|||
|
|||
// create
|
|||
// console.log(curriedCreate(Vue.prototype.$db.db));
|
|||
Vue.prototype.$db.create = curriedCreate(Vue.prototype.$db.db); |
|||
}; |
|||
|
|||
export default { install }; |
@ -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, |
|||
}, |
|||
}; |
Loading…
Reference in new issue