9 changed files with 856 additions and 34 deletions
@ -0,0 +1,122 @@ |
|||||
|
<template> |
||||
|
<!-- 时间间隔栏 --> |
||||
|
<!-- <Barrier /> --> |
||||
|
|
||||
|
<scroll-view |
||||
|
:lower-threshold="300" |
||||
|
scroll-y="true" |
||||
|
:upper-threshold="300" |
||||
|
:scroll-into-view="scrollToTaskId" |
||||
|
@scroll="scroll" |
||||
|
@scrolltolower="handleScrollBottom" |
||||
|
@scrolltoupper="handleScrollTop" |
||||
|
id="scroll" |
||||
|
> |
||||
|
<!-- 时间轴 --> |
||||
|
<!-- <u-divider bg-color="#f3f4f6" class="pt-5" fontSize="14px" v-if="topEnd">到顶啦</u-divider> --> |
||||
|
|
||||
|
<!-- <TimeBox /> --> |
||||
|
|
||||
|
<!-- <u-divider bg-color="#f3f4f6" class="pb-5" fontSize="14px" v-if="bottomEnd">到底啦</u-divider> --> |
||||
|
</scroll-view> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { reactive, computed, defineEmits } from 'vue'; |
||||
|
import { useStore } from 'vuex'; |
||||
|
// import Barrier from './component/Barrier.vue'; |
||||
|
import dayjs from 'dayjs'; |
||||
|
import TimeBox from './component/TimeBox.vue'; |
||||
|
|
||||
|
const store = useStore(); |
||||
|
// const visibleRoles = computed(() => store.state.role.visibleRoles); |
||||
|
// const scrollTop = computed(() => store.state.task.scrollTop); |
||||
|
const tasks = computed(() => store.state.task.tasks); |
||||
|
const topEnd = computed(() => store.state.task.topEnd); |
||||
|
const bottomEnd = computed(() => store.state.task.bottomEnd); |
||||
|
const showSkeleton = computed(() => store.state.task.showSkeleton); |
||||
|
const timeNode = computed(() => store.state.task.timeNode); |
||||
|
const scrollToTaskId = computed(() => store.state.task.scrollToTaskId); |
||||
|
const timeGranularity = computed(() => store.getters['task/timeGranularity']); |
||||
|
const emit = defineEmits(['getTasks']); |
||||
|
|
||||
|
const data = reactive({ top: 0 }); |
||||
|
|
||||
|
// 滚动 |
||||
|
function scroll(e) { |
||||
|
data.top = e.detail.scrollTop; |
||||
|
store.commit('task/setShrink', data.top > data.scrollTop); |
||||
|
store.commit('task/setScrollTop', data.top); |
||||
|
} |
||||
|
|
||||
|
// 滚动到顶部 |
||||
|
async function handleScrollTop() { |
||||
|
if (!tasks.value || !tasks.value.length || showSkeleton.value) return; |
||||
|
const startTime = tasks.value[0].planStart - 0; |
||||
|
if (topEnd.value) { |
||||
|
// 没有数据时 自动加载数据 |
||||
|
console.warn('滚动到顶部没有数据时: '); |
||||
|
const addTasks = uni.$task.setPlaceholderTasks(startTime, true, timeGranularity.value); |
||||
|
store.commit('task/setUpTasks', addTasks); |
||||
|
} else { |
||||
|
// 有数据时 |
||||
|
console.warn('滚动到顶部有数据时: '); |
||||
|
const detailId = tasks.value.findIndex(task => task.detailId); |
||||
|
const timeNodeValue = tasks.value[detailId].planStart - 0; |
||||
|
const upQuery = { |
||||
|
timeNode: timeNodeValue, |
||||
|
queryType: 0, |
||||
|
queryNum: 6, |
||||
|
}; |
||||
|
await emit('getTasks', upQuery); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 滚动到底部 |
||||
|
async function handleScrollBottom() { |
||||
|
if (!tasks.value || !tasks.value.length || showSkeleton.value) return; |
||||
|
const startTime = tasks.value[tasks.value.length - 1].planStart - 0; |
||||
|
if (bottomEnd.value) { |
||||
|
// 没有数据时 自动加载数据 |
||||
|
console.warn('滚动到底部没有数据时: '); |
||||
|
const addTasks = uni.$task.setPlaceholderTasks(startTime, false, timeGranularity.value); |
||||
|
store.commit('task/setDownTasks', addTasks); |
||||
|
} else { |
||||
|
// 时间基准点=最后一个任务的开始时间+当前时间颗粒度 |
||||
|
console.warn('滚动到底部有数据时: '); |
||||
|
const arr = []; |
||||
|
tasks.value.forEach(task => { |
||||
|
if (task.detailId) { |
||||
|
arr.push(task); |
||||
|
} |
||||
|
}); |
||||
|
const nextQueryTime = +uni.$time.add(+arr[arr.length - 1].planStart, 1, timeGranularity.value); |
||||
|
const downQuery = { |
||||
|
timeNode: nextQueryTime, |
||||
|
queryType: 1, |
||||
|
queryNum: 6, |
||||
|
}; |
||||
|
await emit('getTasks', downQuery); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 设置自动滚动位置 |
||||
|
function setScrollPosition() { |
||||
|
// 如果storage里有taskId 滚动到这个id的任务 |
||||
|
const taskId = uni.$storage.getStorageSync('taskId'); |
||||
|
if (taskId) { |
||||
|
store.commit('task/setScrollToTaskId', `a${taskId}`); |
||||
|
uni.$storage.setStorageSync('taskId', ''); // 记录后即刻清除本地存储 |
||||
|
} else { |
||||
|
const item = tasks.value.find(task => task.detailId); |
||||
|
if (item) { |
||||
|
store.commit('task/setScrollToTaskId', `a${item.id}`); |
||||
|
} else { |
||||
|
// 没有本地记录的taskId |
||||
|
// 找到当前时间基准线的任务id 记录 并滚动到当前时间基准线 |
||||
|
const task = tasks.value.find(item => dayjs(+item.planStart).isSame(timeNode.value, timeGranularity.value)); |
||||
|
task && store.commit('task/setScrollToTaskId', `a${task.id}`); // 有这个task 就记录他的id |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
@ -0,0 +1,38 @@ |
|||||
|
<!-- |
||||
|
* @Author: aBin |
||||
|
* @email: binbin0314@126.com |
||||
|
* @Date: 2021-07-19 14:22:54 |
||||
|
* @LastEditors: aBin |
||||
|
* @LastEditTime: 2021-07-20 11:46:04 |
||||
|
--> |
||||
|
<template> |
||||
|
<view class> |
||||
|
<!-- :class="{ active: cycleTasks.time.start === filter.startTime }" --> |
||||
|
<view class="cycle-time active"> |
||||
|
<!-- {{ $util.formatStartTimeToCycleTime(filter.time, cycleTasks.time.start) }} --> |
||||
|
2021年30周 |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
|
||||
|
</script> |
||||
|
<style scoped lang="scss"> |
||||
|
.cycle-time { |
||||
|
padding: 8rpx 16rpx; |
||||
|
margin-bottom: 16rpx; |
||||
|
background: #fafafc; |
||||
|
color: $uni-text-color; |
||||
|
font-size: 28rpx; |
||||
|
position: sticky; |
||||
|
top: -1px; |
||||
|
left: 0; |
||||
|
z-index: 99; |
||||
|
|
||||
|
&.active { |
||||
|
background: $uni-color-primary; |
||||
|
color: $uni-text-color-inverse; |
||||
|
} |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,177 @@ |
|||||
|
<template> |
||||
|
<view> |
||||
|
<view class="flex justify-between" style="min-width: 90px; position: relative"> |
||||
|
<u-icon custom-prefix="custom-icon" name="C-bxl-redux" size="17px"></u-icon> |
||||
|
<u-icon custom-prefix="custom-icon" name="attachment" size="21px"></u-icon> |
||||
|
<!-- <u-icon custom-prefix="custom-icon" name="moneycollect" size="20px"></u-icon> --> |
||||
|
<u-icon name="xuanxiang" custom-prefix="custom-icon" size="21px" @click="operation"></u-icon> |
||||
|
|
||||
|
<!-- 右上角 ... 弹窗 --> |
||||
|
<view class="popup border shadow-md" v-if="data.show"> |
||||
|
<!-- <view class="flex justify-center pb-3 border-b-1"> |
||||
|
<span>添加插件</span> |
||||
|
</view> --> |
||||
|
<view class="flex justify-center pb-3 border-b-1"> |
||||
|
<span @click="createTask">新建任务</span> |
||||
|
</view> |
||||
|
<view class="flex pt-3 justify-center"> |
||||
|
<span>克隆任务</span> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 遮罩 --> |
||||
|
<view class="mask" v-if="data.maskShow" @click="closeMask"></view> |
||||
|
<!-- 新建任务弹窗 --> |
||||
|
<CreateTask |
||||
|
:startTime="data.startTime" |
||||
|
:endTime="data.endTime" |
||||
|
:task="task" |
||||
|
:source="'regular'" |
||||
|
@showTime="showTime" |
||||
|
@closeMask="closeMask" |
||||
|
class="thirdPopup flex transition-transform" |
||||
|
v-if="data.createTaskShow" |
||||
|
/> |
||||
|
|
||||
|
<u-picker title="开始时间" mode="time" v-model="data.showStart" :params="data.params" @confirm="confirmStartTime"></u-picker> |
||||
|
<u-picker title="结束时间" mode="time" v-model="data.showEnd" :params="data.params" @confirm="confirmEndTime"></u-picker> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { defineProps, reactive } from 'vue'; |
||||
|
import CreateTask from '@/components/Title/components/CreateTask.vue'; |
||||
|
|
||||
|
defineProps({ task: { type: Object, default: () => {} } }); |
||||
|
|
||||
|
const data = reactive({ |
||||
|
show: false, // 右上角 ... 显示 |
||||
|
createTaskShow: false, // 新建项目显示 |
||||
|
secondShow: false, // 分享项目显示 |
||||
|
maskShow: false, // 遮罩显示 |
||||
|
showStart: false, |
||||
|
showEnd: false, |
||||
|
startTime: '', // 新建任务的开始时间 |
||||
|
endTime: '', // 新建任务的截止时间 |
||||
|
params: { |
||||
|
year: true, |
||||
|
month: true, |
||||
|
day: true, |
||||
|
hour: true, |
||||
|
minute: true, |
||||
|
second: true, |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
// 操作 |
||||
|
function operation() { |
||||
|
// this.$t.ui.showToast('操作'); |
||||
|
data.show = !data.show; |
||||
|
} |
||||
|
|
||||
|
// 新建项目 |
||||
|
function createTask() { |
||||
|
// 关闭 ... 弹窗 |
||||
|
data.show = false; |
||||
|
// 打开遮罩 |
||||
|
data.maskShow = true; |
||||
|
// 打开新建项目弹窗 |
||||
|
data.createTaskShow = true; |
||||
|
} |
||||
|
|
||||
|
// 点击遮罩,关闭弹窗 |
||||
|
function closeMask() { |
||||
|
// 关闭遮罩 |
||||
|
data.maskShow = false; |
||||
|
// 关闭分享项目弹窗 |
||||
|
data.secondShow = false; |
||||
|
// 关闭新建项目弹窗 |
||||
|
data.createTaskShow = false; |
||||
|
} |
||||
|
|
||||
|
function showTime() { |
||||
|
data.showStart = !data.showStart; |
||||
|
} |
||||
|
|
||||
|
// 选择开始时间 |
||||
|
function confirmStartTime(e) { |
||||
|
data.startTime = `${e.year}-${e.month}-${e.day} ${e.hour}:${e.minute}:${e.second}`; |
||||
|
data.showEnd = true; |
||||
|
} |
||||
|
|
||||
|
// 选择结束时间 |
||||
|
function confirmEndTime(e) { |
||||
|
data.endTime = `${e.year}-${e.month}-${e.day} ${e.hour}:${e.minute}:${e.second}`; |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.mask { |
||||
|
width: 100%; |
||||
|
height: 100vh; |
||||
|
z-index: 21; |
||||
|
position: fixed; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
background: rgba(0, 0, 0, 0.3); |
||||
|
} |
||||
|
|
||||
|
.thirdPopup { |
||||
|
background: #ffffff; |
||||
|
position: fixed; |
||||
|
left: 50%; |
||||
|
top: 50%; |
||||
|
transform: translate(-50%, -50%); |
||||
|
z-index: 33; |
||||
|
border-radius: 5px; |
||||
|
width: 90%; |
||||
|
} |
||||
|
|
||||
|
.popup { |
||||
|
width: 110px; |
||||
|
background: #fff; |
||||
|
position: absolute; |
||||
|
right: 0; |
||||
|
top: 35px; |
||||
|
z-index: 99; |
||||
|
padding: 15px 0; |
||||
|
color: black; |
||||
|
animation: opacity 1s ease-in; |
||||
|
} |
||||
|
|
||||
|
@keyframes opacity { |
||||
|
0% { |
||||
|
opacity: 0; |
||||
|
} |
||||
|
50% { |
||||
|
opacity: 0.8; |
||||
|
} |
||||
|
100% { |
||||
|
opacity: 1; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
::v-deep .u-slot-content { |
||||
|
min-width: 0; |
||||
|
} |
||||
|
::v-deep .u-dropdown__content { |
||||
|
min-height: 120px !important; |
||||
|
height: auto !important; |
||||
|
overflow-y: auto; |
||||
|
background: #fff !important; |
||||
|
transition: none !important; |
||||
|
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); |
||||
|
} |
||||
|
::v-deep .u-dropdown__menu__item .u-flex { |
||||
|
justify-content: space-between; |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
flex-wrap: nowrap; |
||||
|
border: 1px solid #afbed1; |
||||
|
padding: 0 8px; |
||||
|
} |
||||
|
::v-deep .u-dropdown__content__mask { |
||||
|
display: none; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,131 @@ |
|||||
|
<template> |
||||
|
<view class="column" v-finger:pinch="pinchHandler"> |
||||
|
<!-- v-if="tasks && tasks.length" --> |
||||
|
<view> |
||||
|
<view :key="task.id" v-for="task in tasks" :id="`a${task.id}`"> |
||||
|
<view class="flex"> |
||||
|
<!-- <TimeStatus :task="task" /> --> |
||||
|
<view class="flex items-center justify-between flex-1 ml-2 task-column"> |
||||
|
<view v-if="task.process !== 4">{{ $moment(+task.planStart).format(startTimeFormat) }}</view> |
||||
|
<view v-else>{{ $moment(+task.planStart).format('D日') }}</view> |
||||
|
|
||||
|
<!-- 任务功能菜单 --> |
||||
|
<!-- <TaskTools v-if="task.process !== 4" :task="task" /> --> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view class="border-l-2 border-gray-300 plugin"> |
||||
|
<view class="h-3" v-if="task.process === 4"></view> |
||||
|
<view class="ml-3 overflow-hidden shadow-lg task-box"> |
||||
|
<u-card :show-foot="false" :show-head="false" :style="{ height: setHeight(task.panel) }" class="h-16" margin="0" v-if="showSkeleton"> |
||||
|
<view slot="body"> |
||||
|
<view> |
||||
|
<!-- <skeleton :banner="false" :loading="true" :row="4" animate class="mt-2 u-line-2 skeleton"></skeleton> --> |
||||
|
</view> |
||||
|
</view> |
||||
|
</u-card> |
||||
|
|
||||
|
<u-card |
||||
|
@click="onClickTask(task.planStart - 0, task.id)" |
||||
|
:show-foot="false" |
||||
|
:show-head="false" |
||||
|
:style="{ height: setHeight(task.panel) }" |
||||
|
class="h-16" |
||||
|
margin="0" |
||||
|
v-if="tasks && tasks.length && task.process !== 4 && !showSkeleton" |
||||
|
> |
||||
|
<!-- 任务面板插件 --> |
||||
|
<view slot="body"> |
||||
|
<view class="p-0 u-col-between"> |
||||
|
<view :key="pIndex" v-for="(row, pIndex) in task.plugins"> |
||||
|
<view class="grid gap-2 grid-cols-1" v-if="row.length"> |
||||
|
<!-- <Plugin |
||||
|
:class="[`row-span-${plugin.row}`, `col-span-${plugin.col}`]" |
||||
|
:task="task" |
||||
|
:key="plugin.pluginTaskId" |
||||
|
:plugin-task-id="plugin.pluginTaskId" |
||||
|
:plugin-id="plugin.pluginId" |
||||
|
:param="plugin.param" |
||||
|
:style-type="data.styleType || 0" |
||||
|
v-for="plugin in row" |
||||
|
/> --> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</u-card> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
<!-- 局部弹框操作栏 --> |
||||
|
<!-- <Tips /> --> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { useStore } from 'vuex'; |
||||
|
import { computed, reactive } from 'vue'; |
||||
|
import TimeStatus from './TimeStatus.vue'; |
||||
|
import TaskTools from './TaskTools.vue'; |
||||
|
|
||||
|
// const data = reactive({ |
||||
|
// currentComponent: '', |
||||
|
// styleType: 0, |
||||
|
// }); |
||||
|
|
||||
|
const store = useStore(); |
||||
|
const roleId = computed(() => store.state.role.roleId); |
||||
|
const timeUnit = computed(() => store.state.task.timeUnit); |
||||
|
const tasks = computed(() => store.state.task.tasks); |
||||
|
const showSkeleton = computed(() => store.state.task.showSkeleton); |
||||
|
const startTimeFormat = computed(() => store.getters['task/startTimeFormat']); |
||||
|
|
||||
|
// 设置任务面板高度 |
||||
|
function setHeight(panel) { |
||||
|
if (panel && panel.height) { |
||||
|
return `${panel.height}px`; |
||||
|
} |
||||
|
return 'auto'; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 点击了定期任务的面板 更新可变的日常任务 |
||||
|
* @param {number} planStart 任务计划开始时间 |
||||
|
* @param {string} taskId 任务id |
||||
|
*/ |
||||
|
function onClickTask(planStart, taskId) { |
||||
|
const param = { roleId: roleId.value, timeNode: planStart, timeUnit: timeUnit.value }; |
||||
|
store.dispatch('task/getGlobal', param); |
||||
|
uni.$storage.setStorageSync('taskId', taskId); |
||||
|
uni.$storage.setStorageSync('roleId', roleId.value); |
||||
|
} |
||||
|
|
||||
|
function pinchHandler(evt) { |
||||
|
// evt.scale代表两个手指缩放的比例 |
||||
|
console.log(`缩放:${evt.zoom}`); |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
.task-box { |
||||
|
border-radius: 24rpx; |
||||
|
} |
||||
|
.column { |
||||
|
padding: 24px 14px; |
||||
|
} |
||||
|
.task-column { |
||||
|
height: 33px; |
||||
|
} |
||||
|
.plugin { |
||||
|
margin-top: 8px; |
||||
|
margin-bottom: 8px; |
||||
|
margin-left: 15px; |
||||
|
} |
||||
|
::v-deep .ml-2 { |
||||
|
margin-left: 16px; |
||||
|
} |
||||
|
|
||||
|
::v-deep .ml-3 { |
||||
|
margin-left: 20px; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,316 @@ |
|||||
|
<template> |
||||
|
<view class="u-font-14"> |
||||
|
<view |
||||
|
class="flex items-center justify-center rounded-full icon-column" |
||||
|
:style="{ color: orderStyle.color }" |
||||
|
@click="changeStatus(task.process, $event)" |
||||
|
> |
||||
|
<!-- 1进行中 2暂停中 3已完成 --> |
||||
|
<u-circle-progress |
||||
|
:percent="orderStyle.persent - 0" |
||||
|
:active-color="orderStyle.color" |
||||
|
bg-color="rgba(255,255,255,0)" |
||||
|
border-width="4" |
||||
|
:width="task.process !== 4 ? 66 : 50" |
||||
|
v-if="task.process === 1 || task.process === 2 || task.process === 3" |
||||
|
> |
||||
|
<view class="u-progress-content"> |
||||
|
<view class="u-progress-dot"></view> |
||||
|
<view class="u-progress-info"> |
||||
|
<u-icon :name="orderStyle.icon" v-if="orderStyle.icon" size="15px"></u-icon> |
||||
|
<template v-else>{{ data.durationText }}</template> |
||||
|
</view> |
||||
|
</view> |
||||
|
</u-circle-progress> |
||||
|
<!-- 0未开始 4添加任务 --> |
||||
|
<view class="flex items-center justify-center rounded-full progress-box" v-else :class="task.process === 4 ? 'progress-box-4' : ''"> |
||||
|
<view class="u-progress-content"> |
||||
|
<view class="u-progress-dot"></view> |
||||
|
<view class="u-progress-info"> |
||||
|
<span v-if="orderStyle.icon"> |
||||
|
<u-icon :name="orderStyle.icon" v-if="task.process !== 4" size="15px"></u-icon> |
||||
|
<u-icon :name="orderStyle.icon" v-else size="15px"></u-icon> |
||||
|
</span> |
||||
|
<template v-else>{{ data.durationText }}</template> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 遮罩 --> |
||||
|
<view class="mask" v-if="data.maskShow" @click="closeMask"></view> |
||||
|
<!-- 新建任务弹窗 --> |
||||
|
<CreateTask |
||||
|
:startTime="data.startTime" |
||||
|
:endTime="data.endTime" |
||||
|
:task="task" |
||||
|
:source="'regular'" |
||||
|
@showTime="showTime" |
||||
|
@closeMask="closeMask" |
||||
|
class="thirdPopup flex transition-transform" |
||||
|
v-if="data.createTaskShow" |
||||
|
/> |
||||
|
|
||||
|
<u-picker title="开始时间" mode="time" v-model="data.showStart" :params="data.params" @confirm="confirmStartTime"></u-picker> |
||||
|
<u-picker title="结束时间" mode="time" v-model="data.showEnd" :params="data.params" @confirm="confirmEndTime"></u-picker> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { reactive, onMounted, defineProps, computed } from 'vue'; |
||||
|
import { useStore } from 'vuex'; |
||||
|
import CreateTask from '../../Title/components/CreateTask.vue'; |
||||
|
|
||||
|
const props = defineProps({ task: { type: Object, default: () => {} } }); |
||||
|
|
||||
|
const data = reactive({ |
||||
|
time: '', |
||||
|
start: [{ text: '确认开始任务', color: 'blue' }], |
||||
|
pause: [{ text: '继续' }, { text: '重新开始任务', color: 'blue' }, { text: '结束' }], |
||||
|
proceed: [{ text: '暂停' }, { text: '重新开始任务', color: 'blue' }, { text: '结束' }], |
||||
|
again: [{ text: '重新开始任务', color: 'blue' }], |
||||
|
timer: null, |
||||
|
durationText: 0, |
||||
|
maskShow: false, // 遮罩显示 |
||||
|
createTaskShow: false, // 新建项目显示 |
||||
|
startTime: '', // 新建任务的开始时间 |
||||
|
endTime: '', // 新建任务的截止时间 |
||||
|
showStart: false, |
||||
|
showEnd: false, |
||||
|
params: { |
||||
|
year: true, |
||||
|
month: true, |
||||
|
day: true, |
||||
|
hour: true, |
||||
|
minute: true, |
||||
|
second: true, |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
const store = useStore(); |
||||
|
const tip = computed(() => store.state.task.tip); |
||||
|
const status = computed(() => [props.task ? props.task.process : 0]); |
||||
|
const taskName = computed(() => [props.task ? props.task.name : '']); |
||||
|
const taskId = computed(() => [props.task ? props.task.id : '']); |
||||
|
|
||||
|
// 计算圆环的弧度百分比 |
||||
|
function computeCyclePersent() { |
||||
|
if (!props.task || !props.task.realStart || !props.task.planDuration) return 100; |
||||
|
const { realStart, planDuration } = props.task; |
||||
|
return (((Date.now() - +realStart) * 100) / +planDuration).toFixed(2); |
||||
|
} |
||||
|
|
||||
|
const orderStyle = computed(() => { |
||||
|
// 图标文本颜色 |
||||
|
// 任务状态 0未开始 1进行中 2暂停中 3已完成 |
||||
|
let color = '#9CA3AF'; |
||||
|
let icon = 'play-right-fill'; |
||||
|
let persent = 100; |
||||
|
switch (status.value) { |
||||
|
case 1: // 进行中 |
||||
|
color = '#60A5FA'; |
||||
|
icon = ''; |
||||
|
if (+computeCyclePersent() > 100) { |
||||
|
persent = 96; |
||||
|
} else { |
||||
|
persent = computeCyclePersent(); |
||||
|
} |
||||
|
break; |
||||
|
case 2: // 暂停中 |
||||
|
color = '#F87171'; |
||||
|
icon = 'pause'; |
||||
|
persent = 50; // TODO: 暂时这样 暂停状态没有计算剩余多少时间 |
||||
|
break; |
||||
|
case 3: // 已结束 |
||||
|
color = '#34D399'; |
||||
|
icon = 'checkmark'; |
||||
|
persent = 100; |
||||
|
break; |
||||
|
case 4: // 添加任务 |
||||
|
color = '#60A5FA'; |
||||
|
icon = 'plus'; |
||||
|
persent = 100; |
||||
|
break; |
||||
|
default: |
||||
|
// 未开始 |
||||
|
color = '#9CA3AF'; |
||||
|
icon = 'play-right'; |
||||
|
persent = 100; |
||||
|
break; |
||||
|
} |
||||
|
return { color, icon, persent }; |
||||
|
}); |
||||
|
|
||||
|
// unMounted(() => { |
||||
|
// if (data.timer) { |
||||
|
// clearInterval(data.timer); |
||||
|
// data.timer = null; |
||||
|
// } |
||||
|
// }); |
||||
|
|
||||
|
/** |
||||
|
* 计算tip的标题内容 |
||||
|
*/ |
||||
|
function genetateTips(type, content) { |
||||
|
if (type === 0) { |
||||
|
return `确认开始任务"${content}"吗?`; |
||||
|
} |
||||
|
if (type === 3) { |
||||
|
return '是否要重新开始此任务'; |
||||
|
} |
||||
|
return '请选择要执行的操作'; |
||||
|
} |
||||
|
|
||||
|
// 新建任务 |
||||
|
function addTask() { |
||||
|
// uni.$ui.showToast('新建任务'); |
||||
|
// 打开遮罩 |
||||
|
data.maskShow = true; |
||||
|
// 打开新建项目弹窗 |
||||
|
data.createTaskShow = true; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 点击了图标 修改任务状态 |
||||
|
* @param {object} event |
||||
|
*/ |
||||
|
function changeStatus(process, event) { |
||||
|
if (process === 4) { |
||||
|
addTask(); |
||||
|
return; |
||||
|
} |
||||
|
// return false; |
||||
|
tip.status = status; |
||||
|
tip.taskId = taskId; |
||||
|
tip.left = event.target.x; |
||||
|
tip.top = event.target.y; |
||||
|
tip.show = true; |
||||
|
tip.text = genetateTips(status, taskName); |
||||
|
store.commit('task/setTip', tip); |
||||
|
} |
||||
|
|
||||
|
// 点击遮罩,关闭弹窗 |
||||
|
function closeMask() { |
||||
|
// 关闭遮罩 |
||||
|
data.maskShow = false; |
||||
|
// 关闭新建项目弹窗 |
||||
|
data.createTaskShow = false; |
||||
|
} |
||||
|
|
||||
|
function showTime(type) { |
||||
|
if (type === 1) { |
||||
|
data.showStart = !data.showStart; |
||||
|
} else { |
||||
|
data.showEnd = !data.showEnd; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 选择开始时间 |
||||
|
function confirmStartTime(e) { |
||||
|
data.startTime = `${e.year}-${e.month}-${e.day} ${e.hour}:${e.minute}:${e.second}`; |
||||
|
data.showEnd = true; |
||||
|
} |
||||
|
|
||||
|
// 选择结束时间 |
||||
|
function confirmEndTime(e) { |
||||
|
data.endTime = `${e.year}-${e.month}-${e.day} ${e.hour}:${e.minute}:${e.second}`; |
||||
|
} |
||||
|
|
||||
|
// 计算进行中状态剩余时间 |
||||
|
// 预计结束时间 = realStart(实际开始) + planDuration(计划时长) |
||||
|
// 剩余时间 = 预计结束时间 - 当前时间 |
||||
|
// 剩余时间 = realStart + planDuration - Date.now() |
||||
|
function computeDurationText() { |
||||
|
const { realStart, planDuration } = props.task; |
||||
|
const leftTime = +realStart + +planDuration - Date.now(); // 剩余时间 |
||||
|
const { num, time } = uni.$time.computeDurationText(leftTime); |
||||
|
if (num <= 0) { |
||||
|
clearInterval(data.timer); |
||||
|
data.timer = null; |
||||
|
} |
||||
|
data.durationText = num; |
||||
|
return time; |
||||
|
} |
||||
|
|
||||
|
function updateDurationText(time) { |
||||
|
if (data.timer) { |
||||
|
clearInterval(data.timer); |
||||
|
data.timer = null; |
||||
|
} |
||||
|
if (!time) return; |
||||
|
setInterval(() => { |
||||
|
computeDurationText(); |
||||
|
}, time); |
||||
|
} |
||||
|
|
||||
|
onMounted(() => { |
||||
|
// TODO: 计算在不在窗口内显示 |
||||
|
const time = computeDurationText(); |
||||
|
updateDurationText(time); |
||||
|
}); |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
.icon-column { |
||||
|
height: 33px; |
||||
|
width: 33px; |
||||
|
} |
||||
|
.one { |
||||
|
height: 33px; |
||||
|
width: 33px; |
||||
|
} |
||||
|
|
||||
|
.progress-box { |
||||
|
background: rgba(255, 255, 255, 0); |
||||
|
width: 33px; |
||||
|
height: 33px; |
||||
|
border: 2px solid #9ca3af; |
||||
|
} |
||||
|
|
||||
|
.progress-box-4 { |
||||
|
width: 25px; |
||||
|
height: 25px; |
||||
|
border: 2px solid #60a5fa; |
||||
|
} |
||||
|
|
||||
|
.mask { |
||||
|
width: 100%; |
||||
|
height: 100vh; |
||||
|
z-index: 21; |
||||
|
position: fixed; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
background: rgba(0, 0, 0, 0.3); |
||||
|
} |
||||
|
|
||||
|
.thirdPopup { |
||||
|
background: #ffffff; |
||||
|
position: fixed; |
||||
|
left: 50%; |
||||
|
top: 50%; |
||||
|
transform: translate(-50%, -50%); |
||||
|
z-index: 33; |
||||
|
border-radius: 5px; |
||||
|
width: 90%; |
||||
|
} |
||||
|
|
||||
|
::v-deep .u-dropdown__content { |
||||
|
min-height: 120px !important; |
||||
|
height: auto !important; |
||||
|
overflow-y: auto; |
||||
|
background: #fff !important; |
||||
|
transition: none !important; |
||||
|
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); |
||||
|
} |
||||
|
::v-deep .u-dropdown__menu__item .u-flex { |
||||
|
justify-content: space-between; |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
flex-wrap: nowrap; |
||||
|
border: 1px solid #afbed1; |
||||
|
padding: 0 8px; |
||||
|
} |
||||
|
::v-deep .u-dropdown__content__mask { |
||||
|
display: none; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,7 @@ |
|||||
|
<!-- |
||||
|
* @Author: aBin |
||||
|
* @email: binbin0314@126.com |
||||
|
* @Date: 2021-07-19 15:40:02 |
||||
|
* @LastEditors: aBin |
||||
|
* @LastEditTime: 2021-07-19 15:40:03 |
||||
|
--> |
Loading…
Reference in new issue