Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
P
project_manager_xy
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
David Yang
project_manager_xy
Commits
8d74d2c6
Commit
8d74d2c6
authored
Sep 08, 2026
by
Andy-bubu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: align pie chart palette with xinyuan baseline
parent
89d9efa3
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
170 additions
and
12 deletions
+170
-12
ui-architecture.md
docs/ui-architecture.md
+1
-1
ui-migration-checklist.md
docs/ui-migration-checklist.md
+2
-0
xinyuan-design-system.md
docs/xinyuan-design-system.md
+1
-1
xinyuan-ui-audit.md
docs/xinyuan-ui-audit.md
+9
-0
XinyuanEChart.jsx
src/components/XinyuanEChart.jsx
+47
-2
chartPalette.js
src/design-system/chartPalette.js
+72
-2
theme.css
src/design-system/theme.css
+17
-0
tokens.css
src/design-system/tokens.css
+17
-0
project-management.business-flow.md
...es/project_manager_xy/project-management.business-flow.md
+1
-1
index.jsx
src/pages/project_manager_xy/resource-stat/index.jsx
+3
-5
No files found.
docs/ui-architecture.md
View file @
8d74d2c6
...
@@ -88,7 +88,7 @@ Layout route/path change + 60s timer + notification-state event
...
@@ -88,7 +88,7 @@ Layout route/path change + 60s timer + notification-state event
-
可见结构使用 HeroUI 原生组合:L1
`Card`
承载分析模块,L2
`Surface secondary`
承载时间轴,L3
`Surface tertiary`
承载刻度和任务行。
-
可见结构使用 HeroUI 原生组合:L1
`Card`
承载分析模块,L2
`Surface secondary`
承载时间轴,L3
`Surface tertiary`
承载刻度和任务行。
-
实际进度与时间进度使用
`ProgressBar`
compound API;结果状态使用语义
`Chip`
,空范围使用 Pro
`EmptyState`
。
-
实际进度与时间进度使用
`ProgressBar`
compound API;结果状态使用语义
`Chip`
,空范围使用 Pro
`EmptyState`
。
-
共享 CSS 只控制网格、宽度、间距、对齐与横向滚动;组件颜色、圆角、描边和交互状态由 HeroUI variant 与鑫元共享 Tokens 负责。
-
共享 CSS 只控制网格、宽度、间距、对齐与横向滚动;组件颜色、圆角、描边和交互状态由 HeroUI variant 与鑫元共享 Tokens 负责。
-
图表颜色由
`tokens.css`
的共享
`--rc-chart-*`
序列和
`XinyuanEChart`
适配器统一提供,
优先使用品牌红深浅、暖色、中性和灰蓝层级;业务页面不得添加绿色、荧光色或页面私有图表
色。
-
图表颜色由
`tokens.css`
的共享
`--rc-chart-*`
序列和
`XinyuanEChart`
适配器统一提供,
普通 Bar/Line/Ranking 保持该色板;Pie/Donut 独立读取
`--rc-pie-chart-*`
,前六个为
`#DA241A`
、
`#3F5F86`
、
`#8A668F`
、
`#C28A3D`
、
`#8A6253`
、
`#667080`
,并按稳定分类 key 确定性分配、冲突消解且在筛选/排序/Tab/主题切换后保持不变。业务页面不得添加绿色、青绿色、荧光色、彩虹色或页面私有饼图
色。
## 个人日历架构
## 个人日历架构
...
...
docs/ui-migration-checklist.md
View file @
8d74d2c6
...
@@ -43,6 +43,8 @@
...
@@ -43,6 +43,8 @@
-
[
x
]
状态环图、结果/进度柱图和成员负载组合图保持真实业务口径并使用共享图表 Token。
-
[
x
]
状态环图、结果/进度柱图和成员负载组合图保持真实业务口径并使用共享图表 Token。
-
[
x
]
Chart Tooltip、坐标轴和饼图标签由适配器统一配置。
-
[
x
]
Chart Tooltip、坐标轴和饼图标签由适配器统一配置。
-
[
x
]
图表共享色系固定为品牌红深浅 -> 暖色 -> 中性 -> 灰蓝;已检查资源统计全部图表,未使用绿色系、荧光色或彩虹式相邻系列色。
-
[
x
]
图表共享色系固定为品牌红深浅 -> 暖色 -> 中性 -> 灰蓝;已检查资源统计全部图表,未使用绿色系、荧光色或彩虹式相邻系列色。
-
[
x
]
饼图/环形图同步独立
`--xinyuan-pie-chart-*`
/
`--rc-pie-chart-*`
色板(前六色为
`#DA241A`
、
`#3F5F86`
、
`#8A668F`
、
`#C28A3D`
、
`#8A6253`
、
`#667080`
);共享适配器按稳定分类 key 分配并消除冲突,页面级旧颜色不再覆盖,普通 Bar/Line/Ranking 色板保持不变。
-
[
x
]
项目状态环图按
`已完成 / 进行中 / 受阻 / assigned / 草稿`
的稳定业务顺序依次使用专用色板前五色。
-
[
x
]
资源统计、甘特图、个人日历和风险清单模块已移除重复副标题,范围信息保留在控件和数据区域内。
-
[
x
]
资源统计、甘特图、个人日历和风险清单模块已移除重复副标题,范围信息保留在控件和数据区域内。
-
[
x
]
灰色 L2 嵌套 Surface 统一使用
`rc-nested-surface`
的 8px 圆角,外层工作台模块仍保持 24px。
-
[
x
]
灰色 L2 嵌套 Surface 统一使用
`rc-nested-surface`
的 8px 圆角,外层工作台模块仍保持 24px。
-
[
x
]
整个周进度记录模块及其记录项使用 HeroUI
`Surface variant="transparent"`
+
`rc-outline-surface`
,去除灰色填充并统一使用灰色描边。
-
[
x
]
整个周进度记录模块及其记录项使用 HeroUI
`Surface variant="transparent"`
+
`rc-outline-surface`
,去除灰色填充并统一使用灰色描边。
...
...
docs/xinyuan-design-system.md
View file @
8d74d2c6
...
@@ -53,7 +53,7 @@
...
@@ -53,7 +53,7 @@
-
ActionBar:选中后位于当前主内容视口下方中央,右侧关闭清除选择。
-
ActionBar:选中后位于当前主内容视口下方中央,右侧关闭清除选择。
-
Modal:标准 24px 圆角;详情/复杂表单 4xl;Header 中功能标题与记录标题分层展示,正文与 Header 共享内容左右边界;查看态使用无框标签/值布局,不增加灰色填充 Surface,字段从
`md`
起双列、列间距 32px、行间距 8px、字段上下 12px、标签和值间距 6px,标签为 14px/500 muted、值为 14px/400 foreground;可编辑记录的查看态 Footer 只保留右对齐的“编辑”主操作,右上角关闭图标负责退出;编辑态 controls 直接位于同一 Overlay 并使用
`secondary`
,已有记录的删除作为 Footer 右侧操作组中的独立危险次操作,位于“取消”之前且不抢占最右主操作,确认仍通过受控 AlertDialog;查看/编辑切换复用同一 4xl Modal 几何,避免双 Modal 进出场造成跳动。
-
Modal:标准 24px 圆角;详情/复杂表单 4xl;Header 中功能标题与记录标题分层展示,正文与 Header 共享内容左右边界;查看态使用无框标签/值布局,不增加灰色填充 Surface,字段从
`md`
起双列、列间距 32px、行间距 8px、字段上下 12px、标签和值间距 6px,标签为 14px/500 muted、值为 14px/400 foreground;可编辑记录的查看态 Footer 只保留右对齐的“编辑”主操作,右上角关闭图标负责退出;编辑态 controls 直接位于同一 Overlay 并使用
`secondary`
,已有记录的删除作为 Footer 右侧操作组中的独立危险次操作,位于“取消”之前且不抢占最右主操作,确认仍通过受控 AlertDialog;查看/编辑切换复用同一 4xl Modal 几何,避免双 Modal 进出场造成跳动。
-
KPI:HeroUI Pro KPI compound,24px 外卡、16px board gap、实际 data-count 布局。
-
KPI:HeroUI Pro KPI compound,24px 外卡、16px board gap、实际 data-count 布局。
-
图表:ECharts +
`echarts-for-react`
通过共享
`XinyuanEChart`
适配器渲染;
应用扩展
`--rc-chart-*`
使用
`#DA241A`
品牌红及低饱和红、暖色、中性、灰蓝层级,禁止绿色系、荧光色和彩虹式相邻对撞。适配器读取扩展色板后再向 ECharts 注入具体颜色;
Tooltip、坐标轴和饼图间隙由适配器统一处理。
-
图表:ECharts +
`echarts-for-react`
通过共享
`XinyuanEChart`
适配器渲染;
普通柱状图、折线图和排名图继续使用
`--xinyuan-chart-*`
/
`--rc-chart-*`
,其序列为品牌红、低饱和暖色、中性和灰蓝层级。饼图/环形图独立使用
`--xinyuan-pie-chart-*`
/
`--rc-pie-chart-*`
,前六个固定为
`#DA241A`
、
`#3F5F86`
、
`#8A668F`
、
`#C28A3D`
、
`#8A6253`
、
`#667080`
,禁止绿色、青绿色、荧光色和彩虹色。适配器按稳定分类 key 确定性分配饼图颜色,过滤、排序、Tab 和主题切换不改变分类颜色;页面不得写入饼图颜色覆盖。
Tooltip、坐标轴和饼图间隙由适配器统一处理。
-
模块头部只保留功能标题;图表、甘特图、日历和清单不显示重复性副标题或日期说明,必要的范围和解释由控件、坐标轴或弹窗上下文承载。
-
模块头部只保留功能标题;图表、甘特图、日历和清单不显示重复性副标题或日期说明,必要的范围和解释由控件、坐标轴或弹窗上下文承载。
-
字段标题旁的持久性规则说明使用小型 HeroUI Tooltip 信息图标承载;以项目状态为例,工作流说明不再占用字段下方垂直空间。
-
字段标题旁的持久性规则说明使用小型 HeroUI Tooltip 信息图标承载;以项目状态为例,工作流说明不再占用字段下方垂直空间。
-
个人日历:HeroUI Pro Agenda 月视图;跨日期项目使用 MonthSpanningEvent,单日项目使用 MonthEvent,导航和日期状态使用 Agenda 官方 compound API。
-
个人日历:HeroUI Pro Agenda 月视图;跨日期项目使用 MonthSpanningEvent,单日项目使用 MonthEvent,导航和日期状态使用 Agenda 官方 compound API。
...
...
docs/xinyuan-ui-audit.md
View file @
8d74d2c6
...
@@ -97,6 +97,7 @@
...
@@ -97,6 +97,7 @@
-
`bash /Users/liuchenlong/.codex/skills/xinyuan-design-system/scripts/audit_project.sh /Users/liuchenlong/Desktop/job/project_manager_xy`
:退出码 0;权威主题、原生 HeroUI 架构和四份文档检查通过。脚本仍输出 6 类启发式警告,均已逐项复核:Pro 子路径警告源于 Node
`require.resolve`
加载包内 CSS;Modal、DataGrid 字体层级、人员双行信息和可点击主字段使用当前 HeroUI compound/页面数据 schema,未沿用旧包装;
`--rc-shadow-card`
与 Skill 原始副本逐字一致,脚本的单行正则不能匹配格式化后的多行值。作为对照,同一脚本对问题整改本身也输出 Pro 子路径、DataGrid 命名和 shadow 正则等警告。这些警告不代表活动页面遗留;已用源代码扫描、
`exports`
、
`import.meta.resolve`
、生产构建和浏览器计算结果复核。
-
`bash /Users/liuchenlong/.codex/skills/xinyuan-design-system/scripts/audit_project.sh /Users/liuchenlong/Desktop/job/project_manager_xy`
:退出码 0;权威主题、原生 HeroUI 架构和四份文档检查通过。脚本仍输出 6 类启发式警告,均已逐项复核:Pro 子路径警告源于 Node
`require.resolve`
加载包内 CSS;Modal、DataGrid 字体层级、人员双行信息和可点击主字段使用当前 HeroUI compound/页面数据 schema,未沿用旧包装;
`--rc-shadow-card`
与 Skill 原始副本逐字一致,脚本的单行正则不能匹配格式化后的多行值。作为对照,同一脚本对问题整改本身也输出 Pro 子路径、DataGrid 命名和 shadow 正则等警告。这些警告不代表活动页面遗留;已用源代码扫描、
`exports`
、
`import.meta.resolve`
、生产构建和浏览器计算结果复核。
-
旧组件扫描:Catalyst、Headless UI、compat、旧 DataTable/MetricCard/FormSelect 及 Recharts/Pro Charts 活动引用为 0;图表统一使用 ECharts 适配器。
-
旧组件扫描:Catalyst、Headless UI、compat、旧 DataTable/MetricCard/FormSelect 及 Recharts/Pro Charts 活动引用为 0;图表统一使用 ECharts 适配器。
-
图表色系扫描:资源统计的状态环图、结果/进度柱图、成员负载组合图均只从应用扩展共享
`--rc-chart-*`
序列取色,采用
`#DA241A`
品牌红及低饱和红、暖色、中性、灰蓝层级;页面图表未使用绿色系、荧光色或私有色值。主题与扩展 Token 的运行时计算值已复验一致。
-
图表色系扫描:资源统计的状态环图、结果/进度柱图、成员负载组合图均只从应用扩展共享
`--rc-chart-*`
序列取色,采用
`#DA241A`
品牌红及低饱和红、暖色、中性、灰蓝层级;页面图表未使用绿色系、荧光色或私有色值。主题与扩展 Token 的运行时计算值已复验一致。
-
饼图专项同步:状态环图改由
`XinyuanEChart`
统一使用
`--xinyuan-pie-chart-*`
/
`--rc-pie-chart-*`
专用色板;前六色固定为
`#DA241A`
、
`#3F5F86`
、
`#8A668F`
、
`#C28A3D`
、
`#8A6253`
、
`#667080`
,按稳定分类 key 确定性取色并消除冲突。普通柱图、折线图和排名图仍使用原
`--rc-chart-*`
,页面布局、尺寸、数据结构和交互回调未改变。
-
原生控件扫描:可见
`<select>`
与
`type=date|datetime-local|file`
为 0。
-
原生控件扫描:可见
`<select>`
与
`type=date|datetime-local|file`
为 0。
-
页面私有视觉扫描:禁用色系/背景/描边/圆角/阴影 utility 为 0;页面 CSS/LESS/SCSS 的 HeroUI slot/BEM/伪元素命中为 0。
-
页面私有视觉扫描:禁用色系/背景/描边/圆角/阴影 utility 为 0;页面 CSS/LESS/SCSS 的 HeroUI slot/BEM/伪元素命中为 0。
-
Typography 扫描:Navbar 20px/600、模块标题 16px/600、正文 400、标签 500 均由共享 Token/组件合同提供;侧栏应用名已从 650 修正为 600,未保留非规范字重。
-
Typography 扫描:Navbar 20px/600、模块标题 16px/600、正文 400、标签 500 均由共享 Token/组件合同提供;侧栏应用名已从 650 修正为 600,未保留非规范字重。
...
@@ -128,3 +129,11 @@
...
@@ -128,3 +129,11 @@
-
真实接口当前返回通知空列表和未读 0;浏览器临时路由夹具覆盖未读 1/99/100(100 显示
`99+`
且 aria 保留 100)、转义搜索
`a.*[`
、未读服务端状态、两页 Pagination、单条/全部已读、动态 action、站内/站外跳转与恶意 HTML 纯文本渲染。夹具只存在于 Playwright 会话,没有写入源码或业务数据。
-
真实接口当前返回通知空列表和未读 0;浏览器临时路由夹具覆盖未读 1/99/100(100 显示
`99+`
且 aria 保留 100)、转义搜索
`a.*[`
、未读服务端状态、两页 Pagination、单条/全部已读、动态 action、站内/站外跳转与恶意 HTML 纯文本渲染。夹具只存在于 Playwright 会话,没有写入源码或业务数据。
-
项目清单与通知列表分页默认每页 10 条,可切换 10/20/50 条/页;页容量选择沿用共享 HeroUI Autocomplete 受控值且隐藏搜索,Pagination 保持
`sm`
字号。
-
项目清单与通知列表分页默认每页 10 条,可切换 10/20/50 条/页;页容量选择沿用共享 HeroUI Autocomplete 受控值且隐藏搜索,Pagination 保持
`sm`
字号。
-
最终目标通知页控制台为 0 error、0 warning;登录时人为误读验证码产生的历史请求错误已通过全新浏览器会话隔离,不计入页面最终控制台结果。
-
最终目标通知页控制台为 0 error、0 warning;登录时人为误读验证码产生的历史请求错误已通过全新浏览器会话隔离,不计入页面最终控制台结果。
## 2026-09-08 饼图 / 环形图配色专项同步
-
本轮仅同步 Pie/Donut 相关 Token、共享
`XinyuanEChart`
适配器和资源统计状态环图调用;普通 Bar/Line/Ranking 色板、品牌主色、页面布局、图表尺寸、接口、统计口径及业务回调均未修改。
-
新增
`--xinyuan-pie-chart-1..16`
与
`--rc-pie-chart-1..16`
。前六色固定为
`#DA241A`
、
`#3F5F86`
、
`#8A668F`
、
`#C28A3D`
、
`#8A6253`
、
`#667080`
,扩展色保持灰蓝、灰紫、暖棕和暖灰,禁止绿色、青绿色、荧光色和彩虹色。
-
`XinyuanEChart`
对
`type: 'pie'`
(含 donut)收集完整分类 key,使用专用色板和冲突消解;页面级旧
`itemStyle.color`
不再覆盖。Tooltip、标签、引导线、间隙、圆角和点击行为保持原实现。
-
项目状态环图使用固定业务顺序
`已完成 -> 进行中 -> 受阻 -> assigned -> 草稿`
,直接对应专用色板第 1 至第 5 色;不再因分类名称哈希而跳到扩展色。
-
`npm run build`
、
`git diff --check`
均通过;HeroUI Pro 子路径导入和依赖树检查通过。Playwright 登录页 Token 检查返回
`--xinyuan-pie-chart-1=#DA241A`
、
`--xinyuan-pie-chart-6=#667080`
、
`--rc-pie-chart-1=#DA241A`
,页面横向溢出为 0,控制台无 error/warning。受保护资源统计数据在未登录会话不可展开,本轮图表填充态标记为待真实数据复验。
src/components/XinyuanEChart.jsx
View file @
8d74d2c6
import
{
import
{
createResolvedXinyuanPieChartColorMap
,
getXinyuanEChartsTheme
,
getXinyuanEChartsTheme
,
}
from
'@/design-system/chartPalette'
;
}
from
'@/design-system/chartPalette'
;
import
ReactECharts
from
'echarts-for-react'
;
import
ReactECharts
from
'echarts-for-react'
;
...
@@ -41,6 +42,21 @@ function mergeAxisTheme(axis, theme) {
...
@@ -41,6 +42,21 @@ function mergeAxisTheme(axis, theme) {
return
Array
.
isArray
(
axis
)
?
axis
.
map
(
applyTheme
)
:
applyTheme
(
axis
);
return
Array
.
isArray
(
axis
)
?
axis
.
map
(
applyTheme
)
:
applyTheme
(
axis
);
}
}
function
forceItemStyle
(
data
,
itemStyle
)
{
if
(
!
Array
.
isArray
(
data
))
return
data
;
return
data
.
map
((
item
)
=>
{
if
(
!
item
||
typeof
item
!==
'object'
||
Array
.
isArray
(
item
))
return
item
;
return
{
...
item
,
itemStyle
:
{
...
item
.
itemStyle
,
...
itemStyle
,
},
};
});
}
export
default
function
XinyuanEChart
({
export
default
function
XinyuanEChart
({
ariaLabel
,
ariaLabel
,
className
=
''
,
className
=
''
,
...
@@ -62,14 +78,43 @@ export default function XinyuanEChart({
...
@@ -62,14 +78,43 @@ export default function XinyuanEChart({
const
applyPieTheme
=
(
series
)
=>
{
const
applyPieTheme
=
(
series
)
=>
{
if
(
series
?.
type
!==
'pie'
)
return
series
;
if
(
series
?.
type
!==
'pie'
)
return
series
;
const
{
pieColorOrder
,
...
pieSeries
}
=
series
;
const
pieColorMap
=
createResolvedXinyuanPieChartColorMap
(
Array
.
isArray
(
series
.
data
)
?
series
.
data
.
map
((
item
)
=>
item
?.
name
)
:
[],
{
order
:
pieColorOrder
},
);
const
pieData
=
Array
.
isArray
(
series
.
data
)
?
series
.
data
.
map
((
item
,
index
)
=>
{
if
(
!
item
||
typeof
item
!==
'object'
||
Array
.
isArray
(
item
))
return
item
;
const
key
=
String
(
item
.
name
??
''
).
trim
();
return
{
...
item
,
itemStyle
:
{
...
item
.
itemStyle
,
// Dedicated pie palette wins over legacy page-level colors.
color
:
pieColorMap
.
get
(
key
)
||
theme
.
piePalette
[
index
%
theme
.
piePalette
.
length
],
},
};
})
:
series
.
data
;
const
seriesItemStyle
=
{
...
series
.
itemStyle
};
delete
seriesItemStyle
.
color
;
return
{
return
{
...
series
,
...
pieSeries
,
color
:
theme
.
piePalette
,
itemStyle
:
{
itemStyle
:
{
...
seriesItemStyle
,
borderColor
:
theme
.
sectorGap
,
borderColor
:
theme
.
sectorGap
,
borderRadius
:
theme
.
sectorRadius
,
borderRadius
:
theme
.
sectorRadius
,
borderWidth
:
2
,
borderWidth
:
2
,
...
series
.
itemStyle
,
},
},
data
:
forceItemStyle
(
pieData
,
{
borderColor
:
theme
.
sectorGap
,
borderRadius
:
theme
.
sectorRadius
,
borderWidth
:
2
,
}),
padAngle
:
series
.
padAngle
??
1
,
padAngle
:
series
.
padAngle
??
1
,
};
};
};
};
...
...
src/design-system/chartPalette.js
View file @
8d74d2c6
...
@@ -19,6 +19,12 @@ export const XINYUAN_CHART_PALETTE = Object.freeze([
...
@@ -19,6 +19,12 @@ export const XINYUAN_CHART_PALETTE = Object.freeze([
'var(--rc-chart-16)'
,
'var(--rc-chart-16)'
,
]);
]);
// Pie and donut slices use a dedicated palette so ordinary bar/line/ranking
// colors remain unchanged while adjacent sectors stay distinguishable.
export
const
XINYUAN_PIE_CHART_PALETTE
=
Object
.
freeze
(
Array
.
from
({
length
:
16
},
(
_
,
index
)
=>
`var(--rc-pie-chart-
${
index
+
1
}
)`
),
);
export
const
XINYUAN_CHART_SEMANTIC
=
Object
.
freeze
({
export
const
XINYUAN_CHART_SEMANTIC
=
Object
.
freeze
({
primary
:
'var(--rc-chart-primary)'
,
primary
:
'var(--rc-chart-primary)'
,
risk
:
'var(--rc-chart-risk)'
,
risk
:
'var(--rc-chart-risk)'
,
...
@@ -32,6 +38,13 @@ function normalizeChartKey(key) {
...
@@ -32,6 +38,13 @@ function normalizeChartKey(key) {
return
String
(
key
??
''
).
trim
();
return
String
(
key
??
''
).
trim
();
}
}
function
hashChartKey
(
key
)
{
return
Array
.
from
(
key
).
reduce
(
(
value
,
character
)
=>
((
value
*
31
)
+
character
.
codePointAt
(
0
))
>>>
0
,
0
,
);
}
export
function
createXinyuanChartColorMap
(
keys
=
[],
options
=
{})
{
export
function
createXinyuanChartColorMap
(
keys
=
[],
options
=
{})
{
const
sourceKeys
=
Array
.
isArray
(
keys
)
?
keys
:
[];
const
sourceKeys
=
Array
.
isArray
(
keys
)
?
keys
:
[];
const
order
=
Array
.
isArray
(
options
?.
order
)
?
options
.
order
:
[];
const
order
=
Array
.
isArray
(
options
?.
order
)
?
options
.
order
:
[];
...
@@ -101,9 +114,16 @@ function readRootToken(tokenName, fallback = '') {
...
@@ -101,9 +114,16 @@ function readRootToken(tokenName, fallback = '') {
.
trim
()
||
fallback
;
.
trim
()
||
fallback
;
}
}
export
function
resolveXinyuanChartColor
(
color
,
fallback
=
''
)
{
function
resolveChartColorValue
(
color
,
fallback
,
seen
)
{
const
match
=
String
(
color
||
''
).
trim
().
match
(
/^var
\((
--
[^
)
]
+
)\)
$/
);
const
match
=
String
(
color
||
''
).
trim
().
match
(
/^var
\((
--
[^
)
]
+
)\)
$/
);
return
match
?
readRootToken
(
match
[
1
],
fallback
)
:
String
(
color
||
fallback
);
if
(
!
match
)
return
String
(
color
||
fallback
);
if
(
seen
.
has
(
match
[
1
]))
return
fallback
;
seen
.
add
(
match
[
1
]);
return
resolveChartColorValue
(
readRootToken
(
match
[
1
],
fallback
),
fallback
,
seen
);
}
export
function
resolveXinyuanChartColor
(
color
,
fallback
=
''
)
{
return
resolveChartColorValue
(
color
,
fallback
,
new
Set
());
}
}
export
function
createResolvedXinyuanChartColorMap
(
keys
=
[],
options
=
{})
{
export
function
createResolvedXinyuanChartColorMap
(
keys
=
[],
options
=
{})
{
...
@@ -115,6 +135,53 @@ export function createResolvedXinyuanChartColorMap(keys = [], options = {}) {
...
@@ -115,6 +135,53 @@ export function createResolvedXinyuanChartColorMap(keys = [], options = {}) {
);
);
}
}
export
function
getXinyuanPieChartColor
(
index
=
0
)
{
return
XINYUAN_PIE_CHART_PALETTE
[
Math
.
max
(
0
,
Number
(
index
)
||
0
)
%
XINYUAN_PIE_CHART_PALETTE
.
length
];
}
export
function
createResolvedXinyuanPieChartColorMap
(
keys
=
[],
options
=
{})
{
const
preferredOrder
=
new
Map
(
(
Array
.
isArray
(
options
?.
order
)
?
options
.
order
:
[])
.
map
(
normalizeChartKey
)
.
filter
(
Boolean
)
.
map
((
key
,
index
)
=>
[
key
,
index
]),
);
const
stableKeys
=
[...
new
Set
(
keys
.
map
(
normalizeChartKey
).
filter
(
Boolean
))]
.
sort
((
left
,
right
)
=>
{
const
leftOrder
=
preferredOrder
.
get
(
left
);
const
rightOrder
=
preferredOrder
.
get
(
right
);
if
(
leftOrder
!==
undefined
||
rightOrder
!==
undefined
)
{
if
(
leftOrder
===
undefined
)
return
1
;
if
(
rightOrder
===
undefined
)
return
-
1
;
if
(
leftOrder
!==
rightOrder
)
return
leftOrder
-
rightOrder
;
}
return
left
.
localeCompare
(
right
,
'zh-CN'
);
});
const
colorMap
=
new
Map
();
const
usedIndexes
=
new
Set
();
stableKeys
.
forEach
((
key
)
=>
{
const
preferredIndex
=
preferredOrder
.
has
(
key
)
?
preferredOrder
.
get
(
key
)
%
XINYUAN_PIE_CHART_PALETTE
.
length
:
hashChartKey
(
key
)
%
XINYUAN_PIE_CHART_PALETTE
.
length
;
let
paletteIndex
=
preferredIndex
;
for
(
let
offset
=
0
;
offset
<
XINYUAN_PIE_CHART_PALETTE
.
length
;
offset
+=
1
)
{
const
candidate
=
(
preferredIndex
+
offset
)
%
XINYUAN_PIE_CHART_PALETTE
.
length
;
if
(
!
usedIndexes
.
has
(
candidate
))
{
paletteIndex
=
candidate
;
usedIndexes
.
add
(
candidate
);
break
;
}
}
colorMap
.
set
(
key
,
resolveXinyuanChartColor
(
getXinyuanPieChartColor
(
paletteIndex
)));
});
return
colorMap
;
}
export
function
getXinyuanEChartsTheme
()
{
export
function
getXinyuanEChartsTheme
()
{
const
documentFont
=
typeof
document
===
'undefined'
const
documentFont
=
typeof
document
===
'undefined'
?
'Inter, sans-serif'
?
'Inter, sans-serif'
...
@@ -129,6 +196,9 @@ export function getXinyuanEChartsTheme() {
...
@@ -129,6 +196,9 @@ export function getXinyuanEChartsTheme() {
palette
:
XINYUAN_CHART_PALETTE
.
map
((
color
)
=>
(
palette
:
XINYUAN_CHART_PALETTE
.
map
((
color
)
=>
(
resolveXinyuanChartColor
(
color
,
'#667085'
)
resolveXinyuanChartColor
(
color
,
'#667085'
)
)),
)),
piePalette
:
XINYUAN_PIE_CHART_PALETTE
.
map
((
color
)
=>
(
resolveXinyuanChartColor
(
color
,
'#667080'
)
)),
tooltipBackground
:
readRootToken
(
'--xinyuan-chart-tooltip-background'
,
'#ffffff'
),
tooltipBackground
:
readRootToken
(
'--xinyuan-chart-tooltip-background'
,
'#ffffff'
),
tooltipBorder
:
readRootToken
(
'--xinyuan-chart-tooltip-border'
,
'#dedede'
),
tooltipBorder
:
readRootToken
(
'--xinyuan-chart-tooltip-border'
,
'#dedede'
),
sectorGap
:
readRootToken
(
'--xinyuan-chart-sector-gap'
,
'#ffffff'
),
sectorGap
:
readRootToken
(
'--xinyuan-chart-sector-gap'
,
'#ffffff'
),
...
...
src/design-system/theme.css
View file @
8d74d2c6
...
@@ -115,6 +115,23 @@
...
@@ -115,6 +115,23 @@
--xinyuan-chart-14
:
#61758F
;
--xinyuan-chart-14
:
#61758F
;
--xinyuan-chart-15
:
#74879A
;
--xinyuan-chart-15
:
#74879A
;
--xinyuan-chart-16
:
#8798A8
;
--xinyuan-chart-16
:
#8798A8
;
/* Pie / donut only: independent higher-hue-separation palette. */
--xinyuan-pie-chart-1
:
#DA241A
;
--xinyuan-pie-chart-2
:
#3F5F86
;
--xinyuan-pie-chart-3
:
#8A668F
;
--xinyuan-pie-chart-4
:
#C28A3D
;
--xinyuan-pie-chart-5
:
#8A6253
;
--xinyuan-pie-chart-6
:
#667080
;
--xinyuan-pie-chart-7
:
#74879A
;
--xinyuan-pie-chart-8
:
#9A8174
;
--xinyuan-pie-chart-9
:
#6F6674
;
--xinyuan-pie-chart-10
:
#B87958
;
--xinyuan-pie-chart-11
:
#61758F
;
--xinyuan-pie-chart-12
:
#807783
;
--xinyuan-pie-chart-13
:
#B0A4A0
;
--xinyuan-pie-chart-14
:
#AFA5B1
;
--xinyuan-pie-chart-15
:
#897A73
;
--xinyuan-pie-chart-16
:
#556B88
;
--xinyuan-chart-grid
:
#e8e8e8
;
--xinyuan-chart-grid
:
#e8e8e8
;
--xinyuan-chart-axis
:
#737373
;
--xinyuan-chart-axis
:
#737373
;
--xinyuan-chart-label
:
#737373
;
--xinyuan-chart-label
:
#737373
;
...
...
src/design-system/tokens.css
View file @
8d74d2c6
...
@@ -174,6 +174,23 @@
...
@@ -174,6 +174,23 @@
--rc-chart-14
:
#61758F
;
--rc-chart-14
:
#61758F
;
--rc-chart-15
:
#74879A
;
--rc-chart-15
:
#74879A
;
--rc-chart-16
:
#8798A8
;
--rc-chart-16
:
#8798A8
;
/* Pie / donut series remain independent from bar/line categorical colors. */
--rc-pie-chart-1
:
var
(
--xinyuan-pie-chart-1
);
--rc-pie-chart-2
:
var
(
--xinyuan-pie-chart-2
);
--rc-pie-chart-3
:
var
(
--xinyuan-pie-chart-3
);
--rc-pie-chart-4
:
var
(
--xinyuan-pie-chart-4
);
--rc-pie-chart-5
:
var
(
--xinyuan-pie-chart-5
);
--rc-pie-chart-6
:
var
(
--xinyuan-pie-chart-6
);
--rc-pie-chart-7
:
var
(
--xinyuan-pie-chart-7
);
--rc-pie-chart-8
:
var
(
--xinyuan-pie-chart-8
);
--rc-pie-chart-9
:
var
(
--xinyuan-pie-chart-9
);
--rc-pie-chart-10
:
var
(
--xinyuan-pie-chart-10
);
--rc-pie-chart-11
:
var
(
--xinyuan-pie-chart-11
);
--rc-pie-chart-12
:
var
(
--xinyuan-pie-chart-12
);
--rc-pie-chart-13
:
var
(
--xinyuan-pie-chart-13
);
--rc-pie-chart-14
:
var
(
--xinyuan-pie-chart-14
);
--rc-pie-chart-15
:
var
(
--xinyuan-pie-chart-15
);
--rc-pie-chart-16
:
var
(
--xinyuan-pie-chart-16
);
--rc-chart-primary
:
var
(
--rc-chart-1
);
--rc-chart-primary
:
var
(
--rc-chart-1
);
--rc-chart-risk
:
var
(
--rc-chart-1
);
--rc-chart-risk
:
var
(
--rc-chart-1
);
--rc-chart-warning
:
var
(
--rc-chart-3
);
--rc-chart-warning
:
var
(
--rc-chart-3
);
...
...
src/pages/project_manager_xy/project-management.business-flow.md
View file @
8d74d2c6
...
@@ -136,7 +136,7 @@
...
@@ -136,7 +136,7 @@
-
即将到期项目
-
即将到期项目
-
超时项目清单
-
超时项目清单
-
风险清单区位于成员负载明细下方,采用独立全宽区块展示,避免作为右侧纵列造成页面左右高度失衡
-
风险清单区位于成员负载明细下方,采用独立全宽区块展示,避免作为右侧纵列造成页面左右高度失衡
-
图表统一使用 ECharts,通过共享
`XinyuanEChart`
适配器处理 Pie、Bar、组合图、Tooltip 和主题色;统计口径不变。
系列色按共享 Token 使用品牌红深浅、暖色、中性与灰蓝层级,不使用绿色系、荧光色或页面私有颜
色
-
图表统一使用 ECharts,通过共享
`XinyuanEChart`
适配器处理 Pie、Bar、组合图、Tooltip 和主题色;统计口径不变。
普通 Bar/Line/Ranking 系列继续使用
`--rc-chart-*`
,Pie/Donut 独立使用
`--rc-pie-chart-*`
(前六色固定为
`#DA241A`
、
`#3F5F86`
、
`#8A668F`
、
`#C28A3D`
、
`#8A6253`
、
`#667080`
),按稳定分类 key 确定性分配且不使用绿色、青绿色、荧光色或彩虹
色
-
建议补充统计维度:
-
建议补充统计维度:
-
项目状态分布
-
项目状态分布
-
结果状态分布(按时间规则实时派生)
-
结果状态分布(按时间规则实时派生)
...
...
src/pages/project_manager_xy/resource-stat/index.jsx
View file @
8d74d2c6
...
@@ -31,9 +31,9 @@ const PROGRESS_BUCKETS = [
...
@@ -31,9 +31,9 @@ const PROGRESS_BUCKETS = [
{
label
:
'100%'
,
min
:
100
,
max
:
100
},
{
label
:
'100%'
,
min
:
100
,
max
:
100
},
];
];
const
STATUS_CHART_ORDER
=
[
'已完成'
,
'进行中'
,
'受阻'
,
'assigned'
,
'草稿'
];
const
RESULT_CHART_ORDER
=
[
'已超时'
,
'提前完成'
,
'超时完成'
,
'准时完成'
];
const
RESULT_CHART_ORDER
=
[
'已超时'
,
'提前完成'
,
'超时完成'
,
'准时完成'
];
const
PROGRESS_CHART_ORDER
=
PROGRESS_BUCKETS
.
map
((
bucket
)
=>
bucket
.
label
);
const
PROGRESS_CHART_ORDER
=
PROGRESS_BUCKETS
.
map
((
bucket
)
=>
bucket
.
label
);
const
STATUS_CHART_ORDER
=
[
'已完成'
,
'进行中'
,
'受阻'
,
'assigned'
,
'草稿'
];
function
formatUserLabel
(
user
)
{
function
formatUserLabel
(
user
)
{
return
user
?.
displayName
||
user
?.
username
||
user
?.
id
||
'-'
;
return
user
?.
displayName
||
user
?.
username
||
user
?.
id
||
'-'
;
...
@@ -88,18 +88,16 @@ function ChartEmptyState() {
...
@@ -88,18 +88,16 @@ function ChartEmptyState() {
function
StatusPieChart
({
data
,
total
})
{
function
StatusPieChart
({
data
,
total
})
{
const
option
=
useMemo
(()
=>
{
const
option
=
useMemo
(()
=>
{
const
theme
=
getXinyuanEChartsTheme
();
const
theme
=
getXinyuanEChartsTheme
();
const
colorMap
=
createResolvedXinyuanChartColorMap
(
data
.
map
((
item
)
=>
item
.
name
),
{
order
:
STATUS_CHART_ORDER
,
});
return
{
return
{
legend
:
{
bottom
:
0
,
left
:
'center'
},
legend
:
{
bottom
:
0
,
left
:
'center'
},
series
:
[{
series
:
[{
type
:
'pie'
,
type
:
'pie'
,
name
:
'项目状态'
,
name
:
'项目状态'
,
pieColorOrder
:
STATUS_CHART_ORDER
,
radius
:
[
'52%'
,
'72%'
],
radius
:
[
'52%'
,
'72%'
],
center
:
[
'50%'
,
'44%'
],
center
:
[
'50%'
,
'44%'
],
avoidLabelOverlap
:
true
,
avoidLabelOverlap
:
true
,
data
:
data
.
map
((
item
)
=>
({
...
item
,
itemStyle
:
{
color
:
colorMap
.
get
(
item
.
name
)
}
}))
,
data
,
label
:
{
show
:
true
,
formatter
:
({
name
,
value
})
=>
[
label
:
{
show
:
true
,
formatter
:
({
name
,
value
})
=>
[
`{name|
${
name
}
}`
,
`{name|
${
name
}
}`
,
`{value|
${
value
}
个}`
,
`{value|
${
value
}
个}`
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment