@ -0,0 +1,8 @@ |
|||
[*.{js,jsx,ts,tsx,vue}] |
|||
indent_style = space |
|||
indent_size = 2 |
|||
end_of_line = lf |
|||
trim_trailing_whitespace = true |
|||
insert_final_newline = true |
|||
max_line_length = 140 |
|||
root = true |
@ -0,0 +1,8 @@ |
|||
VUE_APP_NODE_ENV=development |
|||
VUE_APP_BASE_URL=https://test.tall.wiki |
|||
VUE_APP_API_URL=https://test.tall.wiki/gateway |
|||
VUE_APP_MSG_URL=ws://101.201.226.163/websocket/message/v4.0/ws |
|||
VUE_APP_PROJECT_PATH=https://test.tall.wiki/carBasicTall |
|||
VUE_APP_QUESTION_PATH=https://test.tall.wiki/carbasics |
|||
VUE_APP_VERSION=v3.1.0 |
|||
VUE_APP_PUBLIC_PATH=/carBasicCalendar/ |
@ -0,0 +1,2 @@ |
|||
VUE_APP_BASE_URL=http://127.0.0.1:8080 |
|||
VUE_APP_API_URL=http://127.0.0.1:8080 |
@ -0,0 +1,8 @@ |
|||
VUE_APP_NODE_ENV=production |
|||
VUE_APP_BASE_URL=https://test.tall.wiki |
|||
VUE_APP_API_URL=https://test.tall.wiki/gateway |
|||
VUE_APP_MSG_URL=ws://101.201.226.163/websocket/message/v4.0/ws |
|||
VUE_APP_PROJECT_PATH=https://test.tall.wiki/carBasicTall |
|||
VUE_APP_QUESTION_PATH=https://test.tall.wiki/carbasics |
|||
VUE_APP_VERSION=v3.1.0 |
|||
VUE_APP_PUBLIC_PATH=/carBasicCalendar/ |
@ -0,0 +1,13 @@ |
|||
node_modules |
|||
dist/ |
|||
test |
|||
build/ |
|||
unpackage/ |
|||
babel.config.js |
|||
package.json |
|||
postcss.config.js |
|||
.eslint.js |
|||
vue.config.js |
|||
src/common/styles/index.css |
|||
src/pages.json |
|||
manifest.json |
@ -0,0 +1,48 @@ |
|||
module.exports = { |
|||
root: true, |
|||
env: { |
|||
node: true, |
|||
browser: true, |
|||
}, |
|||
extends: ['plugin:vue/essential', 'eslint:recommended', '@vue/prettier'], |
|||
rules: { |
|||
'vue/html-self-closing': 'off', |
|||
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', |
|||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', |
|||
'no-param-reassign': 'off', |
|||
'max-len': ['error', { code: 140, tabWidth: 2 }], |
|||
'object-curly-newline': ['error', { multiline: true }], |
|||
'arrow-parens': ['error', 'as-needed'], |
|||
'linebreak-style': 'off', |
|||
'vue/attributes-order': 'off', |
|||
'vue/singleline-html-element-content-newline': 'off', |
|||
'vue/max-attributes-per-line': 'off', |
|||
'vue/multiline-html-element-content-newline': 'off', |
|||
'vue/html-indent': 'off', |
|||
'vue/html-closing-bracket-newline': [ |
|||
'error', |
|||
{ |
|||
singleline: 'never', |
|||
multiline: 'always', |
|||
}, |
|||
], |
|||
}, |
|||
|
|||
parserOptions: { parser: 'babel-eslint' }, |
|||
|
|||
overrides: [ |
|||
{ |
|||
files: ['**/__tests__/*.{j,t}s?(x)'], |
|||
env: { jest: true }, |
|||
}, |
|||
], |
|||
|
|||
globals: { |
|||
Vue: true, |
|||
VueRouter: true, |
|||
Vuex: true, |
|||
_: true, |
|||
uni: true, |
|||
wx: true, |
|||
}, |
|||
}; |
@ -0,0 +1,27 @@ |
|||
.DS_Store |
|||
node_modules/ |
|||
unpackage/ |
|||
dist/ |
|||
|
|||
# local env files |
|||
.env.local |
|||
.env.*.local |
|||
|
|||
# Log files |
|||
npm-debug.log* |
|||
yarn-debug.log* |
|||
yarn-error.log* |
|||
|
|||
yarn.lock |
|||
package-lock.json |
|||
|
|||
# Editor directories and files |
|||
.project |
|||
.idea |
|||
.vscode |
|||
*.suo |
|||
*.ntvs* |
|||
*.njsproj |
|||
*.sln |
|||
*.sw* |
|||
.eslintcache |
@ -0,0 +1,11 @@ |
|||
{ // 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" |
|||
} |
|||
} |
|||
] |
|||
} |
@ -0,0 +1 @@ |
|||
registry=https://registry.npm.taobao.org |
@ -0,0 +1,9 @@ |
|||
node_modules |
|||
dist/ |
|||
test |
|||
build/ |
|||
unpackage/ |
|||
babel.config.js |
|||
package.json |
|||
postcss.config.js |
|||
.eslint.js |
@ -0,0 +1,13 @@ |
|||
{ |
|||
"printWidth": 140, |
|||
"singleQuote": true, |
|||
"semi": true, |
|||
"trailingComma": "all", |
|||
"arrowParens": "avoid", |
|||
"tabWidth": 2, |
|||
"useTabs": false, |
|||
"bracketSpacing": true, |
|||
"jsxBracketSameLine": false, |
|||
"proseWrap": "always", |
|||
"endOfLine": "lf" |
|||
} |
@ -0,0 +1,243 @@ |
|||
# 0.1.0 (2021-11-22) |
|||
|
|||
### 🌟 新功能 |
|||
范围|描述|commitId |
|||
--|--|-- |
|||
- | 绑定手机号 | [52e0352](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/52e0352) |
|||
- | 暴风眼相关小程序修改 | [8947ea8](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/8947ea8) |
|||
- | 标题栏变化 | [3898cfe](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/3898cfe) |
|||
- | 标题栏变化 | [c0fcd9d](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/c0fcd9d) |
|||
- | 标题栏角色栏全局任务组件新建 | [0500cb4](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/0500cb4) |
|||
- | 插件参数处理调整 | [a3e68d3](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/a3e68d3) |
|||
- | 插件数据获取 | [5b91bdc](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/5b91bdc) |
|||
- | 存token | [b8a178d](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/b8a178d) |
|||
- | 导入项目,更新项目 | [5e06adf](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/5e06adf) |
|||
- | 导入项目后提示并打开项目详情页 | [410f527](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/410f527) |
|||
- | 导入wbs | [1224fcb](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/1224fcb) |
|||
- | 点击日历日期查询项目列表 | [c458385](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/c458385) |
|||
- | 定期任务面板骨架屏添加 | [b2698c0](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/b2698c0) |
|||
富文本插件 | 富文本插件demo测试 | [ed3d644](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/ed3d644) |
|||
- | 缓存修改 | [63e1f0d](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/63e1f0d) |
|||
- | 获取用户收取那,提交用户信息 | [a3c54f1](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/a3c54f1) |
|||
- | 角色栏实现 | [94cd671](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/94cd671) |
|||
- | 进入项目默认打开项目列表第一个项目 | [f666730](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/f666730) |
|||
- | 距调整pc端 | [5069aa1](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/5069aa1) |
|||
- | 客服加分享 | [ccae107](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/ccae107) |
|||
- | 客服位置更改及首页分享功能 | [239a6ba](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/239a6ba) |
|||
- | 面变化首页变化 | [5e860f1](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/5e860f1) |
|||
- | 模拟接口测试 | [69e7931](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/69e7931) |
|||
- | 配置默认插件接口 | [f0c177d](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/f0c177d) |
|||
- | 全局插件及默认插件位置修改 | [6c80d08](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/6c80d08) |
|||
- | 任务进行中状态数字 | [27b7326](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/27b7326) |
|||
- | 任务状态时间显示 | [56f5183](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/56f5183) |
|||
- | 日常任务插件调整 | [c1881f9](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/c1881f9) |
|||
- | 日历定位;合并 | [ea3f937](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/ea3f937) |
|||
- | 删除项目 | [00b886c](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/00b886c) |
|||
- | 上传逻辑变化 | [3ff1dc2](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/3ff1dc2) |
|||
- | 设置小红点 | [9316bcb](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/9316bcb) |
|||
- | 升级版本v3.1.0;tailwindcss添加class | [9ef05e1](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/9ef05e1) |
|||
- | 时间基准线,默认插件 | [a33ba1e](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/a33ba1e) |
|||
- | 时间轴界面 | [33927e9](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/33927e9) |
|||
- | 时间轴修改状态时提示框增加 | [e841392](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/e841392) |
|||
- | 适配小程序;小程序登录 | [cefc0eb](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/cefc0eb) |
|||
- | 首页项目样式改变 | [8514c85](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/8514c85) |
|||
- | 提交到本地 | [9cbe411](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/9cbe411) |
|||
- | 添加 环境变量,动态控制webview project的path | [8a40481](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/8a40481) |
|||
- | 添加时间轴上下滚动 | [2b81bbc](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/2b81bbc) |
|||
- | 添加项目排序 | [a0b491b](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/a0b491b) |
|||
- | 添加子任务插件 子项目插件 | [7bda7e2](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/7bda7e2) |
|||
- | 问卷功能取消,排名查看功能新增 | [f405a38](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/f405a38) |
|||
- | 细节调整,添加project-webview | [4d9050b](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/4d9050b) |
|||
- | 向右箭头图标变化 | [8e9ca55](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/8e9ca55) |
|||
- | 项目列表, 项目url | [32e005b](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/32e005b) |
|||
- | 项目列表排序 | [224c58b](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/224c58b) |
|||
- | 项目api url设置 | [6cd5245](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/6cd5245) |
|||
- | 修改小程序id | [4206bf2](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/4206bf2) |
|||
- | 引入dayjs | [29b8b93](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/29b8b93) |
|||
- | 字体大小更改 | [82cfdd4](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/82cfdd4) |
|||
- | api封装 | [7d4edfc](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/7d4edfc) |
|||
bind phone | 图形验证码;短信验证码;绑定手机号 | [93ffea2](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/93ffea2) |
|||
- | cache indexedDB处理 | [3388967](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/3388967) |
|||
calendar, tall.js | 上下滑动切换日历的模式,tall.js中domain根据环境变量切换 | [364e25d](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/364e25d) |
|||
- | db store | [6414c4f](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/6414c4f) |
|||
default plugin | 添加默认插件;项目列表;全局项目最大高度设置 | [ed1d87b](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/ed1d87b) |
|||
- | indexedDB | [687394e](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/687394e) |
|||
modules update;network | npm包升级;网络判断,网络不好才开启本地存储 | [ebf7bdc](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/ebf7bdc) |
|||
mp | 兼容小程序,去除window,document等 | [9178255](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/9178255) |
|||
phone-bind | 验证码validate | [a427250](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/a427250) |
|||
pinch | alloy finger实现图片的pinch放大缩小 | [de01343](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/de01343) |
|||
plugin | 插件添加了token及param参数 | [aeb0292](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/aeb0292) |
|||
- | post 封装 | [da52e94](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/da52e94) |
|||
- | tailwindcss添加部分属性 | [5b46b6d](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/5b46b6d) |
|||
- | tall插件封装 | [1bcb920](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/1bcb920) |
|||
task status | 任务状态切换未完 | [7ffd135](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/7ffd135) |
|||
- | ws storage | [21b3a06](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/21b3a06) |
|||
|
|||
|
|||
### 🎨 代码样式 |
|||
范围|描述|commitId |
|||
--|--|-- |
|||
- | 代码格式细节调整 | [cb2532b](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/cb2532b) |
|||
- | 代码审查 | [d75134c](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/d75134c) |
|||
- | 格式细节调整 | [b907a03](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/b907a03) |
|||
- | 更新代码 | [8c27e68](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/8c27e68) |
|||
- | 更新代码 | [1f40a76](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/1f40a76) |
|||
- | 任务快捷方式图标增加 | [4aba872](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/4aba872) |
|||
- | 日常任务修改 | [dfa7ee2](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/dfa7ee2) |
|||
- | 删除插件携带的多余文件 | [0f392bb](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/0f392bb) |
|||
- | 删除多余字段 | [5ae3973](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/5ae3973) |
|||
- | 删除没用代码 | [34b20e1](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/34b20e1) |
|||
- | 删除calendar中多余的console | [e339eec](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/e339eec) |
|||
- | 删除console.log | [5064a38](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/5064a38) |
|||
- | 删除index中没用的alert代码 | [9c9eec7](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/9c9eec7) |
|||
- | 删除mock,console;upload添加loading | [99d42e2](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/99d42e2) |
|||
- | 添加插件数据 | [2f11b42](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/2f11b42) |
|||
- | 图标修改 | [54bca09](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/54bca09) |
|||
- | 无基本变化 | [21ac4bb](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/21ac4bb) |
|||
- | 细节调整 | [2cfc09a](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/2cfc09a) |
|||
- | 修改角色样式 | [73e268e](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/73e268e) |
|||
- | 组件新建 | [89c0035](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/89c0035) |
|||
- | calendar注释 | [a2ec112](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/a2ec112) |
|||
- | indexedDB.js格式整理 | [b0d3a36](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/b0d3a36) |
|||
|
|||
|
|||
### 🐛 Bug 修复 |
|||
范围|描述|commitId |
|||
--|--|-- |
|||
- | 1.时间轴数据渲染 2.时间基准线 | [d643af2](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/d643af2) |
|||
- | 插件bug解决 | [41257eb](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/41257eb) |
|||
- | 初始展示角色修改 | [2ac4053](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/2ac4053) |
|||
- | 定期任务本地缓存和api赋值,未完成 | [5a10856](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/5a10856) |
|||
定期任务本地缓存和api赋值,未完成 | 定期任务本地缓存和api赋值,未完成 | [b22a366](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/b22a366) |
|||
- | 定期任务插件 | [92b3254](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/92b3254) |
|||
- | 定期任务骨架屏修改 | [8ff72dd](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/8ff72dd) |
|||
- | 定期任务接口 | [aa4981c](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/aa4981c) |
|||
- | 定期任务未加载时,显示空的时间轴并能上下滑动 | [ce38093](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/ce38093) |
|||
- | 定期任务key值修改 | [c6688db](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/c6688db) |
|||
- | 骨架屏替换 | [e9fdd71](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/e9fdd71) |
|||
- | 监听时间基本点 | [033fca0](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/033fca0) |
|||
- | 角色栏修改 | [19228d6](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/19228d6) |
|||
- | 角色显示状态修改 | [7d3b906](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/7d3b906) |
|||
- | 解决时间轴报错 | [da1eece](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/da1eece) |
|||
- | 平车演示临时去掉项目快捷方式的toast提示 | [e0b2c23](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/e0b2c23) |
|||
- | 切换到默认项目角色没有激活状态的bug | [438d448](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/438d448) |
|||
- | 切换日历时查询小红点 | [7091789](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/7091789) |
|||
- | 任务开始时间延迟插件 | [992a313](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/992a313) |
|||
- | 日常任务插件遍历时的key值修改 | [cd26285](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/cd26285) |
|||
- | 日常任务插件面板高度修改 | [249f9e4](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/249f9e4) |
|||
- | 日常任务html数据查验 | [880ce5c](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/880ce5c) |
|||
- | 日历无任务时添加小绿点,时间轴刻度无任务不显示时分 | [0f90868](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/0f90868) |
|||
- | 上下滚动时间轴 | [d533a01](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/d533a01) |
|||
- | 上下滑动加载定期任务 | [4090d89](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/4090d89) |
|||
- | 设置时间轴自动滚动到当前位置 | [a3474f8](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/a3474f8) |
|||
- | 时间轴插件 | [225d3cc](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/225d3cc) |
|||
- | 时间轴骨架屏修改 | [ca78d02](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/ca78d02) |
|||
- | 时间轴滚动位置修改 | [551da63](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/551da63) |
|||
- | 时间轴上下滚动数据加载bug修改 | [e82ede4](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/e82ede4) |
|||
- | 时间轴上下滑动 | [4d0ae46](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/4d0ae46) |
|||
- | 时间轴无任务时时间刻度加载修改 | [4921672](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/4921672) |
|||
- | 收到消息修改任务状态 | [c378063](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/c378063) |
|||
- | 手动展开日常任务 | [0a4a622](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/0a4a622) |
|||
- | 提示信息显示bug及日常任务收缩问题 | [f2f06c5](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/f2f06c5) |
|||
- | 跳转详情页返回路径修改 | [c5e17c0](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/c5e17c0) |
|||
- | 下拉加载定期任务传参,时间格式化修改 | [0b95a0e](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/0b95a0e) |
|||
项目列表排序 | 项目列表排序 | [402c563](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/402c563) |
|||
- | 项目列表排序修改 | [fd3c3ac](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/fd3c3ac) |
|||
- | 项目列表排序修改 | [59f4c21](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/59f4c21) |
|||
- | 修改报错 | [531c14d](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/531c14d) |
|||
- | 修改定期任务状态0和4时不加载圆圈 | [30e352f](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/30e352f) |
|||
- | 修改角色栏组件 | [a54c601](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/a54c601) |
|||
- | 修改接口路径 | [df6acf2](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/df6acf2) |
|||
- | 修改小红点传参 | [87b20fd](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/87b20fd) |
|||
- | 修改样式 | [f0ddc90](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/f0ddc90) |
|||
- | 修改main | [749ae9a](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/749ae9a) |
|||
- | api 存storage | [81032ba](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/81032ba) |
|||
ID1000343 | 解决向下预加载查询参数时间没+1颗粒度;以及滚动加载颗粒度写死的问题 | [940603a](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/940603a), closes [#ID1000343](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/issues/ID1000343) |
|||
plugin | 插件解析机制完善 | [0f5a27d](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/0f5a27d) |
|||
project title | 项目标题修改; 切换角色移除script | [5c20017](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/5c20017) |
|||
role | 切换角色的逻辑修正完善 | [4ae534f](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/4ae534f) |
|||
roles | 修复默认显示不是我的角色的问题 | [b69f94f](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/b69f94f) |
|||
task任务逻辑完善 | 减少初始global及regular的不必要请求 | [bd4bd38](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/bd4bd38) |
|||
- | title.vue根据页面栈显示返回按钮;标题文本超出显示... | [0cbacf4](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/0cbacf4) |
|||
|
|||
|
|||
### 📝 文档 |
|||
范围|描述|commitId |
|||
--|--|-- |
|||
- | README.md | [ab0eb05](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/ab0eb05) |
|||
|
|||
|
|||
### 🔧 测试 |
|||
范围|描述|commitId |
|||
--|--|-- |
|||
- | 禁用任务开始操作 | [b5425db](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/b5425db) |
|||
- | 添加测试,测试utils/time.js的computeDurationText | [e758010](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/e758010) |
|||
- | 暂时移除了jest浏览器配置 | [5088d01](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/5088d01) |
|||
|
|||
|
|||
### 🔨 代码重构 |
|||
范围|描述|commitId |
|||
--|--|-- |
|||
- | 界面样式调整 | [4367249](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/4367249) |
|||
- | 去掉tailwindcss | [4bed47e](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/4bed47e) |
|||
- | 任务状态重构 | [4693655](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/4693655) |
|||
- | 删除多余的技术验证界面 | [542ae5b](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/542ae5b) |
|||
- | 删除多余的weekmode store里的东西 | [0841fe0](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/0841fe0) |
|||
- | 下滑时间轴添加备注 | [4fd20e3](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/4fd20e3) |
|||
- | 修改utils/upload 兼容小程序选择客户端文件上传WBS | [8f49129](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/8f49129) |
|||
- | 重构store分层 | [5f6fff8](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/5f6fff8) |
|||
calendar | 日历细节调整 | [1a8d6bf](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/1a8d6bf) |
|||
- | project 代码健壮性完善 | [a3202c5](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/a3202c5) |
|||
store/home | 删除store/home | [db8a3b4](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/db8a3b4) |
|||
task beginTime | 格式化任务开始时间 | [fbc0301](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/fbc0301) |
|||
template | eslint prettier sass uview tailwindcss | [9c966a1](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/9c966a1) |
|||
tip | 任务状态显示及tip组件数据的重构 | [78a5750](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/78a5750) |
|||
tips | 修改任务状态方法重构 | [b57d3ac](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/b57d3ac) |
|||
title.vue | 移除测试的repeat; 样式细节调整 | [c32d2bd](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/c32d2bd) |
|||
|
|||
|
|||
### 🚀 性能优化 |
|||
范围|描述|commitId |
|||
--|--|-- |
|||
- | 1.时间轴筛选相同的时间替换数据 2.整理代码 | [e082ccb](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/e082ccb) |
|||
- | 测试接口 | [215e074](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/215e074) |
|||
- | 插件查询及展示 | [4dba770](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/4dba770) |
|||
- | 角色栏文字颜色修改 | [215c6b3](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/215c6b3) |
|||
- | 解决警告 | [c932b09](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/c932b09) |
|||
- | 日历的更改 | [7353ac8](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/7353ac8) |
|||
- | 数据存储,避免重复调用接口 | [d22308a](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/d22308a) |
|||
- | 提交本地代码 | [e0cf2ed](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/e0cf2ed) |
|||
- | 小红点api缓存修改 | [e992343](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/e992343) |
|||
- | 修改代码格式 | [14123d7](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/14123d7) |
|||
- | 修改定期任务骨架屏高度 | [909a734](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/909a734) |
|||
- | 整理代码 | [7a55315](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/7a55315) |
|||
- | 组件文件夹新建 | [22bfe7b](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/22bfe7b) |
|||
- | 组件文件夹新建 | [17bb8c9](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/17bb8c9) |
|||
- | 组件文件夹新建 | [1421504](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/1421504) |
|||
|
|||
|
|||
### chore |
|||
范围|描述|commitId |
|||
--|--|-- |
|||
- | 删除多余的构建的命令 | [3f4eb2f](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/3f4eb2f) |
|||
- | 添加mp-weixin的构建命令 | [3776a67](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/3776a67) |
|||
信息配置 | 配置eslint等配置 | [7421443](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/7421443) |
|||
- | 修复不能build的问题 | [0b7b91e](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/0b7b91e) |
|||
- | api 封装 | [8dcb8a2](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/8dcb8a2) |
|||
- | dart-sass替换node-sass;删除多余的uni平台包 | [519f28b](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/519f28b) |
|||
- | env host修改 | [a79a4a5](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/a79a4a5) |
|||
- | merge globals | [b0957cc](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/b0957cc) |
|||
- | merge wrr | [5ccc7a5](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/5ccc7a5) |
|||
- | mock | [51c24a5](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/51c24a5) |
|||
package manifest | 去掉了摇树 | [f7c1dd4](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/f7c1dd4) |
|||
pwa 小程序 | 移除了pwa,alloyFinger添加平台判断 | [875fab4](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/875fab4) |
|||
- | uview-ui | [a9ea34b](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/a9ea34b) |
|||
v3.0.1 | tall api 地址从1.0改成了3.0 | [db5afd5](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/db5afd5) |
|||
|
|||
|
|||
范围|描述|commitId |
|||
--|--|-- |
|||
- | style:index | [978f272](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/978f272) |
|||
- | !2 基础模板v1.1.0 | [f5e61dd](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/f5e61dd) |
|||
- | init | [c0f1deb](https://dd.tall.wiki/gitea/jiawei/tall-qcp2.0/commits/c0f1deb) |
|||
|
@ -0,0 +1,101 @@ |
|||
# tall-mui-cli |
|||
|
|||
## 发布注意事项 |
|||
|
|||
环境变量里的`VUE_APP_VERSION=v3.0.1` 如果project路径变了 或者版本升级了, 发行之前一定要跟着改 |
|||
|
|||
本项目, TALL程序主体框架升级, 或者服务端路径变化, 要修改`manifest.json` 下的 `h5.router.base` |
|||
|
|||
--- |
|||
|
|||
## 项目运行 |
|||
|
|||
### 安装依赖 |
|||
``` |
|||
yarn |
|||
``` |
|||
|
|||
### 本地环境运行 |
|||
+ h5 |
|||
``` |
|||
yarn dev:h5 |
|||
``` |
|||
|
|||
浏览器输入网址: |
|||
http://localhost:8080/tall/v3.0.1/#/?u=1217647686598135808&p=1420652719055839232 |
|||
- u: userId |
|||
- p: projectId |
|||
- r: roleId |
|||
- pn: projectName |
|||
- t: taskId |
|||
|
|||
+ 微信小程序 |
|||
``` |
|||
yarn dev:mp-weixin |
|||
``` |
|||
|
|||
+ app |
|||
``` |
|||
yarn dev:app-plus |
|||
``` |
|||
|
|||
### 生产环境构建 |
|||
|
|||
+ h5 |
|||
``` |
|||
yarn build:h5 |
|||
``` |
|||
|
|||
+ app |
|||
``` |
|||
yarn build:app-plus |
|||
``` |
|||
|
|||
+ 微信小程序 |
|||
``` |
|||
yarn build:mp-weixin |
|||
``` |
|||
|
|||
### Customize configuration |
|||
See [Configuration Reference](https://cli.vuejs.org/config/). |
|||
|
|||
## 代码提交 |
|||
|
|||
+ 项目设置了commit lint, commit信息验证;运行`yarn cz` 命令依次填写commit信息即可 |
|||
+ 以及pre-commit钩子执行eslint代码格式检测, 代码格式不符合规则无法提交 |
|||
|
|||
``` |
|||
yarn cz |
|||
``` |
|||
|
|||
## 技术栈 |
|||
|
|||
### UI及工具库 |
|||
+ uni-app的cli构建版本 |
|||
+ vuex vue官方状态管理库 |
|||
+ tailwindcss 公共样式库(注意这个版本不是最新版本, 最新版本安装后报错) |
|||
+ uview-ui uni-app组件库 |
|||
+ alloyfinger 移动端手势库 |
|||
+ dayjs 时间处理库 |
|||
+ pwa 处理缓存, 构建离线应用 |
|||
|
|||
|
|||
### 构建相关 |
|||
+ sass node-sass |
|||
+ prettier 自动格式化代码 |
|||
+ eslint 代码可是校验 |
|||
+ commitlint git commit信息校验 |
|||
+ husky lint-staged git钩子处理commit校验及eslint代码检测 |
|||
+ vue-cli-plugin-mock mock数据 |
|||
|
|||
## H5 indexedDB |
|||
### 设计概要 |
|||
|
|||
db挂载到全局的store上,store存放的数据: |
|||
```js |
|||
{ |
|||
db: null, // object |
|||
name: 'TALL_indexedDB', // string |
|||
version: 1, // number |
|||
} |
|||
``` |
@ -0,0 +1,57 @@ |
|||
const plugins = []; |
|||
|
|||
if (process.env.UNI_OPT_TREESHAKINGNG) { |
|||
plugins.push(require('@dcloudio/vue-cli-plugin-uni-optimize/packages/babel-plugin-uni-api/index.js')); |
|||
} |
|||
|
|||
if ( |
|||
(process.env.UNI_PLATFORM === 'app-plus' && process.env.UNI_USING_V8) || |
|||
(process.env.UNI_PLATFORM === 'h5' && process.env.UNI_H5_BROWSER === 'builtin') |
|||
) { |
|||
const path = require('path'); |
|||
|
|||
const isWin = /^win/.test(process.platform); |
|||
|
|||
const normalizePath = path => (isWin ? path.replace(/\\/g, '/') : path); |
|||
|
|||
const input = normalizePath(process.env.UNI_INPUT_DIR); |
|||
try { |
|||
plugins.push([ |
|||
require('@dcloudio/vue-cli-plugin-hbuilderx/packages/babel-plugin-console'), |
|||
{ |
|||
file(file) { |
|||
file = normalizePath(file); |
|||
if (file.indexOf(input) === 0) { |
|||
return path.relative(input, file); |
|||
} |
|||
return false; |
|||
}, |
|||
}, |
|||
]); |
|||
} catch (e) {} |
|||
} |
|||
|
|||
process.UNI_LIBRARIES = process.UNI_LIBRARIES || ['@dcloudio/uni-ui']; |
|||
process.UNI_LIBRARIES.forEach(libraryName => { |
|||
plugins.push([ |
|||
'import', |
|||
{ |
|||
libraryName: libraryName, |
|||
customName: name => { |
|||
return `${libraryName}/lib/${name}/${name}`; |
|||
}, |
|||
}, |
|||
]); |
|||
}); |
|||
module.exports = { |
|||
presets: [ |
|||
[ |
|||
'@vue/app', |
|||
{ |
|||
modules: 'commonjs', |
|||
useBuiltIns: process.env.UNI_PLATFORM === 'h5' ? 'usage' : 'entry', |
|||
}, |
|||
], |
|||
], |
|||
plugins, |
|||
}; |
@ -0,0 +1 @@ |
|||
module.exports = { extends: ['./node_modules/vue-cli-plugin-commitlint/lib/lint'] }; |
@ -0,0 +1,52 @@ |
|||
module.exports = { |
|||
globalTeardown: '@dcloudio/uni-automator/dist/teardown.js', |
|||
// testEnvironment: '@dcloudio/uni-automator/dist/environment.js',
|
|||
testEnvironmentOptions: { |
|||
compile: true, |
|||
h5: { |
|||
// 为了节省测试时间,可以指定一个 H5 的 url 地址,若不指定,每次运行测试,会先 npm run dev:h5
|
|||
url: 'http://localhost:8080/tall/v3.0.1/#/h5', |
|||
options: { |
|||
headless: true, // 配置是否显示 puppeteer 测试窗口
|
|||
args: ['--no-sandbox'], |
|||
}, |
|||
}, |
|||
'app-plus': { |
|||
// 需要安装 HBuilderX
|
|||
android: { |
|||
executablePath: 'HBuilderX/plugins/launcher/base/android_base.apk', // apk 目录
|
|||
}, |
|||
ios: { |
|||
// uuid 必须配置,目前仅支持模拟器,可以(xcrun simctl list)查看要使用的模拟器 uuid
|
|||
id: '', |
|||
executablePath: 'HBuilderX/plugins/launcher/base/Pandora_simulator.app', // ipa 目录
|
|||
}, |
|||
}, |
|||
'mp-weixin': { |
|||
port: 9420, // 默认 9420
|
|||
account: '', // 测试账号
|
|||
args: '', // 指定开发者工具参数
|
|||
cwd: '', // 指定开发者工具工作目录
|
|||
launch: true, // 是否主动拉起开发者工具
|
|||
teardown: 'disconnect', // 可选值 "disconnect"|"close" 运行测试结束后,断开开发者工具或关闭开发者工具
|
|||
remote: false, // 是否真机自动化测试
|
|||
executablePath: '', // 开发者工具cli路径,默认会自动查找, windows: C:/Program Files (x86)/Tencent/微信web开发者工具/cli.bat", mac: /Applications/wechatwebdevtools.app/Contents/MacOS/cli
|
|||
}, |
|||
'mp-baidu': { |
|||
port: 9430, // 默认 9430
|
|||
args: '', // 指定开发者工具参数
|
|||
cwd: '', // 指定开发者工具工作目录
|
|||
launch: true, // 是否主动拉起开发者工具
|
|||
teardown: 'disconnect', // 可选值 "disconnect"|"close" 运行测试结束后,断开开发者工具或关闭开发者工具
|
|||
remote: false, // 是否真机自动化测试
|
|||
executablePath: '', // 开发者工具cli路径,默认会自动查找
|
|||
}, |
|||
}, |
|||
testTimeout: 15000, |
|||
reporters: ['default'], |
|||
watchPathIgnorePatterns: ['/node_modules/', '/dist/', '/.git/'], |
|||
moduleFileExtensions: ['js', 'json'], |
|||
rootDir: __dirname, |
|||
testMatch: ['<rootDir>/src/test/**/*test.[jt]s?(x)'], // 测试文件目录
|
|||
testPathIgnorePatterns: ['/node_modules/'], |
|||
}; |
@ -0,0 +1,114 @@ |
|||
{ |
|||
"name": "TALL", |
|||
"version": "0.1.0", |
|||
"private": true, |
|||
"scripts": { |
|||
"serve": "npm run dev:h5", |
|||
"build": "npm run build:h5", |
|||
"lint": "vue-cli-service lint", |
|||
"fix": "vue-cli-service lint --fix", |
|||
"test": "npm run test:h5", |
|||
"dev:h5": "cross-env NODE_ENV=development UNI_PLATFORM=h5 vue-cli-service uni-serve --mode development", |
|||
"dev:h5-pro": "cross-env NODE_ENV=development UNI_PLATFORM=h5 vue-cli-service uni-serve --mode production", |
|||
"build:h5-test": "cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build --mode development", |
|||
"build:h5": "cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build --mode production", |
|||
"build:app-plus": "cross-env NODE_ENV=production UNI_PLATFORM=app-plus vue-cli-service uni-build --mode production", |
|||
"build:mp-weixin": "cross-env NODE_ENV=production UNI_PLATFORM=mp-weixin vue-cli-service uni-build --mode production", |
|||
"cz": "npm run log && git add . && git cz", |
|||
"dev:app-plus": "cross-env NODE_ENV=development UNI_PLATFORM=app-plus vue-cli-service uni-build --watch", |
|||
"dev:custom": "cross-env NODE_ENV=development uniapp-cli custom", |
|||
"dev:mp-weixin": "cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin vue-cli-service uni-build --watch", |
|||
"info": "node node_modules/@dcloudio/vue-cli-plugin-uni/commands/info.js", |
|||
"log": "conventional-changelog --config ./node_modules/vue-cli-plugin-commitlint/lib/log -i CHANGELOG.md -s -r 0", |
|||
"test:android": "cross-env UNI_PLATFORM=app-plus UNI_OS_NAME=android jest -i", |
|||
"test:h5": "cross-env UNI_PLATFORM=h5 jest -i", |
|||
"test:ios": "cross-env UNI_PLATFORM=app-plus UNI_OS_NAME=ios jest -i", |
|||
"test:mp-weixin": "cross-env UNI_PLATFORM=mp-weixin jest -i" |
|||
}, |
|||
"dependencies": { |
|||
"@dcloudio/uni-h5": "^2.0.0-32220210818002", |
|||
"@dcloudio/uni-helper-json": "*", |
|||
"@dcloudio/uni-i18n": "^2.0.0-32220210818002", |
|||
"@dcloudio/uni-mp-vue": "^2.0.0-32220210818002", |
|||
"@dcloudio/uni-mp-weixin": "^2.0.0-32220210818002", |
|||
"@dcloudio/uni-stat": "^2.0.0-32220210818002", |
|||
"@vue/shared": "^3.2.6", |
|||
"dayjs": "^1.10.6", |
|||
"flyio": "^0.6.2", |
|||
"lodash": "^4.17.21", |
|||
"regenerator-runtime": "^0.12.1", |
|||
"uview-ui": "^1.8.5", |
|||
"vue": "^2.6.11", |
|||
"vuex": "^3.2.0" |
|||
}, |
|||
"devDependencies": { |
|||
"@babel/runtime": "~7.12.0", |
|||
"@dcloudio/types": "^2.5.1", |
|||
"@dcloudio/uni-automator": "^2.0.0-32220210818002", |
|||
"@dcloudio/uni-cli-shared": "^2.0.0-32220210818002", |
|||
"@dcloudio/uni-migration": "^2.0.0-32220210818002", |
|||
"@dcloudio/uni-template-compiler": "^2.0.0-32220210818002", |
|||
"@dcloudio/vue-cli-plugin-hbuilderx": "^2.0.0-32220210818002", |
|||
"@dcloudio/vue-cli-plugin-uni": "^2.0.0-32220210818002", |
|||
"@dcloudio/vue-cli-plugin-uni-optimize": "^2.0.0-32220210818002", |
|||
"@dcloudio/webpack-uni-mp-loader": "^2.0.0-32220210818002", |
|||
"@dcloudio/webpack-uni-pages-loader": "^2.0.0-32220210818002", |
|||
"@vue/cli-plugin-babel": "~4.5.0", |
|||
"@vue/cli-plugin-eslint": "~4.5.0", |
|||
"@vue/cli-plugin-vuex": "~4.5.0", |
|||
"@vue/cli-service": "~4.5.0", |
|||
"@vue/eslint-config-prettier": "^6.0.0", |
|||
"autoprefixer": "^9.8.6", |
|||
"babel-eslint": "^10.1.0", |
|||
"babel-plugin-import": "^1.11.0", |
|||
"commitizen": "^4.0.3", |
|||
"commitlint": "^8.2.0", |
|||
"compression-webpack-plugin": "^5.0.2", |
|||
"conventional-changelog-cli": "^2.0.28", |
|||
"core-js": "^3.16.3", |
|||
"cross-env": "^7.0.3", |
|||
"eslint": "^6.7.2", |
|||
"eslint-plugin-prettier": "^3.4.1", |
|||
"eslint-plugin-vue": "^6.2.2", |
|||
"husky": "^3.0.9", |
|||
"jest": "^25.4.0", |
|||
"lint-staged": "^11.1.2", |
|||
"mini-types": "*", |
|||
"miniprogram-api-typings": "^3.4.3", |
|||
"postcss": "^7.0.36", |
|||
"postcss-class-rename": "^1.0.1", |
|||
"postcss-comment": "^2.0.0", |
|||
"prettier": "^2.2.1", |
|||
"puppeteer": "^10.2.0", |
|||
"right-pad": "^1.0.1", |
|||
"sass": "^1.38.2", |
|||
"sass-loader": "^8.0.2", |
|||
"vue-cli-plugin-commitlint": "~1.0.12", |
|||
"vue-template-compiler": "^2.6.11" |
|||
}, |
|||
"browserslist": [ |
|||
"Android >= 4", |
|||
"ios >= 8" |
|||
], |
|||
"config": { |
|||
"commitizen": { |
|||
"path": "./node_modules/vue-cli-plugin-commitlint/lib/cz" |
|||
} |
|||
}, |
|||
"husky": { |
|||
"hooks": { |
|||
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS", |
|||
"pre-commit": "lint-staged" |
|||
} |
|||
}, |
|||
"lint-staged": { |
|||
"src/**/*.{js,json,css,vue}": [ |
|||
"eslint --fix", |
|||
"git add" |
|||
], |
|||
"*.js": "eslint --cache --fix" |
|||
}, |
|||
"uni-app": { |
|||
"scripts": {} |
|||
} |
|||
} |
@ -0,0 +1,21 @@ |
|||
const path = require('path'); |
|||
|
|||
module.exports = { |
|||
parser: require('postcss-comment'), |
|||
plugins: [ |
|||
require('postcss-import')({ |
|||
resolve(id, basedir, importOptions) { |
|||
if (id.startsWith('~@/')) { |
|||
return path.resolve(process.env.UNI_INPUT_DIR, id.substr(3)); |
|||
} else if (id.startsWith('@/')) { |
|||
return path.resolve(process.env.UNI_INPUT_DIR, id.substr(2)); |
|||
} else if (id.startsWith('/') && !id.startsWith('//')) { |
|||
return path.resolve(process.env.UNI_INPUT_DIR, id.substr(1)); |
|||
} |
|||
return id; |
|||
}, |
|||
}), |
|||
require('autoprefixer')({ remove: process.env.UNI_PLATFORM !== 'h5' }), |
|||
require('@dcloudio/vue-cli-plugin-uni/packages/postcss'), |
|||
], |
|||
}; |
After Width: | Height: | Size: 9.2 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 799 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 215 B |
@ -0,0 +1,28 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="zh-CN"> |
|||
|
|||
<head> |
|||
<meta charset="utf-8"> |
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
|||
<title> |
|||
<%= htmlWebpackPlugin.options.title %> |
|||
</title> |
|||
<script> |
|||
// document.addEventListener('DOMContentLoaded', function() { |
|||
// document.documentElement.style.fontSize = document.documentElement.clientWidth / 20 + 'px' |
|||
// }) |
|||
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)')) |
|||
document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />') |
|||
</script> |
|||
<link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" /> |
|||
</head> |
|||
|
|||
<body> |
|||
<noscript> |
|||
<strong>Please enable JavaScript to continue.</strong> |
|||
</noscript> |
|||
<div id="app"></div> |
|||
<!-- built files will be auto injected --> |
|||
</body> |
|||
|
|||
</html> |
@ -0,0 +1,2 @@ |
|||
User-agent: * |
|||
Disallow: |
@ -0,0 +1,159 @@ |
|||
<script> |
|||
import { mapActions, mapGetters, mapMutations, mapState } from 'vuex'; |
|||
|
|||
export default { |
|||
async onLaunch(options) { |
|||
// const obj = { title: '暴风眼Typhoneye' }; |
|||
// uni.showShareMenu(obj); |
|||
console.log('options: ', options); |
|||
this.checkNetwork(); // 监听网络状态 |
|||
this.getSystemInfo(); // 获取系统设备信息 |
|||
this.autoUpdate(); |
|||
/* #ifdef MP-WEIXIN */ |
|||
await this.signin(); |
|||
/* #endif */ |
|||
|
|||
/* #ifdef H5 */ |
|||
options.query.url && (this.$t.domain = options.query.url); |
|||
if (!this.token) { |
|||
// 不论有没有token都直接从userId获取token |
|||
// token有过期时间 从本地获取可能是过期 干脆直接从userId获取 |
|||
if (!options.query || !options.query.u) { |
|||
// 参数里没有u (userId)提示 |
|||
this.$t.ui.showToast('缺少用户信息参数'); |
|||
} else { |
|||
const data = await this.getToken(options.query.u); |
|||
this.noPhone(data.phone); |
|||
} |
|||
} |
|||
/* #endif */ |
|||
this.initSocket(); |
|||
}, |
|||
|
|||
computed: { |
|||
...mapGetters(['useStorage']), |
|||
...mapState('user', ['token']), |
|||
}, |
|||
|
|||
methods: { |
|||
...mapActions('user', ['getToken']), |
|||
...mapActions('socket', ['initSocket']), |
|||
...mapMutations(['setNetworkConnected', 'setSystemInfo']), |
|||
...mapMutations('user', ['setToken', 'setUser']), |
|||
|
|||
// 检测当前是使用的是否是小程序最新版 |
|||
autoUpdate() { |
|||
var self = this; |
|||
// 获取小程序更新机制兼容 |
|||
const updateManager = wx.getUpdateManager(); |
|||
//1. 检查小程序是否有新版本发布 |
|||
updateManager.onCheckForUpdate(function (res) { |
|||
// 请求完新版本信息的回调 |
|||
if (res.hasUpdate) { |
|||
//检测到新版本,需要更新,给出提示 |
|||
wx.showModal({ |
|||
title: '更新提示', |
|||
content: '检测到新版本,是否下载新版本并重启小程序?', |
|||
success: function (res) { |
|||
if (res.confirm) { |
|||
//2. 用户确定下载更新小程序,小程序下载及更新静默进行 |
|||
self.downLoadAndUpdate(updateManager); |
|||
} else if (res.cancel) { |
|||
//用户点击取消按钮的处理,如果需要强制更新,则给出二次弹窗,如果不需要,则这里的代码都可以删掉了 |
|||
wx.showModal({ |
|||
title: '温馨提示', |
|||
content: '本次版本更新涉及到新的功能添加,旧版本可能无法正常访问哦', |
|||
showCancel: false, //隐藏取消按钮 |
|||
confirmText: '确定更新', //只保留确定更新按钮 |
|||
success: function (res) { |
|||
if (res.confirm) { |
|||
//下载新版本,并重新应用 |
|||
self.downLoadAndUpdate(updateManager); |
|||
} |
|||
}, |
|||
}); |
|||
} |
|||
}, |
|||
}); |
|||
} |
|||
}); |
|||
}, |
|||
downLoadAndUpdate(updateManager) { |
|||
wx.showLoading(); |
|||
//静默下载更新小程序新版本 |
|||
updateManager.onUpdateReady(function () { |
|||
wx.hideLoading(); |
|||
//新的版本已经下载好,调用 applyUpdate 应用新版本并重启 |
|||
updateManager.applyUpdate(); |
|||
}); |
|||
updateManager.onUpdateFailed(function () { |
|||
// 新的版本下载失败 |
|||
wx.showModal({ |
|||
title: '已经有新版本了哟', |
|||
content: '新版本已经上线啦,请您删除当前小程序,重新搜索打开哟', |
|||
}); |
|||
}); |
|||
}, |
|||
// 检查网络状态 设置store里的网络状态变量 |
|||
// 网络连接 且 不是2g 不是3g 才算是网络连接; 否则不是 将启用本地存储 |
|||
checkNetwork() { |
|||
uni.getNetworkType({ |
|||
success: ({ networkType }) => { |
|||
this.setNetworkConnected(!(networkType === 'none' || networkType === '2g' || networkType === '3g')); |
|||
}, |
|||
}); |
|||
// 监听网络状态的变化 |
|||
uni.onNetworkStatusChange(({ isConnected, networkType }) => { |
|||
this.setNetworkConnected(isConnected && !(networkType === '2g' || networkType === '3g')); |
|||
}); |
|||
}, |
|||
|
|||
// 登录 |
|||
async signin() { |
|||
try { |
|||
const data = await this.$u.api.signin(); |
|||
if (data && data.token) { |
|||
this.setUser(data); |
|||
this.setToken(data.token); |
|||
// this.noPhone(data.phone); |
|||
} else { |
|||
this.$t.ui.showToast('返回数据异常'); |
|||
} |
|||
} catch (error) { |
|||
console.error('error: ', error); |
|||
this.$t.ui.showToast(error || '登录失败'); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 没有手机号 跳转绑定手机号的界面 |
|||
* @param {string} phone |
|||
*/ |
|||
async noPhone(phone) { |
|||
if (!phone) { |
|||
// this.$u.route('/pages/get-phone-power/get-phone-power'); |
|||
this.$u.route('/pages/phone-bind/phone-bind'); |
|||
} |
|||
}, |
|||
|
|||
// 获取系统设备信息 |
|||
getSystemInfo() { |
|||
uni.getSystemInfo({ |
|||
success: result => { |
|||
this.setSystemInfo(result); |
|||
}, |
|||
fail: error => { |
|||
console.error('getSystemInfo fail:', error); |
|||
}, |
|||
}); |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss"> |
|||
@import './common/styles/tailwind.scss'; |
|||
@import './common/styles/iconfont.scss'; |
|||
@import 'uview-ui/index.scss'; |
|||
@import './common/styles/app.scss'; |
|||
</style> |
@ -0,0 +1,67 @@ |
|||
const apiUrl = process.env.VUE_APP_API_URL; |
|||
export const carbasics = `${apiUrl}/carbasics/v4.0`; |
|||
const patient = `${carbasics}/patient`; // 患者相关接口
|
|||
const firstAid = `${carbasics}/firstAid`; // 急救数据相关接口
|
|||
|
|||
// 获取急救/出院数据列表
|
|||
export const querySelf = { |
|||
async index(params) { |
|||
let timer = null; |
|||
timer = setTimeout(() => { |
|||
uni.$t.ui.showLoading('正在努力查询...'); |
|||
timer = null; |
|||
}, 10); |
|||
try { |
|||
const data = await uni.$u.http.post(`${patient}/querySelf`, params); |
|||
clearTimeout(timer); |
|||
return data; |
|||
} catch (error) { |
|||
clearTimeout(timer); |
|||
throw new Error(error); |
|||
} |
|||
}, |
|||
}; |
|||
|
|||
/** |
|||
* 批量提交急救信息 |
|||
* @param {object} param 提交的参数 |
|||
* 提交信息 |
|||
* @param { Array } codeAndAnswerList code和答案 |
|||
* @param { String } firstAidId 项目id |
|||
* @param { Number } userType 提交人类型(0平车 1人) |
|||
*/ |
|||
export const setRecord = { |
|||
async index(params) { |
|||
try { |
|||
const param = { |
|||
...params, |
|||
userType: 1, |
|||
}; |
|||
const data = await uni.$u.http.post(`${patient}/aidRecord`, { param }); |
|||
return data; |
|||
} catch (error) { |
|||
uni.$t.ui.showToast(error); |
|||
throw new Error(error); |
|||
} |
|||
}, |
|||
}; |
|||
|
|||
const install = (Vue, vm) => { |
|||
vm.$u.api = { ...vm.$u.api } || {}; |
|||
// 存储患者病况信息
|
|||
vm.$u.api.setRecord = params => setRecord.index(params); |
|||
// 获取急救/出院数据列表
|
|||
vm.$u.api.querySelf = params => querySelf.index(params); |
|||
// 患者加入急救
|
|||
vm.$u.api.joinAid = params => vm.$u.post(`${firstAid}/join`, params); |
|||
// 患者退出急救
|
|||
vm.$u.api.quitAid = params => vm.$u.post(`${firstAid}/quit`, params); |
|||
// 删除演示的急救患者数据
|
|||
vm.$u.api.delDemo = params => vm.$u.post(`${firstAid}/delDemo`, params); |
|||
// 删除演示的急救患者数据
|
|||
vm.$u.api.savePatient = params => vm.$u.post(`${patient}/savePatient`, params); |
|||
// 上传身份证图像识别
|
|||
vm.$u.api.identifyWords = `${carbasics}/ocr/identifyWords`; |
|||
}; |
|||
|
|||
export default { install }; |
@ -0,0 +1,19 @@ |
|||
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); |
|||
|
|||
//创建分享连接
|
|||
vm.$u.api.createShare = param => vm.$u.post(`${uni.$t.domain}/share/create`, param); |
|||
|
|||
//点击分享连接
|
|||
vm.$u.api.clickShare = param => vm.$u.post(`${uni.$t.domain}/share/click`, param); |
|||
|
|||
//查询医院是否填写了调查问卷
|
|||
vm.$u.api.queryNotWrite = param => vm.$u.post(`${uni.$t.domain}/questionnaire/queryNotWrite`, param); |
|||
|
|||
// 根据项目id查询当前项目是不是 医院体验项目
|
|||
vm.$u.api.getByProject = param => vm.$u.post(`${uni.$t.domain}/organization/getByProject`, param); |
|||
}; |
|||
|
|||
export default { install }; |
@ -0,0 +1,49 @@ |
|||
const url = process.env.VUE_APP_API_URL; |
|||
// 查询首页按钮的名称及跳转
|
|||
export const queryMustShow = { |
|||
async index(params) { |
|||
try { |
|||
const data = await uni.$u.http.post(`${url}/carbasics/v4.0/role/queryMustShow`, params); |
|||
return data; |
|||
} catch (error) { |
|||
throw new Error(error); |
|||
} |
|||
}, |
|||
}; |
|||
|
|||
export const queryLastRoleChoose = { |
|||
async index(params) { |
|||
try { |
|||
const data = await uni.$u.http.post(`${url}/carbasics/v4.0/role/queryLastRoleChoose`, params); |
|||
return data; |
|||
} catch (error) { |
|||
throw new Error(error); |
|||
} |
|||
}, |
|||
}; |
|||
|
|||
export const saveRoleRecord = { |
|||
async index(params) { |
|||
try { |
|||
await uni.$u.http.post(`${url}/carbasics/v4.0/role/saveRoleRecord`, params); |
|||
} catch (error) { |
|||
throw new Error(error); |
|||
} |
|||
}, |
|||
}; |
|||
|
|||
const install = (Vue, vm) => { |
|||
vm.$u.api = { ...vm.$u.api } || {}; |
|||
// 根据项目id查找所有体验角色
|
|||
vm.$u.api.queryMustShow = params => queryMustShow.index(params); |
|||
// 根据项目id查找上次退出项目时所选择的角色
|
|||
vm.$u.api.queryLastRoleChoose = params => queryLastRoleChoose.index(params); |
|||
// 保存当前用户在当前项目最后一次选择的角色
|
|||
vm.$u.api.saveRoleRecord = params => saveRoleRecord.index(params); |
|||
// 根据项目id查找角色
|
|||
vm.$u.api.findShowRole = param => vm.$u.post(`${uni.$t.domain}/role/show`, param); |
|||
// 根据项目id查找所有成员
|
|||
vm.$u.api.queryChecker = param => vm.$u.post(`${uni.$t.domain}/deliver/queryChecker`, param); |
|||
}; |
|||
|
|||
export default { install }; |
@ -0,0 +1,109 @@ |
|||
const apiUrl = process.env.VUE_APP_API_URL; |
|||
export const tall = `${apiUrl}/tall3/v3.0`; |
|||
export const carbasics = `${apiUrl}/carbasics/v4.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); |
|||
} |
|||
}, |
|||
}; |
|||
|
|||
// 获取手机号
|
|||
export const bindPhone = { |
|||
async index(params) { |
|||
try { |
|||
/* #endif */ |
|||
const data = await uni.$u.http.post(`${tall}/users/bindingNoCode`, params); |
|||
return data; |
|||
} catch (error) { |
|||
throw new Error(error); |
|||
} |
|||
}, |
|||
}; |
|||
|
|||
// 绑定手机号(合并或者替换)
|
|||
export const bindNowPhone = { |
|||
async index(params) { |
|||
try { |
|||
/* #endif */ |
|||
const data = await uni.$u.http.post(`${tall}/users/merge`, params); |
|||
return data; |
|||
} catch (error) { |
|||
throw new Error(error); |
|||
} |
|||
}, |
|||
}; |
|||
|
|||
// 查询首页按钮的名称及跳转
|
|||
export const getQueryButton = { |
|||
async index(params) { |
|||
try { |
|||
/* #endif */ |
|||
const data = await uni.$u.http.post(`${carbasics}/questionnaire/queryButton`, params); |
|||
return data; |
|||
} catch (error) { |
|||
return null; |
|||
} |
|||
}, |
|||
}; |
|||
|
|||
// 查询当前用户是否展示宣传页
|
|||
export const queryIsShow = { |
|||
async index(params) { |
|||
try { |
|||
/* #endif */ |
|||
const data = await uni.$u.http.post(`${carbasics}/questionnaire/queryIsShow`, 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.bindPhone = params => bindPhone.index(params); |
|||
// 手机号已被注册,是否合并
|
|||
vm.$u.api.bindNowPhone = params => bindNowPhone.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.updateUserInfo = params => vm.$u.http.post(`${tall}/users/userInfo`, params); |
|||
|
|||
// 获取项目列表
|
|||
vm.$u.api.getProjects = (startTime, endTime) => vm.$u.post(`${tall}/project/query`, { startTime, endTime }); |
|||
// 查询首页的按钮展示及跳转
|
|||
vm.$u.api.getQueryButton = params => getQueryButton.index(params); |
|||
// 查询当前用户是否展示宣传页按钮
|
|||
vm.$u.api.queryIsShow = params => queryIsShow.index(params); |
|||
// 查询日历是否有小红点
|
|||
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); |
|||
// 删除某个项目
|
|||
vm.$u.api.delProject = projectId => vm.$u.post(`${tall}/project/deleteProject`, { projectId }); |
|||
}; |
|||
|
|||
export default { install }; |
@ -0,0 +1,17 @@ |
|||
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); |
|||
//新建任务
|
|||
vm.$u.api.saveTask = param => vm.$u.post(`${uni.$t.domain}/task/save`, param); |
|||
//克隆任务
|
|||
vm.$u.api.cloneTask = param => vm.$u.post(`${uni.$t.domain}/task/clone`, param); |
|||
//模糊查询 查找项目下的任务
|
|||
vm.$u.api.queryTaskOfProject = param => vm.$u.post(`${uni.$t.domain}/task/queryTaskOfProject`, param); |
|||
}; |
|||
|
|||
export default { install }; |
@ -0,0 +1,7 @@ |
|||
const install = (Vue, vm) => { |
|||
vm.$u.api = { ...vm.$u.api } || {}; |
|||
// 导入wbs
|
|||
vm.$u.api.import = formData => vm.$t.chooseAndUpload(`${uni.$t.domain}/wbs`, formData); |
|||
}; |
|||
|
|||
export default { install }; |
@ -0,0 +1,7 @@ |
|||
.min-0 { |
|||
min-width: 0; |
|||
} |
|||
|
|||
.flex-shrink-0 { |
|||
flex-shrink: 0; |
|||
} |
@ -0,0 +1,473 @@ |
|||
<template> |
|||
<view class="zzx-calendar"> |
|||
<view class="calendar-heander"> |
|||
{{ timeStr }} |
|||
</view> |
|||
|
|||
<!-- 星期几标题 --> |
|||
<view class="calendar-weeks"> |
|||
<view class="calendar-week" :class="{ 'text-red-500': week === '六' || week === '日' }" v-for="(week, index) in weeks" :key="index"> |
|||
{{ week }} |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="calendar-content"> |
|||
<swiper |
|||
class="calendar-swiper" |
|||
:style="{ |
|||
width: '100%', |
|||
height: sheight, |
|||
}" |
|||
:indicator-dots="false" |
|||
:autoplay="false" |
|||
:duration="duration" |
|||
:current="current" |
|||
@change="changeSwp" |
|||
:circular="true" |
|||
> |
|||
<swiper-item class="calendar-item" v-for="sitem in swiper" :key="sitem"> |
|||
<view class="calendar-days"> |
|||
<!-- 当前的 --> |
|||
<template v-if="sitem === current"> |
|||
<view |
|||
class="calendar-day" |
|||
v-for="(item, index) in days" |
|||
:key="index" |
|||
:class="{ 'day-hidden': !item.show }" |
|||
@click="clickItem(item)" |
|||
> |
|||
<view class="date" :class="[item.isToday ? todayClass : '', item.fullDate === selectedDate ? checkedClass : '']"> |
|||
{{ item.time.getDate() }} |
|||
</view> |
|||
<view class="dot-show" v-if="item.info === '0'" :style="dotStyle"> </view> |
|||
</view> |
|||
</template> |
|||
<template v-else> |
|||
<!-- 下一个月/周 --> |
|||
<template v-if="current - sitem === 1 || current - sitem === -2"> |
|||
<view |
|||
class="calendar-day" |
|||
v-for="(item, index) in predays" |
|||
:key="index" |
|||
:class="{ |
|||
'day-hidden': !item.show, |
|||
}" |
|||
> |
|||
<view class="date" :class="[item.isToday ? todayClass : '']"> |
|||
{{ item.time.getDate() }} |
|||
</view> |
|||
</view> |
|||
</template> |
|||
<!-- 上一个月/周 --> |
|||
<template v-else> |
|||
<view |
|||
class="calendar-day" |
|||
v-for="(item, index) in nextdays" |
|||
:key="index" |
|||
:class="{ |
|||
'day-hidden': !item.show, |
|||
}" |
|||
> |
|||
<view class="date" :class="[item.isToday ? todayClass : '']"> |
|||
{{ item.time.getDate() }} |
|||
</view> |
|||
</view> |
|||
</template> |
|||
</template> |
|||
</view> |
|||
</swiper-item> |
|||
</swiper> |
|||
|
|||
<!-- <view class="mode-change" @click="changeMode"> |
|||
<view :class="weekMode ? 'mode-arrow-bottom' : 'mode-arrow-top'"> </view> |
|||
</view> --> |
|||
</view> |
|||
|
|||
<view class="flex justify-center u-font-18" style="color: #3b82f6" @click="goToday"> 今日 </view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapState } from 'vuex'; |
|||
import { gegerateDates, formatDate } from './generateDates.js'; |
|||
|
|||
export default { |
|||
props: { |
|||
duration: { type: Number, default: 500 }, |
|||
// 是否返回今日 |
|||
showBack: { type: Boolean, default: false }, |
|||
// 今日的自定义样式class |
|||
todayClass: { type: String, default: 'is-today' }, |
|||
// 选中日期的样式class |
|||
checkedClass: { type: String, default: 'is-checked' }, |
|||
// 打点日期的自定义样式 |
|||
dotStyle: { |
|||
type: Object, |
|||
default: () => { |
|||
return { background: '#4ade80' }; |
|||
}, |
|||
}, |
|||
}, |
|||
|
|||
watch: { |
|||
dotList: function (newvalue) { |
|||
const days = this.days.slice(0); |
|||
const index = days.findIndex(day => day.show); |
|||
days.forEach((day, i) => { |
|||
newvalue.forEach((item, j) => { |
|||
if (i - index === j) { |
|||
day.info = item; |
|||
} |
|||
}); |
|||
}); |
|||
this.days = days; |
|||
}, |
|||
}, |
|||
|
|||
data() { |
|||
return { |
|||
weeks: ['日', '一', '二', '三', '四', '五', '六'], // 周 |
|||
current: 1, |
|||
currentYear: '', |
|||
currentMonth: '', |
|||
currentDate: '', |
|||
days: [], |
|||
weekMode: false, // false -> 月 true -> 显示周 |
|||
swiper: [0, 1, 2], |
|||
selectedDate: formatDate(new Date(), 'yyyy-MM-dd'), // 当前选中的日期 |
|||
start: '', |
|||
end: '', |
|||
}; |
|||
}, |
|||
|
|||
computed: { |
|||
...mapState('project', ['dotList']), |
|||
sheight() { |
|||
// 根据年月判断有多少行 |
|||
// 判断该月有多少天 |
|||
let h = '35px'; |
|||
if (!this.weekMode) { |
|||
const d = new Date(this.currentYear, this.currentMonth, 0); |
|||
const days = d.getDate(); // 判断本月有多少天 |
|||
let day = new Date(d.setDate(1)).getDay(); |
|||
// if (day === 0) { |
|||
// day = 7; |
|||
// } |
|||
const pre = 8 - day; |
|||
const rows = Math.ceil((days - pre) / 7) + 1; |
|||
h = 35 * rows + 'px'; |
|||
} |
|||
return h; |
|||
}, |
|||
|
|||
// 当前日期 年月 |
|||
timeStr() { |
|||
let str = ''; |
|||
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate); |
|||
const y = d.getFullYear(); |
|||
const m = d.getMonth() + 1 <= 9 ? `0${d.getMonth() + 1}` : d.getMonth() + 1; |
|||
str = `${y}年${m}月`; |
|||
return str; |
|||
}, |
|||
|
|||
// 上一周期的days书籍 |
|||
predays() { |
|||
let pres = []; |
|||
if (this.weekMode) { |
|||
// 周模式 |
|||
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate); |
|||
d.setDate(d.getDate() - 7); |
|||
pres = gegerateDates(d, 'week'); |
|||
} else { |
|||
// 月模式 |
|||
const d = new Date(this.currentYear, this.currentMonth - 2, 1); |
|||
pres = gegerateDates(d, 'month'); |
|||
} |
|||
return pres; |
|||
}, |
|||
|
|||
// 下一周期的days书籍 |
|||
nextdays() { |
|||
let nexts = []; |
|||
if (this.weekMode) { |
|||
// 周模式 |
|||
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate); |
|||
d.setDate(d.getDate() + 7); |
|||
nexts = gegerateDates(d, 'week'); |
|||
} else { |
|||
// 月模式 |
|||
const d = new Date(this.currentYear, this.currentMonth, 1); |
|||
nexts = gegerateDates(d, 'month'); |
|||
} |
|||
return nexts; |
|||
}, |
|||
}, |
|||
|
|||
created() { |
|||
this.initDate(); |
|||
this.start = this.$moment().startOf('month').valueOf(); |
|||
this.end = this.$moment().endOf('month').valueOf(); |
|||
}, |
|||
|
|||
methods: { |
|||
// |
|||
/** |
|||
* 滑动切换上下周期 |
|||
* 根据前一个减去目前的值我们可以判断是下一个月/周还是上一个月/周 |
|||
* current - pre === 1, -2 下一个月/周 |
|||
* current - pre === -1, 2 上一个月或者上一周 |
|||
*/ |
|||
changeSwp(e) { |
|||
const pre = this.current; |
|||
const current = e.target.current; |
|||
this.current = current; |
|||
|
|||
if (current - pre === 1 || current - pre === -2) { |
|||
// 下一个月 或 下一周 |
|||
this.daysNext(); |
|||
const arr = this.days.filter(s => s.show); |
|||
const end = `${arr[arr.length - 1].fullDate} 23:59:59`; |
|||
this.start = this.$moment(arr[0].fullDate).valueOf(); |
|||
this.end = this.$moment(end).valueOf(); |
|||
this.$emit('handleFindPoint', this.start, this.end); |
|||
} else { |
|||
// 上一个月 或 上一周 |
|||
this.daysPre(); |
|||
const arr = this.days.filter(s => s.show); |
|||
const end = `${arr[arr.length - 1].fullDate} 23:59:59`; |
|||
this.start = this.$moment(arr[0].fullDate).valueOf(); |
|||
this.end = this.$moment(end).valueOf(); |
|||
this.$emit('handleFindPoint', this.start, this.end); |
|||
} |
|||
}, |
|||
|
|||
// 初始化日历的方法 |
|||
initDate(cur) { |
|||
let date = ''; |
|||
if (cur) { |
|||
date = new Date(cur); |
|||
} else { |
|||
date = new Date(); |
|||
} |
|||
this.currentDate = date.getDate(); // 今日几号 |
|||
this.currentYear = date.getFullYear(); // 当前年份 |
|||
this.currentMonth = date.getMonth() + 1; // 当前月份 |
|||
this.currentWeek = date.getDay() === 0 ? 7 : date.getDay(); // 1...6,0 星期几 |
|||
// const nowY = new Date().getFullYear(); // 当前年份 |
|||
// const nowM = new Date().getMonth() + 1; |
|||
// const nowD = new Date().getDate(); // 今日日期 几号 |
|||
// const nowW = new Date().getDay(); |
|||
// this.selectedDate = formatDate(new Date(), 'yyyy-MM-dd') |
|||
this.days = []; |
|||
let days = []; |
|||
if (this.weekMode) { |
|||
days = gegerateDates(date, 'week'); |
|||
// this.selectedDate = days[0].fullDate; |
|||
} else { |
|||
days = gegerateDates(date, 'month'); |
|||
// const sel = new Date(this.selectedDate.replace('-', '/').replace('-', '/')); |
|||
// const isMonth = sel.getFullYear() === this.currentYear && (sel.getMonth() + 1) === this.currentMonth; |
|||
// if(!isMonth) { |
|||
// this.selectedDate = formatDate(new Date(this.currentYear, this.currentMonth-1,1), 'yyyy-MM-dd') |
|||
// } |
|||
} |
|||
// 设置小红点 |
|||
days.forEach((day, i) => { |
|||
this.dotList.forEach((item, j) => { |
|||
if (i === j) { |
|||
day.info = item; |
|||
} |
|||
}); |
|||
}); |
|||
this.days = days; |
|||
// 派发事件,时间发生改变 |
|||
let obj = { |
|||
start: '', |
|||
end: '', |
|||
}; |
|||
if (this.weekMode) { |
|||
obj.start = this.days[0].time; |
|||
obj.end = this.days[6].time; |
|||
} else { |
|||
const start = new Date(this.currentYear, this.currentMonth - 1, 1); |
|||
const end = new Date(this.currentYear, this.currentMonth, 0); |
|||
obj.start = start; |
|||
obj.end = end; |
|||
} |
|||
this.$emit('days-change', obj); |
|||
}, |
|||
|
|||
// 上一个 |
|||
daysPre() { |
|||
if (this.weekMode) { |
|||
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate); |
|||
d.setDate(d.getDate() - 7); |
|||
this.initDate(d); |
|||
} else { |
|||
const d = new Date(this.currentYear, this.currentMonth - 2, 1); |
|||
this.initDate(d); |
|||
} |
|||
}, |
|||
|
|||
// 下一个 |
|||
daysNext() { |
|||
if (this.weekMode) { |
|||
const d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate); |
|||
d.setDate(d.getDate() + 7); |
|||
this.initDate(d); |
|||
} else { |
|||
const d = new Date(this.currentYear, this.currentMonth, 1); |
|||
this.initDate(d); |
|||
} |
|||
}, |
|||
|
|||
// 切换模式 |
|||
changeMode() { |
|||
const premode = this.weekMode; |
|||
let isweek = false; |
|||
if (premode) { |
|||
isweek = !!this.days.find(item => item.fullDate === this.selectedDate); |
|||
} |
|||
this.weekMode = !this.weekMode; |
|||
let d = new Date(this.currentYear, this.currentMonth - 1, this.currentDate); |
|||
const sel = new Date(this.selectedDate.replace('-', '/').replace('-', '/')); |
|||
const isMonth = sel.getFullYear() === this.currentYear && sel.getMonth() + 1 === this.currentMonth; |
|||
if ((this.selectedDate && isMonth) || isweek) { |
|||
d = new Date(this.selectedDate.replace('-', '/').replace('-', '/')); |
|||
} |
|||
this.initDate(d); |
|||
}, |
|||
|
|||
// 点击日期 |
|||
clickItem(e) { |
|||
this.selectedDate = e.fullDate; |
|||
this.$emit('selected-change', e); |
|||
}, |
|||
|
|||
// 返回 |
|||
goToday() { |
|||
const d = new Date(); |
|||
this.initDate(d); |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.zzx-calendar { |
|||
width: 100%; |
|||
height: auto; |
|||
background-color: #fff; |
|||
padding-bottom: 10px; |
|||
|
|||
.calendar-heander { |
|||
text-align: center; |
|||
padding: 16px 0; |
|||
position: relative; |
|||
font-size: 15px; |
|||
} |
|||
|
|||
.calendar-weeks { |
|||
width: 100%; |
|||
display: flex; |
|||
flex-flow: row nowrap; |
|||
margin-bottom: 10px; |
|||
justify-content: center; |
|||
align-items: center; |
|||
font-size: 12px; |
|||
color: #9ca3af; |
|||
font-weight: bold; |
|||
|
|||
.calendar-week { |
|||
width: calc(100% / 7); |
|||
height: 100%; |
|||
text-align: center; |
|||
} |
|||
} |
|||
swiper { |
|||
width: 100%; |
|||
height: 60upx; |
|||
} |
|||
.calendar-content { |
|||
min-height: 30px; |
|||
} |
|||
.calendar-swiper { |
|||
min-height: 35px; |
|||
transition: height ease-out 0.3s; |
|||
} |
|||
.calendar-item { |
|||
margin: 0; |
|||
padding: 0; |
|||
height: 100%; |
|||
} |
|||
.calendar-days { |
|||
display: flex; |
|||
flex-flow: row wrap; |
|||
width: 100%; |
|||
height: 100%; |
|||
overflow: hidden; |
|||
font-size: 14px; |
|||
|
|||
.calendar-day { |
|||
width: calc(100% / 7); |
|||
height: 35px; |
|||
text-align: center; |
|||
display: flex; |
|||
flex-flow: column nowrap; |
|||
justify-content: flex-start; |
|||
align-items: center; |
|||
position: relative; |
|||
} |
|||
} |
|||
.day-hidden { |
|||
visibility: hidden; |
|||
} |
|||
|
|||
.mode-change { |
|||
display: flex; |
|||
justify-content: center; |
|||
margin-top: 5px; |
|||
|
|||
.mode-arrow-top { |
|||
width: 0; |
|||
height: 0; |
|||
border-left: 6px solid transparent; |
|||
border-right: 6px solid transparent; |
|||
border-bottom: 5px solid #ff6633; |
|||
} |
|||
.mode-arrow-bottom { |
|||
width: 0; |
|||
height: 0; |
|||
border-left: 6px solid transparent; |
|||
border-right: 6px solid transparent; |
|||
border-top: 5px solid #ff6633; |
|||
} |
|||
} |
|||
.is-today { |
|||
background: #ffffff; |
|||
border: 1upx solid #ff6633; |
|||
border-radius: 50%; |
|||
color: #ff6633; |
|||
} |
|||
.is-checked { |
|||
background: #ff6633; |
|||
color: #ffffff; |
|||
} |
|||
.date { |
|||
width: 25px; |
|||
height: 25px; |
|||
line-height: 25px; |
|||
margin: 0 auto; |
|||
border-radius: 25px; |
|||
} |
|||
.dot-show { |
|||
width: 6px; |
|||
height: 6px; |
|||
// background: red; |
|||
border-radius: 5px; |
|||
position: absolute; |
|||
top: 2px; |
|||
right: 10px; |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,136 @@ |
|||
/* |
|||
*此函数的作用是根据传入的一个日期,返回这一周的日期或者这一个月的日期, |
|||
* 如果是月的话注意还包含上个月和下个月的日期,月的话总共数据有 6 * 7 = 42个 |
|||
* |
|||
*/ |
|||
/* |
|||
* 时间格式化函数 |
|||
* 重要提示,微信小程序new Date('2020-04-16')在ios中无法获取时间对象 |
|||
* 解决方式: 建议将时间都格式化成'2020/04/16 00:00:00'的格式 |
|||
* 函数示例: formatDate(new Date(), 'YYYY/MM/dd hh:mm:ss') |
|||
*/ |
|||
export const formatDate = (date, fmt) => { |
|||
if (/(y+)/.test(fmt)) { |
|||
fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)); |
|||
} |
|||
let o = { |
|||
'M+': date.getMonth() + 1, |
|||
'd+': date.getDate(), |
|||
'h+': date.getHours(), |
|||
'm+': date.getMinutes(), |
|||
's+': date.getSeconds(), |
|||
}; |
|||
for (let k in o) { |
|||
if (new RegExp(`(${k})`).test(fmt)) { |
|||
let str = o[k] + ''; |
|||
fmt = fmt.replace(RegExp.$1, RegExp.$1.length === 1 ? str : padLeftZero(str)); |
|||
} |
|||
} |
|||
return fmt; |
|||
}; |
|||
const padLeftZero = str => { |
|||
return ('00' + str).substr(str.length); |
|||
}; |
|||
|
|||
// 判断是不是date对象
|
|||
export const judgeType = s => { |
|||
// 函数返回数据的具体类型
|
|||
return Object.prototype.toString.call(s).slice(8, -1); |
|||
}; |
|||
|
|||
export const equalDate = (d1, d2) => { |
|||
let result = false; |
|||
if (d1.getFullYear() === d2.getFullYear() && d1.getMonth() === d2.getMonth() && d1.getDate() === d2.getDate()) { |
|||
result = true; |
|||
} |
|||
return result; |
|||
}; |
|||
|
|||
/* 比较时间,时间格式为2020-04-04 |
|||
*/ |
|||
export const dateEqual = (before, after) => { |
|||
before = new Date(before.replace('-', '/').replace('-', '/')); |
|||
after = new Date(after.replace('-', '/').replace('-', '/')); |
|||
if (before.getTime() - after.getTime() === 0) { |
|||
return true; |
|||
} else { |
|||
return false; |
|||
} |
|||
}; |
|||
|
|||
export const gegerateDates = (date = new Date(), type = 'week') => { |
|||
const result = []; |
|||
if (judgeType(date) === 'Date') { |
|||
// 年,月,日
|
|||
const y = date.getFullYear(); |
|||
const m = date.getMonth(); |
|||
const d = date.getDate(); |
|||
const days = new Date(y, m + 1, 0).getDate(); |
|||
// 获取日期是星期几
|
|||
// let weekIndex = date.getDay() === 0 ? 7 : date.getDay();
|
|||
let weekIndex = date.getDay(); |
|||
if (type === 'month') { |
|||
const dobj = new Date(y, m, 1); |
|||
// weekIndex = dobj.getDay() === 0 ? 7 : dobj.getDay();
|
|||
weekIndex = dobj.getDay(); |
|||
} |
|||
if (type === 'week') { |
|||
for (let i = weekIndex; i > 0; i--) { |
|||
const dtemp = new Date(y, m, d); |
|||
dtemp.setDate(dtemp.getDate() - i); |
|||
result.push({ |
|||
time: dtemp, |
|||
show: true, |
|||
fullDate: formatDate(dtemp, 'yyyy-MM-dd'), |
|||
isToday: equalDate(new Date(), dtemp), |
|||
}); |
|||
} |
|||
for (let i = 0; i <= 7 - weekIndex; i++) { |
|||
const dtemp = new Date(y, m, d); |
|||
dtemp.setDate(dtemp.getDate() + i); |
|||
result.push({ |
|||
time: dtemp, |
|||
show: true, |
|||
fullDate: formatDate(dtemp, 'yyyy-MM-dd'), |
|||
isToday: equalDate(new Date(), dtemp), |
|||
}); |
|||
} |
|||
} else if (type === 'month') { |
|||
// 上个月
|
|||
for (let i = weekIndex; i > 0; i--) { |
|||
const dtemp = new Date(y, m, 1); |
|||
dtemp.setDate(dtemp.getDate() - i); |
|||
result.push({ |
|||
time: dtemp, |
|||
show: false, |
|||
fullDate: formatDate(dtemp, 'yyyy-MM-dd'), |
|||
isToday: equalDate(new Date(), dtemp), |
|||
}); |
|||
} |
|||
// 这个月的日期
|
|||
for (let i = 0; i < days; i++) { |
|||
const dtemp = new Date(y, m, 1); |
|||
dtemp.setDate(dtemp.getDate() + i); |
|||
result.push({ |
|||
time: dtemp, |
|||
show: true, |
|||
fullDate: formatDate(dtemp, 'yyyy-MM-dd'), |
|||
isToday: equalDate(new Date(), dtemp), |
|||
}); |
|||
} |
|||
const len = 42 - result.length; |
|||
// 下个月的日期
|
|||
for (let i = 1; i <= len; i++) { |
|||
const dtemp = new Date(y, m + 1, 0); |
|||
dtemp.setDate(dtemp.getDate() + i); |
|||
result.push({ |
|||
time: dtemp, |
|||
show: false, |
|||
fullDate: formatDate(dtemp, 'yyyy-MM-dd'), |
|||
isToday: equalDate(new Date(), dtemp), |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
return result; |
|||
}; |
@ -0,0 +1,86 @@ |
|||
<template> |
|||
<view :class="organData && organData.organizationType === 0 ? 'organ-box' : ''" v-if="globals && globals.length"> |
|||
<u-subsection :list="globalTabs" :current="current" @change="change"></u-subsection> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapState, mapGetters, mapMutations } from 'vuex'; |
|||
|
|||
export default { |
|||
name: 'Global', |
|||
|
|||
data() { |
|||
return { |
|||
// loading: true, |
|||
task: null, |
|||
current: 0, |
|||
global: [], |
|||
globalTabs: [], |
|||
showLine: false, |
|||
}; |
|||
}, |
|||
watch: {}, |
|||
computed: { |
|||
...mapState('project', ['organData']), |
|||
...mapGetters('task', ['globals']), |
|||
}, |
|||
created() { |
|||
var obj = JSON.parse(this.globals[0].plugins[0][0].param); |
|||
this.setGlobalData(obj); |
|||
this.global[0] = this.globals[0]; |
|||
this.globalTabs = [...this.globals]; |
|||
}, |
|||
methods: { |
|||
...mapMutations('carbasics', ['setGlobalData']), |
|||
change(e) { |
|||
console.log('e: ', e); |
|||
this.current = e; |
|||
if (e !== this.globals.length) { |
|||
this.global[0] = this.globals[e]; |
|||
var obj = JSON.parse(this.globals[e].plugins[0][0].param); |
|||
this.setGlobalData(obj); |
|||
this.$emit('changeShowLine', false); |
|||
this.showLine = false; |
|||
} else { |
|||
this.$emit('changeShowLine', true); |
|||
this.showLine = true; |
|||
} |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped lang="scss"> |
|||
.organ-box { |
|||
position: fixed; |
|||
height: 100vh; |
|||
width: 750rpx; |
|||
left: 0; |
|||
top: 0; |
|||
z-index: 999; |
|||
} |
|||
|
|||
.u-card__body { |
|||
padding: 16px 0; |
|||
} |
|||
|
|||
.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> |
@ -0,0 +1,467 @@ |
|||
<template> |
|||
<div class="flex flex-1 flex-col patient-list"> |
|||
<div class="title flex justify-between items-center"> |
|||
<u-search |
|||
style="width: 500rpx" |
|||
v-model="name" |
|||
shape="round" |
|||
action-text=" " |
|||
placeholder="请输入患者" |
|||
@search="getData(true)" |
|||
@blur="searchBlur" |
|||
></u-search> |
|||
<select-lay |
|||
:zindex="99" |
|||
:showplaceholder="false" |
|||
:value="tval" |
|||
name="name" |
|||
placeholder="请选择类型" |
|||
:options="provinces" |
|||
@selectitem="changeSelect" |
|||
> |
|||
</select-lay> |
|||
</div> |
|||
<u-modal |
|||
v-model="show" |
|||
:closeOnClickOverlay="true" |
|||
title="提示" |
|||
content="是否确定删除当前患者信息?" |
|||
show-cancel-button |
|||
confirm-text="删除" |
|||
@confirm="confirmDel" |
|||
></u-modal> |
|||
<u-modal |
|||
v-model="show1" |
|||
:closeOnClickOverlay="true" |
|||
title="提示" |
|||
content="退出当前病例后,其他医生可接诊。确定要退出吗?" |
|||
show-cancel-button |
|||
confirm-text="退出" |
|||
@confirm="confirmBack" |
|||
></u-modal> |
|||
<u-toast ref="uToast" /> |
|||
<scroll-view scroll-y="true" :style="{ height: height }" :lower-threshold="50" scroll-with-animation @scrolltolower="scrolltolower"> |
|||
<div v-if="patientList.length" class="white list-box w-full flex-1 flex-col"> |
|||
<div class="patients flex flex-row"> |
|||
<div>{{ tval === 0 ? '急救患者' : '出院患者' }}</div> |
|||
<div class="ml-2 card-total flex items-center justify-center">{{ total }}</div> |
|||
</div> |
|||
<div |
|||
v-for="(card, cardIndex) in patientList" |
|||
:key="cardIndex" |
|||
class="mb-4 w-full card-box flex flex-row flex-nowrap" |
|||
style="position: relative" |
|||
@mousedown="start" |
|||
@touchstart="start" |
|||
@mousemove="move($event, cardIndex)" |
|||
@touchmove="move($event, cardIndex)" |
|||
@mouseup="end" |
|||
@touchend="end" |
|||
> |
|||
<div |
|||
@longpress="longpress(card.firstAidId)" |
|||
@click="changeTimeLine(card.recordUserId, card.firstAidId, card.caseType)" |
|||
style="height: 100%; width: 100%; position: absolute; top: 0; left: 0; z-index: 10" |
|||
></div> |
|||
<div :style="{ 'margin-left': outIndex === cardIndex && card.recordUserId - 0 ? '-68px' : '' }" class="w-full anima"> |
|||
<div class="crad-content"> |
|||
<div class="status-wait" v-if="!(card.recordUserId - 0)"></div> |
|||
<div class="flex mb-2"> |
|||
<div class="pr-2 fw-bold"> |
|||
<span v-if="card.name"> |
|||
{{ card.name }} |
|||
</span> |
|||
<span v-else> 无名氏 </span> |
|||
</div> |
|||
<div class="pr-2 fw-bold"> |
|||
<span v-if="card.gender === 0">女</span> |
|||
<span v-else-if="card.gender === 1">男</span> |
|||
<span v-else>-</span> |
|||
</div> |
|||
<div class="pr-2 fw-bold"> |
|||
<span v-if="card.age || card.age === 0">{{ card.age }}</span> |
|||
<span v-else>-</span> |
|||
</div> |
|||
<u-tag style="z-index: 99; margin-right: 0" plain shape="circle" v-if="card.isJmrs - 0 === 1" text="静脉溶栓"> </u-tag> |
|||
<u-tag |
|||
class="ml-2 flex items-center justify-center" |
|||
type="success" |
|||
plain |
|||
shape="circle" |
|||
v-if="card.isXgzl - 0 === 1" |
|||
text="血管内治疗" |
|||
> |
|||
</u-tag> |
|||
</div> |
|||
<div class="flex"> |
|||
<div>{{ tval === 0 ? '到院时间:' : '出院时间:' }}</div> |
|||
<div v-if="card.record2" style="color: rgba(0, 0, 0, 0.85)"> |
|||
{{ $moment(+card.record2).format('YYYY-MM-DD HH:mm') }} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<img src="./icon/yanshi.png" class="img-box" v-if="card.demonstrate === 1" /> |
|||
</div> |
|||
<div |
|||
:style="{ |
|||
width: outIndex === cardIndex && card.recordUserId - 0 ? '68px' : 0, |
|||
color: outIndex === cardIndex && card.recordUserId - 0 ? 'rgba(255,255,255,1)' : 'rgba(255,0,0,0)', |
|||
}" |
|||
class="sign-out flex items-center justify-center anima" |
|||
@click="quitTips(card.firstAidId)" |
|||
> |
|||
退出 |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</scroll-view> |
|||
<div class="add-patient" @click="jump"> |
|||
<u-icon color="#fff" size="40" name="plus"></u-icon> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapState, mapMutations, mapGetters } from 'vuex'; |
|||
|
|||
export default { |
|||
props: {}, |
|||
data: () => ({ |
|||
height: '', |
|||
name: '', // 搜索框患者名称 |
|||
provinces: [ |
|||
{ |
|||
label: '急救患者', |
|||
value: 0, |
|||
}, |
|||
{ |
|||
label: '出院患者', |
|||
value: 1, |
|||
}, |
|||
], |
|||
tval: 0, // 默认选择的患者类型: 急救患者 |
|||
pageNum: 1, // 默认查询第一页的数据 |
|||
patientList: [], // 患者列表 |
|||
total: '', // 列表共有多少条数据 |
|||
role: '', |
|||
show: false, // 是否显示删除modal框 |
|||
show1: false, // 是否显示退出急救的modal框 |
|||
delFirstAidId: '', // 即将要删除的患者的急救id |
|||
firstAidId: '', |
|||
quitId: '', // 将要退出急救的患者的急救id |
|||
startX: 0, // 当前滑动的距离 |
|||
outIndex: -1, // 当前哪个card处于左滑选择可以单击退出的位置 |
|||
isMove: false, // 当前是否处于滑动状态 |
|||
}), |
|||
computed: { |
|||
...mapState('carbasics', ['detailsData', 'globalData', 'refreshList']), |
|||
...mapGetters('project', ['projectId']), |
|||
}, |
|||
mounted() { |
|||
const system = uni.getSystemInfoSync(); |
|||
this.height = system.windowHeight - 33 - 38 - 52 + 'px'; |
|||
console.log('this.height: ', this.height); |
|||
}, |
|||
|
|||
created() { |
|||
this.getData(true); |
|||
}, |
|||
methods: { |
|||
...mapMutations('carbasics', ['setFirstAidId']), |
|||
jump() { |
|||
uni.navigateTo({ url: `/pages/establish/establish?role=${this.role}` }); |
|||
}, |
|||
// 鼠标按下事件 |
|||
start(event) { |
|||
if (event.touches) { |
|||
this.startX = event.touches[0].clientX; |
|||
// console.log(event.touches[0].clientX); |
|||
} |
|||
this.isMove = true; |
|||
}, |
|||
// 鼠标松开事件 |
|||
end() { |
|||
this.isMove = false; |
|||
}, |
|||
// 拖动box事件 |
|||
move(event, index) { |
|||
if (this.isMove) { |
|||
if (this.outIndex === index) { |
|||
this.outIndex = -1; |
|||
} else { |
|||
if (event.touches && (event.touches[0].clientX - this.startX > 10 || event.touches[0].clientX - this.startX < -10)) { |
|||
this.outIndex = index; |
|||
} |
|||
} |
|||
} |
|||
this.isMove = false; |
|||
}, |
|||
// 退出急救 |
|||
quitTips(id) { |
|||
console.log('id: ', id); |
|||
this.quitId = id; |
|||
this.show1 = true; |
|||
}, |
|||
// 退出急救二次确认 |
|||
async confirmBack() { |
|||
try { |
|||
const param = { firstAidId: this.quitId, projectId: this.projectId }; |
|||
const res = await uni.$u.api.quitAid(param); |
|||
console.log('res: ', res); |
|||
this.getData(true); |
|||
this.visible1 = false; |
|||
} catch (error) { |
|||
this.$refs.uToast.show({ |
|||
title: '退出失败', |
|||
type: 'error', |
|||
}); |
|||
} |
|||
this.outIndex = -1; |
|||
}, |
|||
// 用户点击患者card时,判断是否已经被接诊 |
|||
// 如果没有被接诊,这自动选择接诊该患者 |
|||
// 如果已经接诊,则直接跳转到患者的信息录入目录中 |
|||
changeTimeLine(recordUserId, firstAidId, caseType) { |
|||
try { |
|||
if (!(recordUserId - 0)) { |
|||
this.changeShow(firstAidId); |
|||
} else { |
|||
this.setFirstAidId(firstAidId); |
|||
// this.$router.push(`/patient-line`); |
|||
uni.navigateTo({ url: `/pages/patientLine/patientLine?caseType=${caseType}` }); |
|||
} |
|||
} catch (error) { |
|||
this.$refs.uToast.show({ |
|||
title: '切换失败', |
|||
type: 'error', |
|||
}); |
|||
0; |
|||
} |
|||
}, |
|||
// 判断当前用户是否为医生,如果是医生,则将该患者加入急救 |
|||
changeShow(id) { |
|||
if (this.role === 'YiSheng') { |
|||
// 只有加入急救的时候用到了这个急救id,但还是存了起来 |
|||
// 这里存起来的原因,是因为目前只有神内路线,当神外路线打开后,需要选择神内/神外才能加入,所以需要存储 |
|||
this.firstAidId = id; |
|||
this.handleOk(this.detailsData.type); |
|||
// this.visible = true; // 神内/神外选择加入 |
|||
} |
|||
}, |
|||
// 将患者加入急救 |
|||
async handleOk(type) { |
|||
try { |
|||
const { projectId, firstAidId } = this; |
|||
const param = { |
|||
projectId, |
|||
firstAidId, |
|||
type, |
|||
}; |
|||
const res = await uni.$u.api.joinAid(param); |
|||
console.log('res: ', res); |
|||
if (res) { |
|||
this.$refs.uToast.show({ |
|||
title: '加入成功', |
|||
type: 'success', |
|||
}); |
|||
const codeAndAnswerList = [ |
|||
{ |
|||
questionCode: 'JKJY-SFXJ', |
|||
answer: ['是'], |
|||
}, |
|||
{ |
|||
questionCode: 'JKJY-XJFS', |
|||
answer: ['集体病区教育'], |
|||
}, |
|||
{ |
|||
questionCode: 'YJJL-CTendTime-outSide', |
|||
answer: ['否'], |
|||
}, |
|||
]; |
|||
const setParam = { |
|||
codeAndAnswerList, |
|||
firstAidId, |
|||
}; |
|||
uni.$u.api.setRecord(setParam); |
|||
this.getData(true); |
|||
} else { |
|||
this.$refs.uToast.show({ |
|||
title: '加入失败', |
|||
type: 'error', |
|||
}); |
|||
} |
|||
} catch (error) { |
|||
this.$refs.uToast.show({ |
|||
title: error, |
|||
type: 'error', |
|||
}); |
|||
} |
|||
}, |
|||
// 长按事件 |
|||
longpress(delFirstAidId) { |
|||
this.delFirstAidId = delFirstAidId; |
|||
this.show = true; |
|||
}, |
|||
async confirmDel() { |
|||
try { |
|||
const param = { firstAidId: this.delFirstAidId }; |
|||
const res = await this.$u.api.delDemo(param); |
|||
console.log('res: ', res); |
|||
this.getData(true); |
|||
} catch (error) { |
|||
console.log('error: ', error); |
|||
} |
|||
}, |
|||
// 获取列表数据 |
|||
async getData(status) { |
|||
try { |
|||
// status 是否是重新请求数据,如果是重新请求数据,则清空页码和已查询的数据 |
|||
if (status) { |
|||
this.pageNum = 1; |
|||
this.patientList = []; |
|||
} |
|||
const params = { |
|||
param: { |
|||
firstAidType: this.tval, |
|||
name: this.name, |
|||
type: this.globalData.powerType, |
|||
projectId: this.projectId, |
|||
caseType: this.globalData.createAuth - 0 === 0 ? 1 : 0, |
|||
pageNum: this.pageNum, |
|||
pageSize: 10, |
|||
}, |
|||
}; |
|||
const data = await this.$u.api.querySelf(params); |
|||
if (data.page.list.length) { |
|||
if (status) { |
|||
this.patientList = data.page.list; |
|||
} else { |
|||
this.patientList = this.patientList.concat(data.page.list); |
|||
} |
|||
this.total = data.page.total; |
|||
this.role = data.role; |
|||
} else { |
|||
this.$t.ui.showToast('没有更多数据'); |
|||
} |
|||
} catch (error) { |
|||
console.log('error: ', error); |
|||
} |
|||
}, |
|||
// 改变急救类型时,重新查询数据 |
|||
changeSelect(e) { |
|||
this.tval = this.provinces[e].value; |
|||
this.getData(true); |
|||
}, |
|||
searchBlur() { |
|||
setTimeout(() => this.getData(true), 10); |
|||
}, |
|||
// scroll-view滚动到底部时,触发查询下一页数据 |
|||
scrolltolower() { |
|||
this.pageNum++; |
|||
this.getData(false); |
|||
}, |
|||
}, |
|||
watch: { |
|||
refreshList() { |
|||
setTimeout(() => { |
|||
this.getData(true); |
|||
}, 300); |
|||
}, |
|||
}, |
|||
// 组件周期函数--监听组件数据更新之前 |
|||
beforeUpdate() {}, |
|||
// 组件周期函数--监听组件数据更新之后 |
|||
updated() {}, |
|||
// 组件周期函数--监听组件激活(显示) |
|||
activated() {}, |
|||
// 组件周期函数--监听组件停用(隐藏) |
|||
deactivated() {}, |
|||
// 组件周期函数--监听组件销毁之前 |
|||
beforeDestroy() {}, |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.add-patient { |
|||
z-index: 10; |
|||
border-radius: 50%; |
|||
height: 40px; |
|||
width: 40px; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
background-color: #0284c7; |
|||
position: fixed; |
|||
bottom: 100px; |
|||
right: 16px; |
|||
} |
|||
.patient-list { |
|||
background-color: #fff; |
|||
} |
|||
.title { |
|||
height: 52px; |
|||
width: 750rpx; |
|||
padding: 8px 16px; |
|||
// position: fixed; |
|||
// top: 32px; |
|||
background: #fff; |
|||
box-shadow: 0 0 4px 4px #ccc; |
|||
} |
|||
.card-box { |
|||
/* box-shadow: 0 0 5px #ccc; */ |
|||
border: 2px solid #ccc; |
|||
margin: 16px 0; |
|||
border-radius: 8px; |
|||
overflow: hidden; |
|||
} |
|||
.anima { |
|||
transition: all 0.5s; |
|||
position: relative; |
|||
} |
|||
.crad-content { |
|||
font-size: 14px; |
|||
color: #414141; |
|||
padding: 12px; |
|||
} |
|||
.status-wait { |
|||
position: absolute; |
|||
right: 6px; |
|||
top: 6px; |
|||
height: 14px; |
|||
width: 14px; |
|||
border-radius: 50%; |
|||
background: #ff8f00; |
|||
box-shadow: 0 0 5px #ff8f00; |
|||
} |
|||
.fw-bold { |
|||
font-size: 16px; |
|||
font-weight: bold; |
|||
} |
|||
.sign-out { |
|||
background-color: red; |
|||
font-size: 14px; |
|||
color: #fff; |
|||
z-index: 10; |
|||
} |
|||
.list-box { |
|||
padding: 16px; |
|||
} |
|||
.patients { |
|||
font-size: 16px; |
|||
font-weight: bold; |
|||
padding: 10px 0; |
|||
} |
|||
.card-total { |
|||
padding: 0 8px; |
|||
border-radius: 10px; |
|||
background-color: #009dff; |
|||
color: white; |
|||
} |
|||
.img-box { |
|||
position: absolute; |
|||
top: 14px; |
|||
width: 44px; |
|||
height: 44px; |
|||
right: 16px; |
|||
} |
|||
</style> |
After Width: | Height: | Size: 2.6 KiB |
@ -0,0 +1,520 @@ |
|||
<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 flex-shrink-0">进行中</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 flex-shrink-0" |
|||
> |
|||
{{ 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> |
|||
<view class="edition">v1.7.1</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', 'setProjects']), |
|||
// 展开子项目 |
|||
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(obj) { |
|||
let action = this.menuList[obj.index].text; |
|||
if (action === '排序') { |
|||
this.changeEvent = true; |
|||
this.$t.ui.showToast('请移动进行排序'); |
|||
} |
|||
|
|||
if (action === '删除') { |
|||
this.changeEvent = false; |
|||
this.delProject(obj.projectId); |
|||
} |
|||
|
|||
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; |
|||
} |
|||
}, |
|||
|
|||
// 删除项目 |
|||
delProject(id) { |
|||
uni.showModal({ |
|||
title: '', |
|||
content: '是否删除项目?', |
|||
showCancel: true, |
|||
success: async ({ confirm }) => { |
|||
if (confirm) { |
|||
await this.$u.api.delProject(id); |
|||
let flag_index = 0; |
|||
this.itemList.forEach((item, index) => { |
|||
if (item.id == id) { |
|||
flag_index = index; |
|||
} |
|||
}); |
|||
|
|||
this.itemList.splice(flag_index, 1); |
|||
this.setProjects(this.itemList); |
|||
} |
|||
}, |
|||
}); |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.edition { |
|||
position: fixed; |
|||
width: 200px; |
|||
text-align: center; |
|||
left: 50%; |
|||
margin-left: -100px; |
|||
bottom: 12px; |
|||
font-size: 12px; |
|||
color: #ccc; |
|||
} |
|||
.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> |
@ -0,0 +1,161 @@ |
|||
<template> |
|||
<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> |
|||
<!-- <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 flex-shrink-0">进行中</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 class="mover" name="https://www.tall.wiki/staticrec/drag.svg" size="48"></u-icon> |
|||
<!-- <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 flex-shrink-0" |
|||
> |
|||
{{ 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> --> |
|||
<u-action-sheet :list="menuList" :tips="tips" @click="chooseAction" 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, |
|||
projectId: 0, |
|||
}; |
|||
}, |
|||
|
|||
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), |
|||
}); |
|||
// uni.navigateTo({ url: `/pages/task-page/task-page?u=${this.userId}&p=${id}&pname=${name}&url=${encodeURIComponent(url)}` }); |
|||
}, |
|||
|
|||
/** |
|||
* 弹出项目操作面板 |
|||
*/ |
|||
openMenu(project) { |
|||
this.showMenu = true; |
|||
this.projectId = project.id; |
|||
this.tips.text = project.name; |
|||
}, |
|||
|
|||
chooseAction(e) { |
|||
let data = { index: e, projectId: this.projectId }; |
|||
this.$emit('chooseAction', data); |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.border-100 { |
|||
height: 4rpx; |
|||
margin: 0 20rpx; |
|||
} |
|||
.border-80 { |
|||
height: 4rpx; |
|||
margin: 0 20rpx 0 90rpx; |
|||
} |
|||
</style> |
@ -0,0 +1,65 @@ |
|||
<template> |
|||
<view class="py-3 mt-4 bg-white u-font-15"> |
|||
<PrettyExchange @change="change" /> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import PrettyExchange from '../PrettyExchange/PrettyExchange.vue'; |
|||
|
|||
export default { |
|||
components: { PrettyExchange }, |
|||
data() { |
|||
return {}; |
|||
}, |
|||
|
|||
methods: { |
|||
change(options) { |
|||
if (options instanceof Array) { |
|||
let projectIdList = []; |
|||
let arr = []; |
|||
options.forEach(item => { |
|||
projectIdList.push(item.id); |
|||
arr.push(item.name); |
|||
}); |
|||
this.setProjectSort(projectIdList); |
|||
} else { |
|||
this.setProjectRelation(options); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 设置项目顺序 |
|||
* @param { Array } projectIdList 项目id |
|||
*/ |
|||
async setProjectSort(projectIdList) { |
|||
try { |
|||
const params = { projectIdList }; |
|||
await this.$u.api.setProjectSort(params); |
|||
this.$t.ui.showToast('排序修改成功'); |
|||
} catch (error) { |
|||
console.log('error: ', error); |
|||
this.$t.ui.showToast(error.msg || '排序修改失败'); |
|||
} |
|||
this.$emit('getProjects'); |
|||
}, |
|||
|
|||
/** |
|||
* 设置项目父子结构 |
|||
* @param { string } id 当前移动的项目的id |
|||
* @param { string } parentId 父项目的id |
|||
*/ |
|||
async setProjectRelation(options) { |
|||
try { |
|||
const params = options; |
|||
await this.$u.api.setProjectRelation(params); |
|||
this.$t.ui.showToast('排序修改成功'); |
|||
} catch (error) { |
|||
console.error('error: ', error); |
|||
this.$t.ui.showToast(error.msg || '排序修改失败'); |
|||
} |
|||
this.$emit('getProjects'); |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
@ -0,0 +1,264 @@ |
|||
<template> |
|||
<view class="px-2 bg-white wrap"> |
|||
<view class="home-box u-skeleton"> |
|||
<scroll-view :enable-flex="true" :scroll-left="scrollLeft" :throttle="false" scroll-with-animation scroll-x @scroll="scroll"> |
|||
<view class="tab-box"> |
|||
<!-- 角色项 |
|||
default-tab-choice 是 我的角色 && 当前展示 |
|||
default-tab-item 是 我的角色 && 当前不展示 |
|||
tab-choice 不是我的 && 当前展示 |
|||
--> |
|||
<div class="flex flex-1"> |
|||
<template v-for="(item, index) in roles"> |
|||
<view |
|||
:class="{ |
|||
'default-tab-choice': item.mine == 1 && roleId === item.id, |
|||
'default-tab-item': item.mine == 1 && roleId !== item.id, |
|||
'tab-choice': item.mine == 0 && roleId === item.id, |
|||
}" |
|||
:key="index" |
|||
@click="changeRole(item.id)" |
|||
class="tab-item" |
|||
> |
|||
<view class="tab-children u-skeleton-fillet u-font-14"> |
|||
{{ item.name }} |
|||
</view> |
|||
</view> |
|||
</template> |
|||
</div> |
|||
<u-icon |
|||
name="arrow-down" |
|||
color="#2979ff" |
|||
size="28" |
|||
type="down" |
|||
v-if="invisibleRoles.length" |
|||
:style="{ transform: `rotate(${isActive ? 0 : 180}deg)` }" |
|||
@click="isActive = !isActive" |
|||
style="transition: transform 0.24s; margin-right: 0px" |
|||
/> |
|||
</view> |
|||
</scroll-view> |
|||
</view> |
|||
<view :style="{ height: isActive ? '100px' : 0 }" style="transition: all 0.24s" class="role-more-box"> |
|||
<template v-for="roleItem in allRoles"> |
|||
<u-tag |
|||
:type="roleId === roleItem.id ? 'primary' : 'info'" |
|||
v-if="roleItem.name !== '平车'" |
|||
class="m-3" |
|||
:key="roleItem.id" |
|||
:text="roleItem.name" |
|||
mode="light" |
|||
@click="changeRole(roleItem.id)" |
|||
/> |
|||
</template> |
|||
</view> |
|||
<!-- 骨架屏 --> |
|||
<u-skeleton :animation="true" :loading="loading" bg-color="#fff"></u-skeleton> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapState, mapMutations, mapGetters } 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 }, |
|||
], |
|||
allRoles: [], |
|||
roleLeft: 0, |
|||
isActive: false, |
|||
}; |
|||
}, |
|||
|
|||
computed: { |
|||
...mapState('role', ['visibleRoles', 'invisibleRoles', 'roleId']), |
|||
...mapGetters('project', ['projectId']), |
|||
}, |
|||
|
|||
watch: { |
|||
visibleRoles(val) { |
|||
if (val && val.length) { |
|||
// this.roles = [...this.visibleRoles, ...this.invisibleRoles]; |
|||
this.roles = [...this.visibleRoles]; |
|||
this.allRoles = [...this.visibleRoles, ...this.invisibleRoles]; |
|||
this.loading = false; |
|||
} |
|||
}, |
|||
roleId(val) { |
|||
let list = [...this.allRoles]; |
|||
let newRoleList = [...this.roles]; |
|||
let newList = []; |
|||
for (var i = 0; i < list.length; i++) { |
|||
if (val === list[i].id && list[i].name !== '平车') { |
|||
newList.push(list[i]); |
|||
newRoleList[0] = list[i]; |
|||
list.splice(i, 1); |
|||
break; |
|||
} |
|||
} |
|||
for (var j = 0; j < list.length; j++) { |
|||
newList.push(list[j]); |
|||
} |
|||
this.roles = [...newRoleList]; |
|||
this.allRoles = [...newList]; |
|||
}, |
|||
}, |
|||
|
|||
mounted() { |
|||
if (!this.visibleRoles || !this.visibleRoles.length) { |
|||
this.loading = true; |
|||
} else { |
|||
this.roles = [...this.visibleRoles]; |
|||
this.allRoles = [...this.visibleRoles, ...this.invisibleRoles]; |
|||
} |
|||
}, |
|||
|
|||
methods: { |
|||
...mapMutations('role', ['setRoleId']), |
|||
|
|||
scroll(e) { |
|||
this.scrollLeft = e.detail.scrollLeft; |
|||
}, |
|||
|
|||
// 切换角色 |
|||
// 查任务这里不用管 project监听了roleId的变化 |
|||
// 时间基准点不用管 project监听了roleId 里处理了 |
|||
changeRole(id) { |
|||
try { |
|||
this.isActive = false; |
|||
const { projectId } = this; |
|||
// 清除多余的script |
|||
this.$nextTick(async () => { |
|||
this.setRoleId(id); |
|||
const saveParams = { param: { roleId: id, projectId } }; |
|||
await uni.$u.api.saveRoleRecord(saveParams); |
|||
}); |
|||
} catch (error) { |
|||
console.error('role.vue changeRole error: ', error); |
|||
} |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.role-more-box { |
|||
box-shadow: 0 6px 6px rgba(0, 0, 0, 0.15); |
|||
// border-top: 1px solid rgba(0, 0, 0, 0.15); |
|||
overflow: hidden; |
|||
width: 100%; |
|||
background: #fff; |
|||
z-index: 10; |
|||
left: 0; |
|||
// top: 0; |
|||
position: fixed; |
|||
border-radius: 0 0 6px 6px; |
|||
} |
|||
.home-box { |
|||
// 对此盒子进行 sticky 粘性定位 |
|||
position: sticky; |
|||
top: 0; |
|||
background: #fff; // 设置背景 否则会透明 |
|||
|
|||
/* #ifdef H5 */ |
|||
//粘性定位 在h5下 加 原生头部高度 44px |
|||
top: 88rpx; |
|||
/* #endif */ |
|||
|
|||
.tab-box { |
|||
position: relative; |
|||
white-space: nowrap; |
|||
height: 60rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
// height: 84rpx; |
|||
|
|||
.tab-item { |
|||
// width: 20%; |
|||
// height: 84rpx; |
|||
// padding: 20rpx 24rpx; |
|||
padding: 0 24rpx; |
|||
position: relative; |
|||
// display: inline-block; |
|||
// text-align: center; |
|||
font-size: 30rpx; |
|||
height: 60rpx; |
|||
line-height: 60rpx; |
|||
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> |
@ -0,0 +1,33 @@ |
|||
<template> |
|||
<div class="upload"> |
|||
<!-- <div class="flex justify-center w-12 h-12 bg-blue-100 rounded-full shadow-md" style="line-height: 42px">客服</div> --> |
|||
<button |
|||
class="flex justify-center w-12 h-12 rounded-full shadow-md" |
|||
style="padding: 0; align-items: center; background-color: #04be02" |
|||
open-type="contact" |
|||
> |
|||
<!-- 客服 --> |
|||
<img style="height: 28px; width: 28px" src="./icon/tel-we.png" alt="" /> |
|||
</button> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
export default { |
|||
name: 'Service', |
|||
data() { |
|||
return {}; |
|||
}, |
|||
}; |
|||
</script> |
|||
<style lang="scss" scoped> |
|||
.upload { |
|||
z-index: 99; |
|||
position: fixed; |
|||
left: 50%; |
|||
margin-left: -1.5rem; |
|||
font-size: 14px; |
|||
bottom: 5rem; |
|||
transform: translate3d(0, 99%, 0); |
|||
color: $uni-color-primary !important; |
|||
} |
|||
</style> |
After Width: | Height: | Size: 6.8 KiB |
@ -0,0 +1,126 @@ |
|||
<template> |
|||
<!-- 时间间隔栏 --> |
|||
<!-- <Barrier /> --> |
|||
|
|||
<scroll-view |
|||
:lower-threshold="300" |
|||
scroll-y="true" |
|||
:upper-threshold="300" |
|||
:scroll-into-view="scrollToTaskId" |
|||
@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 { setPlaceholderTasks } from '@/utils/task'; |
|||
import TimeBox from './component/TimeBox.vue'; |
|||
|
|||
export default { |
|||
name: 'TimeLine', |
|||
components: { TimeBox }, |
|||
|
|||
data() { |
|||
return { top: 0 }; |
|||
}, |
|||
|
|||
computed: { |
|||
...mapState('role', ['visibleRoles']), |
|||
...mapState('task', ['scrollTop', 'tasks', 'topEnd', 'bottomEnd', 'showSkeleton', 'timeNode', 'scrollToTaskId']), |
|||
...mapGetters('task', ['timeGranularity']), |
|||
}, |
|||
|
|||
methods: { |
|||
...mapMutations('task', ['setScrollTop', 'setShrink', 'setUpTasks', 'setDownTasks', 'setScrollToTaskId']), |
|||
|
|||
// 滚动 |
|||
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.topEnd) { |
|||
// 没有数据时 自动加载数据 |
|||
console.warn('滚动到顶部没有数据时: '); |
|||
const addTasks = setPlaceholderTasks(startTime, true, this.timeGranularity); |
|||
this.setUpTasks(addTasks); |
|||
} else { |
|||
// 有数据时 |
|||
console.warn('滚动到顶部有数据时: '); |
|||
const detailId = this.tasks.findIndex(task => task.detailId); |
|||
const timeNode = this.tasks[detailId].planStart - 0; |
|||
const upQuery = { |
|||
timeNode, |
|||
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 (this.bottomEnd) { |
|||
// 没有数据时 自动加载数据 |
|||
console.warn('滚动到底部没有数据时: '); |
|||
const addTasks = setPlaceholderTasks(startTime, false, this.timeGranularity); |
|||
this.setDownTasks(addTasks); |
|||
} else { |
|||
// 时间基准点=最后一个任务的开始时间+当前时间颗粒度 |
|||
console.warn('滚动到底部有数据时: '); |
|||
const arr = []; |
|||
this.tasks.forEach(task => { |
|||
if (task.detailId) { |
|||
arr.push(task); |
|||
} |
|||
}); |
|||
const nextQueryTime = +this.$t.time.add(+arr[arr.length - 1].planStart, 1, timeGranularity); |
|||
const downQuery = { |
|||
timeNode: nextQueryTime, |
|||
queryType: 1, |
|||
queryNum: 6, |
|||
}; |
|||
await this.$emit('getTasks', downQuery); |
|||
} |
|||
}, |
|||
|
|||
// 设置自动滚动位置 |
|||
setScrollPosition() { |
|||
// 如果storage里有taskId 滚动到这个id的任务 |
|||
const taskId = this.$t.storage.getStorageSync('taskId'); |
|||
if (taskId) { |
|||
this.setScrollToTaskId(`a${taskId}`); |
|||
this.$t.storage.setStorageSync('taskId', ''); // 记录后即刻清除本地存储 |
|||
} else { |
|||
const item = this.tasks.find(task => task.detailId); |
|||
console.log(this.tasks); |
|||
if (item) { |
|||
this.setScrollToTaskId(`a${item.id}`); |
|||
} else { |
|||
// 没有本地记录的taskId |
|||
// 找到当前时间基准线的任务id 记录 并滚动到当前时间基准线 |
|||
const task = this.tasks.find(item => this.$moment(+item.planStart).isSame(this.timeNode, this.timeGranularity)); |
|||
task && this.setScrollToTaskId(`a${task.id}`); // 有这个task 就记录他的id |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
@ -0,0 +1,42 @@ |
|||
<!-- |
|||
* @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> |
@ -0,0 +1,185 @@ |
|||
<template> |
|||
<view> |
|||
<view class="flex justify-between" style="min-width: 90px; position: relative"> |
|||
<u-icon custom-prefix="custom-icon" name="C-bxl-redux" size="17px"></u-icon> |
|||
<u-icon custom-prefix="custom-icon" name="attachment" size="21px"></u-icon> |
|||
<!-- <u-icon custom-prefix="custom-icon" name="moneycollect" size="20px"></u-icon> --> |
|||
<u-icon name="xuanxiang" custom-prefix="custom-icon" size="21px" @click="operation"></u-icon> |
|||
|
|||
<!-- 右上角 ... 弹窗 --> |
|||
<view class="popup border shadow-md" v-if="show"> |
|||
<view class="flex justify-center pb-3 border-b-1"> |
|||
<span @click="createTask">新建任务</span> |
|||
</view> |
|||
<view class="flex pt-3 justify-center"> |
|||
<span>克隆任务</span> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 遮罩 --> |
|||
<view class="mask" v-if="maskShow" @click="closeMask"></view> |
|||
<!-- 新建任务弹窗 --> |
|||
<CreateTask |
|||
:startTime="startTime" |
|||
:endTime="endTime" |
|||
:task="task" |
|||
@showTime="showTime" |
|||
@closeMask="closeMask" |
|||
class="thirdPopup flex transition-transform" |
|||
v-if="createTaskShow" |
|||
/> |
|||
|
|||
<u-picker title="开始时间" mode="time" v-model="showStart" :params="params" @confirm="confirmStartTime"></u-picker> |
|||
<u-picker title="结束时间" mode="time" v-model="showEnd" :params="params" @confirm="confirmEndTime"></u-picker> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import CreateTask from '../../Title/components/CreateTask.vue'; |
|||
|
|||
export default { |
|||
components: { CreateTask }, |
|||
|
|||
props: { |
|||
task: { |
|||
type: Object, |
|||
default: () => {}, |
|||
}, |
|||
}, |
|||
|
|||
data() { |
|||
return { |
|||
show: false, //右上角 ... 显示 |
|||
createTaskShow: false, //新建项目显示 |
|||
secondShow: false, //分享项目显示 |
|||
maskShow: false, //遮罩显示 |
|||
showStart: false, |
|||
showEnd: false, |
|||
startTime: '', // 新建任务的开始时间 |
|||
endTime: '', // 新建任务的截止时间 |
|||
params: { |
|||
year: true, |
|||
month: true, |
|||
day: true, |
|||
hour: true, |
|||
minute: true, |
|||
second: true, |
|||
}, |
|||
}; |
|||
}, |
|||
|
|||
methods: { |
|||
//操作 |
|||
operation() { |
|||
// this.$t.ui.showToast('操作'); |
|||
this.show = !this.show; |
|||
}, |
|||
|
|||
// 新建项目 |
|||
createTask() { |
|||
// 关闭 ... 弹窗 |
|||
this.show = false; |
|||
// 打开遮罩 |
|||
this.maskShow = true; |
|||
// 打开新建项目弹窗 |
|||
this.createTaskShow = true; |
|||
}, |
|||
|
|||
//点击遮罩,关闭弹窗 |
|||
closeMask() { |
|||
// 关闭遮罩 |
|||
this.maskShow = false; |
|||
// 关闭分享项目弹窗 |
|||
this.secondShow = false; |
|||
// 关闭新建项目弹窗 |
|||
this.createTaskShow = false; |
|||
}, |
|||
|
|||
showTime() { |
|||
this.showStart = !this.showStart; |
|||
}, |
|||
|
|||
// 选择开始时间 |
|||
confirmStartTime(e) { |
|||
this.startTime = `${e.year}-${e.month}-${e.day} ${e.hour}:${e.minute}:${e.second}`; |
|||
this.showEnd = true; |
|||
}, |
|||
|
|||
// 选择结束时间 |
|||
confirmEndTime(e) { |
|||
this.endTime = `${e.year}-${e.month}-${e.day} ${e.hour}:${e.minute}:${e.second}`; |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.mask { |
|||
width: 100%; |
|||
height: 100vh; |
|||
z-index: 21; |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
background: rgba(0, 0, 0, 0.3); |
|||
} |
|||
|
|||
.thirdPopup { |
|||
background: #ffffff; |
|||
position: fixed; |
|||
left: 50%; |
|||
top: 50%; |
|||
transform: translate(-50%, -50%); |
|||
z-index: 33; |
|||
border-radius: 5px; |
|||
width: 90%; |
|||
} |
|||
|
|||
.popup { |
|||
width: 110px; |
|||
background: #fff; |
|||
position: absolute; |
|||
right: 0; |
|||
top: 35px; |
|||
z-index: 99; |
|||
padding: 15px 0; |
|||
color: black; |
|||
animation: opacity 1s ease-in; |
|||
} |
|||
|
|||
@keyframes opacity { |
|||
0% { |
|||
opacity: 0; |
|||
} |
|||
50% { |
|||
opacity: 0.8; |
|||
} |
|||
100% { |
|||
opacity: 1; |
|||
} |
|||
} |
|||
|
|||
::v-deep .u-slot-content { |
|||
min-width: 0; |
|||
} |
|||
::v-deep .u-dropdown__content { |
|||
min-height: 120px !important; |
|||
height: auto !important; |
|||
overflow-y: auto; |
|||
background: #fff !important; |
|||
transition: none !important; |
|||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); |
|||
} |
|||
::v-deep .u-dropdown__menu__item .u-flex { |
|||
justify-content: space-between; |
|||
width: 100%; |
|||
height: 100%; |
|||
flex-wrap: nowrap; |
|||
border: 1px solid #afbed1; |
|||
padding: 0 8px; |
|||
} |
|||
::v-deep .u-dropdown__content__mask { |
|||
display: none; |
|||
} |
|||
</style> |
@ -0,0 +1,142 @@ |
|||
<template> |
|||
<view class="column"> |
|||
<!-- v-if="tasks && tasks.length" --> |
|||
<view> |
|||
<view :key="task.id" v-for="task in tasks" :id="`a${task.id}`"> |
|||
<view class="flex"> |
|||
<TimeStatus :task="task" /> |
|||
<view class="flex items-center justify-between flex-1 ml-2 task-column"> |
|||
<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" :task="task" /> |
|||
</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 |
|||
@click="onClickTask(task.planStart - 0, task.id)" |
|||
:show-foot="false" |
|||
:show-head="false" |
|||
:style="{ height: setHeight(task.panel) }" |
|||
class="h-16" |
|||
margin="0" |
|||
v-if="tasks && tasks.length && task.process !== 4 && !showSkeleton" |
|||
> |
|||
<!-- 任务面板插件 --> |
|||
<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="[`row-span-${plugin.row}`, `col-span-${plugin.col}`]" |
|||
: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', '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); |
|||
}, |
|||
}, |
|||
}; |
|||
</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; |
|||
} |
|||
::v-deep .ml-2 { |
|||
margin-left: 16px; |
|||
} |
|||
|
|||
::v-deep .ml-3 { |
|||
margin-left: 20px; |
|||
} |
|||
</style> |
@ -0,0 +1,231 @@ |
|||
<template> |
|||
<view class="u-font-14"> |
|||
<view |
|||
class="flex items-center justify-center rounded-full icon-column" |
|||
:style="{ color: orderStyle.color }" |
|||
@click="changeStatus(task.process, $event)" |
|||
> |
|||
<!-- 1进行中 2暂停中 3已完成 --> |
|||
<u-circle-progress |
|||
:percent="orderStyle.persent - 0" |
|||
: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>{{ durationText }}</template> |
|||
</view> |
|||
</view> |
|||
</u-circle-progress> |
|||
<!-- 0未开始 4添加任务 --> |
|||
<view class="flex items-center justify-center rounded-full progress-box" v-else :class="task.process === 4 ? 'progress-box-4' : ''"> |
|||
<view class="u-progress-content"> |
|||
<view class="u-progress-dot"></view> |
|||
<view class="u-progress-info"> |
|||
<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>{{ durationText }}</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, |
|||
durationText: 0, |
|||
}; |
|||
}, |
|||
|
|||
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 }; |
|||
}, |
|||
}, |
|||
|
|||
mounted() { |
|||
// TODO: 计算在不在窗口内显示 |
|||
const time = this.computeDurationText(); |
|||
this.updateDurationText(time); |
|||
}, |
|||
|
|||
destroyed() { |
|||
if (this.timer) { |
|||
clearInterval(this.timer); |
|||
this.timer = null; |
|||
} |
|||
}, |
|||
|
|||
methods: { |
|||
...mapMutations('task', ['setTip']), |
|||
|
|||
/** |
|||
* 点击了图标 修改任务状态 |
|||
* @param {object} event |
|||
*/ |
|||
changeStatus(process, event) { |
|||
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() { |
|||
const { realStart, planDuration } = this.task; |
|||
const leftTime = +realStart + +planDuration - Date.now(); // 剩余时间 |
|||
const { num, time } = this.$t.time.computeDurationText(leftTime); |
|||
if (num <= 0) { |
|||
clearInterval(this.timer); |
|||
this.timer = null; |
|||
} |
|||
this.durationText = num; |
|||
return time; |
|||
}, |
|||
|
|||
updateDurationText(time) { |
|||
if (this.timer) { |
|||
clearInterval(this.timer); |
|||
this.timer = null; |
|||
} |
|||
if (!time) return; |
|||
setInterval(() => { |
|||
this.computeDurationText(); |
|||
}, time); |
|||
}, |
|||
}, |
|||
}; |
|||
</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> |
@ -0,0 +1,7 @@ |
|||
<!-- |
|||
* @Author: aBin |
|||
* @email: binbin0314@126.com |
|||
* @Date: 2021-07-19 15:40:02 |
|||
* @LastEditors: aBin |
|||
* @LastEditTime: 2021-07-19 15:40:03 |
|||
--> |
@ -0,0 +1,235 @@ |
|||
<template> |
|||
<view> |
|||
<!-- :is-back="false" --> |
|||
<u-navbar :custom-back="onBack" class="overflow-hidden"> |
|||
<view class="flex justify-start flex-1 px-3 font-bold min-0"> |
|||
<view class="truncate">{{ project.name }}</view> |
|||
</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 |
|||
class="mask" |
|||
v-if="maskShow" |
|||
@click="closeMask" |
|||
style="width: 100%; height: 100vh; z-index: 21; position: fixed; background: rgba(0, 0, 0, 0.3)" |
|||
></view> |
|||
<!-- 右上角 ... 弹窗 --> |
|||
<view class="popup border shadow-md" v-if="show"> |
|||
<view class="flex pb-3 border-b-1"> |
|||
<u-icon name="plus-circle" size="36" style="margin: 0 15px 3px 0"></u-icon> |
|||
<!-- <view @click="createTask">新建任务</view> --> |
|||
<view>新建任务</view> |
|||
</view> |
|||
<view class="flex pt-3"> |
|||
<u-icon name="share" size="32" style="margin: 0 15px 3px 0"></u-icon> |
|||
<view @click="share">分享项目</view> |
|||
</view> |
|||
</view> |
|||
<!-- 分享项目弹窗 --> |
|||
<ShareProject v-if="secondShow" class="second-popup" /> |
|||
<!-- 新建任务弹窗 --> |
|||
<CreateTask |
|||
:startTime="startTime" |
|||
:endTime="endTime" |
|||
@showTime="showTime" |
|||
@closeMask="closeMask" |
|||
class="third-popup flex transition-transform" |
|||
v-if="createTaskShow" |
|||
/> |
|||
|
|||
<u-picker title="开始时间" mode="time" v-model="showStart" :params="params" @confirm="confirmStartTime"></u-picker> |
|||
<u-picker title="结束时间" mode="time" v-model="showEnd" :params="params" @confirm="confirmEndTime"></u-picker> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapGetters, mapState } from 'vuex'; |
|||
import CreateTask from './components/CreateTask.vue'; |
|||
import ShareProject from './components/ShareProject.vue'; |
|||
|
|||
export default { |
|||
name: 'ProjectTitle', |
|||
components: { CreateTask, ShareProject }, |
|||
data() { |
|||
return { |
|||
show: false, //右上角 ... 显示 |
|||
createTaskShow: false, //新建项目显示 |
|||
secondShow: false, //分享项目显示 |
|||
maskShow: false, //遮罩显示 |
|||
showStart: false, |
|||
showEnd: false, |
|||
startTime: '', // 新建任务的开始时间 |
|||
endTime: '', // 新建任务的截止时间 |
|||
params: { |
|||
year: true, |
|||
month: true, |
|||
day: true, |
|||
hour: true, |
|||
minute: true, |
|||
second: true, |
|||
}, |
|||
}; |
|||
}, |
|||
|
|||
computed: { |
|||
...mapState('project', ['project']), |
|||
...mapGetters('user', ['userId']), |
|||
}, |
|||
|
|||
methods: { |
|||
showTime() { |
|||
this.showStart = !this.showStart; |
|||
}, |
|||
|
|||
// 选择开始时间 |
|||
confirmStartTime(e) { |
|||
this.startTime = `${e.year}-${e.month}-${e.day} ${e.hour}:${e.minute}:${e.second}`; |
|||
this.showEnd = true; |
|||
}, |
|||
|
|||
// 选择结束时间 |
|||
confirmEndTime(e) { |
|||
this.endTime = `${e.year}-${e.month}-${e.day} ${e.hour}:${e.minute}:${e.second}`; |
|||
}, |
|||
|
|||
// 点击返回按钮 |
|||
onBack() { |
|||
// eslint-disable-next-line no-undef |
|||
const pages = getCurrentPages(); // 获取页面栈数组 |
|||
console.log('历史pages: ', pages.length); |
|||
// if (pages.length > 1) { |
|||
// uni.webView.navigateBack(); |
|||
uni.webView.reLaunch({ url: `/pages/index/index?u=${this.userId}` }); |
|||
// } else { |
|||
// // this.$u.route('/', { u: this.userId }); |
|||
// uni.webView.reLaunch({ url: `/pages/index/index?u=${this.userId}` }); |
|||
// } |
|||
}, |
|||
|
|||
// LWBS提示 |
|||
lwbs() { |
|||
// this.$t.ui.showToast('LWBS'); |
|||
}, |
|||
//项目概览 |
|||
projectOverview() { |
|||
// this.$t.ui.showToast('项目概览'); |
|||
}, |
|||
// 回到首页 |
|||
openIndex() { |
|||
console.log(111); |
|||
uni.webView.reLaunch({ url: `/pages/index/index?u=${this.userId}` }); |
|||
}, |
|||
|
|||
//操作 |
|||
operation() { |
|||
// this.$t.ui.showToast('操作'); |
|||
this.show = !this.show; |
|||
}, |
|||
|
|||
// 新建项目 |
|||
createTask() { |
|||
// 关闭 ... 弹窗 |
|||
this.show = false; |
|||
// 打开遮罩 |
|||
this.maskShow = true; |
|||
// 打开新建项目弹窗 |
|||
this.createTaskShow = true; |
|||
}, |
|||
|
|||
//分享项目 |
|||
share() { |
|||
// 关闭 ... 弹窗 |
|||
this.show = false; |
|||
// 打开遮罩 |
|||
this.maskShow = true; |
|||
// 打开分享项目弹窗 |
|||
this.secondShow = true; |
|||
}, |
|||
|
|||
//点击遮罩,关闭弹窗 |
|||
closeMask() { |
|||
// 关闭遮罩 |
|||
this.maskShow = false; |
|||
// 关闭分享项目弹窗 |
|||
this.secondShow = false; |
|||
// 关闭新建项目弹窗 |
|||
this.createTaskShow = false; |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.second-popup { |
|||
background: #ffffff; |
|||
position: fixed; |
|||
left: 50%; |
|||
top: 50%; |
|||
transform: translate(-50%, -50%); |
|||
z-index: 33; |
|||
border-radius: 5px; |
|||
width: 90%; |
|||
} |
|||
|
|||
.third-popup { |
|||
background: #ffffff; |
|||
position: fixed; |
|||
left: 50%; |
|||
top: 50%; |
|||
transform: translate(-50%, -50%); |
|||
z-index: 33; |
|||
border-radius: 5px; |
|||
width: 90%; |
|||
} |
|||
|
|||
.popup { |
|||
width: 40%; |
|||
background: #fff; |
|||
position: absolute; |
|||
right: 0; |
|||
z-index: 99; |
|||
padding: 15px; |
|||
color: black; |
|||
animation: opacity 0.5s ease-in; |
|||
} |
|||
|
|||
@keyframes opacity { |
|||
0% { |
|||
opacity: 0; |
|||
} |
|||
50% { |
|||
opacity: 0.8; |
|||
} |
|||
100% { |
|||
opacity: 1; |
|||
} |
|||
} |
|||
|
|||
::v-deep .u-slot-content { |
|||
min-width: 0; |
|||
} |
|||
::v-deep .u-dropdown__content { |
|||
min-height: 120px !important; |
|||
height: auto !important; |
|||
overflow-y: auto; |
|||
background: #fff !important; |
|||
transition: none !important; |
|||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); |
|||
} |
|||
::v-deep .u-dropdown__menu__item .u-flex { |
|||
justify-content: space-between; |
|||
width: 100%; |
|||
height: 100%; |
|||
flex-wrap: nowrap; |
|||
border: 1px solid #afbed1; |
|||
padding: 0 8px; |
|||
} |
|||
::v-deep .u-dropdown__content__mask { |
|||
display: none; |
|||
} |
|||
</style> |
@ -0,0 +1,460 @@ |
|||
<template> |
|||
<div class="new-projects-box"> |
|||
<div class="form"> |
|||
<!-- 项目名称 --> |
|||
<view class="mb-3 font-bold text-base flex justify-center">新建任务</view> |
|||
<div class="flex items-center mb-2"> |
|||
<div>名称<span class="text-red-500">*</span>:</div> |
|||
<u-input max-length="5" v-model="name" :type="type" :border="border" /> |
|||
</div> |
|||
<!-- 起止时间 --> |
|||
<div class="mb-2"> |
|||
<div>起止时间:</div> |
|||
<u-input placeholder="请选择起止时间" v-model="timeValue" :type="type" :border="border" @click="$emit('showTime')" /> |
|||
</div> |
|||
<!-- 多选框 --> |
|||
<div class="flex justify-between items-center"> |
|||
<div>负责人<span class="text-red-500">*</span>:</div> |
|||
<div class="flex-1" v-if="hasRole">{{ roleName }}</div> |
|||
<div label="负责人" class="flex-1" v-else> |
|||
<u-dropdown disabled ref="uDropdown" placeholder="请选择负责人"> |
|||
<u-dropdown-item :title="roleList"> |
|||
<view class="slot-content bg-white"> |
|||
<div |
|||
class="flex flex-row justify-between mb-1 drop-item" |
|||
v-for="(role, roleIndex) in roleOptions" |
|||
:key="roleIndex" |
|||
@click="change(roleIndex)" |
|||
> |
|||
<view v-model="role.id">{{ role.name }}</view> |
|||
<u-icon v-if="role.dropdownShow" name="checkbox-mark" color="#2979ff" size="28"></u-icon> |
|||
</div> |
|||
</view> |
|||
</u-dropdown-item> |
|||
</u-dropdown> |
|||
</div> |
|||
</div> |
|||
<!-- 下拉图标 --> |
|||
<div class="flex justify-center my-6"> |
|||
<u-icon v-if="arrow" name="arrow-down" size="28" @click="openDropdown"></u-icon> |
|||
<u-icon v-else name="arrow-up" size="28" @click="closeSecondDropdown"></u-icon> |
|||
</div> |
|||
<!-- 下拉框的内容 --> |
|||
<div v-if="show" class="mb-6"> |
|||
<!-- 描述 --> |
|||
<div class="flex items-center mb-2"> |
|||
<div>描述:</div> |
|||
<u-input v-model="description" max-length="48" type="textarea" height="36" auto-height :border="border" /> |
|||
</div> |
|||
<!-- 所属项目 --> |
|||
<div class="w flex items-center mb-2"> |
|||
<div>所属项目<span class="text-red-500">*</span>:</div> |
|||
<div>{{ project.name }}</div> |
|||
</div> |
|||
<!-- 所属任务 --> |
|||
<div class="w flex items-center mb-2" v-if="task && task.id"> |
|||
<div>所属任务:</div> |
|||
<div>{{ task.name }}</div> |
|||
</div> |
|||
<!-- 上道工序 --> |
|||
<div class="flex items-center mb-2"> |
|||
<div>上道工序:</div> |
|||
<InputSearch |
|||
@searchPrevTask="searchPrevTask" |
|||
:dataSource="allTasks" |
|||
@select="handleChange" |
|||
@clearAllTasks="clearAllTasks" |
|||
placeholder="请输入上道工序" |
|||
/> |
|||
</div> |
|||
<!-- 检查人多选框 --> |
|||
<div class="flex justify-between items-center"> |
|||
<div>检查人<span class="text-red-500">*</span>:</div> |
|||
<div label="检查人" class="flex-1"> |
|||
<u-dropdown ref="dropdown"> |
|||
<u-dropdown-item :title="checkerList"> |
|||
<view class="slot-content bg-white"> |
|||
<div |
|||
class="flex flex-row justify-between mb-1 drop-item" |
|||
v-for="(checkoutOption, Index) in checkoutOptions" |
|||
:key="Index" |
|||
@click="choose(Index)" |
|||
> |
|||
<view v-model="checkoutOption.value">{{ checkoutOption.name }}</view> |
|||
<u-icon v-if="checkoutOption.dropdownShow" name="checkbox-mark" color="#2979ff" size="28"></u-icon> |
|||
</div> |
|||
</view> |
|||
</u-dropdown-item> |
|||
</u-dropdown> |
|||
</div> |
|||
</div> |
|||
<!-- 是否是日常任务 --> |
|||
<div class="flex justify-between items-center mt-6"> |
|||
是否是日常任务: |
|||
<u-switch v-model="isGlobal" size="28"></u-switch> |
|||
</div> |
|||
<div class="mt-6"> |
|||
<div>交付物:</div> |
|||
<div v-for="(sort, sortIndex) in deliverSort" :key="sortIndex"> |
|||
<u-input |
|||
@blur="addDeliverInput" |
|||
v-model="sort.name" |
|||
:placeholder="`交付物名称${sortIndex + 1}`" |
|||
:type="type" |
|||
:border="border" |
|||
/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="flex items-center mb-6"> |
|||
<u-button type="primary" size="medium" @click="setParameters">提交</u-button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapState, mapGetters, mapMutations } from 'vuex'; |
|||
|
|||
export default { |
|||
props: { |
|||
startTime: { |
|||
type: String, |
|||
default: '', |
|||
}, |
|||
endTime: { |
|||
type: String, |
|||
default: '', |
|||
}, |
|||
task: { |
|||
type: Object, |
|||
default: null, |
|||
}, |
|||
}, |
|||
data() { |
|||
return { |
|||
arrow: true, |
|||
show: false, |
|||
isGlobal: false, //是否日常任务 |
|||
name: '', //名称 |
|||
showChooseTime: false, |
|||
timeValue: '', //起止时间 |
|||
description: '', //描述 |
|||
projectShow: false, //所属项目模糊搜索展示 |
|||
processTaskId: '', //上道工序 |
|||
type: 'text', |
|||
border: true, |
|||
roleList: undefined, //负责人默认多选 |
|||
checkerList: undefined, //检查人默认多选 |
|||
roleOptions: [], // 负责人下拉多选列表 |
|||
checkoutOptions: [], // 检查人下拉多选列表 |
|||
roleIdList: [], // 选中的负责人id |
|||
checkerIdList: [], // 选中的检查人id |
|||
deliverables: [], // 交付物 |
|||
deliverSort: [{ name: '' }], // 交付物排序 |
|||
allTasks: [], |
|||
roleName: '', // 负责人名字 |
|||
hasRole: false, // 有没有负责人 |
|||
}; |
|||
}, |
|||
|
|||
computed: { |
|||
...mapState('role', ['visibleRoles', 'roleId']), |
|||
...mapState('project', ['project']), |
|||
...mapState('task', ['tasks']), |
|||
...mapGetters('project', ['projectId']), |
|||
}, |
|||
|
|||
watch: { |
|||
endTime(val) { |
|||
if (val) { |
|||
this.timeValue = this.startTime + ' 至 ' + val; |
|||
} |
|||
}, |
|||
}, |
|||
|
|||
mounted() { |
|||
// 获取负责人和检查人列表 |
|||
if (this.visibleRoles.length) { |
|||
this.visibleRoles.forEach(role => { |
|||
role.dropdownShow = false; |
|||
role.status = false; |
|||
}); |
|||
} |
|||
this.roleOptions = this.$u.deepClone(this.visibleRoles); |
|||
this.checkoutOptions = this.$u.deepClone(this.visibleRoles); |
|||
|
|||
// 判断有没有负责人 是不是添加子任务 |
|||
if (this.roleId) { |
|||
const item = this.visibleRoles.find(r => r.id === this.roleId); |
|||
if (item) { |
|||
this.roleName = item.name; |
|||
this.hasRole = true; |
|||
} |
|||
} |
|||
}, |
|||
|
|||
methods: { |
|||
...mapMutations('task', ['updateTasks']), |
|||
|
|||
// 负责人下拉多选选中 |
|||
change(index) { |
|||
let arr = [...this.roleOptions]; |
|||
// 选择多选项图标的展示 |
|||
arr[index].dropdownShow = !arr[index].dropdownShow; |
|||
// 多选展示的改变 |
|||
this.roleList = arr[index].name; |
|||
let shows = ''; |
|||
// 遍历arr,如果选中,添加到多选展示框上 |
|||
arr.map(val => { |
|||
if (val.dropdownShow === true) { |
|||
shows += val.name + ','; |
|||
this.roleIdList.push(val.id); |
|||
} |
|||
}); |
|||
this.roleOptions = [...arr]; |
|||
// 删除最后的',' |
|||
this.roleList = shows.slice(0, shows.length - 1); |
|||
}, |
|||
|
|||
// 检查人下拉多选选中 |
|||
choose(index) { |
|||
let arr = [...this.checkoutOptions]; |
|||
// 选择多选项图标的展示 |
|||
arr[index].dropdownShow = !arr[index].dropdownShow; |
|||
// 多选展示的改变 |
|||
this.checkerList = arr[index].name; |
|||
let shows = ''; |
|||
// 遍历arr,如果选中,添加到多选展示框上 |
|||
arr.map(val => { |
|||
if (val.dropdownShow === true) { |
|||
shows += val.name + ','; |
|||
this.checkerIdList.push(val.id); |
|||
} |
|||
}); |
|||
this.checkoutOptions = [...arr]; |
|||
// 删除最后的',' |
|||
this.checkerList = shows.slice(0, shows.length - 1); |
|||
// this.roleList = arr[value - 1].name; |
|||
}, |
|||
|
|||
// 打开下拉框 |
|||
openDropdown() { |
|||
this.arrow = !this.arrow; |
|||
this.show = true; |
|||
}, |
|||
|
|||
// 关闭下拉框 |
|||
closeSecondDropdown() { |
|||
this.arrow = !this.arrow; |
|||
this.show = false; |
|||
}, |
|||
|
|||
/** |
|||
* 模糊查询 查找项目下的任务 |
|||
* @param name 任务名 |
|||
* @param projectId 项目id |
|||
*/ |
|||
async searchPrevTask(val) { |
|||
try { |
|||
const params = { name: val, projectId: this.projectId }; |
|||
const data = await this.$u.api.queryTaskOfProject(params); |
|||
this.allTasks = data; |
|||
return data; |
|||
} catch (error) { |
|||
console.error('error: ', error); |
|||
} |
|||
}, |
|||
|
|||
//用户点击获取的数据 |
|||
handleChange(data) { |
|||
console.log('data', data); |
|||
this.processTaskId = data.detailId; |
|||
}, |
|||
// 清空模糊查询信息 |
|||
clearAllTasks() { |
|||
this.allTasks = []; |
|||
}, |
|||
|
|||
// 数组最后一项有值 添加一条交付物输入框 |
|||
addDeliverInput() { |
|||
if (this.deliverSort[this.deliverSort.length - 1].name) { |
|||
this.deliverSort.push({ name: '' }); |
|||
} |
|||
}, |
|||
|
|||
// 设置提交参数 |
|||
async setParameters() { |
|||
const { |
|||
projectId, |
|||
task, |
|||
name, |
|||
startTime, |
|||
endTime, |
|||
hasRole, |
|||
roleIdList, |
|||
roleId, |
|||
description, |
|||
processTaskId, |
|||
checkerIdList, |
|||
isGlobal, |
|||
} = this; |
|||
if (!name) { |
|||
this.$t.ui.showToast('请输入名称'); |
|||
return; |
|||
} |
|||
if ((!roleIdList || !roleIdList.length) && !hasRole) { |
|||
this.$t.ui.showToast('请选择负责人'); |
|||
return; |
|||
} |
|||
if (!checkerIdList || !checkerIdList.length) { |
|||
this.$t.ui.showToast('请选择检查人'); |
|||
return; |
|||
} |
|||
const deliverList = []; |
|||
this.deliverSort.forEach(item => { |
|||
if (item.name) { |
|||
deliverList.push(item.name); |
|||
} |
|||
}); |
|||
const params = { |
|||
name, |
|||
startTime: startTime ? this.$moment(startTime).format('x') - 0 : '', |
|||
endTime: endTime ? this.$moment(endTime).format('x') - 0 : '', |
|||
roleIdList: hasRole ? [roleId] : roleIdList, |
|||
description, |
|||
projectId, |
|||
parentTaskId: task && task.id ? task.id : '', // 父任务 |
|||
processTaskId, // 上道工序 TODO |
|||
checkerIdList, |
|||
global: isGlobal ? 1 : 0, |
|||
deliverList, |
|||
}; |
|||
await this.handleSubmit(params); |
|||
}, |
|||
|
|||
/** |
|||
* 新建任务 |
|||
* @param name 任务名 |
|||
* @param startTime 开始时间 |
|||
* @param endTime 结束时间 |
|||
* @param roleIdList 负责人id(数组) |
|||
* @param description 描述 |
|||
* @param projectId 所属项目id |
|||
* @param parentTaskId 所属任务id |
|||
* @param processTaskId 上道工序(任务id) |
|||
* @param checkerIdList 检查人id(数组) |
|||
* @param global 是否日常任务 0否 1是 |
|||
* @param deliverList 交付物名字(数组) |
|||
*/ |
|||
async handleSubmit(params) { |
|||
try { |
|||
const data = await this.$u.api.saveTask(params); |
|||
// TODO 任务新建成功 继续 or 取消 |
|||
this.$emit('closeMask'); |
|||
const newTasks = { |
|||
data: data[0], |
|||
processTaskId: params.processTaskId, |
|||
}; |
|||
// 将新加的任务加到store |
|||
// 判断不是子任务 |
|||
if (!this.task || !this.task.id) { |
|||
this.addNewTasks(newTasks); |
|||
} |
|||
} catch (error) { |
|||
this.$emit('closeMask'); |
|||
console.error('error: ', error); |
|||
} |
|||
}, |
|||
|
|||
// 添加任务后更新tasks |
|||
addNewTasks(data) { |
|||
const oldTasks = this.$u.deepClone(this.tasks); |
|||
let res = data.data; |
|||
// 判断有没有选择上道工序 |
|||
if (data.processTaskId) { |
|||
const index = oldTasks.find(item => item.detailId === data.processTaskId); |
|||
if (index) { |
|||
oldTasks.splice(index + 1, 0, res); |
|||
} |
|||
} else { |
|||
this.setAddPosition(res, oldTasks); |
|||
} |
|||
}, |
|||
|
|||
// 设置添加位置 |
|||
setAddPosition(res, oldTasks) { |
|||
if (res.planStart - 0 < oldTasks[0].planStart - 0) { |
|||
// 开始时间小于列表的第一个 插入最前面 |
|||
oldTasks.splice(0, 0, res); |
|||
} else if (res.planStart - 0 === oldTasks[0].planStart - 0) { |
|||
// 开始时间等于列表的第一个 插入第二 |
|||
oldTasks.splice(1, 0, res); |
|||
} else if (res.planStart - 0 >= oldTasks[oldTasks.length - 1].planStart - 0) { |
|||
// 开始时间大等于列表的最后一个 插入最后 |
|||
oldTasks.splice(-1, 0, res); |
|||
} else { |
|||
// 判断开始时间在列表中间的哪个位置 |
|||
for (let i = 0; i < oldTasks.length; i++) { |
|||
const item = oldTasks[i]; |
|||
if (res.planStart - 0 > item.planStart - 0) { |
|||
if (res.planStart - 0 <= oldTasks[i + 1].planStart - 0) { |
|||
oldTasks.splice(i + 1, 0, res); |
|||
console.log('res: ', res); |
|||
return; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
// TODO: 不能全更新 |
|||
console.log('oldTasks: ', oldTasks); |
|||
this.updateTasks([...oldTasks]); |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.form { |
|||
display: flex; |
|||
flex-direction: column; |
|||
width: 100%; |
|||
max-height: 400px; |
|||
overflow-y: scroll; |
|||
} |
|||
|
|||
.drop-item { |
|||
border-bottom: 1px solid #f1f1f1; |
|||
padding: 16rpx; |
|||
} |
|||
|
|||
::v-deep.u-input--border { |
|||
border: none; |
|||
border-radius: 0; |
|||
} |
|||
::v-deep.u-dropdown__menu__item > uni-view { |
|||
border: none !important; |
|||
padding: 5px; |
|||
} |
|||
.u-input { |
|||
border-bottom: 1px solid #dcdfe6; |
|||
} |
|||
|
|||
.new-projects-box { |
|||
margin-top: 20px; |
|||
padding: 15px; |
|||
width: 100%; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.w { |
|||
width: 300px; |
|||
height: 39px; |
|||
} |
|||
|
|||
::v-deep .u-dropdown__menu__item .u-flex { |
|||
border: 0 !important; |
|||
border-bottom: 1px solid #dcdfe6 !important; |
|||
padding: 0 20rpx; |
|||
} |
|||
</style> |
@ -0,0 +1,210 @@ |
|||
<template> |
|||
<view class="flex justify-center"> |
|||
<view class="content p-3 pb-8"> |
|||
<view class="mb-3 font-bold text-base flex justify-center">创建分享链接</view> |
|||
<view class="flex flex-col"> |
|||
<view class="mb-1">用户以什么角色加入项目</view> |
|||
<!-- 下拉多选 --> |
|||
<view class="uni-list"> |
|||
<view class="uni-list-cell"> |
|||
<view class="uni-list-cell-db ml-2" v-if="rolesArray.length"> |
|||
<picker @change="changeRole" :value="index" :range="rolesArray"> |
|||
<view class="uni-input">{{ allRolesName[index].name }}</view> |
|||
</picker> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 复制链接 --> |
|||
<view class="link flex items-center mt-4"> |
|||
<view class="link-url">{{ links }}</view> |
|||
<u-button |
|||
style="border-radius: 0; height: 100%" |
|||
type="primary" |
|||
v-clipboard:copy="copyText" |
|||
v-clipboard:success="copySuccess" |
|||
v-clipboard:error="copyError" |
|||
> |
|||
复制链接 |
|||
</u-button> |
|||
</view> |
|||
<view @click="select"> |
|||
<!-- 全选按钮 --> |
|||
<!-- <view class="flex mt-4"> |
|||
<view> |
|||
<u-checkbox-group> |
|||
<u-checkbox v-model="checked" @change="checkedAll"></u-checkbox> |
|||
</u-checkbox-group> |
|||
</view> |
|||
<view>已选择({{ this.quantity }})</view> |
|||
<view style="color: #f37378; margin-left: 20px">批量删除</view> |
|||
</view> --> |
|||
<!-- 多选框 --> |
|||
<!-- <view> |
|||
<u-checkbox-group class="checkboxs flex flex-1 items-center mt-4" v-for="(item, index) in list" :key="index"> |
|||
<div class="flex-1 flex items-center"> |
|||
<u-checkbox v-model="item.checked"></u-checkbox> |
|||
<u-avatar :src="item.src" size="55" style="background: #d8dce0; margin-right: 10px"></u-avatar> |
|||
<div style="width: 60%; font-size: 12px"> |
|||
<div style="color: gray">{{ item.name }}</div> |
|||
<div style="color: #c4d0e1">{{ item.joinMethod }}</div> |
|||
</div> |
|||
</div> |
|||
</u-checkbox-group> |
|||
</view> --> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapGetters, mapState } from 'vuex'; |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
rolesArray: [], |
|||
allRolesName: [], |
|||
index: 0, |
|||
links: '', //复制的链接 |
|||
copyText: '', |
|||
checked: false, //全选按钮是否选中 |
|||
roleName: '观众', |
|||
// 多选框列表 |
|||
list: [ |
|||
{ |
|||
name: '冯老师', |
|||
src: '', |
|||
joinMethod: '文件创建者', |
|||
role: '观众', |
|||
checked: false, |
|||
disabled: false, |
|||
}, |
|||
{ |
|||
name: '马壮', |
|||
src: '', |
|||
joinMethod: '通过链接加入', |
|||
role: '干系人', |
|||
checked: false, |
|||
disabled: false, |
|||
}, |
|||
{ |
|||
name: '张野', |
|||
src: '', |
|||
joinMethod: '通过链接加入', |
|||
role: '观众', |
|||
checked: false, |
|||
disabled: false, |
|||
}, |
|||
], |
|||
quantity: 0, //多选里面已选择的数量 |
|||
path: '', |
|||
}; |
|||
}, |
|||
|
|||
computed: { |
|||
...mapState('role', ['visibleRoles', 'invisibleRoles']), |
|||
...mapState('project', ['project']), |
|||
...mapGetters('project', ['projectId']), |
|||
}, |
|||
|
|||
mounted() { |
|||
this.$nextTick(() => { |
|||
this.path = window.location.href.split('?')[0]; |
|||
const { path, projectId } = this; |
|||
const params = { path: `${path}`, projectId, roleId: '0' }; |
|||
this.creatShare(params); |
|||
}); |
|||
|
|||
if (this.visibleRoles.length || this.invisibleRoles.length) { |
|||
const arr = this.visibleRoles.concat(this.invisibleRoles); |
|||
arr.forEach(role => { |
|||
let item = { id: '', name: '' }; |
|||
item.id = role.id; |
|||
item.name = role.name; |
|||
this.allRolesName.push(item); |
|||
this.rolesArray.push(role.name); |
|||
}); |
|||
const firstItem = { id: '0', name: '观众' }; |
|||
this.allRolesName.unshift(firstItem); |
|||
this.rolesArray.unshift('观众'); |
|||
} |
|||
}, |
|||
|
|||
methods: { |
|||
// 选择角色 |
|||
async changeRole(e) { |
|||
this.index = e.target.value; |
|||
this.roleName = this.allRolesName[this.index].name; |
|||
const { path, projectId } = this; |
|||
const params = { path, projectId, roleId: this.allRolesName[this.index].id }; |
|||
await this.creatShare(params); |
|||
}, |
|||
|
|||
// 复制成功 |
|||
copySuccess() { |
|||
this.$t.ui.showToast('复制成功'); |
|||
}, |
|||
// 复制失败 |
|||
copyError() { |
|||
this.$t.ui.showToast('复制失败,请稍后重试'); |
|||
}, |
|||
|
|||
/** |
|||
* 创建分享链接 |
|||
* @param path 路径前缀 |
|||
* @param projectId 项目id |
|||
* @param roleId 角色id |
|||
*/ |
|||
async creatShare(params) { |
|||
try { |
|||
const data = await this.$u.api.createShare(params); |
|||
this.links = data.path; |
|||
this.copyText = `邀请您加入${this.project.name}的项目,角色为${this.roleName},链接为${data.path}&url=${this.$t.domain}`; |
|||
} catch (error) { |
|||
console.error('error: ', error); |
|||
} |
|||
}, |
|||
|
|||
//已选择 |
|||
select() { |
|||
this.quantity = 0; |
|||
this.list.forEach(val => { |
|||
if (val.checked == true) { |
|||
this.quantity++; |
|||
} |
|||
}); |
|||
}, |
|||
|
|||
// 全选 |
|||
checkedAll() { |
|||
this.list.map(val => { |
|||
val.checked = !this.checked; |
|||
}); |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.content { |
|||
width: 100%; |
|||
max-height: 400px; |
|||
} |
|||
|
|||
.link { |
|||
height: 40px; |
|||
border: 1px solid #afbed1; |
|||
} |
|||
|
|||
.link-url { |
|||
color: #afbed1; |
|||
width: 80%; |
|||
line-height: 40px; |
|||
margin-left: 5px; |
|||
overflow: hidden; |
|||
white-space: nowrap; |
|||
text-overflow: ellipsis; |
|||
} |
|||
</style> |
@ -0,0 +1,201 @@ |
|||
<template> |
|||
<view class="upload"> |
|||
<!-- <u-icon name="plus" size="24px" class="flex justify-center w-12 h-12 bg-blue-100 rounded-full shadow-md" @click="handleUpload"> |
|||
</u-icon> --> |
|||
<template v-if="user.phone"> |
|||
<div |
|||
v-if="btnList.length === 1" |
|||
class="flex justify-center w-12 h-12 bg-blue-100 rounded-full shadow-md" |
|||
style="line-height: 48px" |
|||
@click="jumpV(btnList[0].url)" |
|||
> |
|||
{{ btnList[0].name }} |
|||
</div> |
|||
<div v-else-if="btnList.length === 2" class="flex h-12 bg-blue-100 rounded-full shadow-md items-center" style="line-height: 48px"> |
|||
<div class="border-gray-300 min-w-16 border-r-2 border-solid flex justify-center h-4 items-center" @click="jumpV(btnList[0].url)"> |
|||
{{ btnList[0].name }} |
|||
</div> |
|||
<div class="flex min-w-16 justify-center" @click="jumpV(btnList[1].url)">{{ btnList[1].name }}</div> |
|||
</div> |
|||
<div v-else-if="btnList.length > 2" class="flex h-12 bg-blue-100 rounded-full shadow-md items-center" style="line-height: 48px"> |
|||
<div class="border-gray-300 min-w-16 border-r-2 border-solid flex justify-center h-4 items-center" @click="jumpV(btnList[0].url)"> |
|||
{{ btnList[0].name }} |
|||
</div> |
|||
<div class="flex min-w-16 justify-center" @click="isActive = !isActive"> |
|||
<div class="mr-1">其他</div> |
|||
<u-icon |
|||
name="arrow-down" |
|||
color="#0284c7" |
|||
size="28" |
|||
type="down" |
|||
:style="{ transform: `rotate(${isActive ? -180 : 0}deg)` }" |
|||
@click="isActive = !isActive" |
|||
style="transition: transform 0.24s; margin-right: 0px" |
|||
/> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
<u-button |
|||
v-else |
|||
open-type="getPhoneNumber" |
|||
@getphonenumber="getphonenumber" |
|||
:custom-style="customStyle" |
|||
shape="square" |
|||
size="default" |
|||
type="primary" |
|||
> |
|||
授权 |
|||
</u-button> |
|||
<view :style="{ height: isActive ? '200px' : 0 }" style="transition: all 0.24s" class="role-more-box"> |
|||
<template v-for="(item, index) in btnList"> |
|||
<div :class="index === btnList.length - 1 ? '' : 'border-bottom'" class="jump-list-box" v-if="index !== 0" :key="item.url"> |
|||
{{ item.name }} |
|||
</div> |
|||
</template> |
|||
</view> |
|||
<!-- <u-button @click="jump" size="default" type="primary"> 拍照 </u-button> --> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapState, mapGetters, mapMutations } from 'vuex'; |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
name: '', |
|||
url: '', |
|||
customStyle: { |
|||
borderRadius: '50%', |
|||
width: '3rem;', |
|||
height: '3rem;', |
|||
'--tw-bg-opacity': 1, |
|||
backgroundColor: 'rgba(219, 234, 254, var(--tw-bg-opacity))', |
|||
color: '#0284c7', |
|||
}, |
|||
btnList: [], |
|||
isActive: false, |
|||
}; |
|||
}, |
|||
computed: { |
|||
...mapState('user', ['user']), |
|||
...mapGetters('user', ['userId']), |
|||
}, |
|||
created() { |
|||
this.getInfo(); |
|||
}, |
|||
methods: { |
|||
...mapMutations('user', ['setToken', 'setUser']), |
|||
|
|||
jump() { |
|||
uni.navigateTo({ url: '/pages/camera/camera' }); |
|||
}, |
|||
async getphonenumber(e) { |
|||
try { |
|||
if (e.detail.errMsg === 'getPhoneNumber:fail user deny') { |
|||
console.log('e: ', e); |
|||
} else if (e.detail.errMsg === 'getPhoneNumber:ok') { |
|||
const params = { |
|||
encryptedData: e.detail.encryptedData, |
|||
iv: e.detail.iv, |
|||
miniType: 'basicCar', |
|||
}; |
|||
const data = await this.$u.api.bindPhone(params); |
|||
if (data && data.id) { |
|||
this.setUser(data); |
|||
this.setToken(data.token); |
|||
this.$refs.uTips.show({ |
|||
title: '授权成功', |
|||
type: 'success', |
|||
duration: '3000', |
|||
}); |
|||
} |
|||
} |
|||
} catch (error) { |
|||
this.$refs.uTips.show({ |
|||
title: '授权失败', |
|||
type: 'success', |
|||
duration: '3000', |
|||
}); |
|||
} |
|||
}, |
|||
// 导入wbs |
|||
async handleUpload() { |
|||
try { |
|||
const data = await this.$u.api.import(); |
|||
// 导入WBS成功后 |
|||
// 直接打开导入的项目 |
|||
this.$emit('success'); |
|||
data.url && (uni.$t.domain = data.url); |
|||
setTimeout(() => { |
|||
this.$u.route('/pages/project-webview/project-webview', { |
|||
u: this.userId, |
|||
p: data.id, |
|||
pname: data.pname, |
|||
url: data.url, |
|||
}); |
|||
}, 2000); |
|||
} catch (error) { |
|||
console.log('error: ', error); |
|||
this.$emit('error', error); |
|||
} |
|||
}, |
|||
// 跳转到问卷调查 |
|||
jumpV(url) { |
|||
if (this.user.phone) { |
|||
this.$u.route('pages/questionnaire-webview/questionnaire-webview', { u: this.userId, url: url }); |
|||
} else { |
|||
// this.$u.route('/pages/get-phone-power/get-phone-power'); |
|||
this.$u.route('/pages/phone-bind/phone-bind'); |
|||
} |
|||
}, |
|||
// 获取右侧按钮信息及跳转路径 |
|||
async getInfo() { |
|||
const that = this; |
|||
const data = await that.$u.api.getQueryButton({}); |
|||
this.btnList = data; |
|||
console.log('data: ', data); |
|||
if (data && data.length) { |
|||
that.name = data[0].name; |
|||
that.url = data[0].url; |
|||
} else if (data && data.name) { |
|||
that.name = data.name; |
|||
that.url = data.url; |
|||
} else if (!data) { |
|||
setTimeout(() => { |
|||
that.getInfo(); |
|||
}, 500); |
|||
} |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.upload { |
|||
position: absolute; |
|||
z-index: 99; |
|||
right: 10px; |
|||
bottom: 0; |
|||
transform: translate3d(0, 50%, 0); |
|||
color: $uni-color-primary !important; |
|||
} |
|||
.role-more-box { |
|||
box-shadow: 0 6px 6px rgba(0, 0, 0, 0.15); |
|||
overflow: hidden; |
|||
width: 750rpx; |
|||
background: #fff; |
|||
z-index: 10; |
|||
right: -10px; |
|||
position: fixed; |
|||
border-radius: 0 0 6px 6px; |
|||
} |
|||
.jump-list-box { |
|||
height: 48px; |
|||
line-height: 48px; |
|||
text-align: center; |
|||
} |
|||
.border-bottom { |
|||
border-bottom: 1px solid rgba(155, 155, 155, 0.35); |
|||
} |
|||
</style> |
@ -0,0 +1,418 @@ |
|||
<template> |
|||
<view class="uni-select-lay" :style="{ 'z-index': zindex }"> |
|||
<input type="text" :name="name" v-model="value" class="uni-select-input" /> |
|||
<view class="uni-select-lay-select" :class="{ active: active }"> |
|||
<!-- 禁用mask --> |
|||
<view class="uni-disabled" v-if="disabled"></view> |
|||
<!-- 禁用mask --> |
|||
<!-- 清空 --> |
|||
<view class="uni-select-lay-input-close" v-if="changevalue != '' && this.active"> |
|||
<text @click.stop="removevalue"></text> |
|||
</view> |
|||
<!-- 清空 --> |
|||
<input |
|||
type="text" |
|||
class="uni-select-lay-input" |
|||
:class="{ active: changevalue != '' && changevalue != placeholder }" |
|||
v-model="changevalue" |
|||
:disabled="disabled" |
|||
:placeholder="placeholder" |
|||
@focus="unifocus" |
|||
@input="intchange" |
|||
@blur="uniblur" |
|||
/> |
|||
<view class="uni-select-lay-icon" :class="{ disabled: disabled }" @click.stop="select"><text></text></view> |
|||
</view> |
|||
<scroll-view class="uni-select-lay-options" :scroll-y="true" v-show="active"> |
|||
<template v-if="!changes"> |
|||
<view class="uni-select-lay-item" v-if="showplaceholder" :class="{ active: value == '' }" @click.stop="selectitem(-1, null)"> |
|||
{{ placeholder }} |
|||
</view> |
|||
<view |
|||
class="uni-select-lay-item" |
|||
:class="{ active: value == item[svalue] }" |
|||
v-for="(item, index) in options" |
|||
:key="index" |
|||
@click.stop="selectitem(index, item)" |
|||
> |
|||
{{ item[slabel] }} |
|||
</view> |
|||
</template> |
|||
<!-- 搜索 --> |
|||
<template v-else> |
|||
<template v-if="vlist.length > 0"> |
|||
<view |
|||
class="uni-select-lay-item" |
|||
:class="{ active: value == item[svalue] }" |
|||
v-for="(item, index) in vlist" |
|||
:key="index" |
|||
@click.stop="selectitem(index, item)" |
|||
>{{ item[slabel] }} |
|||
</view> |
|||
</template> |
|||
<template v-else> |
|||
<view class="nosearch">{{ changesValue }}</view> |
|||
</template> |
|||
</template> |
|||
</scroll-view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'select-lay', |
|||
props: { |
|||
disabled: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
zindex: { |
|||
type: Number, |
|||
default: 999, |
|||
}, |
|||
options: { |
|||
type: Array, |
|||
default() { |
|||
return []; |
|||
}, |
|||
}, |
|||
name: { |
|||
type: String, |
|||
default: '', |
|||
}, |
|||
value: { |
|||
type: String, |
|||
default: '', |
|||
}, |
|||
placeholder: { |
|||
type: String, |
|||
default: '请选择', |
|||
}, |
|||
showplaceholder: { |
|||
type: Boolean, |
|||
default: true, |
|||
}, |
|||
slabel: { |
|||
type: String, |
|||
default: 'label', |
|||
}, |
|||
svalue: { |
|||
type: String, |
|||
default: 'value', |
|||
}, |
|||
}, |
|||
data() { |
|||
return { |
|||
active: false, //组件是否激活, |
|||
isremove: false, //是否是因为点击清空才导致的失去焦点 |
|||
changevalue: '', //搜索框同步 |
|||
oldvalue: '', //数据回滚 |
|||
changes: false, //正在搜索 |
|||
changesValue: '', |
|||
vlist: [], //搜索框查询的列表 |
|||
settimer: null, //value改变定时器 |
|||
}; |
|||
}, |
|||
mounted() { |
|||
this.itemcheck(); |
|||
}, |
|||
watch: { |
|||
//value改变 |
|||
value() { |
|||
this.itemcheck(); |
|||
}, |
|||
//初始化数组 |
|||
options() { |
|||
// 此处判断是否有初始value,存在则判断显示文字 |
|||
this.itemcheck(); |
|||
}, |
|||
}, |
|||
methods: { |
|||
//判断数组跟当前active值 |
|||
itemcheck() { |
|||
// 此处判断是否有初始value,存在则判断显示文字 |
|||
if (this.value != '') { |
|||
// 展示plachhoder |
|||
//判断数组 |
|||
if (this.options.length > 0) { |
|||
this.options.forEach(item => { |
|||
if (this.value == item[this.svalue]) { |
|||
this.oldvalue = this.changevalue = item[this.slabel]; |
|||
return; |
|||
} |
|||
}); |
|||
} |
|||
} else { |
|||
this.oldvalue = this.changevalue = ''; |
|||
} |
|||
}, |
|||
//点击组件 |
|||
select() { |
|||
if (this.disabled) return; |
|||
this.active = !this.active; |
|||
if (this.active) { |
|||
this.changes = false; |
|||
} else { |
|||
this.changevalue = this.oldvalue; |
|||
} |
|||
}, |
|||
// 获得焦点 |
|||
unifocus() { |
|||
if (this.disabled) return; |
|||
this.active = true; |
|||
this.changes = false; |
|||
}, |
|||
// 失去焦点 |
|||
uniblur() { |
|||
// bug 点击组件列会先触发失去焦点,此时组件列事件不执行 |
|||
setTimeout(() => { |
|||
if (this.isremove) { |
|||
this.isremove = false; |
|||
} else { |
|||
this.changevalue = this.oldvalue; |
|||
this.isremove = false; |
|||
this.active = false; |
|||
} |
|||
}, 153); |
|||
}, |
|||
//移除数据 |
|||
removevalue() { |
|||
this.isremove = true; |
|||
this.changes = false; |
|||
this.changevalue = ''; |
|||
}, |
|||
//value 改变 |
|||
intchange() { |
|||
if (this.changevalue == '') { |
|||
this.changes = false; |
|||
return; |
|||
} |
|||
this.vlist = []; |
|||
this.changes = true; |
|||
this.changesValue = '正在搜索...'; |
|||
if (this.settimer) { |
|||
clearTimeout(this.settimer); |
|||
} |
|||
this.settimer = setTimeout(() => { |
|||
this.vlist = this.options.filter(item => { |
|||
return item[this.slabel].includes(this.changevalue); |
|||
}); |
|||
if (this.vlist.length === 0) { |
|||
this.changesValue = '暂无匹配内容!'; |
|||
} |
|||
}, 600); |
|||
}, |
|||
|
|||
//点击组件列 |
|||
selectitem(index, item) { |
|||
this.changevalue = this.oldvalue; |
|||
this.active = false; |
|||
this.$emit('selectitem', index, item); |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.uni-select-lay { |
|||
position: relative; |
|||
z-index: 999; |
|||
|
|||
.uni-select-input { |
|||
opacity: 0; |
|||
position: absolute; |
|||
z-index: -111; |
|||
} |
|||
|
|||
// select部分 |
|||
.uni-select-lay-select { |
|||
user-select: none; |
|||
position: relative; |
|||
z-index: 3; |
|||
height: 36px; |
|||
padding: 0 30px 0 10px; |
|||
box-sizing: border-box; |
|||
border-radius: 4px; |
|||
border: 1px solid rgb(229, 229, 229); |
|||
display: flex; |
|||
align-items: center; |
|||
font-size: 14px; |
|||
color: #999; |
|||
|
|||
.uni-disabled { |
|||
position: absolute; |
|||
left: 0; |
|||
width: 100%; |
|||
height: 100%; |
|||
z-index: 19; |
|||
cursor: no-drop; |
|||
background: rgba(255, 255, 255, 0.5); |
|||
} |
|||
|
|||
// input 框的清除按钮 |
|||
.uni-select-lay-input-close { |
|||
position: absolute; |
|||
right: 35px; |
|||
top: 0; |
|||
height: 100%; |
|||
width: 15px; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
z-index: 3; |
|||
cursor: pointer; |
|||
|
|||
text { |
|||
position: relative; |
|||
background: #fff; |
|||
width: 13px; |
|||
height: 13px; |
|||
border-radius: 50%; |
|||
border: 1px solid #bbb; |
|||
|
|||
&::before, |
|||
&::after { |
|||
content: ''; |
|||
position: absolute; |
|||
left: 20%; |
|||
top: 50%; |
|||
height: 1px; |
|||
width: 60%; |
|||
transform: rotate(45deg); |
|||
background-color: #bbb; |
|||
} |
|||
|
|||
&::after { |
|||
transform: rotate(-45deg); |
|||
} |
|||
} |
|||
} |
|||
|
|||
.uni-select-lay-input { |
|||
font-size: 14px; |
|||
color: #999; |
|||
display: block; |
|||
width: 98%; |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
white-space: nowrap; |
|||
line-height: 30px; |
|||
box-sizing: border-box; |
|||
|
|||
&.active { |
|||
color: #333; |
|||
} |
|||
} |
|||
|
|||
.uni-select-lay-icon { |
|||
cursor: pointer; |
|||
position: absolute; |
|||
right: 0; |
|||
top: 0; |
|||
height: 100%; |
|||
width: 30px; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
|
|||
&::before { |
|||
content: ''; |
|||
width: 1px; |
|||
height: 100%; |
|||
position: absolute; |
|||
left: 0; |
|||
top: 0; |
|||
background-color: #e5e5e5; |
|||
} |
|||
|
|||
text { |
|||
display: block; |
|||
width: 0; |
|||
height: 0; |
|||
border-width: 12rpx 12rpx 0; |
|||
border-style: solid; |
|||
border-color: #bbb transparent transparent; |
|||
transition: 0.3s; |
|||
} |
|||
|
|||
&.disabled { |
|||
cursor: no-drop; |
|||
text { |
|||
width: 20rpx; |
|||
height: 20rpx; |
|||
border: 2px solid #ff0000; |
|||
border-radius: 50%; |
|||
transition: 0.3s; |
|||
position: relative; |
|||
z-index: 999; |
|||
|
|||
&::after { |
|||
content: ''; |
|||
position: absolute; |
|||
top: 50%; |
|||
left: 0; |
|||
width: 100%; |
|||
height: 2px; |
|||
margin-top: -1px; |
|||
background-color: #ff0000; |
|||
transform: rotate(45deg); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
&.active .uni-select-lay-icon { |
|||
text { |
|||
transform: rotate(180deg); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// options部分 |
|||
.uni-select-lay-options { |
|||
user-select: none; |
|||
position: absolute; |
|||
top: calc(100% + 5px); |
|||
left: 0; |
|||
width: 100%; |
|||
max-height: 500rpx; |
|||
// overflow-y: auto; |
|||
border-radius: 4px; |
|||
border: 1px solid rgb(229, 229, 229); |
|||
background: #fff; |
|||
padding: 5px 0; |
|||
box-sizing: border-box; |
|||
z-index: 9; |
|||
|
|||
.uni-select-lay-item { |
|||
padding: 0 10px; |
|||
box-sizing: border-box; |
|||
cursor: pointer; |
|||
line-height: 2.5; |
|||
transition: 0.3s; |
|||
font-size: 14px; |
|||
|
|||
&.active { |
|||
background: #007aff; |
|||
color: #fff; |
|||
|
|||
&:hover { |
|||
background: #007aff; |
|||
color: #fff; |
|||
} |
|||
} |
|||
|
|||
&:hover { |
|||
background-color: #f5f5f5; |
|||
} |
|||
} |
|||
|
|||
.nosearch { |
|||
font-size: 16px; |
|||
line-height: 3; |
|||
text-align: center; |
|||
color: #666; |
|||
} |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,6 @@ |
|||
export default { |
|||
V: process.env.VUE_APP_VERSION, |
|||
version: process.env.VUE_APP_VERSION, |
|||
theme: [], |
|||
tokenKey: 'anyringToken', // storage token key
|
|||
}; |
@ -0,0 +1,3 @@ |
|||
export const db = null; // indexedDB 对象
|
|||
export const name = 'TALL_indexedDB'; // indexDB name
|
|||
export const version = 1; // indexDB version
|
@ -0,0 +1,97 @@ |
|||
// 定义插件相关信息
|
|||
/* 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列表
|
|||
}; |
@ -0,0 +1,2 @@ |
|||
// 每页加载颗粒度的个数
|
|||
export default { pageCount: 10 }; |
@ -0,0 +1,17 @@ |
|||
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, |
|||
}; |
@ -0,0 +1,44 @@ |
|||
// 用户登录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, credential: 'basicCar' }, |
|||
// data: { identifier: res.code, credential: 'tall' },
|
|||
}; |
|||
resolve(params); |
|||
} else { |
|||
reject(res.errMsg); |
|||
} |
|||
}, |
|||
fail() { |
|||
console.log('fail'); |
|||
reject('微信登录失败'); |
|||
}, |
|||
}); |
|||
}); |
|||
}; |
|||
|
|||
export default { |
|||
clients, |
|||
types, |
|||
}; |
@ -0,0 +1,5 @@ |
|||
// 定义项目中定位的元素的层级
|
|||
/* eslint-disable */ |
|||
export default { |
|||
roleBar: 999, // 角色栏成绩
|
|||
}; |
@ -0,0 +1,52 @@ |
|||
import App from './App'; |
|||
import Tall from '@/utils/tall'; |
|||
import Vue from 'vue'; |
|||
import request from '@/utils/request.js'; |
|||
import dayjs from 'dayjs'; |
|||
import project from '@/apis/project.js'; |
|||
import role from '@/apis/role.js'; |
|||
import store from './store'; |
|||
import tall from '@/apis/tall.js'; |
|||
import task from '@/apis/task.js'; |
|||
import carbasics from '@/apis/carbasics.js'; |
|||
import uView from 'uview-ui'; |
|||
import wbs from '@/apis/wbs.js'; |
|||
|
|||
//#ifdef H5
|
|||
// import './registerServiceWorker';
|
|||
// import AlloyFinger from 'alloyfinger';
|
|||
// import AlloyFingerPlugin from 'alloyfinger/vue/alloy_finger_vue';
|
|||
// Vue.use(AlloyFingerPlugin, { AlloyFinger });
|
|||
// indexedDB
|
|||
// import indexedDB from '@/utils/indexedDB';
|
|||
// Vue.use(indexedDB);
|
|||
//#endif
|
|||
|
|||
Vue.config.productionTip = false; |
|||
Vue.prototype.$moment = dayjs; |
|||
Vue.use(uView); |
|||
Vue.use(Tall); |
|||
|
|||
uni.$moment = dayjs; |
|||
|
|||
dayjs.locale('zh-cn'); |
|||
|
|||
App.mpType = 'app'; |
|||
|
|||
const app = new Vue({ ...App, store }); |
|||
|
|||
const obj = { title: '暴风眼Typhoneye' }; |
|||
uni.showShareMenu(obj); |
|||
uni.onShareAppMessage = function () { |
|||
return { title: '暴风眼Typhoneye', path: '/pages/index/index' }; |
|||
}; |
|||
|
|||
Vue.use(request, app); |
|||
Vue.use(tall, app); |
|||
Vue.use(project, app); |
|||
Vue.use(role, app); |
|||
Vue.use(carbasics, app); |
|||
Vue.use(task, app); |
|||
Vue.use(wbs, app); |
|||
|
|||
app.$mount(); |
@ -0,0 +1,81 @@ |
|||
{ |
|||
"name": "暴风眼Typhoneye", |
|||
"appid": "wx3190e3f68dd4d068", |
|||
"description": "", |
|||
"versionName": "1.0.0", |
|||
"versionCode": "100", |
|||
"transformPx": false, |
|||
"app-plus": { |
|||
/* 5+App特有相关 */ "usingComponents": true, |
|||
"splashscreen": { |
|||
"alwaysShowBeforeRender": true, |
|||
"waiting": true, |
|||
"autoclose": true, |
|||
"delay": 0 |
|||
}, |
|||
"modules": { |
|||
/* 模块配置 */ |
|||
}, |
|||
"distribute": { |
|||
/* 应用发布信息 */ |
|||
"android": { |
|||
/* android打包配置 */ |
|||
"permissions": [ |
|||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>", |
|||
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>", |
|||
"<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>", |
|||
"<uses-permission android:name=\"android.permission.VIBRATE\"/>", |
|||
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>", |
|||
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>", |
|||
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>", |
|||
"<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>", |
|||
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>", |
|||
"<uses-permission android:name=\"android.permission.CAMERA\"/>", |
|||
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>", |
|||
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>", |
|||
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>", |
|||
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>", |
|||
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>", |
|||
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>", |
|||
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>", |
|||
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>", |
|||
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>", |
|||
"<uses-feature android:name=\"android.hardware.camera\"/>", |
|||
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>", |
|||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>" |
|||
] |
|||
}, |
|||
"ios": { |
|||
/* ios打包配置 */ |
|||
}, |
|||
"sdkConfigs": { |
|||
/* SDK配置 */ |
|||
} |
|||
} |
|||
}, |
|||
"quickapp": { |
|||
/* 快应用特有相关 */ |
|||
}, |
|||
"mp-weixin": { |
|||
"appid": "wx3190e3f68dd4d068", |
|||
"setting": { |
|||
"urlCheck": false |
|||
}, |
|||
"usingComponents": true |
|||
}, |
|||
|
|||
"h5": { |
|||
"router": { |
|||
"base": "/carBasicCalendar" |
|||
}, |
|||
"title": "暴风眼Typhoneye", |
|||
"sdkConfigs": { |
|||
"maps": {} |
|||
}, |
|||
"optimization": { |
|||
"treeShaking": { |
|||
"enable": false |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,48 @@ |
|||
import { mapMutations, mapState } from 'vuex'; |
|||
|
|||
import { waitTokenRequest } from '@/utils/cacheAndRequest'; |
|||
|
|||
export default { |
|||
computed: mapState('user', ['token', 'user']), |
|||
methods: { |
|||
...mapMutations('user', ['setUser']), |
|||
// 获取授权
|
|||
openAuth() { |
|||
if (this.user && this.user.wxInfo && this.user.wxInfo.nickname) return; // 用户信息里有微信信息就不用再获取了
|
|||
if (this.token) { |
|||
this.updateUserInfo(); |
|||
} else { |
|||
waitTokenRequest(this.updateUserInfo); |
|||
} |
|||
}, |
|||
|
|||
// 弹出授权框
|
|||
// 用户允许后 提交微信用户信息
|
|||
updateUserInfo() { |
|||
/* #ifdef MP-WEIXIN */ |
|||
uni.getUserProfile({ |
|||
desc: '仅需要获取您的基本用户信息', |
|||
success: async res => { |
|||
const { avatarUrl, city, country, gender, language, nickName, province } = res.userInfo; |
|||
const data = await this.$u.api.updateUserInfo({ |
|||
city, |
|||
country, |
|||
headImgUrl: avatarUrl, |
|||
language, |
|||
nickname: nickName, |
|||
province, |
|||
sex: gender, |
|||
}); |
|||
console.log('data: ', data); |
|||
const { user } = this; |
|||
user.wxInfo = data; |
|||
this.setUser(user); |
|||
}, |
|||
fail: error => { |
|||
console.log('error: ', error); |
|||
}, |
|||
}); |
|||
/* #endif */ |
|||
}, |
|||
}, |
|||
}; |
@ -0,0 +1,78 @@ |
|||
{ |
|||
"pages": [ |
|||
{ |
|||
"path": "pages/index/index", |
|||
"style": { |
|||
"navigationBarText": "暴风眼Typhoneye" |
|||
} |
|||
}, |
|||
{ |
|||
"path": "pages/get-phone-power/get-phone-power", |
|||
"style": { |
|||
"navigationBarTitleText": "宣传页" |
|||
} |
|||
}, |
|||
{ |
|||
"path": "pages/phone-bind/phone-bind", |
|||
"style": { |
|||
"navigationBarTitleText": "绑定手机号" |
|||
} |
|||
}, |
|||
{ |
|||
"path": "pages/project-webview/project-webview", |
|||
"style": { |
|||
"navigationStyle": "custom", |
|||
"navigationBarTitleText": "暴风眼Typhoneye" |
|||
} |
|||
}, |
|||
{ |
|||
"path": "pages/questionnaire-webview/questionnaire-webview", |
|||
"style": { |
|||
"navigationBarTitleText": "详情" |
|||
} |
|||
}, |
|||
{ |
|||
"path": "pages/camera/camera", |
|||
"style": { |
|||
"navigationBarTitleText": "拍照" |
|||
} |
|||
}, |
|||
{ |
|||
"path": "pages/task-page/task-page", |
|||
"style": { |
|||
"navigationBarTitleText": "项目详情页" |
|||
} |
|||
}, |
|||
{ |
|||
"path": "pages/patientLine/patientLine", |
|||
"style": { |
|||
"navigationBarTitleText": "病例填写目录" |
|||
} |
|||
}, |
|||
{ |
|||
"path": "pages/establish/establish", |
|||
"style": { |
|||
"navigationBarTitleText": "创建病例" |
|||
} |
|||
}, |
|||
{ |
|||
"path": "pages/inner/inner", |
|||
"style": { |
|||
"navigationBarTitleText": "信息录入" |
|||
} |
|||
} |
|||
], |
|||
"globalStyle": { |
|||
"navigationBarTextStyle": "black", |
|||
"navigationBarTitleText": "暴风眼Typhoneye", |
|||
"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,71 @@ |
|||
<template> |
|||
<div class="camera"> |
|||
<camera device-position="back" flash="auto" @error="error" style="width: 100%; height: 500upx"> |
|||
<!-- <cover-image src="../../static/scan-frame/scan-img.png" class="scan-img"></cover-image> --> |
|||
</camera> |
|||
<view class="scan-text">支持将“住院病案首页”“医嘱单”拍照进行文字识别</view> |
|||
<button type="primary" @click="takePhoto">拍照</button> |
|||
<image v-for="item in srcList" :key="item" mode="widthFix" class="photos-box" :src="item"></image> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
components: {}, |
|||
data: () => ({ srcList: [] }), |
|||
computed: {}, |
|||
methods: { |
|||
takePhoto() { |
|||
const ctx = uni.createCameraContext(); |
|||
ctx.takePhoto({ |
|||
quality: 'high', |
|||
success: res => { |
|||
this.srcList.push(res.tempImagePath); |
|||
console.log('this.srcList: ', this.srcList); |
|||
/* 返回调用页面并把图片URL传递过去 */ |
|||
/* let pages = getCurrentPages(); |
|||
let prevPage = pages[pages.length - 2]; |
|||
prevPage.setData({ |
|||
"image": res.tempImagePath, |
|||
}) |
|||
uni.navigateBack(); */ |
|||
|
|||
/* 调用页面获取图片URL方法 */ |
|||
/* let pages = getCurrentPages(); |
|||
let currPage = pages[pages.length-1]; |
|||
if(typeof(currPage.data.image) != undefined && currPage.data.image != null){ |
|||
console.log('获取图片:', currPage.data.image) |
|||
} */ |
|||
}, |
|||
}); |
|||
}, |
|||
error(e) { |
|||
console.log(e.detail); |
|||
}, |
|||
}, |
|||
watch: {}, |
|||
|
|||
// 页面周期函数--监听页面加载 |
|||
onLoad() {}, |
|||
// 页面周期函数--监听页面初次渲染完成 |
|||
onReady() {}, |
|||
// 页面周期函数--监听页面显示(not-nvue) |
|||
onShow() {}, |
|||
// 页面周期函数--监听页面隐藏 |
|||
onHide() {}, |
|||
// 页面周期函数--监听页面卸载 |
|||
onUnload() {}, |
|||
// 页面处理函数--监听用户下拉动作 |
|||
onPullDownRefresh() { |
|||
uni.stopPullDownRefresh(); |
|||
}, |
|||
// 页面处理函数--监听用户上拉触底 |
|||
onReachBottom() {}, |
|||
// 页面处理函数--监听页面滚动(not-nvue) |
|||
/* onPageScroll(event) {}, */ |
|||
// 页面处理函数--用户点击右上角分享 |
|||
/* onShareAppMessage(options) {}, */ |
|||
}; |
|||
</script> |
|||
|
|||
<style></style> |
@ -0,0 +1,444 @@ |
|||
<template> |
|||
<div class="establish bg-gray-100"> |
|||
<div bordered class="list-box bg-white" v-for="(item, index) in list" :key="index"> |
|||
<div |
|||
class="list-item" |
|||
:style="{ 'border-bottom': listIndex === item.length - 1 ? '' : '1px solid #ccc;' }" |
|||
v-for="(listItem, listIndex) in item" |
|||
:key="listIndex" |
|||
> |
|||
<div class="w-full flex flex-nowrap justify-between items-center"> |
|||
<div class="flex items-center" v-if="listItem.title"> |
|||
{{ listItem.title }} |
|||
<span v-if="listItem.isTrue" style="color: red; font-size: 20px">*</span> |
|||
</div> |
|||
<div> |
|||
<u-switch v-if="listItem.type === 1" v-model="codeValue['CJBL-YLMS']" /> |
|||
<u-upload |
|||
v-else-if="listItem.type === 2" |
|||
name="part" |
|||
accept="image/*" |
|||
:action="action" |
|||
:show-upload-list="false" |
|||
:custom-btn="true" |
|||
@on-success="successUpload" |
|||
> |
|||
<img slot="addBtn" src="./icon/idcard.png" class="img-icon" /> |
|||
</u-upload> |
|||
<div v-else-if="listItem.type === 3" style="width: 174px"> |
|||
<!-- {{ codeValue[listItem.code] }} --> |
|||
|
|||
<u-input |
|||
input-align="right" |
|||
:value="codeValue[listItem.code]" |
|||
placeholder="请输入" |
|||
@blur="iptBlur(listItem.code)" |
|||
style="text-align: right" |
|||
/> |
|||
<!-- <input type="text" :value="codeValue[listItem.code]" /> --> |
|||
<div class="text-red-400 font-12" style="text-align: right" v-if="!isFit && listItem.code === 'CJBL-idCard'"> |
|||
身份证号输入有误! |
|||
</div> |
|||
</div> |
|||
<u-radio-group :value="codeValue[listItem.code]" v-else-if="listItem.type === 4" name="radioGroup"> |
|||
<div @click="clickRadio(listItem.code, radioItem.name)" v-for="radioItem in listItem.listItem" :key="radioItem.id"> |
|||
<u-radio |
|||
@change="changeRadio($event, listItem.code)" |
|||
:disabled="isDisabled(listItem.code, radioItem.name)" |
|||
:key="radioItem.id" |
|||
:name="radioItem.id" |
|||
> |
|||
{{ radioItem.name }} |
|||
</u-radio> |
|||
</div> |
|||
<!-- <u-radio :value="1"> 男 </u-radio> --> |
|||
</u-radio-group> |
|||
<u-radio-group |
|||
:disabled="sexIsDisabled('CJBL-idCard')" |
|||
:value="codeValue[listItem.code]" |
|||
v-else-if="listItem.type === 41" |
|||
name="radioGroup" |
|||
> |
|||
<u-radio |
|||
@change="changeRadio($event, listItem.code)" |
|||
v-for="radioItem in listItem.listItem" |
|||
:key="radioItem.id" |
|||
:name="radioItem.id" |
|||
> |
|||
{{ radioItem.name }} |
|||
</u-radio> |
|||
</u-radio-group> |
|||
<!-- <div |
|||
v-else-if="listItem.type === 5" |
|||
style="min-width: 100px; width: auto; justify-content: flex-end" |
|||
class="d-flex align-center" |
|||
@click="showDrop = true" |
|||
> |
|||
<span style="margin-right: 10px">{{ codeValue['CJBL-YSBL'] }}</span> |
|||
<img src="@/static/icon/right.png" style="height: 20px" /> |
|||
</div> --> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="d-flex btn-box" v-if="showBtn"> |
|||
<u-button type="primary" :disabled="isSubmit" id="complete-btn" class="flex-1 btn mr-2" @click="submit"> 完成创建病例 </u-button> |
|||
<!-- <a-button |
|||
:disabled="isStartDisabled()" |
|||
:class="isStartDisabled() ? '' : 'green-btn'" |
|||
class="flex-2 btn ml-2" |
|||
@click="startGreen"> |
|||
一键启动绿道 |
|||
</a-button> --> |
|||
</div> |
|||
<u-toast ref="uToast" /> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapState, mapGetters, mapMutations } from 'vuex'; |
|||
|
|||
export default { |
|||
components: {}, |
|||
data: () => ({ |
|||
action: '', |
|||
codeValue: { |
|||
'CJBL-YLMS': false, |
|||
'CJBL-NAME': null, |
|||
'CJBL-SEX': null, |
|||
'CJBL-nation': null, |
|||
'CJBL-idCard': null, |
|||
'CJBL-YSBL': 'AS急性脑卒中', |
|||
}, |
|||
list: [ |
|||
[{ title: '演练模式', type: 1, isTrue: false }], |
|||
[{ title: '扫描身份证', type: 2, isTrue: false }], |
|||
[ |
|||
{ title: '姓名', type: 3, code: 'CJBL-NAME', isTrue: true }, |
|||
{ |
|||
title: '性别', |
|||
type: 41, |
|||
code: 'CJBL-SEX', |
|||
isTrue: true, |
|||
listItem: [ |
|||
{ name: '女', id: 0 }, |
|||
{ name: '男', id: 1 }, |
|||
], |
|||
}, |
|||
{ title: '民族', type: 3, code: 'CJBL-nation', isTrue: false }, |
|||
{ title: '身份证号', type: 3, code: 'CJBL-idCard', isTrue: false }, |
|||
{ |
|||
title: '疑似诊断', |
|||
code: 'CJBL-YSBL', |
|||
type: 4, |
|||
isTrue: false, |
|||
}, |
|||
{ |
|||
title: '', |
|||
code: 'CJBL-YSBL', |
|||
type: 4, |
|||
isTrue: false, |
|||
listItem: [ |
|||
{ name: 'AS急性脑卒中', id: 'AS急性脑卒中' }, |
|||
{ name: 'AMI急性心肌梗死', id: 'AMI急性心肌梗死' }, |
|||
{ name: 'ATI急性创伤', id: 'ATI急性创伤' }, |
|||
{ name: 'AGB急性消化道出血', id: 'AGB急性消化道出血' }, |
|||
], |
|||
}, |
|||
], |
|||
], |
|||
dropList: [], |
|||
bodyStyle: { textAlign: 'center', height: '240px', padding: '24px 24px 0 24px', position: 'relative', overFlow: 'hidden' }, |
|||
visible: false, |
|||
isActive: true, |
|||
active: 0, |
|||
showBtn: true, |
|||
role: '', |
|||
isFit: true, // 身份证号是否符合验证规则 |
|||
firstAidId: null, |
|||
showTips: false, |
|||
topOrBottom: true, |
|||
timer: null, |
|||
isSubmit: false, |
|||
isStart: false, |
|||
}), |
|||
computed: { |
|||
...mapGetters('project', ['projectId']), |
|||
...mapState('carbasics', ['globalData']), |
|||
}, |
|||
|
|||
onLoad(options) { |
|||
console.log('options: ', options); |
|||
this.role = options.role; |
|||
this.action = uni.$u.api.identifyWords; |
|||
}, |
|||
|
|||
methods: { |
|||
...mapMutations('carbasics', ['setRefreshList']), |
|||
// 上传图片成功时 |
|||
successUpload(res) { |
|||
const { code, data } = res; |
|||
let obj = { ...this.codeValue }; |
|||
if (code === 200) { |
|||
obj['CJBL-NAME'] = data.name; |
|||
obj['CJBL-SEX'] = data.sex; |
|||
obj['CJBL-idCard'] = data.idCardNo; |
|||
obj['CJBL-nation'] = data.nation; |
|||
this.codeValue = { ...obj }; |
|||
} |
|||
}, |
|||
// 判断当前选项是否可点 |
|||
isDisabled(code, name) { |
|||
if (code === 'CJBL-YSBL' && name !== 'AS急性脑卒中') { |
|||
return true; |
|||
} else { |
|||
return false; |
|||
} |
|||
}, |
|||
sexIsDisabled(code) { |
|||
if (this.codeValue[code] && this.codeValue[code].length > 0) { |
|||
return true; |
|||
} |
|||
}, |
|||
// 点击了疑似病例的其他选项 |
|||
clickRadio(code, name) { |
|||
if (code === 'CJBL-YSBL' && name !== 'AS急性脑卒中') { |
|||
// this.$message.warning('请联系系统代理商开通该功能'); |
|||
this.$refs.uToast.show({ |
|||
title: '请联系系统代理商开通该功能', |
|||
type: 'warning', |
|||
}); |
|||
} |
|||
}, |
|||
// 单选改变事件 |
|||
changeRadio(e, code) { |
|||
this.codeValue[code] = e; |
|||
}, |
|||
// 输入框失去焦点 |
|||
iptBlur(code) { |
|||
if (code === 'CJBL-idCard') { |
|||
if (this.codeValue['CJBL-idCard']) { |
|||
this.isFit = this.isIdentityId(this.codeValue['CJBL-idCard']); |
|||
const idcard = this.codeValue['CJBL-idCard']; |
|||
if (this.codeValue['CJBL-idCard'].length === 15) { |
|||
this.codeValue['CJBL-SEX'] = (idcard[idcard.length - 1] - 0) % 2; |
|||
} else if (this.codeValue['CJBL-idCard'].length === 18) { |
|||
this.codeValue['CJBL-SEX'] = (idcard[idcard.length - 2] - 0) % 2; |
|||
} |
|||
} else { |
|||
this.isFit = true; |
|||
} |
|||
} |
|||
}, |
|||
// 验证身份证 |
|||
isIdentityId(identityId) { |
|||
var patrn = /(^\d{15}$)|(^\d{17}(\d|X|x)$)/; //长度或格式校验 |
|||
//地区校验 |
|||
var aCity = { |
|||
11: '北京', |
|||
12: '天津', |
|||
13: '河北', |
|||
14: '山西', |
|||
15: '内蒙古', |
|||
21: '辽宁', |
|||
22: '吉林', |
|||
23: '黑龙江', |
|||
31: '上海', |
|||
32: '江苏', |
|||
33: '浙江', |
|||
34: '安徽', |
|||
35: '福建', |
|||
36: '江西', |
|||
37: '山东', |
|||
41: '河南', |
|||
42: '湖北', |
|||
43: '湖南', |
|||
44: '广东', |
|||
45: '广西', |
|||
46: '海南', |
|||
50: '重庆', |
|||
51: '四川', |
|||
52: '贵州', |
|||
53: '云南', |
|||
54: '西藏', |
|||
61: '陕西', |
|||
62: '甘肃', |
|||
63: '青海', |
|||
64: '宁夏', |
|||
65: '新疆', |
|||
71: '台湾', |
|||
81: '香港', |
|||
82: '澳门', |
|||
91: '国外', |
|||
}; |
|||
// 出生日期验证 |
|||
var sBirthday = (identityId.substr(6, 4) + '-' + Number(identityId.substr(10, 2)) + '-' + Number(identityId.substr(12, 2))).replace( |
|||
/-/g, |
|||
'/', |
|||
), |
|||
d = new Date(sBirthday); |
|||
// 身份证号码校验 最后4位 包括最后一位的数字/字母X |
|||
var sum = 0, |
|||
weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2], |
|||
codes = '10X98765432', |
|||
codes1 = '10x98765432'; |
|||
for (var i = 0; i < identityId.length - 1; i++) { |
|||
sum += identityId[i] * weights[i]; |
|||
} |
|||
var last = codes[sum % 11]; //计算出来的最后一位身份证号码 |
|||
var last1 = codes1[sum % 11]; //计算出来的最后一位身份证号码 |
|||
|
|||
var errorMsg = true; |
|||
if (identityId === '') { |
|||
errorMsg = false; |
|||
} else if (!patrn.exec(identityId)) { |
|||
errorMsg = false; |
|||
} else if (!aCity[parseInt(identityId.substr(0, 2))]) { |
|||
errorMsg = false; |
|||
} else if (sBirthday != d.getFullYear() + '/' + (d.getMonth() + 1) + '/' + d.getDate()) { |
|||
errorMsg = false; |
|||
} else if (identityId[identityId.length - 1] != last && identityId[identityId.length - 1] != last1) { |
|||
errorMsg = false; |
|||
} |
|||
return errorMsg; |
|||
}, |
|||
/** |
|||
* 创建病例 |
|||
*/ |
|||
async submit() { |
|||
try { |
|||
this.isSubmit = true; |
|||
const params = { |
|||
gender: this.codeValue['CJBL-SEX'], |
|||
idcard: this.codeValue['CJBL-idCard'], |
|||
name: this.codeValue['CJBL-NAME'], |
|||
nation: this.codeValue['CJBL-nation'], |
|||
projectId: this.projectId, |
|||
suspected: this.codeValue['CJBL-YSBL'], |
|||
valueType: this.codeValue['CJBL-YLMS'] ? 1 : 0, |
|||
}; |
|||
const data = await this.$u.api.savePatient(params); |
|||
if (data && data.firstAidId) { |
|||
// this.$message.success('创建成功,请选择录入模板'); |
|||
this.$refs.uToast.show({ |
|||
title: '创建成功', |
|||
type: 'success', |
|||
}); |
|||
this.firstAidId = data.firstAidId; |
|||
this.isSubmit = false; |
|||
if (this.role === 'YiSheng') { |
|||
// this.visible = true; |
|||
this.handleOk(this.globalData.createAuth - 0 === 0 ? 1 : 0); |
|||
uni.navigateBack(); |
|||
uni.navigateTo({ url: `/pages/patientLine/patientLine?caseType=${this.globalData.createAuth - 0 === 0 ? 1 : 0}` }); |
|||
} else if (this.role === 'HuShi') { |
|||
// this.$router.push(`/function`); |
|||
uni.navigateBack(); |
|||
} |
|||
this.setRefreshList(); |
|||
} else { |
|||
this.$refs.uToast.show({ |
|||
title: '创建失败', |
|||
type: 'error', |
|||
}); |
|||
this.isSubmit = false; |
|||
} |
|||
} catch (error) { |
|||
this.$refs.uToast.show({ |
|||
title: '创建失败', |
|||
type: 'error', |
|||
}); |
|||
this.isSubmit = false; |
|||
} |
|||
}, |
|||
/** |
|||
* 点击了modal框的确认按钮 |
|||
* 加入急救,并且切换tall的时间轴界面 |
|||
*/ |
|||
async handleOk(type) { |
|||
try { |
|||
const params = { |
|||
projectId: this.projectId, |
|||
firstAidId: this.firstAidId, |
|||
type, |
|||
}; |
|||
const data = await uni.$u.api.joinAid(params); |
|||
if (data) { |
|||
const codeAndAnswerList = [ |
|||
{ |
|||
questionCode: 'JKJY-SFXJ', |
|||
answer: ['是'], |
|||
}, |
|||
{ |
|||
questionCode: 'JKJY-XJFS', |
|||
answer: ['集体病区教育'], |
|||
}, |
|||
{ |
|||
questionCode: 'YJJL-CTendTime-outSide', |
|||
answer: ['否'], |
|||
}, |
|||
]; |
|||
const setParams = { |
|||
codeAndAnswerList, |
|||
firstAidId: this.firstAidId, |
|||
}; |
|||
uni.$u.api.setRecord(setParams); |
|||
} |
|||
} catch (error) { |
|||
console.log(error); |
|||
} |
|||
}, |
|||
}, |
|||
watch: {}, |
|||
// 页面周期函数--监听页面初次渲染完成 |
|||
onReady() {}, |
|||
// 页面周期函数--监听页面显示(not-nvue) |
|||
onShow() {}, |
|||
// 页面周期函数--监听页面隐藏 |
|||
onHide() {}, |
|||
// 页面周期函数--监听页面卸载 |
|||
onUnload() {}, |
|||
// 页面处理函数--监听用户下拉动作 |
|||
onPullDownRefresh() { |
|||
uni.stopPullDownRefresh(); |
|||
}, |
|||
// 页面处理函数--监听用户上拉触底 |
|||
onReachBottom() {}, |
|||
// 页面处理函数--监听页面滚动(not-nvue) |
|||
/* onPageScroll(event) {}, */ |
|||
// 页面处理函数--用户点击右上角分享 |
|||
/* onShareAppMessage(options) {}, */ |
|||
}; |
|||
</script> |
|||
|
|||
<style> |
|||
.img-icon { |
|||
height: 24px; |
|||
width: 24px; |
|||
color: #717171; |
|||
} |
|||
.btn-box { |
|||
padding: 16px; |
|||
} |
|||
.list-box { |
|||
border-radius: 4px; |
|||
overflow: hidden; |
|||
box-sizing: border-box; |
|||
margin: 0 0 0.75rem 0; |
|||
padding: 0; |
|||
color: rgba(0, 0, 0, 0.65); |
|||
font-size: 14px; |
|||
font-variant: tabular-nums; |
|||
line-height: 1.5; |
|||
list-style: none; |
|||
font-feature-settings: 'tnum'; |
|||
position: relative; |
|||
} |
|||
.list-item { |
|||
min-height: 54px; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
padding: 12px 16px; |
|||
} |
|||
</style> |
After Width: | Height: | Size: 8.0 KiB |
After Width: | Height: | Size: 4.1 KiB |
@ -0,0 +1,156 @@ |
|||
<template> |
|||
<view> |
|||
<!-- <img style="margin-left: 75rpx; width: 600rpx; height: 800rpx" src="https://www.tall.wiki/staticrec/img/data.png" /> --> |
|||
<div style="margin-top: 100rpx; width: 750rpx; height: 850rpx"> |
|||
<swiper class="swiper" :circular="true" :indicator-dots="true" :autoplay="true" :interval="3000" :duration="3000"> |
|||
<swiper-item v-for="item in imgList" :key="item"> |
|||
<view class="swiper-item uni-bg-red"> |
|||
<img style="width: 750rpx; height: 800rpx" :src="item" /> |
|||
</view> |
|||
</swiper-item> |
|||
</swiper> |
|||
</div> |
|||
<!-- <u-button |
|||
v-if="user && user.wxInfo && !user.wxInfo.headImgUrl" |
|||
type="primary" |
|||
:custom-style="customStyle1" |
|||
size="default" |
|||
open-type="openAuth" |
|||
@click="openAuth" |
|||
> |
|||
授权信息 |
|||
</u-button> |
|||
<u-button v-else-if="projects.length" type="primary" :custom-style="customStyle1" size="default" @click="openProject"> |
|||
脑防委数据上报及质控分析体验 |
|||
</u-button> --> |
|||
<u-button :custom-style="customStyle" disabled shape="square" size="default" type="primary"> |
|||
<!-- open-type="getPhoneNumber" --> |
|||
<!-- @getphonenumber="getphonenumber" --> |
|||
<!-- 脑防委数据上报及质控分析体验 --> |
|||
问卷提交截止 |
|||
</u-button> |
|||
<u-modal |
|||
v-model="show" |
|||
:content="content" |
|||
show-cancel-button |
|||
cancel-text="不合并" |
|||
confirm-text="合并" |
|||
@confirm="bindNowPhone(0)" |
|||
@cancel="bindNowPhone(1)" |
|||
></u-modal> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapState, mapMutations, mapGetters } from 'vuex'; |
|||
import UserAuthMixin from '@/mixins/userAuth'; |
|||
|
|||
export default { |
|||
mixins: [UserAuthMixin], |
|||
data() { |
|||
return { |
|||
imgList: [ |
|||
'https://www.tall.wiki/staticrec/img/1.png', |
|||
'https://www.tall.wiki/staticrec/img/2.png', |
|||
'https://www.tall.wiki/staticrec/img/3.png', |
|||
'https://www.tall.wiki/staticrec/img/4.png', |
|||
'https://www.tall.wiki/staticrec/img/5.png', |
|||
], |
|||
customStyle: { |
|||
margin: '0 88rpx', |
|||
width: '574rpx', |
|||
}, |
|||
customStyle1: { |
|||
backgroundColor: 'rgba(41, 121, 255, 0.6)', |
|||
margin: '0 88rpx', |
|||
width: '574rpx', |
|||
}, |
|||
show: false, |
|||
content: '当前手机号已被注册,是否合并信息', |
|||
phone: '', |
|||
}; |
|||
}, |
|||
computed: { |
|||
...mapState('user', ['user']), |
|||
...mapState('project', ['projects']), |
|||
...mapGetters('user', ['userId']), |
|||
}, |
|||
created() { |
|||
this.getProjects(); |
|||
}, |
|||
methods: { |
|||
...mapMutations('user', ['setUser']), |
|||
...mapMutations('project', ['setProjects']), |
|||
// 获取项目列表 |
|||
getProjects(start = this.$moment().startOf('day').valueOf(), end = this.$moment().endOf('day').valueOf()) { |
|||
// const data = await this.$u.api.getProjects(start, end); |
|||
this.$t.$q.getProjects(start, end, (err, data) => { |
|||
if (err) { |
|||
console.error('err: ', err); |
|||
} else { |
|||
data.forEach(item => { |
|||
item.show = false; |
|||
}); |
|||
this.setProjects(data); |
|||
console.log('data: ', data); |
|||
console.log('project:', this.projects); |
|||
} |
|||
}); |
|||
}, |
|||
openProject() { |
|||
const { name, id, url } = this.projects[0]; |
|||
url && (uni.$t.domain = url); |
|||
this.$u.route('pages/project-webview/project-webview', { |
|||
u: this.userId, |
|||
p: id, |
|||
pname: name, |
|||
url: encodeURIComponent(url), |
|||
}); |
|||
}, |
|||
// 点击体验按钮,获取用户手机号权限并绑定 |
|||
// 如果拒绝授权,则跳转到手机号验证码绑定界面 |
|||
// 如果授权,查看返回的绑定信息,如果有id,则直接绑定成功,跳转到项目列表页 |
|||
// 如果没有id,则提示当前手机号已存在,是否合并信息 |
|||
async getphonenumber(e) { |
|||
console.log('e: ', e); |
|||
// // if (e.detail.errMsg === 'getPhoneNumber:fail user deny') { |
|||
// // this.$u.route('/pages/phone-bind/phone-bind'); |
|||
// // } else { |
|||
// if (e.detail.errMsg === 'getPhoneNumber:ok') { |
|||
// const params = { |
|||
// encryptedData: e.detail.encryptedData, |
|||
// iv: e.detail.iv, |
|||
// miniType: 'basicCar', |
|||
// }; |
|||
// const data = await this.$u.api.bindPhone(params); |
|||
// if (data && data.id) { |
|||
// // const newUser = { ...this.user, phone: data.phone }; |
|||
// // this.setUser(newUser); |
|||
// // setTimeout(() => uni.navigateBack({ delta: 2 }), 50); |
|||
// this.$u.route('pages/questionnaire-webview/questionnaire-webview', { u: this.userId }); |
|||
// } else { |
|||
// this.phone = data.phone; |
|||
// this.show = true; |
|||
// } |
|||
// } |
|||
}, |
|||
// 合并手机号接口 isMerge:0 合并, 1 不合并 |
|||
async bindNowPhone(num) { |
|||
const params = { |
|||
phone: this.phone, |
|||
isMerge: num, |
|||
}; |
|||
const data = await this.$u.api.bindNowPhone(params); |
|||
this.setUser(data); |
|||
this.show = false; |
|||
setTimeout(() => uni.navigateBack({ delta: 2 }), 500); |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped lang="scss"> |
|||
.swiper { |
|||
height: 800rpx; |
|||
} |
|||
</style> |
@ -0,0 +1,170 @@ |
|||
<template> |
|||
<!-- <view class="flex flex-col h-full bg-gray-50" @click="openAuth"> --> |
|||
<view class="flex flex-col h-screen bg-gray-50"> |
|||
<view class="relative" @touchmove="onMove"> |
|||
<!-- 日历 --> |
|||
<Calendar @selected-change="onDateChange" :show-back="true" ref="calendar" @handleFindPoint="handleFindPoint" /> |
|||
<!-- 上传 导入wbs --> |
|||
<Upload @success="onUploadSuccess" @error="onUploadError" /> |
|||
|
|||
<!-- #ifdef H5 --> |
|||
<!-- #endif --> |
|||
</view> |
|||
<!-- 联系客服 --> |
|||
<Service /> |
|||
<!-- 项目列表 --> |
|||
<Projects @getProjects="getProjects" class="flex-1 overflow-y-auto" /> |
|||
|
|||
<!-- 全局提示框 --> |
|||
<u-top-tips ref="uTips"></u-top-tips> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapState, mapMutations, mapGetters } from 'vuex'; |
|||
import UserAuthMixin from '@/mixins/userAuth'; |
|||
|
|||
let prevY = 0; |
|||
|
|||
export default { |
|||
mixins: [UserAuthMixin], |
|||
data() { |
|||
return { |
|||
calendar: null, |
|||
days: [], |
|||
}; |
|||
}, |
|||
|
|||
computed: { |
|||
...mapState('user', ['token', 'user']), |
|||
...mapGetters('user', ['userId']), |
|||
}, |
|||
|
|||
watch: { |
|||
// token(value) { |
|||
// if (!value) return; |
|||
// this.getProjects(); |
|||
// this.handleFindPoint(); |
|||
// }, |
|||
user(value) { |
|||
if (!value) return; |
|||
const that = this; |
|||
setTimeout(function () { |
|||
that.getProjects(); |
|||
that.handleFindPoint(); |
|||
}, 100); |
|||
}, |
|||
}, |
|||
|
|||
async created() { |
|||
if (!this.token) return; |
|||
this.getProjects(); |
|||
this.handleFindPoint(); |
|||
}, |
|||
|
|||
onReady() { |
|||
this.calendar = this.$refs.calendar; |
|||
}, |
|||
|
|||
methods: { |
|||
...mapMutations('project', ['setProjects', 'setDotList']), |
|||
|
|||
// 获取项目列表 |
|||
getProjects(start = this.$moment().startOf('day').valueOf(), end = this.$moment().endOf('day').valueOf()) { |
|||
// const res = await this.$u.api.getQueryButton({}); |
|||
// const data = await this.$u.api.getProjects(start, end); |
|||
this.$t.$q.getProjects(start, end, (err, data) => { |
|||
if (err) { |
|||
console.error('err: ', err); |
|||
} else { |
|||
data.forEach(item => { |
|||
item.show = false; |
|||
}); |
|||
this.setProjects(data); |
|||
if (data && data[0]) { |
|||
// this.openFirstProject(data[0]); |
|||
} |
|||
// else if (this.user.phone) { |
|||
// this.$u.route('pages/questionnaire-webview/questionnaire-webview', { u: this.userId, url: res.url }); |
|||
// } |
|||
} |
|||
}); |
|||
}, |
|||
|
|||
/** |
|||
* 查询小红点 |
|||
* @param { string } endTime 结束时间 |
|||
* @param { string } startTime 开始时间 |
|||
*/ |
|||
async handleFindPoint(start, end) { |
|||
try { |
|||
const startTime = start || this.$moment().startOf('month').valueOf(); |
|||
const endTime = end || this.$moment().endOf('month').valueOf(); |
|||
const data = await this.$u.api.findRedPoint(startTime, endTime); |
|||
this.setDotList(data); |
|||
} catch (error) { |
|||
console.log('error: ', error); |
|||
} |
|||
}, |
|||
|
|||
// 点击了某个日期 |
|||
onDateChange(event) { |
|||
const day = this.$moment(event.fullDate); |
|||
const start = day.startOf('date').valueOf(); |
|||
const end = day.endOf('date').valueOf(); |
|||
this.getProjects(start, end); |
|||
}, |
|||
|
|||
// 监听触摸滑动 切换日历的模式 月/周 |
|||
onMove(event) { |
|||
const y = event.changedTouches[0].pageY; |
|||
if (y - prevY > 0) { |
|||
// 向下滑动 如果是周视图weekMode=true 就 变成 月视图weekMode=false |
|||
this.calendar.weekMode && (this.calendar.weekMode = false); |
|||
} else if (y - prevY < 0) { |
|||
// 向上滑动 如果是月视图weekMode=false 就变成 周视图weekMode=true |
|||
!this.calendar.weekMode && (this.calendar.weekMode = true); |
|||
} |
|||
prevY = y; |
|||
this.calendar.initDate(); |
|||
}, |
|||
|
|||
// 导入成功 |
|||
onUploadSuccess() { |
|||
this.$refs.uTips.show({ |
|||
title: '导入成功,即将打开新项目', |
|||
type: 'success', |
|||
duration: '3000', |
|||
}); |
|||
}, |
|||
|
|||
// 导入失败 |
|||
onUploadError(error) { |
|||
this.$refs.uTips.show({ |
|||
title: error || '导入失败', |
|||
type: 'error', |
|||
duration: '6000', |
|||
}); |
|||
}, |
|||
|
|||
// 打开第一个项目 |
|||
openFirstProject(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), |
|||
}); |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
page { |
|||
height: 100%; |
|||
overflow: hidden; |
|||
} |
|||
</style> |
@ -0,0 +1,36 @@ |
|||
<template> |
|||
<div class="inner">inner</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
components: {}, |
|||
data: () => ({}), |
|||
computed: {}, |
|||
methods: {}, |
|||
watch: {}, |
|||
|
|||
// 页面周期函数--监听页面加载 |
|||
onLoad() {}, |
|||
// 页面周期函数--监听页面初次渲染完成 |
|||
onReady() {}, |
|||
// 页面周期函数--监听页面显示(not-nvue) |
|||
onShow() {}, |
|||
// 页面周期函数--监听页面隐藏 |
|||
onHide() {}, |
|||
// 页面周期函数--监听页面卸载 |
|||
onUnload() {}, |
|||
// 页面处理函数--监听用户下拉动作 |
|||
onPullDownRefresh() { |
|||
uni.stopPullDownRefresh(); |
|||
}, |
|||
// 页面处理函数--监听用户上拉触底 |
|||
onReachBottom() {}, |
|||
// 页面处理函数--监听页面滚动(not-nvue) |
|||
/* onPageScroll(event) {}, */ |
|||
// 页面处理函数--用户点击右上角分享 |
|||
/* onShareAppMessage(options) {}, */ |
|||
}; |
|||
</script> |
|||
|
|||
<style></style> |
@ -0,0 +1,181 @@ |
|||
<template> |
|||
<div class="patient-line"> |
|||
<template v-if="showLine"> |
|||
<div v-for="(item, index) in dataList" :key="index" class="flex flex-row item-box mb-2"> |
|||
<div class="flex flex-col items-center mr-1" style="width: 36px"> |
|||
<img src="./png/播放.png" alt="" style="width: 36px; height: 36px" /> |
|||
<div class="mt-1 flex-1" style="border-right: 2px solid rgb(209, 213, 219)"></div> |
|||
<div v-if="index === innerList.length - 1" class="end-ric mt-2"></div> |
|||
</div> |
|||
<div class="flex-1 flex-col"> |
|||
<div class="w-full time-box flex items-center" style="height: 34px; padding-left: 12px"> |
|||
<!-- {{ $moment(time).format('MM月DD日') }} --> |
|||
{{ item.time }} |
|||
</div> |
|||
<div class="flex mt-2" style="height: 50px" @click="jump(item.code, item.path)"> |
|||
<div class="name-box flex items-center time-box" style="padding-left: 16px; position: relative"> |
|||
{{ item.name }} |
|||
<u-icon name="arrow-right" size="28" color="#303133" style="position: absolute; right: 16px" /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
import { mapMutations } from 'vuex'; |
|||
export default { |
|||
components: {}, |
|||
data: () => ({ |
|||
showLine: false, |
|||
innerList: [ |
|||
// 神内任务列表 |
|||
{ |
|||
name: '患者信息', |
|||
time: '11月24日 16:56', |
|||
code: '', |
|||
path: '/pages/inner/inner', |
|||
}, |
|||
{ |
|||
name: '基本信息', |
|||
time: '11月24日 16:56', |
|||
code: '', |
|||
path: '/pages/inner/inner', |
|||
}, |
|||
{ |
|||
name: '入院评估', |
|||
time: '11月24日 16:56', |
|||
code: 'RYPG', |
|||
path: '/pages/inner/inner', |
|||
}, |
|||
{ |
|||
name: '主要治疗操作', |
|||
time: '11月24日 16:56', |
|||
code: 'SSXG', |
|||
path: '/pages/inner/inner', |
|||
}, |
|||
{ |
|||
name: '出院记录', |
|||
time: '11月24日 16:56', |
|||
code: 'CYJL', |
|||
path: '/pages/inner/inner', |
|||
}, |
|||
], |
|||
outSideList: [ |
|||
// 神外任务列表 |
|||
{ |
|||
name: '患者信息', |
|||
time: '11月24日 16:56', |
|||
code: '', |
|||
path: '/pages/inner/inner', |
|||
}, |
|||
{ |
|||
name: '基本信息', |
|||
time: '11月24日 16:56', |
|||
code: '', |
|||
path: '/pages/inner/inner', |
|||
}, |
|||
{ |
|||
name: '入院评估', |
|||
time: '11月24日 16:56', |
|||
code: 'RYPG', |
|||
path: '/pages/inner/inner', |
|||
}, |
|||
{ |
|||
name: '主要检查', |
|||
time: '11月24日 16:56', |
|||
code: 'ZYJC', |
|||
path: '/pages/inner/inner', |
|||
}, |
|||
{ |
|||
name: '手术相关操作', |
|||
time: '11月24日 16:56', |
|||
code: 'SSXG', |
|||
path: '/pages/inner/inner', |
|||
}, |
|||
{ |
|||
name: '出院记录', |
|||
time: '11月24日 16:56', |
|||
code: 'CYJL', |
|||
path: '/pages/inner/inner', |
|||
}, |
|||
], |
|||
time: 0, |
|||
caseType: 0, |
|||
}), |
|||
computed: { |
|||
dataList() { |
|||
return this.caseType === 0 ? this.innerList : this.outSideList; |
|||
}, |
|||
}, |
|||
onLoad(options) { |
|||
console.log('options: ', options); |
|||
this.caseType = options.caseType - 0; |
|||
this.showLine = true; |
|||
}, |
|||
methods: { |
|||
...mapMutations('carbasics', ['setInputCode']), |
|||
jump(code, path) { |
|||
// console.log('code, path: ', code, path); |
|||
this.setInputCode(code ? code : 'RYPG'); |
|||
uni.navigateTo({ url: path }); |
|||
}, |
|||
}, |
|||
watch: {}, |
|||
|
|||
// 页面周期函数--监听页面初次渲染完成 |
|||
onReady() {}, |
|||
// 页面周期函数--监听页面显示(not-nvue) |
|||
onShow() {}, |
|||
// 页面周期函数--监听页面隐藏 |
|||
onHide() {}, |
|||
// 页面周期函数--监听页面卸载 |
|||
onUnload() {}, |
|||
// 页面处理函数--监听用户下拉动作 |
|||
onPullDownRefresh() { |
|||
uni.stopPullDownRefresh(); |
|||
}, |
|||
// 页面处理函数--监听用户上拉触底 |
|||
onReachBottom() {}, |
|||
// 页面处理函数--监听页面滚动(not-nvue) |
|||
/* onPageScroll(event) {}, */ |
|||
// 页面处理函数--用户点击右上角分享 |
|||
/* onShareAppMessage(options) {}, */ |
|||
}; |
|||
</script> |
|||
|
|||
<style> |
|||
.patient-line { |
|||
margin-top: 16px; |
|||
} |
|||
.end-ric { |
|||
height: 6px; |
|||
width: 6px; |
|||
border: 2px solid rgb(209, 213, 219); |
|||
border-radius: 50%; |
|||
} |
|||
.name-box { |
|||
background-color: #fff; |
|||
height: 50px; |
|||
width: 100%; |
|||
border-radius: 10px; |
|||
box-shadow: 0px 5px 15px 5px rgba(0, 0, 0, 0.1); |
|||
} |
|||
.time-box { |
|||
font-size: 14px; |
|||
font-weight: 500; |
|||
color: #303133; |
|||
} |
|||
.red { |
|||
border: 1px solid red; |
|||
} |
|||
.green { |
|||
border: 1px solid green; |
|||
} |
|||
.item-box { |
|||
/* height: 110px; */ |
|||
width: 100%; |
|||
padding: 0 16px; |
|||
} |
|||
</style> |
After Width: | Height: | Size: 9.2 KiB |
@ -0,0 +1,192 @@ |
|||
<template> |
|||
<view class="wrap" @click="openAuth"> |
|||
<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> |
|||
import UserAuthMixin from '@/mixins/userAuth'; |
|||
|
|||
export default { |
|||
mixins: [UserAuthMixin], |
|||
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(-2), 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,41 @@ |
|||
<template> |
|||
<web-view :src="src" /> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { src: '' }; |
|||
}, |
|||
|
|||
onLoad(options) { |
|||
const obj = { title: '暴风眼Typhoneye', path: '/pages/index/index' }; |
|||
uni.showShareMenu(obj); |
|||
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}/#/?u=${u}&p=${p}&url=${url}&pname=${pname}`; |
|||
} |
|||
}, |
|||
|
|||
methods: { |
|||
onShareAppMessage() { |
|||
return { title: '暴风眼Typhoneye', path: '/pages/index/index' }; |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
@ -0,0 +1,31 @@ |
|||
<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 { u, url } = options; |
|||
if (!u) { |
|||
this.$t.ui.showToast('缺少用户信息, 请登录'); |
|||
return; |
|||
} |
|||
if (!url) { |
|||
this.$t.ui.showToast('缺少跳转信息, 请返回重试'); |
|||
return; |
|||
} |
|||
// const baseUrl = process.env.VUE_APP_QUESTION_PATH; |
|||
// this.src = `${baseUrl}/hospital?userId=${u}`; |
|||
this.src = `${url}?userId=${u}`; |
|||
} |
|||
}, |
|||
}; |
|||
</script> |
@ -0,0 +1,319 @@ |
|||
<template> |
|||
<view :style="{ height: height }" class="flex flex-col overflow-hidden u-font-14"> |
|||
<view class="container flex flex-col flex-1 mx-auto overflow-hidden bg-gray-100"> |
|||
<!-- 角色栏 --> |
|||
<Roles /> |
|||
<!-- 日常任务面板 --> |
|||
<Globals v-if="globals.length" /> |
|||
<!-- 任务详情 --> |
|||
<div v-if="globalData && permanents.length" class="flex flex-1"> |
|||
<PatientList v-if="showPage === 'function'" class="flex flex-1" /> |
|||
</div> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'; |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
height: '', |
|||
show: false, |
|||
count: 0, |
|||
chooseItem: false, |
|||
name: '', |
|||
url: '', |
|||
showStatus: 0, |
|||
showPage: '', |
|||
}; |
|||
}, |
|||
|
|||
computed: { |
|||
...mapState('task', ['permanents']), |
|||
...mapState('user', ['user', 'token']), |
|||
...mapState('role', ['visibleRoles', 'roleId']), |
|||
...mapState('project', ['project']), |
|||
...mapGetters('task', ['globals']), |
|||
...mapGetters('project', ['projectId']), |
|||
...mapState('carbasics', ['globalData']), |
|||
}, |
|||
|
|||
async onLoad(options) { |
|||
this.init(options); |
|||
}, |
|||
|
|||
watch: { |
|||
/** |
|||
* 当角色发生变化时 |
|||
* 重新查询永久日常任务和普通日常任务 |
|||
* 注意: 切换角色后 重新设置了时间基准点 时间基准点一定会变 |
|||
* 所以监听时间基准点获取 可变日常任务即可 这里不用获取 避免重复获取 |
|||
*/ |
|||
roleId(val) { |
|||
if (val) { |
|||
const params = { roleId: val, projectId: this.projectId }; |
|||
this.getPermanent(params); |
|||
} |
|||
}, |
|||
// 收到跳转新项目的消息 |
|||
newProjectInfo(val) { |
|||
if (val && val.projectId && val.url) { |
|||
this.$u.route('/', { u: this.userId, p: val.projectId, url: val.url }); |
|||
this.clearTasksData(); |
|||
this.setRoleId(''); |
|||
const options = this.$route.query; |
|||
this.init(options); |
|||
this.getByProject(val.projectId); |
|||
} |
|||
}, |
|||
|
|||
globalData(val) { |
|||
var strList = val.url.split('/'); |
|||
this.showPage = strList[strList.length - 1]; |
|||
}, |
|||
}, |
|||
|
|||
mounted() { |
|||
const system = uni.getSystemInfoSync(); |
|||
this.height = system.windowHeight + 'px'; |
|||
}, |
|||
|
|||
onUnload() { |
|||
// this.clearTasksData(); |
|||
this.setRoleId(''); |
|||
}, |
|||
|
|||
methods: { |
|||
...mapActions('user', ['getToken']), |
|||
...mapActions('task', ['getPermanent']), |
|||
...mapMutations('user', ['setToken']), |
|||
...mapMutations('project', ['setProject', 'setProjectName', 'setOrganData']), |
|||
...mapMutations('role', ['setInvisibleRoles', 'setVisibleRoles', 'setRoleId']), |
|||
|
|||
// 初始化 定期任务 |
|||
async initPlanTasks() { |
|||
this.setPrevPlaceholderTasks(); // 向上加载空数据 |
|||
this.setNextPlaceholderTasks(); // 向下加载空数据 |
|||
// // this.$nextTick(() => this.$refs.timeLine.setScrollPosition()); // 滚动到对应位置 |
|||
await this.getInitTasks(); // 获取初始数据 |
|||
|
|||
// 滚动到对应位置 |
|||
// let timer = null; |
|||
// timer = setInterval(() => { |
|||
// if (this.showScrollTo) { |
|||
// clearInterval(timer); |
|||
// this.$nextTick(() => this.$refs.timeLine.setScrollPosition()); |
|||
// } |
|||
// }, 1000); |
|||
}, |
|||
|
|||
// 切换了 颗粒度 || 角色时候 获取初始定期任务 |
|||
getInitTasks() { |
|||
// 预加载 上下的定期任务 |
|||
function preloadFn(that) { |
|||
const detailId = that.tasks.findIndex(task => task.detailId); |
|||
const arr = []; |
|||
// setTimeout(() => { |
|||
// that.tasks.forEach(task => { |
|||
// if (task.detailId) { |
|||
// arr.push(task); |
|||
// } |
|||
// }); |
|||
// that.$nextTick(() => that.$refs.timeLine.setScrollPosition()); |
|||
// }, 100); |
|||
if (detailId !== -1) { |
|||
// 只要有1个真实的任务 就预加载上下周期的任务 |
|||
const { pageCount } = that.$t.task; |
|||
that.$nextTick(() => { |
|||
// 向上拿数据 |
|||
const { tasks, timeGranularity } = that; |
|||
that.getTasks({ timeNode: +tasks[detailId].planStart, queryType: 0, queryNum: pageCount }); |
|||
// 向下拿数据 |
|||
const nextQueryTime = +that.$t.time.add(+arr[arr.length - 1].planStart, 1, timeGranularity); |
|||
that.getTasks({ timeNode: nextQueryTime, queryType: 1, queryNum: pageCount }); |
|||
}); |
|||
} else { |
|||
// 没有任务 上下显示时间刻度 |
|||
// 向上加载 |
|||
// that.setPrevPlaceholderTasks(); |
|||
// // 向下加载 |
|||
// that.setNextPlaceholderTasks(); |
|||
} |
|||
} |
|||
// 根据时间基准点和角色查找定期任务 |
|||
this.getTasks({ queryType: 0 }); // 向上获取定期任务数据 |
|||
|
|||
// 根据项目id获取角色列表 |
|||
this.getTasks({ queryType: 1 }, preloadFn); // 向下获取定期任务数据 |
|||
}, |
|||
|
|||
/** |
|||
* 根据时间基准点和角色查找定期任务 |
|||
* @param {object} query |
|||
* @param {string} query.roleId 角色id |
|||
* @param {string} query.timeNode 时间基准点 默认当前 |
|||
* @param {string} query.timeUnit 时间颗粒度 默认天 |
|||
* @param {string} query.queryNum 查找颗粒度数量 默认3个 |
|||
* @param {number} query.queryType 0向上查找 1向下查找(默认) 下查包含自己,上查不包含 |
|||
*/ |
|||
getTasks(query, fn) { |
|||
this.setShowSkeleton(true); |
|||
const params = this.generateGetTaskParam(query); |
|||
|
|||
this.$t.$q.getRegularTask(params, (err, data) => { |
|||
this.setShowSkeleton(false); |
|||
if (err) { |
|||
// TODO: 提示错误 |
|||
console.error('err: ', err); |
|||
} else { |
|||
this.setShowScrollTo(true); |
|||
// 有数据用数据替换刻度 |
|||
// 没有数据 继续加载刻度 |
|||
if (data && data.length) { |
|||
this.replacePrevData(data, params.queryType); |
|||
params.queryType === 0 ? this.setTopEnd(false) : this.setBottomEnd(false); |
|||
} else { |
|||
// TODO: 0 -> 向上 1 -> 向下 |
|||
params.queryType === 0 ? this.setPrevPlaceholderTasks() : this.setNextPlaceholderTasks(); |
|||
} |
|||
if (this.tasks.length && fn) { |
|||
fn(this); |
|||
} |
|||
} |
|||
}); |
|||
}, |
|||
|
|||
/** |
|||
* 生成getTasks所用的参数 |
|||
* @param {object} query getTasks传递的参数 |
|||
*/ |
|||
generateGetTaskParam(query) { |
|||
const { roleId, timeNode, timeUnit, projectId } = this; |
|||
return { |
|||
roleId, |
|||
timeNode: query.timeNode || timeNode, |
|||
timeUnit: query.timeUnit || timeUnit, |
|||
queryNum: query.queryNum || 3, |
|||
queryType: query.queryType, |
|||
projectId, |
|||
}; |
|||
}, |
|||
|
|||
/** |
|||
* 初始化 |
|||
* @param {object | null} options |
|||
*/ |
|||
init(options) { |
|||
// 参数里有项目名称 就设置标题里的项目名称 |
|||
options && options.pname && this.setProjectName(options.pname); |
|||
|
|||
if (!options || !options.p) { |
|||
this.$t.ui.showToast('缺少项目信息参数'); // 没有项目id参数 |
|||
} else { |
|||
uni.setNavigationBarTitle({ title: options.pname }); |
|||
if (options.p !== this.$t.storage.getStorageSync('projectId')) { |
|||
this.$t.storage.setStorageSync('roleId', ''); |
|||
} |
|||
// TODO |
|||
this.getProjectById({ projectId: options.p, num: 0 }); // 根据项目id获取项目信息 |
|||
this.getByProject(options.p); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 通过项目id获取项目信息 |
|||
* @param {object} params 提交的参数 |
|||
*/ |
|||
async getProjectById(params) { |
|||
try { |
|||
const data = await this.$u.api.findProjectById(params); |
|||
this.setProject(data); |
|||
// 根据项目id获取角色列表 |
|||
this.getRoles(params); |
|||
} catch (error) { |
|||
console.log('error: ', error || '获取项目信息失败'); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 通过项目id获取角色信息 |
|||
* @param {string} projectId |
|||
* @param {object} params 提交的参数 |
|||
*/ |
|||
getRoles(params) { |
|||
this.$t.$q.findShowRole(params, (err, data) => { |
|||
if (err) { |
|||
console.error('err: ', err || '获取角色信息失败'); |
|||
} else { |
|||
this.setInvisibleRoles(data ? data.invisibleList : []); |
|||
this.setVisibleRoles(data ? data.visibleList : []); |
|||
this.setInitialRoleId(data ? data.visibleList : []); |
|||
} |
|||
}); |
|||
}, |
|||
|
|||
// 设置 初始显示角色信息 |
|||
async setInitialRoleId(visibleList) { |
|||
if (!visibleList || !visibleList.length) return; |
|||
const index = visibleList.findIndex(item => +item.mine === 1); |
|||
const currentRole = index > 0 ? visibleList[index] : visibleList[0]; |
|||
const storageRoleId = this.$t.storage.getStorageSync('roleId'); |
|||
const params = { param: { projectId: this.projectId } }; |
|||
const data = await uni.$u.api.queryLastRoleChoose(params); |
|||
if (data && data.roleId) { |
|||
this.setRoleId(data.roleId); |
|||
} else { |
|||
const currentRoleId = storageRoleId ? storageRoleId : currentRole ? currentRole.id : ''; |
|||
const saveParams = { param: { roleId: currentRoleId, projectId: this.projectId } }; |
|||
await uni.$u.api.saveRoleRecord(saveParams); |
|||
this.setRoleId(currentRoleId); |
|||
} |
|||
// 清空storage |
|||
this.$t.storage.setStorageSync('roleId', ''); |
|||
}, |
|||
|
|||
// 清除已有的任务数据 |
|||
clearTasksData() { |
|||
// 清空日常任务的数据 |
|||
this.setPermanents([]); |
|||
this.setDailyTasks([]); |
|||
// 清空定期任务数据 |
|||
this.clearTasks(); |
|||
// 到顶的标志复位 |
|||
// 到底的标志复位 |
|||
this.clearEndFlag(); |
|||
}, |
|||
|
|||
// 根据当前打开的项目id 查询当前项目的配置信息 |
|||
async getByProject(projectId) { |
|||
try { |
|||
const param = { projectId }; |
|||
const data = await this.$u.api.getByProject(param); |
|||
if (data && data.organizationType === 3) { |
|||
this.showEXP = true; |
|||
this.showGuide = true; |
|||
this.setOrganData(data); |
|||
} else if (data && data.organizationType === 0) { |
|||
this.setOrganData(data); |
|||
} else { |
|||
this.showEXP = false; |
|||
this.showGuide = false; |
|||
} |
|||
} catch (error) { |
|||
console.log('error: ', error); |
|||
} |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.container { |
|||
width: 100%; |
|||
} |
|||
.border-b { |
|||
border-bottom: 1px solid #e4e7ed; |
|||
} |
|||
</style> |
@ -0,0 +1,29 @@ |
|||
/* eslint-disable no-console */ |
|||
|
|||
import { register } from 'register-service-worker'; |
|||
|
|||
if (process.env.NODE_ENV === 'production') { |
|||
register(`${process.env.BASE_URL}service-worker.js`, { |
|||
ready() { |
|||
console.log('App is being served from cache by a service worker.\n' + 'For more details, visit https://goo.gl/AFskqB'); |
|||
}, |
|||
registered() { |
|||
console.log('Service worker has been registered.'); |
|||
}, |
|||
cached() { |
|||
console.log('Content has been cached for offline use.'); |
|||
}, |
|||
updatefound() { |
|||
console.log('New content is downloading.'); |
|||
}, |
|||
updated() { |
|||
console.log('New content is available; please refresh.'); |
|||
}, |
|||
offline() { |
|||
console.log('No internet connection found. App is running in offline mode.'); |
|||
}, |
|||
error(error) { |
|||
console.error('Error during service worker registration:', error); |
|||
}, |
|||
}); |
|||
} |
@ -0,0 +1,3 @@ |
|||
const actions = {}; |
|||
|
|||
export default actions; |
@ -0,0 +1,3 @@ |
|||
const getters = {}; |
|||
|
|||
export default getters; |
@ -0,0 +1,12 @@ |
|||
import state from './state'; |
|||
import getters from './getters'; |
|||
import mutations from './mutations'; |
|||
import actions from './actions'; |
|||
|
|||
export default { |
|||
namespaced: true, |
|||
state, |
|||
getters, |
|||
mutations, |
|||
actions, |
|||
}; |
@ -0,0 +1,35 @@ |
|||
const mutations = { |
|||
/** |
|||
* 存储当前正在进行的患者的急救id |
|||
* @param { object } state |
|||
* @param { string } id |
|||
*/ |
|||
setFirstAidId(state, id) { |
|||
state.firstAidId = id; |
|||
}, |
|||
/** |
|||
* 存储当前插件的param参数,包括url和其他具体参数 |
|||
* @param { object } state |
|||
* @param { object } data |
|||
*/ |
|||
setGlobalData(state, data) { |
|||
state.globalData = { ...data }; |
|||
}, |
|||
/** |
|||
* 监听refreshList变化,重新请求病例列表数据 |
|||
* @param { object } state |
|||
*/ |
|||
setRefreshList(state) { |
|||
state.refreshList = state.refreshList + 1; |
|||
}, |
|||
/** |
|||
* 信息录入界面默认为 RYPG(入院评估),当进入患者目录选择时,切换此code |
|||
* @param { object } state |
|||
* @param { string } data |
|||
*/ |
|||
setInputCode(state, data) { |
|||
state.InputCode = data; |
|||
}, |
|||
}; |
|||
|
|||
export default mutations; |