Browse Source

feat: 时间轴展示

feat
song 4 years ago
parent
commit
8b1b380a6b
  1. 16
      CHANGELOG.md
  2. 18
      common/styles/tailwind.scss
  3. 98
      components/Plugin/Plugin.vue
  4. 1
      components/Roles/Roles.vue
  5. 8
      components/TimeLine/TimeLine.vue
  6. 23
      components/TimeLine/component/TimeBox.vue
  7. 9
      components/TimeLine/component/TimeStatus.vue
  8. 2
      config/task.js
  9. 159
      hooks/project/useGetTasks.js
  10. 449
      hooks/project/useInit - 副本.js
  11. 16
      hooks/project/useInit.js
  12. 3
      main.js
  13. 434
      pages/project/project A.vue
  14. 18
      pages/project/project.vue
  15. 36
      utils/cacheAndRequest.js
  16. 7
      utils/task.js
  17. 47
      utils/time.js

16
CHANGELOG.md

@ -3,24 +3,25 @@
### 🌟 新功能 ### 🌟 新功能
范围|描述|commitId 范围|描述|commitId
--|--|-- --|--|--
- | 更新代码 | [392c8cc](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/392c8cc) - | app.vue | [970cf9a](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/970cf9a)
- | 日历页首页 | [561c8e6](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/561c8e6) - | first commit | [8dc26de](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/8dc26de)
- | vue3 | [12ed2ad](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/12ed2ad)
- | 使用uview完成api请求 | [1b3efd8](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/1b3efd8)
- | 日历页添加 | [1b46a91](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/1b46a91) - | 日历页添加 | [1b46a91](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/1b46a91)
- | 日历页首页 | [561c8e6](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/561c8e6)
- | 时间轴接口 | [a95d005](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/a95d005) - | 时间轴接口 | [a95d005](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/a95d005)
- | 时间轴页面 | [e926b75](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/e926b75) - | 时间轴页面 | [e926b75](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/e926b75)
- | 使用uview完成api请求 | [1b3efd8](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/1b3efd8) - | 更新代码 | [392c8cc](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/392c8cc)
- | 添加 timeline | [72dad2b](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/72dad2b) - | 添加 timeline | [72dad2b](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/72dad2b)
- | 项目操作面板 | [3beb05e](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/3beb05e)
- | 项目列表 | [a52e6d5](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/a52e6d5) - | 项目列表 | [a52e6d5](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/a52e6d5)
- | app.vue | [970cf9a](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/970cf9a) - | 项目操作面板 | [3beb05e](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/3beb05e)
- | first commit | [8dc26de](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/8dc26de)
- | vue3 | [12ed2ad](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/12ed2ad)
### 🎨 代码样式 ### 🎨 代码样式
范围|描述|commitId 范围|描述|commitId
--|--|-- --|--|--
- | calender格式及细节调整 | [db9602b](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/db9602b) - | calender格式及细节调整 | [db9602b](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/db9602b)
- | 细节调整 | [bdd5f87](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/bdd5f87)
### 🐛 Bug 修复 ### 🐛 Bug 修复
@ -32,6 +33,7 @@
### 🔨 代码重构 ### 🔨 代码重构
范围|描述|commitId 范围|描述|commitId
--|--|-- --|--|--
- | project init 重构 | [2457a87](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/2457a87)
- | 重构project init 部分 | [c7bf2df](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/c7bf2df) - | 重构project init 部分 | [c7bf2df](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/c7bf2df)

18
common/styles/tailwind.scss

@ -2207,6 +2207,15 @@
box-sizing: content-box; box-sizing: content-box;
} }
.border-l-2 {
border-left-width: 2px;
}
.border-gray-300 {
--tw-border-opacity: 1;
border-color: rgba(209, 213, 219, var(--tw-border-opacity));
}
.block { .block {
display: block; display: block;
} }
@ -4310,6 +4319,11 @@
.opacity-100 { .opacity-100 {
opacity: 1; opacity: 1;
} }
.h-3 {
height: 0.75rem;
}
.h-full { .h-full {
height: 100%; height: 100%;
} }
@ -4317,6 +4331,10 @@
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgba(249, 250, 251, var(--tw-bg-opacity)); background-color: rgba(249, 250, 251, var(--tw-bg-opacity));
} }
.bg-gray-100 {
--tw-bg-opacity: 1;
background-color: rgba(243, 244, 246, var(--tw-bg-opacity));
}
.w-12 { .w-12 {
width: 3rem; width: 3rem;
} }

98
components/Plugin/Plugin.vue

