Browse Source

feat: 使用uniapp完成打卡插件(包括详情页)

uni
xuesinan 3 years ago
parent
commit
7f14dabe4b
  1. 3
      CHANGELOG.md
  2. 12
      apis/plugin.js
  3. 4
      common/styles/tailwind.scss
  4. 87
      components/Plugin/Plugin.vue
  5. 731
      components/PrettyExchange/PrettyExchange - 副本.vue
  6. 693
      components/PrettyExchange/PrettyExchange222.vue
  7. 234
      components/SearchPopup/SearchPopup.vue
  8. 126
      components/TimeLine 复制/TimeLine.vue
  9. 38
      components/TimeLine 复制/component/Barrier.vue
  10. 177
      components/TimeLine 复制/component/TaskTools.vue
  11. 132
      components/TimeLine 复制/component/TimeBox.vue
  12. 317
      components/TimeLine 复制/component/TimeStatus.vue
  13. 0
      components/TimeLine 复制/component/Title.vue
  14. 476
      hooks/project/useGetTasks - 副本 (2).js
  15. 343
      hooks/project/useGetTasks - 副本 (3).js
  16. 263
      hooks/project/useGetTasks - 副本.js
  17. 336
      hooks/project/useGetTasks222.js
  18. 6
      pages.json
  19. 26
      pages/detail/detail.vue
  20. 142
      pages/project/project 复制.vue
  21. 66
      pages/submitLog/submitLog - 副本.vue
  22. 395
      plugins/p-check-work/detail.vue
  23. 165
      plugins/p-check-work/p-check-work.vue
  24. 1
      store/index.js

3
CHANGELOG.md

