feat(Company): 优化主题系统,添加颜色工具函数和 ESLint 规则

- 新增 colorUtils.ts:提供 alpha()、hex()、fui.* 语义化颜色 API
- 新增 chartTheme:统一图表主题配置(坐标轴、tooltip、渐变等)
- 扩展 FUI_COLORS.line:完整的透明度级别(0.03-0.8)
- 新增 ESLint 规则:检测硬编码金色值(rgba/hex),warning 级别
- 迁移 chartOptions.ts:~15 处硬编码值改用工具函数
- 迁移 shared/styles.ts:~8 处硬编码值改用工具函数

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
zdl
2025-12-24 19:29:53 +08:00
parent fc13666ff0
commit 7f4f9e4032
10 changed files with 434 additions and 47 deletions

10
eslint-rules/index.js Normal file
View File

@@ -0,0 +1,10 @@
/**
* 本地 ESLint 规则插件
*
* 在 .eslintrc.js 中通过 eslint-plugin-local-rules 使用
*/
module.exports = {
rules: {
'no-hardcoded-fui-colors': require('./no-hardcoded-fui-colors'),
},
};

View File

@@ -0,0 +1,86 @@
/**
* ESLint 规则:禁止在 Company 目录使用硬编码颜色
*
* 检测模式:
* - #D4AF37 (金色十六进制)
* - rgba(212, 175, 55, x) (金色 RGBA)
*
* 使用方式:
* 在 .eslintrc.js 中添加规则配置
*/
module.exports = {
meta: {
type: 'suggestion',
docs: {
description: '禁止在 FUI 主题组件中使用硬编码颜色值',
category: 'Best Practices',
recommended: true,
},
messages: {
noHardcodedGoldRgba:
'避免硬编码金色 RGBA 值 "{{value}}"。请使用 alpha("gold", {{opacity}}) 或 fui.border() 等语义化 API。',
noHardcodedGoldHex:
'避免硬编码金色十六进制值 "{{value}}"。请使用 fui.gold 或 FUI_COLORS.gold[400]。',
},
schema: [],
},
create(context) {
const filename = context.getFilename();
// 仅在 src/views/Company 目录下生效
if (!filename.includes('src/views/Company')) {
return {};
}
// 排除主题定义文件
if (
filename.includes('/theme/') ||
filename.includes('/utils/colorUtils')
) {
return {};
}
// 金色 RGBA 正则 - 匹配 rgba(212, 175, 55, x)
const goldRgbaPattern =
/rgba\(\s*212\s*,\s*175\s*,\s*55\s*,\s*([\d.]+)\s*\)/i;
// 金色十六进制 - 匹配 #D4AF37不区分大小写
const goldHexPattern = /#D4AF37/i;
function checkValue(node, value) {
if (typeof value !== 'string') return;
// 检测金色十六进制
if (goldHexPattern.test(value)) {
context.report({
node,
messageId: 'noHardcodedGoldHex',
data: { value },
});
return;
}
// 检测金色 RGBA
const rgbaMatch = value.match(goldRgbaPattern);
if (rgbaMatch) {
const opacity = rgbaMatch[1];
context.report({
node,
messageId: 'noHardcodedGoldRgba',
data: { value, opacity },
});
}
}
return {
Literal(node) {
checkValue(node, node.value);
},
TemplateElement(node) {
checkValue(node, node.value.raw);
},
};
},
};