模块说明: 数据订单 API 提供数据需求订单的创建、分析、审批、驳回、完成等全生命周期管理功能。当用户在数据服务列表中找不到所需数据时,可以发起数据订单,系统会通过 LLM 提取实体并检测业务领域图谱的连通性。
基础路径:
/api/dataservice版本: 2.1.0 (更新于 2026-01-09)
数据订单功能允许用户:
┌─────────────────┐
│ 新增订单 │
│ (pending) │
└────────┬────────┘
│ 发起分析
▼
┌─────────────────┐
│ 分析中 │
│ (analyzing) │
└────────┬────────┘
│
┌───────────────────┼───────────────────┐
│ 分析通过 │ │ 分析有问题
▼ │ ▼
┌─────────────────┐ │ ┌─────────────────┐
│ 待审批 │ │ │ 待人工处理 │
│(pending_approval)│ │ │ (manual_review) │
└────────┬────────┘ │ └────────┬────────┘
│ │ │
┌───────────┴───────────┐ │ │ 修改后
│ 审批通过 │审批驳回│ │ 重新分析
▼ ▼ │ │
┌─────────────────┐ ┌─────────────────┐ │
│ 加工中 │ │ 已驳回 │ │
│ (processing) │ │ (rejected) │◄─────────────────┘
└────────┬────────┘ └─────────────────┘
│ 数据工厂回调
▼
┌─────────────────┐
│ 数据产品就绪 │
│ (onboard) │
└────────┬────────┘
│ 标记完成
▼
┌─────────────────┐
│ 已完成 │
│ (completed) │
└─────────────────┘
| 步骤 | 操作 | 状态变化 | 说明 |
|---|---|---|---|
| 1 | 用户创建订单 | → pending |
订单初始状态 |
| 2 | 发起分析 | pending → analyzing |
调用 LLM 提取实体 |
| 3a | 分析通过 | analyzing → pending_approval |
等待人工审批确认 |
| 3b | 分析有问题 | analyzing → manual_review |
需要人工修改 |
| 4 | 人工修改订单 | 保持 manual_review |
修改描述或提取结果 |
| 5 | 重新分析 | manual_review → analyzing |
再次进行分析 |
| 6a | 审批通过 | pending_approval → processing |
自动生成资源 |
| 6b | 审批驳回 | pending_approval → rejected |
订单被驳回 |
| 7 | 数据工厂回调 | processing → onboard |
数据产品生产完成 |
| 8 | 标记完成 | onboard → completed |
订单最终完成 |
所有接口返回统一的 JSON 格式:
{
"code": 200,
"message": "操作成功",
"data": { ... }
}
| 字段 | 类型 | 说明 |
|---|---|---|
code |
number | 状态码,200 表示成功,其他表示失败 |
message |
string | 操作结果描述信息 |
data |
object | array | null | 返回的数据内容 |
| 状态码 | 说明 | 常见场景 |
|---|---|---|
| 200 | 成功 | 操作成功完成 |
| 400 | 请求参数错误 | 缺少必填字段、状态不允许操作、驳回原因为空 |
| 404 | 资源不存在 | 数据订单 ID 不存在 |
| 500 | 服务器内部错误 | 数据库连接失败、LLM 调用失败、图谱查询异常 |
| 状态值 | 中文标签 | 说明 | 可执行操作 |
|---|---|---|---|
pending |
待处理 | 订单刚创建,等待分析 | 分析、更新、删除 |
analyzing |
分析中 | 正在进行 LLM 提取和图谱分析 | - |
pending_approval |
待审批 | 分析通过,等待人工审批 | 审批通过、驳回 |
processing |
加工中 | 审批通过,正在生成数据流/数据产品 | - |
onboard |
数据产品就绪 | 数据流程完成,产品可用 | 完成 |
completed |
已完成 | 订单处理完成 | 删除 |
rejected |
已驳回 | 订单被驳回 | 删除 |
need_supplement |
待补充 | 需要用户补充信息 | 更新、分析 |
manual_review |
待人工处理 | 需要人工修改 | 更新、分析、审批、驳回 |
建议的 Axios 全局配置:
// src/utils/request.js
import axios from 'axios'
import { ElMessage } from 'element-plus'
const request = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL || 'http://localhost:5050',
timeout: 60000, // 分析接口可能需要较长时间
headers: {
'Content-Type': 'application/json'
}
})
// 响应拦截器
request.interceptors.response.use(
response => {
const res = response.data
if (res.code !== 200) {
ElMessage.error(res.message || '请求失败')
return Promise.reject(new Error(res.message || 'Error'))
}
return res
},
error => {
ElMessage.error(error.message || '网络错误')
return Promise.reject(error)
}
)
export default request
分页获取数据订单列表,支持搜索和状态过滤。
| 项目 | 说明 |
|---|---|
| URL | GET /api/dataservice/orderlist |
| Method | GET |
| Content-Type | - |
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
page |
integer | 否 | 1 | 页码 |
page_size |
integer | 否 | 20 | 每页数量 |
search |
string | 否 | "" | 搜索关键词(匹配订单编号、标题、描述) |
status |
string | 否 | - | 状态过滤,见订单状态说明 |
{
"code": 200,
"message": "获取数据订单列表成功",
"data": {
"list": [
{
"id": 1,
"order_no": "DO202601090001",
"title": "员工与部门关联数据",
"description": "需要获取员工信息和所属部门的关联数据",
"extracted_domains": ["员工", "部门"],
"extracted_fields": ["员工ID", "姓名", "部门ID", "部门名称"],
"extraction_purpose": "用于人力资源分析报表",
"graph_analysis": {
"matched_domains": [...],
"matched_fields": [...],
"connection_analysis": {...}
},
"can_connect": true,
"connection_path": {...},
"status": "pending_approval",
"status_label": "待审批",
"reject_reason": null,
"result_product_id": null,
"result_dataflow_id": null,
"created_by": "张三",
"created_at": "2026-01-09T09:00:00",
"updated_at": "2026-01-09T09:15:00",
"processed_by": null,
"processed_at": null
}
],
"pagination": {
"page": 1,
"page_size": 20,
"total": 45,
"total_pages": 3
}
}
}
| 字段 | 类型 | 说明 |
|---|---|---|
id |
integer | 订单唯一 ID |
order_no |
string | 订单编号,格式: DO + YYYYMMDD + 4位序列号 |
title |
string | 订单标题 |
description |
string | 需求描述 |
extracted_domains |
array | null | LLM 提取的业务领域列表 |
extracted_fields |
array | null | LLM 提取的数据字段列表 |
extraction_purpose |
string | null | LLM 提取的数据用途 |
graph_analysis |
object | null | 图谱连通性分析结果 |
can_connect |
boolean | null | 是否可在图谱中连通 |
connection_path |
object | null | 连通路径详情 |
status |
string | 订单状态 |
status_label |
string | 状态中文标签 |
reject_reason |
string | null | 驳回原因(仅状态为 rejected 时有值) |
result_product_id |
integer | null | 生成的数据产品 ID |
result_dataflow_id |
integer | null | 生成的数据流 ID |
created_by |
string | 创建人 |
created_at |
string | 创建时间(ISO 8601 格式) |
updated_at |
string | 更新时间 |
processed_by |
string | null | 处理人 |
processed_at |
string | null | 处理时间 |
import request from '@/utils/request'
// 获取订单列表
const fetchOrders = async (params) => {
const res = await request.get('/api/dataservice/orderlist', { params })
return res.data
}
// 使用示例
const { list, pagination } = await fetchOrders({
page: 1,
page_size: 20,
status: 'pending_approval'
})
根据 ID 获取单个数据订单的详细信息。
| 项目 | 说明 |
|---|---|
| URL | GET /api/dataservice/orders/{order_id}/detail |
| Method | GET |
| Content-Type | - |
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
order_id |
integer | 是 | 数据订单 ID |
{
"code": 200,
"message": "获取数据订单详情成功",
"data": {
"id": 1,
"order_no": "DO202601090001",
"title": "员工与部门关联数据",
"description": "需要获取员工信息和所属部门的关联数据...",
"extracted_domains": ["员工", "部门"],
"extracted_fields": ["员工ID", "姓名", "部门ID", "部门名称"],
"extraction_purpose": "用于人力资源分析报表",
"graph_analysis": {...},
"can_connect": true,
"connection_path": {...},
"status": "pending_approval",
"status_label": "待审批",
...
}
}
const fetchOrderDetail = async (orderId) => {
const res = await request.get(`/api/dataservice/orders/${orderId}/detail`)
return res.data
}
创建新的数据需求订单。
| 项目 | 说明 |
|---|---|
| URL | POST /api/dataservice/neworder |
| Method | POST |
| Content-Type | application/json |
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
title |
string | 是 | - | 订单标题,最大 200 字符 |
description |
string | 是 | - | 需求描述,详细说明需要什么数据 |
created_by |
string | 否 | "user" | 创建人标识 |
{
"title": "员工与部门关联数据",
"description": "需要获取员工信息和所属部门的关联数据,包括:\n1. 员工基本信息(ID、姓名、入职日期)\n2. 部门信息(部门ID、部门名称)\n3. 部门层级关系\n\n用途:生成人力资源分析报表",
"created_by": "张三"
}
{
"code": 200,
"message": "创建数据订单成功",
"data": {
"id": 1,
"order_no": "DO202601090001",
"title": "员工与部门关联数据",
"description": "...",
"status": "pending",
"status_label": "待处理",
...
}
}
const createOrder = async (data) => {
const res = await request.post('/api/dataservice/neworder', data)
return res.data
}
// 使用示例
const newOrder = await createOrder({
title: '员工与部门关联数据',
description: '需要获取员工信息...'
})
更新数据订单信息,支持修改标题、描述和 LLM 提取结果。
注意: 只允许在
pending、manual_review、need_supplement状态下修改订单。
| 项目 | 说明 |
|---|---|
| URL | PUT /api/dataservice/orders/{order_id}/update |
| Method | PUT |
| Content-Type | application/json |
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
order_id |
integer | 是 | 数据订单 ID |
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
title |
string | 否 | 订单标题 |
description |
string | 否 | 需求描述 |
extracted_domains |
array | 否 | 提取的业务领域列表 |
extracted_fields |
array | 否 | 提取的数据字段列表 |
extraction_purpose |
string | 否 | 数据用途 |
{
"title": "员工与部门关联数据(更新)",
"description": "需要获取员工信息和所属部门的关联数据,补充:需要包含员工的岗位信息",
"extracted_domains": ["员工", "部门", "岗位"],
"extracted_fields": ["员工ID", "姓名", "部门ID", "部门名称", "岗位名称"]
}
{
"code": 200,
"message": "更新数据订单成功",
"data": {
"id": 1,
"order_no": "DO202601090001",
"title": "员工与部门关联数据(更新)",
"description": "...",
"extracted_domains": ["员工", "部门", "岗位"],
"extracted_fields": ["员工ID", "姓名", "部门ID", "部门名称", "岗位名称"],
"status": "manual_review",
"status_label": "待人工处理",
...
}
}
状态不允许修改 (400):
{
"code": 400,
"message": "订单状态 processing 不允许修改,只有 ['pending', 'manual_review', 'need_supplement'] 状态可以修改",
"data": null
}
<template>
<el-dialog v-model="dialogVisible" title="编辑订单" width="600px">
<el-form :model="form" :rules="rules" ref="formRef" label-width="120px">
<el-form-item label="订单标题" prop="title">
<el-input v-model="form.title" />
</el-form-item>
<el-form-item label="需求描述" prop="description">
<el-input v-model="form.description" type="textarea" :rows="4" />
</el-form-item>
<el-form-item label="业务领域">
<el-select v-model="form.extracted_domains" multiple allow-create filterable>
<el-option
v-for="domain in domainOptions"
:key="domain"
:label="domain"
:value="domain"
/>
</el-select>
</el-form-item>
<el-form-item label="数据字段">
<el-select v-model="form.extracted_fields" multiple allow-create filterable>
<el-option
v-for="field in fieldOptions"
:key="field"
:label="field"
:value="field"
/>
</el-select>
</el-form-item>
<el-form-item label="数据用途">
<el-input v-model="form.extraction_purpose" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSubmit" :loading="submitting">
保存修改
</el-button>
</template>
</el-dialog>
</template>
<script setup>
import { ref, reactive } from 'vue'
import { ElMessage } from 'element-plus'
import request from '@/utils/request'
const emit = defineEmits(['success'])
const dialogVisible = ref(false)
const submitting = ref(false)
const currentOrderId = ref(null)
const formRef = ref(null)
const form = reactive({
title: '',
description: '',
extracted_domains: [],
extracted_fields: [],
extraction_purpose: ''
})
const open = (order) => {
currentOrderId.value = order.id
form.title = order.title
form.description = order.description
form.extracted_domains = order.extracted_domains || []
form.extracted_fields = order.extracted_fields || []
form.extraction_purpose = order.extraction_purpose || ''
dialogVisible.value = true
}
const handleSubmit = async () => {
submitting.value = true
try {
const data = {}
if (form.title) data.title = form.title
if (form.description) data.description = form.description
if (form.extracted_domains.length) data.extracted_domains = form.extracted_domains
if (form.extracted_fields.length) data.extracted_fields = form.extracted_fields
if (form.extraction_purpose) data.extraction_purpose = form.extraction_purpose
await request.put(`/api/dataservice/orders/${currentOrderId.value}/update`, data)
ElMessage.success('更新成功')
dialogVisible.value = false
emit('success')
} catch (error) {
ElMessage.error(error.message || '更新失败')
} finally {
submitting.value = false
}
}
defineExpose({ open })
</script>
触发 LLM 实体提取和业务领域图谱连通性分析。
| 项目 | 说明 |
|---|---|
| URL | POST /api/dataservice/orders/{order_id}/analyze |
| Method | POST |
| Content-Type | - |
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
order_id |
integer | 是 | 数据订单 ID |
无需请求体。
分析成功后返回更新后的订单数据:
{
"code": 200,
"message": "数据订单分析完成",
"data": {
"id": 1,
"order_no": "DO202601090001",
"title": "员工与部门关联数据",
"extracted_domains": ["员工", "部门"],
"extracted_fields": ["员工ID", "姓名", "部门ID", "部门名称"],
"extraction_purpose": "用于人力资源分析报表",
"graph_analysis": {
"matched_domains": [
{ "id": 101, "name_zh": "员工信息", "name_en": "employee" },
{ "id": 102, "name_zh": "部门信息", "name_en": "department" }
],
"matched_fields": [...],
"connection_analysis": {
"can_connect": true,
"common_fields": [...]
}
},
"can_connect": true,
"connection_path": {...},
"status": "pending_approval",
"status_label": "待审批"
}
}
分析结果说明:
| 结果 | 说明 | 后续状态 |
|---|---|---|
can_connect: true |
所有实体都能在图谱中连通 | pending_approval (待人工审批) |
can_connect: false |
存在无法连通的实体 | manual_review (待人工处理) |
const analyzeOrder = async (orderId) => {
const loadingInstance = ElLoading.service({
text: '正在分析订单,可能需要几秒钟...',
background: 'rgba(0, 0, 0, 0.7)'
})
try {
const res = await request.post(`/api/dataservice/orders/${orderId}/analyze`)
loadingInstance.close()
if (res.data.can_connect) {
ElMessage.success('分析完成,实体可连通,请进行审批确认!')
} else {
ElMessage.warning('分析完成,部分实体无法连通,请修改后重新分析')
}
return res.data
} catch (error) {
loadingInstance.close()
ElMessage.error(error.message || '分析失败')
throw error
}
}
审批通过数据订单,系统将自动生成 BusinessDomain 和 DataFlow 资源。
注意: 只允许从
pending_approval或manual_review状态审批。
| 项目 | 说明 |
|---|---|
| URL | POST /api/dataservice/orders/{order_id}/approve |
| Method | POST |
| Content-Type | application/json |
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
order_id |
integer | 是 | 数据订单 ID |
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
processed_by |
string | 否 | "admin" | 处理人标识 |
{
"processed_by": "管理员A"
}
{
"code": 200,
"message": "数据订单审批通过,资源已生成",
"data": {
"order": {
"id": 1,
"order_no": "DO202601090001",
"status": "processing",
"status_label": "加工中",
"result_dataflow_id": 156,
"processed_by": "管理员A",
"processed_at": "2026-01-09T10:00:00",
...
},
"generated_resources": {
"target_business_domain_id": 201,
"dataflow_id": 156,
"input_domain_ids": [101, 102]
}
}
}
| 字段 | 类型 | 说明 |
|---|---|---|
target_business_domain_id |
integer | 新创建的目标 BusinessDomain 节点 ID |
dataflow_id |
integer | 新创建的 DataFlow 节点 ID |
input_domain_ids |
array | 输入的 BusinessDomain 节点 ID 列表 |
状态不允许审批 (400):
{
"code": 400,
"message": "订单状态 pending 不允许审批,只有 ['pending_approval', 'manual_review'] 状态可以审批",
"data": null
}
const approveOrder = async (orderId, processedBy = 'admin') => {
try {
await ElMessageBox.confirm(
'确定要审批通过该订单吗?通过后将自动生成数据流程资源。',
'审批确认',
{ type: 'warning' }
)
const res = await request.post(`/api/dataservice/orders/${orderId}/approve`, {
processed_by: processedBy
})
ElMessage.success('审批通过,资源已生成')
// 可以显示生成的资源信息
console.log('生成的 DataFlow ID:', res.data.generated_resources.dataflow_id)
return res.data
} catch (error) {
if (error !== 'cancel') {
ElMessage.error(error.message || '审批失败')
}
}
}
驳回数据订单,需要提供驳回原因。
| 项目 | 说明 |
|---|---|
| URL | POST /api/dataservice/orders/{order_id}/reject |
| Method | POST |
| Content-Type | application/json |
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
order_id |
integer | 是 | 数据订单 ID |
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
reason |
string | 是 | - | 驳回原因 |
processed_by |
string | 否 | "admin" | 处理人标识 |
{
"reason": "需求描述不够清晰,请补充具体需要的数据字段和业务场景",
"processed_by": "管理员A"
}
{
"code": 200,
"message": "数据订单已驳回",
"data": {
"id": 1,
"order_no": "DO202601090001",
"status": "rejected",
"status_label": "已驳回",
"reject_reason": "需求描述不够清晰,请补充具体需要的数据字段和业务场景",
"processed_by": "管理员A",
"processed_at": "2026-01-09T10:00:00",
...
}
}
<template>
<el-dialog v-model="dialogVisible" title="驳回订单" width="500px">
<el-form :model="form" :rules="rules" ref="formRef">
<el-form-item label="驳回原因" prop="reason">
<el-input
v-model="form.reason"
type="textarea"
:rows="4"
placeholder="请输入驳回原因,将通知订单创建人"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="danger" @click="submitReject" :loading="rejecting">
确认驳回
</el-button>
</template>
</el-dialog>
</template>
<script setup>
import { ref, reactive } from 'vue'
import { ElMessage } from 'element-plus'
import request from '@/utils/request'
const emit = defineEmits(['success'])
const dialogVisible = ref(false)
const rejecting = ref(false)
const currentOrderId = ref(null)
const formRef = ref(null)
const form = reactive({
reason: ''
})
const rules = {
reason: [
{ required: true, message: '请输入驳回原因', trigger: 'blur' },
{ min: 5, message: '驳回原因至少5个字符', trigger: 'blur' }
]
}
const open = (order) => {
currentOrderId.value = order.id
form.reason = ''
dialogVisible.value = true
}
const submitReject = async () => {
const valid = await formRef.value.validate()
if (!valid) return
rejecting.value = true
try {
await request.post(`/api/dataservice/orders/${currentOrderId.value}/reject`, {
reason: form.reason
})
ElMessage.success('订单已驳回')
dialogVisible.value = false
emit('success')
} catch (error) {
ElMessage.error(error.message || '驳回失败')
} finally {
rejecting.value = false
}
}
defineExpose({ open })
</script>
数据工厂回调接口:当数据流程执行完成后,调用此接口将订单状态更新为"数据产品就绪"。
注意: 只允许从
processing状态转换为onboard状态。此接口通常由数据工厂(n8n 工作流)自动调用。
| 项目 | 说明 |
|---|---|
| URL | POST /api/dataservice/orders/{order_id}/onboard |
| Method | POST |
| Content-Type | application/json |
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
order_id |
integer | 是 | 数据订单 ID |
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
product_id |
integer | 否 | null | 生成的数据产品 ID |
dataflow_id |
integer | 否 | null | 数据流 ID |
processed_by |
string | 否 | "n8n-workflow" | 处理人标识 |
{
"product_id": 15,
"dataflow_id": 156,
"processed_by": "n8n-workflow-001"
}
{
"code": 200,
"message": "数据订单已设置为数据产品就绪状态",
"data": {
"id": 1,
"order_no": "DO202601090001",
"status": "onboard",
"status_label": "数据产品就绪",
"result_product_id": 15,
"result_dataflow_id": 156,
"processed_by": "n8n-workflow-001",
"processed_at": "2026-01-09T14:30:00",
...
}
}
状态不允许操作 (400):
{
"code": 400,
"message": "订单状态 pending_approval 不允许设置为 onboard,只有 processing 状态可以转换",
"data": null
}
// 此接口通常由后端/数据工厂调用,前端一般不直接调用
// 如需手动触发,可使用以下代码:
const setOrderOnboard = async (orderId, productId, dataflowId) => {
const res = await request.post(`/api/dataservice/orders/${orderId}/onboard`, {
product_id: productId,
dataflow_id: dataflowId,
processed_by: 'manual'
})
return res.data
}
将订单标记为最终完成状态。
注意: 只允许从
onboard(数据产品就绪)状态标记完成。
| 项目 | 说明 |
|---|---|
| URL | POST /api/dataservice/orders/{order_id}/complete |
| Method | POST |
| Content-Type | application/json |
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
order_id |
integer | 是 | 数据订单 ID |
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
processed_by |
string | 否 | "user" | 处理人标识 |
{
"processed_by": "张三"
}
{
"code": 200,
"message": "数据订单已完成",
"data": {
"id": 1,
"order_no": "DO202601090001",
"status": "completed",
"status_label": "已完成",
"result_product_id": 15,
"result_dataflow_id": 156,
"processed_by": "张三",
"processed_at": "2026-01-09T15:00:00",
...
}
}
状态不允许完成 (400):
{
"code": 400,
"message": "订单状态 processing 不允许标记完成,只有 onboard 状态可以标记完成",
"data": null
}
const completeOrder = async (orderId) => {
try {
await ElMessageBox.confirm(
'确定要标记该订单为完成吗?',
'完成确认',
{ type: 'info' }
)
const res = await request.post(`/api/dataservice/orders/${orderId}/complete`, {
processed_by: currentUser.value.name
})
ElMessage.success('订单已完成')
return res.data
} catch (error) {
if (error !== 'cancel') {
ElMessage.error(error.message || '操作失败')
}
}
}
删除数据订单记录(软删除)。
| 项目 | 说明 |
|---|---|
| URL | PUT /api/dataservice/orders/{order_id}/delete |
| Method | PUT |
| Content-Type | - |
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
order_id |
integer | 是 | 数据订单 ID |
{
"code": 200,
"message": "删除数据订单成功",
"data": {}
}
const deleteOrder = async (orderId) => {
try {
await ElMessageBox.confirm(
'确定要删除该订单吗?此操作不可恢复。',
'删除确认',
{ type: 'warning', confirmButtonClass: 'el-button--danger' }
)
await request.put(`/api/dataservice/orders/${orderId}/delete`)
ElMessage.success('删除成功')
} catch (error) {
if (error !== 'cancel') {
ElMessage.error(error.message || '删除失败')
}
}
}
建议将所有数据订单 API 封装到独立模块:
// src/api/dataOrder.js
import request from '@/utils/request'
const BASE_URL = '/api/dataservice'
export const dataOrderApi = {
/**
* 获取数据订单列表
*/
getOrders(params) {
return request.get(`${BASE_URL}/orderlist`, { params })
},
/**
* 获取数据订单详情
*/
getOrderDetail(orderId) {
return request.get(`${BASE_URL}/orders/${orderId}/detail`)
},
/**
* 创建数据订单
*/
createOrder(data) {
return request.post(`${BASE_URL}/neworder`, data)
},
/**
* 更新数据订单
*/
updateOrder(orderId, data) {
return request.put(`${BASE_URL}/orders/${orderId}/update`, data)
},
/**
* 分析数据订单
*/
analyzeOrder(orderId) {
return request.post(`${BASE_URL}/orders/${orderId}/analyze`)
},
/**
* 审批通过订单
*/
approveOrder(orderId, processedBy = 'admin') {
return request.post(`${BASE_URL}/orders/${orderId}/approve`, {
processed_by: processedBy
})
},
/**
* 驳回订单
*/
rejectOrder(orderId, reason, processedBy = 'admin') {
return request.post(`${BASE_URL}/orders/${orderId}/reject`, {
reason,
processed_by: processedBy
})
},
/**
* 设置数据产品就绪状态(数据工厂回调)
*/
setOrderOnboard(orderId, options = {}) {
return request.post(`${BASE_URL}/orders/${orderId}/onboard`, {
product_id: options.productId,
dataflow_id: options.dataflowId,
processed_by: options.processedBy || 'n8n-workflow'
})
},
/**
* 完成订单
*/
completeOrder(orderId, processedBy = 'user') {
return request.post(`${BASE_URL}/orders/${orderId}/complete`, {
processed_by: processedBy
})
},
/**
* 删除订单
*/
deleteOrder(orderId) {
return request.put(`${BASE_URL}/orders/${orderId}/delete`)
}
}
export default dataOrderApi
以下是一个完整的数据订单管理页面示例,包含完整的状态流转操作:
<!-- src/views/dataservice/DataOrderManage.vue -->
<template>
<div class="data-order-manage">
<!-- 页面标题 -->
<div class="page-header">
<h2>数据订单管理</h2>
<p class="page-description">
当您在数据服务列表中找不到所需数据时,可以创建数据订单提交您的数据需求。
</p>
</div>
<!-- 搜索栏 -->
<el-card class="search-card">
<el-form :inline="true" :model="searchParams">
<el-form-item label="搜索">
<el-input
v-model="searchParams.search"
placeholder="订单编号/标题/描述"
clearable
@keyup.enter="fetchOrders"
/>
</el-form-item>
<el-form-item label="状态">
<el-select v-model="searchParams.status" placeholder="全部" clearable>
<el-option
v-for="(label, value) in statusOptions"
:key="value"
:label="label"
:value="value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="fetchOrders">
<el-icon><Search /></el-icon> 查询
</el-button>
<el-button @click="resetSearch">重置</el-button>
<el-button type="success" @click="createDialogRef?.open()">
<el-icon><Plus /></el-icon> 新建订单
</el-button>
</el-form-item>
</el-form>
</el-card>
<!-- 数据表格 -->
<el-card class="table-card">
<el-table :data="orderList" v-loading="loading" border stripe>
<el-table-column prop="order_no" label="订单编号" width="160" fixed />
<el-table-column prop="title" label="标题" min-width="200" show-overflow-tooltip />
<el-table-column prop="status" label="状态" width="130" align="center">
<template #default="{ row }">
<el-tag :type="getStatusType(row.status)" effect="light">
{{ row.status_label }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="can_connect" label="可连通" width="90" align="center">
<template #default="{ row }">
<el-icon v-if="row.can_connect === true" color="#67C23A" :size="18">
<CircleCheck />
</el-icon>
<el-icon v-else-if="row.can_connect === false" color="#F56C6C" :size="18">
<CircleClose />
</el-icon>
<span v-else class="text-gray">-</span>
</template>
</el-table-column>
<el-table-column prop="created_by" label="创建人" width="100" />
<el-table-column prop="created_at" label="创建时间" width="170">
<template #default="{ row }">
{{ formatDate(row.created_at) }}
</template>
</el-table-column>
<el-table-column label="操作" width="300" fixed="right">
<template #default="{ row }">
<el-button size="small" @click="showDetail(row)">详情</el-button>
<!-- 待处理/待人工处理/待补充:可编辑和分析 -->
<el-button
v-if="canEdit(row.status)"
size="small"
@click="editDialogRef?.open(row)"
>
编辑
</el-button>
<el-button
v-if="canAnalyze(row.status)"
size="small"
type="primary"
@click="handleAnalyze(row)"
>
分析
</el-button>
<!-- 待审批/待人工处理:可审批和驳回 -->
<el-button
v-if="canApprove(row.status)"
size="small"
type="success"
@click="handleApprove(row)"
>
审批
</el-button>
<el-button
v-if="canReject(row.status)"
size="small"
type="warning"
@click="rejectDialogRef?.open(row)"
>
驳回
</el-button>
<!-- 数据产品就绪:可完成 -->
<el-button
v-if="row.status === 'onboard'"
size="small"
type="success"
@click="handleComplete(row)"
>
完成
</el-button>
<!-- 可删除状态 -->
<el-button
v-if="canDelete(row.status)"
size="small"
type="danger"
@click="handleDelete(row)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="pagination-wrapper">
<el-pagination
v-model:current-page="searchParams.page"
v-model:page-size="searchParams.page_size"
:total="pagination.total"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
@current-change="fetchOrders"
@size-change="fetchOrders"
/>
</div>
</el-card>
<!-- 子组件 -->
<CreateOrderDialog ref="createDialogRef" @success="fetchOrders" />
<EditOrderDialog ref="editDialogRef" @success="fetchOrders" />
<RejectOrderDialog ref="rejectDialogRef" @success="fetchOrders" />
<OrderDetailDrawer ref="detailDrawerRef" @refresh="fetchOrders" />
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus'
import { Search, Plus, CircleCheck, CircleClose } from '@element-plus/icons-vue'
import dayjs from 'dayjs'
import { dataOrderApi } from '@/api/dataOrder'
// 子组件引用
const createDialogRef = ref(null)
const editDialogRef = ref(null)
const rejectDialogRef = ref(null)
const detailDrawerRef = ref(null)
// 状态
const loading = ref(false)
const orderList = ref([])
const pagination = ref({ page: 1, page_size: 20, total: 0, total_pages: 0 })
// 搜索参数
const searchParams = reactive({
page: 1,
page_size: 20,
search: '',
status: ''
})
// 状态选项
const statusOptions = {
pending: '待处理',
analyzing: '分析中',
pending_approval: '待审批',
processing: '加工中',
onboard: '数据产品就绪',
completed: '已完成',
rejected: '已驳回',
need_supplement: '待补充',
manual_review: '待人工处理'
}
// 获取订单列表
const fetchOrders = async () => {
loading.value = true
try {
const params = { ...searchParams }
if (!params.status) delete params.status
if (!params.search) delete params.search
const res = await dataOrderApi.getOrders(params)
orderList.value = res.data.list
pagination.value = res.data.pagination
} finally {
loading.value = false
}
}
// 重置搜索
const resetSearch = () => {
searchParams.page = 1
searchParams.search = ''
searchParams.status = ''
fetchOrders()
}
// 状态判断函数
const canEdit = (status) => ['pending', 'manual_review', 'need_supplement'].includes(status)
const canAnalyze = (status) => ['pending', 'manual_review', 'need_supplement'].includes(status)
const canApprove = (status) => ['pending_approval', 'manual_review'].includes(status)
const canReject = (status) => ['pending_approval', 'manual_review'].includes(status)
const canDelete = (status) => ['pending', 'completed', 'rejected'].includes(status)
// 获取状态标签类型
const getStatusType = (status) => {
const types = {
pending: 'info',
analyzing: 'warning',
pending_approval: '',
processing: 'primary',
onboard: 'success',
completed: 'success',
rejected: 'danger',
need_supplement: 'warning',
manual_review: 'warning'
}
return types[status] || 'info'
}
// 格式化日期
const formatDate = (dateStr) => {
return dateStr ? dayjs(dateStr).format('YYYY-MM-DD HH:mm') : '-'
}
// 显示详情
const showDetail = (order) => {
detailDrawerRef.value?.open(order.id)
}
// 分析订单
const handleAnalyze = async (order) => {
const loadingInstance = ElLoading.service({
text: '正在分析订单,请稍候...',
background: 'rgba(0, 0, 0, 0.7)'
})
try {
const res = await dataOrderApi.analyzeOrder(order.id)
loadingInstance.close()
if (res.data.can_connect) {
ElMessage.success('分析完成,实体可连通,请进行审批确认!')
} else {
ElMessage.warning('分析完成,部分实体无法连通,请修改后重新分析')
}
fetchOrders()
} catch (error) {
loadingInstance.close()
ElMessage.error(error.message || '分析失败')
}
}
// 审批通过
const handleApprove = async (order) => {
try {
await ElMessageBox.confirm(
`确定要审批通过订单 "${order.title}" 吗?\n通过后将自动生成数据流程资源。`,
'审批确认',
{ type: 'info' }
)
const res = await dataOrderApi.approveOrder(order.id)
ElMessage.success(`审批通过,已生成 DataFlow ID: ${res.data.generated_resources.dataflow_id}`)
fetchOrders()
} catch (error) {
if (error !== 'cancel') {
ElMessage.error(error.message || '审批失败')
}
}
}
// 完成订单
const handleComplete = async (order) => {
try {
await ElMessageBox.confirm(
`确定要标记订单 "${order.title}" 为完成吗?`,
'完成确认',
{ type: 'info' }
)
await dataOrderApi.completeOrder(order.id)
ElMessage.success('订单已完成')
fetchOrders()
} catch (error) {
if (error !== 'cancel') {
ElMessage.error(error.message || '操作失败')
}
}
}
// 删除订单
const handleDelete = async (order) => {
try {
await ElMessageBox.confirm(
`确定要删除订单 "${order.title}" 吗?此操作不可恢复。`,
'删除确认',
{ type: 'warning', confirmButtonClass: 'el-button--danger' }
)
await dataOrderApi.deleteOrder(order.id) // 使用 PUT 方法调用 /delete 接口
ElMessage.success('删除成功')
fetchOrders()
} catch (error) {
if (error !== 'cancel') {
ElMessage.error(error.message || '删除失败')
}
}
}
onMounted(() => {
fetchOrders()
})
</script>
<style scoped>
.data-order-manage {
padding: 20px;
}
.page-header {
margin-bottom: 20px;
}
.page-header h2 {
margin: 0 0 8px 0;
font-size: 20px;
font-weight: 600;
}
.page-description {
color: #909399;
font-size: 14px;
margin: 0;
}
.search-card {
margin-bottom: 16px;
}
.table-card {
min-height: 400px;
}
.pagination-wrapper {
margin-top: 16px;
display: flex;
justify-content: flex-end;
}
.text-gray {
color: #909399;
}
</style>
A: 分析接口涉及 LLM 调用,可能需要较长时间。建议:
timeout(如 60 秒)manual_review?A: 当分析结果显示 can_connect: false 时,表示 LLM 提取的实体在业务领域图谱中无法完全连通,订单会变成 manual_review 状态,需要人工修改后重新分析。
A: 审批通过后系统会:
processingA: 只有以下状态的订单可以修改:
pending (待处理)manual_review (待人工处理)need_supplement (待补充)onboard 状态是如何触发的?A: onboard 状态通常由数据工厂(n8n 工作流)在数据流程执行完成后调用 /orders/{id}/onboard 接口触发。这表示数据产品已生产完成,可供使用。
A: 格式为 DO + YYYYMMDD + 4位序列号,例如 DO202601090001。每天的序列号从 0001 开始递增。
| 版本 | 日期 | 说明 |
|---|---|---|
| 2.1.0 | 2026-01-09 | 接口路径规范化:获取订单详情改为 /orders/{id}/detail;更新订单改为 /orders/{id}/update;删除订单改为 PUT /orders/{id}/delete(软删除) |
| 2.0.0 | 2026-01-09 | 重构订单流程:新增 pending_approval、onboard 状态;新增更新订单、onboard 回调接口;审批接口新增自动资源生成功能 |
| 1.0.0 | 2024-12-29 | 初始版本,包含完整的数据订单 API 文档 |