@ -1,4 +1,4 @@
# 1.0.0 (2022-09-09)
# 1.0.0 (2022-09-14)
### 🌟 新功能
范围|描述|commitId
@ -83,6 +83,7 @@
- | 项目列表新 | [88cf48d](https://101.201.226.163:50022/ccsens_tall/TALL-MUI-4/commits/88cf48d)
- | 小红点显示逻辑 | [11923f3](https://101.201.226.163:50022/ccsens_tall/TALL-MUI-4/commits/11923f3)
- | 小绿点隐藏 | [31f3dc7](https://101.201.226.163:50022/ccsens_tall/TALL-MUI-4/commits/31f3dc7)
- | 修改一些东西 | [5b577b0](https://101.201.226.163:50022/ccsens_tall/TALL-MUI-4/commits/5b577b0)
- | 引导页、广告页 | [4aa76ff](https://101.201.226.163:50022/ccsens_tall/TALL-MUI-4/commits/4aa76ff)
- | 隐藏软键盘 | [919a44e](https://101.201.226.163:50022/ccsens_tall/TALL-MUI-4/commits/919a44e)
- | 域名配置 | [b68272d](https://101.201.226.163:50022/ccsens_tall/TALL-MUI-4/commits/b68272d)

12
apis/plugin.js

@ -38,4 +38,16 @@ export function setupPlugin(app) {
uni.$u.api.checkDeliver = (param, url) => uni.$u.post(`${url || domain.value}/deliver/checkDeliver`, param);
// 查看检查记录
uni.$u.api.queryCheckLog = param => uni.$u.post(`${domain.value}/deliver/queryCheckLog`, param);
/**
* 考勤api
*/
// 批量查询打卡信息
uni.$u.api.clockQuery = (params, url) => uni.$u.post(`${url ? url : domain.value}/clock/query`, params);
// 打卡
uni.$u.api.clockPunch = (params, url) => uni.$u.post(`${url ? url : domain.value}/clock/punch`, params);
// 审核
uni.$u.api.clockAudit = (params, url) => uni.$u.post(`${url ? url : domain.value}/clock/audit`, params);
}

4
common/styles/tailwind.scss

@ -4676,4 +4676,8 @@
.list-outside {
list-style-position: outside;
}
.line-through {
text-decoration: line-through;
}

87
components/Plugin/Plugin.vue

@ -1,51 +1,56 @@
<template>
<view class="u-font-14 rounded-md bg-white relative" style="height: 100%" @click="setStorage">
<u-badge :is-dot="true" :offset="[0, 0]" v-show="pluginInfo && pluginInfo.remindNum > 0"></u-badge>
<template v-if="pluginId != '26'">
<view class="u-font-14 rounded-md bg-white relative shadow-lg" style="height: 100%" @click="setStorage">
<u-badge :is-dot="true" :offset="[0, 0]" v-show="pluginInfo && pluginInfo.remindNum > 0"></u-badge>
<!-- <plugin-default /> -->
<!-- <component :task="task" :is="pluginComponent"></component> -->
<p-task-title :task="task" v-if="pluginId === '1'" class="p-2" />
<!-- <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'" /> -->
<!-- <plugin-default /> -->
<!-- <component :task="task" :is="pluginComponent"></component> -->
<p-task-title :task="task" v-if="pluginId === '1'" class="p-2" />
<!-- <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 v-else-if="pluginId === '15'" /> -->
<p-deliver-second v-else-if="pluginId === '15'" />
<!-- 交付物插件 -->
<!-- <p-deliver v-else-if="pluginId === '15'" /> -->
<p-deliver-second v-else-if="pluginId === '15'" />
<p-source-manage v-else-if="pluginId === '16'" class="p-2" />
<p-finance-audit v-else-if="pluginId === '17'" class="p-2" />
<p-finance v-else-if="pluginId === '18'" class="p-2" />
<p-source-manage v-else-if="pluginId === '16'" class="p-2" />
<p-finance-audit v-else-if="pluginId === '17'" class="p-2" />
<p-finance v-else-if="pluginId === '18'" class="p-2" />
<!-- 个人和终端按钮-->
<!-- <p-account-management /> -->
<p-account-management v-else-if="pluginId === '19'" class="p-2" />
<p-domain-source-manage v-else-if="pluginId === '20'" class="p-2" />
<p-project-version-management v-else-if="pluginId === '21'" class="p-2" />
<!-- 个人和终端按钮-->
<!-- <p-account-management /> -->
<p-account-management v-else-if="pluginId === '19'" class="p-2" />
<p-domain-source-manage v-else-if="pluginId === '20'" class="p-2" />
<p-project-version-management v-else-if="pluginId === '21'" class="p-2" />
<!-- 任务名和跳转详情页箭头 -->
<p-task-to-detail :task="task" v-else-if="pluginId === '24'" class="p-2"></p-task-to-detail>
<!-- 任务名和跳转详情页箭头 -->
<p-task-to-detail :task="task" v-else-if="pluginId === '24'" class="p-2"></p-task-to-detail>
<Render
v-else
:task="task"
:pluginId="pluginId"
:styleType="styleType"
:pluginTaskId="pluginTaskId"
:businessPluginId="businessPluginId"
:param="param"
/>
</view>
<!-- 考勤插件 -->
<p-check-work :task="task" v-else-if="pluginId === '1485171846022434817'"></p-check-work>
<Render
v-else
:task="task"
:pluginId="pluginId"
:styleType="styleType"
:pluginTaskId="pluginTaskId"
:businessPluginId="businessPluginId"
:param="param"
/>
</view>
</template>
</template>
<script setup>

731
components/PrettyExchange/PrettyExchange - 副本.vue

@ -1,731 +0,0 @@
<template>
<view>
<scroll-view scroll-y="true">
<view>
<view
:id="'cu-' + index"
class="cu-item flex-col"
v-for="(item, index) in data.itemList"
:key="item.id"
:style="{ 'background-color': item.color }"
@touchend="stops($event, index)"
@touchmove.stop.prevent="move"
@touchstart="start($event, index)"
>
<!-- <view class="border-100 bg-blue-500" v-if="item.showTopBorder"></view> -->
<view class="w-full" :style="{background: item.styleColor}">
<!-- 有子项目 父项目 -->
<view class="flex items-center justify-between p-3">
<u-icon @click="openMenu(item, index)" 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" :class="{'mb-1': index > 0}">
<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">{{item.status === 1 ? '进行中' : item.status === 2 ? '已结束' : item.status === 0 ? '未开始' : '暂停'}}</view>
</view>
<view v-if="index > 0" 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 class="workbench-btn" v-if="index === 0" @click="toWorkbench">工作台</view>
<view class="remind-box bg-red-500 text-white text-xs" v-if="item.remindNum">{{ item.remindNum > 99 ? '99+' : item.remindNum }}</view>
<!-- 箭头 -->
<view v-if="item.sonProjectList && item.sonProjectList.length">
<u-icon
@click="openSubProject(item.sonProjectList.length, index)"
class="text-gray-400"
name="arrow-up"
size="14px"
v-if="item.show"
></u-icon>
<u-icon
@click="openSubProject(item.sonProjectList.length, index)"
class="text-gray-400"
name="arrow-down"
size="14px"
v-else
></u-icon>
</view>
<u-icon @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"
@touchend.stop.prevent="stops($event, index + '-' + subIndex, item.sonProjectList.length)"
@touchmove.stop.prevent="move($event, item.sonProjectList.length)"
@longpress.stop.prevent="start($event, index + '-' + 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 w-full">
<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>
<view class="border-100 bg-blue-500" v-if="item.showBorder"></view>
<view class="border-80 bg-blue-500" v-if="item.showSubBorder"></view>
</view>
</view>
</scroll-view>
<!-- 移动悬浮 begin -->
<view v-if="data.showMoveImage">
<view :style="{ left: data.moveLeft + 'px', top: data.moveTop + 'px' }" class="cu-item absolute">
<ProjectItem class="w-full" :item="data.moveItem" />
</view>
</view>
<!-- 移动悬浮 end -->
<!-- 项目操作面板 -->
<u-action-sheet :list="data.menuList" :tips="data.tips" @click="chooseAction" v-model="data.showMenu" :cancel-btn="false"></u-action-sheet>
</view>
</template>
<script setup>
import { reactive, onMounted, watchEffect, computed } from 'vue';
import { useStore } from 'vuex';
import dayjs from 'dayjs';
import ProjectItem from '@/components/Projects/ProjectItem.vue';
const store = useStore();
const projects = computed(() => store.state.project.projects);
const remindData = computed(() => store.state.socket.remindData);
const userId = computed(() => store.getters['user/userId']);
const data = reactive({
// itemTop: 0,
// itemLeft: 0,
itemHeight: 0, //
itemWidth: 0, //
subItemHeight: 0, //
showMoveImage: false,
moveItem: '', //
moveLeft: 0, //
moveTop: 0, //
deltaLeft: 0,
deltaTop: 0,
beginleft: 0, //
begintop: 0, //
itemList: [], //
setSubItem: false, //
changeEvent: false, //
showMenu: false,
tips: { text: '', color: '#909399', fontSize: 28 },
clickProject: {},
projectId: 0,
// menuList: [{ text: '' }, { text: '' }, { text: '' }, { text: '' }, { text: '' }],
menuList: [{ text: '导入' }, { text: '导出' }, { text: '删除' }],
// show: false,
// border: 'border border-blue-500 shadow rounded-md',
// showBorder: false, //
showItemIndex: undefined,
isStartMove: 0, //
});
const emit = defineEmits(['changeHeight', 'change']);
//
watchEffect(() => {
if (projects.value) {
data.itemList = projects.value;
data.itemList.forEach(item => {
item.showBorder = false; //
item.showSubBorder = false; //
item.showTopBorder = false; //
item.remindNum = 0;
if (remindData.value) {
remindData.value.forEach(remind => {
const remind_data = JSON.parse(remind.data);
if (remind_data.data.projectId === item.id) {
item.remindNum++;
}
});
}
});
}
});
onMounted(() => {
data.itemList = projects.value;
data.itemList.forEach(item => {
item.showBorder = false; //
item.showSubBorder = false; //
item.showTopBorder = false; //
});
});
//
function openSubProject(length, index) {
store.commit('project/setProjectItemShow', { index, show: !data.itemList[index].show });
if (length && index) {
emit('changeHeight', length, index);
}
data.showItemIndex = index;
}
//
function getDate() {
const query = uni
.createSelectorQuery()
.select('#cu-0')
.fields(
{
id: true,
dataset: true,
rect: true,
size: true,
},
res => {
data.begintop = res.top;
data.beginleft = res.left;
},
)
.exec();
}
// function setData(flag, project, tips) {
// data.showMenu = flag;
// data.projectId = project.id;
// data.tips = tips;
// data.clickProject = project;
// }
function chooseAction(e) {
const obj = {
index: e,
projectId: data.projectId,
url: data.clickProject.url,
projectName: data.tips.text
};
// emit('chooseAction', data);
actionFun(obj);
}
//
function actionFun(obj) {
const action = data.menuList[obj.index].text;
// if (action === '') {
// data.changeEvent = true;
// uni.$ui.showToast('');
// }
if (action === '删除') {
// data.changeEvent = false;
delProject(obj.projectId, obj.url);
}
if (action === '导入') {
// data.changeEvent = false;
store.commit('setDomain', obj.url);
importProject(obj.projectId, obj.projectName);
}
if (action === '导出') {
// data.changeEvent = false;
exportProject(obj.projectId, obj.url);
}
if (data.showItemIndex !== undefined) {
store.commit('project/setProjectItemShow', {
index: data.showItemIndex,
show: true,
});
}
}
function isNumber(val) {
return val === +val;
}
function start(e, index) {
console.log('开始', e);
data.isStartMove = 1;
setTimeout(() => {
getDate();
}, 300);
if (isNumber(index)) {
//
data.setSubItem = false;
const query = uni
.createSelectorQuery()
.select(`#cu-${index}`)
.fields(
{
id: true,
dataset: true,
rect: true,
size: true,
},
res => {
data.moveTop = res.top;
data.moveLeft = res.left;
data.moveItem = data.itemList[index];
data.itemWidth = res.width;
data.itemHeight = res.height;
},
)
.exec();
} else {
//
const arr = index.split('-');
data.setSubItem = true;
const query = uni.createSelectorQuery();
query
.select(`#cu-${arr[0] - 0}`)
.fields(
{
id: true,
dataset: true,
rect: true,
size: true,
},
res => {
data.itemHeight = res.height;
},
)
.exec();
query
.select(`#cu-${index}`)
.fields(
{
id: true,
dataset: true,
rect: true,
size: true,
},
res => {
console.log('res', res)
if (res) {
data.moveTop = res.top;
data.moveLeft = res.left;
data.itemWidth = res.width;
data.subItemHeight = res.height;
}
data.moveItem = data.itemList[arr[0] - 0].sonProjectList[arr[1] - 0];
},
)
.exec();
}
}
function move(e, length) {
if (!data.isStartMove) return false;
console.log('移动');
data.showMoveImage = true; //
const touch = e.touches[0];
if (data.deltaLeft == 0) {
//
data.deltaLeft = touch.pageX - data.moveLeft;
data.deltaTop = touch.pageY - data.moveTop;
}
data.moveLeft = touch.pageX - data.deltaLeft;
data.moveTop = touch.pageY - data.deltaTop;
const lastIndex = findOverIndex(touch.pageY, length);
// 线
for (let i = 0; i < data.itemList.length; i++) {
if (data.moveLeft > 35) {
data.itemList[i].showBorder = false;
data.itemList[i].showTopBorder = false;
if (i === lastIndex) {
data.itemList[i].showSubBorder = true;
} else {
data.itemList[i].showSubBorder = false;
}
} else if (lastIndex === -1) {
data.itemList[0].showTopBorder = true;
data.itemList[i].showSubBorder = false;
data.itemList[i].showBorder = false;
} else {
data.itemList[i].showSubBorder = false;
data.itemList[i].showTopBorder = false;
if (i === lastIndex) {
data.itemList[i].showBorder = true;
} else {
data.itemList[i].showBorder = false;
}
}
}
}
function stops(e, index, length) {
console.log('结束', e, index);
data.isStartMove = 0;
const touch = e.changedTouches[0];
const lastIndex = findOverIndex(touch.pageY, length);
//
for (let i = 0; i < data.itemList.length; i++) {
//
if (data.itemList[i].showTopBorder) {
if (isNumber(index)) {
const Value = data.itemList[index];
data.itemList.unshift(Value);
data.itemList.splice(index + 1, 1);
} else {
const arr = index.split('-');
const Value = data.itemList[arr[0] - 0].sonProjectList[arr[1] - 0];
data.itemList.unshift(Value);
data.itemList[arr[0] - 0].sonProjectList.splice([arr[1] - 0], 1);
// const options = {
// id: Value.id,
// parentId: 0,
// };
const options = {
businessCode: Value.businessCode,
moveProjectId: Value.id,
targetProjectId: '',
};
emit('change', options);
}
//
clearSet(i);
emit('change', data.itemList);
return;
}
//
if (data.itemList[i].showBorder) {
if (isNumber(index)) {
const Value = data.itemList[index];
data.itemList.splice(i + 1, 0, Value);
if (i < index) {
data.itemList.splice(index + 1, 1);
} else {
data.itemList.splice(index, 1);
}
} else {
const arr = index.split('-');
const Value = data.itemList[arr[0] - 0].sonProjectList[arr[1] - 0];
data.itemList[arr[0] - 0].sonProjectList.splice([arr[1] - 0], 1);
data.itemList.splice(i + 1, 0, Value);
// const options = {
// id: Value.id,
// parentId: 0,
// };
const options = {
businessCode: Value.businessCode,
moveProjectId: Value.id,
targetProjectId: '',
};
emit('change', options);
}
//
clearSet(i);
emit('change', data.itemList);
return;
}
//
if (data.itemList[i].showSubBorder) {
if (isNumber(index)) {
const Value = data.itemList[index];
if (data.itemList[lastIndex - 1].sonProjectList && data.itemList[lastIndex - 1].sonProjectList.length) {
data.itemList[lastIndex - 1].sonProjectList.push(Value);
} else {
data.itemList[lastIndex].sonProjectList = [Value];
}
data.itemList.splice(index, 1);
//
clearSet(i);
// const options = {
// id: Value.id,
// parentId: data.itemList[lastIndex - 1].id,
// };
const options = {
businessCode: Value.businessCode,
moveProjectId: Value.id,
targetProjectId: data.itemList[lastIndex - 1].id,
};
emit('change', options);
} else {
const arr = index.split('-');
const Value = data.itemList[arr[0] - 0].sonProjectList[arr[1] - 0];
if (data.itemList[lastIndex].sonProjectList && data.itemList[lastIndex].sonProjectList.length) {
data.itemList[lastIndex].sonProjectList.push(Value);
} else {
data.itemList[lastIndex].sonProjectList = [Value];
}
data.itemList[arr[0] - 0].sonProjectList.splice([arr[1] - 0], 1);
//
clearSet(i);
// const options = {
// id: Value.id,
// parentId: data.itemList[lastIndex].id,
// };
const options = {
businessCode: Value.businessCode,
moveProjectId: Value.id,
targetProjectId: data.itemList[lastIndex].id,
};
emit('change', options);
// const options1 = {
// id: Value.id,
// parentId: 0,
// };
const options1 = {
businessCode: Value.businessCode,
moveProjectId: Value.id,
targetProjectId: '',
};
emit('change', options1);
}
return;
}
}
}
//
function clearSet(i) {
if (i < data.itemList.length) {
data.itemList[i].showBorder = false;
data.itemList[i].showSubBorder = false;
data.itemList[i].showTopBorder = false;
}
data.deltaLeft == 0;
data.showMoveImage = false;
data.setSubItem = false;
// data.changeEvent = false;
data.showItemIndex = undefined;
}
//
function findOverIndex(posY) {
//
const leng = data.itemList.length * data.itemHeight; //
if (posY < data.begintop) {
return -1;
}
for (let i = 0; i < data.itemList.length; i++) {
const begin = data.itemHeight * i + data.begintop;
const end = data.itemHeight * i + data.begintop + data.itemHeight;
if (begin <= posY && end >= posY) {
return i;
}
}
if (posY > leng) {
//
return data.itemList.length - 1;
}
if (posY < data.begintop) {
return 0;
}
}
//
function delProject(id, url) {
uni.showModal({
title: '',
content: '是否删除项目?',
showCancel: true,
success: async ({ confirm }) => {
if (confirm) {
await uni.$u.api.delProject(id, url);
let flag_index = 0;
data.itemList.forEach((item, index) => {
if (item.id == id) {
flag_index = index;
}
});
data.itemList.splice(flag_index, 1);
store.commit('project/setProjects', data.itemList);
}
},
});
}
//
function importProject(id, name) {
uni.showModal({
content: '是否导入到' + name,
showCancel: true,
success: async ({ confirm }) => {
if (confirm) {
try {
const res = await uni.$u.api.import(id);
// WBS
//
emit('success');
// const { apiUrl } = Config;
// let defaultwbs = `${apiUrl}/defaultwbs`;
// res.url && (defaultwbs = res.url);
store.commit('project/setIsRefresh', 1);
setTimeout(() => {
uni.navigateTo({ url: `/pages/project/project?u=${user.value.id}&p=${res.id}&pname=${res.name}&url=${encodeURIComponent(res.url)}` });
}, 2000);
} catch (error) {
console.error('error: ', error);
emit('error', error);
}
}
},
});
}
//
function exportProject(id, url) {
uni.showModal({
title: '',
content: '是否导出项目?',
showCancel: true,
success: async ({ confirm }) => {
if (confirm) {
const data = await uni.$u.post(`${url}/tall/project/exportWbs`, { projectId: id });
// #ifdef H5
window.location.href = data.url;
// #endif
// #ifdef APP-PLUS
uni.downloadFile({
url: data.url, //
success: ({statusCode, tempFilePath}) => {
if (statusCode === 200) {
console.log('下载成功', tempFilePath);
uni.saveFile({
tempFilePath,
success:(res)=>{
uni.$ui.showToast('文件保存路径:' + res.savedFilePath);
//res.savedFilePath
//
// uni.openDocument({
// filePath: res.savedFilePath,
// success:(res)=>console.log('')
// })
},
fail:()=>console.log('下载失败')
})
}
}
});
// #endif
}
},
});
}
//
function toWorkbench() {
uni.navigateTo({ url: '/pages/workbench/workbench' });
}
//
function openProject(project) {
store.commit('task/clearTasks'); //
store.commit('task/clearRealTasks'); //
store.commit('socket/setCurrLocationTaskId', '');
store.commit('task/setAllTasks', []); //
store.commit('task/setUpNextPage', 1);
store.commit('task/setDownNextPage', 1);
store.commit('task/setTimeLineType', 1);
const { name, id, url, businessCode } = project;
uni.navigateTo({ url: `/pages/project/project?u=${userId.value}&p=${id}&pname=${name}&url=${encodeURIComponent(url)}&businessCode=${businessCode}` });
}
/**
* 弹出项目操作面板
*/
function openMenu(project, index) {
if (index === 0) return;
data.showMenu = true;
data.projectId = project.id;
data.tips.text = project.name;
data.clickProject = project;
// emit('setData', data.showMenu, project, data.tips);
}
</script>
<style lang="scss" scoped>
.cu-item {
width: 100%;
display: flex;
align-items: center;
font-size: 14px;
}
.border-100 {
height: 4rpx;
margin: 0 20rpx;
}
.border-80 {
height: 4rpx;
margin: 0 20rpx 0 90rpx;
}
.workbench-btn {
margin-right: 10px;
width: 80px;
height: 30px;
line-height: 30px;
border-radius: 15px;
overflow: hidden;
border: 1px solid #2b85e4;
background-color: #1890ff;
font-size: 12px;
color: #ffffff;
text-align: center;
}
.remind-box {
padding: 0 3px;
min-width: 16px;
height: 16px;
text-align: center;
line-height: 16px;
border-radius: 8px;
font-weight: 100;
}
</style>

693
components/PrettyExchange/PrettyExchange222.vue

@ -1,693 +0,0 @@
<template>
<view>
<scroll-view scroll-y="true">
<view v-if="!data.changeEvent">
<view :id="'cu-' + index" :key="item.id" class="cu-item flex-col" v-for="(item, index) in data.itemList">
<ProjectItem
class="w-full"
:index="index"
:item="item"
:menuList="data.menuList"
@setData="setData"
@openSubProject="openSubProject"
/>
</view>
</view>
<!-- 点击排序之后的效果 -->
<view v-else>
<view
:id="'cu-' + index"
:key="index"
:style="{ 'background-color': item.color }"
@touchend="stops($event, index)"
@touchmove.stop.prevent="move"
@touchstart="start($event, index)"
class="cu-item flex-col"
v-for="(item, index) in data.itemList"
>
<!-- <view class="border-100 bg-blue-500" v-if="item.showTopBorder"></view> -->
<!-- 内容区 -->
<!-- 父项目 -->
<view class="w-full">
<view class="flex items-center justify-between p-3">
<u-icon class="mover" name="https://www.tall.wiki/staticrec/drag.svg" size="48"></u-icon>
<view class="flex-1 px-3">
<view class="flex items-center mb-1">
<view class="mr-2">{{ item.name }}</view>
<!-- 状态 TODO:-->
<view class="px-2 text-xs text-green-400 bg-green-100 rounded-full flex-shrink-0">进行中</view>
</view>
<view class="flex items-center text-xs text-gray-400">
<view class="pr-2">{{ 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 class="workbench-btn" v-if="index === 0" @click="toWorkbench">工作台</view> -->
<!-- 箭头 -->
<view v-if="item.sonProjectList && item.sonProjectList.length">
<u-icon
@click="openSubProject(item.sonProjectList.length, index)"
class="text-gray-400"
name="arrow-up"
size="14px"
v-if="item.show"
></u-icon>
<u-icon
@click="openSubProject(item.sonProjectList.length, index)"
class="text-gray-400"
name="arrow-down"
size="14px"
v-else
></u-icon>
</view>
<u-icon class="text-gray-400" name="arrow-right" size="14px" v-else></u-icon>
</view>
<!-- 父项目 end -->
<!-- 子项目 -->
<view class="ml-8" v-if="item.show">
<view
:id="'cu-' + index + '-' + subIndex"
:key="subIndex"
@touchend.stop.prevent="stops($event, index + '-' + subIndex, item.sonProjectList.length)"
@touchmove.stop.prevent="move($event, item.sonProjectList.length)"
@touchstart.stop.prevent="start($event, index + '-' + subIndex)"
class="cu-item flex-col"
v-for="(subItem, subIndex) in item.sonProjectList"
>
<view class="flex items-center justify-between p-3 w-full">
<u-icon class="mover" name="https://www.tall.wiki/staticrec/drag.svg" size="48"></u-icon>
<view class="flex-1 px-3">
<view class="flex items-center">
<view class="mr-2">{{ subItem.name }}</view>
<!-- 状态 -->
<view
:class="
subItem.status === 0
? 'text-blue-400 bg-blue-100'
: subItem.status === 1
? 'text-green-400 bg-green-100'
: subItem.status === 2
? 'text-red-400 bg-red-100'
: 'text-gray-400 bg-gray-100'
"
class="px-2 text-xs text-gray-400 bg-gray-100 rounded-full flex-shrink-0"
>
{{ subItem.status === 0 ? '未开始' : subItem.status === 1 ? '进行中' : subItem.status === 2 ? '暂停' : '已完成' }}
</view>
</view>
</view>
<!-- 箭头 -->
<u-icon class="text-gray-400" name="arrow-right" size="14px"></u-icon>
</view>
</view>
</view>
</view>
<!-- 内容区 end -->
<view class="border-100 bg-blue-500" v-if="item.showBorder"></view>
<view class="border-80 bg-blue-500" v-if="item.showSubBorder"></view>
</view>
</view>
</scroll-view>
<!-- 移动悬浮 begin -->
<view v-if="data.showMoveImage">
<view :style="{ left: data.moveLeft + 'px', top: data.moveTop + 'px' }" class="cu-item absolute">
<ProjectItem class="w-full" :item="data.moveItem" />
</view>
</view>
<!-- 移动悬浮 end -->
<!-- 项目操作面板 -->
<u-action-sheet :list="data.menuList" :tips="data.tips" @click="chooseAction" v-model="data.showMenu"></u-action-sheet>
</view>
</template>
<script setup>
import { reactive, onMounted, watchEffect, computed } from 'vue';
import { useStore } from 'vuex';
import dayjs from 'dayjs';
import ProjectItem from '@/components/Projects/ProjectItem.vue';
const store = useStore();
const projects = computed(() => store.state.project.projects);
const remindData = computed(() => store.state.socket.remindData);
const data = reactive({
// itemTop: 0,
// itemLeft: 0,
itemHeight: 0, //
itemWidth: 0, //
subItemHeight: 0, //
showMoveImage: false,
moveItem: '', //
moveLeft: 0, //
moveTop: 0, //
deltaLeft: 0,
deltaTop: 0,
beginleft: 0, //
begintop: 0, //
itemList: [], //
setSubItem: false, //
changeEvent: false, //
showMenu: false,
tips: { text: '', color: '#909399', fontSize: 28 },
clickProject: {},
projectId: 0,
// menuList: [{ text: '' }, { text: '' }, { text: '' }, { text: '' }, { text: '' }],
menuList: [{ text: '导入' }, { text: '导出' }, { text: '删除' }, { text: '排序' }],
// show: false,
// border: 'border border-blue-500 shadow rounded-md',
// showBorder: false, //
showItemIndex: undefined,
});
const emit = defineEmits(['changeHeight', 'change']);
//
watchEffect(() => {
if (projects.value) {
data.itemList = projects.value;
data.itemList.forEach(item => {
item.showBorder = false; //
item.showSubBorder = false; //
item.showTopBorder = false; //
item.remindNum = 0;
if (remindData.value) {
remindData.value.forEach(remind => {
const remind_data = JSON.parse(remind.data);
if (remind_data.data.projectId === item.id) {
item.remindNum++;
}
});
}
});
}
});
onMounted(() => {
data.itemList = projects.value;
data.itemList.forEach(item => {
item.showBorder = false; //
item.showSubBorder = false; //
item.showTopBorder = false; //
});
});
//
function openSubProject(length, index) {
store.commit('project/setProjectItemShow', { index, show: !data.itemList[index].show });
if (length && index) {
emit('changeHeight', length, index);
}
data.showItemIndex = index;
}
//
function getDate() {
const query = uni
.createSelectorQuery()
.select('#cu-0')
.fields(
{
id: true,
dataset: true,
rect: true,
size: true,
},
res => {
data.begintop = res.top;
data.beginleft = res.left;
},
)
.exec();
}
function setData(flag, project, tips) {
data.showMenu = flag;
data.projectId = project.id;
data.tips = tips;
data.clickProject = project;
}
function chooseAction(e) {
const obj = {
index: e,
projectId: data.projectId,
url: data.clickProject.url,
projectName: data.tips.text
};
// emit('chooseAction', data);
actionFun(obj);
}
//
function actionFun(obj) {
const action = data.menuList[obj.index].text;
if (action === '排序') {
data.changeEvent = true;
uni.$ui.showToast('请移动进行排序');
}
if (action === '删除') {
data.changeEvent = false;
delProject(obj.projectId, obj.url);
}
if (action === '导入') {
data.changeEvent = false;
store.commit('setDomain', obj.url);
importProject(obj.projectId, obj.projectName);
}
if (action === '导出') {
data.changeEvent = false;
exportProject(obj.projectId, obj.url);
}
if (data.showItemIndex !== undefined) {
store.commit('project/setProjectItemShow', {
index: data.showItemIndex,
show: true,
});
}
}
function isNumber(val) {
return val === +val;
}
function start(e, index) {
console.log('开始');
setTimeout(() => {
getDate();
}, 300);
if (isNumber(index)) {
//
data.setSubItem = false;
const query = uni
.createSelectorQuery()
.select(`#cu-${index}`)
.fields(
{
id: true,
dataset: true,
rect: true,
size: true,
},
res => {
data.moveTop = res.top;
data.moveLeft = res.left;
data.moveItem = data.itemList[index];
data.itemWidth = res.width;
data.itemHeight = res.height;
},
)
.exec();
} else {
//
const arr = index.split('-');
data.setSubItem = true;
const query = uni.createSelectorQuery();
query
.select(`#cu-${arr[0] - 0}`)
.fields(
{
id: true,
dataset: true,
rect: true,
size: true,
},
res => {
data.itemHeight = res.height;
},
)
.exec();
query
.select(`#cu-${index}`)
.fields(
{
id: true,
dataset: true,
rect: true,
size: true,
},
res => {
data.moveTop = res.top;
data.moveLeft = res.left;
data.moveItem = data.itemList[arr[0] - 0].sonProjectList[arr[1] - 0];
data.itemWidth = res.width;
data.subItemHeight = res.height;
},
)
.exec();
}
}
function move(e, length) {
console.log('移动');
data.showMoveImage = true; //
const touch = e.touches[0];
if (data.deltaLeft == 0) {
//
data.deltaLeft = touch.pageX - data.moveLeft;
data.deltaTop = touch.pageY - data.moveTop;
}
data.moveLeft = touch.pageX - data.deltaLeft;
data.moveTop = touch.pageY - data.deltaTop;
const lastIndex = findOverIndex(touch.pageY, length);
// 线
for (let i = 0; i < data.itemList.length; i++) {
if (data.moveLeft > 35) {
data.itemList[i].showBorder = false;
data.itemList[i].showTopBorder = false;
if (i === lastIndex) {
data.itemList[i].showSubBorder = true;
} else {
data.itemList[i].showSubBorder = false;
}
} else if (lastIndex === -1) {
data.itemList[0].showTopBorder = true;
data.itemList[i].showSubBorder = false;
data.itemList[i].showBorder = false;
} else {
data.itemList[i].showSubBorder = false;
data.itemList[i].showTopBorder = false;
if (i === lastIndex) {
data.itemList[i].showBorder = true;
} else {
data.itemList[i].showBorder = false;
}
}
}
}
function stops(e, index, length) {
console.log('结束', e, index, length);
const touch = e.changedTouches[0];
const lastIndex = findOverIndex(touch.pageY, length);
console.log('11111111111', data.itemList)
//
for (let i = 0; i < data.itemList.length; i++) {
//
if (data.itemList[i].showTopBorder) {
if (isNumber(index)) {
const Value = data.itemList[index];
data.itemList.unshift(Value);
data.itemList.splice(index + 1, 1);
} else {
const arr = index.split('-');
const Value = data.itemList[arr[0] - 0].sonProjectList[arr[1] - 0];
data.itemList.unshift(Value);
data.itemList[arr[0] - 0].sonProjectList.splice([arr[1] - 0], 1);
// const options = {
// id: Value.id,
// parentId: 0,
// };
const options = {
businessCode: Value.businessCode,
moveProjectId: Value.id,
targetProjectId: '',
};
emit('change', options);
}
//
clearSet(i);
emit('change', data.itemList);
return;
}
//
if (data.itemList[i].showBorder) {
if (isNumber(index)) {
const Value = data.itemList[index];
data.itemList.splice(i + 1, 0, Value);
if (i < index) {
data.itemList.splice(index + 1, 1);
} else {
data.itemList.splice(index, 1);
}
} else {
const arr = index.split('-');
const Value = data.itemList[arr[0] - 0].sonProjectList[arr[1] - 0];
data.itemList.splice(i + 1, 0, Value);
data.itemList[arr[0] - 0].sonProjectList.splice([arr[1] - 0], 1);
// const options = {
// id: Value.id,
// parentId: 0,
// };
const options = {
businessCode: Value.businessCode,
moveProjectId: Value.id,
targetProjectId: '',
};
emit('change', options);
}
//
clearSet(i);
emit('change', data.itemList);
return;
}
//
if (data.itemList[i].showSubBorder) {
if (isNumber(index)) {
const Value = data.itemList[index];
if (data.itemList[lastIndex - 1].sonProjectList && data.itemList[lastIndex - 1].sonProjectList.length) {
data.itemList[lastIndex - 1].sonProjectList.push(Value);
} else {
data.itemList[lastIndex].sonProjectList = [Value];
}
data.itemList.splice(index, 1);
//
clearSet(i);
// const options = {
// id: Value.id,
// parentId: data.itemList[lastIndex - 1].id,
// };
const options = {
businessCode: Value.businessCode,
moveProjectId: Value.id,
targetProjectId: data.itemList[lastIndex - 1].id,
};
emit('change', options);
} else {
const arr = index.split('-');
const Value = data.itemList[arr[0] - 0].sonProjectList[arr[1] - 0];
if (data.itemList[lastIndex].sonProjectList && data.itemList[lastIndex].sonProjectList.length) {
data.itemList[lastIndex].sonProjectList.push(Value);
} else {
data.itemList[lastIndex].sonProjectList = [Value];
}
data.itemList[arr[0] - 0].sonProjectList.splice([arr[1] - 0], 1);
//
clearSet(i);
// const options = {
// id: Value.id,
// parentId: data.itemList[lastIndex].id,
// };
const options = {
businessCode: Value.businessCode,
moveProjectId: Value.id,
targetProjectId: data.itemList[lastIndex].id,
};
emit('change', options);
// const options1 = {
// id: Value.id,
// parentId: 0,
// };
const options1 = {
businessCode: Value.businessCode,
moveProjectId: Value.id,
targetProjectId: '',
};
emit('change', options1);
}
return;
}
}
}
//
function clearSet(i) {
data.itemList[i].showBorder = false;
data.itemList[i].showSubBorder = false;
data.itemList[i].showTopBorder = false;
data.deltaLeft == 0;
data.showMoveImage = false;
data.setSubItem = false;
data.changeEvent = false;
data.showItemIndex = undefined;
}
//
function findOverIndex(posY) {
//
const leng = data.itemList.length * data.itemHeight; //
if (posY < data.begintop) {
return -1;
}
for (let i = 0; i < data.itemList.length; i++) {
const begin = data.itemHeight * i + data.begintop;
const end = data.itemHeight * i + data.begintop + data.itemHeight;
if (begin <= posY && end >= posY) {
return i;
}
}
if (posY > leng) {
//
return data.itemList.length - 1;
}
if (posY < data.begintop) {
return 0;
}
}
//
function delProject(id, url) {
uni.showModal({
title: '',
content: '是否删除项目?',
showCancel: true,
success: async ({ confirm }) => {
if (confirm) {
await uni.$u.api.delProject(id, url);
let flag_index = 0;
data.itemList.forEach((item, index) => {
if (item.id == id) {
flag_index = index;
}
});
data.itemList.splice(flag_index, 1);
store.commit('project/setProjects', data.itemList);
}
},
});
}
//
function importProject(id, name) {
uni.showModal({
content: '是否导入到' + name,
showCancel: true,
success: async ({ confirm }) => {
if (confirm) {
try {
const res = await uni.$u.api.import(id);
// WBS
//
emit('success');
// const { apiUrl } = Config;
// let defaultwbs = `${apiUrl}/defaultwbs`;
// res.url && (defaultwbs = res.url);
store.commit('project/setIsRefresh', 1);
setTimeout(() => {
uni.navigateTo({ url: `/pages/project/project?u=${user.value.id}&p=${res.id}&pname=${res.name}&url=${encodeURIComponent(res.url)}` });
}, 2000);
} catch (error) {
console.error('error: ', error);
emit('error', error);
}
}
},
});
}
//
function exportProject(id, url) {
uni.showModal({
title: '',
content: '是否导出项目?',
showCancel: true,
success: async ({ confirm }) => {
if (confirm) {
const data = await uni.$u.post(`${url}/tall/project/exportWbs`, { projectId: id });
// #ifdef H5
window.location.href = data.url;
// #endif
// #ifdef APP-PLUS
uni.downloadFile({
url: data.url, //
success: ({statusCode, tempFilePath}) => {
if (statusCode === 200) {
console.log('下载成功', tempFilePath);
uni.saveFile({
tempFilePath,
success:(res)=>{
uni.$ui.showToast('文件保存路径:' + res.savedFilePath);
//res.savedFilePath
//
// uni.openDocument({
// filePath: res.savedFilePath,
// success:(res)=>console.log('')
// })
},
fail:()=>console.log('下载失败')
})
}
}
});
// #endif
}
},
});
}
//
// function toWorkbench() {
// uni.navigateTo({ url: '/pages/workbench/workbench' });
// }
</script>
<style lang="scss" scoped>
.cu-item {
width: 100%;
display: flex;
align-items: center;
font-size: 14px;
}
.border-100 {
width: 92%;
height: 4rpx;
}
.border-80 {
width: 84%;
height: 2px;
margin-left: 30px;
}
.workbench-btn {
margin-right: 10px;
width: 80px;
height: 36px;
line-height: 36px;
border-radius: 18px;
overflow: hidden;
border: 1px solid #2b85e4;
background-color: #1890ff;
font-size: 12px;
color: #ffffff;
text-align: center;
}
</style>

234
components/SearchPopup/SearchPopup.vue

@ -0,0 +1,234 @@
<template>
<view class="search-box fixed z-10 p-4 w-full bg-white shadow-lg">
<view class="flex">
<u-input class="mr-3" v-model="startTimeValue" type="text" :border="true" height="64" @focus="openCal" />
<u-input v-model="endTimeValue" type="text" :border="true" height="64" @focus="openCal" />
</view>
<u-input class="mt-3" v-model="selectedMembers" type="text" :border="true" height="64" @focus="openMember" />
<view class="mt-3 text-center">
<u-button class="mr-3" size="mini" @click="closePopup">取消</u-button>
<u-button class="mr-3" type="primary" size="mini" @click="submitSearch(1)">过滤</u-button>
<u-button type="primary" size="mini" @click="submitSearch(2)">导出</u-button>
</view>
<u-popup title="请选择角色" mode="bottom" v-model="showMembers" :mask-close-able="false">
<view class="multiple-select-box">
<view class="multiple-select-title flex justify-between items-center">
<view @click="handleCancel">取消</view>
<view @click="handleOK" class="text-blue-500">确认</view>
</view>
<scroll-view scroll-y="true" style="height: 400rpx;">
<view v-for="(item, index) in members" :key="index" @click="changeItem(item)"
class="multiple-select-item flex items-center justify-between"
:class="[selectedMemberId.indexOf(item.value) > -1 ? 'selected' : '']"
>
<text>{{ item.label }} </text>
<u-icon name="checkbox-mark" class="icon"></u-icon>
</view>
</scroll-view>
</view>
</u-popup>
<u-calendar v-if="!source" v-model="showCal" mode="range" @change="change"></u-calendar>
<template v-if="source === 'checkWorkSummary'">
<u-picker mode="time" v-model="showCal" :params="params" @confirm="selectedStartTime"></u-picker>
<u-picker mode="time" v-model="showEndCal" :params="params" @confirm="selectedEndTime"></u-picker>
</template>
</view>
</template>
<script setup>
import { onMounted, ref } from 'vue';
import { useStore } from 'vuex';
import dayjs from 'dayjs';
const props = defineProps({
//
members: {
type: Array,
default: () => [],
},
show: {
type: Boolean,
default: false
},
source: {
type: String,
default: ""
}
});
const emit = defineEmits(['closePopup', 'getClockQuery']);
const store = useStore();
let startTimeValue = ref(null); //
let endTimeValue = ref(null); //
let showCal = ref(false); //
let showEndCal = ref(false); //
let showMembers = ref(false); //
let defaultMembers = ref([]); //
let selectedMemberArr = ref([]);
let selectedMemberName = ref([]); //
let selectedMemberId = ref([]); //
let selectedMembers = ref(null);
let selectedRoles = ref([]);
const params = ref({ year: true, month: true, day: false, hour: false, minute: false, second: false })
//
function openCal() {
showCal.value = true;
}
//
function change(e) {
startTimeValue.value = e.startDate;
endTimeValue.value = e.endDate;
}
//
function selectedStartTime(e) {
showEndCal.value = true;
startTimeValue.value = e.year + '-' + e.month;
}
//
function selectedEndTime(e) {
endTimeValue.value = e.year + '-' + e.month;
}
//
function openMember() {
showMembers.value = true;
// ,
selectedMemberId.value = [];
let curr = (selectedMembers.value || "").split(",");
let arr = [];
selectedMemberArr.value.forEach(member => {
const index = curr.findIndex(item => item === member.label);
if (index > -1) {
arr.push(member);
selectedMemberId.value.push(member.value);
}
})
selectedMemberArr.value = [...arr];
}
//
function changeItem(item) {
let index = selectedMemberArr.value.findIndex(member => member.value === item.value);
if (index === -1) {
selectedMemberArr.value.push(item);
} else {
selectedMemberArr.value.splice(index, 1);
}
selectedMemberName.value = [];
selectedMemberId.value = [];
selectedMemberArr.value.forEach(item => {
selectedMemberName.value.push(item.label);
selectedMemberId.value.push(item.value);
})
}
//
function handleOK() {
showMembers.value = false;
selectedMembers.value = selectedMemberName.value.toString();
}
//
function handleCancel() {
showMembers.value = false;
}
//
function closePopup() {
emit('closePopup', false);
}
//
function submitSearch(type) {
if (!startTimeValue.value) {
uni.showToast({
title: "请选择开始时间",
icon: 'none'
});
return false;
}
if (!endTimeValue.value) {
uni.showToast({
title: "请选择结束时间",
icon: 'none'
});
return false;
}
const param = {
startTime: startTimeValue.value,
endTime: endTimeValue.value,
memberIdList: selectedMemberId.value
}
if (type === 1) {
emit('getClockQuery', param)
} else {
emit('clockExport', param)
}
}
</script>
<style lang="scss" scoped>
.search-box {
top: 50px;
}
.selected-member {
padding: 2px 10px;
min-height: 34px;
border: 1px solid #d9d9d9;
border-radius: 4px;
}
.member-box {
padding: 0 10px;
background-color: #fafafa;
border: 1px solid #e8e8e8;
border-radius: 2px;
height: 24px;
margin: 2px 0;
margin-right: 4px;
}
.multiple-select-box {
background-color: #fff;
}
.multiple-select-title {
height: 45px;
line-height: 45;
border-bottom: 1px solid #f4f6f8;
view {
padding: 0 12px;
}
}
.multiple-select-item {
padding: 0 40rpx;
height: 32px;
}
.multiple-select-item.selected {
color: #2979ff;
}
</style>

126
components/TimeLine 复制/TimeLine.vue

@ -1,126 +0,0 @@
<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 } 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() {
// storagetaskId 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
}
}
}
defineExpose({
setScrollPosition
})
</script>

38
components/TimeLine 复制/component/Barrier.vue

@ -1,38 +0,0 @@
<!--
* @Author: aBin
* @email: binbin0314@126.com
* @Date: 2021-07-19 14:22:54
* @LastEditors: aBin
* @LastEditTime: 2021-07-20 11:46:04
-->
<template>
<view class>
<!-- :class="{ active: cycleTasks.time.start === filter.startTime }" -->
<view class="cycle-time active">
<!-- {{ $util.formatStartTimeToCycleTime(filter.time, cycleTasks.time.start) }} -->
2021年30周
</view>
</view>
</template>
<script 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>

177
components/TimeLine 复制/component/TaskTools.vue

@ -1,177 +0,0 @@
<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 { 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>

132
components/TimeLine 复制/component/TimeBox.vue

@ -1,132 +0,0 @@
<template>
<!-- v-finger:pinch="pinchHandler" -->
<view class="column">
<view v-if="tasks && tasks.length">
<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="plugin">
<view class="h-3" v-if="task.process === 4"></view>
<!-- <view class="ml-3 overflow-hidden shadow-lg task-box"> -->
<view class="ml-3">
<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)"
:style="{ height: setHeight(task.panel) }"
:show-foot="false"
:show-head="false"
class="h-16"
margin="0"
v-if="tasks && tasks.length && task.process !== 4 && !showSkeleton"
>
<template v-slot:body> -->
<view class="h-16" v-if="tasks && tasks.length && task.process !== 4 && !showSkeleton" @click="onClickTask(task.planStart - 0, task.id)">
<view class="p-0 u-col-between grid gap-3">
<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>
<!-- </template>
</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';
import Skeleton from '@/components/Skeleton/Skeleton.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;
border-left: 2px solid #d1d5db;
}
::v-deep .ml-2 {
margin-left: 16px;
}
::v-deep .ml-3 {
margin-left: 20px;
}
</style>

317
components/TimeLine 复制/component/TimeStatus.vue

@ -1,317 +0,0 @@
<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, computed } from 'vue';
import { useStore } from 'vuex';
import dayjs from 'dayjs';
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-0 || 0) + (planDuration-0 || 0) - 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
components/TimeLine 复制/component/Title.vue

476
hooks/project/useGetTasks - 副本 (2).js

@ -1,476 +0,0 @@
import { computed, nextTick, watch } from 'vue';
import { useStore } from 'vuex';
import { flatten } from 'lodash';
import dayjs from 'dayjs';
export default function useGetTasks() {
const store = useStore();
const tasks = computed(() => store.state.task.tasks);
const timeLineType = computed(() => store.state.task.timeLineType); // 时间轴模式
const realTasks = computed(() => store.state.task.realTasks); // 真实任务
const downNextPage = computed(() => store.state.task.downNextPage); // 下一页
const upNextPage = computed(() => store.state.task.upNextPage); // 下一页
const currUpTimeNode = computed(() => store.state.task.currUpTimeNode); // 当前查询的时间
const currDownTimeNode = computed(() => store.state.task.currDownTimeNode); // 当前查询的时间
const roleId = computed(() => store.state.role.roleId);
const timeNode = computed(() => store.state.task.timeNode);
const timeUnit = computed(() => store.state.task.timeUnit);
const visibleRoles = computed(() => store.state.role.visibleRoles);
const allTasks = computed(() => store.state.task.allTasks);
const roleIndex = computed(() => store.state.role.roleIndex);
const projectId = computed(() => store.getters['project/projectId']);
const timeGranularity = computed(() => store.getters['task/timeGranularity']);
const remindData = computed(() => store.state.socket.remindData); // 小红点
const currRoleRealTasks = computed(() => store.state.task.currRoleRealTasks); // 当前角色的真实任务数据
// 初始化 定期任务
async function initPlanTasks() {
// timeLineType.value === 1 ? setNextPlaceholderTasks({}) : '';
await getTasks({}); // 获取初始数据
// await dataRender({});
}
/**
* 生成getTasks所用的参数
* @param {object} query getTasks传递的参数
*/
function generateGetTaskParam(query) {
return {
roleId: roleId.value,
timeNode: query.timeNode || timeNode.value,
timeUnit: query.timeUnit || timeUnit.value,
queryType: query.queryType === 0 ? 0 : 1,
pageNum: query.pageNum || 1,
pageSize: query.pageSize || uni.$taskConfig.pageCount,
taskId: query.taskId || ''
};
}
/**
* 根据时间基准点和角色查找定期任务
* @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) {
store.commit('task/setShowSkeleton', false);
const params = generateGetTaskParam(query);
uni.$catchReq.getTaskByNum(params, (err, data) => {
store.commit('task/setShowSkeleton', false);
if (err) {
// TODO: 提示错误
console.error('err: ', err);
} else {
store.commit('task/setShowScrollTo', true);
params.queryType === 0 ? store.commit('task/setUpRealTasks', data.list) : store.commit('task/setDownRealTasks', data.list);
params.queryType === 0 ? store.commit('task/setUpNextPage', data.nextPage) : store.commit('task/setDownNextPage', data.nextPage); // 下一页
const index = visibleRoles.value.findIndex(role => role.id === roleId.value);
const arr = [...allTasks.value];
arr[index].realTasks = [...realTasks.value];
store.commit('task/setAllTasks', arr);
store.commit('task/setCurrRoleRealTasks', arr[index].realTasks); // 设置当前角色的真实任务数据
// 数据处理
dataRender(params);
}
});
}
function dataRender(params) {
timeLineType.value === 1 ? renderScaleTask(params) : renderConTask(params);
}
// 任务模式
async function renderConTask(params) {
let nextPage = params.queryType === 0 ? upNextPage.value : downNextPage.value; // 下一页的值
let showTasks = tasks.value;
let centerData = await showTaskId(params, showTasks, realTasks.value) || [];
if (centerData.length < 15 && nextPage > 0) {
getTasks({pageNum: nextPage, queryType: params.queryType});
} else {
if (params.queryType === 0) {
showTasks = [...centerData, ...showTasks];
} else {
showTasks = [...showTasks, ...centerData];
}
}
if (showTasks.length < 15 && nextPage === 0 && params.queryType === 1) {
getTasks({pageNum: 1, queryType: 0});
}
if (showTasks.length > 80) {
showTasks = params.queryType === 0 ? showTasks.slice(0, 80) : showTasks.slice(showTasks.length - 80);
}
store.commit('task/clearTasks');
params.queryType === 0 ? store.commit('task/setUpTasks', showTasks) : store.commit('task/setDownTasks', showTasks);
}
// 刻度模式数据处理
async function renderScaleTask(params) {
// params.queryType === 0 ? setPrevPlaceholderTasks(params) : setNextPlaceholderTasks(params);
// let centerData = await showTaskId(params, tasks.value, currRoleRealTasks.value) || [];
let centerData = await showTaskTime(params, tasks.value, currRoleRealTasks.value) || [];
// tasksData(params, centerData, currRoleRealTasks.value);
handleTasksData(params, centerData, currRoleRealTasks.value);
}
// 已显示的任务第一个时间和最后一个时间
async function showTaskTime(params, showTasks, realTasks) {
// 初始值
let centerData = params.queryType === 0 ? [] : realTasks.slice(0, params.pageSize);
/**
* 1判断显示任务中是否有真实任务
* 1-1根据id查找任务
* 1-2根据时间查找任务
* 2查找15个任务
*/
const firstDetailIndex = showTasks.findIndex(task => task.detailId);
if (firstDetailIndex > -1) {
// 显示任务中有真实任务数据
const firstId = showTasks[firstDetailIndex].id;
let lastDetailIndex = -1;
showTasks.forEach((item, index) => {
if (item.detailId) {
lastDetailIndex = index;
}
})
const lastId = showTasks[lastDetailIndex].id;
realTasks.forEach((item, index) => {
if (params.queryType === 1 && item.id === lastId) {
centerData = realTasks.slice(index + 1, index + 1 + params.pageSize) || [];
} else if (params.queryType === 0 && item.id === firstId) {
if (index >= params.pageSize) {
centerData = realTasks.slice(index - params.pageSize, index) || [];
} else {
centerData = realTasks.slice(0, index) || [];
}
}
})
} else {
// 显示任务中没有真实任务数据
// 已显示任务的第一个任务时间
const firstTime = showTasks.length ? showTasks[0].planStart : '';
// 已显示任务的最后一个任务时间
const lastTime = showTasks.length ? showTasks[showTasks.length - 1].planStart : '';
try {
realTasks.forEach((item, index) => {
if (params.queryType === 1) {
if (dayjs(+lastTime).isSame(+item.planStart, timeGranularity.value) || dayjs(+lastTime).isBefore(+item.planStart, timeGranularity.value)) {
centerData = realTasks.slice(index, index + params.pageSize) || [];
throw Error();
}
} else {
if (dayjs(+firstTime).isSame(+item.planStart, timeGranularity.value) || dayjs(+firstTime).isAfter(+item.planStart, timeGranularity.value)) {
if (index >= params.pageSize) {
centerData = realTasks.slice(index - params.pageSize, index) || [];
} else {
centerData = realTasks.slice(0, index) || [];
}
}
}
})
} catch (e) {
console.log('退出循环')
}
}
console.log('111111111', centerData);
return centerData;
}
async function handleTasksData(params, centerData, realTasks) {
/**
* 3查找的任务数量是否>=15
* 3-1
* 判断时间跨度是否>=15
* 3-1-1显示时间刻度范围内的任务
* 3-1-2显示全部任务并删除多余的刻度
* 3-2
* 判断时间跨度是否>=15
* 3-2-1显示时间刻度范围内的任务
* 3-2-2
* 下一页是否为0
* 3-2-2-1无下一页显示任务和刻度之后继续展示刻度
* 3-2-2-1查找下一页数据并重复上述步骤
*/
const startTime = centerData.length ? centerData[0].planStart : '';
const endTime = centerData.length ? centerData[centerData.length - 1].planStart : '';
let centerTime = dayjs(+startTime).add(params.pageSize, timeGranularity.value);\
// 时间跨度是否大于等于15
let isExceed = dayjs(+centerTime).isBefore(+endTime, timeGranularity.value) || dayjs(+centerTime).isSame(+endTime, timeGranularity.value);
let nextPage = params.queryType === 0 ? upNextPage.value : downNextPage.value; // 下一页的值
if (isExceed || centerData.length >= params.pageSize || nextPage === 0) {
params.queryType === 0 ? setPrevPlaceholderTasks(params) : setNextPlaceholderTasks(params);
}
let showTasks = tasks.value; // 显示的数据
const firstDetailIndex = showTasks.findIndex(task => task.detailId); // 显示任务中存在真实任务
const firstId = showTasks[firstDetailIndex].id;
let lastDetailIndex = -1;
showTasks.forEach((item, index) => {
if (item.detailId) {
lastDetailIndex = index;
}
})
const lastId = showTasks[lastDetailIndex].id;
showTasks.forEach((task, index) => {
const arr = centerData.filter(item => dayjs(+item.planStart).isSame(+task.planStart, timeGranularity.value));
if (arr && arr.length) {
if (firstDetailIndex > -1) {
if (params.queryType === 1 && task.id === lastId) {
showTasks.splice(index + 1, 0, [...arr])
} else (params.queryType === 0 && task.id === firstId) {
showTasks.splice(index, 0, [...arr])
}
} else {
showTasks.splice(index, 1, [...arr]);
}
}
})
showTasks = flatten(showTasks); // 1维拍平
if (!isExceed) {
if (centerData.length < params.pageSize && nextPage > 0) {
await getTasks({pageNum: nextPage, queryType: params.queryType});
return;
}
let data = params.queryType === 0 ? centerData[0] : centerData[centerData.length - 1];
showTasks.forEach((item, index) => {
if (item.id === data.id) {
len = index;
}
})
showTasks = params.queryType === 0 ? showTasks.slice(len) : showTasks.slice(0, len + 1);
}
if (showTasks.length > 80) {
showTasks = param.queryType === 0 ? showTasks.slice(0, 80) : showTasks.slice(showTasks.length - 80);
}
store.commit('task/clearTasks');
param.queryType === 0 ? store.commit('task/setUpTasks', showTasks) : store.commit('task/setDownTasks', showTasks);
}
// 已显示的任务第一个id和最后一个id
async function showTaskId(params, showTasks, realTasks) {
const firstDetailIndex = showTasks.findIndex(task => task.detailId);
const firstId = firstDetailIndex === -1 ? 0 : showTasks[firstDetailIndex].id;
let lastDetailIndex = -1;
showTasks.forEach((item, index) => {
if (item.detailId) {
lastDetailIndex = index;
}
})
const lastId = lastDetailIndex === -1 ? 0 : showTasks[lastDetailIndex].id;
let centerData = params.queryType === 0 ? [] : realTasks.slice(0, params.pageSize);
let flag = false;
realTasks.forEach((item, index) => {
if (params.queryType === 1 && item.id === lastId) {
flag = true;
centerData = realTasks.slice(index + 1, index + 1 + params.pageSize) || [];
} else if (params.queryType === 0 && item.id === firstId) {
flag = true;
centerData = realTasks.slice(index - params.pageSize, index) || [];
}
})
if (!flag) {
centerData = 0
}
console.log('111111', centerData, realTasks)
// 1、数量大于等于15 centerData.length >= 15
// 2、时间跨度大于等于15
const startTime = centerData.length ? centerData[0].planStart : '';
const endTime = centerData.length ? centerData[centerData.length - 1].planStart : '';
let centerTime = dayjs(+startTime).add(params.pageSize, timeGranularity.value);
let isExceed = dayjs(+centerTime).isBefore(+endTime, timeGranularity.value) || dayjs(+centerTime).isSame(+endTime, timeGranularity.value);
// 3、下一页不为0 nextPage != 0
let nextPage = params.queryType === 0 ? upNextPage.value : downNextPage.value; // 下一页的值
if (centerData.length < 15 && !isExceed && nextPage > 0) {
await getTasks({pageNum: nextPage, queryType: params.queryType});
// centerData = await showTaskId(params, tasks.value, currRoleRealTasks.value);
}
return centerData;
}
/**
* 刻度模式数据处理
* 大于等于15天真实数据的时间跨度
* 或大于等于15条真实数据的数量
* 不用重新加载数据
* @param {Object} params
*/
function tasksData(query, centerData, realTasks) {
let params = generateGetTaskParam(query);
params.queryType === 0 ? setPrevPlaceholderTasks(params) : setNextPlaceholderTasks(params);
let showTasks = tasks.value; // 显示的数据
let nextPage = param.queryType === 0 ? upNextPage.value : downNextPage.value; // 下一页的值
// 判断条件
let isAccordTerm1 = false, isAccordTerm2 = false;
if (centerData.length > 0) {
// 1.数据数量>=15条
isAccordTerm1 = centerData.length >= param.pageSize;
// 2.数据最后一条数据时间>=当前查询的时间
if (param.queryType === 0) {
let firstData = dayjs(centerData[0].planStart).add(param.pageSize, timeGranularity.value);
isAccordTerm2 = dayjs(+firstData).isBefore(+currUpTimeNode.value, timeGranularity.value) || dayjs(+firstData).isSame(+currUpTimeNode.value, timeGranularity.value);
} else {
let lastData = dayjs(centerData[centerData.length - 1].planStart).subtract(param.pageSize, timeGranularity.value);
isAccordTerm2 = dayjs(+lastData).isAfter(+currDownTimeNode.value, timeGranularity.value) || dayjs(+lastData).isSame(+currDownTimeNode.value, timeGranularity.value);
}
}
// 3.下一页===0
// 不需要添加新数据
if (!isAccordTerm1 && !isAccordTerm2 && nextPage > 0) {
// getTasks({pageNum: nextPage, queryType: param.queryType});
} else {
let tasksArr = [], isReplace = false, firstIndex = -1, selctedIndex = -1, replaceTime = 0;
showTasks.forEach((task, index) => {
const arr = centerData.filter(item => dayjs(+item.planStart).isSame(+task.planStart, timeGranularity.value));
if (arr && arr.length) {
if (task.detailId) {
// 新数据与旧数据时间有重叠
if (param.queryType === 1) {
selctedIndex = index;
tasksArr = [...arr];
} else {
firstIndex = showTasks.findIndex(data => dayjs(+data.planStart).isSame(+task.planStart, timeGranularity.value));
}
} else {
showTasks.splice(index, 1, [...arr]);
}
}
})
if (selctedIndex) {
showTasks.splice(selctedIndex + 1, 0, [...tasksArr])
}
if (firstIndex) {
showTasks.splice(firstIndex, 0, [...tasksArr])
}
showTasks.forEach((task, index) => {
const arr = centerData.filter(item => dayjs(+item.planStart).isSame(+task.planStart, timeGranularity.value));
if (arr && arr.length) {
if (!task.detailId) { // 新数据与旧数据时间有重叠
showTasks.splice(index, 1, [...arr]); // 这里加入的数据是array类型的, [{},{},[],[],{}]
}
}
})
showTasks = flatten(showTasks); // 1维拍平
if (isAccordTerm1 && !isAccordTerm2) {
let len = 0;
let data = param.queryType === 0 ? centerData[0] : centerData[centerData.length - 1];
showTasks.forEach((item, index) => {
if (item.id === data.id) {
len = index;
}
})
showTasks = param.queryType === 0 ? showTasks.slice(len) : showTasks.slice(0, len + 1);
}
if (showTasks.length > 80) {
showTasks = param.queryType === 0 ? showTasks.slice(0, 80) : showTasks.slice(showTasks.length - 80);
}
}
store.commit('task/clearTasks');
param.queryType === 0 ? store.commit('task/setUpTasks', showTasks) : store.commit('task/setDownTasks', showTasks);
}
// 设置时间轴向上的空数据
function setPrevPlaceholderTasks() {
store.commit('task/setTopEnd', true);
let startTime = '';
if (!tasks.value || !tasks.value.length) {
startTime = Date.now(); // 没有任务就应该是时间基准点
} else {
startTime = tasks.value[0].planStart - 0; // 有任务就是第一个任务的计划开始时间
}
const placeholderTasks = uni.$task.setPlaceholderTasks(startTime, true, timeGranularity.value);
store.commit('task/setCurrUpTimeNode', startTime);
store.commit('task/setUpTasks', placeholderTasks);
}
// 设置时间轴向下的空数据
function setNextPlaceholderTasks(params) {
// store.commit('task/setBottomEnd', true);
console.log('ddddddddd')
let startTime = '';
if (!tasks.value || !tasks.value.length) {
startTime = Date.now();
} else {
startTime = dayjs(+tasks.value[tasks.value.length - 1].planStart).add(1, timeGranularity.value).valueOf();
}
if (params.taskId) {
realTasks.value.forEach(item => {
if (item.id === params.taskId) {
startTime = Number(item.planStart);
}
})
}
const initData = uni.$task.setPlaceholderTasks(startTime, false, timeGranularity.value);
store.commit('task/setCurrDownTimeNode', startTime);
store.commit('task/setDownTasks', initData);
}
/**
* 当日常任务发生变化时
* 将新获取到的日常任务放在allTasks里
*/
watch(tasks, newValue => {
// 添加到allTasks里
const index = visibleRoles.value.findIndex(role => role.id === roleId.value);
const arr = [...allTasks.value];
arr[index].task = [...newValue];
store.commit('task/setAllTasks', arr);
});
return {
initPlanTasks,
getTasks,
dataRender
}
}

343
hooks/project/useGetTasks - 副本 (3).js

@ -1,343 +0,0 @@
import { computed, nextTick, watch } from 'vue';
import { useStore } from 'vuex';
import { flatten } from 'lodash';
import dayjs from 'dayjs';
export default function useGetTasks() {
const store = useStore();
const tasks = computed(() => store.state.task.tasks);
const timeLineType = computed(() => store.state.task.timeLineType); // 时间轴模式
const realTasks = computed(() => store.state.task.realTasks); // 真实任务
const downNextPage = computed(() => store.state.task.downNextPage); // 下一页
const upNextPage = computed(() => store.state.task.upNextPage); // 下一页
const currUpTimeNode = computed(() => store.state.task.currUpTimeNode); // 当前查询的时间
const currDownTimeNode = computed(() => store.state.task.currDownTimeNode); // 当前查询的时间
const roleId = computed(() => store.state.role.roleId);
const timeNode = computed(() => store.state.task.timeNode);
const timeUnit = computed(() => store.state.task.timeUnit);
const visibleRoles = computed(() => store.state.role.visibleRoles);
const allTasks = computed(() => store.state.task.allTasks);
const roleIndex = computed(() => store.state.role.roleIndex);
const projectId = computed(() => store.getters['project/projectId']);
const timeGranularity = computed(() => store.getters['task/timeGranularity']);
const remindData = computed(() => store.state.socket.remindData); // 小红点
const currRoleRealTasks = computed(() => store.state.task.currRoleRealTasks); // 当前角色的真实任务数据
// 初始化 定期任务
async function initPlanTasks() {
if (timeLineType.value === 1) setNextPlaceholderTasks({});
await getTasks({}); // 获取初始数据
// await dataRender({});
}
/**
* 生成getTasks所用的参数
* @param {object} query getTasks传递的参数
*/
function generateGetTaskParam(query) {
return {
roleId: roleId.value,
timeNode: query.timeNode || timeNode.value,
timeUnit: query.timeUnit || timeUnit.value,
queryType: query.queryType === 0 ? 0 : 1,
pageNum: query.pageNum || 1,
pageSize: query.pageSize || uni.$taskConfig.pageCount,
taskId: query.taskId || ''
};
}
/**
* 根据时间基准点和角色查找定期任务
* @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) {
store.commit('task/setShowSkeleton', false);
const params = generateGetTaskParam(query);
uni.$catchReq.getTaskByNum(params, (err, data) => {
store.commit('task/setShowSkeleton', false);
if (err) {
// TODO: 提示错误
console.error('err: ', err);
} else {
store.commit('task/setShowScrollTo', true);
params.queryType === 0 ? store.commit('task/setUpRealTasks', data.list) : store.commit('task/setDownRealTasks', data.list);
params.queryType === 0 ? store.commit('task/setUpNextPage', data.nextPage) : store.commit('task/setDownNextPage', data.nextPage); // 下一页
const index = visibleRoles.value.findIndex(role => role.id === roleId.value);
const arr = [...allTasks.value];
arr[index].realTasks = [...realTasks.value];
store.commit('task/setAllTasks', arr);
store.commit('task/setCurrRoleRealTasks', arr[index].realTasks); // 设置当前角色的真实任务数据
// 数据处理
dataRender(params);
}
});
}
function dataRender(params) {
timeLineType.value === 1 ? renderScaleTask(params) : renderConTask(params);
}
// 刻度模式数据处理
async function renderScaleTask(query) {
const params = generateGetTaskParam(query);
let centerData = await showTaskTime(params, tasks.value, currRoleRealTasks.value) || [];
await handleTasksData(params, centerData, currRoleRealTasks.value);
}
// 已显示的任务第一个时间和最后一个时间
async function showTaskTime(params, showTasks, realTasks) {
// 初始值
let centerData = params.queryType === 0 ? [] : realTasks.slice(0, params.pageSize);
/**
* 1判断显示任务中是否有真实任务
* 1-1根据id查找任务
* 1-2根据时间查找任务
* 2查找15个任务
*/
const firstDetailIndex = showTasks.findIndex(task => task.detailId);
if (firstDetailIndex > -1) {
// 显示任务中有真实任务数据
const firstId = showTasks[firstDetailIndex].id;
let lastDetailIndex = -1;
showTasks.forEach((item, index) => {
if (item.detailId) {
lastDetailIndex = index;
}
})
const lastId = showTasks[lastDetailIndex].id;
realTasks.forEach((item, index) => {
if (params.queryType === 1 && item.id === lastId) {
centerData = realTasks.slice(index + 1, index + 1 + params.pageSize) || [];
} else if (params.queryType === 0 && item.id === firstId) {
if (index >= params.pageSize) {
centerData = realTasks.slice(index - params.pageSize, index) || [];
} else {
centerData = realTasks.slice(0, index) || [];
}
}
})
} else {
// 显示任务中没有真实任务数据
// 已显示任务的第一个任务时间
const firstTime = showTasks.length ? showTasks[0].planStart : '';
// 已显示任务的最后一个任务时间
const lastTime = showTasks.length ? showTasks[showTasks.length - 1].planStart : '';
try {
realTasks.forEach((item, index) => {
if (params.queryType === 1) {
if (dayjs(+lastTime).isSame(+item.planStart, timeGranularity.value) || dayjs(+lastTime).isBefore(+item.planStart, timeGranularity.value)) {
centerData = realTasks.slice(index, index + params.pageSize) || [];
throw Error();
}
} else {
if (dayjs(+firstTime).isSame(+item.planStart, timeGranularity.value) || dayjs(+firstTime).isAfter(+item.planStart, timeGranularity.value)) {
if (index >= params.pageSize) {
centerData = realTasks.slice(index - params.pageSize, index) || [];
} else {
centerData = realTasks.slice(0, index) || [];
}
}
}
})
} catch (e) {
console.log('退出循环')
}
}
console.log('111111111', centerData);
return centerData;
}
async function handleTasksData(params, centerData, realTasks) {
/**
* 3查找的任务数量是否>=15
* 3-1
* 判断时间跨度是否>=15
* 3-1-1显示时间刻度范围内的任务
* 3-1-2显示全部任务并删除多余的刻度
* 3-2
* 判断时间跨度是否>=15
* 3-2-1显示时间刻度范围内的任务
* 3-2-2
* 下一页是否为0
* 3-2-2-1无下一页显示任务和刻度之后继续展示刻度
* 3-2-2-1查找下一页数据并重复上述步骤
*/
const startTime = centerData.length ? centerData[0].planStart : '';
const endTime = centerData.length ? centerData[centerData.length - 1].planStart : '';
let centerTime = dayjs(+startTime).add(params.pageSize, timeGranularity.value);
// 时间跨度是否大于等于15
let isExceed = dayjs(+centerTime).isBefore(+endTime, timeGranularity.value) || dayjs(+centerTime).isSame(+endTime, timeGranularity.value);
let showTasks = tasks.value; // 显示的数据
const nextPage = params.queryType === 0 ? upNextPage.value : downNextPage.value; // 下一页的值
console.log('下一页', nextPage, isExceed, params.pageSize)
if (isExceed || centerData.length >= params.pageSize || nextPage === 0) {
params.queryType === 0 ? setPrevPlaceholderTasks(params) : setNextPlaceholderTasks(params);
showTasks = tasks.value;
console.log('fffffff', showTasks);
}
if (centerData.length === 0 && nextPage === 0) {
params.queryType === 0 ? setPrevPlaceholderTasks(params) : setNextPlaceholderTasks(params);
showTasks = tasks.value;
console.log('ccccc', showTasks);
} else {
console.log('ttttttttt', showTasks);
const firstDetailIndex = showTasks.findIndex(task => task.detailId); // 显示任务中存在真实任务
const firstId = firstDetailIndex > -1 ? showTasks[firstDetailIndex].id : '';
let lastDetailIndex = -1;
showTasks.forEach((item, index) => {
if (item.detailId) {
lastDetailIndex = index;
}
})
const lastId = lastDetailIndex > -1 ? showTasks[lastDetailIndex].id : '';
showTasks.forEach((task, index) => {
const arr = centerData.filter(item => dayjs(+item.planStart).isSame(+task.planStart, timeGranularity.value));
if (arr && arr.length) {
if (firstDetailIndex > -1) {
if (params.queryType === 1 && task.id === lastId) {
showTasks.splice(index + 1, 0, [...arr])
} else if (params.queryType === 0 && task.id === firstId) {
showTasks.splice(index, 0, [...arr])
}
} else {
showTasks.splice(index, 1, [...arr]);
}
}
})
showTasks = flatten(showTasks); // 1维拍平
if (!isExceed) {
if (centerData.length < params.pageSize && nextPage > 0) {
await getTasks({pageNum: nextPage, queryType: params.queryType});
console.log('oooooooo', showTasks);
return;
}
if (centerData.length) {
let len = 0;
let data = params.queryType === 0 ? centerData[0] : centerData[centerData.length - 1];
showTasks.forEach((item, index) => {
if (item.id === data.id) {
len = index;
}
})
showTasks = params.queryType === 0 ? showTasks.slice(len) : showTasks.slice(0, len + 1);
}
}
}
if (showTasks.length > 80) {
showTasks = params.queryType === 0 ? showTasks.slice(0, 80) : showTasks.slice(showTasks.length - 80);
}
store.commit('task/clearTasks');
params.queryType === 0 ? store.commit('task/setUpTasks', showTasks) : store.commit('task/setDownTasks', showTasks);
}
// 任务模式
async function renderConTask(params) {
let nextPage = params.queryType === 0 ? upNextPage.value : downNextPage.value; // 下一页的值
let showTasks = tasks.value;
let centerData = await showTaskId(params, showTasks, realTasks.value) || [];
if (centerData.length < 15 && nextPage > 0) {
getTasks({pageNum: nextPage, queryType: params.queryType});
} else {
if (params.queryType === 0) {
showTasks = [...centerData, ...showTasks];
} else {
showTasks = [...showTasks, ...centerData];
}
}
if (showTasks.length < 15 && nextPage === 0 && params.queryType === 1) {
getTasks({pageNum: 1, queryType: 0});
}
if (showTasks.length > 80) {
showTasks = params.queryType === 0 ? showTasks.slice(0, 80) : showTasks.slice(showTasks.length - 80);
}
store.commit('task/clearTasks');
params.queryType === 0 ? store.commit('task/setUpTasks', showTasks) : store.commit('task/setDownTasks', showTasks);
}
// 设置时间轴向上的空数据
function setPrevPlaceholderTasks() {
store.commit('task/setTopEnd', true);
let startTime = '';
if (!tasks.value || !tasks.value.length) {
startTime = Date.now(); // 没有任务就应该是时间基准点
} else {
startTime = tasks.value[0].planStart - 0; // 有任务就是第一个任务的计划开始时间
}
const placeholderTasks = uni.$task.setPlaceholderTasks(startTime, true, timeGranularity.value);
store.commit('task/setCurrUpTimeNode', startTime);
store.commit('task/setUpTasks', placeholderTasks);
}
// 设置时间轴向下的空数据
function setNextPlaceholderTasks(params) {
// store.commit('task/setBottomEnd', true);
console.log('ddddddddd')
let startTime = '';
if (!tasks.value || !tasks.value.length) {
startTime = Date.now();
} else {
startTime = dayjs(+tasks.value[tasks.value.length - 1].planStart).add(1, timeGranularity.value).valueOf();
}
if (params.taskId) {
realTasks.value.forEach(item => {
if (item.id === params.taskId) {
startTime = Number(item.planStart);
}
})
}
const initData = uni.$task.setPlaceholderTasks(startTime, false, timeGranularity.value);
store.commit('task/setCurrDownTimeNode', startTime);
store.commit('task/setDownTasks', initData);
}
/**
* 当日常任务发生变化时
* 将新获取到的日常任务放在allTasks里
*/
watch(tasks, newValue => {
// 添加到allTasks里
const index = visibleRoles.value.findIndex(role => role.id === roleId.value);
const arr = [...allTasks.value];
arr[index].task = [...newValue];
store.commit('task/setAllTasks', arr);
});
return {
initPlanTasks,
getTasks,
dataRender
}
}

263
hooks/project/useGetTasks - 副本.js

@ -1,263 +0,0 @@
import { computed, nextTick, watch } from 'vue';
import { useStore } from 'vuex';
import { flatten } from 'lodash';
import dayjs from 'dayjs';
export default function useGetTasks() {
const store = useStore();
const tasks = computed(() => store.state.task.tasks);
const basicTasks = computed(() => store.state.task.basicTasks);
const upBasicTasks = computed(() => store.state.task.upBasicTasks);
const nextPage = computed(() => store.state.task.nextPage); // 下一页
const upNextPage = computed(() => store.state.task.upNextPage); // 下一页
// const lastPage = computed(() => store.state.task.lastPage); // 最后一页
const roleId = computed(() => store.state.role.roleId);
const timeNode = computed(() => store.state.task.timeNode);
const timeUnit = computed(() => store.state.task.timeUnit);
const visibleRoles = computed(() => store.state.role.visibleRoles);
const allTasks = computed(() => store.state.task.allTasks);
const roleIndex = computed(() => store.state.role.roleIndex);
const projectId = computed(() => store.getters['project/projectId']);
const timeGranularity = computed(() => store.getters['task/timeGranularity']);
// 初始化 定期任务
async function initPlanTasks() {
await getTasks({}); // 获取初始数据
}
/**
* 根据时间基准点和角色查找定期任务
* @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) {
store.commit('task/setShowSkeleton', false);
const params = {
roleId: roleId.value,
timeUnit: query.timeUnit || timeUnit.value,
queryType: query.queryType === 0 ? 0 : 1,
pageNum: query.pageNum || 1,
pageSize: query.pageSize || uni.$taskConfig.pageCount
}
uni.$catchReq.getTaskByNum(params, (err, data) => {
store.commit('task/setShowSkeleton', false);
if (err) {
// TODO: 提示错误
console.error('err: ', err);
} else {
store.commit('task/setShowScrollTo', true);
if (params.queryType === 0) {
// 将接口返回的数据存储到store
let lists = [...upBasicTasks.value, ...data.list];
store.commit('task/setUpBasicTask', lists);
store.commit('task/setUpNextPage', data.nextPage); // 下一页
} else {
let lists = [...basicTasks.value, ...data.list];
store.commit('task/setBasicTask', lists);
store.commit('task/setNextPage', data.nextPage); // 下一页
}
// 刻度模式数据处理
renderTask(params);
}
});
}
// 刻度模式数据处理
function renderTask(params) {
params.queryType === 0 ? setPrevPlaceholderTasks() : setNextPlaceholderTasks();
tasksData(params);
}
/**
* 刻度模式数据处理
* 大于等于15天真实数据的时间跨度
* 或大于等于15条真实数据的数量
* 不用重新加载数据
* @param {Object} params
*/
function tasksData(params) {
let oldTasks = tasks.value;
let realTasks = params.queryType === 0 ? upBasicTasks.value : basicTasks.value;
// 下一页的值
let next = params.queryType === 0 ? upNextPage.value : nextPage.value;
// 真实数据是否>=15条 || 是否>=15天
let term = tremFilter(params);
if (term || next === 0) {
// 过滤真实数据中在tasks时间段中的数据,并将最后的数据存储到tasksArr数组中
let tasksArr = [], taskLen = 0, lastIndex = 0;
oldTasks.forEach((task, index) => {
const oldArr = oldTasks.filter(item => dayjs(+item.planStart).isSame(+task.planStart, timeGranularity.value));
const arr = realTasks.filter(item => dayjs(+item.planStart).isSame(+task.planStart, timeGranularity.value));
if (arr && arr.length) {
if (task.detailId) {
tasksArr = [...arr];
lastIndex = index;
} else {
taskLen += arr.length; // 在时间刻度内的数据量
oldTasks.splice(index, 1, [...arr]); // 这里加入的数据是array类型的, [{},{},[],[],{}]
}
}
})
// 数据与上一页最后一个数据时间节点相同
if (lastIndex) {
taskLen += tasksArr.length;
oldTasks.splice(lastIndex, 0, [...tasksArr]);
}
oldTasks = flatten(oldTasks); // 1维拍平
if (taskLen === params.pageSize) {
// 如果真实任务所有数据都在tasks时间段中,则将所有任务显示,并且从最后一个真实任务的时间截止,存储到tasks中
let len = 0;
oldTasks.forEach((item, index) => {
if (item.id === realTasks[realTasks.length - 1].id) {
len = index;
}
})
oldTasks = oldTasks.slice(0, len + 1);
params.queryType === 0 ? store.commit('task/setUpBasicTask', []) : store.commit('task/setBasicTask', []);
} else {
// 只有一部分真实数据展示,展示tasks时间段加时间段内的真实数据
params.queryType === 0 ? store.commit('task/setUpBasicTask', realTasks.slice(taskLen)) : store.commit('task/setBasicTask', realTasks.slice(taskLen));
}
store.commit('task/clearTasks');
params.queryType === 0 ? store.commit('task/setUpTasks', oldTasks) : store.commit('task/setDownTasks', oldTasks);
} else {
if (next > 0) {
getTasks({pageNum: params.pageNum, queryType: params.queryType});
}
}
}
/**
* 数据筛选条件
* 大于等于15天真实数据的时间跨度且大于等于15条真实数据的数量不用重新加载数据
*/
function tremFilter(params) {
let time1 = 0, time2 = 0;
let realTasks = basicTasks.value;
if (realTasks.length > 0) {
// 真实数据第一条数据加上15天后的时间
time1 = dayjs(+realTasks[0].planStart).add(params.pageSize, timeGranularity.value);
// 真实数据最后一条数据的时间
time2 = dayjs(realTasks[realTasks.length - 1].planStart, timeGranularity.value);
}
let result1 = false, result2 = false;
// 判断真实任务的时间跨度是否在15天之内
if (time1 > 0 && time2 > 0) {
// 两个时间是否相等
result1 = dayjs(time1).isSame(time2, timeGranularity.value);
// time1是否大于time2
result2 = dayjs(time1).isAfter(time2, timeGranularity.value);
}
let term1 = realTasks.length >= params.pageSize; // 大于等于15条,真实数据的数量
// 大于等于15天,真实数据的时间跨度
let term2 = result1 || result2;
return term1 || term2;
}
/**
* 用拿到的新数据 替换 时间刻度/旧数据
* 先对比 新旧数据的 始末时间 补齐刻度
* 再遍历对比 用任务替换刻度
* @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); // 已经上下补齐时间刻度的
// console.log('oldTasks', oldTasks)
// // 遍历对比 用任务替换刻度
// // 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[obj.tasks.length - 1].planStart, false, obj.timeGranularity, next);
// store.commit('task/setDownTasks', newTasks);
// }
// return tasks.value;
// }
// 设置时间轴向上的空数据
function setPrevPlaceholderTasks() {
store.commit('task/setTopEnd', true);
let startTime = '';
if (!tasks.value || !tasks.value.length) {
startTime = Date.now(); // 没有任务就应该是时间基准点
} else {
startTime = tasks.value[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 = dayjs(+tasks.value[tasks.value.length - 1].planStart).add(1, timeGranularity.value);
}
const initData = uni.$task.setPlaceholderTasks(startTime, false, timeGranularity.value);
store.commit('task/setDownTasks', initData);
}
/**
* 当日常任务发生变化时
* 将新获取到的日常任务放在allTasks里
*/
watch(tasks, newValue => {
// console.log('newValue----->tasks: ', tasks.value);
// 添加到allTasks里
const index = visibleRoles.value.findIndex(role => role.id === roleId.value);
const arr = [...allTasks.value];
arr[index].task = [...newValue];
store.commit('task/setAllTasks', arr);
});
return {
initPlanTasks,
getTasks,
renderTask
};
}

336
hooks/project/useGetTasks222.js

@ -1,336 +0,0 @@
import { computed, nextTick, watch } from 'vue';
import { useStore } from 'vuex';
import { flatten } from 'lodash';
import dayjs from 'dayjs';
export default function useGetTasks() {
const store = useStore();
const tasks = computed(() => store.state.task.tasks);
const timeLineType = computed(() => store.state.task.timeLineType); // 时间轴模式
const realTasks = computed(() => store.state.task.realTasks); // 真实任务
const downNextPage = computed(() => store.state.task.downNextPage); // 下一页
const upNextPage = computed(() => store.state.task.upNextPage); // 下一页
const currUpTimeNode = computed(() => store.state.task.currUpTimeNode); // 当前查询的时间
const currDownTimeNode = computed(() => store.state.task.currDownTimeNode); // 当前查询的时间
const roleId = computed(() => store.state.role.roleId);
const timeNode = computed(() => store.state.task.timeNode);
const timeUnit = computed(() => store.state.task.timeUnit);
const visibleRoles = computed(() => store.state.role.visibleRoles);
const allTasks = computed(() => store.state.task.allTasks);
const roleIndex = computed(() => store.state.role.roleIndex);
const projectId = computed(() => store.getters['project/projectId']);
const timeGranularity = computed(() => store.getters['task/timeGranularity']);
const remindData = computed(() => store.state.socket.remindData); // 小红点
const currRoleRealTasks = computed(() => store.state.task.currRoleRealTasks); // 当前角色的真实任务数据
const currRoleShowTasks = computed(() => store.state.task.currRoleShowTasks); // 当前角色的展示任务数据
const currLocationTaskId = computed(() => store.state.socket.currLocationTaskId);
// 初始化 定期任务
async function initPlanTasks() {
if (timeLineType.value === 1) setNextPlaceholderTasks({});
console.log('查询定期任务');
await getTasks({}); // 获取初始数据
// await dataRender({});
}
/**
* 生成getTasks所用的参数
* @param {object} query getTasks传递的参数
*/
function generateGetTaskParam(query) {
return {
roleId: roleId.value,
timeNode: query.timeNode || timeNode.value,
timeUnit: query.timeUnit || timeUnit.value,
queryType: query.queryType === 0 ? 0 : 1,
pageNum: query.pageNum || 1,
pageSize: query.pageSize || uni.$taskConfig.pageCount,
taskId: query.taskId || currLocationTaskId.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) {
store.commit('task/setShowSkeleton', false);
const params = generateGetTaskParam(query);
console.log('查询定期任务api', params);
uni.$catchReq.getTaskByNum(params, (err, data) => {
store.commit('task/setShowSkeleton', false);
if (err) {
// TODO: 提示错误
console.error('err: ', err);
} else {
store.commit('task/setShowScrollTo', true);
params.queryType === 0 ? store.commit('task/setUpRealTasks', data.list) : store.commit('task/setDownRealTasks', data.list);
console.log('查询到的真实任务', data.list);
const index = visibleRoles.value.findIndex(role => role.id === roleId.value);
console.log('api当前角色id', roleId.value, index);
const arr = [...allTasks.value];
arr[index].realTasks = [...realTasks.value];
arr[index].upNextPage = params.queryType === 0 ? data.nextPage : 1;
arr[index].downNextPage = params.queryType === 1 ? data.nextPage : 1;
store.commit('task/setAllTasks', arr);
console.log('设置当前真实任务', arr[index].realTasks);
store.commit('task/setCurrRoleRealTasks', arr[index].realTasks); // 设置当前角色的真实任务数据
params.queryType === 0 ? store.commit('task/setUpNextPage', arr[index].upNextPage) : store.commit('task/setDownNextPage', arr[index].downNextPage); // 下一页
// 如果第一次渲染但没有空数据则加载空数据
if (!currRoleShowTasks.value || !currRoleShowTasks.value.length && timeLineType.value === 1) {
setNextPlaceholderTasks(params);
}
// 数据处理
dataRender(params);
}
});
}
function dataRender(params) {
timeLineType.value === 1 ? renderScaleTask(params) : renderConTask(params);
}
// 刻度模式数据处理
async function renderScaleTask(query) {
const params = generateGetTaskParam(query);
console.log('当前角色id', roleId.value);
console.log('当前角色的真实任务', currRoleRealTasks.value);
let centerData = await showTaskTime(params, currRoleShowTasks.value, currRoleRealTasks.value) || [];
console.log('需要显示的真实任务', centerData);
await handleTasksData(params, centerData, currRoleRealTasks.value);
}
// 已显示的任务第一个时间和最后一个时间
async function showTaskTime(params, showTasks, realTasks) {
/**
* 1判断显示任务中是否有真实任务
* 1-1根据id查找任务
* 1-2根据时间查找任务
* 2查找15个任务
*/
// 初始值
// 显示任务中没有真实任务数据
let centerData = [];
if (realTasks.length > params.pageSize && params.queryType === 0) {
centerData = realTasks.slice(realTasks.length - params.pageSize);
} else {
centerData = realTasks.slice(0, params.pageSize);
}
const firstDetailIndex = showTasks.findIndex(task => task.detailId);
if (firstDetailIndex > -1) {
// 显示任务中有真实任务数据
const firstId = showTasks[firstDetailIndex].id;
let lastDetailIndex = -1;
showTasks.forEach((item, index) => {
if (item.detailId) {
lastDetailIndex = index;
}
})
const lastId = showTasks[lastDetailIndex].id;
realTasks.forEach((item, index) => {
if (params.queryType === 1 && item.id === lastId) {
centerData = realTasks.slice(index + 1, index + 1 + params.pageSize);
} else if (params.queryType === 0 && item.id === firstId) {
centerData = index >= params.pageSize ? realTasks.slice(index - params.pageSize, index) : realTasks.slice(0, index);
}
})
}
return centerData;
}
async function handleTasksData(params, centerData, realTasks) {
/**
* 3查找的任务数量是否>=15
* 3-1
* 判断时间跨度是否>=15
* 3-1-1显示时间刻度范围内的任务
* 3-1-2显示全部任务并删除多余的刻度
* 3-2
* 判断时间跨度是否>=15
* 3-2-1显示时间刻度范围内的任务
* 3-2-2
* 下一页是否为0
* 3-2-2-1无下一页显示任务和刻度之后继续展示刻度
* 3-2-2-1查找下一页数据并重复上述步骤
*/
let showTasks = currRoleShowTasks.value; // 显示的数据
const nextPage = params.queryType === 0 ? upNextPage.value : downNextPage.value; // 下一页的值
if (centerData.length) {
let centerDataTime = '', // 中间数据的时间
scaleTime = '', // 空时间节点的开始时间
centerTime = '', // 中间数据+/-15后的数据
isExceed = false; // 时间跨度是否大于15
if (params.queryType) {
centerDataTime = centerData[centerData.length - 1].planStart;
scaleTime = currDownTimeNode.value;
centerTime = dayjs(+centerDataTime).subtract(params.pageSize, timeGranularity.value);
isExceed = dayjs(+centerTime).isSame(+scaleTime, timeGranularity.value) || dayjs(+centerTime).isAfter(+scaleTime, timeGranularity.value)
} else {
centerDataTime = centerData[0].planStart;
scaleTime = currUpTimeNode.value;
centerTime = dayjs(+centerDataTime).add(params.pageSize, timeGranularity.value);
isExceed = dayjs(+centerTime).isSame(+scaleTime, timeGranularity.value) || dayjs(+centerTime).isBefore(+scaleTime, timeGranularity.value)
}
const firstDetailIndex = showTasks.findIndex(task => task.detailId); // 显示任务中存在真实任务
const firstId = firstDetailIndex > -1 ? showTasks[firstDetailIndex].id : '';
let lastDetailIndex = -1;
showTasks.forEach((item, index) => {
if (item.detailId) {
lastDetailIndex = index;
}
})
const lastId = lastDetailIndex > -1 ? showTasks[lastDetailIndex].id : '';
showTasks.forEach((task, index) => {
const arr = centerData.filter(item => dayjs(+item.planStart).isSame(+task.planStart, timeGranularity.value));
if (arr.length) {
if (params.queryType === 1 && task.id === lastId) {
showTasks.splice(index + 1, 0, [...arr])
} else if (params.queryType === 0 && task.id === firstId) {
showTasks.splice(index, 0, [...arr])
} else {
showTasks.splice(index, 1, [...arr])
}
}
})
showTasks = flatten(showTasks); // 1维拍平
if (!isExceed) {
if (centerData.length >= params.pageSize) {
let len = -1;
let data = params.queryType === 0 ? centerData[0] : centerData[centerData.length - 1];
showTasks.forEach((item, index) => {
if (item.id === data.id) {
len = index;
}
})
if (len > -1) {
showTasks = params.queryType === 0 ? showTasks.slice(len) : showTasks.slice(0, len + 1);
}
} else if (nextPage > 0) {
console.log('数据不为空,时间跨度小于15')
getTasks({pageNum: nextPage, queryType: params.queryType});
}
}
} else {
if (nextPage > 0) {
console.log('数据为空')
getTasks({pageNum: nextPage, queryType: params.queryType});
} else {
params.queryType === 0 ? setPrevPlaceholderTasks(params) : setNextPlaceholderTasks(params);
}
}
// if (showTasks.length > 30) {
// showTasks = params.queryType === 0 ? showTasks.slice(0, 80) : showTasks.slice(showTasks.length - 80);
// }
store.commit('task/clearTasks');
params.queryType === 0 ? store.commit('task/setUpTasks', showTasks) : store.commit('task/setDownTasks', showTasks);
}
// 任务模式
async function renderConTask(params) {
let nextPage = params.queryType === 0 ? upNextPage.value : downNextPage.value; // 下一页的值
let showTasks = currRoleShowTasks.value;
let centerData = await showTaskTime(params, showTasks, currRoleRealTasks.value) || [];
if (centerData.length < 15 && nextPage > 0) {
getTasks({pageNum: nextPage, queryType: params.queryType});
} else {
if (params.queryType === 0) {
showTasks = [...centerData, ...showTasks];
} else {
showTasks = [...showTasks, ...centerData];
}
}
if (showTasks.length < 15 && nextPage === 0 && params.queryType === 1) {
getTasks({pageNum: 1, queryType: 0});
}
if (showTasks.length > 80) {
showTasks = params.queryType === 0 ? showTasks.slice(0, 80) : showTasks.slice(showTasks.length - 80);
}
store.commit('task/clearTasks');
params.queryType === 0 ? store.commit('task/setUpTasks', showTasks) : store.commit('task/setDownTasks', showTasks);
}
// 设置时间轴向上的空数据
function setPrevPlaceholderTasks() {
store.commit('task/setTopEnd', true);
let startTime = '';
if (!currRoleShowTasks.value || !currRoleShowTasks.value.length) {
startTime = Date.now(); // 没有任务就应该是时间基准点
} else {
startTime = currRoleShowTasks.value[0].planStart - 0; // 有任务就是第一个任务的计划开始时间
}
const placeholderTasks = uni.$task.setPlaceholderTasks(startTime, true, timeGranularity.value);
store.commit('task/setCurrUpTimeNode', startTime);
store.commit('task/setUpTasks', placeholderTasks);
}
// 设置时间轴向下的空数据
function setNextPlaceholderTasks(params) {
// store.commit('task/setBottomEnd', true);
let startTime = '';
if (!currRoleShowTasks.value || !currRoleShowTasks.value.length) {
startTime = Date.now();
} else {
startTime = dayjs(+currRoleShowTasks.value[currRoleShowTasks.value.length - 1].planStart).add(1, timeGranularity.value).valueOf();
}
if (params.taskId) {
currRoleRealTasks.value.forEach(item => {
if (item.id === params.taskId) {
startTime = Number(item.planStart);
}
})
}
const initData = uni.$task.setPlaceholderTasks(startTime, false, timeGranularity.value);
store.commit('task/setCurrDownTimeNode', startTime);
store.commit('task/setDownTasks', initData);
}
/**
* 当日常任务发生变化时
* 将新获取到的日常任务放在allTasks里
*/
watch(tasks, () => {
// 添加到allTasks里
const index = visibleRoles.value.findIndex(role => role.id === roleId.value);
const arr = [...allTasks.value];
arr[index].task = [...tasks.value];
store.commit('task/setAllTasks', arr);
store.commit('task/setCurrRoleShowTasks', arr[index].task); // 设置当前角色的展示任务数据
});
return {
initPlanTasks,
getTasks,
dataRender
}
}

6
pages.json

@ -62,6 +62,12 @@
"navigationBarTitleText": "审核记录"
}
},
{
"path": "pages/detail/detail",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/detailWebview/detailWebview",
"style": {

26
pages/detail/detail.vue

@ -0,0 +1,26 @@
<template>
<!-- 考勤详情页 -->
<p-check-work-detail v-if="key === 'checkWork'" :clockParams="params"></p-check-work-detail>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import pCheckWorkDetail from "@/plugins/p-check-work/detail";
let key = ref(null);
let params = ref({});
onMounted(() => {
key.value = uni.$storage.getStorageSync('pluginKey');
})
//
function checkClock(data) {
params.value = data;
// uni.$storage.setStorageSync('pluginKey', 'checkWork');
key.value = 'checkWork';
}
</script>
<style>
</style>

142
pages/project/project 复制.vue

@ -1,142 +0,0 @@
<template>
<theme :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" />
<!-- TODO: DEBUG: -->
<u-button @click="$store.commit('setTheme', 'theme-test')">测试切换主题</u-button>
</view>
</theme>
</template>
<script setup>
import { ref, computed, watch, onMounted } from 'vue';
import { useStore } from 'vuex';
import useInit from '@/hooks/project/useInit';
import useGetTasks from '@/hooks/project/useGetTasks';
const initHook = useInit();
const getTasksHook = useGetTasks();
const store = useStore();
const roleId = computed(() => store.state.role.roleId);
const timeNode = computed(() => store.state.task.timeNode);
const timeUnit = computed(() => store.state.task.timeUnit);
const projectId = computed(() => store.getters['project/projectId']);
const userId = computed(() => store.getters['user/userId']);
const newProjectInfo = computed(() => store.state.task.newProjectInfo);
const showScrollTo = computed(() => store.state.task.showScrollTo);
const height = ref(null);
const timeLine = ref(null);
onMounted(() => {
const system = uni.getSystemInfoSync();
height.value = `${system.windowHeight}px`;
});
//
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');
}
/**
* 当时间基准点发生变化时
* 重新根据时间和角色查询普通日常任务
* 永久日常任务不发生 改变
*/
watch(timeNode, newValue => {
if (newValue && roleId.value) {
console.log('当时间基准点发生变化时');
clearTasksData();
getGlobalData(); //
getTasksHook.initPlanTasks(); //
//
let timer = null;
timer = setInterval(() => {
if (showScrollTo.value) {
clearInterval(timer);
console.log('timeLine: ', timeLine);
timeLine.value.setScrollPosition();
}
}, 500);
}
});
/**
* 当角色发生变化时
* 重新查询永久日常任务和普通日常任务
* 注意: 切换角色后 重新设置了时间基准点 时间基准点一定会变
* 所以监听时间基准点获取 可变日常任务即可 这里不用获取 避免重复获取
*/
watch(roleId, newValue => {
if (newValue) {
console.log('当角色发生变化时', newValue);
store.commit('task/setTimeNode', Date.now());
//
const params = {
roleId: newValue,
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;
initHook.init(options);
}
});
function getTasks(params) {
getTasksHook.initPlanTasks(params); //
}
</script>
<style lang="scss" scoped>
.border-b {
border-bottom: 1px solid #e4e7ed;
}
</style>

66
pages/submitLog/submitLog - 副本.vue

@ -1,66 +0,0 @@
<template>
<theme class="min-h-full">
<view class="px-3 pt-1" v-if="listRef && listRef.length">
<view class="bg-white my-2 rounded-md p-3 text-gray-400" v-for="item in listRef">
<!-- 插件名称和提交时间显示 -->
<view class="flex justify-between mb-2">
<view class="text-gray-800">{{ deliverName }}</view>
<view class="text-xs">{{ dayjs(+item.submitTime).format('MM-DD HH:mm') }}</view>
</view>
<!-- 提交的链接 -->
<DeliverLink v-if="item.details[0]" :link="item.details[0]" />
<!-- 该插件物的审核人 -->
<view class="mb-1 mt-3">审核人</view>
<view class="flex justify-between mb-2" v-for="checkItem in item.checkerList">
<view>
<view class="mb-1 text-gray-800 font-semibold">
{{ checkItem.checkerName }}
</view>
<view class="mb-1 text-xs">
{{ checkItem.remark }}
</view>
<view class="mb-1 text-xs" v-if="+checkItem.checkTime > 0">
{{ dayjs(+checkItem.checkTime).format('MM-DD HH:mm') }}
</view>
</view>
<view class="text-center text-xs">
<view v-if="checkItem.status == null" class="text-gray-400">待审核</view>
<view v-else-if="checkItem.status === 1">
<view class="text-green-600 mb-1">已通过</view>
<zwp-ring-timing mode="chart" :value="checkItem.score" active-color="#F59E0B" :radius="30" :bar-width="4">
<text class="text-yellow-500 font-medium">{{ checkItem.score }}</text>
</zwp-ring-timing>
</view>
<view class="text-red-600" v-else>已驳回</view>
</view>
</view>
</view>
</view>
<u-empty text="暂无记录" mode="history" style="padding-top: 120rpx" v-else></u-empty>
</theme>
</template>
<script setup>
import { ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import dayjs from 'dayjs';
const listRef = ref([]);
const deliverName = ref('');
onLoad(options => {
// id
(async function getHistory() {
try {
const param = { deliverId: options.deliverId };
const data = await uni.$u.api.getDeliverHistory(param);
deliverName.value = data.deliverName;
listRef.value = data.deliverRecordList;
} catch (error) {
console.log('error: ', error);
uni.$ui.showToast('获取交付物历史失败');
}
})();
});
</script>

395
plugins/p-check-work/detail.vue

@ -0,0 +1,395 @@
<template>
<view>
<!-- 标题 + 筛选 -->
<view class="check-work-title px-3 fixed top-0 z-10 w-full flex justify-between items-center bg-white">
<text>考勤管理</text>
<view>
<u-button class="mr-3" size="mini" type="primary" @click="isShow = !isShow">过滤</u-button>
<u-button size="mini" type="primary" @click="isShow = !isShow">导出</u-button>
</view>
</view>
<!-- 列表 -->
<view class="check-work-list">
<u-table class="table-head">
<u-tr>
<u-th>姓名</u-th>
<u-th></u-th>
<u-th></u-th>
<u-th width="30%">审核人</u-th>
</u-tr>
</u-table>
<view v-if="clockInfos.length" v-for="(list, listIndex) in clockInfos" :key="listIndex">
<view class="table-time px-2">{{ list.dateTime }}</view>
<u-table class="table-body">
<u-tr v-if="list.recordList.length" v-for="(item, index) in list.recordList" :key="index">
<u-td>{{ item.memberName }}</u-td>
<u-td>
<template v-if="!item.morningStatus">
<view v-if="item.isMine === 1">
<u-button class="m-0" size="mini" type="primary" @click="showTimeSelect(0, item)">早打卡</u-button>
</view>
<template v-else>
<view>未打卡</view>
</template>
</template>
<view v-else class="flex justify-center">
<view :class="{'relative': item.morningStatus === 1}">
<text :class="{'font-semibold': item.isMine === 1 || item.isChecker === 1,
'text-green-500': item.isChecker === 1 && (item.morningStatus === 1 || item.morningStatus === 3),
'line-through': item.morningStatus === 2,
'text-gray-400': item.morningStatus === 2 && (item.isMine === 1 || item.isChecker === 1),
'text-cyan': item.morningStatus === 3 && item.isMine === 1}"
@click="showActionPanel(item.morningStatus, 'morning', item.morning, item)"
>
{{ dayjs(+item.morning).format("HH:mm") }}
</text>
<!-- 小红点 -->
<template v-if="item.morningStatus === 1">
<u-badge v-if="item.isMine === 1" :is-dot="true"
type="error" size="mini" style="top: -2px; right: -10px;"></u-badge>
<!-- 小红点 -->
<template v-else-if="item.isChecker === 1">
<u-badge class="animate-ping" :is-dot="true" type="error" size="mini" style="top: -2px; right: -10px;"></u-badge>
<u-badge :is-dot="true" type="error" size="mini" style="top: -2px; right: -10px;"></u-badge>
</template>
<!-- 小红点 -->
<u-badge v-else :is-dot="true"
type="warning" size="mini" style="top: -2px; right: -10px;"></u-badge>
</template>
</view>
</view>
</u-td>
<u-td>
<template v-if="!item.nightStatus">
<view v-if="item.isMine === 1">
<u-button class="m-0" size="mini" type="primary" @click="showTimeSelect(1, item)">晚打卡</u-button>
</view>
<template v-else>
<view>未打卡</view>
</template>
</template>
<view v-else class="flex justify-center">
<view :class="{'relative': item.nightStatus === 1}">
<text :class="{'font-semibold': item.isMine === 1 || item.isChecker === 1,
'text-green-500': item.isChecker === 1 && (item.nightStatus === 1 || item.nightStatus === 3),
'line-through': item.nightStatus === 2,
'text-gray-400': item.nightStatus === 2 && (item.isMine === 1 || item.isChecker === 1),
'text-cyan': item.nightStatus === 3 && item.isMine === 1}"
@click="showActionPanel(item.nightStatus, 'night', item.night, item)"
>
{{ dayjs(+item.night).format("HH:mm") }}
</text>
<!-- 小红点 -->
<template v-if="item.nightStatus === 1">
<u-badge v-if="item.isMine === 1" :is-dot="true"
type="error" size="mini" style="top: -2px; right: -10px;"></u-badge>
<!-- 小红点 -->
<template v-else-if="item.isChecker === 1">
<u-badge class="animate-ping" :is-dot="true" type="error" size="mini" style="top: -2px; right: -10px;"></u-badge>
<u-badge :is-dot="true" type="error" size="mini" style="top: -2px; right: -10px;"></u-badge>
</template>
<!-- 小红点 -->
<u-badge v-else :is-dot="true"
type="warning" size="mini" style="top: -2px; right: -10px;"></u-badge>
</template>
</view>
</view>
</u-td>
<u-td width="30%">
<view class="flex justify-center">
<view v-if="item.isMine === 1 && (!item.morningStatus && !item.nightStatus)" class="px-2 py-1 flex items-center border border-solid rounded border-gray-200" @click="show = true">
<text class="mr-3 whitespace-nowrap">{{ item.lastCheckerName ? item.lastCheckerName : item.checkerName ? item.checkerName : checkerName }}</text>
<u-icon size="24" name="arrow-down"></u-icon>
</view>
<view v-else>{{ item.lastCheckerName ? item.lastCheckerName : item.checkerName ? item.checkerName : '周勇' }}</view>
</view>
</u-td>
</u-tr>
</u-table>
</view>
</view>
<!-- 审核人列表 -->
<u-select v-model="show" :list="list" @confirm="confirm"></u-select>
<!-- 审核操作按钮列表 -->
<u-action-sheet :list="actions" v-model="actionShow" @click="clickAction"></u-action-sheet>
<!-- 时间选择框 -->
<u-picker mode="time" v-model="showModal" :params="params" @confirm="changeTime"></u-picker>
<!-- 筛选框 -->
<SearchPopup v-if="isShow" :members="list" :show="isShow" @closePopup="closePopup" @getClockQuery="getClockQuery" @clockExport="clockExport"></SearchPopup>
</view>
</template>
<script setup>
import { computed, onMounted, ref } from 'vue';
import { useStore } from 'vuex';
import dayjs from 'dayjs';
import SearchPopup from '@/components/SearchPopup/SearchPopup.vue';
const props = defineProps({
clockParams: {
type: Object,
default: () => {}
}
})
const store = useStore();
const projectId = uni.$storage.getStorageSync('projectId');
const roleId = uni.$storage.getStorageSync('roleId');
const checkers = uni.$storage.getStorageSync('checkers'); //
const url = uni.$storage.getStorageSync('domain');
let clockInfos = ref([]); //
const show = ref(false); //
let list = ref([]); //
let actionShow = ref(false); //
const actions = ref([{ text: '修改' }, { text: '驳回' }, { text: '确认' }]); //
let examineParams = ref({}); //
let showModal = ref(false); //
const params = ref({year: false, month: false, day: false, hour: true, minute: true, timestamp: true})
let checkerId = ref(null);
let checkerName = ref(null);
let isShow = ref(false);
let timeType = ref(null); // 0 1
let actionType = ref(0); // 0 1
let currRecord = ref({}); //
let selectedTime = ref(null); //
let startTime = dayjs().startOf('day').valueOf();
let endTime = dayjs().endOf('day').valueOf();
let memberIdList = ref([]);
onMounted(() => {
list.value = [];
let checker_arr = JSON.parse(checkers);
checker_arr.forEach(item => {
list.value.push({
value: item.memberId,
label: item.name
})
if (item.name === '周勇') {
checkerId.value = item.memberId;
checkerName.value = item.name;
}
})
getClockQuery(props.clockParams);
})
/**
* 批量查询打卡信息
*/
async function getClockQuery(data) {
closePopup();
startTime = data ? dayjs(data.startTime).startOf('day').valueOf() : startTime;
endTime = data ? dayjs(data.endTime).endOf('day').valueOf() : endTime;
memberIdList.value = data ? data.memberIdList : memberIdList.value;
try {
const params = { projectId, roleId, memberIdList: memberIdList.value, startTime, endTime }
const data = await uni.$u.api.clockQuery(params, url);
data.forEach(list => {
let arr = [];
list.recordList.forEach(item => {
if (item.isMine === 1) {
arr.push(item);
}
})
list.recordList.forEach(item => {
if (item.isChecker === 1) {
arr.push(item);
}
})
list.recordList.forEach(item => {
if (!item.isMine && !item.isChecker) {
arr.push(item);
}
})
list.recordList = arr;
})
clockInfos.value = data;
} catch (error) {
console.log('error: ', error);
}
}
//
function confirm(e) {
checkerId.value = e[0].value;
checkerName.value = e[0].label;
}
//
function showTimeSelect(clockType, record) {
showModal.value = true;
actionType.value = 0;
timeType.value = clockType;
currRecord.value = record;
}
//
async function punch() {
checkerId.value = currRecord.value.lastCheckerId ? currRecord.value.lastCheckerId : currRecord.value.checkerId ? currRecord.value.checkerId : checkerId.value;
try {
const params = {
checkerId: checkerId.value,
id: !currRecord.value.id ? '' : currRecord.value.id,
memberId: currRecord.value.memberId,
dateTime: selectedTime.value,
clockType: timeType.value,
remark: ''
}
const data = await uni.$u.api.clockPunch(params, url);
getClockQuery(); //
} catch (error) {
console.log('error: ', error);
}
}
//
async function showActionPanel(status, type, time, data) {
if (status !== 1) return;
actionShow.value = true;
timeType.value = type;
examineParams.value = { id: data.id, [type]: time, projectId, type: 0 };
}
// 0 1 2
function clickAction(index) {
// if (timeType.value === 'morning') {
// if (index === 0 || index === 2) {
// examineParams.value.morningStatus = 3;
// } else if (index === 1) {
// examineParams.value.morningStatus = 2;
// }
// } else {
// if (index === 0 || index === 2) {
// examineParams.value.nightStatus = 3;
// } else if (index === 1) {
// examineParams.value.nightStatus = 2;
// }
// }
if (index === 1) { //
examineParams.value.type = 1;
} else if (index === 2) { //
examineParams.value.type = 2;
}
if (index === 0) {
//
showModal.value = true;
actionType.value = 1;
} else {
handleClockAudit();
}
}
//
function changeTime(e) {
selectedTime.value = e.timestamp * 1000;
examineParams.value[timeType.value] = e.timestamp * 1000;
if (actionType.value === 0) {
punch();
} else {
handleClockAudit();
}
}
//
async function handleClockAudit() {
try {
const data = await uni.$u.api.clockAudit(examineParams.value, url);
getClockQuery();
} catch (error) {
console.log('error: ', error);
}
}
//
function closePopup(data) {
isShow.value = data;
}
//
function clockExport() {
closePopup();
}
</script>
<style lang="scss" scoped>
.whitespace-nowrap {
white-space: nowrap;
}
.check-work-title {
height: 50px;
border-bottom: 1px solid #e8e8e8;
}
.check-work-list {
padding-top: 50px;
}
.u-table {
border-left: unset !important;
}
.table-head {
border-top: unset !important;
}
.u-th {
border-right: unset !important;
height: 36px;
background: #fafafa;
}
.u-td {
border-right: unset !important;
height: 40px;
}
.table-time {
height: 30px;
line-height: 30px;
background: #fafafa;
}
.text-cyan {
color: #3B83F6;
}
</style>

165
plugins/p-check-work/p-check-work.vue

@ -0,0 +1,165 @@
<template>
<view class="p-4 flex justify-between items-center">
<view>
<u-button class="m-0" size="mini" type="primary" @click="punch(0)" v-if="!currPunchInfo.morningStatus">早打卡</u-button>
<template v-else>
<!-- 1 待审核 2 已驳回 3 已通过 -->
<view :class="{'relative': currPunchInfo.morningStatus === 1}">
<text class="font-semibold"
:class="{'line-through text-red-500': currPunchInfo.morningStatus === 2, 'text-cyan': currPunchInfo.morningStatus === 3}"
>
{{ dayjs(+currPunchInfo.morning).format("HH:mm") }}
</text>
<!-- 小红点 -->
<u-badge v-if="currPunchInfo.morningStatus === 1"
:is-dot="true" type="error" size="mini" style="top: -2px; right: -10px;"
></u-badge>
</view>
</template>
</view>
<view>
<u-button class="m-0" size="mini" type="primary" @click="punch(1)" v-if="!currPunchInfo.nightStatus">晚打卡</u-button>
<template v-else>
<!-- 1 待审核 2 已驳回 3 已通过 -->
<view :class="{'relative': currPunchInfo.nightStatus === 1}">
<text class="font-semibold"
:class="{'line-through text-red-500': currPunchInfo.nightStatus === 2, 'text-cyan': currPunchInfo.nightStatus === 3}"
>
{{ dayjs(+currPunchInfo.night).format("HH:mm") }}
</text>
<!-- 小红点 -->
<u-badge v-if="currPunchInfo.nightStatus === 1"
:is-dot="true" type="error" size="mini" style="top: -2px; right: -10px;"
></u-badge>
</view>
</template>
</view>
<!-- 审核人 -->
<view class="flex items-center">
<view class="mr-2 flex items-center rounded-md border-gray-200"
:class="{'px-2 py-1 border border-solid': !(currPunchInfo.morning && currPunchInfo.night)}"
@click="showCheckerList">
<text>{{ checkerName ? checkerName : members[0].name }}</text>
<u-icon v-if="!(currPunchInfo.morning && currPunchInfo.night)" class="ml-3" size="24" name="arrow-down"></u-icon>
</view>
<u-icon size="30" name="arrow-right" @click="toDetail"></u-icon>
<u-select v-model="show" :list="list" @confirm="confirm"></u-select>
</view>
</view>
</template>
<script setup>
import { computed, onMounted, ref, watch } from 'vue';
import { useStore } from 'vuex';
import dayjs from 'dayjs';
const store = useStore();
const projectId = computed(() => store.getters['project/projectId']);
const roleId = computed(() => store.state.role.roleId);
const members = computed(() => store.state.role.members); //
const businessCode = computed(() => store.state.task.businessCode); //
let currPunchInfo = ref({}); //
const show = ref(false); //
let list = ref([]); //
let checkerId = ref(null); // id
let checkerName = ref(null); //
onMounted(async () => {
//
await handleUser();
await getClockQuery();
})
//
async function handleUser() {
//
list.value = [];
members.value.forEach(item => {
list.value.push({
value: item.memberId,
label: item.name
})
if (item.name === '周勇') {
checkerId.value = item.memberId;
checkerName.value = item.name;
}
})
}
/**
* 批量查询打卡信息
*/
async function getClockQuery() {
let startTime = dayjs().startOf('day').valueOf().toString();
let endTime = dayjs().endOf('day').valueOf().toString();
try {
const params = { projectId: projectId.value, roleId: roleId.value, memberIdList: [], startTime, endTime }
const data = await uni.$u.api.clockQuery(params);
currPunchInfo.value = data[0].recordList[0];
checkerId.value = currPunchInfo.value.lastCheckerId ? currPunchInfo.value.lastCheckerId : currPunchInfo.value.checkerId ? currPunchInfo.value.checkerId : checkerId.value;
checkerName.value = currPunchInfo.value.lastCheckerName ? currPunchInfo.value.lastCheckerName : currPunchInfo.value.checkerName ? currPunchInfo.value.checkerName : checkerName.value;
} catch (error) {
console.log('error: ', error);
}
}
function showCheckerList() {
if (!(currPunchInfo.morning && currPunchInfo.night)) {
show.value = true
}
}
//
function confirm(e) {
checkerId.value = e[0].value;
checkerName.value = e[0].label;
}
//
async function punch(clockType) {
try {
const params = {
checkerId: checkerId.value,
id: currPunchInfo.value.id,
memberId: currPunchInfo.value.memberId,
dateTime: dayjs().valueOf(),
clockType,
longitude: "",
latitude: ""
}
const data = await uni.$u.api.clockPunch(params);
getClockQuery(); //
} catch (error) {
console.log('error: ', error);
}
}
function toDetail() {
uni.$storage.setStorageSync('pluginKey', 'checkWork');
uni.navigateTo({
url: "/pages/detail/detail"
})
}
</script>
<style lang="scss" scoped>
.text-cyan {
color: #13acc4;
}
</style>

1
store/index.js

@ -97,6 +97,7 @@ const mutations = {
*/
setDomain(state, data) {
state.domain = data;
uni.$storage.setStorageSync('domain', data);
},
/**

Loading…
Cancel
Save