This commit is contained in:
2026-01-23 14:42:02 +08:00
15 changed files with 167 additions and 82 deletions

View File

@@ -240,7 +240,7 @@ import { formOptionsFormat } from './lib';
import { uniqBy, cloneDeep } from 'lodash-es';
import { exportFile } from '@/utils/file';
import HeadSearch from './treeHeadSearch.vue';
import { traverseTree } from '@/utils/node';
import { flatNode, traverseTree } from '@/utils/node';
import { useI18n } from 'vue-i18n';
const emit = defineEmits([
@@ -290,7 +290,7 @@ const props = withDefaults(defineProps<Props>(), {
editMode: false,
listTitle: '',
actionList: [],
showExpandSelect: false, // 默认显示展开级别下拉框
showExpandSelect: true, // 默认显示展开级别下拉框
});
const { t } = useI18n();
const checkMethod: any = inject('checkMethod', () => {
@@ -326,7 +326,6 @@ const expandOptions = computed(() => {
for (let i = 1; i <= maxTreeLevel.value; i++) {
options.push({ label: t('表格.显示级', { level: i }), value: String(i) });
}
options.push();
return options;
});
@@ -393,15 +392,15 @@ const calcMaxLevelFun = () => {
if (!vxeTableRef.value) {
return;
}
const treeData = vxeTableRef.value.getTableData().fullData;
if (!treeData || treeData.length === 0) {
const { fullData } = vxeTableRef.value.getTableData();
if (!fullData || fullData.length === 0) {
maxTreeLevel.value = 1;
return;
}
let maxLevel = 1;
const levelMap = new Map<any, number>();
traverseTree(
treeData,
fullData,
(node: any, parent: any) => {
const level = parent ? (levelMap.get(parent) || 1) + 1 : 1;
levelMap.set(node, level);
@@ -423,48 +422,46 @@ const expandVisibleChangeFun = (visible: boolean) => {
}
};
const collectRowsToExpand = (data: any[], targetLevel: number) => {
const rowsToExpand: any[] = [];
const levelMap = new Map<any, number>();
if (!Array.isArray(data) || !targetLevel) {
return rowsToExpand;
}
traverseTree(
data,
(node: any, parent: any) => {
const nodeLevel = parent ? (levelMap.get(parent) || 1) + 1 : 1;
levelMap.set(node, nodeLevel);
if (nodeLevel < targetLevel) {
rowsToExpand.push(node);
}
},
null
);
return rowsToExpand;
};
const expandLevelFun = (level: string) => {
if (!vxeTableRef.value) {
return;
}
expandLevel.value = level;
const { fullData = [], visibleData = [] } = vxeTableRef.value.getTableData();
const flattedVisibleData = flatNode(visibleData);
if (level === 'all') {
vxeTableRef.value.setAllTreeExpand(true);
vxeTableRef.value.setTreeExpand(flattedVisibleData, true);
} else if (level === 'collapse') {
vxeTableRef.value.setAllTreeExpand(false);
vxeTableRef.value.setTreeExpand(flattedVisibleData, false);
} else {
const targetLevel = parseInt(level, 10);
const treeData = vxeTableRef.value.getTableData().fullData;
const levelMap = new Map<any, number>();
const rowsToExpand: any[] = [];
traverseTree(
treeData,
(node: any, parent: any) => {
const nodeLevel = parent ? (levelMap.get(parent) || 1) + 1 : 1;
levelMap.set(node, nodeLevel);
if (nodeLevel < targetLevel) {
rowsToExpand.push(node);
}
},
null
);
vxeTableRef.value.setAllTreeExpand(false);
const rowsToExpand = collectRowsToExpand(fullData, targetLevel);
vxeTableRef.value.setTreeExpand(flattedVisibleData, false);
nextTick(() => {
vxeTableRef.value.setTreeExpand(rowsToExpand, true);
});
}
};
const checkDataChangeFun = () => {
if (!vxeTableRef.value) {
return;
}
calcMaxLevelFun();
nextTick(() => {
expandLevelFun(expandLevel.value);
});
};
watch(
() => props.params,
(val: any) => {

View File

@@ -136,6 +136,8 @@ watch(
standard.value = formData.value.standard;
if (formData.value.flowTemplate) {
selectedFlowTemplate.value = formData.value.flowTemplate;
} else {
selectedFlowTemplate.value = null;
}
}
});

View File

@@ -170,6 +170,7 @@
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
clearable
:disabled-date="(time: Date) => disabledDate(time, row, 'beginTime')"
/>
</template>
<!-- 计划结束时间 -->
@@ -189,6 +190,7 @@
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
clearable
:disabled-date="(time: Date) => disabledDate(time, row, 'endTime')"
/>
</template>
<!-- 军令状时间 -->
@@ -595,6 +597,22 @@ const onNodeNameChangeFun = (row: any, val: string) => {
}
};
const disabledDate = (time: Date, row: any, flag: string) => {
if (flag === 'beginTime') {
if (row.endTime) {
return time.getTime() > new Date(row.endTime).getTime();
} else {
return false;
}
} else {
if (row.beginTime) {
return time.getTime() < new Date(row.beginTime).getTime();
} else {
return false;
}
}
};
onMounted(() => {
initProjectDicts();
taskStore.fetchTemplates();

View File

@@ -94,17 +94,16 @@ const initFun = (data: any) => {
if (uploading.value) {
return;
}
const isSaveLocal = data.data?.isSaveLocal || 'N';
listData.value.some((item: any, index: number) => {
if (item.data.status === '0') {
sliceFileFun(index, isSaveLocal);
sliceFileFun(index);
return true;
}
});
};
// 分片并上传
const sliceFileFun = async (fileIndex: number, isSaveLocal?: any) => {
const sliceFileFun = async (fileIndex: number) => {
uploading.value = true;
const fileObj = listData.value[fileIndex];
const file = fileObj.file;
@@ -124,7 +123,7 @@ const sliceFileFun = async (fileIndex: number, isSaveLocal?: any) => {
chunk: chunkIndex + 1,
chunkTotal: totalChunks,
file: chunkFile,
isSaveLocal,
isSaveLocal: fileData.isSaveLocal,
};
if (fileTempPath) {
params.fileTempPath = fileTempPath;

View File

@@ -362,6 +362,7 @@ const runUploadRunFilesFun = async (list: any) => {
if (res && res.code === 200) {
res.data.forEach((item: any, index: any) => {
item.isSaveLocal = 'Y';
emitter.emit('ADD_UPLOAD_FILE', {
file: list[index].raw,
data: {
@@ -369,7 +370,6 @@ const runUploadRunFilesFun = async (list: any) => {
...item,
isApprove: 0, // 0否 1是
taskType: 4, // 4交付物
isSaveLocal: 'Y',
},
});
});

View File

@@ -92,6 +92,7 @@ import { CommonStore } from '@/stores/common';
// import dayjs from 'dayjs';
import { getTagMapList } from '@/utils/task';
import TableForm from '@/components/common/table/tableForm.vue';
import { useI18n } from 'vue-i18n';
const props = defineProps<{
showNodeInfoDialog: boolean;
@@ -100,6 +101,9 @@ const props = defineProps<{
projectBeginTime?: string;
projectEndTime?: string;
}>();
const { t } = useI18n();
const emits = defineEmits([
'update:showNodeInfoDialog',
'nextPageFun',
@@ -124,6 +128,8 @@ const actionList = ref([
{
title: '删除',
type: 'danger',
needConfirm: true,
confirmTip: t('通用.确认删除吗'),
click: (row: any) => {
disposeDeleteListFun(row);
},

View File

@@ -541,7 +541,7 @@ const getUserGroupTaskCompleteStatistics = async () => {
res.data?.allExeStatus?.map((item: any) => {
return TASK_PROCESS_STATUS_OBJ[item];
}) || [];
console.log(legendData, 'legendData');
seriesData = legendData?.map((item: any) => {
return {
name: item,
@@ -556,16 +556,28 @@ const getUserGroupTaskCompleteStatistics = async () => {
},
};
});
res.data?.result?.forEach((item: any) => {
xData.push(item.userName);
for (const key in item.statusCount) {
seriesData?.forEach((seriesItem: any) => {
if (seriesItem.name === TASK_PROCESS_STATUS_OBJ[key]) {
seriesItem.data.push(item.statusCount[key]);
if (res.data?.result) {
res.data.result.forEach((item: any) => {
if (item.userName) {
xData.push(item.userName);
}
// 遍历所有状态
legendData.forEach((statusName: string) => {
// 找到对应的 seriesItem
const seriesItem = seriesData.find((item: any) => item.name === statusName);
if (seriesItem) {
// 获取状态对应的 key
const statusKey = Object.keys(TASK_PROCESS_STATUS_OBJ).find(
(key) => TASK_PROCESS_STATUS_OBJ[key] === statusName
);
if (statusKey) {
// 如果 statusCount 中有这个状态,使用其值,否则使用 0
seriesItem.data.push(item.statusCount?.[statusKey] || '');
}
}
});
}
});
});
}
}
return {
xData,
@@ -620,9 +632,8 @@ const userDifficultyCoefficientFormData = reactive<any>({
const userDifficultyCoefficientChartRef = ref();
const getDifficultyLevel = (difficulty: number) => {
const str = DIFFICULTY_COEFFICIENT.value.O[difficulty];
return str ? str + ', 系数' : '难度系数';
return str ? str : '难度系数';
};
// console.log(getDifficultyLevel(5), '000000');
const initUserDifficultyCoefficientStatistics = async () => {
let xData: any = [];
// const yData:any = [1, 2, 3, 4];
@@ -1276,16 +1287,28 @@ const getProjectGroupTaskCompleteStatistics = async () => {
},
};
});
res.data?.result?.forEach((item: any) => {
xData.push(item.userName);
for (const key in item.statusCount) {
seriesData?.forEach((seriesItem: any) => {
if (seriesItem.name === TASK_PROCESS_STATUS_OBJ[key]) {
seriesItem.data.push(item.statusCount[key]);
if (res.data?.result) {
res.data.result.forEach((item: any) => {
if (item.userName) {
xData.push(item.userName);
}
// 遍历所有状态
legendData.forEach((statusName: string) => {
// 找到对应的 seriesItem
const seriesItem = seriesData.find((item: any) => item.name === statusName);
if (seriesItem) {
// 获取状态对应的 key
const statusKey = Object.keys(TASK_PROCESS_STATUS_OBJ).find(
(key) => TASK_PROCESS_STATUS_OBJ[key] === statusName
);
if (statusKey) {
// 如果 statusCount 中有这个状态,使用其值,否则使用 0
seriesItem.data.push(item.statusCount?.[statusKey] || '');
}
}
});
}
});
});
}
}
return {
xData,

View File

@@ -137,10 +137,9 @@ const openDialog = (type: string, row?: any) => {
// nextTick(() => {
if (type === 'edit' && row) {
row.fileType = String(row.fileType);
row.files = [{ name: row.originalName }];
row.files = [{ name: row.originalName, id: row.id }];
oldFile.value = {
id: row.id,
uid: row.files[0].uid,
};
// tableFormRef.value.setFormDataFun(row);
editRowInfo.value = { ...row };
@@ -231,9 +230,11 @@ const confirmUploadFun = async () => {
}
});
}
const oldFileInfo = fromData.files.find((item: any) => item.uid === oldFile.value.uid);
if (!oldFileInfo) {
dataDelFileApi({ delFileId: oldFile.value.id });
if (isEditDialog.value) {
const oldFileInfo = fromData.files.find((item: any) => item?.id === oldFile.value.id);
if (!oldFileInfo) {
dataDelFileApi({ delFileId: oldFile.value.id });
}
}
} else {
// 无文件更新

View File

@@ -497,7 +497,7 @@ const queryUserTaskCompletion = async () => {
// });
const getDifficultyLevel = (difficulty: number) => {
const str = DIFFICULTY_COEFFICIENT.value.O[difficulty];
return str ? str + ', 系数' : '难度系数';
return str ? str : '难度系数';
};
const userDifficultyCoefficientChartRef = ref();
const queryUserDifficultStatistics = async () => {

View File

@@ -419,7 +419,8 @@ const expandTree = (treeRef: any) => {
const selectMethod = ref('template'); // template 模板库 project 历史项目
const transferTask = async () => {
if (getLeftVxeRef().getCheckboxRecords().length === 0) {
const leftSelection = getLeftVxeRef().getCheckboxRecords();
if (leftSelection.length === 0) {
ElMessage.warning('请先选择左侧任务节点!');
return;
}
@@ -432,12 +433,27 @@ const transferTask = async () => {
const rightSelection = getRightVxeRef().getCheckboxRecords();
if (rightSelection.length === 0) {
// console.log('getRightVxeRef().getTableData()', getRightVxeRef().getTableData());
const { fullData } = getRightVxeRef().getTableData();
for (let index = 0; index < leftSelection.length; index++) {
if (
fullData.find((item: { nodeName: any }) => {
return item.nodeName === leftSelection[index].nodeName;
})
) {
ElMessage.warning('右侧已存在同名节点,如想覆盖,则需勾选右侧相同节点!');
return;
}
}
}
if (rightSelection.length > 1) {
ElMessage.warning('右侧只能选择一个节点进行导入!');
return;
}
const leftMultipleSelection = clearLeftSelectRepeat(getLeftVxeRef().getCheckboxRecords());
const leftMultipleSelection = clearLeftSelectRepeat(leftSelection);
const leftInsertArr: any[][] = [];
for (let index = 0; index < leftMultipleSelection.length; index++) {
@@ -595,7 +611,11 @@ const mergeArrays = async (
key !== 'pid' &&
key !== '_X_ROW_CHILD'
) {
updateRow[key] = leftList[index][key];
// console.log('leftList', key, leftList[index], leftList[index][key]);
// if (updateRow.hasOwnProperty(key)) {
if (updateRow.hasOwnProperty(key)) {
updateRow[key] = leftList[index][key];
}
}
});
await getRightVxeRef().setRow(rightList[foundIndex], newObj);
@@ -1069,10 +1089,10 @@ const tableFormChangeFun = (data: any) => {
};
const checkMethod = computed(() => {
return ({ row }: any) => {
// return row.uuid === 'simu_pool_task_7df6f758-001a-4893-8104-821f6e2a612513130';
return !checkChildrenIds.value.includes(row.uuid);
};
return () => true;
// return ({ row }: any) => {
// return !checkChildrenIds.value.includes(row.uuid);
// };
});
const checkChildrenIds = ref<any>([]);

View File

@@ -26,6 +26,7 @@
@change="changeFun"
@load="formLoad"
v-model:data="editRow"
:formAttrs="formAttrs"
>
</TableForm>
<template #footer>
@@ -78,6 +79,19 @@ const props = defineProps({
},
});
const formAttrs = ref({
progress: {
min: 0,
max: 100,
},
confidence: {
min: 0,
max: 1,
precision: 2,
step: 0.01,
},
});
const taskParams = ref({ type: 0 });
const exeTableRef = ref();

View File

@@ -89,6 +89,12 @@ const formAttrs = ref({
min: 0,
max: 100,
},
confidence: {
min: 0,
max: 1,
precision: 2,
step: 0.01,
},
});
const taskParams = ref({ type: 3 });

View File

@@ -35,7 +35,6 @@
<template #progress="{ row }"> {{ row.progress || 0 }}% </template>
<template #approvalStatus="{ row }">
<StatusDot
class="clcik-approval"
:status="
getApproveStyleClass(row.approvalStatus || TASK_APPROVE_STATUS_ENUM.NOT_APPROVED)
"

View File

@@ -8,6 +8,7 @@
v-model="filterFprmData.userGroupId"
class="mw200"
clearable
@clear="filterFprmData.userGroupId = ''"
@change="filterWorkLoadFun('group')"
>
<el-option
@@ -26,7 +27,7 @@
multiple
clearable
class="mw200"
@change="filterWorkLoadFun"
@change="userChangeFun"
@focus="focusUserFun"
>
<el-option
@@ -105,6 +106,7 @@ import { getListUserWorkloadsApi } from '@/api/project/task';
import { ElMessage } from 'element-plus';
import type { ChineseWorkday } from 'chinese-workday';
import DetailDia from '@/views/task/workLoad/detailDia.vue';
import { debounce } from 'lodash-es';
const props = defineProps({
// 维度工作负载以人person为维度 人力负载以项目project为维度
@@ -124,6 +126,7 @@ const props = defineProps({
type: Array,
default: () => [],
},
// 是否需要展示汇总行
showTotal: {
type: Boolean,
default: false,
@@ -145,7 +148,7 @@ dayjs.extend(isoWeek);
let Gantt: any = gantt;
const ganttEvents = ref<any>([]);
const colorList: string[] = ['#ffffff', '#d9ecff', '#c6e2ff', '#c6e2ff', '#79bbff', '#409eff']; // 格子颜色
const colorList: string[] = ['#ffffff', '#e9f4ff', '#c6e2ff', '#acd3ff', '#79bbff', '#409eff']; // 格子颜色
const taskOriginData = ref<any>([]); // 所有用户的任务数据
const loading = ref<boolean>(false);
// const workDaysRange = ref<number>(0);
@@ -227,13 +230,6 @@ const getWorkLoadDataFun = async () => {
...filterFprmData,
...props.filterData,
};
if (!filterFprmData.userGroupId) {
param.userGroupId = '';
}
if (!filterFprmData.userIds.length) {
param.userIds = [];
}
// 根据页面类型去掉没用的参数
if (props.dimension === 'project') {
delete param.userGroupId;
@@ -737,7 +733,11 @@ const refreshGanttFun = async () => {
initGantt();
await getWorkLoadDataFun();
};
// 切换用户
const userChangeFun = debounce(async () => {
await filterWorkLoadFun();
}, 500);
// 用户下拉框获取焦点
const focusUserFun = () => {
if (!filterFprmData.userGroupId) {
ElMessage.warning('请选择用户组后再选择用户进行筛选!');

View File

@@ -52,7 +52,7 @@ const columns = [
const fieldMapFun = (data: any) => {
const list = data.map((item: any) => {
return {
userName: item.projectName, // 显示项目名称
userName: item.projectName, // 显示项目名称--姓名
userId: item.projectId, // 项目ID
taskNum: item.taskNum, // 任务数量
workNum: item.personNum, // 人员数量