@ -1,6 +1,7 @@
<template> <template>
<view class="u-font-14" style="height: 100%"> <view class="u-font-14" style="height: 100%">
<view v-if="data.pluginContent" @click="setStorage"> 插件面板
<!-- <view v-if="data.pluginContent" @click="setStorage">
<view <view
:data-did="task.detailId" :data-did="task.detailId"
:data-param="param" :data-param="param"
@ -17,9 +18,9 @@
style="height: 100%" style="height: 100%"
v-html="data.pluginContent" v-html="data.pluginContent"
></view> ></view>
</view> </view> -->
<view v-else @click="setStorage"> <!-- <view v-else @click="setStorage"> -->
<!-- <plugin-default /> --> <!-- <plugin-default /> -->
<!-- <component :task="task" :is="pluginComponent"></component> --> <!-- <component :task="task" :is="pluginComponent"></component> -->
<!-- <p-task-title :task="task" v-if="pluginId === '1'" /> <!-- <p-task-title :task="task" v-if="pluginId === '1'" />
@ -37,7 +38,7 @@
<p-manage-task :task="task" v-if="pluginId === '12'" /> <p-manage-task :task="task" v-if="pluginId === '12'" />
<p-wbs-import :task="task" v-if="pluginId === '13' || pluginId === '14'" /> <p-wbs-import :task="task" v-if="pluginId === '13' || pluginId === '14'" />
<p-deliver-check :task="task" v-if="pluginId === '15'" /> --> <p-deliver-check :task="task" v-if="pluginId === '15'" /> -->
</view> <!-- </view> -->
</view> </view>
</template> </template>
@ -53,14 +54,14 @@ const props = defineProps({
param: { type: String, default: '' }, param: { type: String, default: '' },
}); });
const data = reactive({ pluginContent: null }); // const data = reactive({ pluginContent: null });
const store = useStore(); const store = useStore();
const roleId = computed(() => store.state.role.roleId); const roleId = computed(() => store.state.role.roleId);
const token = computed(() => store.state.user.token); // const token = computed(() => store.state.user.token);
const userId = computed(() => store.getters['user/userId']); // const userId = computed(() => store.getters['user/userId']);
const projectId = computed(() => store.getters['project/projectId']); const projectId = computed(() => store.getters['project/projectId']);
const isMine = computed(() => store.getters['role/isMine']); // const isMine = computed(() => store.getters['role/isMine']);
// //
// pluginComponent() { // pluginComponent() {
@ -70,48 +71,48 @@ const isMine = computed(() => store.getters['role/isMine']);
// }, // },
// script dom // script dom
function handleDom(js) { // function handleDom(js) {
const domList = Array.from(document.getElementsByTagName('script')); // const domList = Array.from(document.getElementsByTagName('script'));
const index = domList.findIndex(item => item.id === `p${props.pluginTaskId}`); // const index = domList.findIndex(item => item.id === `p${props.pluginTaskId}`);
if (index >= 0) { // if (index >= 0) {
document.body.removeChild(document.getElementById(`p${props.pluginTaskId}`)); // document.body.removeChild(document.getElementById(`p${props.pluginTaskId}`));
} // }
const scriptDom = document.createElement('script'); // const scriptDom = document.createElement('script');
scriptDom.id = `p${props.pluginTaskId}`; // scriptDom.id = `p${props.pluginTaskId}`;
scriptDom.setAttribute('data-type', 'plugin'); // scriptDom.setAttribute('data-type', 'plugin');
scriptDom.innerHTML = js; // scriptDom.innerHTML = js;
nextTick(() => { // nextTick(() => {
document.body.append(scriptDom); // document.body.append(scriptDom);
}); // });
} // }
// //
async function getPlugin() { // async function getPlugin() {
const params = { pluginId: props.pluginId, styleType: props.styleType }; // const params = { pluginId: props.pluginId, styleType: props.styleType };
uni.$catchReq.getOtherPlugin(params, (err, data) => { // uni.$catchReq.getOtherPlugin(params, (err, data) => {
if (err) { // if (err) {
console.error('err: ', err); // console.error('err: ', err);
} else { // } else {
if (!data || !data.id) return; // if (!data || !data.id) return;
const reg = /data-root=["|']?(\w+)["|']?/gi; // const reg = /data-root=["|']?(\w+)["|']?/gi;
let uuid = ''; // let uuid = '';
// FIXME: js, html // // FIXME: js, html
if (data.html) { // if (data.html) {
// data-root=xxx xxx pluginTaskId // // data-root=xxx xxx pluginTaskId
if (reg.test(data.html)) { // if (reg.test(data.html)) {
uuid = RegExp.$1; // uuid = RegExp.$1;
const str = data.html.replace(new RegExp(uuid, 'g'), `p${props.pluginTaskId}`); // const str = data.html.replace(new RegExp(uuid, 'g'), `p${props.pluginTaskId}`);
data.pluginContent = str; // data.pluginContent = str;
} else { // } else {
data.pluginContent = data.html; // data.pluginContent = data.html;
} // }
const str = data.js.replace(new RegExp(uuid, 'g'), `p${props.pluginTaskId}`); // const str = data.js.replace(new RegExp(uuid, 'g'), `p${props.pluginTaskId}`);
handleDom(str); // handleDom(str);
} // }
} // }
}); // });
// if (data.js) { // if (data.js) {
// if (reg.test(data.js)) { // if (reg.test(data.js)) {
@ -122,13 +123,14 @@ async function getPlugin() {
// this.handleDom(data.js); // this.handleDom(data.js);
// } // }
// } // }
} // }
console.log('props.pluginId: ', props.pluginId);
if (props.pluginId === '5') { if (props.pluginId === '5') {
// id // id
store.dispatch('role/getAllMembers', { projectId: projectId.value }); store.dispatch('role/getAllMembers', { projectId: projectId.value });
} }
getPlugin(); // getPlugin();
// storage // storage
async function setStorage() { async function setStorage() {

1
components/Roles/Roles.vue

@ -66,7 +66,6 @@ onMounted(() => {
query query
.selectAll('.tab-children') .selectAll('.tab-children')
.boundingClientRect(res => { .boundingClientRect(res => {
console.log('data', res);
if (res.length) { if (res.length) {
data.roleLeft = res[0].left; data.roleLeft = res[0].left;
} }

8
components/TimeLine/TimeLine.vue

@ -15,14 +15,14 @@
<!-- 时间轴 --> <!-- 时间轴 -->
<!-- <u-divider bg-color="#f3f4f6" class="pt-5" fontSize="14px" v-if="topEnd">到顶啦</u-divider> --> <!-- <u-divider bg-color="#f3f4f6" class="pt-5" fontSize="14px" v-if="topEnd">到顶啦</u-divider> -->
<!-- <TimeBox /> --> <TimeBox />
<!-- <u-divider bg-color="#f3f4f6" class="pb-5" fontSize="14px" v-if="bottomEnd">到底啦</u-divider> --> <!-- <u-divider bg-color="#f3f4f6" class="pb-5" fontSize="14px" v-if="bottomEnd">到底啦</u-divider> -->
</scroll-view> </scroll-view>
</template> </template>
<script setup> <script setup>
import { reactive, computed } from 'vue'; import { reactive, computed, defineExpose, defineEmits } from 'vue';
import { useStore } from 'vuex'; import { useStore } from 'vuex';
// import Barrier from './component/Barrier.vue'; // import Barrier from './component/Barrier.vue';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
@ -119,4 +119,8 @@ function setScrollPosition() {
} }
} }
} }
defineExpose({
setScrollPosition
})
</script> </script>

23
components/TimeLine/component/TimeBox.vue

@ -1,25 +1,25 @@
<template> <template>
<view class="column" v-finger:pinch="pinchHandler"> <!-- v-finger:pinch="pinchHandler" -->
<!-- v-if="tasks && tasks.length" --> <view class="column" >
<view> <view v-if="tasks && tasks.length">
<view :key="task.id" v-for="task in tasks" :id="`a${task.id}`"> <view :key="task.id" v-for="task in tasks" :id="`a${task.id}`">
<view class="flex"> <view class="flex">
<!-- <TimeStatus :task="task" /> --> <TimeStatus :task="task" />
<view class="flex items-center justify-between flex-1 ml-2 task-column"> <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-if="task.process !== 4">{{ $moment(+task.planStart).format(startTimeFormat) }}</view>
<view v-else>{{ $moment(+task.planStart).format('D日') }}</view> <view v-else>{{ $moment(+task.planStart).format('D日') }}</view>
<!-- 任务功能菜单 --> <!-- 任务功能菜单 -->
<!-- <TaskTools v-if="task.process !== 4" :task="task" /> --> <TaskTools v-if="task.process !== 4" :task="task" />
</view> </view>
</view> </view>
<view class="border-l-2 border-gray-300 plugin"> <view class="plugin">
<view class="h-3" v-if="task.process === 4"></view> <view class="h-3" v-if="task.process === 4"></view>
<view class="ml-3 overflow-hidden shadow-lg task-box"> <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"> <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 slot="body">
<view> <view>
<!-- <skeleton :banner="false" :loading="true" :row="4" animate class="mt-2 u-line-2 skeleton"></skeleton> --> <skeleton :banner="false" :loading="true" :row="4" animate class="mt-2 u-line-2 skeleton"></skeleton>
</view> </view>
</view> </view>
</u-card> </u-card>
@ -37,8 +37,8 @@
<view slot="body"> <view slot="body">
<view class="p-0 u-col-between"> <view class="p-0 u-col-between">
<view :key="pIndex" v-for="(row, pIndex) in task.plugins"> <view :key="pIndex" v-for="(row, pIndex) in task.plugins">
<view class="grid gap-2 grid-cols-1" v-if="row.length"> <!-- <view class="grid gap-2 grid-cols-1" v-if="row.length">
<!-- <Plugin <Plugin
:class="[`row-span-${plugin.row}`, `col-span-${plugin.col}`]" :class="[`row-span-${plugin.row}`, `col-span-${plugin.col}`]"
:task="task" :task="task"
:key="plugin.pluginTaskId" :key="plugin.pluginTaskId"
@ -47,8 +47,8 @@
:param="plugin.param" :param="plugin.param"
:style-type="data.styleType || 0" :style-type="data.styleType || 0"
v-for="plugin in row" v-for="plugin in row"
/> --> />
</view> </view> -->
</view> </view>
</view> </view>
</view> </view>
@ -120,6 +120,7 @@ function pinchHandler(evt) {
margin-top: 8px; margin-top: 8px;
margin-bottom: 8px; margin-bottom: 8px;
margin-left: 15px; margin-left: 15px;
border-left: 2px solid #d1d5db;
} }
::v-deep .ml-2 { ::v-deep .ml-2 {
margin-left: 16px; margin-left: 16px;

9
components/TimeLine/component/TimeStatus.vue

@ -59,6 +59,7 @@
<script setup> <script setup>
import { reactive, onMounted, computed } from 'vue'; import { reactive, onMounted, computed } from 'vue';
import { useStore } from 'vuex'; import { useStore } from 'vuex';
import dayjs from 'dayjs';
import CreateTask from '../../Title/components/CreateTask.vue'; import CreateTask from '../../Title/components/CreateTask.vue';
const props = defineProps({ task: { type: Object, default: () => {} } }); const props = defineProps({ task: { type: Object, default: () => {} } });
@ -89,9 +90,9 @@ const data = reactive({
const store = useStore(); const store = useStore();
const tip = computed(() => store.state.task.tip); const tip = computed(() => store.state.task.tip);
const status = computed(() => [props.task ? props.task.process : 0]); const status = computed(() => props.task ? props.task.process : 0);
const taskName = computed(() => [props.task ? props.task.name : '']); const taskName = computed(() => props.task ? props.task.name : '');
const taskId = computed(() => [props.task ? props.task.id : '']); const taskId = computed(() => props.task ? props.task.id : '');
// //
function computeCyclePersent() { function computeCyclePersent() {
@ -222,7 +223,7 @@ function confirmEndTime(e) {
// = realStart + planDuration - Date.now() // = realStart + planDuration - Date.now()
function computeDurationText() { function computeDurationText() {
const { realStart, planDuration } = props.task; const { realStart, planDuration } = props.task;
const leftTime = +realStart + +planDuration - Date.now(); // const leftTime = (realStart-0 || 0) + (planDuration-0 || 0) - Date.now(); //
const { num, time } = uni.$time.computeDurationText(leftTime); const { num, time } = uni.$time.computeDurationText(leftTime);
if (num <= 0) { if (num <= 0) {
clearInterval(data.timer); clearInterval(data.timer);

2
config/task.js

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

159
hooks/project/useGetTasks.js

@ -1,11 +1,10 @@
import { ref, computed, nextTick } from 'vue'; import { computed, nextTick } from 'vue';
import { useStore } from 'vuex'; import { useStore } from 'vuex';
import { flatten } from 'lodash';
import dayjs from 'dayjs';
export default function useGetTasks() { export default function useGetTasks() {
const timeLine = ref(null);
const store = useStore(); const store = useStore();
const tasks = computed(() => store.state.task.tasks); const tasks = computed(() => store.state.task.tasks);
const showScrollTo = computed(() => store.state.task.showScrollTo);
const roleId = computed(() => store.state.role.roleId); const roleId = computed(() => store.state.role.roleId);
const timeNode = computed(() => store.state.task.timeNode); const timeNode = computed(() => store.state.task.timeNode);
const timeUnit = computed(() => store.state.task.timeUnit); const timeUnit = computed(() => store.state.task.timeUnit);
@ -17,67 +16,58 @@ export default function useGetTasks() {
setPrevPlaceholderTasks(); // 向上加载空数据 setPrevPlaceholderTasks(); // 向上加载空数据
setNextPlaceholderTasks(); // 向下加载空数据 setNextPlaceholderTasks(); // 向下加载空数据
await getInitTasks(); // 获取初始数据 await getInitTasks(); // 获取初始数据
// 滚动到对应位置
// let timer = null;
// timer = setInterval(() => {
// if (showScrollTo.value) {
// clearInterval(timer);
// console.log('timeLine',timeLine)
// nextTick(() => timeLine.setScrollPosition());
// }
// }, 500);
} }
// 切换了 颗粒度 || 角色时候 获取初始定期任务 // 切换了 颗粒度 || 角色时候 获取初始定期任务
function getInitTasks() { function getInitTasks() {
// 预加载 上下的定期任务 // 预加载 上下的定期任务
// function preloadFn(that) { function preloadFn(that) {
// const detailId = tasks.value.findIndex(task => task.detailId); const detailId = tasks.value.findIndex(task => task.detailId);
// const arr = []; const arr = [];
// tasks.value.forEach(task => { tasks.value.forEach(task => {
// if (task.detailId) { if (task.detailId) {
// arr.push(task); arr.push(task);
// } }
// }); });
// if (detailId !== -1) { if (detailId !== -1) {
// // 只要有1个真实的任务 就预加载上下周期的任务 // 只要有1个真实的任务 就预加载上下周期的任务
// const { const { pageCount } = uni.$task;
// pageCount nextTick(() => {
// } = uni.$task; // 向上拿数据
// nextTick(() => { getTasks({
// // 向上拿数据 timeNode: +tasks.value[detailId].planStart,
// getTasks({ queryType: 0,
// timeNode: +tasks.value[detailId].planStart, queryNum: pageCount,
// queryType: 0, });
// queryNum: pageCount // 向下拿数据
// }); const nextQueryTime = +uni.$time.add(+arr[arr.length - 1].planStart, 1, timeGranularity.value);
// // 向下拿数据 getTasks({
// const nextQueryTime = +uni.$time.add(+arr[arr.length - 1].planStart, 1, timeGranularity.value); timeNode: nextQueryTime,
// getTasks({ queryType: 1,
// timeNode: nextQueryTime, queryNum: pageCount,
// queryType: 1, });
// queryNum: pageCount });
// }); } else {
// }); // 没有任务 上下显示时间刻度
// } else { // 向上加载
// // 没有任务 上下显示时间刻度 setPrevPlaceholderTasks();
// // 向上加载 // // 向下加载
// setPrevPlaceholderTasks(); setNextPlaceholderTasks();
// // // 向下加载 }
// setNextPlaceholderTasks(); }
// }
// }
// 根据时间基准点和角色查找定期任务 // 根据时间基准点和角色查找定期任务
getTasks({ getTasks({
queryType: 0 queryType: 0,
}); // 向上获取定期任务数据 }); // 向上获取定期任务数据
// 根据项目id获取角色列表 // 根据项目id获取角色列表
// 向下获取定期任务数据 // 向下获取定期任务数据
// getTasks({ getTasks(
// queryType: 1 {
// }, preloadFn); queryType: 1,
},
preloadFn,
);
} }
/** /**
@ -105,8 +95,7 @@ export default function useGetTasks() {
* @param {number} query.queryType 0向上查找 1向下查找(默认) 下查包含自己上查不包含 * @param {number} query.queryType 0向上查找 1向下查找(默认) 下查包含自己上查不包含
*/ */
function getTasks(query, fn) { function getTasks(query, fn) {
// store.commit('task/setShowSkeleton', false); store.commit('task/setShowSkeleton', false);
console.log('根据时间基准点和角色查找定期任务')
const params = generateGetTaskParam(query); const params = generateGetTaskParam(query);
uni.$catchReq.getRegularTask(params, (err, data) => { uni.$catchReq.getRegularTask(params, (err, data) => {
store.commit('task/setShowSkeleton', false); store.commit('task/setShowSkeleton', false);
@ -118,17 +107,58 @@ export default function useGetTasks() {
// 有数据用数据替换刻度 // 有数据用数据替换刻度
// 没有数据 继续加载刻度 // 没有数据 继续加载刻度
if (data && data.length) { if (data && data.length) {
// replacePrevData(data, params.queryType); replacePrevData(data, params.queryType);
params.queryType === 0 ? store.commit('task/setTopEnd', false) : store.commit('task/setBottomEnd', false); params.queryType === 0 ? store.commit('task/setTopEnd', false) : store.commit('task/setBottomEnd', false);
} else { } else {
// TODO: 0 -> 向上 1 -> 向下 // TODO: 0 -> 向上 1 -> 向下
// params.queryType === 0 ? setPrevPlaceholderTasks() : setNextPlaceholderTasks(); params.queryType === 0 ? setPrevPlaceholderTasks() : setNextPlaceholderTasks();
}
if (tasks.value.length && fn) {
fn(this);
}
} }
// if (tasks.value.length && fn) { });
// fn(this); }
// }
/**
* 用拿到的新数据 替换 时间刻度/旧数据
* 先对比 新旧数据的 始末时间 补齐刻度
* 再遍历对比 用任务替换刻度
* @param {array} data 服务端返回的新数据 上边已经处理过空值
* @param {number} type 0 -> 向上 1->向下
*/
function replacePrevData(data, type) {
const obj = { tasks: tasks.value, data, timeGranularity: timeGranularity.value };
let oldTasks = fillPlaceholderTask(obj); // 已经上下补齐时间刻度的
// 遍历对比 用任务替换刻度
// TODO: tasks越来越多 遍历越来越多 需要优化
oldTasks.forEach((taskItem, index) => {
const arr = data.filter(dataItem => dayjs(+dataItem.planStart).isSame(+taskItem.planStart, timeGranularity.value));
if (arr && arr.length) {
oldTasks.splice(index, 1, [...arr]); // 这里加入的数据是array类型的, [{},{},[],[],{}]
} }
}); });
oldTasks = flatten(oldTasks); // 1维拍平
store.commit('task/clearTasks');
type === 0 ? store.commit('task/setUpTasks', oldTasks) : store.commit('task/setDownTasks', oldTasks);
}
/**
* 超出旧数据上下限 补齐时间刻度到新数据的起始时间颗粒度
*/
function fillPlaceholderTask(obj) {
const { prev, next } = uni.$task.computeFillPlaceholderTaskCount(obj);
if (prev) {
const newTasks = uni.$task.setPlaceholderTasks(+obj.tasks[0].planStart, true, obj.timeGranularity, prev);
store.commit('task/setUpTasks', newTasks);
}
if (next) {
const newTasks = uni.$task.setPlaceholderTasks(+obj.tasks[tasks.length - 1].planStart, false, obj.timeGranularity, next);
store.commit('task/setDownTasks', newTasks);
}
return tasks.value;
} }
// 设置时间轴向上的空数据 // 设置时间轴向上的空数据
@ -138,7 +168,7 @@ export default function useGetTasks() {
if (!tasks.value || !tasks.value.length) { if (!tasks.value || !tasks.value.length) {
startTime = Date.now(); // 没有任务就应该是时间基准点 startTime = Date.now(); // 没有任务就应该是时间基准点
} else { } else {
startTime = tasks[0].planStart - 0; // 有任务就是第一个任务的计划开始时间 startTime = tasks.value[0].planStart - 0; // 有任务就是第一个任务的计划开始时间
} }
const placeholderTasks = uni.$task.setPlaceholderTasks(startTime, true, timeGranularity.value); const placeholderTasks = uni.$task.setPlaceholderTasks(startTime, true, timeGranularity.value);
store.commit('task/setUpTasks', placeholderTasks); store.commit('task/setUpTasks', placeholderTasks);
@ -158,6 +188,7 @@ export default function useGetTasks() {
} }
return { return {
initPlanTasks initPlanTasks,
} getTasks,
};
} }

449
hooks/project/useInit - 副本.js

@ -1,449 +0,0 @@
import {
ref,
onMounted,
computed,
watch,
nextTick
} from 'vue';
import {
onLoad
} from '@dcloudio/uni-app';
import useGetUserIdFromLocal from '@/hooks/user/useGetUserIdFromLocal';
import {
useStore
} from 'vuex';
import {
flatten
} from 'lodash';
export default function useInit() {
const store = useStore();
const token = computed(() => store.state.user.token);
const userId = useGetUserIdFromLocal();
const roleId = computed(() => store.state.role.roleId);
const timeNode = computed(() => store.state.task.timeNode);
const timeUnit = computed(() => store.state.task.timeUnit);
const tasks = computed(() => store.state.task.tasks);
const newProjectInfo = computed(() => store.state.task.newProjectInfo);
const showScrollTo = computed(() => store.state.task.showScrollTo);
const timeGranularity = computed(() => store.getters['task/timeGranularity']);
const projectId = computed(() => store.getters['project/projectId']);
const height = ref(null);
const timeLine = ref(null);
onLoad(options => {
console.log('onLoad options: ', options);
if (options.share && options.share === '1') {
shareInit(options);
} else {
init(options);
}
});
/**
* 当时间基准点发生变化时
* 重新根据时间和角色查询普通日常任务
* 永久日常任务不发生 改变
*/
watch(timeNode, newValue => {
if (newValue && roleId.value) {
console.log('当时间基准点发生变化时')
clearTasksData();
getGlobalData(); // 查可变日常任务
initPlanTasks(); // 处理定期任务
}
});
/**
* 当角色发生变化时
* 重新查询永久日常任务和普通日常任务
* 注意: 切换角色后 重新设置了时间基准点 时间基准点一定会变
* 所以监听时间基准点获取 可变日常任务即可 这里不用获取 避免重复获取
*/
watch(roleId, newValue => {
if (newValue) {
console.log('当角色发生变化时')
store.commit('task/setTimeNode', Date.now());
// 根据角色查找永久的日常任务
const params = {
roleId: newValue.value,
projectId: projectId.value
};
store.dispatch('task/getPermanent', params);
}
});
/**
* 当时间基准点发生变化时
* 重新根据时间和角色查询普通日常任务
* 永久日常任务不发生改变
*/
watch(newProjectInfo, newValue => {
console.log('当时间基准点发生变化时')
if (newValue && newValue.value.projectId && newValue.value.url) {
uni.$u.route('/', {
u: userId.value,
p: newValue.value.projectId,
url: newValue.value.url
});
clearTasksData();
store.commit('role/setRoleId', '');
const options = uni.$route.query;
init(options);
}
});
onMounted(() => {
const system = uni.getSystemInfoSync();
height.value = `${system.windowHeight}px`;
});
/**
* 初始化
* @param {object | null} options
*/
function init(options) {
console.log('初始化init')
if (!token.value) {
// 不论有没有token都直接从userId获取token
// token有过期时间 从本地获取可能是过期 干脆直接从userId获取
if (!options || !options.u) {
uni.$ui.showToast('缺少用户信息参数'); // 参数里没有u (userId)提示
} else {
store.dispatch('user/getToken', options.u);
}
}
// 参数里有项目名称 就设置标题里的项目名称
options && options.pname && store.commit('project/setProjectName', options.pname);
if (!options || !options.p) {
uni.$ui.showToast('缺少项目信息参数'); // 没有项目id参数
} else {
if (options.p !== uni.$storage.getStorageSync('projectId')) {
console.log('切项目了');
uni.$storage.setStorageSync('roleId', '');
}
// 根据项目id获取项目信息
const params = {
projectId: options.p,
num: 0
}
getProjectById(params);
// 查询医院是否填写了调查问卷
// this.handleQueryNotWrite(options.p);
// 根据项目id获取成员列表
store.dispatch('role/getAllMembers', {
projectId: options.p
});
}
}
// 初始化 定期任务
async function initPlanTasks() {
setPrevPlaceholderTasks(); // 向上加载空数据
setNextPlaceholderTasks(); // 向下加载空数据
await getInitTasks(); // 获取初始数据
// 滚动到对应位置
let timer = null;
timer = setInterval(() => {
if (showScrollTo.value) {
clearInterval(timer);
// nextTick(() => timeLine.setScrollPosition());
}
}, 500);
}
// 切换了 颗粒度 || 角色时候 获取初始定期任务
function getInitTasks() {
// 预加载 上下的定期任务
function preloadFn(that) {
const detailId = tasks.value.findIndex(task => task.detailId);
const arr = [];
tasks.value.forEach(task => {
if (task.detailId) {
arr.push(task);
}
});
if (detailId !== -1) {
// 只要有1个真实的任务 就预加载上下周期的任务
const {
pageCount
} = uni.$task;
nextTick(() => {
// 向上拿数据
getTasks({
timeNode: +tasks.value[detailId].planStart,
queryType: 0,
queryNum: pageCount
});
// 向下拿数据
const nextQueryTime = +uni.$time.add(+arr[arr.length - 1].planStart, 1, timeGranularity.value);
getTasks({
timeNode: nextQueryTime,
queryType: 1,
queryNum: pageCount
});
});
} else {
// 没有任务 上下显示时间刻度
// 向上加载
setPrevPlaceholderTasks();
// // 向下加载
setNextPlaceholderTasks();
}
}
// 根据时间基准点和角色查找定期任务
getTasks({
queryType: 0
}); // 向上获取定期任务数据
// 根据项目id获取角色列表
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向下查找(默认) 下查包含自己上查不包含
*/
function getTasks(query, fn) {
store.commit('task/setShowSkeleton', false);
const params = generateGetTaskParam(query);
uni.$catchReq.getRegularTask(params, (err, data) => {
store.commit('task/setShowSkeleton', false);
if (err) {
// TODO: 提示错误
console.error('err: ', err);
} else {
store.commit('task/setShowScrollTo', true);
// 有数据用数据替换刻度
// 没有数据 继续加载刻度
if (data && data.length) {
replacePrevData(data, params.queryType);
params.queryType === 0 ? store.commit('task/setTopEnd', false) : store.commit('task/setBottomEnd', false);
} else {
// TODO: 0 -> 向上 1 -> 向下
params.queryType === 0 ? setPrevPlaceholderTasks() : setNextPlaceholderTasks();
}
if (tasks.value.length && fn) {
fn(this);
}
}
});
}
/**
* 生成getTasks所用的参数
* @param {object} query getTasks传递的参数
*/
function generateGetTaskParam(query) {
return {
roleId: roleId.value,
timeNode: query.timeNode || timeNode.value,
timeUnit: query.timeUnit || timeUnit.value,
queryNum: query.queryNum || 3,
queryType: query.queryType,
projectId: projectId.value,
};
}
// 设置时间轴向上的空数据
function setPrevPlaceholderTasks() {
store.commit('task/setTopEnd', true);
let startTime = '';
if (!tasks.value || !tasks.value.length) {
startTime = Date.now(); // 没有任务就应该是时间基准点
} else {
startTime = tasks[0].planStart - 0; // 有任务就是第一个任务的计划开始时间
}
const placeholderTasks = uni.$task.setPlaceholderTasks(startTime, true, timeGranularity.value);
store.commit('task/setUpTasks', placeholderTasks);
}
// 设置时间轴向下的空数据
function setNextPlaceholderTasks() {
store.commit('task/setBottomEnd', true);
let startTime = '';
if (!tasks.value || !tasks.value.length) {
startTime = Date.now();
} else {
startTime = +tasks.value[tasks.value.length - 1].planStart;
}
const initData = uni.$task.setPlaceholderTasks(startTime, false, timeGranularity.value);
store.commit('task/setDownTasks', initData);
}
/**
* 用拿到的新数据 替换 时间刻度/旧数据
* 先对比 新旧数据的 始末时间 补齐刻度
* 再遍历对比 用任务替换刻度
* @param {array} data 服务端返回的新数据 上边已经处理过空值
* @param {number} type 0 -> 向上 1->向下
*/
function replacePrevData(data, type) {
let oldTasks = fillPlaceholderTask({ tasks.value, data, timeGranularity.value }); // 已经上下补齐时间刻度的
// 遍历对比 用任务替换刻度
// TODO: tasks越来越多 遍历越来越多 需要优化
oldTasks.forEach((taskItem, index) => {
const arr = data.filter(dataItem => dayjs(+dataItem.planStart).isSame(+taskItem.planStart, timeGranularity
.value));
if (arr && arr.length) {
oldTasks.splice(index, 1, [...arr]); // 这里加入的数据是array类型的, [{},{},[],[],{}]
}
});
oldTasks = flatten(oldTasks); // 1维拍平
store.commit('task/clearTasks');
type === 0 ? store.commit('task/setUpTasks', oldTasks) : store.commit('task/setDownTasks', oldTasks);
}
/**
* 超出旧数据上下限 补齐时间刻度到新数据的起始时间颗粒度
*/
function fillPlaceholderTask({
tasks,
data,
timeGranularity
}) {
const {
prev,
next
} = uni.$task.computeFillPlaceholderTaskCount({
tasks,
data,
timeGranularity
});
if (prev) {
const newTasks = uni.$task.setPlaceholderTasks(+tasks[0].planStart, true, timeGranularity, prev);
store.commit('task/setUpTasks', newTasks);
}
if (next) {
const newTasks = uni.$task.setPlaceholderTasks(+tasks[tasks.length - 1].planStart, false, timeGranularity, next);
store.commit('task/setDownTasks', newTasks);
}
return tasks.value;
}
// 分享链接来的初始化
async function shareInit(options) {
console.log('分享链接来的初始化init')
const storageUser = uni.$storage.getStorageSync('user');
const user = storageUser ? JSON.parse(storageUser) : null;
if (user && user.id) {
await store.dispatch('user/getToken', user.id);
const res = await clickShare({
code: options.shareId
});
if (res && res.projectId) {
let query = {
...uni.$route.query
};
query = {
u: user.id,
p: res.projectId,
};
uni.$router.push({
path: uni.$route.path,
query
});
console.log('query',query)
init(query);
}
} else {
uni.$ui.showToast('缺少用户信息参数,请登录');
}
}
/**
* 点击分享连接
* @param {any} commit
* @param {object} param 请求参数
*/
async function clickShare(param) {
try {
const data = await uni.$catchReq.clickShare(param);
return data;
} catch (error) {
uni.$ui.showToast(error.msg || '获取失败');
}
}
/**
* 通过项目id获取项目信息
* @param {object} params 提交的参数
*/
async function getProjectById(params) {
try {
const data = await uni.$u.api.findProjectById(params);
store.commit('project/setProject', data);
// 根据项目id获取角色列表
getRoles(params);
} catch (error) {
console.log('error: ', error || '获取项目信息失败');
}
}
/**
* 通过项目id获取角色信息
* @param {string} projectId
* @param {object} params 提交的参数
*/
function getRoles(params) {
uni.$catchReq.findShowRole(params, (err, data) => {
if (err) {
console.error('err: ', err || '获取角色信息失败');
} else {
store.commit('role/setInvisibleRoles', data ? data.invisibleList : []);
store.commit('role/setVisibleRoles', data ? data.visibleList : []);
setInitialRoleId(data ? data.visibleList : []);
}
});
}
// 设置 初始显示角色信息
function 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 = uni.$storage.getStorageSync('roleId');
const currentRoleId = storageRoleId || (currentRole ? currentRole.id : '');
store.commit('role/setRoleId', currentRoleId);
// 清空storage
uni.$storage.setStorageSync('roleId', '');
}
// 获取可变全局任务
function getGlobalData() {
const param = {
roleId: roleId.value,
timeNode: timeNode.value,
timeUnit: timeUnit.value,
projectId: projectId.value
};
store.dispatch('task/getGlobal', param);
}
// 清除已有的任务数据
function clearTasksData() {
// 清空日常任务的数据
store.commit('task/setPermanents', []);
store.commit('task/setDailyTasks', []);
// 清空定期任务数据
store.commit('task/clearTasks');
// 到顶的标志复位
// 到底的标志复位
store.commit('task/clearEndFlag');
}
}

16
hooks/project/useInit.js

@ -81,8 +81,6 @@ export default function useInit() {
// 根据项目id获取项目信息 // 根据项目id获取项目信息
const params = { projectId: options.p, num: 0 }; const params = { projectId: options.p, num: 0 };
getProjectById(params); getProjectById(params);
// 查询医院是否填写了调查问卷
// this.handleQueryNotWrite(options.p);
// 根据项目id获取成员列表 // 根据项目id获取成员列表
store.dispatch('role/getAllMembers', { projectId: options.p }); store.dispatch('role/getAllMembers', { projectId: options.p });
} }
@ -106,5 +104,19 @@ export default function useInit() {
} }
} }
/**
* 点击分享连接
* @param {any} commit
* @param {object} param 请求参数
*/
async function clickShare(param) {
try {
const data = await uni.$catchReq.clickShare(param);
return data;
} catch (error) {
uni.$ui.showToast(error.msg || '获取失败');
}
}
return { init }; return { init };
} }

3
main.js

@ -14,6 +14,7 @@ import store from './store';
import task from '@/utils/task.js'; import task from '@/utils/task.js';
import time from '@/utils/time.js'; import time from '@/utils/time.js';
import timeConfig from '@/config/time'; import timeConfig from '@/config/time';
import taskConfig from '@/config/task';
import uView from './uni_modules/vk-uview-ui'; // 引入 uView UI import uView from './uni_modules/vk-uview-ui'; // 引入 uView UI
import ui from '@/utils/ui.js'; import ui from '@/utils/ui.js';
import upload from '@/utils/upload.js'; import upload from '@/utils/upload.js';
@ -29,6 +30,7 @@ export function createApp() {
app.config.globalProperties.$upload = upload; app.config.globalProperties.$upload = upload;
app.config.globalProperties.$task = task; app.config.globalProperties.$task = task;
app.config.globalProperties.$timeConfig = timeConfig; app.config.globalProperties.$timeConfig = timeConfig;
app.config.globalProperties.$taskConfig = taskConfig;
uni.$cache = cache; uni.$cache = cache;
uni.$catchReq = cacheAndRequest; uni.$catchReq = cacheAndRequest;
@ -38,6 +40,7 @@ export function createApp() {
uni.$upload = upload; uni.$upload = upload;
uni.$task = task; uni.$task = task;
uni.$timeConfig = timeConfig; uni.$timeConfig = timeConfig;
uni.$taskConfig = taskConfig;
setupDayjs(app); setupDayjs(app);
app.use(uView); // 使用 uView UI app.use(uView); // 使用 uView UI

434
pages/project/project A.vue

@ -1,434 +0,0 @@
<template>
<view :style="{ height: height }" class="flex flex-col overflow-hidden u-font-14">
<!-- 标题栏 -->
<Title />
<view class="container flex flex-col flex-1 mx-auto overflow-hidden bg-gray-100">
<!-- 角色栏 -->
<Roles />
<!-- 日常任务面板 -->
<Globals />
<!-- 定期任务面板 -->
<!-- <TimeLine @getTasks="getTasks" class="flex-1 overflow-hidden" ref="timeLine" /> -->
</view>
</view>
</template>
<script>
import { defineComponent, ref, onMounted, computed, watch, nextTick } from 'vue';
import { useStore } from 'vuex';
import { flatten } from 'lodash';
export default defineComponent({
setup(options) {
const store = useStore();
const token = computed(() => store.state.user.token);
const userId = computed(() => store.getters['user/userId']);
const roleId = computed(() => store.state.role.roleId);
const timeNode = computed(() => store.state.task.timeNode);
const timeUnit = computed(() => store.state.task.timeUnit);
const tasks = computed(() => store.state.task.tasks);
const newProjectInfo = computed(() => store.state.task.newProjectInfo);
const showScrollTo = computed(() => store.state.task.showScrollTo);
const timeGranularity = computed(() => store.getters['task/timeGranularity']);
const projectId = computed(() => store.getters['project/projectId']);
const height = ref(null);
const timeLine = ref(null);
/**
* 当时间基准点发生变化时
* 重新根据时间和角色查询普通日常任务
* 永久日常任务不发生 改变
*/
watch(timeNode, newValue => {
if (newValue && roleId.value) {
clearTasksData();
getGlobalData(); //
initPlanTasks(); //
}
});
/**
* 当角色发生变化时
* 重新查询永久日常任务和普通日常任务
* 注意: 切换角色后 重新设置了时间基准点 时间基准点一定会变
* 所以监听时间基准点获取 可变日常任务即可 这里不用获取 避免重复获取
*/
watch(roleId, newValue => {
if (newValue) {
store.commit('task/setTimeNode', Date.now());
//
const params = { roleId: newValue, projectId: projectId.value };
store.dispatch('task/getPermanent', params);
}
});
/**
* 当时间基准点发生变化时
* 重新根据时间和角色查询普通日常任务
* 永久日常任务不发生改变
*/
watch(newProjectInfo, newValue => {
if (newValue && newValue.projectId && newValue.url) {
uni.$u.route('/', { u: userId.value, p: newValue.projectId, url: newValue.url });
clearTasksData();
store.commit('role/setRoleId', '');
const options = uni.$route.query;
init(options);
}
});
onMounted(() => {
const system = uni.getSystemInfoSync();
height.value = `${system.windowHeight}px`;
});
//
async function initPlanTasks() {
setPrevPlaceholderTasks(); //
setNextPlaceholderTasks(); //
await getInitTasks(); //
//
let timer = null;
timer = setInterval(() => {
if (showScrollTo.value) {
clearInterval(timer);
// nextTick(() => timeLine.setScrollPosition());
}
}, 500);
}
// ||
function getInitTasks() {
//
function preloadFn(that) {
const detailId = tasks.value.findIndex(task => task.detailId);
const arr = [];
tasks.value.forEach(task => {
if (task.detailId) {
arr.push(task);
}
});
if (detailId !== -1) {
// 1
const { pageCount } = uni.$task;
nextTick(() => {
//
getTasks({ timeNode: +tasks.value[detailId].planStart, queryType: 0, queryNum: pageCount });
//
const nextQueryTime = +uni.$time.add(+arr[arr.length - 1].planStart, 1, timeGranularity.value);
getTasks({ timeNode: nextQueryTime, queryType: 1, queryNum: pageCount });
});
} else {
//
//
setPrevPlaceholderTasks();
// //
setNextPlaceholderTasks();
}
}
//
getTasks({ queryType: 0 }); //
// id
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向下查找(默认) 下查包含自己上查不包含
*/
function getTasks(query, fn) {
store.commit('task/setShowSkeleton', false);
const params = generateGetTaskParam(query);
uni.$catchReq.getRegularTask(params, (err, data) => {
store.commit('task/setShowSkeleton', false);
if (err) {
// TODO:
console.error('err: ', err);
} else {
store.commit('task/setShowScrollTo', true);
//
//
if (data && data.length) {
replacePrevData(data, params.queryType);
params.queryType === 0 ? store.commit('task/setTopEnd', false) : store.commit('task/setBottomEnd', false);
} else {
// TODO: 0 -> 1 ->
params.queryType === 0 ? setPrevPlaceholderTasks() : setNextPlaceholderTasks();
}
if (tasks.value.length && fn) {
fn(this);
}
}
});
}
/**
* 生成getTasks所用的参数
* @param {object} query getTasks传递的参数
*/
function generateGetTaskParam(query) {
return {
roleId: roleId.value,
timeNode: query.timeNode || timeNode.value,
timeUnit: query.timeUnit || timeUnit.value,
queryNum: query.queryNum || 3,
queryType: query.queryType,
projectId: projectId.value,
};
}
//
function setPrevPlaceholderTasks() {
store.commit('task/setTopEnd', true);
let startTime = '';
if (!tasks.value || !tasks.value.length) {
startTime = Date.now(); //
} else {
startTime = tasks[0].planStart - 0; //
}
const placeholderTasks = uni.$task.setPlaceholderTasks(startTime, true, timeGranularity.value);
store.commit('task/setUpTasks', placeholderTasks);
}
//
function setNextPlaceholderTasks() {
store.commit('task/setBottomEnd', true);
let startTime = '';
if (!tasks.value || !tasks.value.length) {
startTime = Date.now();
} else {
startTime = +tasks.value[tasks.value.length - 1].planStart;
}
const initData = uni.$task.setPlaceholderTasks(startTime, false, timeGranularity.value);
store.commit('task/setDownTasks', initData);
}
/**
* 用拿到的新数据 替换 时间刻度/旧数据
* 先对比 新旧数据的 始末时间 补齐刻度
* 再遍历对比 用任务替换刻度
* @param {array} data 服务端返回的新数据 上边已经处理过空值
* @param {number} type 0 -> 向上 1->向下
*/
function replacePrevData(data, type) {
let oldTasks = fillPlaceholderTask({ tasks.value, data, timeGranularity.value }); //
//
// TODO: tasks
oldTasks.forEach((taskItem, index) => {
const arr = data.filter(dataItem => dayjs(+dataItem.planStart).isSame(+taskItem.planStart, timeGranularity.value));
if (arr && arr.length) {
oldTasks.splice(index, 1, [...arr]); // array, [{},{},[],[],{}]
}
});
oldTasks = flatten(oldTasks); // 1
store.commit('task/clearTasks');
type === 0 ? store.commit('task/setUpTasks', oldTasks) : store.commit('task/setDownTasks', oldTasks);
}
/**
* 超出旧数据上下限 补齐时间刻度到新数据的起始时间颗粒度
*/
function fillPlaceholderTask({ tasks, data, timeGranularity }) {
const { prev, next } = uni.$task.computeFillPlaceholderTaskCount({ tasks, data, timeGranularity });
if (prev) {
const newTasks = uni.$task.setPlaceholderTasks(+tasks[0].planStart, true, timeGranularity, prev);
store.commit('task/setUpTasks', newTasks);
}
if (next) {
const newTasks = uni.$task.setPlaceholderTasks(+tasks[tasks.length - 1].planStart, false, timeGranularity, next);
store.commit('task/setDownTasks', newTasks);
}
return tasks.value;
}
/**
* 初始化
* @param {object | null} options
*/
function init(options) {
if (!token.value) {
// tokenuserIdtoken
// token userId
if (!options || !options.u) {
uni.$ui.showToast('缺少用户信息参数'); // u (userId)
} else {
store.dispatch('user/getToken', options.u);
}
}
//
options && options.pname && store.commit('project/setProjectName', options.pname);
if (!options || !options.p) {
uni.$ui.showToast('缺少项目信息参数'); // id
} else {
if (options.p !== uni.$storage.getStorageSync('projectId')) {
console.log('切项目了');
uni.$storage.setStorageSync('roleId', '');
}
// TODO
getProjectById({ projectId: options.p, num: 0 }); // id
//
// this.handleQueryNotWrite(options.p);
// id
store.dispatch('role/getAllMembers', { projectId: options.p });
}
}
//
async function shareInit(options) {
const storageUser = uni.$storage.getStorageSync('user');
const user = storageUser ? JSON.parse(storageUser) : null;
if (user && user.id) {
await store.dispatch('user/getToken', user.id);
const res = await clickShare({ code: options.shareId });
if (res && res.projectId) {
let query = { ...uni.$route.query };
query = {
u: user.id,
p: res.projectId,
};
uni.$router.push({ path: uni.$route.path, query });
init(query);
}
} else {
uni.$ui.showToast('缺少用户信息参数,请登录');
}
}
function setOptions(options) {
if (options.share && options.share === '1') {
shareInit(options);
} else {
init(options);
}
}
setOptions(options);
/**
* 点击分享连接
* @param {any} commit
* @param {object} param 请求参数
*/
async function clickShare(param) {
try {
const data = await uni.$catchReq.clickShare(param);
return data;
} catch (error) {
uni.$ui.showToast(error.msg || '获取失败');
}
}
/**
* 通过项目id获取项目信息
* @param {object} params 提交的参数
*/
async function getProjectById(params) {
try {
const data = await uni.$u.api.findProjectById(params);
store.commit('project/setProject', data);
// id
getRoles(params);
} catch (error) {
console.log('error: ', error || '获取项目信息失败');
}
}
/**
* 通过项目id获取角色信息
* @param {string} projectId
* @param {object} params 提交的参数
*/
function getRoles(params) {
uni.$catchReq.findShowRole(params, (err, data) => {
if (err) {
console.error('err: ', err || '获取角色信息失败');
} else {
store.commit('role/setInvisibleRoles', data ? data.invisibleList : []);
store.commit('role/setVisibleRoles', data ? data.visibleList : []);
setInitialRoleId(data ? data.visibleList : []);
}
});
}
//
function 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 = uni.$storage.getStorageSync('roleId');
const currentRoleId = storageRoleId || (currentRole ? currentRole.id : '');
store.commit('role/setRoleId', currentRoleId);
// storage
uni.$storage.setStorageSync('roleId', '');
}
//
function getGlobalData() {
const param = { roleId: roleId.value, timeNode: timeNode.value, timeUnit: timeUnit.value, projectId: projectId.value };
store.dispatch('task/getGlobal', param);
}
//
function clearTasksData() {
//
store.commit('task/setPermanents', []);
store.commit('task/setDailyTasks', []);
//
store.commit('task/clearTasks');
//
//
store.commit('task/clearEndFlag');
}
return {
height,
timeLine,
roleId,
timeNode,
timeUnit,
tasks,
newProjectInfo,
showScrollTo,
timeGranularity,
projectId,
userId,
initPlanTasks,
getInitTasks,
getTasks,
generateGetTaskParam,
setPrevPlaceholderTasks,
setNextPlaceholderTasks,
replacePrevData,
fillPlaceholderTask,
init,
shareInit,
setOptions,
clickShare,
getProjectById,
getRoles,
setInitialRoleId,
getGlobalData,
clearTasksData,
};
},
});
</script>
<style lang="scss" scoped>
.border-b {
border-bottom: 1px solid #e4e7ed;
}
</style>

18
pages/project/project.vue

@ -11,8 +11,7 @@
<Globals /> <Globals />
<!-- 定期任务面板 --> <!-- 定期任务面板 -->
<!-- <TimeLine @getTasks="getTasks" class="flex-1 overflow-hidden" ref="timeLine" /> --> <TimeLine @getTasks="getTasks" class="flex-1 overflow-hidden" ref="timeLine" />
<TimeLine class="flex-1 overflow-hidden" ref="timeLine" />
</view> </view>
</view> </view>
</template> </template>
@ -32,7 +31,9 @@ const timeUnit = computed(() => store.state.task.timeUnit);
const projectId = computed(() => store.getters['project/projectId']); const projectId = computed(() => store.getters['project/projectId']);
const userId = computed(() => store.getters['user/userId']); const userId = computed(() => store.getters['user/userId']);
const newProjectInfo = computed(() => store.state.task.newProjectInfo); const newProjectInfo = computed(() => store.state.task.newProjectInfo);
const showScrollTo = computed(() => store.state.task.showScrollTo);
const height = ref(null); const height = ref(null);
const timeLine = ref(null);
onMounted(() => { onMounted(() => {
const system = uni.getSystemInfoSync(); const system = uni.getSystemInfoSync();
@ -74,6 +75,15 @@ watch(timeNode, newValue => {
getGlobalData(); // getGlobalData(); //
// initPlanTasks(); // // initPlanTasks(); //
getTasksHook.initPlanTasks(); // getTasksHook.initPlanTasks(); //
//
let timer = null;
timer = setInterval(() => {
if (showScrollTo.value) {
clearInterval(timer);
timeLine.value.setScrollPosition();
}
}, 500);
} }
}); });
@ -116,6 +126,10 @@ watch(newProjectInfo, newValue => {
initHook.init(options); initHook.init(options);
} }
}); });
function getTasks(params) {
getTasksHook.initPlanTasks(params); //
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

36
utils/cacheAndRequest.js

@ -24,7 +24,8 @@ export default {
let remote = false; let remote = false;
if (store.getters.useStorage) { if (store.getters.useStorage) {
// 有缓存 且 服务端数据未返回 就先返回缓存 // 有缓存 且 服务端数据未返回 就先返回缓存
uni.$cache.getProjectsByDay(startTime, endTime) uni.$cache
.getProjectsByDay(startTime, endTime)
.then(data => { .then(data => {
!remote && fn(null, data); !remote && fn(null, data);
}) })
@ -32,7 +33,8 @@ export default {
} }
waitTokenRequest(() => { waitTokenRequest(() => {
// 拿到api数据后 再用api的数据 // 拿到api数据后 再用api的数据
uni.$u.api.getProjects(startTime, endTime) uni.$u.api
.getProjects(startTime, endTime)
.then(data => { .then(data => {
remote = true; remote = true;
fn(null, data); fn(null, data);
@ -50,7 +52,8 @@ export default {
findShowRole(params, fn) { findShowRole(params, fn) {
let remote = false; let remote = false;
// 有缓存 且 服务端数据未返回 就先返回缓存 // 有缓存 且 服务端数据未返回 就先返回缓存
uni.$cache.getShowRole(params.projectId) uni.$cache
.getShowRole(params.projectId)
.then(data => { .then(data => {
!remote && fn(null, data); !remote && fn(null, data);
}) })
@ -58,7 +61,8 @@ export default {
waitTokenRequest(() => { waitTokenRequest(() => {
// 拿到api数据后 再用api的数据 // 拿到api数据后 再用api的数据
uni.$u.api.findShowRole(params) uni.$u.api
.findShowRole(params)
.then(data => { .then(data => {
remote = true; remote = true;
fn(null, data); fn(null, data);
@ -76,7 +80,8 @@ export default {
getRegularTask(params, fn) { getRegularTask(params, fn) {
let remote = false; let remote = false;
// 有缓存 且 服务端数据未返回 就先返回缓存 // 有缓存 且 服务端数据未返回 就先返回缓存
uni.$cache.getStorageRegularTask(params) uni.$cache
.getStorageRegularTask(params)
.then(data => { .then(data => {
console.log('cache data: ', data); console.log('cache data: ', data);
!remote && fn(null, data); !remote && fn(null, data);
@ -85,7 +90,8 @@ export default {
waitTokenRequest(() => { waitTokenRequest(() => {
// 拿到api数据后 再用api的数据 // 拿到api数据后 再用api的数据
uni.$u.api.getRegularTask(params) uni.$u.api
.getRegularTask(params)
.then(data => { .then(data => {
console.log('api data: ', uni.$u.deepClone(data)); console.log('api data: ', uni.$u.deepClone(data));
remote = true; remote = true;
@ -105,7 +111,8 @@ export default {
getPermanent(params, fn) { getPermanent(params, fn) {
let remote = false; let remote = false;
// 有缓存 且 服务端数据未返回 就先返回缓存 // 有缓存 且 服务端数据未返回 就先返回缓存
uni.$cache.getStoragePermanent(params) uni.$cache
.getStoragePermanent(params)
.then(data => { .then(data => {
!remote && fn(null, data); !remote && fn(null, data);
}) })
@ -113,7 +120,8 @@ export default {
waitTokenRequest(() => { waitTokenRequest(() => {
// 拿到api数据后 再用api的数据 // 拿到api数据后 再用api的数据
uni.$u.api.getPermanent(params) uni.$u.api
.getPermanent(params)
.then(data => { .then(data => {
remote = true; remote = true;
fn(null, data); fn(null, data);
@ -131,7 +139,8 @@ export default {
getGlobal(params, fn) { getGlobal(params, fn) {
let remote = false; let remote = false;
// 有缓存 且 服务端数据未返回 就先返回缓存 // 有缓存 且 服务端数据未返回 就先返回缓存
uni.$cache.getDailyTask(params) uni.$cache
.getDailyTask(params)
.then(data => { .then(data => {
!remote && fn(null, data); !remote && fn(null, data);
}) })
@ -139,7 +148,8 @@ export default {
waitTokenRequest(() => { waitTokenRequest(() => {
// 拿到api数据后 再用api的数据 // 拿到api数据后 再用api的数据
uni.$u.api.getGlobal(params) uni.$u.api
.getGlobal(params)
.then(data => { .then(data => {
remote = true; remote = true;
fn(null, data); fn(null, data);
@ -157,7 +167,8 @@ export default {
getOtherPlugin(params, fn) { getOtherPlugin(params, fn) {
let remote = false; let remote = false;
// 有缓存 且 服务端数据未返回 就先返回缓存 // 有缓存 且 服务端数据未返回 就先返回缓存
uni.$cache.getPlugin(params.pluginId) uni.$cache
.getPlugin(params.pluginId)
.then(data => { .then(data => {
!remote && fn(null, data); !remote && fn(null, data);
}) })
@ -165,7 +176,8 @@ export default {
waitTokenRequest(() => { waitTokenRequest(() => {
// 拿到api数据后 再用api的数据 // 拿到api数据后 再用api的数据
uni.$u.api.getOtherPlugin(params) uni.$u.api
.getOtherPlugin(params)
.then(data => { .then(data => {
remote = true; remote = true;
fn(null, data); fn(null, data);

7
utils/task.js

@ -9,7 +9,7 @@ import dayjs from 'dayjs';
*/ */
const setPlaceholderTasks = (startTime, isUp, timeGranularity, pageCount) => { const setPlaceholderTasks = (startTime, isUp, timeGranularity, pageCount) => {
let result = []; let result = [];
pageCount = pageCount || uni.$task.pageCount; pageCount = pageCount || uni.$taskConfig.pageCount;
for (let i = 0; i < pageCount; i++) { for (let i = 0; i < pageCount; i++) {
const delta = isUp ? `-${i + 1}` - 0 : i + 1; const delta = isUp ? `-${i + 1}` - 0 : i + 1;
let item = { let item = {
@ -33,7 +33,8 @@ const setPlaceholderTasks = (startTime, isUp, timeGranularity, pageCount) => {
* @param {array} option.data 新拿到的任务数据 空值已经过滤过了 * @param {array} option.data 新拿到的任务数据 空值已经过滤过了
* @param {string} option.timeGranularity 颗粒度 * @param {string} option.timeGranularity 颗粒度
*/ */
const computeFillPlaceholderTaskCount = ({ tasks, data, timeGranularity }) => { const computeFillPlaceholderTaskCount = obj => {
const { tasks, data, timeGranularity } = obj;
let result = { prev: 0, next: 0 }; let result = { prev: 0, next: 0 };
// 新数据的开始时间 < 旧数据的开始时间 // 新数据的开始时间 < 旧数据的开始时间
// 超出了上限 补上限的时间刻度 // 超出了上限 补上限的时间刻度
@ -54,5 +55,5 @@ const computeFillPlaceholderTaskCount = ({ tasks, data, timeGranularity }) => {
export default { export default {
setPlaceholderTasks, setPlaceholderTasks,
computeFillPlaceholderTaskCount computeFillPlaceholderTaskCount,
}; };

47
utils/time.js

@ -12,7 +12,7 @@ import dayjs from 'dayjs';
* 格式化数字 * 格式化数字
* @param {*} n * @param {*} n
*/ */
const formatNumber = (n) => { const formatNumber = n => {
const str = n.toString(); const str = n.toString();
return str[1] ? str : `0${str}`; return str[1] ? str : `0${str}`;
}; };
@ -21,7 +21,7 @@ const formatNumber = (n) => {
* 格式化时间 * 格式化时间
* @param {number} beginTime * @param {number} beginTime
*/ */
const formatTime = (beginTime) => { const formatTime = beginTime => {
const date = new Date(beginTime); const date = new Date(beginTime);
const year = date.getFullYear(); const year = date.getFullYear();
const month = date.getMonth() + 1; const month = date.getMonth() + 1;
@ -49,7 +49,7 @@ const add = (time, num, cycle) => {
* @param {string} time * @param {string} time
* @returns {{hours: number, minutes: number}} * @returns {{hours: number, minutes: number}}
*/ */
const convertTime = (time) => { const convertTime = time => {
const arr = time.split(':'); const arr = time.split(':');
return { return {
hours: parseInt(arr[0], 10), hours: parseInt(arr[0], 10),
@ -61,7 +61,7 @@ const convertTime = (time) => {
* 将秒 -> * 将秒 ->
* @param {number} seconds * @param {number} seconds
*/ */
const secondToMinute = (seconds) => { const secondToMinute = seconds => {
const minute = formatNumber(Math.floor(seconds / 60)); const minute = formatNumber(Math.floor(seconds / 60));
const second = formatNumber(parseInt(seconds % 60, 10)); const second = formatNumber(parseInt(seconds % 60, 10));
return { return {
@ -75,7 +75,7 @@ const secondToMinute = (seconds) => {
* @param {Number} timestamp 时间戳 * @param {Number} timestamp 时间戳
* @return date:2018/10/09 time: 12:59 * @return date:2018/10/09 time: 12:59
*/ */
const setTimestampToStr = (timestamp) => { const setTimestampToStr = timestamp => {
const timeObj = new Date(timestamp); const timeObj = new Date(timestamp);
const year = timeObj.getFullYear(); const year = timeObj.getFullYear();
const month = formatNumber(timeObj.getMonth() + 1); const month = formatNumber(timeObj.getMonth() + 1);
@ -94,11 +94,10 @@ const setTimestampToStr = (timestamp) => {
* 检测时间(ms)是不是今天 * 检测时间(ms)是不是今天
* @param {Number} time 时间戳 * @param {Number} time 时间戳
*/ */
const validateTimeIsToday = (time) => { const validateTimeIsToday = time => {
const timeDate = new Date(time); const timeDate = new Date(time);
const date = new Date(); const date = new Date();
return timeDate.getFullYear() === date.getFullYear() && timeDate.getMonth() === date.getMonth() && timeDate return timeDate.getFullYear() === date.getFullYear() && timeDate.getMonth() === date.getMonth() && timeDate.getDate() === date.getDate();
.getDate() === date.getDate();
}; };
/** /**
@ -120,7 +119,7 @@ const isSame = (time, value, cycle) => {
* 如果不是今年 -> // : * 如果不是今年 -> // :
* 否则 ** : * 否则 ** :
*/ */
const formatBeginTime = (timestamp) => { const formatBeginTime = timestamp => {
const timeObj = new Date(timestamp); const timeObj = new Date(timestamp);
const year = timeObj.getFullYear(); const year = timeObj.getFullYear();
const month = formatNumber(timeObj.getMonth() + 1); const month = formatNumber(timeObj.getMonth() + 1);
@ -134,7 +133,8 @@ const formatBeginTime = (timestamp) => {
if (validateTimeIsToday(timestamp)) { if (validateTimeIsToday(timestamp)) {
// 今天 // 今天
return `今天 ${time}`; return `今天 ${time}`;
} if (currentYear !== year) { }
if (currentYear !== year) {
// 不是今年 // 不是今年
return `${date} ${time}`; return `${date} ${time}`;
} }
@ -149,7 +149,7 @@ const formatBeginTime = (timestamp) => {
* 其余的显示分钟 * 其余的显示分钟
* 超过2小时 2 * 60 * 60 * 1000 ms 转换成小时 + 分钟数 * 超过2小时 2 * 60 * 60 * 1000 ms 转换成小时 + 分钟数
*/ */
const formatDuration = (duration) => { const formatDuration = duration => {
const minuteTime = 60 * 1000; const minuteTime = 60 * 1000;
const hourTime = 60 * minuteTime; const hourTime = 60 * minuteTime;
const dayTime = 24 * hourTime; const dayTime = 24 * hourTime;
@ -159,7 +159,8 @@ const formatDuration = (duration) => {
if (duration <= 60 * 1000) { if (duration <= 60 * 1000) {
// 小于1分钟 返回几秒 // 小于1分钟 返回几秒
return `${Math.floor(duration / 1000)}`; return `${Math.floor(duration / 1000)}`;
} if (duration > dayTime) { }
if (duration > dayTime) {
// 大于1天 // 大于1天
if (minutes === 0) { if (minutes === 0) {
if (hours === 0) { if (hours === 0) {
@ -171,7 +172,8 @@ const formatDuration = (duration) => {
} }
// 分钟不是0 返回几天几时几分 // 分钟不是0 返回几天几时几分
return `${days}${hours}${minutes}`; return `${days}${hours}${minutes}`;
} if (duration > 2 * hourTime) { }
if (duration > 2 * hourTime) {
// 大于2h // 大于2h
if (minutes === 0) { if (minutes === 0) {
// 分钟是0 返回几小时 // 分钟是0 返回几小时
@ -192,7 +194,7 @@ const formatDuration = (duration) => {
* 其余的显示分钟 { days: 0, hours: 0, minutes, seconds: 0 } * 其余的显示分钟 { days: 0, hours: 0, minutes, seconds: 0 }
* 超过2小时 2 * 60 * 60 * 1000 ms 转换成{ days: 0, hours, minutes, seconds: 0 } * 超过2小时 2 * 60 * 60 * 1000 ms 转换成{ days: 0, hours, minutes, seconds: 0 }
*/ */
const formatDurationToObject = (duration) => { const formatDurationToObject = duration => {
const minuteTime = 60 * 1000; const minuteTime = 60 * 1000;
const hourTime = 60 * minuteTime; const hourTime = 60 * minuteTime;
const dayTime = 24 * hourTime; const dayTime = 24 * hourTime;
@ -247,14 +249,15 @@ const formatDurationToObject = (duration) => {
* @param {obj} 对象格式的时间 days, hours, minutes, seconds * @param {obj} 对象格式的时间 days, hours, minutes, seconds
* @return 时长的ms * @return 时长的ms
*/ */
const formatObjectTimeToMs = (days = 0, hours = 0, minutes = 0, seconds = 0) => days * 24 * 60 * 60 * 1000 + hours * 60 * 60 * 1000 + minutes * 60 * 1000 + seconds * 1000; const formatObjectTimeToMs = (days = 0, hours = 0, minutes = 0, seconds = 0) =>
days * 24 * 60 * 60 * 1000 + hours * 60 * 60 * 1000 + minutes * 60 * 1000 + seconds * 1000;
/** /**
* 计算过滤 周期 * 计算过滤 周期
* @param {string} time 周期字符串 * @param {string} time 周期字符串
* @return {string} cycle 周期英文字符串 * @return {string} cycle 周期英文字符串
*/ */
const computeCycle = (time) => { const computeCycle = time => {
// 加载下一个周期的任务 // 加载下一个周期的任务
let cycle = 'day'; let cycle = 'day';
switch (time) { switch (time) {
@ -307,7 +310,7 @@ const formatStartTimeToCycleTime = (cycle, time) => {
* @param {number} leftTime 剩余时间ms * @param {number} leftTime 剩余时间ms
* @returns { num: 显示的数字, time: 演示器演示时长 } * @returns { num: 显示的数字, time: 演示器演示时长 }
*/ */
const computeDurationText = (leftTime) => { const computeDurationText = leftTime => {
try { try {
if (leftTime < 0) { if (leftTime < 0) {
return { return {
@ -315,15 +318,7 @@ const computeDurationText = (leftTime) => {
time: null, time: null,
}; };
} }
const { const { years, months, days, hours, minutes, seconds, milliseconds } = dayjs.duration(leftTime).$d;
years,
months,
days,
hours,
minutes,
seconds,
milliseconds,
} = dayjs.duration(leftTime).$d;
let num = 0; let num = 0;
let time = 1000; let time = 1000;

Loading…
Cancel
Save