Files
MyGoNavi/frontend/src/components/DatabaseIcons.tsx
Syngnat 6bbe5ad30d 🐛 fix(database-icons): 替换数据源官方图标并修正透明底展示
- 为 OceanBase、GaussDB、GoldenDB、Kafka、RocketMQ 等数据源替换官方品牌资源
- 扩展 DatabaseIcons 对 svg/png/ico 的统一加载与底色边框控制
- 补充图标资源断言测试并移除未使用的字母块 fallback
2026-06-14 14:43:03 +08:00

355 lines
14 KiB
TypeScript
Raw 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.
import React from 'react';
// ─── 公共接口 ───────────────────────────────────────────────
export interface DbIconProps {
size?: number;
color?: string;
}
const IconFrame: React.FC<{
size: number;
children: React.ReactNode;
}> = ({ size, children }) => (
<span
data-db-icon-frame="true"
style={{
width: size,
height: size,
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
flexShrink: 0,
}}
>
{children}
</span>
);
// ─── 默认色表 ───────────────────────────────────────────────
const DB_DEFAULT_COLORS: Record<string, string> = {
mysql: '#00758F',
mariadb: '#003545',
oceanbase: '#0052CC',
postgres: '#336791',
redis: '#DC382D',
mongodb: '#47A248',
elasticsearch: '#FEC514',
jvm: '#1677FF',
kingbase: '#1890FF',
dameng: '#E6002D',
oracle: '#F80000',
sqlserver: '#CC2927',
clickhouse: '#FFBF00',
sqlite: '#003B57',
duckdb: '#FFC107',
vastbase: '#0066CC',
opengauss: '#2446A8',
gaussdb: '#0B7FAB',
goldendb: '#D97706',
highgo: '#00A86B',
iris: '#1F6FEB',
tdengine: '#2962FF',
iotdb: '#0F766E',
rocketmq: '#EA580C',
mqtt: '#0EA5A4',
kafka: '#F97316',
rabbitmq: '#FF6B35',
chroma: '#7C3AED',
qdrant: '#DC244C',
diros: '#0050B3',
starrocks: '#00A6A6',
sphinx: '#2F5D62',
custom: '#888888',
};
export const getDbDefaultColor = (type: string): string =>
DB_DEFAULT_COLORS[type?.toLowerCase()] || DB_DEFAULT_COLORS.custom;
type BrandAssetConfig = {
background?: string;
borderColor?: string;
iconScale?: number;
src: string;
};
// ─── 官方品牌资源(文件在 /db-icons/ 下) ────────────────────
const BRAND_ASSET_CONFIGS: Record<string, BrandAssetConfig> = {
mysql: { src: '/db-icons/mysql.svg' },
mariadb: { src: '/db-icons/mariadb.svg' },
oceanbase: { src: '/db-icons/oceanbase.png', iconScale: 0.72 },
postgres: { src: '/db-icons/postgres.svg' },
redis: { src: '/db-icons/redis.svg' },
mongodb: { src: '/db-icons/mongodb.svg' },
elasticsearch: { src: '/db-icons/elasticsearch.svg' },
jvm: { src: '/db-icons/jvm.ico', iconScale: 0.72 },
kingbase: { src: '/db-icons/kingbase.ico', iconScale: 0.72 },
dameng: { src: '/db-icons/dameng.png', iconScale: 0.72 },
oracle: { src: '/db-icons/oracle.ico', iconScale: 0.72 },
sqlserver: { src: '/db-icons/sqlserver.svg' },
clickhouse: { src: '/db-icons/clickhouse.svg' },
sqlite: { src: '/db-icons/sqlite.svg' },
duckdb: { src: '/db-icons/duckdb.svg' },
vastbase: { src: '/db-icons/vastbase.svg', iconScale: 0.84 },
opengauss: { src: '/db-icons/opengauss.ico', iconScale: 0.72 },
gaussdb: { src: '/db-icons/gaussdb.ico', iconScale: 0.72 },
goldendb: { src: '/db-icons/goldendb.ico', iconScale: 0.72 },
highgo: { src: '/db-icons/highgo.ico', iconScale: 0.72 },
iris: { src: '/db-icons/iris.png', iconScale: 0.72 },
tdengine: { src: '/db-icons/tdengine.ico', iconScale: 0.72 },
iotdb: {
src: '/db-icons/iotdb.svg',
background: '#0F766E',
borderColor: '#0F766E',
iconScale: 0.82,
},
rocketmq: {
src: '/db-icons/rocketmq.png',
background: '#0F172A',
borderColor: '#EA580C',
iconScale: 0.84,
},
mqtt: {
src: '/db-icons/mqtt.svg',
background: '#0F172A',
borderColor: '#0EA5A4',
iconScale: 0.84,
},
kafka: { src: '/db-icons/kafka.png', iconScale: 0.8 },
rabbitmq: { src: '/db-icons/rabbitmq.svg', iconScale: 0.74 },
chroma: { src: '/db-icons/chroma.svg', iconScale: 0.9 },
qdrant: { src: '/db-icons/qdrant.svg', iconScale: 0.74 },
diros: { src: '/db-icons/diros.svg' },
starrocks: {
src: '/db-icons/starrocks.png',
background: '#0B1021',
borderColor: '#00A6A6',
iconScale: 0.84,
},
sphinx: { src: '/db-icons/sphinx.svg' },
};
const BRAND_ASSET_TYPES = new Set(Object.keys(BRAND_ASSET_CONFIGS));
/** 品牌图标:用 <img> 加载官方 svg/png/ico 资源 */
const BrandAssetIcon: React.FC<{ type: string; size: number; color?: string }> = ({ type, size, color }) => {
const config = BRAND_ASSET_CONFIGS[type.toLowerCase()];
const bgColor = color || config?.borderColor || getDbDefaultColor(type);
const iconScale = config?.iconScale ?? 0.64;
return (
<IconFrame size={size}>
<span style={{
display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
width: size, height: size, borderRadius: size * 0.22,
background: config?.background || '#fff', border: `1.5px solid ${bgColor}`,
flexShrink: 0, overflow: 'hidden', boxSizing: 'border-box',
}}>
<img
src={config?.src || `/db-icons/${type}.svg`}
alt={type}
width={Math.round(size * iconScale)}
height={Math.round(size * iconScale)}
style={{ display: 'block', objectFit: 'contain' }}
/>
</span>
</IconFrame>
);
};
// ─── 各数据库图标 ───────────────────────────────────────────
// 有品牌官方资源的数据库
const MySQLIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="mysql" size={size} color={color} />
);
const MariaDBIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="mariadb" size={size} color={color} />
);
const OceanBaseIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="oceanbase" size={size} color={color} />
);
const PostgresIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="postgres" size={size} color={color} />
);
const RedisIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="redis" size={size} color={color} />
);
const MongoDBIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="mongodb" size={size} color={color} />
);
const ClickHouseIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="clickhouse" size={size} color={color} />
);
const SQLiteIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="sqlite" size={size} color={color} />
);
const OracleIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="oracle" size={size} color={color} />
);
const SQLServerIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="sqlserver" size={size} color={color} />
);
const DorisIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="diros" size={size} color={color} />
);
const StarRocksIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="starrocks" size={size} color={color} />
);
const SphinxIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="sphinx" size={size} color={color} />
);
const DuckDBIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="duckdb" size={size} color={color} />
);
const KingBaseIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="kingbase" size={size} color={color} />
);
const DamengIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="dameng" size={size} color={color} />
);
const VastBaseIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="vastbase" size={size} color={color} />
);
const OpenGaussIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="opengauss" size={size} color={color} />
);
const GaussDBIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="gaussdb" size={size} color={color} />
);
const GoldenDBIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="goldendb" size={size} color={color} />
);
const HighGoIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="highgo" size={size} color={color} />
);
const IrisIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="iris" size={size} color={color} />
);
const TDengineIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="tdengine" size={size} color={color} />
);
const IoTDBIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="iotdb" size={size} color={color} />
);
const RocketMQIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="rocketmq" size={size} color={color} />
);
const MQTTIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="mqtt" size={size} color={color} />
);
const KafkaIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="kafka" size={size} color={color} />
);
const RabbitMQIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="rabbitmq" size={size} color={color} />
);
const ChromaIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="chroma" size={size} color={color} />
);
const QdrantIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="qdrant" size={size} color={color} />
);
const JVMIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="jvm" size={size} color={color} />
);
const ElasticsearchIcon: React.FC<DbIconProps> = ({ size = 16, color }) => (
<BrandAssetIcon type="elasticsearch" size={size} color={color} />
);
/** Custom — 齿轮图标 */
const CustomIcon: React.FC<DbIconProps> = ({ size = 16, color }) => {
const c = color || DB_DEFAULT_COLORS.custom;
return (
<IconFrame size={size}>
<svg width={size} height={size} viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="24" height="24" rx="5" fill={c}/>
<circle cx="12" cy="12" r="3.5" stroke="#fff" strokeWidth="1.5" fill="none"/>
<path d="M12 4v2.5M12 17.5V20M4 12h2.5M17.5 12H20M6.34 6.34l1.77 1.77M15.89 15.89l1.77 1.77M6.34 17.66l1.77-1.77M15.89 8.11l1.77-1.77" stroke="#fff" strokeWidth="1.3" strokeLinecap="round"/>
</svg>
</IconFrame>
);
};
// ─── 图标注册表 ─────────────────────────────────────────────
const DB_ICON_MAP: Record<string, React.FC<DbIconProps>> = {
mysql: MySQLIcon,
mariadb: MariaDBIcon,
oceanbase: OceanBaseIcon,
diros: DorisIcon,
starrocks: StarRocksIcon,
sphinx: SphinxIcon,
postgres: PostgresIcon,
redis: RedisIcon,
mongodb: MongoDBIcon,
jvm: JVMIcon,
kingbase: KingBaseIcon,
dameng: DamengIcon,
oracle: OracleIcon,
sqlserver: SQLServerIcon,
clickhouse: ClickHouseIcon,
sqlite: SQLiteIcon,
duckdb: DuckDBIcon,
vastbase: VastBaseIcon,
opengauss: OpenGaussIcon,
gaussdb: GaussDBIcon,
goldendb: GoldenDBIcon,
highgo: HighGoIcon,
iris: IrisIcon,
tdengine: TDengineIcon,
iotdb: IoTDBIcon,
rocketmq: RocketMQIcon,
mqtt: MQTTIcon,
kafka: KafkaIcon,
rabbitmq: RabbitMQIcon,
chroma: ChromaIcon,
qdrant: QdrantIcon,
elasticsearch: ElasticsearchIcon,
custom: CustomIcon,
};
/** 可选图标类型列表(用于图标选择器 UI */
export const DB_ICON_TYPES: string[] = [
'mysql', 'mariadb', 'oceanbase', 'postgres', 'redis', 'mongodb', 'jvm',
'oracle', 'sqlserver', 'sqlite', 'duckdb', 'clickhouse', 'starrocks',
'kingbase', 'dameng', 'vastbase', 'opengauss', 'gaussdb', 'goldendb', 'highgo', 'iris', 'tdengine', 'iotdb', 'rocketmq', 'mqtt', 'kafka', 'rabbitmq', 'chroma', 'qdrant', 'elasticsearch', 'custom',
];
/** 该类型是否有品牌图标资源 */
export const hasBrandSvg = (type: string): boolean => BRAND_ASSET_TYPES.has(type?.toLowerCase());
/** 获取数据库图标 React 节点 */
export const getDbIcon = (type: string, color?: string, size?: number): React.ReactNode => {
const key = (type || 'custom').toLowerCase();
const Component = DB_ICON_MAP[key] || CustomIcon;
return <Component size={size} color={color} />;
};
/** 获取数据库图标显示名称(中文) */
export const getDbIconLabel = (type: string): string => {
const labels: Record<string, string> = {
mysql: 'MySQL', mariadb: 'MariaDB', oceanbase: 'OceanBase', postgres: 'PostgreSQL',
redis: 'Redis', mongodb: 'MongoDB', jvm: 'JVM',
oracle: 'Oracle',
sqlserver: 'SQL Server', clickhouse: 'ClickHouse', sqlite: 'SQLite',
starrocks: 'StarRocks',
duckdb: 'DuckDB', kingbase: '金仓', dameng: '达梦',
vastbase: 'VastBase', opengauss: 'OpenGauss', gaussdb: 'GaussDB', goldendb: 'GoldenDB', highgo: '瀚高', iris: 'InterSystems IRIS', tdengine: 'TDengine', iotdb: 'Apache IoTDB', rocketmq: 'RocketMQ', mqtt: 'MQTT', kafka: 'Kafka', rabbitmq: 'RabbitMQ',
chroma: 'Chroma',
qdrant: 'Qdrant',
elasticsearch: 'Elasticsearch',
custom: '自定义',
};
return labels[type?.toLowerCase()] || type;
};
/** 预设颜色列表 */
export const PRESET_ICON_COLORS: string[] = [
'#336791', '#00758F', '#DC382D', '#47A248', '#F80000',
'#CC2927', '#1890FF', '#E6002D', '#FFBF00', '#2962FF',
'#00A86B', '#0066CC', '#FF6B35', '#7C3AED',
];