本文档为前端开发人员提供业务领域组合创建 (
/compose) 接口的详细使用说明。
该接口用于从已有的元数据中组合创建新的业务领域。用户可以从不同的业务领域中选择需要的元数据(DataMeta),将它们组合到一个新的业务领域中。
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 用户选择 │ │ 提交创建 │ │ 返回结果 │
│ 元数据列表 │ ──► │ 请求 │ ──► │ 新业务领域 │
└─────────────────┘ └─────────────────┘ └─────────────────┘
INCLUDES 关系| 项目 | 说明 |
|---|---|
| 请求URL | POST /api/bd/compose |
| Content-Type | application/json |
| 请求方法 | POST |
Content-Type: application/json
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| name_zh | string | ✅ 是 | - | 业务领域中文名称 |
| name_en | string | 否 | 自动翻译 | 业务领域英文名称 |
| id_list | array | ✅ 是 | - | 选中的元数据ID列表 |
| describe | string | 否 | - | 业务领域描述 |
| type | string | 否 | - | 业务领域类型 |
| category | string | 否 | - | 业务领域分类 |
| tag | array/integer | 否 | - | 标签ID或标签对象数组 |
| data_source | integer | 否 | - | 数据源ID |
id_list 支持两种格式,前端可根据实际情况选择:
最简洁的格式,直接传递元数据的 ID 列表:
{
"name_zh": "销售分析域",
"id_list": [123, 456, 789]
}
兼容旧格式,传递包含 id 字段的对象数组:
{
"name_zh": "销售分析域",
"id_list": [
{ "id": 123 },
{ "id": 456 },
{ "id": 789 }
]
}
tag 参数支持多种格式:
// 格式1:单个标签ID
{ "tag": 100 }
// 格式2:标签ID数组
{ "tag": [100, 101, 102] }
// 格式3:标签对象数组
{ "tag": [{ "id": 100 }, { "id": 101 }] }
// 格式4:完整标签对象
{ "tag": [{ "id": 100, "name_zh": "核心业务", "name_en": "core" }] }
以下字段均为可选,根据业务需求选择性传递:
| 字段名 | 类型 | 说明 |
|---|---|---|
| leader | string | 负责人 |
| organization | string | 所属组织 |
| status | string | 状态 |
| keywords | string | 关键词 |
| data_sensitivity | string | 数据敏感性 |
| frequency | string | 更新频率 |
| url | string | 相关URL |
| storage_location | string | 存储位置 |
{
"code": 200,
"message": "操作成功",
"data": {
"business_domain": {
"id": 12350,
"name_zh": "销售分析域",
"name_en": "sales_analysis_domain",
"describe": "整合订单和客户数据的销售分析业务领域",
"type": "analysis",
"category": "业务分析",
"create_time": "2025-01-09 10:30:00",
"update_time": "2025-01-09 10:30:00",
"tag": [
{
"id": 100,
"name_zh": "核心业务",
"name_en": "core_business"
}
]
}
}
}
| 字段路径 | 类型 | 说明 |
|---|---|---|
| code | integer | 状态码,200 表示成功 |
| message | string | 操作结果消息 |
| data.business_domain | object | 创建的业务领域详情 |
| data.business_domain.id | integer | 新创建的业务领域节点ID |
| data.business_domain.name_zh | string | 中文名称 |
| data.business_domain.name_en | string | 英文名称 |
| data.business_domain.tag | array | 关联的标签列表 |
{
"code": 500,
"message": "组合创建业务领域失败",
"data": null,
"error": "具体错误信息"
}
import axios from 'axios';
/**
* 组合创建业务领域
* @param {Object} params - 创建参数
* @param {string} params.name_zh - 中文名称(必填)
* @param {string} [params.name_en] - 英文名称(可选,自动翻译)
* @param {number[]} params.id_list - 元数据ID列表(必填)
* @param {string} [params.describe] - 描述
* @param {string} [params.type] - 类型
* @param {string} [params.category] - 分类
* @param {number|number[]} [params.tag] - 标签ID
* @param {number} [params.data_source] - 数据源ID
* @returns {Promise<Object>} 创建结果
*/
async function composeBusinessDomain(params) {
try {
const response = await axios.post('/api/bd/compose', params);
if (response.data.code === 200) {
return {
success: true,
data: response.data.data.business_domain
};
} else {
return {
success: false,
message: response.data.message,
error: response.data.error
};
}
} catch (error) {
console.error('组合创建业务领域失败:', error);
throw error;
}
}
// 使用示例
const result = await composeBusinessDomain({
name_zh: '客户订单分析域',
describe: '整合客户信息和订单数据的分析业务领域',
id_list: [101, 102, 103, 201, 202], // 选中的元数据ID
tag: [100], // 标签ID
category: '业务分析'
});
if (result.success) {
console.log('创建成功,新业务领域ID:', result.data.id);
} else {
console.error('创建失败:', result.message);
}
/**
* 组合创建业务领域
*/
async function composeBusinessDomain(params) {
const response = await fetch('/api/bd/compose', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
});
const data = await response.json();
if (data.code !== 200) {
throw new Error(data.message || '创建失败');
}
return data.data.business_domain;
}
// 使用示例
try {
const newDomain = await composeBusinessDomain({
name_zh: '销售报表域',
id_list: [301, 302, 303]
});
console.log('创建成功:', newDomain);
} catch (error) {
console.error('创建失败:', error.message);
}
<template>
<div class="compose-form">
<el-form :model="form" :rules="rules" ref="formRef" label-width="100px">
<el-form-item label="中文名称" prop="name_zh">
<el-input v-model="form.name_zh" placeholder="请输入业务领域中文名称" />
</el-form-item>
<el-form-item label="英文名称" prop="name_en">
<el-input v-model="form.name_en" placeholder="可选,不填则自动翻译" />
</el-form-item>
<el-form-item label="描述" prop="describe">
<el-input type="textarea" v-model="form.describe" :rows="3" />
</el-form-item>
<el-form-item label="元数据" prop="id_list">
<div class="selected-meta">
<el-tag
v-for="id in form.id_list"
:key="id"
closable
@close="removeMeta(id)"
>
{{ getMetaName(id) }}
</el-tag>
</div>
<el-button type="primary" text @click="openMetaSelector">
选择元数据
</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSubmit" :loading="loading">
创建业务领域
</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { ElMessage } from 'element-plus';
import axios from 'axios';
const formRef = ref(null);
const loading = ref(false);
const form = reactive({
name_zh: '',
name_en: '',
describe: '',
id_list: []
});
const rules = {
name_zh: [
{ required: true, message: '请输入中文名称', trigger: 'blur' }
],
id_list: [
{
required: true,
validator: (rule, value, callback) => {
if (!value || value.length === 0) {
callback(new Error('请至少选择一个元数据'));
} else {
callback();
}
},
trigger: 'change'
}
]
};
// 选择元数据
const openMetaSelector = () => {
// 打开元数据选择器对话框
// 实现略...
};
// 移除已选元数据
const removeMeta = (id) => {
const index = form.id_list.indexOf(id);
if (index > -1) {
form.id_list.splice(index, 1);
}
};
// 获取元数据名称(用于显示)
const getMetaName = (id) => {
// 根据ID获取元数据名称
// 实现略...
return `元数据-${id}`;
};
// 提交表单
const handleSubmit = async () => {
try {
await formRef.value.validate();
loading.value = true;
const response = await axios.post('/api/bd/compose', {
name_zh: form.name_zh,
name_en: form.name_en || undefined,
describe: form.describe || undefined,
id_list: form.id_list
});
if (response.data.code === 200) {
ElMessage.success('业务领域创建成功');
const newDomain = response.data.data.business_domain;
console.log('新建业务领域:', newDomain);
// 跳转到详情页或刷新列表
} else {
ElMessage.error(response.data.message || '创建失败');
}
} catch (error) {
if (error.name !== 'Error') {
// 非表单验证错误
ElMessage.error('创建失败: ' + error.message);
}
} finally {
loading.value = false;
}
};
</script>
import React, { useState } from 'react';
import axios from 'axios';
function ComposeBusinessDomain({ selectedMetaIds, onSuccess }) {
const [form, setForm] = useState({
name_zh: '',
name_en: '',
describe: ''
});
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const handleChange = (e) => {
const { name, value } = e.target;
setForm(prev => ({ ...prev, [name]: value }));
};
const handleSubmit = async (e) => {
e.preventDefault();
if (!form.name_zh.trim()) {
setError('请输入中文名称');
return;
}
if (!selectedMetaIds || selectedMetaIds.length === 0) {
setError('请至少选择一个元数据');
return;
}
setLoading(true);
setError(null);
try {
const response = await axios.post('/api/bd/compose', {
name_zh: form.name_zh,
name_en: form.name_en || undefined,
describe: form.describe || undefined,
id_list: selectedMetaIds
});
if (response.data.code === 200) {
onSuccess?.(response.data.data.business_domain);
} else {
setError(response.data.message || '创建失败');
}
} catch (err) {
setError(err.response?.data?.message || err.message);
} finally {
setLoading(false);
}
};
return (
<form onSubmit={handleSubmit}>
<div className="form-group">
<label>中文名称 *</label>
<input
type="text"
name="name_zh"
value={form.name_zh}
onChange={handleChange}
placeholder="请输入业务领域中文名称"
required
/>
</div>
<div className="form-group">
<label>英文名称</label>
<input
type="text"
name="name_en"
value={form.name_en}
onChange={handleChange}
placeholder="可选,不填则自动翻译"
/>
</div>
<div className="form-group">
<label>描述</label>
<textarea
name="describe"
value={form.describe}
onChange={handleChange}
rows={3}
/>
</div>
<div className="form-group">
<label>已选元数据</label>
<div className="selected-count">
已选择 {selectedMetaIds?.length || 0} 个元数据
</div>
</div>
{error && <div className="error-message">{error}</div>}
<button type="submit" disabled={loading}>
{loading ? '创建中...' : '创建业务领域'}
</button>
</form>
);
}
export default ComposeBusinessDomain;
用户浏览多个现有业务领域,从中选取需要的元数据字段,组合成新的业务领域。
// 用户从订单域选取了 order_id, order_amount
// 从客户域选取了 customer_id, customer_name
// 组合创建 "订单客户分析域"
const selectedMetaIds = [
101, // order_id
102, // order_amount
201, // customer_id
202 // customer_name
];
await composeBusinessDomain({
name_zh: '订单客户分析域',
describe: '用于分析订单与客户关联关系',
id_list: selectedMetaIds,
category: '分析域'
});
从一个大的业务领域中选取部分元数据,创建更细粒度的子域。
// 从 "销售管理" 域中选取部分字段创建 "销售统计" 子域
await composeBusinessDomain({
name_zh: '销售统计域',
id_list: [301, 302, 303, 304],
tag: [100], // 关联 "核心业务" 标签
data_source: 1 // 关联数据源
});
整合来自不同数据源的元数据,创建统一的业务视图。
await composeBusinessDomain({
name_zh: '统一客户视图',
describe: '整合CRM、ERP、电商系统的客户数据',
id_list: [
...crmCustomerFieldIds,
...erpCustomerFieldIds,
...ecommerceCustomerFieldIds
],
category: 'MDM',
tag: [200] // "主数据" 标签
});
| 错误消息 | 原因 | 解决方案 |
|---|---|---|
| 请求数据不能为空 | 未发送请求体 | 检查请求是否包含 JSON body |
| name_zh 为必填项 | 未提供中文名称 | 添加 name_zh 参数 |
| id_list 为必填项 | 未提供元数据列表 | 添加 id_list 参数 |
| 创建业务领域节点失败 | Neo4j 数据库错误 | 联系后端排查 |
async function handleComposeError(error, response) {
// 网络错误
if (!response) {
showMessage('网络连接失败,请检查网络');
return;
}
const { code, message, error: errorDetail } = response.data;
switch (message) {
case 'name_zh 为必填项':
showMessage('请输入业务领域中文名称');
focusField('name_zh');
break;
case 'id_list 为必填项':
showMessage('请至少选择一个元数据');
break;
default:
showMessage(`创建失败: ${message}`);
console.error('详细错误:', errorDetail);
}
}
在调用接口前进行前端校验,减少无效请求:
function validateComposeParams(params) {
const errors = [];
if (!params.name_zh?.trim()) {
errors.push('中文名称不能为空');
}
if (!params.id_list || params.id_list.length === 0) {
errors.push('请至少选择一个元数据');
}
if (params.name_zh && params.name_zh.length > 100) {
errors.push('中文名称不能超过100个字符');
}
return errors;
}
确保 id_list 中没有重复的 ID:
const uniqueIds = [...new Set(selectedMetaIds)];
// 1. 添加加载状态
setLoading(true);
// 2. 成功后给予反馈
ElMessage.success({
message: `业务领域"${result.name_zh}"创建成功`,
duration: 3000
});
// 3. 提供快捷操作
showDialog({
title: '创建成功',
message: '是否立即查看新创建的业务领域?',
confirmText: '查看详情',
cancelText: '继续创建',
onConfirm: () => router.push(`/bd/detail/${result.id}`)
});
提供高效的元数据选择方式:
// 支持按业务领域批量选择
async function selectMetaFromDomain(domainId) {
const metaList = await fetchDomainMeta(domainId);
return metaList.map(meta => meta.id);
}
// 支持搜索过滤
async function searchAndSelectMeta(keyword) {
const results = await searchMeta(keyword);
// 显示选择器...
}
| 版本 | 日期 | 更新内容 |
|---|---|---|
| 2.0.0 | 2025-01-09 | 简化 id_list 格式,支持纯ID数组;移除 domain_id 参数 |
| 1.0.0 | 2025-12-06 | 初始版本 |
如有问题,请联系后端开发团队。