v1.9.0-rc.5 - SIT
This commit is contained in:
+4
-4
@@ -101,7 +101,7 @@ const applyDataSource = (source: RawDataSource) => {
|
||||
description: resData.description,
|
||||
department: resData.department,
|
||||
skills: resData.skills,
|
||||
utilization: resData.utilization,
|
||||
capacity: resData.capacity,
|
||||
color: resData.color,
|
||||
tasks: resData.tasks || []
|
||||
})
|
||||
@@ -293,13 +293,13 @@ const resourceListConfig = computed<ResourceListConfig>(() => ({
|
||||
formatter: (resource: Resource) => resource.name || '-',
|
||||
},
|
||||
{
|
||||
key: 'utilization',
|
||||
key: 'capacity',
|
||||
label: '利用率',
|
||||
visible: true,
|
||||
width: 100,
|
||||
formatter: (resource: Resource) => {
|
||||
if (resource.utilization != null) {
|
||||
return `${resource.utilization}%`
|
||||
if (resource.capacity != null) {
|
||||
return `${resource.capacity}%`
|
||||
}
|
||||
// 简单计算:基于任务数量的利用率
|
||||
const taskCount = resource.tasks?.length || 0
|
||||
|
||||
+100
-100
@@ -11,7 +11,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 66,
|
||||
"capacity": 66,
|
||||
"color": "#4caf50",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -477,7 +477,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 73,
|
||||
"capacity": 73,
|
||||
"color": "#ff9800",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -928,7 +928,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 79,
|
||||
"capacity": 79,
|
||||
"color": "#f44336",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -1394,7 +1394,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 64,
|
||||
"capacity": 64,
|
||||
"color": "#9c27b0",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -1815,7 +1815,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 82,
|
||||
"capacity": 82,
|
||||
"color": "#00bcd4",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -2266,7 +2266,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 75,
|
||||
"capacity": 75,
|
||||
"color": "#8bc34a",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -2657,7 +2657,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 93,
|
||||
"capacity": 93,
|
||||
"color": "#a8a8a8",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -3108,7 +3108,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 73,
|
||||
"capacity": 73,
|
||||
"color": "#e91e63",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -3454,7 +3454,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 80,
|
||||
"capacity": 80,
|
||||
"color": "#3f51b5",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -3920,7 +3920,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 63,
|
||||
"capacity": 63,
|
||||
"color": "#2196f3",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -4251,7 +4251,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 86,
|
||||
"capacity": 86,
|
||||
"color": "#4caf50",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -4672,7 +4672,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 62,
|
||||
"capacity": 62,
|
||||
"color": "#ff9800",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -5018,7 +5018,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 95,
|
||||
"capacity": 95,
|
||||
"color": "#f44336",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -5394,7 +5394,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 87,
|
||||
"capacity": 87,
|
||||
"color": "#9c27b0",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -5785,7 +5785,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 73,
|
||||
"capacity": 73,
|
||||
"color": "#00bcd4",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -6221,7 +6221,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 67,
|
||||
"capacity": 67,
|
||||
"color": "#8bc34a",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -6537,7 +6537,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 95,
|
||||
"capacity": 95,
|
||||
"color": "#ffc107",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -6988,7 +6988,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 77,
|
||||
"capacity": 77,
|
||||
"color": "#e91e63",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -7364,7 +7364,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 63,
|
||||
"capacity": 63,
|
||||
"color": "#3f51b5",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -7725,7 +7725,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 61,
|
||||
"capacity": 61,
|
||||
"color": "#2196f3",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -8161,7 +8161,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 69,
|
||||
"capacity": 69,
|
||||
"color": "#4caf50",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -8522,7 +8522,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 83,
|
||||
"capacity": 83,
|
||||
"color": "#ff9800",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -8928,7 +8928,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 99,
|
||||
"capacity": 99,
|
||||
"color": "#f44336",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -9304,7 +9304,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 66,
|
||||
"capacity": 66,
|
||||
"color": "#9c27b0",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -9725,7 +9725,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 97,
|
||||
"capacity": 97,
|
||||
"color": "#00bcd4",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -10071,7 +10071,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 95,
|
||||
"capacity": 95,
|
||||
"color": "#8bc34a",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -10462,7 +10462,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 80,
|
||||
"capacity": 80,
|
||||
"color": "#ffc107",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -10778,7 +10778,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 82,
|
||||
"capacity": 82,
|
||||
"color": "#e91e63",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -11199,7 +11199,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 86,
|
||||
"capacity": 86,
|
||||
"color": "#3f51b5",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -11605,7 +11605,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 74,
|
||||
"capacity": 74,
|
||||
"color": "#2196f3",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -11951,7 +11951,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 73,
|
||||
"capacity": 73,
|
||||
"color": "#4caf50",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -12417,7 +12417,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 64,
|
||||
"capacity": 64,
|
||||
"color": "#ff9800",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -12823,7 +12823,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 93,
|
||||
"capacity": 93,
|
||||
"color": "#f44336",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -13229,7 +13229,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 62,
|
||||
"capacity": 62,
|
||||
"color": "#9c27b0",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -13695,7 +13695,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 93,
|
||||
"capacity": 93,
|
||||
"color": "#00bcd4",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -14146,7 +14146,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 69,
|
||||
"capacity": 69,
|
||||
"color": "#8bc34a",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -14597,7 +14597,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 88,
|
||||
"capacity": 88,
|
||||
"color": "#ffc107",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -14958,7 +14958,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 84,
|
||||
"capacity": 84,
|
||||
"color": "#e91e63",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -15364,7 +15364,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 60,
|
||||
"capacity": 60,
|
||||
"color": "#3f51b5",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -15680,7 +15680,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 81,
|
||||
"capacity": 81,
|
||||
"color": "#2196f3",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -16116,7 +16116,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 97,
|
||||
"capacity": 97,
|
||||
"color": "#4caf50",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -16492,7 +16492,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 88,
|
||||
"capacity": 88,
|
||||
"color": "#ff9800",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -16913,7 +16913,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 90,
|
||||
"capacity": 90,
|
||||
"color": "#f44336",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -17259,7 +17259,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 63,
|
||||
"capacity": 63,
|
||||
"color": "#9c27b0",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -17590,7 +17590,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 69,
|
||||
"capacity": 69,
|
||||
"color": "#00bcd4",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -17951,7 +17951,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 85,
|
||||
"capacity": 85,
|
||||
"color": "#8bc34a",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -18387,7 +18387,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 67,
|
||||
"capacity": 67,
|
||||
"color": "#ffc107",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -18733,7 +18733,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 63,
|
||||
"capacity": 63,
|
||||
"color": "#e91e63",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -19154,7 +19154,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 78,
|
||||
"capacity": 78,
|
||||
"color": "#3f51b5",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -19500,7 +19500,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 87,
|
||||
"capacity": 87,
|
||||
"color": "#2196f3",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -19921,7 +19921,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 91,
|
||||
"capacity": 91,
|
||||
"color": "#4caf50",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -20327,7 +20327,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 65,
|
||||
"capacity": 65,
|
||||
"color": "#ff9800",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -20658,7 +20658,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 68,
|
||||
"capacity": 68,
|
||||
"color": "#f44336",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -21034,7 +21034,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 67,
|
||||
"capacity": 67,
|
||||
"color": "#9c27b0",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -21350,7 +21350,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 72,
|
||||
"capacity": 72,
|
||||
"color": "#00bcd4",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -21786,7 +21786,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 97,
|
||||
"capacity": 97,
|
||||
"color": "#8bc34a",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -22252,7 +22252,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 60,
|
||||
"capacity": 60,
|
||||
"color": "#ffc107",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -22568,7 +22568,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 96,
|
||||
"capacity": 96,
|
||||
"color": "#e91e63",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -22944,7 +22944,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 87,
|
||||
"capacity": 87,
|
||||
"color": "#3f51b5",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -23380,7 +23380,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 82,
|
||||
"capacity": 82,
|
||||
"color": "#2196f3",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -23801,7 +23801,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 74,
|
||||
"capacity": 74,
|
||||
"color": "#4caf50",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -24117,7 +24117,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 99,
|
||||
"capacity": 99,
|
||||
"color": "#ff9800",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -24538,7 +24538,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 70,
|
||||
"capacity": 70,
|
||||
"color": "#f44336",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -24989,7 +24989,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 91,
|
||||
"capacity": 91,
|
||||
"color": "#9c27b0",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -25320,7 +25320,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 93,
|
||||
"capacity": 93,
|
||||
"color": "#00bcd4",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -25726,7 +25726,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 99,
|
||||
"capacity": 99,
|
||||
"color": "#8bc34a",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -26132,7 +26132,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 68,
|
||||
"capacity": 68,
|
||||
"color": "#ffc107",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -26538,7 +26538,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 99,
|
||||
"capacity": 99,
|
||||
"color": "#e91e63",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -26944,7 +26944,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 81,
|
||||
"capacity": 81,
|
||||
"color": "#3f51b5",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -27410,7 +27410,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 95,
|
||||
"capacity": 95,
|
||||
"color": "#2196f3",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -27801,7 +27801,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 98,
|
||||
"capacity": 98,
|
||||
"color": "#4caf50",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -28147,7 +28147,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 86,
|
||||
"capacity": 86,
|
||||
"color": "#ff9800",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -28568,7 +28568,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 61,
|
||||
"capacity": 61,
|
||||
"color": "#f44336",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -28989,7 +28989,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 86,
|
||||
"capacity": 86,
|
||||
"color": "#9c27b0",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -29305,7 +29305,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 97,
|
||||
"capacity": 97,
|
||||
"color": "#00bcd4",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -29696,7 +29696,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 97,
|
||||
"capacity": 97,
|
||||
"color": "#8bc34a",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -30117,7 +30117,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 78,
|
||||
"capacity": 78,
|
||||
"color": "#ffc107",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -30553,7 +30553,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 66,
|
||||
"capacity": 66,
|
||||
"color": "#e91e63",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -30974,7 +30974,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 63,
|
||||
"capacity": 63,
|
||||
"color": "#3f51b5",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -31335,7 +31335,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 79,
|
||||
"capacity": 79,
|
||||
"color": "#2196f3",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -31711,7 +31711,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 72,
|
||||
"capacity": 72,
|
||||
"color": "#4caf50",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -32027,7 +32027,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 82,
|
||||
"capacity": 82,
|
||||
"color": "#ff9800",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -32373,7 +32373,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 61,
|
||||
"capacity": 61,
|
||||
"color": "#f44336",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -32719,7 +32719,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 89,
|
||||
"capacity": 89,
|
||||
"color": "#9c27b0",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -33065,7 +33065,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 78,
|
||||
"capacity": 78,
|
||||
"color": "#00bcd4",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -33381,7 +33381,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 64,
|
||||
"capacity": 64,
|
||||
"color": "#8bc34a",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -33832,7 +33832,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 68,
|
||||
"capacity": 68,
|
||||
"color": "#ffc107",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -34193,7 +34193,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 73,
|
||||
"capacity": 73,
|
||||
"color": "#e91e63",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -34524,7 +34524,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 91,
|
||||
"capacity": 91,
|
||||
"color": "#3f51b5",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -34960,7 +34960,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 96,
|
||||
"capacity": 96,
|
||||
"color": "#2196f3",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -35411,7 +35411,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 96,
|
||||
"capacity": 96,
|
||||
"color": "#4caf50",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -35802,7 +35802,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 77,
|
||||
"capacity": 77,
|
||||
"color": "#ff9800",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -36193,7 +36193,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 85,
|
||||
"capacity": 85,
|
||||
"color": "#f44336",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -36524,7 +36524,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 89,
|
||||
"capacity": 89,
|
||||
"color": "#9c27b0",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -36870,7 +36870,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 79,
|
||||
"capacity": 79,
|
||||
"color": "#00bcd4",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -37201,7 +37201,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 91,
|
||||
"capacity": 91,
|
||||
"color": "#8bc34a",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -37622,7 +37622,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 91,
|
||||
"capacity": 91,
|
||||
"color": "#ffc107",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -38073,7 +38073,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 67,
|
||||
"capacity": 67,
|
||||
"color": "#e91e63",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -38524,7 +38524,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 77,
|
||||
"capacity": 77,
|
||||
"color": "#3f51b5",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -38870,7 +38870,7 @@
|
||||
"技能B",
|
||||
"技能C"
|
||||
],
|
||||
"utilization": 65,
|
||||
"capacity": 65,
|
||||
"color": "#2196f3",
|
||||
"tasks": [
|
||||
{
|
||||
|
||||
+13
-13
@@ -7,7 +7,7 @@
|
||||
"avatar": "/50-11.jpg",
|
||||
"department": "临床研究部",
|
||||
"skills": ["临床试验管理", "项目规划", "团队领导"],
|
||||
"utilization": 85,
|
||||
"capacity": 85,
|
||||
"color": "#2196f3",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -52,7 +52,7 @@
|
||||
"avatar": "/50-12.jpg",
|
||||
"department": "I期临床研究组",
|
||||
"skills": ["I期试验设计", "药代动力学", "安全性评估"],
|
||||
"utilization": 92,
|
||||
"capacity": 92,
|
||||
"color": "#4caf50",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -97,7 +97,7 @@
|
||||
"avatar": "/50-13.jpg",
|
||||
"department": "临床研究部",
|
||||
"skills": ["方案设计", "伦理审查", "监管申报"],
|
||||
"utilization": 75,
|
||||
"capacity": 75,
|
||||
"tasks": [
|
||||
{
|
||||
"id": 1101,
|
||||
@@ -131,7 +131,7 @@
|
||||
"avatar": "/50-14.jpg",
|
||||
"department": "数据管理与统计部",
|
||||
"skills": ["统计分析", "数据可视化", "报告撰写"],
|
||||
"utilization": 68,
|
||||
"capacity": 68,
|
||||
"color": "#ff9800",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -176,7 +176,7 @@
|
||||
"avatar": "/50-15.jpg",
|
||||
"department": "质量保证部",
|
||||
"skills": ["GCP审计", "质量控制", "SOP管理"],
|
||||
"utilization": 88,
|
||||
"capacity": 88,
|
||||
"tasks": [
|
||||
{
|
||||
"id": 1104,
|
||||
@@ -211,7 +211,7 @@
|
||||
"avatar": "/50-16.jpg",
|
||||
"department": "II期临床研究组",
|
||||
"skills": ["试验协调", "中心管理", "受试者跟踪"],
|
||||
"utilization": 55,
|
||||
"capacity": 55,
|
||||
"tasks": [
|
||||
{
|
||||
"id": 1200,
|
||||
@@ -238,7 +238,7 @@
|
||||
"avatar": "/50-17.jpg",
|
||||
"department": "设备与后勤部",
|
||||
"skills": ["设备维护", "库存管理", "供应链协调"],
|
||||
"utilization": 42,
|
||||
"capacity": 42,
|
||||
"tasks": [
|
||||
{
|
||||
"id": 5011,
|
||||
@@ -265,7 +265,7 @@
|
||||
"avatar": "/50-18.jpg",
|
||||
"department": "III期临床研究组",
|
||||
"skills": ["大型试验管理", "多中心协调", "里程碑管理"],
|
||||
"utilization": 35,
|
||||
"capacity": 35,
|
||||
"color": "#9c27b0",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -285,7 +285,7 @@
|
||||
"avatar": "/50-19.jpg",
|
||||
"department": "数据管理与统计部",
|
||||
"skills": ["统计建模", "样本量计算", "数据分析"],
|
||||
"utilization": 95,
|
||||
"capacity": 95,
|
||||
"color": "#ff5733",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -341,7 +341,7 @@
|
||||
"avatar": "/50-20.jpg",
|
||||
"department": "临床监查部",
|
||||
"skills": ["现场监查", "数据核查", "问题解决"],
|
||||
"utilization": 110,
|
||||
"capacity": 110,
|
||||
"color": "#3498db",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -397,7 +397,7 @@
|
||||
"avatar": "/50-21.jpg",
|
||||
"department": "医学事务部",
|
||||
"skills": ["研究报告撰写", "文献检索", "医学翻译"],
|
||||
"utilization": 72,
|
||||
"capacity": 72,
|
||||
"color": "#e74c3c",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -442,7 +442,7 @@
|
||||
"avatar": "/50-22.jpg",
|
||||
"department": "药物警戒部",
|
||||
"skills": ["不良事件管理", "安全性报告", "信号检测"],
|
||||
"utilization": 88,
|
||||
"capacity": 88,
|
||||
"color": "#f39c12",
|
||||
"tasks": [
|
||||
{
|
||||
@@ -478,7 +478,7 @@
|
||||
"avatar": "/50-23.jpg",
|
||||
"department": "注册事务部",
|
||||
"skills": ["IND申报", "监管沟通", "文件管理"],
|
||||
"utilization": 65,
|
||||
"capacity": 65,
|
||||
"tasks": [
|
||||
{
|
||||
"id": 6015,
|
||||
|
||||
@@ -56,7 +56,7 @@ function generateLargeResourceData() {
|
||||
avatar: `https://i.pravatar.cc/150?img=${i}`,
|
||||
department: departments[i % departments.length],
|
||||
skills: ['技能A', '技能B', '技能C'],
|
||||
utilization: 60 + Math.floor(Math.random() * 40),
|
||||
capacity: 60 + Math.floor(Math.random() * 40),
|
||||
color: colors[i % colors.length],
|
||||
tasks,
|
||||
})
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
} from '../models/configs/TaskListConfig'
|
||||
import type { TaskBarConfig } from '../models/configs/TaskBarConfig'
|
||||
import { TimelineScale, SCALE_CONFIGS } from '../models/types/TimelineScale'
|
||||
import { detectConflicts } from '../utils/conflictUtils'
|
||||
import { useMessage } from '../composables/useMessage'
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
@@ -189,6 +190,7 @@ const resourceRowPositions = computed(() => {
|
||||
})
|
||||
|
||||
// 计算资源冲突状态(依赖updateTaskTrigger以便实时更新)
|
||||
// v1.9.9 修复:使用 detectConflicts 函数来正确检测多任务叠加的超载情况
|
||||
const resourceConflicts = computed(() => {
|
||||
if (currentViewMode.value !== 'resource') return new Map()
|
||||
|
||||
@@ -198,38 +200,22 @@ const resourceConflicts = computed(() => {
|
||||
// 依赖 updateTaskTrigger 以便在任务更新时重新计算冲突
|
||||
if (updateTaskTrigger.value >= 0) {
|
||||
resources.forEach(resource => {
|
||||
// v1.9.2 使用 Resource.isOverloaded() 方法检测真正的资源超载
|
||||
// 超载定义:同一时间段内,资源总占用比例 > 100%
|
||||
if (typeof resource.isOverloaded === 'function' && resource.isOverloaded()) {
|
||||
const tasks = resource.tasks || []
|
||||
if (tasks.length < 2) return
|
||||
|
||||
// 使用 conflictUtils 的 detectConflicts 函数来检测冲突
|
||||
// 这个函数能正确处理多任务叠加的超载情况(如 A:40% + B:40% + C:30% = 110%)
|
||||
const conflictZones = detectConflicts(tasks, resource.id)
|
||||
|
||||
if (conflictZones.length > 0) {
|
||||
const conflicts = new Set<number>()
|
||||
const tasks = resource.tasks || []
|
||||
const validTasks = tasks.filter(task => task.startDate && task.endDate)
|
||||
|
||||
// 找出所有导致超载的任务对
|
||||
for (let i = 0; i < validTasks.length; i++) {
|
||||
for (let j = i + 1; j < validTasks.length; j++) {
|
||||
const task1 = validTasks[i]
|
||||
const task2 = validTasks[j]
|
||||
|
||||
// 检查时间重叠
|
||||
const start1 = new Date(task1.startDate!).getTime()
|
||||
const end1 = new Date(task1.endDate!).getTime()
|
||||
const start2 = new Date(task2.startDate!).getTime()
|
||||
const end2 = new Date(task2.endDate!).getTime()
|
||||
|
||||
if (start1 < end2 && start2 < end1) {
|
||||
// 有时间重叠,检查总占比是否超过100%
|
||||
const percent1 = getTaskAllocationPercent(resource, task1)
|
||||
const percent2 = getTaskAllocationPercent(resource, task2)
|
||||
|
||||
if (percent1 + percent2 > 100) {
|
||||
// 超载,标记这两个任务
|
||||
conflicts.add(task1.id)
|
||||
conflicts.add(task2.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 收集所有冲突区域中涉及的任务ID
|
||||
conflictZones.forEach(zone => {
|
||||
zone.tasks.forEach(taskInfo => {
|
||||
conflicts.add(taskInfo.id)
|
||||
})
|
||||
})
|
||||
|
||||
if (conflicts.size > 0) {
|
||||
conflictsMap.set(String(resource.id), conflicts)
|
||||
@@ -241,21 +227,6 @@ const resourceConflicts = computed(() => {
|
||||
return conflictsMap
|
||||
})
|
||||
|
||||
// 辅助函数:获取任务中当前资源的投入占比
|
||||
function getTaskAllocationPercent(resource: Resource, task: Task): number {
|
||||
if (!task.resources || !Array.isArray(task.resources)) {
|
||||
return 100 // 未配置resources时,默认100%
|
||||
}
|
||||
|
||||
const allocation = task.resources.find((r: any) => String(r.id) === String(resource.id))
|
||||
if (!allocation) {
|
||||
return 100 // 未找到当前资源的分配信息,默认100%
|
||||
}
|
||||
|
||||
const percent = allocation.percent ?? 100
|
||||
return Math.max(20, Math.min(100, percent)) // 限制范围 20-100
|
||||
}
|
||||
|
||||
// 提供资源布局信息给子组件
|
||||
provide('resourceTaskLayouts', resourceTaskLayouts)
|
||||
provide('resourceRowPositions', resourceRowPositions)
|
||||
|
||||
@@ -47,7 +47,7 @@ defineSlots<{
|
||||
// 从 GanttChart 注入 enableLinkAnchor 配置
|
||||
const enableLinkAnchor = inject<ComputedRef<boolean>>('enable-link-anchor', computed(() => true))
|
||||
|
||||
// v1.9.0 计算当前资源的投入占比
|
||||
// v1.9.0 计算当前资源的利用率
|
||||
const resourcePercent = computed(() => {
|
||||
// 如果直接传递了占比,使用传递的值
|
||||
if (props.resourceAllocationPercent !== undefined) {
|
||||
@@ -156,7 +156,7 @@ interface Props {
|
||||
hasResourceConflict?: boolean
|
||||
// v1.9.2 资源视图:冲突任务列表(用于显示详细冲突信息)
|
||||
conflictTasks?: Task[]
|
||||
// v1.9.0 资源视图:当前资源在任务中的投入占比 (20-100)
|
||||
// v1.9.0 资源视图:当前资源在任务中的利用率 (20-100)
|
||||
resourceAllocationPercent?: number
|
||||
// v1.9.0 资源视图:当前资源ID(用于查找占比信息)
|
||||
currentResourceId?: string | number
|
||||
@@ -2694,7 +2694,7 @@ const handleTaskBarMouseEnter = (event: MouseEvent) => {
|
||||
const rowHeight = 24 // 每行内容高度
|
||||
let contentRows = 4 // 默认4行(开始日期、结束日期、预估工时、实际工时、进度)
|
||||
|
||||
// 资源视图且投入占比<100%时,多1行
|
||||
// 资源视图且利用率<100%时,多1行
|
||||
if (viewMode.value === 'resource' && resourcePercent.value < 100) {
|
||||
contentRows += 1
|
||||
}
|
||||
@@ -3636,7 +3636,7 @@ const handleAnchorDragEnd = (anchorEvent: { taskId: number; type: 'predecessor'
|
||||
<div class="tooltip-arrow"></div>
|
||||
<div class="tooltip-title">{{ task.name }}</div>
|
||||
<div class="tooltip-content">
|
||||
<!-- v1.9.0 资源视图:显示投入占比 -->
|
||||
<!-- v1.9.0 资源视图:显示利用率 -->
|
||||
<div v-if="viewMode === 'resource' && resourcePercent < 100" class="tooltip-row">
|
||||
<span class="tooltip-label">{{ t('investment') || '投入' }}:</span>
|
||||
<span class="tooltip-value">{{ resourcePercent }}%</span>
|
||||
|
||||
@@ -130,6 +130,9 @@ const getConflictTasksForTask = (resourceId: string | number, taskId: string | n
|
||||
// v1.9.7 修复:返回所有与当前任务时间重叠的冲突任务
|
||||
// 不需要再次验证占比相加是否超过100%,因为resourceConflicts已经包含了所有冲突的任务ID
|
||||
// 当多个任务同时重叠时(如3个任务各75%),应该全部返回,而不是只返回第一个两两超载的任务
|
||||
// v1.9.9 修复:endDate 包含当天,需要 +1 天来判断交集(与 conflictUtils 保持一致)
|
||||
const currentEndPlus = currentEnd + 24 * 60 * 60 * 1000
|
||||
|
||||
const conflictTasks = resource.tasks.filter(task => {
|
||||
if (task.id === taskId) return false
|
||||
if (!task.startDate || !task.endDate) return false
|
||||
@@ -138,9 +141,11 @@ const getConflictTasksForTask = (resourceId: string | number, taskId: string | n
|
||||
|
||||
const taskStart = new Date(task.startDate).getTime()
|
||||
const taskEnd = new Date(task.endDate).getTime()
|
||||
const taskEndPlus = taskEnd + 24 * 60 * 60 * 1000
|
||||
|
||||
// 检查时间重叠:只要与当前任务有时间交集,就是冲突任务
|
||||
return currentStart < taskEnd && taskStart < currentEnd
|
||||
// 检查时间重叠:endDate 包含当天,所以需要 +1 天来判断
|
||||
// 例如:任务A endDate=12-24, 任务B startDate=12-24,应判断为重叠(都占用12-24这一天)
|
||||
return currentStart < taskEndPlus && taskStart < currentEndPlus
|
||||
})
|
||||
|
||||
return conflictTasks
|
||||
|
||||
@@ -197,7 +197,7 @@ const conflictInfoList = computed(() => {
|
||||
// 计算当前任务的资源占比
|
||||
const currentPercent = props.resourcePercent || 100
|
||||
|
||||
// v1.9.8 修改:只显示冲突任务自己的投入占比
|
||||
// v1.9.8 修改:只显示冲突任务自己的利用率
|
||||
return props.conflictTasks.map(conflictTask => {
|
||||
if (!conflictTask.startDate || !conflictTask.endDate) return null
|
||||
|
||||
@@ -228,7 +228,7 @@ const conflictInfoList = computed(() => {
|
||||
taskName: conflictTask.name,
|
||||
overlapStart: formatDate(overlapStart),
|
||||
overlapEnd: formatDate(overlapEnd),
|
||||
conflictPercent, // 该冲突任务自己的投入占比
|
||||
conflictPercent, // 该冲突任务自己的利用率
|
||||
}
|
||||
}).filter(Boolean)
|
||||
})
|
||||
@@ -246,6 +246,9 @@ const totalOverloadPercent = computed(() => {
|
||||
const currentEnd = new Date(currentTask.endDate).getTime()
|
||||
const currentPercent = props.resourcePercent || 100
|
||||
|
||||
// v1.9.9 修复:endDate 包含当天,需要 +1 天来判断交集
|
||||
const DAY_MS = 24 * 60 * 60 * 1000
|
||||
|
||||
// 计算所有冲突任务在重叠时间段内的最大总占比
|
||||
let maxTotalPercent = currentPercent
|
||||
|
||||
@@ -257,26 +260,31 @@ const totalOverloadPercent = computed(() => {
|
||||
if (!task1.startDate || !task1.endDate) return
|
||||
const start1 = new Date(task1.startDate).getTime()
|
||||
const end1 = new Date(task1.endDate).getTime()
|
||||
const end1Plus = end1 + DAY_MS // endDate 包含当天,需要 +1 天
|
||||
|
||||
allTasks.forEach((task2, j) => {
|
||||
if (i >= j || !task2.startDate || !task2.endDate) return
|
||||
const start2 = new Date(task2.startDate).getTime()
|
||||
const end2 = new Date(task2.endDate).getTime()
|
||||
const end2Plus = end2 + DAY_MS // endDate 包含当天,需要 +1 天
|
||||
|
||||
// 检查是否有时间重叠
|
||||
if (start1 < end2 && start2 < end1) {
|
||||
// 检查是否有时间重叠(使用 +1 天后的 endDate)
|
||||
// 例如:任务A endDate=12-24, 任务B startDate=12-24,应判断为重叠
|
||||
if (start1 < end2Plus && start2 < end1Plus) {
|
||||
// 计算该重叠区间的所有任务总占比
|
||||
const overlapStart = Math.max(start1, start2)
|
||||
const overlapEnd = Math.min(end1, end2)
|
||||
const overlapEndPlus = overlapEnd + DAY_MS
|
||||
|
||||
let intervalTotal = 0
|
||||
allTasks.forEach(task => {
|
||||
if (!task.startDate || !task.endDate) return
|
||||
const tStart = new Date(task.startDate).getTime()
|
||||
const tEnd = new Date(task.endDate).getTime()
|
||||
const tEndPlus = tEnd + DAY_MS
|
||||
|
||||
// 检查任务是否在该重叠区间内
|
||||
if (tStart < overlapEnd && tEnd > overlapStart) {
|
||||
// 检查任务是否在该重叠区间内(使用 +1 天后的 endDate)
|
||||
if (tStart < overlapEndPlus && tEndPlus > overlapStart) {
|
||||
let taskPercent = 100
|
||||
if (task.resources && Array.isArray(task.resources)) {
|
||||
const allocation = task.resources.find(
|
||||
@@ -422,9 +430,9 @@ onUnmounted(() => {
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<div class="expanded-body">
|
||||
<!-- 投入占比 -->
|
||||
<!-- 利用率 -->
|
||||
<div class="expanded-row">
|
||||
<span class="info-label">投入占比</span>
|
||||
<span class="info-label">利用率</span>
|
||||
<span class="info-value">{{ percentText }}</span>
|
||||
</div>
|
||||
<!-- 日期范围 -->
|
||||
@@ -440,7 +448,7 @@ onUnmounted(() => {
|
||||
<path fill="currentColor" d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/>
|
||||
</svg>
|
||||
<span class="conflict-title">资源超载警告</span>
|
||||
<span class="total-overload">+{{ totalOverloadPercent }}%</span>
|
||||
<span class="total-overload">▲ {{ totalOverloadPercent }}%</span>
|
||||
</div>
|
||||
<!-- 可滚动的冲突列表 -->
|
||||
<div class="conflict-list-container">
|
||||
@@ -451,7 +459,7 @@ onUnmounted(() => {
|
||||
<span class="conflict-value">{{ info.overlapStart }} ~ {{ info.overlapEnd }}</span>
|
||||
</div>
|
||||
<div class="conflict-detail">
|
||||
<span class="conflict-label">任务投入占比:</span>
|
||||
<span class="conflict-label">任务利用率:</span>
|
||||
<span class="conflict-value">{{ info.conflictPercent }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -598,10 +606,13 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
.total-overload {
|
||||
font-size: 13px;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: #ff5252;
|
||||
margin-left: auto;
|
||||
background: #FFC107;
|
||||
padding: 2px 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.conflict-item {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Task } from './Task'
|
||||
import { detectConflicts } from '../../utils/conflictUtils'
|
||||
|
||||
/**
|
||||
* 资源类 (Resource Class)
|
||||
@@ -15,7 +16,7 @@ export class Resource {
|
||||
description?: string
|
||||
department?: string
|
||||
skills?: string[]
|
||||
utilization?: number
|
||||
capacity?: number
|
||||
color?: string // 自定义资源行左边框颜色,如 '#ff5733',若不设置则使用默认颜色方案
|
||||
tasks: Task[]
|
||||
[key: string]: unknown
|
||||
@@ -28,7 +29,7 @@ export class Resource {
|
||||
description?: string
|
||||
department?: string
|
||||
skills?: string[]
|
||||
utilization?: number
|
||||
capacity?: number
|
||||
color?: string
|
||||
tasks?: Task[]
|
||||
[key: string]: unknown
|
||||
@@ -40,7 +41,7 @@ export class Resource {
|
||||
this.description = data.description
|
||||
this.department = data.department
|
||||
this.skills = data.skills
|
||||
this.utilization = data.utilization
|
||||
this.capacity = data.capacity
|
||||
this.color = data.color
|
||||
this.tasks = data.tasks || []
|
||||
|
||||
@@ -89,7 +90,7 @@ export class Resource {
|
||||
* 更新利用率
|
||||
*/
|
||||
updateUtilization(): void {
|
||||
this.utilization = this.calculateUtilization()
|
||||
this.capacity = this.calculateUtilization()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,45 +131,21 @@ export class Resource {
|
||||
/**
|
||||
* v1.9.0 检测资源是否超载(基于占用比例)
|
||||
* 超载定义:同一时间段内,资源总占用比例 > 100%
|
||||
* v1.9.9 修复:使用 detectConflicts 函数来正确检测多任务叠加的超载
|
||||
* @returns 是否资源超载
|
||||
*/
|
||||
isOverloaded(): boolean {
|
||||
if (this.tasks.length < 2) return false
|
||||
|
||||
// 过滤掉没有开始日期和结束日期的任务
|
||||
const validTasks = this.tasks.filter(task => task.startDate && task.endDate)
|
||||
if (validTasks.length < 2) return false
|
||||
// 使用 conflictUtils 的 detectConflicts 函数来检测冲突
|
||||
// 这个函数能正确处理多任务叠加的超载情况(如 A:40% + B:40% + C:30% = 110%)
|
||||
const conflictZones = detectConflicts(this.tasks, this.id)
|
||||
|
||||
// 检测任意时间点的总占比是否超过100%
|
||||
for (let i = 0; i < validTasks.length; i++) {
|
||||
for (let j = i + 1; j < validTasks.length; j++) {
|
||||
const task1 = validTasks[i]
|
||||
const task2 = validTasks[j]
|
||||
|
||||
// 检查两个任务是否有时间交集
|
||||
const start1 = new Date(task1.startDate!).getTime()
|
||||
const end1 = new Date(task1.endDate!).getTime()
|
||||
const start2 = new Date(task2.startDate!).getTime()
|
||||
const end2 = new Date(task2.endDate!).getTime()
|
||||
|
||||
// 判断时间是否重叠
|
||||
if (start1 < end2 && start2 < end1) {
|
||||
// 有重叠,计算总占比
|
||||
const percent1 = this.getTaskAllocationPercent(task1)
|
||||
const percent2 = this.getTaskAllocationPercent(task2)
|
||||
|
||||
if (percent1 + percent2 > 100) {
|
||||
return true // 超负荷
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
return conflictZones.length > 0
|
||||
}
|
||||
|
||||
/**
|
||||
* v1.9.0 获取任务中当前资源的投入占比
|
||||
* v1.9.0 获取任务中当前资源的利用率
|
||||
* @param task 任务对象
|
||||
* @returns 占比百分比 (20-100),默认100
|
||||
*/
|
||||
|
||||
@@ -7,7 +7,7 @@ export type ResourceListColumnType =
|
||||
| 'name'
|
||||
| 'type'
|
||||
| 'department'
|
||||
| 'utilization'
|
||||
| 'capacity'
|
||||
| 'taskCount'
|
||||
|
||||
/**
|
||||
@@ -71,10 +71,10 @@ export const DEFAULT_RESOURCE_LIST_COLUMNS: ResourceListColumnConfig[] = [
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
type: 'utilization',
|
||||
key: 'utilization',
|
||||
type: 'capacity',
|
||||
key: 'capacity',
|
||||
label: '利用率',
|
||||
cssClass: 'col-utilization',
|
||||
cssClass: 'col-capacity',
|
||||
visible: true,
|
||||
},
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user