|
|
@ -2,61 +2,95 @@ |
|
|
|
<a-divider /> |
|
|
|
<div class="list-flex"> |
|
|
|
<div class="item-box" v-for="(item, index) in projects" :key="index"> |
|
|
|
<div class="one-level h-70 cursor-pointer flex items-center" @click="toDetail(item)"> |
|
|
|
<div class="icon" @click.stop="showActionCard(item)"><img src="https://www.tall.wiki/staticrec/drag.svg" /></div> |
|
|
|
<div class="detail"> |
|
|
|
<div class="name-box flex items-center" :class="{ 'mb-2': item.businessCode !== 'ZERO' }"> |
|
|
|
<div class="name truncate">{{ item.name }}</div> |
|
|
|
<div class="precent-num"> |
|
|
|
{{ item.status === 1 ? '进行中' : item.status === 2 ? '已结束' : item.status === 0 ? '未开始' : '暂停' }} |
|
|
|
<div class="one-level h-70 cursor-pointer flex items-center"> |
|
|
|
<!-- <div class="icon" @click.stop="showActionCard(item)"><img src="https://www.tall.wiki/staticrec/drag.svg" /></div> --> |
|
|
|
<div class="flex-none"> |
|
|
|
<a-popover placement="bottomLeft"> |
|
|
|
<template #content> |
|
|
|
<p class="cursor-pointer" @click="showImportCard(item)">导入</p> |
|
|
|
<p class="cursor-pointer" @click="exportProject(item.id)">导出</p> |
|
|
|
<p class="m-0 cursor-pointer" @click="showDelCard(item)">删除</p> |
|
|
|
</template> |
|
|
|
<div class="icon"><img src="https://www.tall.wiki/staticrec/drag.svg" /></div> |
|
|
|
</a-popover> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="w-full flex items-center justify-between" @click="toDetail(item)"> |
|
|
|
<div class="detail"> |
|
|
|
<div class="name-box flex items-center" :class="{ 'mb-2': item.businessCode !== 'ZERO' }"> |
|
|
|
<div class="name truncate">{{ item.name }}</div> |
|
|
|
<div class="precent-num"> |
|
|
|
{{ item.status === 1 ? '进行中' : item.status === 2 ? '已结束' : item.status === 0 ? '未开始' : '暂停' }} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="time" v-if="item.businessCode !== 'ZERO'"> |
|
|
|
{{ dayjs(Number(item.startTime)).format('MM-DD HH:mm') }} 至 |
|
|
|
{{ dayjs(Number(item.endTime)).format('MM-DD HH:mm') }} |
|
|
|
<div class="time" v-if="item.businessCode !== 'ZERO'"> |
|
|
|
{{ dayjs(Number(item.startTime)).format('MM-DD HH:mm') }} 至 |
|
|
|
{{ dayjs(Number(item.endTime)).format('MM-DD HH:mm') }} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="right flex justify-end items-center" @click.stop="openMenu"> |
|
|
|
<a-button v-if="item.businessCode === 'ZERO'" class="mr-2" shape="round" type="primary" @click="toWorkbench(item)"> |
|
|
|
工作台 |
|
|
|
</a-button> |
|
|
|
<div class="right flex justify-end items-center" @click.stop="openMenu"> |
|
|
|
<a-button v-if="item.businessCode === 'ZERO'" class="mr-2" shape="round" type="primary" @click="toWorkbench(item)"> |
|
|
|
工作台 |
|
|
|
</a-button> |
|
|
|
|
|
|
|
<RightOutlined v-if="!item.show" @click="changeShow(item)" /> |
|
|
|
<DownOutlined v-else @click="changeShow(item)" /> |
|
|
|
<RightOutlined v-if="!item.show" @click="changeShow(item)" /> |
|
|
|
<DownOutlined v-else @click="changeShow(item)" /> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="two-box" v-if="item.show"> |
|
|
|
<div class="two-flex" v-for="(sonItem, sonIndex) in item.sonProjectList" :key="sonIndex"> |
|
|
|
<div class="two-level h-70 cursor-pointer flex items-center" @click="toDetail(sonItem)"> |
|
|
|
<div class="icon" @click.stop="showActionCard(sonItem)"><img src="https://www.tall.wiki/staticrec/drag.svg" /></div> |
|
|
|
<div class="detail"> |
|
|
|
<div class="name-box mb-2 flex items-center"> |
|
|
|
<div class="name truncate">{{ sonItem.name }}</div> |
|
|
|
<div class="precent-num"> |
|
|
|
{{ item.status === 1 ? '进行中' : item.status === 2 ? '已结束' : item.status === 0 ? '未开始' : '暂停' }} |
|
|
|
<div class="two-level h-70 cursor-pointer flex items-center"> |
|
|
|
<!-- <div class="icon" @click.stop="showActionCard(sonItem)"><img src="https://www.tall.wiki/staticrec/drag.svg" /></div> --> |
|
|
|
|
|
|
|
<div class="flex-none"> |
|
|
|
<a-popover placement="bottomLeft"> |
|
|
|
<template #content> |
|
|
|
<p class="cursor-pointer" @click="showImportCard(sonItem)">导入</p> |
|
|
|
<p class="cursor-pointer" @click="exportProject(sonItem.id)">导出</p> |
|
|
|
<p class="m-0 cursor-pointer" @click="showDelCard(sonItem)">删除</p> |
|
|
|
</template> |
|
|
|
<div class="icon"><img src="https://www.tall.wiki/staticrec/drag.svg" /></div> |
|
|
|
</a-popover> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="flex items-center justify-between" style="width: calc(100% - 32px)" @click="toDetail(sonItem)"> |
|
|
|
<div class="detail"> |
|
|
|
<div class="name-box mb-2 flex items-center"> |
|
|
|
<div class="name truncate">{{ sonItem.name }}</div> |
|
|
|
<div class="precent-num"> |
|
|
|
{{ item.status === 1 ? '进行中' : item.status === 2 ? '已结束' : item.status === 0 ? '未开始' : '暂停' }} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="time"> |
|
|
|
{{ dayjs(Number(sonItem.startTime)).format('MM-DD HH:mm') }} 至 {{ dayjs(Number(sonItem.endTime)).format('MM-DD HH:mm') }} |
|
|
|
<div class="time"> |
|
|
|
{{ dayjs(Number(sonItem.startTime)).format('MM-DD HH:mm') }} 至 {{ dayjs(Number(sonItem.endTime)).format('MM-DD HH:mm') }} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="right" @click.stop="openMenu"> |
|
|
|
<RightOutlined v-if="!sonItem.show" @click="changeShow(sonItem)" /> |
|
|
|
<DownOutlined v-else @click="changeShow(sonItem)" /> |
|
|
|
<div class="right" @click.stop="openMenu"> |
|
|
|
<RightOutlined v-if="!sonItem.show" @click="changeShow(sonItem)" /> |
|
|
|
<DownOutlined v-else @click="changeShow(sonItem)" /> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<input class="import-wbs hidden" type="file" @change="toImport" /> |
|
|
|
<a-modal v-model:visible="importVisible" title="导入" @ok="handleImport"> |
|
|
|
<p>确定要导入到{{ importParent }}吗?</p> |
|
|
|
</a-modal> |
|
|
|
|
|
|
|
<a-modal v-model:visible="visible" title="删除" @ok="handleOk"> |
|
|
|
<p>确定要删除吗?</p> |
|
|
|
</a-modal> |
|
|
|
|
|
|
|
<nested v-if="projects.length > 0" :lists="projects" @changeData="handleChangeData"></nested> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
|
|
|
@ -65,13 +99,19 @@ import { ref, watch, computed } from 'vue'; |
|
|
|
import { useStore } from 'vuex'; |
|
|
|
import { useRouter } from 'vue-router'; |
|
|
|
import dayjs from 'dayjs'; |
|
|
|
import { getProjects, delProject } from 'apis'; |
|
|
|
import { getProjects, delProject, setProjectSort, exportWbs, importWbs } from 'apis'; |
|
|
|
import { RightOutlined, DownOutlined } from '@ant-design/icons-vue'; |
|
|
|
import { message } from 'ant-design-vue'; |
|
|
|
import draggable from 'vuedraggable'; |
|
|
|
import nested from 'components/tall/Center/nested.vue'; |
|
|
|
|
|
|
|
const store = useStore(); |
|
|
|
const router = useRouter(); |
|
|
|
const visible = ref(false); // 删除弹框 |
|
|
|
const importVisible = ref(false); // 导入弹框 |
|
|
|
const importParent = ref(null); // 导入的目标项目名称 |
|
|
|
const importParentId = ref(null); // 导入的目标项目ID |
|
|
|
const currUrl = ref(null); // 当前导入的url |
|
|
|
const deleteId = ref(null); // 删除项目id |
|
|
|
const sessionProject = sessionStorage.getItem('project'); // 项目信息缓存 |
|
|
|
const projectInfo = computed(() => store.state.projects.project); // 当前选择项目信息 |
|
|
@ -101,12 +141,6 @@ watch([startTime, endTime, refreshProjects], () => { |
|
|
|
getProjectsList(); |
|
|
|
}); |
|
|
|
|
|
|
|
// 点击操作面板显示 |
|
|
|
const showActionCard = item => { |
|
|
|
visible.value = true; |
|
|
|
deleteId.value = item.id; |
|
|
|
}; |
|
|
|
|
|
|
|
// 获取项目列表 |
|
|
|
async function getProjectsList() { |
|
|
|
try { |
|
|
@ -141,7 +175,44 @@ function changeShow(item) { |
|
|
|
item.show = !item.show; |
|
|
|
} |
|
|
|
|
|
|
|
// 操作面板确定 |
|
|
|
const showImportCard = item => { |
|
|
|
importVisible.value = true; |
|
|
|
importParent.value = item.name; |
|
|
|
importParentId.value = item.id; |
|
|
|
currUrl.value = item.url; |
|
|
|
}; |
|
|
|
|
|
|
|
// 确认导入 |
|
|
|
async function handleImport() { |
|
|
|
importVisible.value = false; |
|
|
|
await importProject(); |
|
|
|
getProjectsList(); |
|
|
|
} |
|
|
|
|
|
|
|
// 导入 |
|
|
|
async function importProject() { |
|
|
|
document.querySelector('.import-wbs').click(); |
|
|
|
} |
|
|
|
|
|
|
|
async function toImport(e) { |
|
|
|
try { |
|
|
|
const file = e.target.files[0]; |
|
|
|
const param = new FormData(); |
|
|
|
param.append('file', file); |
|
|
|
const config = { headers: { 'Content-Type': 'multipart/form-data' } }; |
|
|
|
|
|
|
|
const res = await importWbs(currUrl.value, param, config, importParentId.value); |
|
|
|
} catch (error) { |
|
|
|
message.info(error || '导入失败'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 点击打开删除确认弹框 |
|
|
|
const showDelCard = item => { |
|
|
|
visible.value = true; |
|
|
|
deleteId.value = item.id; |
|
|
|
}; |
|
|
|
|
|
|
|
// 删除 |
|
|
|
async function handleOk() { |
|
|
|
visible.value = false; |
|
|
@ -159,12 +230,28 @@ async function deleteProject(param) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 导出 |
|
|
|
async function exportProject(id) { |
|
|
|
try { |
|
|
|
const params = { param: { projectId: id } }; |
|
|
|
|
|
|
|
const { url } = store.state.projects.project; |
|
|
|
const data = await exportWbs(params, url); |
|
|
|
window.open(data.url, '_blank'); |
|
|
|
} catch (error) { |
|
|
|
message.info(error); |
|
|
|
throw new Error(error); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 清空角色数据 |
|
|
|
function clearRolesData() { |
|
|
|
store.commit('role/setInvisibleRoles', []); |
|
|
|
store.commit('role/setVisibleRoles', []); |
|
|
|
store.commit('role/setRoleId', ''); |
|
|
|
} |
|
|
|
|
|
|
|
// 清空任务数据 |
|
|
|
function clearTasksData() { |
|
|
|
// 清空日常任务的数据 |
|
|
|
store.commit('task/setPermanents', []); |
|
|
@ -177,10 +264,81 @@ function clearTasksData() { |
|
|
|
store.commit('task/setDownNextPage', 1); |
|
|
|
} |
|
|
|
|
|
|
|
// 跳转到工作台 |
|
|
|
function toWorkbench(item) { |
|
|
|
toDetail(item); |
|
|
|
store.commit('task/setTaskDetailShow', 'workbench'); // 设置内置组件关键字(根据关键字判断显示的详情页) |
|
|
|
} |
|
|
|
|
|
|
|
// 项目列表拖拽移动 |
|
|
|
// 经多次测验,只有当一级项目变为二级项目时,会调用该函数 |
|
|
|
// 一级项目移动位置不处理,刷新列表 |
|
|
|
// function checkMove(e) { |
|
|
|
// console.log('父组件', e, projects.value); |
|
|
|
// moveProjectId.value = e.draggedContext.element.id; |
|
|
|
// moveBusinessCode.value = e.draggedContext.element.businessCode; |
|
|
|
// } |
|
|
|
|
|
|
|
// 移动结束数据处理 |
|
|
|
// function onEnd() { |
|
|
|
// console.log('父组件onEnd', projects.value); |
|
|
|
// targetProjectId.value = ''; |
|
|
|
// projects.value.forEach(item => { |
|
|
|
// if (item.sonProjectList) { |
|
|
|
// item.sonProjectList.forEach(pro => { |
|
|
|
// if (pro.id === moveProjectId.value) { |
|
|
|
// targetProjectId.value = item.id; |
|
|
|
// } |
|
|
|
// }); |
|
|
|
// } |
|
|
|
// }); |
|
|
|
|
|
|
|
// const param = { |
|
|
|
// moveProjectId: moveProjectId.value, |
|
|
|
// targetProjectId: targetProjectId.value, |
|
|
|
// businessCode: moveBusinessCode.value, |
|
|
|
// }; |
|
|
|
|
|
|
|
// handleSort(param); |
|
|
|
// } |
|
|
|
|
|
|
|
// 子组件传参 |
|
|
|
function handleChangeData(data) { |
|
|
|
console.log('子组件传参', projects.value); |
|
|
|
|
|
|
|
let targetProjectId = ''; |
|
|
|
projects.value.forEach(item => { |
|
|
|
if (item.sonProjectList) { |
|
|
|
item.sonProjectList.forEach(pro => { |
|
|
|
if (pro.id === data.moveProjectId) { |
|
|
|
targetProjectId = item.id; |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
const param = { |
|
|
|
moveProjectId: data.moveProjectId, |
|
|
|
targetProjectId, |
|
|
|
businessCode: data.businessCode, |
|
|
|
}; |
|
|
|
console.log('param', param); |
|
|
|
handleSort(param); |
|
|
|
} |
|
|
|
|
|
|
|
// 排序 |
|
|
|
async function handleSort(param) { |
|
|
|
try { |
|
|
|
const params = { param }; |
|
|
|
await setProjectSort(params); |
|
|
|
message.info('层级关系修改成功'); |
|
|
|
} catch (error) { |
|
|
|
message.info(error.msg || '层级关系修改失败'); |
|
|
|
throw new Error(error); |
|
|
|
} |
|
|
|
|
|
|
|
getProjectsList(); |
|
|
|
} |
|
|
|
</script> |
|
|
|
|
|
|
|
<style scoped> |
|
|
@ -225,7 +383,7 @@ function toWorkbench(item) { |
|
|
|
} |
|
|
|
|
|
|
|
.detail { |
|
|
|
width: calc(100% - 76px); |
|
|
|
width: calc(100% - 46px); |
|
|
|
} |
|
|
|
|
|
|
|
.name { |
|
|
|