@owocow/industries
v0.0.2
Published
Versioned two-level customer industry catalog with JSON data and typed lookup utilities
Downloads
210
Maintainers
Readme
@owocow/industries
两级客户行业目录,包含 20 个一级行业、114 个二级行业。提供静态数据、浏览器兼容的 ESM 查询方法和只读 TypeScript 类型,零运行时依赖,不绑定 UI 框架。
行业目录由 npm 包维护,前端直接导入。每个客户只保存一个二级行业 industry_code,如 ai_agent;名称和完整路径由本包解析。null 表示未设置。一级 code 和数字 id 不作为客户的行业值。
安装
npm install --save-exact @owocow/[email protected]上述命令适用于包已发布的情况。发布前可在本项目执行 npm pack,然后在消费项目安装生成的本地包:
npm install /absolute/path/to/owocow-industries-0.0.1.tgz主入口为 ESM,支持 import,不提供 CommonJS require 入口。构建和验证环境使用 Node.js 22 或以上版本。
通过 code 获取名称
import { getIndustryName } from '@owocow/industries'
// 默认只获取本节点名称。
getIndustryName('ai_agent')
// 'AI Agent'
// 获取一级行业到本节点的完整路径。
getIndustryName('ai_agent', { fullPath: true })
// '人工智能·AI / AI Agent'
// 自定义路径分隔符。
getIndustryName('ai_agent', { fullPath: true, separator: ' → ' })
// '人工智能·AI → AI Agent'
getIndustryName('ai') // '人工智能·AI'
getIndustryName('unknown') // ''
getIndustryName('') // ''
getIndustryName(null) // ''
getIndustryName() // ''方法签名:
getIndustryName(code?: string | null, options?: IndustryNameOptions): string
interface IndustryNameOptions {
readonly fullPath?: boolean // 默认 false
readonly separator?: string // 完整路径默认用 ' / ' 连接
}separator 仅在 fullPath: true 时生效,可以传空字符串。一级 code 的完整路径就是该一级名称。停用节点仍可以解析名称及完整路径,便于展示已有客户。
一级名称内部使用 · 连接并列领域,例如 人工智能·AI、教育·知识服务、影视·短剧·动漫;完整路径默认使用 / 分隔层级,例如 教育·知识服务 / 学校。也可通过 separator 自定义层级分隔符。
行业选择器
使用 getIndustryTree() 获取按排序排列的两级目录,只允许选择二级节点。选择器将 code 作为值、name 作为标签:
import {
getIndustryTree, isSelectableIndustry,
type SecondaryIndustryCode,
} from '@owocow/industries'
// 返回节点包含 id/code/name/sort/enabled,一级节点包含 children。
const industryOptions = getIndustryTree().map(parent => ({
value: parent.code,
label: parent.name,
children: parent.children.map(child => ({
value: child.code,
label: child.name,
})),
}))
// 两级选择器选中的路径;提交时取最后一级 code。
const selectedPath: string[] = ['ai', 'ai_agent']
const code = selectedPath.at(-1)
if (!isSelectableIndustry(code)) {
throw new Error('请选择一个有效的二级行业')
}
// 客户请求中只传 code,字段命名按项目现有约定。
const payload = { industry_code: code }
const typedCode: SecondaryIndustryCode = 'ai_agent'默认隐藏停用节点及停用一级下的全部子级;无有效子级的一级也不显示。isSelectableIndustry 对一级、未知或停用 code 返回 false。目录与查询结果均为只读数据,组件需要修改选项时可像上面一样映射出自己的对象。
客户列表与详情展示
假设客户接口返回 industry_code,可直接解析为名称:
import { getIndustryName } from '@owocow/industries'
const customer = { industry_code: 'ai_agent' }
// 列表中显示简短名称。
const listLabel = getIndustryName(customer.industry_code) || '未设置'
// 'AI Agent'
// 详情中显示完整路径。
const detailLabel = getIndustryName(customer.industry_code, {
fullPath: true,
separator: ' → ',
}) || '未设置'
// '人工智能·AI → AI Agent'空值和未知 code 都返回 ''。如果页面需要区分“未设置”和“当前包版本无法识别”,可以分别处理:
const code = customer.industry_code
const label = code ? getIndustryName(code) || `未知行业(${code})` : '未设置'客户列表筛选
二级行业筛选使用该节点的 code,例如 ai_agent。选择器沿用上述两级目录;筛选请求传 code,显示标签由 getIndustryName 生成。
如果页面需要按一级行业筛选,可从本包取得其全部二级 code:
import { getChildren } from '@owocow/industries'
const industryCodes = getChildren('ai', { includeDisabled: true })
.map(node => node.code)包含停用 code 可以覆盖历史客户。getChildren 对未知或二级 code 返回 [],调用页面应处理空结果。industryCodes 只是前端计算出的编码列表;是否支持多 code 筛选、请求字段名和查询逻辑由客户接口另行约定。
前端缓存
目录随 npm 包和前端构建产物发布,直接使用包导出的查询方法即可。当前数据不需要额外的目录请求、localStorage 或 IndexedDB 缓存。
包的主模块在同一个 JavaScript 模块环境中初始化一次,建立 code 与父子关系的内存索引;各页面导入的 getIndustryName 等方法复用这些索引。查询名称时直接调用,不要在每一行或每次渲染时重新执行 createIndustryCatalog。
- 全局树形数据:直接复用
getIndustryTree()返回的只读结果。 - UI 组件专用选项:按上面的映射生成,可放在组件模块或框架的计算属性中复用。
- 客户详情名称:根据
industry_code直接查询,无需另外缓存名称。 - 更新目录:升级 npm 包、提交锁文件并重新构建部署前端。已部署页面不会因 npm 发布而自动更新目录。
如果在多个窗口、Worker 或多份构建中加载本包,各自拥有独立的模块实例。无需将查询结果跨环境持久化。
全部导出
| 导出 | 行为 |
| --- | --- |
| getIndustryName(code, options?) | 默认返回本节点名称;fullPath: true 返回完整路径,默认分隔符为 /;未知值返回 '' |
| getIndustry(code) | 精确编码查找,返回节点,未知值返回 undefined;保留停用节点 |
| getIndustryTree(options?) | 默认返回可选目录;includeDisabled: true 返回完整树 |
| getChildren(parentCode, options?) | 默认只返回有效二级节点;未知或二级 code 返回 [] |
| getIndustryPath(code) | 返回一级到目标节点的节点数组;未知值返回 [] |
| formatIndustryPath(code, separator?) | 返回完整路径字符串,默认分隔符为 →;未知值返回 '' |
| isSelectableIndustry(code) | 仅在二级自身和父级同时启用时返回 true |
| createIndustryCatalog(tree) | 校验并复制一份目录,返回相同查询 API,包含 getIndustryName |
| industryTree | 完整只读树,包含停用节点 |
| industryFlat | 全部 134 个只读节点;包含 level、parentCode、parentName |
| catalogVersion / schemaVersion | 当前包的目录版本 / JSON 结构版本(当前结构版本为 1) |
TypeScript 导出:
- 编码类型:
IndustryCode、PrimaryIndustryCode、SecondaryIndustryCode。 - 节点类型:
IndustryBase、IndustryLeaf、IndustryCategory、PrimaryIndustry、SecondaryIndustry、FlatIndustry。 - 查询类型:
IndustryCatalog、IndustryQueryOptions、IndustryNameOptions。
编码联合类型对应安装版本的静态目录。查询方法接受 string | null | undefined,方便直接解析接口字段;空值不会匹配任何节点。
所有目录及查询结果均被冻结。节点按 sort 升序排列,同序按 id 排列。父级停用时,扁平数据的子级 enabled 也为 false,完整树保留源节点的独立开关。
可选:为自己的目录创建查询对象
通常使用包主入口的静态目录即可。如需处理另一份本地目录,可以使用工厂:
import { createIndustryCatalog, industryTree } from '@owocow/industries'
const catalog = createIndustryCatalog(industryTree)
catalog.getIndustryName('ai_agent') // 'AI Agent'
catalog.getIndustryName('ai_agent', { fullPath: true })
catalog.getIndustryTree()工厂校验、复制、排序并冻结输入,不持有传入节点的引用。非法目录抛出 TypeError。工厂用于显式创建独立目录,普通页面查询无需调用它。
JSON 数据
发布包也包含可独立读取的 JSON 子路径:
import tree from '@owocow/industries/industry-tree.json' with { type: 'json' }
import flat from '@owocow/industries/industry-flat.json' with { type: 'json' }
import mapping from '@owocow/industries/industry-mapping.json' with { type: 'json' }
import meta from '@owocow/industries/catalog-meta.json' with { type: 'json' }industry-tree.json:一级节点包含children的完整数组。industry-flat.json:所有一级、二级节点;一级的parentCode/parentName为null,二级包含父级信息,enabled为有效状态。industry-mapping.json:一级 code 到二级 code 数组的完整映射,包含停用节点,用于一级行业筛选与统计。catalog-meta.json:catalogVersion、schemaVersion、primaryCount、secondaryCount、sourceSha256。
对应实体文件在包的 dist/ 中。JSON 字符编码为 UTF-8;JSON 模块导入语法的支持取决于消费方工具链。浏览器项目优先使用主入口的查询方法。
后端参数配置用的行业映射
dist/industry-mapping.json 从 data/industries.json 自动生成,不单独维护。它只包含 code 及归属关系,没有名称、id 或启用状态。包含 20 个一级 code,每个二级 code 恰好出现一次,共 114 个。停用一级及停用二级也保留映射,供历史客户筛选与统计使用。
以下是文件中 ai 的完整条目,其余一级行业采用相同结构:
{
"ai": [
"ai_generative",
"ai_agent",
"ai_large_model",
"ai_application",
"ai_infrastructure",
"ai_data_service",
"ai_smart_hardware"
]
}可以把完整文件内容写入后端参数 industry_mapping。后端加载参数后解析并缓存:
- 一级筛选:取对应二级 code 数组,作为客户
industry_code IN (...)的条件。 - 一级统计:建立“二级 code → 一级 code”的反向映射,将数据库按二级 code 分组的计数归并到一级。
- 无效一级 code 应返回参数错误;未设置和无法识别的客户 code 单独计数,避免漏计。
客户表仍只保存二级 industry_code。映射是完整归属数据,不能用来判断新客户可选行业;选择校验使用 isSelectableIndustry 或目录中的启用状态。
Node.js 也可以通过包子路径获取配置文本:
import mapping from '@owocow/industries/industry-mapping.json' with { type: 'json' }
const configValue = JSON.stringify(mapping)
const aiCodes = mapping.ai更新目录后重新构建本包,并同步后端参数及其缓存,保持前后端的 code 归属一致。
维护与验证
npm ci
npm run verify
npm run pack:check
npm packverify 构建并校验数据、运行 Node 测试和 TypeScript 类型检查。pack:check 创建真实 tarball,安装进临时项目并校验主入口方法、JSON 子路径及类型声明。prepack 和 prepublishOnly 都运行完整验证。
行业数据的唯一维护文件为 data/industries.json。dist/ 自动生成,不手工修改。构建失败会清除旧产物,防止打包陈旧数据。sourceSha256 是原始目录解析后 JSON.stringify 内容的 SHA-256,而非格式化文件字节的摘要。
编码与版本约定
- 保留既有
code、id及父级关系;code 最多 100 字符,仅使用小写字母、数字和下划线。不要通过数字 id 推算父级。 - 名称修正与停用保留原编码;新增节点使用新 code/id。编码不能改含义或复用,停用后仍保留节点供已有客户展示。
- 归属调整、合并和拆分使用新编码并另行处理已有客户的迁移。
data/releases/中的既有身份基线不修改或删除。构建检查这些基线,拒绝旧编码缺失、重编号或换父级。- 发布新版本时更新
package.json及锁文件,保留旧基线;新增身份基线只包含审核后节点的id/code/parentCode。 - 名称修正或停用建议使用 patch,兼容新增使用 minor,结构/API 破坏性变更使用 major。消费者固定版本并提交锁文件。
本包只包含通用行业定义与查询工具,不包含客户数据。行业目录不属于官方统计分类标准。
