{ "Rows": { "RowColumnAttachedInfos": { "0": { "GridRowColumnDefinition": { "DesignLengthInPixel": 15.0 } }, "1": { "GridRowColumnDefinition": { "DesignLengthInPixel": 102.0, "Mode": 1 } }, "2": { "GridRowColumnDefinition": { "DesignLengthInPixel": 10.0 } }, "3": { "GridRowColumnDefinition": { "DesignLengthInPixel": 97.0, "Mode": 1 } }, "4": { "GridRowColumnDefinition": { "DesignLengthInPixel": 10.0 } }, "5": { "GridRowColumnDefinition": { "DesignLengthInPixel": 15.0 } }, "6": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "7": { "GridRowColumnDefinition": { "DesignLengthInPixel": 10.0 } }, "8": { "GridRowColumnDefinition": { "DesignLengthInPixel": 243.0 } }, "9": { "GridRowColumnDefinition": { "DesignLengthInPixel": 10.0 } }, "10": { "GridRowColumnDefinition": { "DesignLengthInPixel": 383.0 } }, "11": { "GridRowColumnDefinition": { "DesignLengthInPixel": 10.0 } }, "12": { "GridRowColumnDefinition": { "DesignLengthInPixel": 1000.0 } }, "13": { "GridRowColumnDefinition": { "DesignLengthInPixel": 15.0 } }, "14": { "GridRowColumnDefinition": { "DesignLengthInPixel": 50.0, "Mode": 1 } }, "15": { "GridRowColumnDefinition": { "DesignLengthInPixel": 10.0 } }, "16": { "GridRowColumnDefinition": { "DesignLengthInPixel": 1000.0 } }, "17": { "GridRowColumnDefinition": { "DesignLengthInPixel": 15.0 } }, "18": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } } }, "InLogicalVisibleIndexes": [ 2, 3, 18 ], "Count": 19, "DefaultSize": 10.0 }, "Cols": { "RowColumnAttachedInfos": { "0": { "GridRowColumnDefinition": { "DesignLengthInPixel": 24.0 } }, "1": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "2": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "3": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "4": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "5": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "6": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "7": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "8": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "9": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "10": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "11": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "12": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "13": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "14": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "15": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "16": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "17": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "18": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "19": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "20": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "21": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "22": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "23": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "24": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "25": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "26": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "27": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "28": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "29": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "30": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "31": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "32": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "33": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "34": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0 } }, "35": { "GridRowColumnDefinition": { "DesignLengthInPixel": 32.0, "Mode": 2, "MinLength": { "Unit": 1 }, "MaxLength": { "Value": 1.0 } } }, "36": { "GridRowColumnDefinition": { "DesignLengthInPixel": 10.0 } }, "37": { "GridRowColumnDefinition": { "DesignLengthInPixel": 15.0 } }, "38": { "GridRowColumnDefinition": { "DesignLengthInPixel": 313.0 } }, "39": { "GridRowColumnDefinition": { "DesignLengthInPixel": 15.0 } }, "40": { "GridRowColumnDefinition": { "DesignLengthInPixel": 24.0 } } }, "Count": 41, "DefaultSize": 32.0 }, "Values": { "1,1": "工作台_关键信息", "1,37": "公告栏", "3,1": "工作台_快捷入口", "5,1": "工时折线图", "6,38": "项目动态", "8,38": "项目动态", "10,1": "工时排行榜(柱形图)", "12,1": "反馈统计(饼图+表格)" }, "AttachInfos": { "1,1": { "CellType": { "$type": "Forguncy.ContentContainerCellType, ServerDesignerCommon", "PageName": "工作台_关键信息", "OverflowMode": 1 } }, "3,1": { "CellType": { "$type": "Forguncy.ContentContainerCellType, ServerDesignerCommon", "PageName": "工作台_快捷入口" } }, "5,1": { "CssName": "none-background", "CellType": { "$type": "EchartsCustomCellType.EchartsCustomCellTypeCellType, EchartsCustomCellType", "EChartTitle": "报工趋势表", "DataSourceBinding": "DataSources", "DataSources": [ { "Name": "工时表", "BindingTableOptions": { "$type": "ServerDesignerCommon.Model.BindingDataSourceModel, ServerDesignerCommon", "TableName": "任务工时表", "BindingInfos": [ { "GUID": "dcf5c7c2-1643-4eb4-b2a3-8e94ef7a14e2", "BindingInfo": { "TableName": "任务工时表", "ColumnName": "工时日期", "GUID": "82e97a2c-9e2f-42e4-937a-453518b48f70" }, "ColumnName": "日期" }, { "GUID": "800c06fe-a05a-4977-b6fc-65bb5b043fa0", "BindingInfo": { "TableName": "任务工时表", "ColumnName": "工时类型", "GUID": "05ce48bf-f222-4108-8c93-8bf9e0087fe0" }, "ColumnName": "工时类型" }, { "GUID": "edd13b7b-55f0-41ed-919f-758450e718b6", "BindingInfo": { "TableName": "任务工时表", "ColumnName": "总工时", "GUID": "786c776d-dcec-411f-8a24-0b19e5ac7564" }, "ColumnName": "总工时" } ], "SqlCondition": { "$type": "ForguncyDataAccess.GeneralCESqlCondition, ForguncyDataAccess", "CompareType": 3, "ColumnBindingInfo": { "TableName": "任务工时表", "ColumnName": "工时日期", "GUID": "dd32edc3-f14d-460a-a04b-d2267e25bc82" }, "Value": { "$type": "Forguncy.Model.FormulaReferObject, ServerDesignerCommon", "SerializeProperty": "=TODAY()-30" } }, "NullFormulaValueQueryPolicy": 1, "OrderBySqlCondition": { "OrderByColumns": [ { "ColumnBindingInfo": { "TableName": "任务工时表", "ColumnName": "工时日期", "GUID": "7e799144-4ee2-4128-b68c-8c6f41270a5f" }, "Order": 0 } ] }, "CustomColumns": [] } } ], "JSONDataSources": [], "ImageDataSource": [], "Config": "{\"option\":\"let completeXAxisData = []; \\nlet completePlanData = []; // 计划工时数据 \\nlet completeActualData = []; // 实际工时数据 \\n\\n// 打印数据源以进行检查 \\nconsole.log(\\\"Context['工时表']:\\\", Context[\\\"工时表\\\"]); \\n\\n// 按工时类型分组数据 \\nconst groupedData = {}; \\nContext[\\\"工时表\\\"].forEach(item => { \\n if (!groupedData[item[\\\"工时类型\\\"]]) { \\n groupedData[item[\\\"工时类型\\\"]] = { \\n dates: [], \\n hours: [] \\n }; \\n } \\n groupedData[item[\\\"工时类型\\\"]].dates.push(item[\\\"日期\\\"]); \\n groupedData[item[\\\"工时类型\\\"]].hours.push(item[\\\"总工时\\\"]); \\n}); \\n\\n// 日期格式化函数保持不变 \\nfunction getDateFormat(value) { \\n if (typeof value === \\\"number\\\") { \\n const excelEpoch = new Date(Date.UTC(1899, 11, 30)); \\n const date = new Date(excelEpoch.getTime() + value * 24 * 60 * 60 * 1000); \\n const year = date.getUTCFullYear(); \\n const month = (date.getUTCMonth() + 1).toString().padStart(2, \\\"0\\\"); \\n const day = date.getUTCDate().toString().padStart(2, \\\"0\\\"); \\n return `${year}-${month}-${day}`; \\n } else if (typeof value === \\\"string\\\") { \\n return value; \\n } \\n return \\\"\\\"; \\n} \\n\\n// 生成日期范围函数保持不变 \\nfunction getDateRange(startDate, endDate) { \\n const dateList = []; \\n let currentDate = new Date(startDate); \\n while (currentDate <= endDate) { \\n const year = currentDate.getFullYear(); \\n const month = (\\\"0\\\" + (currentDate.getMonth() + 1)).slice(-2); \\n const day = (\\\"0\\\" + currentDate.getDate()).slice(-2); \\n dateList.push(`${year}-${month}-${day}`); \\n currentDate.setDate(currentDate.getDate() + 1); \\n } \\n return dateList; \\n} \\n\\n// 获取所有日期并找出最大最小日期 \\nconst allDates = []; \\nObject.values(groupedData).forEach(data => { \\n data.dates.forEach(date => { \\n allDates.push(new Date(getDateFormat(date))); \\n }); \\n}); \\n\\nif (allDates.length > 0) { \\n const minDate = new Date(Math.min(...allDates)); \\n const maxDate = new Date(Math.max(...allDates)); \\n completeXAxisData = getDateRange(minDate, maxDate); \\n\\n // 处理每种类型的数据 \\n Object.entries(groupedData).forEach(([type, data]) => { \\n // 格式化日期 \\n const formattedDates = data.dates.map(date => getDateFormat(date)); \\n \\n // 创建日期-工时映射 \\n const dataMap = {}; \\n formattedDates.forEach((date, index) => { \\n dataMap[date] = data.hours[index]; \\n }); \\n\\n // 补全数据 \\n const completeData = completeXAxisData.map(date => { \\n return dataMap[date] !== undefined ? dataMap[date] : 0; \\n }); \\n\\n // 根据类型存储数据 \\n if (type === \\\"计划\\\") { \\n completePlanData = completeData; \\n } else if (type === \\\"实际\\\") { \\n completeActualData = completeData; \\n } \\n }); \\n} \\n\\n// 配置 Echarts 图表 \\noption = { \\n backgroundColor: \\\"rgba(0, 0, 0, 0)\\\", \\n title: { \\n text: \\\"报工趋势图 (近30天)\\\", \\n left: \\\"center\\\", \\n top: 24, \\n textStyle: { \\n fontSize: 16, \\n fontWeight: \\\"bold\\\", \\n }, \\n }, \\n legend: { \\n data: ['计划工时', '实际工时'], \\n top: 60, \\n textStyle: { \\n color: '#666' \\n } \\n }, \\n grid: { \\n top: 100, // 增加top值以适应legend \\n left: \\\"24px\\\", \\n right: \\\"24px\\\", \\n bottom: \\\"24px\\\", \\n containLabel: true, \\n }, \\n xAxis: { \\n type: \\\"category\\\", \\n data: completeXAxisData, \\n axisLabel: { \\n color: \\\"#abacac\\\", \\n }, \\n axisLine: { \\n lineStyle: { \\n color: \\\"#f5f6f6\\\", \\n }, \\n }, \\n axisTick: { \\n lineStyle: { \\n color: \\\"#f5f6f6\\\", \\n }, \\n }, \\n }, \\n yAxis: { \\n type: \\\"value\\\", \\n axisLabel: { \\n color: \\\"#abacac\\\", \\n }, \\n axisLine: { \\n lineStyle: { \\n color: \\\"#f5f6f6\\\", \\n }, \\n }, \\n axisTick: { \\n lineStyle: { \\n color: \\\"#f5f6f6\\\", \\n }, \\n }, \\n splitLine: { \\n show: true, \\n lineStyle: { \\n color: \\\"#f8fafc\\\", \\n }, \\n }, \\n }, \\n tooltip: { \\n trigger: \\\"axis\\\", \\n backgroundColor: \\\"#FFFFFF\\\", \\n textStyle: { \\n color: \\\"#000000\\\", \\n }, \\n }, \\n series: [ \\n { \\n name: '计划工时', \\n data: completePlanData, \\n type: \\\"line\\\", \\n lineStyle: { \\n width: 3, \\n shadowColor: \\\"rgba(0, 0, 0, 0.1)\\\", \\n shadowBlur: 10, \\n shadowOffsetX: 0, \\n shadowOffsetY: 4, \\n }, \\n smooth: true, \\n symbolSize: 8, \\n symbol: \\\"none\\\", \\n itemStyle: { \\n color: \\\"#2196f3\\\", // 蓝色 \\n }, \\n areaStyle: { \\n color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ \\n { \\n offset: 0, \\n color: \\\"rgba(33,150,243,0.3)\\\", \\n }, \\n { \\n offset: 1, \\n color: \\\"rgba(33,150,243,0)\\\", \\n }, \\n ]), \\n }, \\n }, \\n { \\n name: '实际工时', \\n data: completeActualData, \\n type: \\\"line\\\", \\n lineStyle: { \\n width: 3, \\n shadowColor: \\\"rgba(0, 0, 0, 0.1)\\\", \\n shadowBlur: 10, \\n shadowOffsetX: 0, \\n shadowOffsetY: 4, \\n }, \\n smooth: true, \\n symbolSize: 8, \\n symbol: \\\"none\\\", \\n itemStyle: { \\n color: \\\"#ff5722\\\", // 橙色 \\n }, \\n areaStyle: { \\n color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ \\n { \\n offset: 0, \\n color: \\\"rgba(255,87,34,0.3)\\\", \\n }, \\n { \\n offset: 1, \\n color: \\\"rgba(255,87,34,0)\\\", \\n }, \\n ]), \\n }, \\n } \\n ], \\n};\",\"graphTheme\":null,\"displayMode\":\"canvas\",\"jsCode\":\"\\n async ({Context,JSONContext,ImageContext,echarts,myChart,dat,Forguncy,d3,setInterval,setTimeout,ForguncyEchartsHelper,PublicResource})=>{\\n var datGUI=undefined;\\n var option={};\\n let completeXAxisData = [];\\nlet completePlanData = []; // 计划工时数据 \\nlet completeActualData = []; // 实际工时数据 \\n// 打印数据源以进行检查 \\nconsole.log(\\\"Context['工时表']:\\\", Context[\\\"工时表\\\"]);\\n// 按工时类型分组数据 \\nconst groupedData = {};\\nContext[\\\"工时表\\\"].forEach(item => {\\n if (!groupedData[item[\\\"工时类型\\\"]]) {\\n groupedData[item[\\\"工时类型\\\"]] = {\\n dates: [],\\n hours: []\\n };\\n }\\n groupedData[item[\\\"工时类型\\\"]].dates.push(item[\\\"日期\\\"]);\\n groupedData[item[\\\"工时类型\\\"]].hours.push(item[\\\"总工时\\\"]);\\n});\\n// 日期格式化函数保持不变 \\nfunction getDateFormat(value) {\\n if (typeof value === \\\"number\\\") {\\n const excelEpoch = new Date(Date.UTC(1899, 11, 30));\\n const date = new Date(excelEpoch.getTime() + value * 24 * 60 * 60 * 1000);\\n const year = date.getUTCFullYear();\\n const month = (date.getUTCMonth() + 1).toString().padStart(2, \\\"0\\\");\\n const day = date.getUTCDate().toString().padStart(2, \\\"0\\\");\\n return `${year}-${month}-${day}`;\\n }\\n else if (typeof value === \\\"string\\\") {\\n return value;\\n }\\n return \\\"\\\";\\n}\\n// 生成日期范围函数保持不变 \\nfunction getDateRange(startDate, endDate) {\\n const dateList = [];\\n let currentDate = new Date(startDate);\\n while (currentDate <= endDate) {\\n const year = currentDate.getFullYear();\\n const month = (\\\"0\\\" + (currentDate.getMonth() + 1)).slice(-2);\\n const day = (\\\"0\\\" + currentDate.getDate()).slice(-2);\\n dateList.push(`${year}-${month}-${day}`);\\n currentDate.setDate(currentDate.getDate() + 1);\\n }\\n return dateList;\\n}\\n// 获取所有日期并找出最大最小日期 \\nconst allDates = [];\\nObject.values(groupedData).forEach(data => {\\n data.dates.forEach(date => {\\n allDates.push(new Date(getDateFormat(date)));\\n });\\n});\\nif (allDates.length > 0) {\\n const minDate = new Date(Math.min(...allDates));\\n const maxDate = new Date(Math.max(...allDates));\\n completeXAxisData = getDateRange(minDate, maxDate);\\n // 处理每种类型的数据 \\n Object.entries(groupedData).forEach(([type, data]) => {\\n // 格式化日期 \\n const formattedDates = data.dates.map(date => getDateFormat(date));\\n // 创建日期-工时映射 \\n const dataMap = {};\\n formattedDates.forEach((date, index) => {\\n dataMap[date] = data.hours[index];\\n });\\n // 补全数据 \\n const completeData = completeXAxisData.map(date => {\\n return dataMap[date] !== undefined ? dataMap[date] : 0;\\n });\\n // 根据类型存储数据 \\n if (type === \\\"计划\\\") {\\n completePlanData = completeData;\\n }\\n else if (type === \\\"实际\\\") {\\n completeActualData = completeData;\\n }\\n });\\n}\\n// 配置 Echarts 图表 \\noption = {\\n backgroundColor: \\\"rgba(0, 0, 0, 0)\\\",\\n title: {\\n text: \\\"报工趋势图 (近30天)\\\",\\n left: \\\"center\\\",\\n top: 24,\\n textStyle: {\\n fontSize: 16,\\n fontWeight: \\\"bold\\\",\\n },\\n },\\n legend: {\\n data: ['计划工时', '实际工时'],\\n top: 60,\\n textStyle: {\\n color: '#666'\\n }\\n },\\n grid: {\\n top: 100,\\n left: \\\"24px\\\",\\n right: \\\"24px\\\",\\n bottom: \\\"24px\\\",\\n containLabel: true,\\n },\\n xAxis: {\\n type: \\\"category\\\",\\n data: completeXAxisData,\\n axisLabel: {\\n color: \\\"#abacac\\\",\\n },\\n axisLine: {\\n lineStyle: {\\n color: \\\"#f5f6f6\\\",\\n },\\n },\\n axisTick: {\\n lineStyle: {\\n color: \\\"#f5f6f6\\\",\\n },\\n },\\n },\\n yAxis: {\\n type: \\\"value\\\",\\n axisLabel: {\\n color: \\\"#abacac\\\",\\n },\\n axisLine: {\\n lineStyle: {\\n color: \\\"#f5f6f6\\\",\\n },\\n },\\n axisTick: {\\n lineStyle: {\\n color: \\\"#f5f6f6\\\",\\n },\\n },\\n splitLine: {\\n show: true,\\n lineStyle: {\\n color: \\\"#f8fafc\\\",\\n },\\n },\\n },\\n tooltip: {\\n trigger: \\\"axis\\\",\\n backgroundColor: \\\"#FFFFFF\\\",\\n textStyle: {\\n color: \\\"#000000\\\",\\n },\\n },\\n series: [\\n {\\n name: '计划工时',\\n data: completePlanData,\\n type: \\\"line\\\",\\n lineStyle: {\\n width: 3,\\n shadowColor: \\\"rgba(0, 0, 0, 0.1)\\\",\\n shadowBlur: 10,\\n shadowOffsetX: 0,\\n shadowOffsetY: 4,\\n },\\n smooth: true,\\n symbolSize: 8,\\n symbol: \\\"none\\\",\\n itemStyle: {\\n color: \\\"#2196f3\\\", // 蓝色 \\n },\\n areaStyle: {\\n color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [\\n {\\n offset: 0,\\n color: \\\"rgba(33,150,243,0.3)\\\",\\n },\\n {\\n offset: 1,\\n color: \\\"rgba(33,150,243,0)\\\",\\n },\\n ]),\\n },\\n },\\n {\\n name: '实际工时',\\n data: completeActualData,\\n type: \\\"line\\\",\\n lineStyle: {\\n width: 3,\\n shadowColor: \\\"rgba(0, 0, 0, 0.1)\\\",\\n shadowBlur: 10,\\n shadowOffsetX: 0,\\n shadowOffsetY: 4,\\n },\\n smooth: true,\\n symbolSize: 8,\\n symbol: \\\"none\\\",\\n itemStyle: {\\n color: \\\"#ff5722\\\", // 橙色 \\n },\\n areaStyle: {\\n color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [\\n {\\n offset: 0,\\n color: \\\"rgba(255,87,34,0.3)\\\",\\n },\\n {\\n offset: 1,\\n color: \\\"rgba(255,87,34,0)\\\",\\n },\\n ]),\\n },\\n }\\n ],\\n};\\n\\n return {\\n option,\\n datGUI,\\n };\\n }\\n \"}" } }, "8,38": { "CellType": { "$type": "Forguncy.RepeaterCellType, ServerDesignerCommon", "TemplatePageName": "3868fc7f40b841649f14b5adba61954", "DataSourceType": 1, "DataSource": { "$type": "ServerDesignerCommon.Model.BindingDataSourceModel, ServerDesignerCommon", "TableName": "项目动态", "BindingInfos": [ { "GUID": "b3f78435-9660-4abe-882b-c49e646e5f0c", "BindingInfo": { "TableName": "项目动态", "ColumnName": "项目ID", "GUID": "92efd49e-0be5-4429-85e0-11fc43ac401b", "RelationBinding": { "RelatedTable": "项目表", "RelatedColumn": "ID", "DisplayColumn": "项目名称" } }, "ColumnName": "项目名称" }, { "GUID": "f88b9218-ba69-4c3d-b07b-cdaf08124e05", "BindingInfo": { "TableName": "项目动态", "ColumnName": "项目动态", "GUID": "748d15fc-d5f0-408a-a4b3-c21b44126093" }, "ColumnName": "项目动态" }, { "GUID": "89bd6358-3520-4e9e-91c6-6e68af024915", "BindingInfo": { "TableName": "项目动态", "ColumnName": "执行人", "GUID": "6eae3b71-c332-4ac4-9d39-f0dac2ca6bc5", "AttachType": { "$type": "ForguncyDataAccess.UserColumnAttachObj, ForguncyDataAccess", "UserColumnAttachType": 1 } }, "ColumnName": "执行人_全名" }, { "GUID": "923d170f-b12e-4d76-9297-348a302bdc40", "BindingInfo": { "TableName": "项目动态", "ColumnName": "类型", "GUID": "50543609-aa2c-43c0-a6ca-74269c242dcb", "RelationBinding": { "RelatedTable": "项目动态类型", "RelatedColumn": "类型码", "DisplayColumn": "类型" } }, "ColumnName": "类型" }, { "GUID": "e92f7984-ecce-4ea7-beab-51eb5b9a055a", "BindingInfo": { "TableName": "项目动态", "ColumnName": "FGC_CreateDate", "GUID": "e75f3c02-ac4d-4deb-a52f-881065832673" }, "ColumnName": "创建日期" } ], "OrderBySqlCondition": { "OrderByColumns": [ { "ColumnBindingInfo": { "TableName": "项目动态", "ColumnName": "FGC_CreateDate", "GUID": "f75648fb-423f-4f0a-b09c-c7394a91d84b" }, "Order": 1 } ] }, "IsListviewDataSource": true, "CustomColumns": [] }, "DataSourceListviewName": "图文列表表格1", "TopCount": 30, "IsLoadOnDemand": true, "LoadOnDemandCount": 30 } }, "10,1": { "CellType": { "$type": "EchartsCustomCellType.EchartsCustomCellTypeCellType, EchartsCustomCellType", "EChartTitle": "工时排行榜", "DataSourceBinding": "DataSources", "DataSources": [ { "Name": "工时统计", "BindingTableOptions": { "$type": "ServerDesignerCommon.Model.BindingDataSourceModel, ServerDesignerCommon", "TableName": "人员工时统计视图", "BindingInfos": [ { "GUID": "8b699743-3aa9-4d92-9903-befbec0b7e5a", "BindingInfo": { "TableName": "人员工时统计视图", "ColumnName": "执行人", "GUID": "49a350f1-88a5-4b57-98c5-e44bfde1da05", "AttachType": { "$type": "ForguncyDataAccess.UserColumnAttachObj, ForguncyDataAccess", "UserColumnAttachType": 1 } }, "ColumnName": "执行人" }, { "GUID": "b5a5da98-fe34-4196-a0c4-f8aaf698b575", "BindingInfo": { "TableName": "人员工时统计视图", "ColumnName": "总上报工时", "GUID": "0b45d04d-ee59-47c1-8dea-3794517e6f8f" }, "ColumnName": "总上报工时" }, { "GUID": "7ca1cd9f-08c4-4384-93e5-176c41214704", "BindingInfo": { "TableName": "人员工时统计视图", "ColumnName": "总核定工时", "GUID": "1658227e-885b-4186-8624-4357b8d11b58" }, "ColumnName": "总核定工时" } ], "SqlCondition": { "$type": "ForguncyDataAccess.RelationSqlCondition, ForguncyDataAccess", "SubConditions": [ { "$type": "ForguncyDataAccess.GeneralCESqlCondition, ForguncyDataAccess", "CompareType": 1, "ColumnBindingInfo": { "TableName": "人员工时统计视图", "ColumnName": "执行人", "GUID": "0b34c9f5-aaee-4d74-9fea-09972a65f116" }, "Value": "%Null%" }, { "$type": "ForguncyDataAccess.GeneralCESqlCondition, ForguncyDataAccess", "ColumnBindingInfo": { "TableName": "人员工时统计视图", "ColumnName": "日期", "GUID": "5d56155e-bbed-4c17-a938-53888dad630a", "AttachType": { "$type": "ForguncyDataAccess.DateColumnAttachObj, ForguncyDataAccess", "ColumnAttachType": 1 } }, "Value": { "$type": "Forguncy.Model.FormulaReferObject, ServerDesignerCommon", "SerializeProperty": "=YEAR(TODAY())" } }, { "$type": "ForguncyDataAccess.GeneralCESqlCondition, ForguncyDataAccess", "ColumnBindingInfo": { "TableName": "人员工时统计视图", "ColumnName": "日期", "GUID": "d4638e91-990f-415a-8a11-365f7a397486", "AttachType": { "$type": "ForguncyDataAccess.DateColumnAttachObj, ForguncyDataAccess", "ColumnAttachType": 4 } }, "Value": { "$type": "Forguncy.Model.FormulaReferObject, ServerDesignerCommon", "SerializeProperty": "=MONTH(TODAY())" } } ] }, "NullFormulaValueQueryPolicy": 2, "OrderBySqlCondition": { "OrderByColumns": [ { "ColumnBindingInfo": { "TableName": "人员工时统计视图", "ColumnName": "总上报工时", "GUID": "68e4253e-8c7e-44c0-95e7-a3bd293eee65" }, "Order": 1 } ] }, "CustomColumns": [] } } ], "JSONDataSources": [], "ImageDataSource": [], "Config": "{\"option\":\"// 获取数据源并拆分数据 \\nvar sourceData = Context[\\\"工时统计\\\"];\\nconsole.log(sourceData);\\nvar splitData = ForguncyEchartsHelper.splitDataSource(sourceData);\\n\\n// 将数据保留到1位小数 \\nfor (var key in splitData) {\\n if (key !== \\\"执行人\\\") {\\n splitData[key] = splitData[key].map(function (value) {\\n return parseFloat(value.toFixed(1));\\n });\\n }\\n}\\n\\n// 将数据按照「总核定工时」降序排序 \\nvar indices = splitData[\\\"总核定工时\\\"] \\n .map(function (value, index) { return index; }) \\n .sort(function (a, b) { return splitData[\\\"总核定工时\\\"][b] - splitData[\\\"总核定工时\\\"][a]; }); \\n\\n// 根据排序后的索引重组数据 \\nvar xData = indices.map(function (index) { return splitData[\\\"执行人\\\"][index]; });\\nvar totalReported = indices.map(function (index) { return splitData[\\\"总上报工时\\\"][index]; });\\nvar totalApproved = indices.map(function (index) { return splitData[\\\"总核定工时\\\"][index]; });\\n\\nvar difference = totalReported.map(function (value, index) {\\n var diff = parseFloat((value - totalApproved[index]).toFixed(1));\\n return diff > 0 ? diff : null; // 当差值小于等于0时返回null \\n});\\n\\n// 配置 Echarts 的 option \\noption = {\\n backgroundColor: \\\"rgba(0, 0, 0, 0)\\\",\\n title: {\\n text: \\\"工时排行榜(本月)\\\",\\n left: \\\"center\\\",\\n top: 24,\\n textStyle: {\\n fontSize: 16,\\n fontWeight: \\\"bold\\\",\\n },\\n },\\n grid: {\\n top: 72,\\n left: \\\"24px\\\",\\n right: \\\"24px\\\",\\n bottom: \\\"24px\\\",\\n containLabel: true,\\n },\\n tooltip: {\\n trigger: 'axis',\\n axisPointer: {\\n type: 'shadow',\\n shadowStyle: {\\n color: 'rgba(0,0,0,0.1)'\\n }\\n },\\n formatter: function (params) {\\n return params[0].name + '
' + params[0].seriesName + ':' + params[0].value + '小时' + '
' +\\n params[1].seriesName + ':' + params[1].value;\\n }\\n },\\n legend: {\\n show: false\\n },\\n xAxis: {\\n type: 'category',\\n data: xData,\\n axisLabel:{\\n fontSize:16,\\n color:'#000000'\\n },\\n axisLine: {\\n show: true,\\n lineStyle: {\\n color: '#ccc'\\n }\\n },\\n axisTick: {\\n show: false\\n }\\n },\\n yAxis: {\\n type: 'value',\\n axisLine: {\\n lineStyle: {\\n color: \\\"#f5f6f6\\\",\\n },\\n },\\n splitLine: {\\n show: true,\\n lineStyle: {\\n type: 'dashed',\\n color: 'rgba(200,200,200,0.3)'\\n }\\n }\\n },\\n series: [\\n {\\n name: '已核定工时',\\n type: 'bar',\\n stack: '总量',\\n data: totalApproved.map((value, index) => ({\\n value: value,\\n itemStyle: {\\n borderRadius: difference[index] === null ? [8, 8, 0, 0] : [0, 0, 0, 0],\\n }\\n })),\\n barWidth: '80%',\\n barMinHeight: 20,\\n itemStyle: {\\n color: {\\n type: 'linear',\\n x: 0,\\n y: 0,\\n x2: 0,\\n y2: 1,\\n colorStops: [{\\n offset: 0,\\n color: 'rgba(99,181,246,0.9)'\\n }, {\\n offset: 1,\\n color: 'rgba(99,181,246,0.6)'\\n }]\\n },\\n shadowColor: 'rgba(0, 0, 0, 0.3)',\\n shadowBlur: 10,\\n opacity: 0.8\\n },\\n label: {\\n show: true,\\n position: 'inside',\\n formatter: '{c}小时',\\n color: '#fff',\\n fontSize: 14\\n },\\n animation: true,\\n animationDuration: 500,\\n animationEasing: 'cubicOut'\\n },\\n {\\n name: '未核定工时',\\n type: 'bar',\\n stack: '总量',\\n data: difference,\\n barWidth: '80%',\\n barMinHeight: 40,\\n itemStyle: {\\n color: 'rgba(200, 200, 200, 0.2)',\\n borderColor: 'rgba(200, 200, 200, 0.6)',\\n borderWidth: 1,\\n borderRadius: [8, 8, 0, 0], // 添加顶部圆角\\n shadowColor: 'rgba(0, 0, 0, 0.1)',\\n shadowBlur: 5\\n },\\n label: {\\n show: true,\\n position: 'inside',\\n formatter: function (params) {\\n if (params.value > 0) {\\n return params.value + '小时';\\n } else {\\n return '';\\n }\\n },\\n color: '#666',\\n fontSize: 14\\n },\\n animation: true,\\n animationDuration: 500,\\n animationEasing: 'cubicOut'\\n }\\n ]\\n};\",\"graphTheme\":null,\"displayMode\":\"canvas\",\"jsCode\":\"\\n async ({Context,JSONContext,ImageContext,echarts,myChart,dat,Forguncy,d3,setInterval,setTimeout,ForguncyEchartsHelper,PublicResource})=>{\\n var datGUI=undefined;\\n var option={};\\n // 获取数据源并拆分数据 \\nvar sourceData = Context[\\\"工时统计\\\"];\\nconsole.log(sourceData);\\nvar splitData = ForguncyEchartsHelper.splitDataSource(sourceData);\\n// 将数据保留到1位小数 \\nfor (var key in splitData) {\\n if (key !== \\\"执行人\\\") {\\n splitData[key] = splitData[key].map(function (value) {\\n return parseFloat(value.toFixed(1));\\n });\\n }\\n}\\n// 将数据按照「总核定工时」降序排序 \\nvar indices = splitData[\\\"总核定工时\\\"]\\n .map(function (value, index) { return index; })\\n .sort(function (a, b) { return splitData[\\\"总核定工时\\\"][b] - splitData[\\\"总核定工时\\\"][a]; });\\n// 根据排序后的索引重组数据 \\nvar xData = indices.map(function (index) { return splitData[\\\"执行人\\\"][index]; });\\nvar totalReported = indices.map(function (index) { return splitData[\\\"总上报工时\\\"][index]; });\\nvar totalApproved = indices.map(function (index) { return splitData[\\\"总核定工时\\\"][index]; });\\nvar difference = totalReported.map(function (value, index) {\\n var diff = parseFloat((value - totalApproved[index]).toFixed(1));\\n return diff > 0 ? diff : null; // 当差值小于等于0时返回null \\n});\\n// 配置 Echarts 的 option \\noption = {\\n backgroundColor: \\\"rgba(0, 0, 0, 0)\\\",\\n title: {\\n text: \\\"工时排行榜(本月)\\\",\\n left: \\\"center\\\",\\n top: 24,\\n textStyle: {\\n fontSize: 16,\\n fontWeight: \\\"bold\\\",\\n },\\n },\\n grid: {\\n top: 72,\\n left: \\\"24px\\\",\\n right: \\\"24px\\\",\\n bottom: \\\"24px\\\",\\n containLabel: true,\\n },\\n tooltip: {\\n trigger: 'axis',\\n axisPointer: {\\n type: 'shadow',\\n shadowStyle: {\\n color: 'rgba(0,0,0,0.1)'\\n }\\n },\\n formatter: function (params) {\\n return params[0].name + '
' + params[0].seriesName + ':' + params[0].value + '小时' + '
' +\\n params[1].seriesName + ':' + params[1].value;\\n }\\n },\\n legend: {\\n show: false\\n },\\n xAxis: {\\n type: 'category',\\n data: xData,\\n axisLabel: {\\n fontSize: 16,\\n color: '#000000'\\n },\\n axisLine: {\\n show: true,\\n lineStyle: {\\n color: '#ccc'\\n }\\n },\\n axisTick: {\\n show: false\\n }\\n },\\n yAxis: {\\n type: 'value',\\n axisLine: {\\n lineStyle: {\\n color: \\\"#f5f6f6\\\",\\n },\\n },\\n splitLine: {\\n show: true,\\n lineStyle: {\\n type: 'dashed',\\n color: 'rgba(200,200,200,0.3)'\\n }\\n }\\n },\\n series: [\\n {\\n name: '已核定工时',\\n type: 'bar',\\n stack: '总量',\\n data: totalApproved.map((value, index) => ({\\n value: value,\\n itemStyle: {\\n borderRadius: difference[index] === null ? [8, 8, 0, 0] : [0, 0, 0, 0],\\n }\\n })),\\n barWidth: '80%',\\n barMinHeight: 20,\\n itemStyle: {\\n color: {\\n type: 'linear',\\n x: 0,\\n y: 0,\\n x2: 0,\\n y2: 1,\\n colorStops: [{\\n offset: 0,\\n color: 'rgba(99,181,246,0.9)'\\n }, {\\n offset: 1,\\n color: 'rgba(99,181,246,0.6)'\\n }]\\n },\\n shadowColor: 'rgba(0, 0, 0, 0.3)',\\n shadowBlur: 10,\\n opacity: 0.8\\n },\\n label: {\\n show: true,\\n position: 'inside',\\n formatter: '{c}小时',\\n color: '#fff',\\n fontSize: 14\\n },\\n animation: true,\\n animationDuration: 500,\\n animationEasing: 'cubicOut'\\n },\\n {\\n name: '未核定工时',\\n type: 'bar',\\n stack: '总量',\\n data: difference,\\n barWidth: '80%',\\n barMinHeight: 40,\\n itemStyle: {\\n color: 'rgba(200, 200, 200, 0.2)',\\n borderColor: 'rgba(200, 200, 200, 0.6)',\\n borderWidth: 1,\\n borderRadius: [8, 8, 0, 0],\\n shadowColor: 'rgba(0, 0, 0, 0.1)',\\n shadowBlur: 5\\n },\\n label: {\\n show: true,\\n position: 'inside',\\n formatter: function (params) {\\n if (params.value > 0) {\\n return params.value + '小时';\\n }\\n else {\\n return '';\\n }\\n },\\n color: '#666',\\n fontSize: 14\\n },\\n animation: true,\\n animationDuration: 500,\\n animationEasing: 'cubicOut'\\n }\\n ]\\n};\\n\\n return {\\n option,\\n datGUI,\\n };\\n }\\n \"}" } }, "12,1": { "CellType": { "$type": "EchartsCustomCellType.EchartsCustomCellTypeCellType, EchartsCustomCellType", "EChartTitle": "Echarts图表", "DataSourceBinding": "DataSources", "DataSources": [ { "Name": "recommands", "BindingTableOptions": { "$type": "ServerDesignerCommon.Model.BindingDataSourceModel, ServerDesignerCommon", "TableName": "项目反馈数量统计视图", "BindingInfos": [ { "GUID": "d15e9015-e7dd-43c5-8527-23c05ea3599e", "BindingInfo": { "TableName": "项目反馈数量统计视图", "ColumnName": "类型", "GUID": "66ee8be0-f0bb-43f2-90a6-c5390466a33a" }, "ColumnName": "类型" }, { "GUID": "91c7c1db-40ed-457b-9f7e-c2b410873c02", "BindingInfo": { "TableName": "项目反馈数量统计视图", "ColumnName": "项目ID", "GUID": "cfa41e1a-2896-4a3c-a568-2f7b989da45a" }, "ColumnName": "项目ID" }, { "GUID": "1da4d2ca-b7f5-4067-870c-50e8958c9c01", "BindingInfo": { "TableName": "项目反馈数量统计视图", "ColumnName": "任务ID", "GUID": "d7cb473d-7134-4378-bcc2-a32ee2a7fcce" }, "ColumnName": "任务ID" }, { "GUID": "7c1248ae-7392-43a9-b0b9-f8f2b7d1e20e", "BindingInfo": { "TableName": "项目反馈数量统计视图", "ColumnName": "项目", "GUID": "d1a1f815-afa1-43db-bdae-abb8545711eb" }, "ColumnName": "项目" }, { "GUID": "6d164818-8269-436d-a12f-097fe6f626f1", "BindingInfo": { "TableName": "项目反馈数量统计视图", "ColumnName": "任务", "GUID": "3967fb33-945b-465c-85d0-f4cf70adb1a1" }, "ColumnName": "任务" }, { "GUID": "91c6f208-7336-46f3-80d8-9582cde6f9b1", "BindingInfo": { "TableName": "项目反馈数量统计视图", "ColumnName": "数量", "GUID": "01c515ec-0904-4418-ab16-7d047db97497" }, "ColumnName": "数量" } ], "NullFormulaValueQueryPolicy": 1, "CustomColumns": [] } } ], "JSONDataSources": [], "ImageDataSource": [], "Config": "{\"option\":\"console.log(JSON.stringify(Context[\\\"recommands\\\"]));\\n\\n// 处理数据,生成节点和链接 \\nconst processData = (data) => {\\n // 生成颜色函数 - 使用HSL颜色空间,为每层生成不同的柔和颜色 \\n const generateColors = (count, depth) => {\\n const colors = [];\\n // 黄金角度 约137.5° \\n const goldenAngle = 137.5;\\n\\n // 根据深度调整饱和度和亮度 \\n const getSaturation = (depth) => {\\n switch (depth) {\\n case 0: return '60%'; // 第一层 \\n case 1: return '50%'; // 第二层 \\n case 2: return '40%'; // 第三层 \\n default: return '50%';\\n }\\n };\\n\\n const getLightness = (depth) => {\\n switch (depth) {\\n case 0: return '60%'; // 第一层 \\n case 1: return '60%'; // 第二层 \\n case 2: return '60%'; // 第三层 \\n default: return '60%';\\n }\\n };\\n\\n // 使用黄金角度来生成颜色 \\n const usedHues = new Set();\\n const minHueDistance = 30; // 最小色相差 \\n\\n for (let i = 0; i < count; i++) {\\n // 基础色相值使用黄金角度 \\n let baseHue = (i * goldenAngle) % 360;\\n\\n // 添加小范围随机偏移,但确保与现有颜色保持最小距离 \\n let hue = baseHue;\\n let attempts = 0;\\n const maxAttempts = 10;\\n\\n // 检查新生成的色相是否与已有的色相保持足够距离 \\n while (attempts < maxAttempts) {\\n let isValidHue = true;\\n\\n for (const existingHue of usedHues) {\\n const distance = Math.min(\\n Math.abs(hue - existingHue),\\n 360 - Math.abs(hue - existingHue)\\n );\\n\\n if (distance < minHueDistance) {\\n isValidHue = false;\\n break;\\n }\\n }\\n\\n if (isValidHue) {\\n break;\\n }\\n\\n // 如果当前色相不合适,添加一个小偏移再试 \\n hue = (baseHue + Math.random() * 30 - 15) % 360;\\n if (hue < 0) hue += 360;\\n attempts++;\\n }\\n\\n usedHues.add(hue);\\n colors.push(`hsl(${hue}, ${getSaturation(depth)}, ${getLightness(depth)})`);\\n }\\n\\n return colors;\\n };\\n\\n // 收集所有唯一的节点 \\n const typeSet = new Set(data.map(item => item.类型));\\n const projectSet = new Set();\\n const taskSet = new Set();\\n\\n // 创建项目和任务的映射关系 \\n const projectTypeMap = new Map();\\n const taskTypeMap = new Map();\\n\\n data.forEach(item => {\\n const projectKey = `[${item.项目ID}]${item.项目}`;\\n const taskKey = `[${item.任务ID}]${item.任务}`;\\n\\n projectSet.add(projectKey);\\n taskSet.add(taskKey);\\n\\n if (!projectTypeMap.has(projectKey)) {\\n projectTypeMap.set(projectKey, new Set());\\n }\\n if (!taskTypeMap.has(taskKey)) {\\n taskTypeMap.set(taskKey, new Set());\\n }\\n\\n projectTypeMap.get(projectKey).add(item.类型);\\n taskTypeMap.get(taskKey).add(item.类型);\\n });\\n\\n // 转换为数组 \\n const typeArray = Array.from(typeSet);\\n const projectArray = Array.from(projectSet);\\n const taskArray = Array.from(taskSet);\\n\\n // 为每层生成颜色 \\n const typeColors = {};\\n const projectColors = {};\\n const taskColors = {};\\n\\n const level0Colors = generateColors(typeArray.length, 0);\\n const level1Colors = generateColors(projectArray.length, 1);\\n const level2Colors = generateColors(taskArray.length, 2);\\n\\n typeArray.forEach((type, index) => {\\n typeColors[type] = level0Colors[index];\\n });\\n\\n projectArray.forEach((project, index) => {\\n projectColors[project] = level1Colors[index];\\n });\\n\\n taskArray.forEach((task, index) => {\\n taskColors[task] = level2Colors[index];\\n });\\n\\n // 计算节点值 \\n const nodeValues = {};\\n data.forEach(item => {\\n const projectKey = `[${item.项目ID}]${item.项目}`;\\n const taskKey = `[${item.任务ID}]${item.任务}`;\\n\\n nodeValues[item.类型] = (nodeValues[item.类型] || 0) + item.数量;\\n nodeValues[projectKey] = (nodeValues[projectKey] || 0) + item.数量;\\n nodeValues[taskKey] = (nodeValues[taskKey] || 0) + item.数量;\\n });\\n\\n // 生成节点 \\n const nodes = [\\n // 类型节点 \\n ...typeArray.map((type, index) => ({\\n name: type,\\n value: nodeValues[type],\\n itemStyle: {\\n color: typeColors[type],\\n borderColor: typeColors[type]\\n },\\n category: '类型',\\n depth: 0\\n })),\\n\\n // 项目节点 \\n ...projectArray.map(project => ({\\n name: project,\\n value: nodeValues[project],\\n itemStyle: {\\n color: projectColors[project]\\n },\\n category: '项目',\\n depth: 1\\n })),\\n\\n // 任务节点 \\n ...taskArray.map(task => ({\\n name: task,\\n value: nodeValues[task],\\n itemStyle: {\\n color: taskColors[task]\\n },\\n category: '任务',\\n depth: 2\\n }))\\n ];\\n\\n // 生成连接 \\n const links = [];\\n\\n // 处理类型到项目的连接 \\n data.forEach(item => {\\n const projectKey = `[${item.项目ID}]${item.项目}`;\\n const source = item.类型;\\n const target = projectKey;\\n\\n const existingLink = links.find(link =>\\n link.source === source && link.target === target\\n );\\n\\n if (existingLink) {\\n existingLink.value += item.数量;\\n } else {\\n links.push({\\n source: source,\\n target: target,\\n value: item.数量,\\n sourceType: item.类型,\\n lineStyle: {\\n color: typeColors[item.类型],\\n opacity: 0.2\\n }\\n });\\n }\\n });\\n\\n // 处理项目到任务的连接 \\n data.forEach(item => {\\n const projectKey = `[${item.项目ID}]${item.项目}`;\\n const taskKey = `[${item.任务ID}]${item.任务}`;\\n\\n const existingLink = links.find(link =>\\n link.source === projectKey && link.target === taskKey\\n );\\n\\n if (existingLink) {\\n existingLink.value += item.数量;\\n } else {\\n links.push({\\n source: projectKey,\\n target: taskKey,\\n value: item.数量,\\n sourceType: item.类型,\\n lineStyle: {\\n color: typeColors[item.类型],\\n opacity: 0.2\\n }\\n });\\n }\\n });\\n\\n return { nodes, links };\\n};\\n\\n// 修改提示文字获取函数 \\nconst gettooltip = (params) => {\\n if (params.dataType === 'node') {\\n return `${params.name}
数量: ${params.value}`;\\n }\\n\\n // 获取源节点和目标节点的深度 \\n const sourceNode = params.data.source;\\n const targetNode = params.data.target;\\n const isProjectToTask = sourceNode.includes(']') && targetNode.includes(']');\\n\\n if (isProjectToTask) {\\n // 项目到任务的连接 \\n return ` \\n ${params.data.sourceType}
\\n 项目:${params.data.source}
\\n 任务:${params.data.target}
数量: ${params.value}`;\\n } else {\\n return ` \\n ${params.data.sourceType}
\\n 项目:${params.data.target}
\\n 数量: ${params.value}`;\\n }\\n};\\n\\n// 处理数据 \\nconst { nodes, links } = processData(Context[\\\"recommands\\\"]);\\n\\n// Echarts配置 \\noption = {\\n backgroundColor: \\\"rgba(0, 0, 0, 0)\\\",\\n title: {\\n text: \\\"项目反馈桑基图\\\",\\n subtext: \\\"展示各个项目任务的不同反馈分类占比\\\",\\n left: \\\"center\\\",\\n top: 24,\\n textStyle: {\\n fontSize: 16,\\n fontWeight: \\\"bold\\\",\\n },\\n },\\n tooltip: {\\n trigger: 'item',\\n triggerOn: 'mousemove',\\n formatter: gettooltip\\n },\\n series: [{\\n type: \\\"sankey\\\",\\n animation: true,\\n animationDuration: 300,\\n animationEasingUpdate: 'quinticInOut',\\n left: '5%',\\n top: '12%',\\n right: '20%',\\n bottom: '12%',\\n nodeAlign: 'justify',\\n orient: 'horizontal',\\n emphasis: {\\n focus: 'adjacency'\\n },\\n data: nodes,\\n links: links,\\n nodeGap: 12,\\n nodeWidth: 24,\\n draggable: true,\\n levels: [{\\n depth: 0,\\n itemStyle: {\\n borderWidth: 2\\n },\\n lineStyle: {\\n curveness: 0.5,\\n opacity: 0.8\\n }\\n }, {\\n depth: 1,\\n itemStyle: {\\n borderWidth: 1\\n },\\n lineStyle: {\\n curveness: 0.5,\\n opacity: 0.8\\n }\\n }, {\\n depth: 2,\\n itemStyle: {\\n borderWidth: 1\\n },\\n lineStyle: {\\n curveness: 0.5,\\n opacity: 0.8\\n }\\n }],\\n label: {\\n position: 'right',\\n fontSize: 10,\\n lineHeight: 14,\\n color: '#000000',\\n distance: 10,\\n formatter: function (params) {\\n var name = params.name;\\n if (name.length > 15) {\\n name = name.substring(0, 15) + '...';\\n }\\n return `${name}(${params.value})`;\\n },\\n show: true,\\n align: 'left',\\n verticalAlign: 'middle'\\n }\\n }]\\n};\",\"graphTheme\":null,\"displayMode\":\"canvas\",\"jsCode\":\"\\n async ({Context,JSONContext,ImageContext,echarts,myChart,dat,Forguncy,d3,setInterval,setTimeout,ForguncyEchartsHelper,PublicResource})=>{\\n var datGUI=undefined;\\n var option={};\\n console.log(JSON.stringify(Context[\\\"recommands\\\"]));\\n// 处理数据,生成节点和链接 \\nconst processData = (data) => {\\n // 生成颜色函数 - 使用HSL颜色空间,为每层生成不同的柔和颜色 \\n const generateColors = (count, depth) => {\\n const colors = [];\\n // 黄金角度 约137.5° \\n const goldenAngle = 137.5;\\n // 根据深度调整饱和度和亮度 \\n const getSaturation = (depth) => {\\n switch (depth) {\\n case 0: return '60%'; // 第一层 \\n case 1: return '50%'; // 第二层 \\n case 2: return '40%'; // 第三层 \\n default: return '50%';\\n }\\n };\\n const getLightness = (depth) => {\\n switch (depth) {\\n case 0: return '60%'; // 第一层 \\n case 1: return '60%'; // 第二层 \\n case 2: return '60%'; // 第三层 \\n default: return '60%';\\n }\\n };\\n // 使用黄金角度来生成颜色 \\n const usedHues = new Set();\\n const minHueDistance = 30; // 最小色相差 \\n for (let i = 0; i < count; i++) {\\n // 基础色相值使用黄金角度 \\n let baseHue = (i * goldenAngle) % 360;\\n // 添加小范围随机偏移,但确保与现有颜色保持最小距离 \\n let hue = baseHue;\\n let attempts = 0;\\n const maxAttempts = 10;\\n // 检查新生成的色相是否与已有的色相保持足够距离 \\n while (attempts < maxAttempts) {\\n let isValidHue = true;\\n for (const existingHue of usedHues) {\\n const distance = Math.min(Math.abs(hue - existingHue), 360 - Math.abs(hue - existingHue));\\n if (distance < minHueDistance) {\\n isValidHue = false;\\n break;\\n }\\n }\\n if (isValidHue) {\\n break;\\n }\\n // 如果当前色相不合适,添加一个小偏移再试 \\n hue = (baseHue + Math.random() * 30 - 15) % 360;\\n if (hue < 0)\\n hue += 360;\\n attempts++;\\n }\\n usedHues.add(hue);\\n colors.push(`hsl(${hue}, ${getSaturation(depth)}, ${getLightness(depth)})`);\\n }\\n return colors;\\n };\\n // 收集所有唯一的节点 \\n const typeSet = new Set(data.map(item => item.类型));\\n const projectSet = new Set();\\n const taskSet = new Set();\\n // 创建项目和任务的映射关系 \\n const projectTypeMap = new Map();\\n const taskTypeMap = new Map();\\n data.forEach(item => {\\n const projectKey = `[${item.项目ID}]${item.项目}`;\\n const taskKey = `[${item.任务ID}]${item.任务}`;\\n projectSet.add(projectKey);\\n taskSet.add(taskKey);\\n if (!projectTypeMap.has(projectKey)) {\\n projectTypeMap.set(projectKey, new Set());\\n }\\n if (!taskTypeMap.has(taskKey)) {\\n taskTypeMap.set(taskKey, new Set());\\n }\\n projectTypeMap.get(projectKey).add(item.类型);\\n taskTypeMap.get(taskKey).add(item.类型);\\n });\\n // 转换为数组 \\n const typeArray = Array.from(typeSet);\\n const projectArray = Array.from(projectSet);\\n const taskArray = Array.from(taskSet);\\n // 为每层生成颜色 \\n const typeColors = {};\\n const projectColors = {};\\n const taskColors = {};\\n const level0Colors = generateColors(typeArray.length, 0);\\n const level1Colors = generateColors(projectArray.length, 1);\\n const level2Colors = generateColors(taskArray.length, 2);\\n typeArray.forEach((type, index) => {\\n typeColors[type] = level0Colors[index];\\n });\\n projectArray.forEach((project, index) => {\\n projectColors[project] = level1Colors[index];\\n });\\n taskArray.forEach((task, index) => {\\n taskColors[task] = level2Colors[index];\\n });\\n // 计算节点值 \\n const nodeValues = {};\\n data.forEach(item => {\\n const projectKey = `[${item.项目ID}]${item.项目}`;\\n const taskKey = `[${item.任务ID}]${item.任务}`;\\n nodeValues[item.类型] = (nodeValues[item.类型] || 0) + item.数量;\\n nodeValues[projectKey] = (nodeValues[projectKey] || 0) + item.数量;\\n nodeValues[taskKey] = (nodeValues[taskKey] || 0) + item.数量;\\n });\\n // 生成节点 \\n const nodes = [\\n // 类型节点 \\n ...typeArray.map((type, index) => ({\\n name: type,\\n value: nodeValues[type],\\n itemStyle: {\\n color: typeColors[type],\\n borderColor: typeColors[type]\\n },\\n category: '类型',\\n depth: 0\\n })),\\n // 项目节点 \\n ...projectArray.map(project => ({\\n name: project,\\n value: nodeValues[project],\\n itemStyle: {\\n color: projectColors[project]\\n },\\n category: '项目',\\n depth: 1\\n })),\\n // 任务节点 \\n ...taskArray.map(task => ({\\n name: task,\\n value: nodeValues[task],\\n itemStyle: {\\n color: taskColors[task]\\n },\\n category: '任务',\\n depth: 2\\n }))\\n ];\\n // 生成连接 \\n const links = [];\\n // 处理类型到项目的连接 \\n data.forEach(item => {\\n const projectKey = `[${item.项目ID}]${item.项目}`;\\n const source = item.类型;\\n const target = projectKey;\\n const existingLink = links.find(link => link.source === source && link.target === target);\\n if (existingLink) {\\n existingLink.value += item.数量;\\n }\\n else {\\n links.push({\\n source: source,\\n target: target,\\n value: item.数量,\\n sourceType: item.类型,\\n lineStyle: {\\n color: typeColors[item.类型],\\n opacity: 0.2\\n }\\n });\\n }\\n });\\n // 处理项目到任务的连接 \\n data.forEach(item => {\\n const projectKey = `[${item.项目ID}]${item.项目}`;\\n const taskKey = `[${item.任务ID}]${item.任务}`;\\n const existingLink = links.find(link => link.source === projectKey && link.target === taskKey);\\n if (existingLink) {\\n existingLink.value += item.数量;\\n }\\n else {\\n links.push({\\n source: projectKey,\\n target: taskKey,\\n value: item.数量,\\n sourceType: item.类型,\\n lineStyle: {\\n color: typeColors[item.类型],\\n opacity: 0.2\\n }\\n });\\n }\\n });\\n return { nodes, links };\\n};\\n// 修改提示文字获取函数 \\nconst gettooltip = (params) => {\\n if (params.dataType === 'node') {\\n return `${params.name}
数量: ${params.value}`;\\n }\\n // 获取源节点和目标节点的深度 \\n const sourceNode = params.data.source;\\n const targetNode = params.data.target;\\n const isProjectToTask = sourceNode.includes(']') && targetNode.includes(']');\\n if (isProjectToTask) {\\n // 项目到任务的连接 \\n return ` \\n ${params.data.sourceType}
\\n 项目:${params.data.source}
\\n 任务:${params.data.target}
数量: ${params.value}`;\\n }\\n else {\\n return ` \\n ${params.data.sourceType}
\\n 项目:${params.data.target}
\\n 数量: ${params.value}`;\\n }\\n};\\n// 处理数据 \\nconst { nodes, links } = processData(Context[\\\"recommands\\\"]);\\n// Echarts配置 \\noption = {\\n backgroundColor: \\\"rgba(0, 0, 0, 0)\\\",\\n title: {\\n text: \\\"项目反馈桑基图\\\",\\n subtext: \\\"展示各个项目任务的不同反馈分类占比\\\",\\n left: \\\"center\\\",\\n top: 24,\\n textStyle: {\\n fontSize: 16,\\n fontWeight: \\\"bold\\\",\\n },\\n },\\n tooltip: {\\n trigger: 'item',\\n triggerOn: 'mousemove',\\n formatter: gettooltip\\n },\\n series: [{\\n type: \\\"sankey\\\",\\n animation: true,\\n animationDuration: 300,\\n animationEasingUpdate: 'quinticInOut',\\n left: '5%',\\n top: '12%',\\n right: '20%',\\n bottom: '12%',\\n nodeAlign: 'justify',\\n orient: 'horizontal',\\n emphasis: {\\n focus: 'adjacency'\\n },\\n data: nodes,\\n links: links,\\n nodeGap: 12,\\n nodeWidth: 24,\\n draggable: true,\\n levels: [{\\n depth: 0,\\n itemStyle: {\\n borderWidth: 2\\n },\\n lineStyle: {\\n curveness: 0.5,\\n opacity: 0.8\\n }\\n }, {\\n depth: 1,\\n itemStyle: {\\n borderWidth: 1\\n },\\n lineStyle: {\\n curveness: 0.5,\\n opacity: 0.8\\n }\\n }, {\\n depth: 2,\\n itemStyle: {\\n borderWidth: 1\\n },\\n lineStyle: {\\n curveness: 0.5,\\n opacity: 0.8\\n }\\n }],\\n label: {\\n position: 'right',\\n fontSize: 10,\\n lineHeight: 14,\\n color: '#000000',\\n distance: 10,\\n formatter: function (params) {\\n var name = params.name;\\n if (name.length > 15) {\\n name = name.substring(0, 15) + '...';\\n }\\n return `${name}(${params.value})`;\\n },\\n show: true,\\n align: 'left',\\n verticalAlign: 'middle'\\n }\\n }]\\n};\\n\\n return {\\n option,\\n datGUI,\\n };\\n }\\n \"}" } }, "16,1": { "CellType": { "$type": "EchartsCustomCellType.EchartsCustomCellTypeCellType, EchartsCustomCellType", "EChartTitle": "Echarts图表", "DataSourceBinding": "JSONDataSources", "DataSources": [ { "Name": "data", "BindingTableOptions": { "$type": "ServerDesignerCommon.Model.BindingDataSourceModel, ServerDesignerCommon", "TableName": "任务成员表", "BindingInfos": [ { "GUID": "047db0a4-c911-484d-a4ce-38fbe3125e91", "BindingInfo": { "TableName": "任务成员表", "ColumnName": "任务成员", "GUID": "19cf3e51-5b5d-450b-8f8d-e2e49f6766b0", "AttachType": { "$type": "ForguncyDataAccess.UserColumnAttachObj, ForguncyDataAccess", "UserColumnAttachType": 1 } }, "ColumnName": "person" }, { "GUID": "d607bf49-3a5a-4e13-b50a-28743c06ce18", "BindingInfo": { "TableName": "任务成员表", "ColumnName": "任务ID", "GUID": "17458116-97bb-4b93-8e6b-56534283bf97", "RelationBinding": { "RelatedTable": "任务平行视图", "RelatedColumn": "ID", "DisplayColumn": "任务名称" } }, "ColumnName": "project" }, { "GUID": "07ebd172-7f0d-4cb2-823f-d7cc9f147da7", "BindingInfo": { "TableName": "任务成员表", "ColumnName": "数量", "GUID": "3c7522ca-0921-4741-8eda-7cc69f282d03" }, "ColumnName": "count" } ], "CustomColumns": [] } } ], "JSONDataSources": [ { "Name": "data", "JSONDemo": "[\r\n {\r\n \"project\": null,\r\n \"person\": \"黄海\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"报价模块\",\r\n \"person\": \"黄海\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"出库管理\",\r\n \"person\": \"黄海\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"出库扫码\",\r\n \"person\": \"黄海\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"第二版手册\",\r\n \"person\": \"黄海\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"第三版手册\",\r\n \"person\": \"黄海\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"第一版手册\",\r\n \"person\": \"黄海\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"方案设计\",\r\n \"person\": \"黄海\",\r\n \"count\": 2\r\n },\r\n {\r\n \"project\": \"方案设计V1\",\r\n \"person\": \"黄海\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"批量移交\",\r\n \"person\": \"黄海\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"入库管理\",\r\n \"person\": \"黄海\",\r\n \"count\": 4\r\n },\r\n {\r\n \"project\": \"新方案设计\",\r\n \"person\": \"黄海\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"功能测试V1\",\r\n \"person\": \"李春花\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"任务版本1\",\r\n \"person\": \"李春花\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"数据库设计\",\r\n \"person\": \"李春花\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"数据清洗\",\r\n \"person\": \"李春花\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": null,\r\n \"person\": \"林希\",\r\n \"count\": 2\r\n },\r\n {\r\n \"project\": \"报价模块\",\r\n \"person\": \"林希\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"测试01\",\r\n \"person\": \"林希\",\r\n \"count\": 2\r\n },\r\n {\r\n \"project\": \"测试02\",\r\n \"person\": \"林希\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"测试项目007\",\r\n \"person\": \"林希\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"出库管理\",\r\n \"person\": \"林希\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"出库扫码\",\r\n \"person\": \"林希\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"第一版手册\",\r\n \"person\": \"林希\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"方案设计\",\r\n \"person\": \"林希\",\r\n \"count\": 2\r\n },\r\n {\r\n \"project\": \"功能测试V1\",\r\n \"person\": \"林希\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"功能测试子任务\",\r\n \"person\": \"林希\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"客户沟通\",\r\n \"person\": \"林希\",\r\n \"count\": 2\r\n },\r\n {\r\n \"project\": \"模板替换插件\",\r\n \"person\": \"林希\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"前期调研需求\",\r\n \"person\": \"林希\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"任务版本1\",\r\n \"person\": \"林希\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"入库管理\",\r\n \"person\": \"林希\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"数据库设计\",\r\n \"person\": \"林希\",\r\n \"count\": 3\r\n },\r\n {\r\n \"project\": \"数据清洗\",\r\n \"person\": \"林希\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"文字排版\",\r\n \"person\": \"林希\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"文字校验\",\r\n \"person\": \"林希\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"系统设计\",\r\n \"person\": \"林希\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"校对\",\r\n \"person\": \"林希\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"需求单管理\",\r\n \"person\": \"林希\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"业务管理\",\r\n \"person\": \"林希\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"制作方案书\",\r\n \"person\": \"林希\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": null,\r\n \"person\": \"刘艳伟\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": null,\r\n \"person\": \"童玉飞\",\r\n \"count\": 2\r\n },\r\n {\r\n \"project\": \"测试01\",\r\n \"person\": \"童玉飞\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"出库管理\",\r\n \"person\": \"童玉飞\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"出库扫码\",\r\n \"person\": \"童玉飞\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"方案设计\",\r\n \"person\": \"童玉飞\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"功能测试\",\r\n \"person\": \"童玉飞\",\r\n \"count\": 2\r\n },\r\n {\r\n \"project\": \"功能测试V1\",\r\n \"person\": \"童玉飞\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"客户沟通\",\r\n \"person\": \"童玉飞\",\r\n \"count\": 4\r\n },\r\n {\r\n \"project\": \"前期调研需求\",\r\n \"person\": \"童玉飞\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"任务版本1\",\r\n \"person\": \"童玉飞\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"入库管理\",\r\n \"person\": \"童玉飞\",\r\n \"count\": 2\r\n },\r\n {\r\n \"project\": \"数据库设计\",\r\n \"person\": \"童玉飞\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"数据清洗\",\r\n \"person\": \"童玉飞\",\r\n \"count\": 3\r\n },\r\n {\r\n \"project\": \"系统设计\",\r\n \"person\": \"童玉飞\",\r\n \"count\": 3\r\n },\r\n {\r\n \"project\": \"业务管理\",\r\n \"person\": \"童玉飞\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"制作方案书\",\r\n \"person\": \"童玉飞\",\r\n \"count\": 2\r\n },\r\n {\r\n \"project\": null,\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"111\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"12312\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"12321333\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"3333\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"版本1\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"版本1设计\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"报价模块\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"测试01\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"测试02\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"测试项目007\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"出库单\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"第二版手册\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"第三版手册\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"发件箱\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"方案设计\",\r\n \"person\": \"夏超\",\r\n \"count\": 4\r\n },\r\n {\r\n \"project\": \"方案设计V1\",\r\n \"person\": \"夏超\",\r\n \"count\": 2\r\n },\r\n {\r\n \"project\": \"功能测试\",\r\n \"person\": \"夏超\",\r\n \"count\": 3\r\n },\r\n {\r\n \"project\": \"功能测试V1\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"功能测试子任务\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"解析报价\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"客户沟通\",\r\n \"person\": \"夏超\",\r\n \"count\": 2\r\n },\r\n {\r\n \"project\": \"前期调研需求\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"任务版本1\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"入库管理\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"收货单\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"收件箱\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"数据清洗\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"文字校验\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"系统设计\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"校对\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"新方案设计\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"业务管理\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"邮件模块\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n },\r\n {\r\n \"project\": \"制作方案书\",\r\n \"person\": \"夏超\",\r\n \"count\": 1\r\n }\r\n]" } ], "ImageDataSource": [], "Config": "{\"option\":\"var data = JSONContext.data; \\nconsole.log(data); \\nconst persons = [...new Set(data.map(item => item.person || \\\"未知成员\\\"))]; \\nconst projects = [...new Set(data.map(item => item.project || \\\"未知项目\\\"))]; \\n// 定义人员颜色 \\nconst personColors = ['#ff6666', '#66ccff', '#ffcc66', '#8bc34a', '#cc66ff', '#86665a', '#9742ca', '#ff6738']; \\n\\n// 计算每个项目关联的人员数量 \\nconst projectPersonCount = projects.reduce((acc, project) => { \\n acc[project] = data.filter(item => item.project === project).length; \\n return acc; \\n}, {}); \\n\\n// 处理数据,创建节点和边 \\nconst nodes = [ \\n // 添加人员节点 \\n ...persons.map((person, index) => ({ \\n name: person, \\n value: person, \\n category: 0, \\n symbolSize: 80, \\n itemStyle: { \\n color: personColors[index % personColors.length], \\n }, \\n label: { \\n position: 'inside', \\n fontSize: 16, \\n fontWeight: 'bold', \\n color: '#fff', \\n }, \\n })), \\n // 添加项目节点 \\n ...projects.map(project => ({ \\n name: project, \\n value: project, \\n category: 1, \\n // 根据关联人数动态设置大小,基础大小为60 \\n symbolSize: 60 + (projectPersonCount[project] * 15), \\n itemStyle: { \\n color: '#4b4b4b7a' \\n }, \\n label: { \\n position: 'inside', \\n fontSize: 12, \\n color: '#fff', \\n width: 70, \\n overflow: 'break', \\n lineHeight: 18, \\n // 添加关联人数显示 \\n formatter: function(params) { \\n return `${params.name}\\\\n(${projectPersonCount[params.name]}人)`; \\n } \\n }, \\n })) \\n]; \\n\\nconsole.log(nodes); \\n\\nconst links = data.map(rel => ({ \\n source: rel.person, \\n target: rel.project, \\n value: rel.project, \\n})); \\n\\noption = { \\n backgroundColor: \\\"rgba(0, 0, 0, 0)\\\", \\n title: { \\n text: '项目关系图', \\n subtext: '展示人员与项目之间的关系', \\n left: \\\"center\\\", \\n top: 24, \\n textStyle: { \\n fontSize: 16, \\n fontWeight: \\\"bold\\\", \\n }, \\n }, \\n tooltip: {}, \\n animationDuration: 1500, \\n animationEasingUpdate: 'quinticInOut', \\n series: [{ \\n name: '项目关系图', \\n type: 'graph', \\n layout: 'force', \\n data: nodes, \\n links: links, \\n top: 100, \\n categories: [ \\n { name: '人员' }, \\n { name: '项目' } \\n ], \\n roam: true, \\n label: { \\n show: true, \\n position: 'right', \\n formatter: '{b}' \\n }, \\n force: { \\n repulsion: 5000, \\n gravity: 1, \\n friction: 0.3, \\n layoutAnimation: false, \\n }, \\n draggable: false, \\n lineStyle: { \\n color: 'source', \\n curveness: 0.3, \\n width: 1 \\n }, \\n edgeLabel: { \\n show: false, \\n position: 'middle', \\n formatter: function (params) { \\n return params.data.value; \\n }, \\n fontSize: 12 \\n }, \\n emphasis: { \\n focus: 'adjacency', \\n lineStyle: { \\n width: 10 \\n } \\n } \\n }] \\n};\",\"graphTheme\":null,\"displayMode\":\"canvas\",\"jsCode\":\"\\n async ({Context,JSONContext,ImageContext,echarts,myChart,dat,Forguncy,d3,setInterval,setTimeout,ForguncyEchartsHelper,ApplicationResource})=>{\\n var datGUI=undefined;\\n var option={};\\n var data = JSONContext.data;\\nconsole.log(data);\\nconst persons = [...new Set(data.map(item => item.person || \\\"未知成员\\\"))];\\nconst projects = [...new Set(data.map(item => item.project || \\\"未知项目\\\"))];\\n// 定义人员颜色 \\nconst personColors = ['#ff6666', '#66ccff', '#ffcc66', '#8bc34a', '#cc66ff', '#86665a', '#9742ca', '#ff6738'];\\n// 计算每个项目关联的人员数量 \\nconst projectPersonCount = projects.reduce((acc, project) => {\\n acc[project] = data.filter(item => item.project === project).length;\\n return acc;\\n}, {});\\n// 处理数据,创建节点和边 \\nconst nodes = [\\n // 添加人员节点 \\n ...persons.map((person, index) => ({\\n name: person,\\n value: person,\\n category: 0,\\n symbolSize: 80,\\n itemStyle: {\\n color: personColors[index % personColors.length],\\n },\\n label: {\\n position: 'inside',\\n fontSize: 16,\\n fontWeight: 'bold',\\n color: '#fff',\\n },\\n })),\\n // 添加项目节点 \\n ...projects.map(project => ({\\n name: project,\\n value: project,\\n category: 1,\\n // 根据关联人数动态设置大小,基础大小为60 \\n symbolSize: 60 + (projectPersonCount[project] * 15),\\n itemStyle: {\\n color: '#4b4b4b7a'\\n },\\n label: {\\n position: 'inside',\\n fontSize: 12,\\n color: '#fff',\\n width: 70,\\n overflow: 'break',\\n lineHeight: 18,\\n // 添加关联人数显示 \\n formatter: function (params) {\\n return `${params.name}\\\\n(${projectPersonCount[params.name]}人)`;\\n }\\n },\\n }))\\n];\\nconsole.log(nodes);\\nconst links = data.map(rel => ({\\n source: rel.person,\\n target: rel.project,\\n value: rel.project,\\n}));\\noption = {\\n backgroundColor: \\\"rgba(0, 0, 0, 0)\\\",\\n title: {\\n text: '项目关系图',\\n subtext: '展示人员与项目之间的关系',\\n left: \\\"center\\\",\\n top: 24,\\n textStyle: {\\n fontSize: 16,\\n fontWeight: \\\"bold\\\",\\n },\\n },\\n tooltip: {},\\n animationDuration: 1500,\\n animationEasingUpdate: 'quinticInOut',\\n series: [{\\n name: '项目关系图',\\n type: 'graph',\\n layout: 'force',\\n data: nodes,\\n links: links,\\n top: 100,\\n categories: [\\n { name: '人员' },\\n { name: '项目' }\\n ],\\n roam: true,\\n label: {\\n show: true,\\n position: 'right',\\n formatter: '{b}'\\n },\\n force: {\\n repulsion: 5000,\\n gravity: 1,\\n friction: 0.3,\\n layoutAnimation: false,\\n },\\n draggable: false,\\n lineStyle: {\\n color: 'source',\\n curveness: 0.3,\\n width: 1\\n },\\n edgeLabel: {\\n show: false,\\n position: 'middle',\\n formatter: function (params) {\\n return params.data.value;\\n },\\n fontSize: 12\\n },\\n emphasis: {\\n focus: 'adjacency',\\n lineStyle: {\\n width: 10\\n }\\n }\\n }]\\n};\\n\\n return {\\n option,\\n datGUI,\\n };\\n }\\n \"}" } } }, "StyleDatas": { "Styles": [ { "FontSize": 37.33333333333333, "Foreground": 0 }, { "HorizontalAlignment": 1 }, { "FontFamily": 2, "FontSize": 37.33333333333333, "Foreground": 0, "HorizontalAlignment": 3 }, { "FontFamily": 2, "HorizontalAlignment": 3 } ], "Types": { "Strs": [ "Background 1 -15", "Left", "Body", "Center" ] }, "CellStyles": { "1,37": 0, "1,39": 0, "2,39": 0, "3,39": 0, "6,38": 1, "8,38": 2, "8,39": 2, "9,39": 2, "10,1": 0, "10,39": 2, "11,39": 2, "12,1": 0, "15,1": 0, "15,2": 0, "15,3": 0, "15,4": 0, "15,5": 0, "15,6": 0, "15,7": 0, "15,8": 0, "15,9": 0, "15,10": 0, "15,11": 0, "15,12": 0, "15,13": 0, "15,14": 0, "15,15": 0, "15,16": 0, "15,17": 0, "15,18": 0, "15,19": 0, "15,20": 0, "15,21": 0, "15,22": 0, "15,23": 0, "15,24": 0, "15,25": 0, "15,26": 0, "15,27": 0, "15,28": 0, "15,29": 0, "15,30": 0, "15,31": 0, "15,32": 0, "15,33": 0, "15,34": 0, "15,35": 0, "15,39": 2, "16,1": 3 }, "SheetStyle": { "FontFamily": 2, "HorizontalAlignment": 3 } }, "Spans": [ "1,37,3,3", "1,1,1,35", "3,1,1,35", "5,1,4,35", "10,1,1,35", "8,38,3,1", "12,1,3,39", "16,1,1,39" ], "PageInfo": { "$type": "Forguncy.Model.Pages.NormalPage, ServerDesignerCommon", "MasterPageName": "FGC_母版页", "PageOverflowMode": 2, "PageLoadedCommandList": [ { "$type": "Forguncy.Model.Commands.SetParameterCommand, ServerDesignerCommon", "ParameterName": "data", "TableValue": { "TableName": "任务成员表", "BindingInfos": [ { "GUID": "0cd65cbe-68f7-471b-8ee4-23442b60cee8", "BindingInfo": { "TableName": "任务成员表", "ColumnName": "项目ID", "GUID": "c43bf190-6c08-4ec3-a6f2-d45df60c270f", "RelationBinding": { "RelatedTable": "项目表", "RelatedColumn": "ID", "DisplayColumn": "项目名称" } }, "ColumnName": "project" }, { "GUID": "eb28b5f2-6937-4158-88e0-dc064b23f5b7", "BindingInfo": { "TableName": "任务成员表", "ColumnName": "任务成员", "GUID": "b6110697-d6f5-4ad0-873b-4071e7f3158d", "AttachType": { "$type": "ForguncyDataAccess.UserColumnAttachObj, ForguncyDataAccess", "UserColumnAttachType": 1 } }, "ColumnName": "person" }, { "GUID": "5f1741a5-8ce7-4e69-b7cd-04f34fce6a3e", "BindingInfo": { "TableName": "任务成员表", "ColumnName": "数量", "GUID": "53850c92-5896-4619-91ed-b4207c7b7eb5" }, "ColumnName": "count" } ], "SqlCondition": { "$type": "ForguncyDataAccess.GeneralCESqlCondition, ForguncyDataAccess", "CompareType": 1, "ColumnBindingInfo": { "TableName": "任务成员表", "ColumnName": "项目ID", "GUID": "f31e6443-fd02-4933-93bf-2e38b2565c11", "RelationBinding": { "RelatedTable": "项目表", "RelatedColumn": "ID", "DisplayColumn": "项目名称" } }, "Value": "%Null%" } }, "ID": "7a61e8b373a84e90bd923a4de584157b", "BreakpointIdentity": "8cda8149-c93f-45bd-b943-00ddae7bc63a" }, { "$type": "JsonUtilityCommand.JsonSerializeCommand, JsonUtilityCommand", "SourceObject": { "$type": "Forguncy.Model.FormulaReferObject, ServerDesignerCommon", "SerializeProperty": "=工作台首页!data" }, "ToParameter": "json", "BreakpointIdentity": "2decae29-2029-4d8a-839b-6938b82cc3b4" }, { "$type": "Forguncy.Model.OperateCellTypeCommand, ServerDesignerCommon", "TargetPageElement": { "$type": "Forguncy.Model.FormulaReferObject, ServerDesignerCommon", "SerializeProperty": "=工作台首页!B17" }, "TargetType": "EchartsCustomCellType.EchartsCustomCellTypeCellType, EchartsCustomCellType, Version=10.0.103.0, Culture=neutral, PublicKeyToken=null", "MethodName": "SetDataSource", "ParameterValues": { "dataSourceName": "data", "JSONString": { "$type": "Forguncy.Model.FormulaReferObject, ServerDesignerCommon", "SerializeProperty": "=工作台首页!json" } }, "BreakpointIdentity": "0d3d7675-1c0a-43b9-82b3-5d2cd89e56b6" }, { "$type": "Notiflix_Forguncy.Loading_Command, Notiflix_Forguncy", "FunctionName": "remove", "Title": "加载中", "BreakpointIdentity": "771582d5-5384-4270-9f7b-d22c2fef94d2" } ], "PermissionData": { "$type": "Forguncy.RbacPermission.Core.Impl.Page.PagePermissionData, Forguncy.RbacPermission.Core", "permissionResource": { "$type": "Forguncy.RbacPermission.Core.Impl.Page.PagePermissionResource, Forguncy.RbacPermission.Core" }, "permissionBindings": [ { "$type": "Forguncy.RbacPermission.Core.Impl.Page.PagePermissionBinding, Forguncy.RbacPermission.Core", "roleNames": [ "FGC_LoginUser" ] } ] }, "RowBreakLines": [], "RepeatRangeSettings": [] }, "PrintInfo": { "PaperSize": {}, "Margin": {} }, "BackgroundPictures": [ { "FitToBrowserWidth": true, "FitToBrowserHeight": true, "Name": "f9665113-5057-40ef-8571-aa152a7302ce.png", "DisplayName": "背景图1", "StyleInfo": { "Fill": "Background 2 0" }, "IsAutomaticFill": false, "Size": "1521,3059" }, { "Name": "0f5baa2c-2dec-44c7-8a3f-45868371fe7b.png", "DisplayName": "背景图2", "StyleInfo": { "CornerRadius": 10.0, "Fill": "Background 1 0" }, "IsAutomaticFill": false, "Location": "24,234", "Size": "1120,300" }, { "Name": "7e86b317-11df-41f3-a863-d077d49a760b.png", "DisplayName": "背景图3", "StyleInfo": { "CornerRadius": 10.0, "Fill": "Background 1 0" }, "IsAutomaticFill": false, "Location": "1154,15", "Size": "343,209" }, { "Name": "75cbd09e-882c-427a-a52b-ba015444352e.png", "DisplayName": "背景图4", "StyleInfo": { "CornerRadius": 10.0, "Fill": "Background 1 0" }, "IsAutomaticFill": false, "Location": "1154,234", "Size": "343,693" }, { "Name": "9585c733-c922-4ba2-8923-e5c50a4f429c.png", "DisplayName": "背景图5", "StyleInfo": { "CornerRadius": 10.0, "Fill": "Background 1 0" }, "IsAutomaticFill": false, "Location": "24,544", "Size": "1120,383" }, { "Name": "cc656816-79e5-4f40-957c-c72753c75e5d.png", "DisplayName": "背景图6", "StyleInfo": { "CornerRadius": 10.0, "Fill": "Background 1 0" }, "IsAutomaticFill": false, "Location": "24,937", "Size": "1473,1065" }, { "Name": "fb94cc28-18cf-4cd3-bae7-8f9a8156ed34.png", "DisplayName": "背景图7", "StyleInfo": { "CornerRadius": 10.0, "Fill": "Background 1 0" }, "IsAutomaticFill": false, "Location": "24,2012", "Size": "1473,1000" } ], "CustomNames": [ { "Name": "关键信息", "Formula": "工作台首页!$B$2" } ] }///Q+F4CovOLPPjzGls3uV3+izmqiaHEfMAmXySQ1lvuK2JdQCrfu+b4uCqMZEK9Gi4ox+FXkO3gs3DnZlHKfw3TdBduRKEsLEeC2GhD+6AjlMnunsMA3Bm1VBR9h5gAYjPzXufpjYT4fg1i9NREa4X63uxuuV6h4eIX7nofeTeLphPn8PpqjG0+YZleDiYbsg5dM+bNf6fMY9Qhsno4DQQy6OPEZNiLGidNNPLJsuRtdOJLeX1CR3yyUViBp769r3uZDy1TjKZR6HNqrfld7j3RQ2nwXItvE+vGN0VTLrdd2aLuJiMLEL8ARiUAxUGV9Yk3Q4yBCckqQnW9FzGoFtUhuFhYHlJDVymR+poiEyaAVuVj7zjRuXI5eYa3JABzHISKDxb4l5S8+YKdjWKfVfQx4kPl5XiN2BK07zD9Y7Ox+kkgHQhA883hkMs00dST0driqcUPG5esDwRoCIxOOpS/S6eL9RDQHp73ckIfB99wt4ocSwhyerQcKY85vTvxohBjbDJrNj75XdkYWL6bqKshJLqW2B8WQ/JLJCMRwu1gPlW46iipOnOm9p8ucR9rAh2AO8xDfLA+sBq1cAM+Eyc8RVngfYhg6dChSyztqBaKsV1lw/UJjjOVNDsWjRS0Ljv6Tz0YYlbn9rij8PJNFQXv38Y1xAvpXIrGYp7QEOCQZareKnrndJvTA0sGPN2vMffojJ5672lqzE7oLPOxtOPnRBgKVqZmwnN7FV6msCYdJwWwxmKMKFodRyrk3VLNWzywAXfNCqpRZmVLHxDW9vIAIAe7q/GE2x5QmDVa8tZqBJKVMg93cATj8ihZQIE+dzhSF+wFD+XulMbew3MRfD7Zzll1cI+JjGc4n5zar//Lf3diZAdliY7aKXIV49c0zfeCq17ziqFw5TZGjMLKJ+Og==|920