Files
clue/Pages/工作台/工作台首页.json

1077 lines
97 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"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
}
},
"1,37": {
"CellType": {
"$type": "嵌入自定义HTML页面.嵌入自定义HTML页面, 嵌入自定义HTML页面",
"HtmlName": "https://i.tianqi.com?c=code&id=21&icon=1&py=shanghai&site=12",
"IsUrl": true
}
},
"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 + '<br/>' + params[0].seriesName + '' + params[0].value + '小时' + '<br/>' +\\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 + '<br/>' + params[0].seriesName + '' + params[0].value + '小时' + '<br/>' +\\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}<br/>数量: ${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 <b>${params.data.sourceType}</b><br/> \\n 项目:${params.data.source}<br/> \\n 任务:${params.data.target}<br/>数量: ${params.value}`;\\n } else {\\n return ` \\n <b>${params.data.sourceType}</b><br/> \\n 项目:${params.data.target}<br/> \\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}<br/>数量: ${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 <b>${params.data.sourceType}</b><br/> \\n 项目:${params.data.source}<br/> \\n 任务:${params.data.target}<br/>数量: ${params.value}`;\\n }\\n else {\\n return ` \\n <b>${params.data.sourceType}</b><br/> \\n 项目:${params.data.target}<br/> \\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,
"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,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",
"1,37,3,3"
],
"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"
}
]
}//YYyfdw2vXZ6CtkWGa/mqynvY+FzuocP1VmZULAo3Amsn4gBPwns8Q9Bwti78mlCokUuztIKLGbjS4oPK8XucFDX6Q+PjXm32OWMQeDmh47RTmst5Lpdh5CuDClWjiG2jlJLODVhUDaOJkA/haBQlCqbMuAbI+kv/48M4WsDnXIwu3FLUiIkGlaAZdNOYEDraHREhnw84XQ9mX7YxpsxFtKUb5DkJd18xo7UJYCadzbJAmnxy8esOKVg86YKRQEOyUdgyoq5sN7bRa1xqS42yAxcCIkliAzphj3Iy4D1uZF8IpomiyBr/f5y2w53zPnNArWreyZafb0lDGRTi93ULm4Mpi+/fa+FmJur2B4r3XIdQGTEC1Gjd9mPcRy4Q3tr1xGs24JdgjFW5AveMDCo05QS16NoPZ3li/Q3I6my/5Q26rcXAqe1c+s6Cohr7stWzu8Jgk8LU6xJFCVByd8htrV5VXspMdy9l5yu1Rlashs5vXBQ+gTLbe/vNi0A3x4PdSANq6CjXLsKARtzwiSedmsrytuoWjoWVS9+a3gYsBjTk4F5/FC2uDbz+OntUzqSj2Nx9bPH+sLM+FxIfpOrnFjlnp0Tm2IjGT4O1Ir7uSOJqldfqhgg8kOss9JziVKXmHBOT9Lr+OIyNUoVRUhlxUwNExT4D035ow32ZeTfKtB9D/jYSXAC5djcDtfEm5PeZUW1eeLjgJ6eaemT2gAprkZMbRe9eekwZwZGrI1PdJhiHX+cFQ6WDp7CGw0JVT5Whnmvgv7jvvfLFGz93vYQc3K15/P0fDWIuPZfpPdBQluWOWZp5agCKw58GKIgJ84SrYg/abcH766yYiC0VBys+5TBExjZXQ+VGwvznfSrsFqU7CW4bNJPL1o2iYc/gM8IwZJs6L084duY7+A5mo41VYw==|920