20 changed files with 1510 additions and 196 deletions
@ -1,8 +1,77 @@ |
|||
<template> |
|||
<view class="m-2" v-show="globals && globals.length"> |
|||
<u-card |
|||
@click="openCard" |
|||
:show-foot="false" |
|||
:show-head="false" |
|||
:style="{ 'max-height': globalsHeight + 'px' }" |
|||
border-radius="25" |
|||
margin="0" |
|||
> |
|||
<view slot="body"> |
|||
<scroll-view :scrollY="true" :style="{ 'max-height': globalsHeight - 30 + 'px' }"> |
|||
<skeleton :banner="false" :loading="!globals.length" :row="4" animate class="u-line-2 skeleton"></skeleton> |
|||
<view class="grid gap-2"> |
|||
<block v-for="item in globals" :key="item.id"> |
|||
<template v-if="item.plugins"> |
|||
<block v-for="(pluginArr, i) in item.plugins" :key="i"> |
|||
<template class="p-0 u-col-between" v-if="pluginArr.length"> |
|||
<Plugin |
|||
:class="[`row-span-${plugin.row}`, `col-span-${plugin.col}`]" |
|||
:task="item" |
|||
:key="plugin.pluginTaskId" |
|||
:plugin-task-id="plugin.pluginTaskId" |
|||
:plugin-id="plugin.pluginId" |
|||
:param="plugin.param" |
|||
:style-type="plugin.styleType || 0" |
|||
v-for="plugin in pluginArr" |
|||
/> |
|||
</template> |
|||
</block> |
|||
</template> |
|||
</block> |
|||
</view> |
|||
</scroll-view> |
|||
</view> |
|||
</u-card> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
<script setup> |
|||
import { computed } from 'vue'; |
|||
import { useStore } from 'vuex'; |
|||
|
|||
const store = useStore(); |
|||
const isShrink = computed(() => store.state.task.isShrink); |
|||
const sysHeight = uni.getSystemInfoSync().screenHeight; |
|||
const globals = computed(() => store.getters['task/globals']); |
|||
const globalsHeight = computed(() => [((sysHeight.value - 44 - 30 - 10) / 5) * 4]); |
|||
|
|||
// 手动展开日常任务 |
|||
function openCard() { |
|||
if (isShrink.value) { |
|||
store.commit('task/setShrink', false); |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
<style scoped lang="scss"> |
|||
.u-card-wrap { |
|||
background-color: $u-bg-color; |
|||
padding: 1px; |
|||
} |
|||
|
|||
.u-body-item { |
|||
font-size: 32rpx; |
|||
color: #333; |
|||
padding: 20rpx 10rpx; |
|||
} |
|||
|
|||
.u-body-item image { |
|||
width: 120rpx; |
|||
flex: 0 0 120rpx; |
|||
height: 120rpx; |
|||
border-radius: 8rpx; |
|||
margin-left: 12rpx; |
|||
} |
|||
</style> |
|||
|
@ -0,0 +1,137 @@ |
|||
<template> |
|||
<view class="u-font-14" style="height: 100%"> |
|||
<view v-if="data.pluginContent" @click="setStorage"> |
|||
<view |
|||
:data-did="task.detailId" |
|||
:data-param="param" |
|||
:data-pdu="task.planDuration" |
|||
:data-pid="projectId" |
|||
:data-pstart="task.planStart" |
|||
:data-rdu="task.realDuration" |
|||
:data-rid="roleId" |
|||
:data-tid="task.id" |
|||
:data-tname="task.name" |
|||
:data-token="token" |
|||
:data-rstart="task.realStart" |
|||
:data-uid="userId" |
|||
style="height: 100%" |
|||
v-html="data.pluginContent" |
|||
></view> |
|||
</view> |
|||
|
|||
<view v-else @click="setStorage"> |
|||
<!-- <plugin-default /> --> |
|||
<!-- <component :task="task" :is="pluginComponent"></component> --> |
|||
<!-- <p-task-title :task="task" v-if="pluginId === '1'" /> |
|||
<p-task-description :task="task" v-if="pluginId === '2'" /> |
|||
<p-task-duration-delay :task="task" v-if="pluginId === '3'" /> |
|||
<p-task-start-time-delay :task="task" v-if="pluginId === '4'" /> |
|||
<p-upload-deliverable :task="task" v-if="pluginId === '5' && isMine" /> |
|||
<p-delivery-history :task="task" v-if="pluginId === '5' && !isMine" /> |
|||
<p-subtasks :task="task" v-if="pluginId === '6'" /> |
|||
<p-subproject :task="task" v-if="pluginId === '7'" /> |
|||
<p-task-countdown :task="task" v-if="pluginId === '8'" /> |
|||
<p-manage-project :task="task" v-if="pluginId === '9'" /> |
|||
<p-manage-role :task="task" v-if="pluginId === '10'" /> |
|||
<p-manage-member :task="task" v-if="pluginId === '11'" /> |
|||
<p-manage-task :task="task" v-if="pluginId === '12'" /> |
|||
<p-wbs-import :task="task" v-if="pluginId === '13' || pluginId === '14'" /> |
|||
<p-deliver-check :task="task" v-if="pluginId === '15'" /> --> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { reactive, defineProps, nextTick, computed } from 'vue'; |
|||
import { useStore } from 'vuex'; |
|||
|
|||
const props = defineProps({ |
|||
task: { default: () => {}, type: Object }, |
|||
pluginId: { default: '1', type: String }, |
|||
styleType: { default: 0, type: Number }, |
|||
pluginTaskId: { default: '', type: String }, |
|||
param: { type: String, default: '' }, |
|||
}); |
|||
|
|||
const data = reactive({ pluginContent: null }); |
|||
|
|||
const store = useStore(); |
|||
const roleId = computed(() => store.state.role.roleId); |
|||
const token = computed(() => store.state.user.token); |
|||
const userId = computed(() => store.getters['user/userId']); |
|||
const projectId = computed(() => store.getters['project/projectId']); |
|||
const isMine = computed(() => store.getters['role/isMine']); |
|||
|
|||
// 插件名称 |
|||
// pluginComponent() { |
|||
// const target = this.$t.plugin.defaults.find(item => item.id === +this.pluginId); |
|||
// if (!target) return ''; |
|||
// return target.component; |
|||
// }, |
|||
|
|||
// 创建script dom |
|||
function handleDom(js) { |
|||
const domList = Array.from(document.getElementsByTagName('script')); |
|||
const index = domList.findIndex(item => item.id === `p${props.pluginTaskId}`); |
|||
if (index >= 0) { |
|||
document.body.removeChild(document.getElementById(`p${props.pluginTaskId}`)); |
|||
} |
|||
const scriptDom = document.createElement('script'); |
|||
scriptDom.id = `p${props.pluginTaskId}`; |
|||
scriptDom.setAttribute('data-type', 'plugin'); |
|||
scriptDom.innerHTML = js; |
|||
nextTick(() => { |
|||
document.body.append(scriptDom); |
|||
}); |
|||
} |
|||
|
|||
// 获取插件信息 |
|||
async function getPlugin() { |
|||
const params = { pluginId: props.pluginId, styleType: props.styleType }; |
|||
uni.$catchReq.getOtherPlugin(params, (err, data) => { |
|||
if (err) { |
|||
console.error('err: ', err); |
|||
} else { |
|||
if (!data || !data.id) return; |
|||
const reg = /data-root=["|']?(\w+)["|']?/gi; |
|||
let uuid = ''; |
|||
// FIXME: 没有兼容 只有js, 没有html的情况 |
|||
if (data.html) { |
|||
// 查有没有data-root=“xxx” 有的话 将xxx替换为 pluginTaskId |
|||
|
|||
if (reg.test(data.html)) { |
|||
uuid = RegExp.$1; |
|||
const str = data.html.replace(new RegExp(uuid, 'g'), `p${props.pluginTaskId}`); |
|||
data.pluginContent = str; |
|||
} else { |
|||
data.pluginContent = data.html; |
|||
} |
|||
|
|||
const str = data.js.replace(new RegExp(uuid, 'g'), `p${props.pluginTaskId}`); |
|||
handleDom(str); |
|||
} |
|||
} |
|||
}); |
|||
|
|||
// if (data.js) { |
|||
// if (reg.test(data.js)) { |
|||
// const uuid = RegExp.$1; |
|||
// const str = data.js.replace(new RegExp(uuid, 'g'), `p${this.pluginTaskId}`); |
|||
// this.handleDom(str); |
|||
// } else { |
|||
// this.handleDom(data.js); |
|||
// } |
|||
// } |
|||
} |
|||
|
|||
if (props.pluginId === '5') { |
|||
// 根据项目id获取成员列表 |
|||
store.dispatch('role/getAllMembers', { projectId: projectId.value }); |
|||
} |
|||
getPlugin(); |
|||
|
|||
// 点击时存储 storage |
|||
async function setStorage() { |
|||
uni.$storage.setStorageSync('roleId', roleId.value); |
|||
} |
|||
</script> |
@ -1,151 +1,134 @@ |
|||
<template> |
|||
<view class="w-full"> |
|||
<!-- 有子项目 --> |
|||
<view class="flex items-center justify-between p-3"> |
|||
<u-icon @click="openMenu(item)" class="mover" name="https://www.tall.wiki/staticrec/drag.svg" size="48"></u-icon> |
|||
|
|||
<view @click="openProject(item)" class="flex-1 px-3"> |
|||
<view class="flex items-center mb-1"> |
|||
<view class="mr-2">{{ item.name }}</view> |
|||
<!-- 状态 TODO:--> |
|||
<view class="px-2 text-xs text-green-400 bg-green-100 rounded-full flex-shrink-0">进行中</view> |
|||
</view> |
|||
|
|||
<view class="flex items-center text-xs text-gray-400"> |
|||
<view class="pr-2">{{ dayjs(item.startTime).format('MM-DD HH:mm') }}</view> |
|||
至 |
|||
<view class="pl-2">{{ dayjs(item.endTime).format('MM-DD HH:mm') }}</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 箭头 --> |
|||
<view v-if="item.sonProjectList && item.sonProjectList.length"> |
|||
<u-icon |
|||
@click="$emit('openSubProject', item.sonProjectList.length, index)" |
|||
class="text-gray-400" |
|||
name="arrow-up" |
|||
size="14px" |
|||
v-if="item.show" |
|||
></u-icon> |
|||
<u-icon |
|||
@click="$emit('openSubProject', item.sonProjectList.length, index)" |
|||
class="text-gray-400" |
|||
name="arrow-down" |
|||
size="14px" |
|||
v-else |
|||
></u-icon> |
|||
</view> |
|||
<u-icon @click="openProject(item)" class="text-gray-400" name="arrow-right" size="14px" v-else></u-icon> |
|||
</view> |
|||
|
|||
<!-- 有子项目 --> |
|||
<view class="ml-8" v-if="item.show"> |
|||
<view |
|||
:id="'cu-' + index + '-' + subIndex" |
|||
:key="subIndex" |
|||
class="cu-item flex-col" |
|||
v-for="(subItem, subIndex) in item.sonProjectList" |
|||
> |
|||
<!-- <view :key="subItem.id" v-for="subItem in item.sonProjectList"> --> |
|||
<view class="flex items-center justify-between p-3"> |
|||
<u-icon @click="openMenu(subItem)" class="mover" name="https://www.tall.wiki/staticrec/drag.svg" size="48"></u-icon> |
|||
|
|||
<view @click="openProject(subItem)" class="flex-1 px-3"> |
|||
<view class="flex items-center"> |
|||
<view class="mr-2">{{ subItem.name }}</view> |
|||
<!-- 状态 --> |
|||
<view |
|||
:class=" |
|||
subItem.status === 0 |
|||
? 'text-blue-400 bg-blue-100' |
|||
: subItem.status === 1 |
|||
? 'text-green-400 bg-green-100' |
|||
: subItem.status === 2 |
|||
? 'text-red-400 bg-red-100' |
|||
: 'text-gray-400 bg-gray-100' |
|||
" |
|||
class="px-2 text-xs text-gray-400 bg-gray-100 rounded-full 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> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, computed } from 'vue'; |
|||
import dayjs from 'dayjs'; |
|||
import { useStore } from 'vuex'; |
|||
import config from '@/common/js/config.js'; |
|||
|
|||
defineProps({ |
|||
item: { |
|||
type: Object, |
|||
default: () => {}, |
|||
}, |
|||
index: { |
|||
type: Number, |
|||
default: 0, |
|||
}, |
|||
menuList: { |
|||
type: Array, |
|||
default: () => [], |
|||
}, |
|||
}); |
|||
const emit = defineEmits(['setData']); |
|||
|
|||
const store = useStore(); |
|||
const userId = computed(() => store.getters['user/userId']); |
|||
|
|||
const data = ref({ |
|||
showMenu: false, |
|||
tips: { |
|||
text: '', |
|||
color: '#909399', |
|||
fontSize: 28, |
|||
}, |
|||
// show: false, |
|||
// border: 'border border-blue-500 shadow rounded-md', |
|||
// showBorder: false, |
|||
projectId: 0, |
|||
}); |
|||
|
|||
// 打开项目详情 |
|||
function openProject(project) { |
|||
const gateway = config.apiUrl; |
|||
const url = `${gateway}/defaultwbs`; |
|||
const { name, id } = project; |
|||
uni.navigateTo({ url: `/pages/project/project?u=${userId.value}&p=${id}&pname=${name}&url=${encodeURIComponent(url)}` }); |
|||
} |
|||
|
|||
/** |
|||
* 弹出项目操作面板 |
|||
*/ |
|||
function openMenu(project) { |
|||
data.value.showMenu = true; |
|||
data.value.projectId = project.id; |
|||
data.value.tips.text = project.name; |
|||
|
|||
emit('setData', data.value.showMenu, data.value.projectId, data.value.tips); |
|||
// this.$emit('setData', data.value.showMenu, data.value.projectId, data.value.tips); |
|||
} |
|||
</script> |
|||
|
|||
<template> |
|||
<view class="w-full"> |
|||
<!-- 有子项目 --> |
|||
<view class="flex items-center justify-between p-3"> |
|||
<u-icon @click="openMenu(item)" class="mover" name="https://www.tall.wiki/staticrec/drag.svg" size="48"></u-icon> |
|||
|
|||
<view @click="openProject(item)" class="flex-1 px-3"> |
|||
<view class="flex items-center mb-1"> |
|||
<view class="mr-2">{{ item.name }}</view> |
|||
<!-- 状态 TODO:--> |
|||
<view class="px-2 text-xs text-green-400 bg-green-100 rounded-full flex-shrink-0">进行中</view> |
|||
</view> |
|||
|
|||
<view class="flex items-center text-xs text-gray-400"> |
|||
<view class="pr-2">{{ dayjs(item.startTime).format('MM-DD HH:mm') }}</view> |
|||
至 |
|||
<view class="pl-2">{{ dayjs(item.endTime).format('MM-DD HH:mm') }}</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 箭头 --> |
|||
<view v-if="item.sonProjectList && item.sonProjectList.length"> |
|||
<u-icon @click="$emit('openSubProject', item.sonProjectList.length, index)" class="text-gray-400" name="arrow-up" size="14px" v-if="item.show"></u-icon> |
|||
<u-icon @click="$emit('openSubProject', item.sonProjectList.length, index)" class="text-gray-400" name="arrow-down" size="14px" v-else></u-icon> |
|||
</view> |
|||
<u-icon @click="openProject(item)" class="text-gray-400" name="arrow-right" size="14px" v-else></u-icon> |
|||
</view> |
|||
|
|||
<!-- 有子项目 --> |
|||
<view class="ml-8" v-if="item.show"> |
|||
<view :id="'cu-' + index + '-' + subIndex" :key="subIndex" class="cu-item flex-col" v-for="(subItem, subIndex) in item.sonProjectList"> |
|||
<!-- <view :key="subItem.id" v-for="subItem in item.sonProjectList"> --> |
|||
<view class="flex items-center justify-between p-3"> |
|||
<u-icon @click="openMenu(subItem)" class="mover" name="https://www.tall.wiki/staticrec/drag.svg" size="48"></u-icon> |
|||
|
|||
<view @click="openProject(subItem)" class="flex-1 px-3"> |
|||
<view class="flex items-center"> |
|||
<view class="mr-2">{{ subItem.name }}</view> |
|||
<!-- 状态 --> |
|||
<view |
|||
:class=" |
|||
subItem.status === 0 |
|||
? 'text-blue-400 bg-blue-100' |
|||
: subItem.status === 1 |
|||
? 'text-green-400 bg-green-100' |
|||
: subItem.status === 2 |
|||
? 'text-red-400 bg-red-100' |
|||
: 'text-gray-400 bg-gray-100' |
|||
" |
|||
class="px-2 text-xs text-gray-400 bg-gray-100 rounded-full 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> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, computed, defineProps, defineEmits } from 'vue'; |
|||
import dayjs from 'dayjs'; |
|||
import { useStore } from 'vuex'; |
|||
import config from '@/common/js/config.js'; |
|||
|
|||
defineProps({ |
|||
item: { |
|||
type: Object, |
|||
default: () => {}, |
|||
}, |
|||
index: { |
|||
type: Number, |
|||
default: 0, |
|||
}, |
|||
// menuList: { |
|||
// type: Array, |
|||
// default: () => [], |
|||
// }, |
|||
}); |
|||
const emit = defineEmits(['setData']); |
|||
|
|||
const store = useStore(); |
|||
const userId = computed(() => store.getters['user/userId']); |
|||
|
|||
const data = ref({ |
|||
showMenu: false, |
|||
tips: { |
|||
text: '', |
|||
color: '#909399', |
|||
fontSize: 28, |
|||
}, |
|||
// show: false, |
|||
// border: 'border border-blue-500 shadow rounded-md', |
|||
// showBorder: false, |
|||
projectId: 0, |
|||
}); |
|||
|
|||
// 打开项目详情 |
|||
function openProject(project) { |
|||
const gateway = config.apiUrl; |
|||
const url = `${gateway}/defaultwbs`; |
|||
const { name, id } = project; |
|||
uni.navigateTo({ url: `/pages/project/project?u=${userId.value}&p=${id}&pname=${name}&url=${encodeURIComponent(url)}` }); |
|||
} |
|||
|
|||
/** |
|||
* 弹出项目操作面板 |
|||
*/ |
|||
function openMenu(project) { |
|||
data.showMenu = true; |
|||
data.projectId = project.id; |
|||
data.tips.text = project.name; |
|||
|
|||
emit('setData', data.showMenu, data.projectId, data.tips); |
|||
// this.$emit('setData', data.showMenu, data.projectId, data.tips); |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.border-100 { |
|||
height: 4rpx; |
|||
margin: 0 20rpx; |
|||
} |
|||
.border-100 { |
|||
height: 4rpx; |
|||
margin: 0 20rpx; |
|||
} |
|||
|
|||
.border-80 { |
|||
height: 4rpx; |
|||
margin: 0 20rpx 0 90rpx; |
|||
} |
|||
.border-80 { |
|||
height: 4rpx; |
|||
margin: 0 20rpx 0 90rpx; |
|||
} |
|||
</style> |
|||
|
@ -0,0 +1,84 @@ |
|||
# skeleton组件 |
|||
|
|||
### 1.描述 |
|||
> 此组件用于加载数据时占位图显示,跟vant-ui骨架屏用法相似,但比vant-ui更灵活 |
|||
|
|||
|
|||
|
|||
### 2.用法 |
|||
|
|||
- 基本用法 |
|||
|
|||
代码: |
|||
```vue |
|||
//基本用法 |
|||
<skeleton :row="3" animate :loading="loading" > |
|||
<view> |
|||
content |
|||
</view> |
|||
</skeleton> |
|||
``` |
|||
|
|||
|
|||
- **显示 title ——通过 **title 属性显示title占位图 |
|||
|
|||
代码: |
|||
```vue |
|||
//显示 title——通过 title 属性显示title占位图 |
|||
<skeleton :row="3" title animate :loading="loading"> |
|||
<view> |
|||
content |
|||
</view> |
|||
</skeleton> |
|||
``` |
|||
|
|||
|
|||
- 显示头像(上面)——通过avatar=‘top’让头像的占位图上面显示 |
|||
|
|||
代码: |
|||
```vue |
|||
<skeleton :avatar="top" avatarAlign="left" :row="3" animate :loading="loading" style="margin-top:24rpx;"> |
|||
<view> |
|||
content |
|||
</view> |
|||
</skeleton> |
|||
``` |
|||
|
|||
|
|||
- 显示头像(左边)——通过avatar=‘left’让头像的占位图左边显示 |
|||
|
|||
代码: |
|||
```vue |
|||
<skeleton title :avatar="left" :row="3" animate :loading="loading" style="margin-top:24rpx;"> |
|||
<view> |
|||
content |
|||
</view> |
|||
</skeleton> |
|||
``` |
|||
|
|||
|
|||
- 显示banner**——通过 **banner属性显示banner占位图(只显示banner,不显示内容占位图时设置row="0") |
|||
|
|||
代码: |
|||
```vue |
|||
<skeleton banner :row="0" animate :loading="loading" style="margin-top:24rpx;"> |
|||
<view> |
|||
content |
|||
</view> |
|||
</skeleton> |
|||
``` |
|||
### |
|||
### 3. API |
|||
### Props |
|||
| **属性名** | **说明** | **类型** | **默认值** | 可取值 | |
|||
| --- | --- | --- | --- | --- | |
|||
| loading | 是否显示骨架屏 | Boolean | true | true/false | |
|||
| row | 段落行数 | Number | String | 3 | 0表示不展现 | |
|||
| rowWidth | 段落行宽度 | Boolean | Number | '100%' | | |
|||
| title | 是否显示标题 | Boolean | String | false | | |
|||
| banner | 是否显示banner | Boolean | String | false | | |
|||
| animate | 是否开启动画 | Boolean | String | false | | |
|||
| avatar | 头像位置 | Boolean | String | ''空 | left/top | |
|||
| avatarSize | 头像大小 | String | - | | |
|||
| avatarShape | 头像形状 | String | circle | circle/round | |
|||
|
@ -0,0 +1,173 @@ |
|||
<template> |
|||
<view> |
|||
<view :class="[avatarClass, animationClass]" class="lx-skeleton" v-show="loading"> |
|||
<view :class="[avatarShapeClass, bannerClass]" :style="{ width: avatarSize, height: avatarSize }" class="avatar-class"></view> |
|||
<view :style="{ width: rowWidth }" class="row"> |
|||
<view class="row-class lx-skeleton_title" v-if="title"></view> |
|||
<view :key="index" class="row-class" v-for="(item, index) in row"></view> |
|||
</view> |
|||
</view> |
|||
<slot v-if="!loading"></slot> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { computed, defineProps } from 'vue'; |
|||
/** |
|||
* skeleton 骨架屏 |
|||
* @description 用于加载数据时占位图显示,跟Vant-UI用法相似,但比Vant-UI更灵活 |
|||
* @property {Boolean} loading 是否显示骨架屏,默认为true |
|||
* @property {Number | String} row 段落行数,默认为3 |
|||
* @property {Boolean | Number} rowWidth 段落行宽度,默认为100% |
|||
* @property {Boolean | String} title 是否显示标题,默认为false |
|||
* @property {Boolean | String} banner 是否显示banner,默认为false |
|||
* @property {Boolean | String} animate 是否开启动画,默认为false |
|||
* @property {Boolean | String} avatar 头像位置 |
|||
* @property {String} avatarSize 头像大小 |
|||
* @property {String} avatarShape 头像形状,默认为circle |
|||
* |
|||
* */ |
|||
const props = defineProps({ |
|||
loading: { |
|||
type: Boolean, |
|||
default: true, |
|||
}, |
|||
row: { |
|||
type: Number, |
|||
default: 3, |
|||
}, |
|||
title: { |
|||
type: String, |
|||
default: '', |
|||
}, |
|||
avatar: { |
|||
type: String, |
|||
default: '', |
|||
}, |
|||
animate: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
avatarSize: { type: String }, |
|||
rowWidth: { |
|||
type: String, |
|||
default: '100%', |
|||
}, |
|||
avatarShape: { |
|||
type: String, |
|||
default: 'circle', |
|||
}, |
|||
banner: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
// avator-size:{ |
|||
// type: String, |
|||
// defualt: '32px' |
|||
// } |
|||
}); |
|||
|
|||
const avatarClass = computed(() => { |
|||
if (props.avatar === 'top') { |
|||
return ['lx-skeleton_avator__top']; |
|||
} |
|||
if (props.avatar === 'left') { |
|||
return ['lx-skeleton_avator__left']; |
|||
} return ''; |
|||
}); |
|||
const animationClass = computed(() => [props.animate ? 'lx-skeleton_animation' : '']); |
|||
const slotClass = computed(() => [!props.loading ? 'show' : 'hide']); |
|||
const avatarShapeClass = computed(() => [props.avatarShape == 'round' ? 'lx-skeleton_avator__round' : '']); |
|||
const bannerClass = computed(() => [props.banner ? 'lx-skeleton_banner' : '']); |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.lx-skeleton { |
|||
background-color: #fff; |
|||
padding: 12px; |
|||
} |
|||
|
|||
.lx-skeleton_avator__left { |
|||
display: flex; |
|||
width: 100%; |
|||
} |
|||
|
|||
.lx-skeleton_avator__left .avatar-class, |
|||
.lx-skeleton_avator__top .avatar-class { |
|||
background-color: #f2f3f5; |
|||
border-radius: 50%; |
|||
width: 32px; |
|||
height: 32px; |
|||
} |
|||
|
|||
.lx-skeleton_avator__left .avatar-class.lx-skeleton_avator__round, |
|||
.lx-skeleton_avator__top .avatar-class.lx-skeleton_avator__round { |
|||
border-radius: 0; |
|||
width: 32px; |
|||
height: 32px; |
|||
} |
|||
|
|||
.lx-skeleton_avator__left .avatar-class { |
|||
margin-right: 16px; |
|||
} |
|||
|
|||
.lx-skeleton_avator__top .avatar-class { |
|||
margin: 0 auto 12px auto; |
|||
} |
|||
|
|||
.row-class { |
|||
width: 100%; |
|||
height: 16px; |
|||
background-color: #f2f3f5; |
|||
margin-top: 12px; |
|||
} |
|||
|
|||
.row-class:first-child { |
|||
margin-top: 0; |
|||
} |
|||
|
|||
.row { |
|||
flex: 1; |
|||
} |
|||
|
|||
.lx-skeleton_avator__left .row { |
|||
width: calc(100% - 48px); |
|||
} |
|||
|
|||
.row-class:last-child { |
|||
width: 60%; |
|||
} |
|||
|
|||
.lx-skeleton_animation .row-class { |
|||
animation-duration: 1.5s; |
|||
animation-name: blink; |
|||
animation-timing-function: ease-in-out; |
|||
animation-iteration-count: infinite; |
|||
} |
|||
|
|||
@keyframes blink { |
|||
50% { |
|||
opacity: 0.6; |
|||
} |
|||
} |
|||
|
|||
.lx-skeleton_title { |
|||
width: 40%; |
|||
} |
|||
|
|||
.show { |
|||
display: block; |
|||
} |
|||
|
|||
.hide { |
|||
display: none; |
|||
} |
|||
|
|||
.lx-skeleton .lx-skeleton_banner { |
|||
width: 92%; |
|||
margin: 10px auto; |
|||
height: 64px; |
|||
border-radius: 0; |
|||
background-color: #f2f3f5; |
|||
} |
|||
</style> |
@ -1,8 +0,0 @@ |
|||
<template> |
|||
</template> |
|||
|
|||
<script> |
|||
</script> |
|||
|
|||
<style> |
|||
</style> |
@ -0,0 +1,81 @@ |
|||
<template> |
|||
<view |
|||
class="fixed shadow-2xl" |
|||
style="z-index: 1000" |
|||
:style="{ |
|||
left: tip.left + 'px', |
|||
top: data.height - tip.top > 110 ? tip.top + 'px' : '', |
|||
bottom: data.height - tip.top > 110 ? '' : '10px', |
|||
}" |
|||
id="u-icard" |
|||
> |
|||
<u-card :title="title" style="width: 500rpx; margin: 0 !important" v-if="tip.show" titleSize="28" :headStyle="data.headStyle" :footStyle="data.footStyle"> |
|||
<view class="" slot="body">{{ tip.text }}</view> |
|||
<view class="flex justify-end" slot="foot"> |
|||
<u-button size="mini" @click="onCancel">取消</u-button> |
|||
<u-button v-if="tip.status === 1" size="mini" @click="onChangeStatus(1)">暂停</u-button> |
|||
<u-button v-if="tip.status === 2" size="mini" @click="onChangeStatus(2)">继续</u-button> |
|||
<u-button v-if="tip.status === 1 || tip.status === 2" size="mini" @click="onChangeStatus(0)">重新开始</u-button> |
|||
<u-button v-if="tip.status === 1 || tip.status === 2" type="primary" size="mini" @click="onChangeStatus(3)">结束</u-button> |
|||
<u-button v-if="tip.status === 0 || tip.status === 3" type="primary" size="mini" @click="onChangeStatus(0)">确定</u-button> |
|||
</view> |
|||
</u-card> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { useStore, defineProps, onMounted, computed, reactive } from 'vuex'; |
|||
|
|||
defineProps({ title: { default: '提示', type: String } }); |
|||
|
|||
const store = useStore(); |
|||
const tip = computed(() => store.state.task.tip); |
|||
|
|||
const data = reactive({ |
|||
footStyle: { padding: '4px 15px' }, |
|||
headStyle: { paddingTop: '8px', paddingBottom: '8px' }, |
|||
height: 0, |
|||
}); |
|||
|
|||
onMounted(() => { |
|||
const system = uni.getSystemInfoSync(); |
|||
data.height = system.windowHeight; |
|||
}); |
|||
|
|||
/** |
|||
* 执行修改任务状态的动作 |
|||
* @param {number} type 状态码 0开始 1暂停 2继续 3完成 默认0 |
|||
*/ |
|||
async function onChangeStatus(type) { |
|||
try { |
|||
const param = { id: data.tip.taskId, type }; |
|||
await uni.$u.api.updateTaskType(param); |
|||
if (type === 0) { |
|||
uni.$ui.showToast('项目已重新开始'); |
|||
} else if (type === 1) { |
|||
uni.$ui.showToast('项目已暂停'); |
|||
} else if (type === 2) { |
|||
uni.$ui.showToast('项目继续'); |
|||
} else if (type === 3) { |
|||
uni.$ui.showToast('项目结束'); |
|||
} |
|||
data.tip.show = false; |
|||
// TODO: 更新界面 不要整体刷新 |
|||
// location.reload(); |
|||
// this.$router.go(0); |
|||
} catch (error) { |
|||
console.error(error); |
|||
uni.$ui.showToast(error.msg || '操作失败'); |
|||
} |
|||
} |
|||
|
|||
// 点击了取消 |
|||
function onCancel() { |
|||
store.commit('task/setTipShow', false); |
|||
} |
|||
|
|||
// 点击了确认 |
|||
// function onConfirm() { |
|||
// onCancel(); |
|||
// } |
|||
</script> |
@ -0,0 +1,133 @@ |
|||
import { computed, nextTick } from 'vue'; |
|||
import { useStore } from 'vuex'; |
|||
|
|||
export default function useGetTasks() { |
|||
const store = useStore(); |
|||
const showScrollTo = computed(() => store.state.task.showScrollTo); |
|||
const roleId = computed(() => store.state.role.roleId); |
|||
const projectId = computed(() => store.getters['project/projectId']); |
|||
const timeNode = computed(() => store.state.task.timeNode); |
|||
const timeUnit = computed(() => store.state.task.timeUnit); |
|||
|
|||
// 初始化 定期任务
|
|||
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);
|
|||
} |
|||
|
|||
/** |
|||
* 生成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, |
|||
}; |
|||
} |
|||
|
|||
/** |
|||
* 根据时间基准点和角色查找定期任务 |
|||
* @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);
|
|||
console.log('根据时间基准点和角色查找定期任务') |
|||
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);
|
|||
// }
|
|||
} |
|||
}); |
|||
} |
|||
|
|||
return { |
|||
initPlanTasks |
|||
} |
|||
} |
@ -0,0 +1,449 @@ |
|||
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'); |
|||
} |
|||
|
|||
|
|||
|
|||
} |
Loading…
Reference in new issue