You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
270 lines
7.3 KiB
270 lines
7.3 KiB
<template>
|
|
<div style="height: 100vh">
|
|
<div class="flex items-center">
|
|
<el-popover placement="bottom" width="500px" trigger="click" @show="handleSearchPeroid">
|
|
<template #reference>
|
|
<div class="flex items-center border-1px w-300px h-32px p-10px peroid-select">
|
|
<Icon icon="ep:calendar" style="color: #aaa" />
|
|
<span class="text-14px ml-10px" style="color: #aaa">
|
|
{{ searchForm.nodeName ? searchForm.nodeName : '选择周期' }}
|
|
</span>
|
|
</div>
|
|
</template>
|
|
<div>
|
|
<div class="mt-10px" style="height: 400px">
|
|
<el-table :data="peroidList" @row-click="handleSelectPeroid">
|
|
<el-table-column label="节点名称">
|
|
<template #default="{ row }">
|
|
<el-radio v-model="searchForm.nodeId" :label="row.nodeId">{{
|
|
row.nodeName
|
|
}}</el-radio>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="开始日期" prop="startTime" width="120" />
|
|
<el-table-column label="截止日期" prop="endTime" width="120" />
|
|
</el-table>
|
|
</div>
|
|
</div>
|
|
</el-popover>
|
|
<el-button class="ml-10px" type="primary" @click="handleAddNode">新建节点</el-button>
|
|
</div>
|
|
|
|
<vue3-tree-org
|
|
ref="treeOrgRef"
|
|
:data="dataList"
|
|
center
|
|
collapsable
|
|
:default-expand-keys="lastExpendKeys"
|
|
:props="treeProps"
|
|
@on-node-click="handleClickNode"
|
|
>
|
|
<template #default="{ node }">
|
|
<div style="cursor: pointer">
|
|
<div class="tree-org-node__text node-label">
|
|
<el-popover placement="right" title="目标" width="270px" trigger="hover">
|
|
<template #reference>
|
|
<div>
|
|
<div style="max-height: 40px; overflow: hidden">{{ node.label }}</div>
|
|
<div class="tip"> 目标数: {{ getNodePropData(node.id, 'objectiveNum') }}</div>
|
|
<!-- 执行人 -->
|
|
<div class="tip">
|
|
执行人: {{ getNodePropData(node.id, 'executorName') || '无' }}
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<template #default>
|
|
<div style="font-size: 0.875rem; line-height: 1.5">
|
|
<div v-for="i in getNodePropData(node.id, 'objectives')" :key="i.id" class="mt-5">
|
|
<span style="color: #aaa">{{ parseInt(i.progress) }}%</span>
|
|
<span style="margin-left: 0.5rem">
|
|
{{ i.objectiveName }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</el-popover>
|
|
</div>
|
|
<div class="p-5px">
|
|
<el-progress
|
|
type="line"
|
|
:percentage="parseInt(getNodePropData(node.id, 'progress')) || 0"
|
|
text-inside
|
|
:stroke-width="12"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</vue3-tree-org>
|
|
<DialogOkr ref="dialogOkr" @edit="handleEditOkr" />
|
|
<DialogOkrInfo ref="dialogOkrInfo" @close="openOkr" @success="resetTreeData" />
|
|
</div>
|
|
</template>
|
|
|
|
<script setup name="ObjectList">
|
|
import { Vue3TreeOrg } from 'vue3-tree-org'
|
|
import 'vue3-tree-org/lib/vue3-tree-org.css'
|
|
import DialogOkr from './DialogOkr.vue'
|
|
import DialogOkrInfo from './DialogOkrInfo.vue'
|
|
|
|
import { getOkrRelationTree, getOkrRelationTreeChildren } from '@/api/okr/okr'
|
|
import { listToTree } from '@/utils/tree'
|
|
|
|
const dataList = ref({})
|
|
const helpDataList = ref([])
|
|
const lastExpendKeys = ref([])
|
|
const treeProps = {
|
|
children: 'children',
|
|
label: 'nodeName',
|
|
id: 'nodeId',
|
|
pid: 'parentId'
|
|
}
|
|
|
|
const searchForm = ref({
|
|
nodeName: '',
|
|
nodeId: null
|
|
})
|
|
|
|
const peroidList = ref([])
|
|
|
|
handleSearchPeroid()
|
|
|
|
function handleSearchPeroid() {
|
|
lastExpendKeys.value = []
|
|
getOkrRelationTree().then((resp) => {
|
|
peroidList.value = resp
|
|
if (resp && resp.length && !searchForm.value.nodeId) {
|
|
searchForm.value.nodeId = resp[0].nodeId
|
|
searchForm.value.nodeName = resp[0].nodeName
|
|
getOkrList()
|
|
}
|
|
})
|
|
}
|
|
|
|
const treeOrgRef = ref(null)
|
|
function resetTreeData() {
|
|
if (treeOrgRef.value) {
|
|
lastExpendKeys.value = treeOrgRef.value.getExpandKeys()
|
|
}
|
|
|
|
// 重新获取tree数据
|
|
getOkrRelationTree().then((resp) => {
|
|
peroidList.value = resp
|
|
if (resp && resp.length) {
|
|
if (!searchForm.value.nodeId) {
|
|
searchForm.value.nodeId = resp[0].nodeId
|
|
searchForm.value.nodeName = resp[0].nodeName
|
|
}
|
|
getOkrRelationTreeChildren({
|
|
nodeId: searchForm.value.nodeId
|
|
}).then((resp) => {
|
|
const tree = listToTree(resp, {
|
|
id: 'nodeId',
|
|
pid: 'parentId',
|
|
children: 'children'
|
|
})
|
|
// // 设置展开的keys
|
|
// if (treeOrgRef.value) {
|
|
// treeOrgRef.value.setExpandKeys(lastExpendKeys.value)
|
|
// }
|
|
helpDataList.value = resp
|
|
if (tree && tree.length) {
|
|
dataList.value = tree[0]
|
|
} else {
|
|
dataList.value = {}
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
function getOkrList() {
|
|
getOkrRelationTreeChildren({
|
|
nodeId: searchForm.value.nodeId
|
|
}).then((resp) => {
|
|
const tree = listToTree(resp, {
|
|
id: 'nodeId',
|
|
pid: 'parentId',
|
|
children: 'children'
|
|
})
|
|
helpDataList.value = resp
|
|
if (tree && tree.length) {
|
|
dataList.value = tree[0]
|
|
} else {
|
|
dataList.value = {}
|
|
}
|
|
})
|
|
}
|
|
|
|
function handleSelectPeroid(row) {
|
|
searchForm.value.nodeName = row.nodeName
|
|
searchForm.value.nodeId = row.nodeId
|
|
getOkrList()
|
|
}
|
|
|
|
function getNodePropData(nodeId, prop) {
|
|
const nodeData = helpDataList.value.find((it) => it.nodeId == nodeId)
|
|
if (nodeData) {
|
|
return nodeData[prop]
|
|
} else {
|
|
return ''
|
|
}
|
|
}
|
|
|
|
function toggleExpand(data, val) {
|
|
if (Array.isArray(data)) {
|
|
data.forEach((item) => {
|
|
item.expand = val
|
|
if (item.children) {
|
|
toggleExpand(item.children, val)
|
|
}
|
|
})
|
|
} else {
|
|
data.expand = val
|
|
if (data.children) {
|
|
toggleExpand(data.children, val)
|
|
}
|
|
}
|
|
}
|
|
|
|
toggleExpand(dataList.value, true)
|
|
|
|
const dialogOkr = ref(null)
|
|
const clickNode = ref(null)
|
|
function handleClickNode(node, data) {
|
|
clickNode.value = data
|
|
openOkr()
|
|
}
|
|
|
|
function openOkr() {
|
|
clickNode.value &&
|
|
dialogOkr.value.open({
|
|
nodeId: clickNode.value.nodeId,
|
|
queryType: 2,
|
|
canEdit: !clickNode.value.children || clickNode.value.children.length == 0
|
|
})
|
|
}
|
|
|
|
const dialogOkrInfo = ref(null)
|
|
function handleAddNode() {
|
|
clickNode.value = null
|
|
dialogOkrInfo.value.open('create', null)
|
|
}
|
|
|
|
function handleEditOkr(nodeId = undefined) {
|
|
dialogOkr.value.close()
|
|
dialogOkrInfo.value.open('update', nodeId || searchForm.value.nodeId, 2)
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.peroid-select {
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
&:hover {
|
|
border-color: var(--el-color-primary-light-5);
|
|
}
|
|
}
|
|
|
|
.tree-org-node__text {
|
|
min-width: 200px;
|
|
min-height: 80px;
|
|
text-align: left;
|
|
font-size: 14px;
|
|
border-bottom: 1px solid #ccc;
|
|
padding: 5px;
|
|
}
|
|
.tip {
|
|
position: relative;
|
|
color: #aaa;
|
|
font-size: 0.875rem;
|
|
}
|
|
:deep(.el-progress-bar__innerText) {
|
|
display: block;
|
|
font-size: 0.75rem !important;
|
|
}
|
|
:deep(.el-overlay-dialog) {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
</style>
|
|
|