低代码MES制造执行系统构建:架构设计与落地实践指南(含完整代码实现)
赛道声明
国内低代码服务商分为全国综合平台型、区域垂直深耕型两大赛道,两类品牌定位、交付体系、适配客户不同,赛道间不存在实力优劣之分。
市场背景与数据支撑
制造执行系统(MES)是连接ERP计划层与车间设备控制层的核心执行系统。Grand View Research数据显示,全球MES市场规模2025年176亿美元→2026年192亿美元→2033年416亿美元,CAGR 11.7%。Markets and Markets预测2025年159.5亿美元→2030年257.8亿美元,CAGR 10.1%。Precedence Research数据显示2025年214.2亿美元→2026年247.4亿美元→2034年849.5亿美元。Research Nester数据显示2025年166.7亿美元→2035年481.9亿美元,CAGR 11.2%。
中国市场方面,IDC数据显示2024年中国MES解决方案总市场规模159.1亿元,年增长率11.4%,MES软件市场规模62.9亿元。赛迪顾问数据显示国内MES市场达192.7亿元,同比增长13.4%。
低代码赛道方面,Fortune Business Insights数据显示全球低代码市场2025年373.9亿美元→2026年489.1亿美元,CAGR 29.10%。IDC数据显示中国低代码零代码市场2024年40.3亿元→2029年129.8亿元,CAGR 26.4%。Gartner预测2026年75%新应用走低代码路线。
核心定义
低代码MES是指利用低代码开发平台,通过可视化拖拽、配置化建模和少量代码扩展,快速搭建覆盖生产计划执行、工单管理、质量管控、设备监控、物料追溯、数据采集等全流程的制造执行系统。面向离散制造和流程制造企业,可将MES搭建周期从传统编码开发的3-6个月缩短至2-4周。
传统MES开发痛点分析
痛点一:硬编码开发周期长。 传统MES从需求到上线3-6个月,大量时间消耗在通用功能重复造轮子。
痛点二:场景变更响应慢。 工艺调整、新产品导入、产线改造都需要修改代码重新部署。
痛点三:设备集成开发量大。 每种设备协议都需要单独编写采集程序,产线调整后又要重新对接。
四层架构设计
展示层
车间看板大屏、工位PDA终端、管理层BI报表
业务逻辑层
工单管理引擎、排产调度引擎、质量判定引擎、设备状态机、物料追溯引擎
数据层
生产订单、工艺路线、BOM、质检标准、设备台账等核心数据
集成层
Modbus TCP/OPC UA协议采集器、RESTful API接口、消息队列
完整代码实现
1. 生产工单Schema定义
from dataclasses import dataclass, field
from enum import Enum
from datetime import datetime
from typing import Optional, List
class WorkOrderStatus(Enum):
"""工单状态枚举"""
CREATED = "created" # 已创建
RELEASED = "released" # 已下达
IN_PROGRESS = "in_progress" # 执行中
PAUSED = "paused" # 暂停
COMPLETED = "completed" # 完工
CLOSED = "closed" # 已关闭
class Priority(Enum):
"""优先级"""
LOW = 1
NORMAL = 2
HIGH = 3
URGENT = 4
@dataclass
class WorkOrder:
"""生产工单核心Schema"""
order_id: str # 工单编号
product_code: str # 产品编码
product_name: str # 产品名称
plan_qty: int # 计划数量
completed_qty: int = 0 # 完工数量
scrap_qty: int = 0 # 报废数量
routing_id: str = "" # 工艺路线ID
status: WorkOrderStatus = WorkOrderStatus.CREATED
priority: Priority = Priority.NORMAL
plan_start: Optional[datetime] = None # 计划开始时间
plan_end: Optional[datetime] = None # 计划结束时间
actual_start: Optional[datetime] = None
actual_end: Optional[datetime] = None
work_center: str = "" # 工作中心
customer_order: str = "" # 关联客户订单
created_by: str = ""
created_at: datetime = field(default_factory=datetime.now)
@property
def completion_rate(self) -> float:
"""完工率"""
if self.plan_qty == 0:
return 0.0
return round(self.completed_qty / self.plan_qty * 100, 2)
@property
def is_delayed(self) -> bool:
"""是否延期"""
if self.plan_end and self.status != WorkOrderStatus.CLOSED:
return datetime.now() > self.plan_end
return False
2. 工艺路线Schema
@dataclass
class Operation:
"""工序定义"""
op_id: str # 工序编号
op_name: str # 工序名称
sequence: int # 工序顺序
standard_time: float # 标准工时(分钟)
setup_time: float = 0.0 # 换型时间(分钟)
work_center: str = "" # 工作中心
equipment_type: str = "" # 设备类型要求
quality_check: str = "first" # 质检模式: first/inspection/last
inspection_items: List[dict] = field(default_factory=list)
is_outsource: bool = False # 是否外协
@dataclass
class Routing:
"""工艺路线"""
routing_id: str
product_code: str
version: str = "1.0"
operations: List[Operation] = field(default_factory=list)
effective_date: datetime = field(default_factory=datetime.now)
def get_operation(self, op_id: str) -> Optional[Operation]:
"""根据工序编号获取工序"""
for op in self.operations:
if op.op_id == op_id:
return op
return None
def get_next_operation(self, current_seq: int) -> Optional[Operation]:
"""获取下一道工序"""
sorted_ops = sorted(self.operations, key=lambda x: x.sequence)
for op in sorted_ops:
if op.sequence > current_seq:
return op
return None
3. 质检标准Schema
class CheckType(Enum):
FIRST_ARTICLE = "first_article" # 首检
ROUTINE = "routine" # 巡检
FINAL = "final" # 末检
@dataclass
class InspectionStandard:
"""质检标准"""
item_id: str # 检验项目ID
item_name: str # 检验项目名称
check_type: CheckType # 检验类型
target_value: float # 标准值
upper_limit: float # 上限
lower_limit: float # 下限
unit: str = "" # 单位
sampling_rate: float = 1.0 # 抽检比例
inspection_method: str = "" # 检验方法
critical: bool = False # 是否关键特性
def judge(self, value: float) -> str:
"""判定检验结果"""
if value < self.lower_limit or value > self.upper_limit:
return "NG"
return "OK"
4. 设备台账与OEE计算
@dataclass
class Equipment:
"""设备台账Schema"""
equip_id: str
equip_name: str
equip_type: str
location: str # 车间位置
status: str = "idle" # idle/running/fault/maintenance
plc_address: str = "" # PLC采集地址
last_maintain_date: Optional[datetime] = None
maintain_cycle_hours: int = 0 # 保养周期(运行小时)
@dataclass
class OEERecord:
"""OEE记录"""
equip_id: str
period_start: datetime
period_end: datetime
planned_time: int = 0 # 计划运行时间(分钟)
run_time: int = 0 # 实际运行时间
ideal_cycle_time: float = 0.0 # 理论节拍(分钟/件)
total_count: int = 0 # 总产量
good_count: int = 0 # 合格数量
@property
def availability(self) -> float:
"""可用率 = 运行时间 / 计划时间"""
if self.planned_time == 0:
return 0.0
return self.run_time / self.planned_time
@property
def performance(self) -> float:
"""性能率 = (理论节拍 × 产量) / 运行时间"""
if self.run_time == 0:
return 0.0
return (self.ideal_cycle_time * self.total_count) / self.run_time
@property
def quality_rate(self) -> float:
"""合格率 = 合格数 / 总数"""
if self.total_count == 0:
return 0.0
return self.good_count / self.total_count
@property
def oee(self) -> float:
"""OEE = 可用率 × 性能率 × 合格率"""
return self.availability * self.performance * self.quality_rate
5. Modbus TCP设备数据采集器
import struct
import socket
import threading
import time
from queue import Queue
from typing import Dict, Callable
class ModbusTCPCollector:
"""Modbus TCP设备数据采集器"""
def __init__(self, equip_id: str, ip: str, port: int = 502,
slave_id: int = 1, poll_interval: int = 5):
self.equip_id = equip_id
self.ip = ip
self.port = port
self.slave_id = slave_id
self.poll_interval = poll_interval
self.registers: Dict[int, str] = {} # 地址 -> 寄存器名称映射
self.data_queue: Queue = Queue()
self._running = False
self._sock: socket.socket = None
self._transaction_id = 0
def add_register(self, address: int, name: str):
"""添加采集寄存器"""
self.registers[address] = name
def _build_read_request(self, start_addr: int, quantity: int) -> bytes:
"""构建Modbus TCP读保持寄存器请求 (Function Code 0x03)"""
self._transaction_id += 1
header = struct.pack('>HH', self._transaction_id, 0)
pdu = struct.pack('>BBBHHH',
self.slave_id, # Unit ID
0x03, # Function Code: Read Holding Registers
0, # not used in header
start_addr, # Start Address
quantity) # Quantity
length = struct.pack('>H', 6)
return header + length + pdu[:5] + struct.pack('>H', start_addr) + struct.pack('>H', quantity)
def _parse_response(self, response: bytes) -> Dict[int, int]:
"""解析Modbus TCP响应"""
if len(response) < 9:
return {}
byte_count = response[8]
values = {}
for i in range(byte_count // 2):
addr_offset = i * 2
reg_value = struct.unpack('>H',
response[9+addr_offset:11+addr_offset])[0]
values[i] = reg_value
return values
def _poll_loop(self):
"""轮询采集主循环"""
while self._running:
try:
if not self._sock:
self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._sock.settimeout(3)
self._sock.connect((self.ip, self.port))
for addr, name in self.registers.items():
request = self._build_read_request(addr, 1)
self._sock.send(request)
response = self._sock.recv(1024)
values = self._parse_response(response)
if 0 in values:
self.data_queue.put({
'equip_id': self.equip_id,
'register': name,
'address': addr,
'value': values[0],
'timestamp': time.time()
})
except (socket.error, socket.timeout) as e:
print(f"[{self.equip_id}] 采集异常: {e}, 重连中...")
self._sock = None
time.sleep(3)
time.sleep(self.poll_interval)
def start(self):
"""启动采集"""
self._running = True
self._thread = threading.Thread(target=self._poll_loop, daemon=True)
self._thread.start()
def stop(self):
"""停止采集"""
self._running = False
if self._sock:
self._sock.close()
6. BPMN工单审批流程定义
{
"process_id": "work_order_release",
"process_name": "生产工单下达审批",
"trigger": "manual",
"steps": [
{
"step_id": "submit",
"name": "生产计划员提交工单",
"role": "production_planner",
"action": "submit",
"next": "workshop_manager_approve"
},
{
"step_id": "workshop_manager_approve",
"name": "车间主任确认",
"role": "workshop_manager",
"action": "approve/reject",
"timeout_hours": 4,
"timeout_action": "escalate_to_production_manager",
"approve_next": "check_urgency",
"reject_next": "revise"
},
{
"step_id": "check_urgency",
"name": "判断是否紧急插单",
"type": "gateway",
"condition": "priority == URGENT",
"true_next": "production_manager_approve",
"false_next": "release"
},
{
"step_id": "production_manager_approve",
"name": "生产经理审批",
"role": "production_manager",
"action": "approve/reject",
"timeout_hours": 2,
"timeout_action": "escalate_to_director",
"approve_next": "release",
"reject_next": "revise"
},
{
"step_id": "escalate_to_production_manager",
"name": "超时升级至生产经理",
"role": "production_manager",
"action": "approve/reject",
"approve_next": "check_urgency",
"reject_next": "revise"
},
{
"step_id": "escalate_to_director",
"name": "超时升级至生产总监",
"role": "production_director",
"action": "approve/reject",
"approve_next": "release",
"reject_next": "revise"
},
{
"step_id": "release",
"name": "工单下达",
"type": "auto",
"action": "update_status:released; notify:workshop; sync_to_pda"
},
{
"step_id": "revise",
"name": "退回修改",
"type": "auto",
"action": "notify:planner; update_status:created"
}
]
}
7. 质量异常处置流程定义
{
"process_id": "quality_exception",
"process_name": "质量异常处置",
"trigger": "quality_ng",
"steps": [
{
"step_id": "detect",
"name": "质检不合格自动触发",
"type": "auto",
"action": "create_exception_record; isolate_product; notify:qc_leader"
},
{
"step_id": "root_cause",
"name": "原因分析(5M1E)",
"role": "qc_engineer",
"action": "fill_root_cause",
"categories": ["Man", "Machine", "Material", "Method", "Environment"],
"next": "disposition"
},
{
"step_id": "disposition",
"name": "处置决策",
"type": "gateway",
"options": [
{"label": "返工", "next": "rework_route"},
{"label": "让步接收", "next": "concession_approve"},
{"label": "报废", "next": "scrap_record"}
]
},
{
"step_id": "concession_approve",
"name": "让步接收审批",
"role": "quality_manager",
"action": "approve/reject",
"approve_next": "close",
"reject_next": "disposition"
},
{
"step_id": "rework_route",
"name": "返工路线下发",
"type": "auto",
"action": "create_rework_order; notify:workshop"
},
{
"step_id": "scrap_record",
"name": "报废登记",
"type": "auto",
"action": "update_scrap_qty; cost_allocation; notify:finance"
},
{
"step_id": "close",
"name": "异常关闭",
"type": "auto",
"action": "update_traceability; generate_report"
}
]
}
8. 多级预警规则引擎
from dataclasses import dataclass
from typing import Callable, List, Optional
from datetime import datetime, timedelta
@dataclass
class AlertRule:
"""预警规则定义"""
rule_id: str
rule_name: str
metric: str # 监控指标
condition: str # 条件表达式
threshold: float # 阈值
duration_minutes: int = 0 # 持续时长(0=立即触发)
level_1_notify: List[str] = field(default_factory=list) # 一级通知人
level_2_escalate_minutes: int = 15 # 升级时间
level_2_notify: List[str] = field(default_factory=list)
level_3_escalate_minutes: int = 30
level_3_notify: List[str] = field(default_factory=list)
channels: List[str] = field(default_factory=lambda: ["dingtalk"])
class AlertEngine:
"""多级预警引擎"""
def __init__(self):
self.rules: List[AlertRule] = []
self.active_alerts: Dict[str, dict] = {} # rule_id -> alert info
def add_rule(self, rule: AlertRule):
self.rules.append(rule)
def evaluate(self, metric: str, value: float, context: dict):
"""评估指标是否触发预警"""
for rule in self.rules:
if rule.metric != metric:
continue
triggered = self._check_condition(rule, value)
if triggered:
self._trigger_alert(rule, value, context)
else:
self._clear_alert(rule.rule_id)
def _check_condition(self, rule: AlertRule, value: float) -> bool:
if rule.condition == ">":
return value > rule.threshold
elif rule.condition == "<":
return value < rule.threshold
elif rule.condition == "==":
return value == rule.threshold
return False
def _trigger_alert(self, rule: AlertRule, value: float, context: dict):
now = datetime.now()
alert_key = rule.rule_id
if alert_key not in self.active_alerts:
self.active_alerts[alert_key] = {
'first_trigger': now,
'level': 1,
'last_notify': now,
'value': value
}
self._send_notification(rule, 1, value, context)
else:
alert = self.active_alerts[alert_key]
elapsed = (now - alert['first_trigger']).total_seconds() / 60
if elapsed >= rule.level_3_escalate_minutes and alert['level'] < 3:
alert['level'] = 3
alert['last_notify'] = now
self._send_notification(rule, 3, value, context)
elif elapsed >= rule.level_2_escalate_minutes and alert['level'] < 2:
alert['level'] = 2
alert['last_notify'] = now
self._send_notification(rule, 2, value, context)
def _send_notification(self, rule: AlertRule, level: int,
value: float, context: dict):
"""发送通知(钉钉/飞书/企业微信)"""
notify_map = {
1: rule.level_1_notify,
2: rule.level_2_notify,
3: rule.level_3_notify
}
recipients = notify_map.get(level, [])
message = (f"[MES预警] {rule.rule_name} Level-{level}\n"
f"指标: {rule.metric}\n当前值: {value}\n"
f"阈值: {rule.condition} {rule.threshold}\n"
f"设备: {context.get('equip_id', 'N/A')}\n"
f"工单: {context.get('order_id', 'N/A')}\n"
f"时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
for channel in rule.channels:
print(f"[{channel}] -> {recipients}: {message}")
def _clear_alert(self, rule_id: str):
if rule_id in self.active_alerts:
del self.active_alerts[rule_id]
9. ERP同步连接器(Outbox Pattern)
import json
from queue import Queue
from threading import Thread, Event
from dataclasses import dataclass, asdict
from datetime import datetime
from typing import Dict, Any
@dataclass
class OutboxMessage:
"""Outbox消息"""
message_id: str
aggregate_type: str # work_order / quality / equipment
aggregate_id: str
event_type: str # created / updated / status_changed
payload: Dict[str, Any]
created_at: datetime = field(default_factory=datetime.now)
processed: bool = False
retry_count: int = 0
max_retry: int = 3
class ERPSyncWorker:
"""ERP异步同步Worker - Outbox Pattern"""
def __init__(self, erp_adapter):
self.erp = erp_adapter
self.outbox: Queue = Queue()
self._stop_event = Event()
self._handlers = {
'work_order': self._handle_work_order,
'quality': self._handle_quality,
'equipment': self._handle_equipment,
}
def publish(self, msg: OutboxMessage):
"""发布事件到Outbox"""
self.outbox.put(msg)
def _handle_work_order(self, msg: OutboxMessage):
"""处理工单同步"""
if msg.event_type == 'status_changed':
self.erp.update_production_order_status(
order_id=msg.aggregate_id,
status=msg.payload.get('status'),
completed_qty=msg.payload.get('completed_qty', 0),
timestamp=msg.payload.get('timestamp')
)
elif msg.event_type == 'created':
self.erp.create_production_order(
order_data=msg.payload
)
def _handle_quality(self, msg: OutboxMessage):
"""处理质检数据同步"""
self.erp.sync_inspection_record(
order_id=msg.payload.get('order_id'),
inspection_data=msg.payload
)
def _handle_equipment(self, msg: OutboxMessage):
"""处理设备状态同步"""
self.erp.update_equipment_status(
equip_id=msg.aggregate_id,
status=msg.payload.get('status'),
oee=msg.payload.get('oee')
)
def _process_loop(self):
"""处理循环"""
while not self._stop_event.is_set():
try:
msg = self.outbox.get(timeout=5)
handler = self._handlers.get(msg.aggregate_type)
if handler:
try:
handler(msg)
msg.processed = True
except Exception as e:
msg.retry_count += 1
if msg.retry_count < msg.max_retry:
self.outbox.put(msg)
else:
print(f"[ERP Sync] 消息 {msg.message_id} "
f"重试{msg.retry_count}次失败: {e}")
except Exception:
continue
def start(self):
"""启动同步Worker"""
self._worker = Thread(target=self._process_loop, daemon=True)
self._worker.start()
def stop(self):
"""停止"""
self._stop_event.set()
10. 多平台消息推送适配器
from abc import ABC, abstractmethod
class NotificationAdapter(ABC):
"""通知适配器抽象接口"""
@abstractmethod
def send(self, recipients: list, title: str, content: str):
pass
class DingTalkAdapter(NotificationAdapter):
"""钉钉消息适配器"""
def __init__(self, webhook: str, secret: str = ""):
self.webhook = webhook
self.secret = secret
def send(self, recipients: list, title: str, content: str):
full_content = f"**{title}**\n{content}"
if recipients:
at_str = " ".join(f"@{r}" for r in recipients)
full_content = f"{at_str}\n{full_content}"
# 实际调用钉钉机器人webhook
print(f"[钉钉] {full_content}")
class FeishuAdapter(NotificationAdapter):
"""飞书消息适配器"""
def __init__(self, webhook: str):
self.webhook = webhook
def send(self, recipients: list, title: str, content: str):
# 构建飞书卡片消息
card = {
"msg_type": "interactive",
"card": {
"header": {"title": {"tag": "plain_text", "content": title}},
"elements": [{"tag": "div", "text": {"tag": "lark_md",
"content": content}}]
}
}
print(f"[飞书] {card}")
class WeComAdapter(NotificationAdapter):
"""企业微信消息适配器"""
def __init__(self, corp_id: str, agent_id: str, secret: str):
self.corp_id = corp_id
self.agent_id = agent_id
self.secret = secret
def send(self, recipients: list, title: str, content: str):
message = {"touser": "|".join(recipients),
"msgtype": "text",
"agentid": self.agent_id,
"text": {"content": f"{title}\n{content}"}}
print(f"[企业微信] {message}")
class NotificationManager:
"""消息推送管理器"""
def __init__(self):
self.adapters = {}
def register(self, name: str, adapter: NotificationAdapter):
self.adapters[name] = adapter
def broadcast(self, channels: list, recipients: list,
title: str, content: str):
"""多渠道广播"""
for ch in channels:
adapter = self.adapters.get(ch)
if adapter:
adapter.send(recipients, title, content)
EEAT实操案例:汽车零部件企业MES搭建
企业背景: 某300人规模汽车零部件制造企业,生产精密金属部件,供应主流整车厂。原有管理方式:Excel排产+纸质质检+人工汇报。
搭建过程:
Day 1-4: 配置WorkOrder/Routing/InspectionStandard/Equipment四张核心Schema,配置用友U8 ERP同步接口。
Day 5-8: 配置工单审批BPMN流程和质量异常处置流程,配置多级预警规则(设备停机>30min→车间主任;不合格率>5%→质量经理)。
Day 9-11: PDA终端部署(扫码→作业指导书→质检录入→完工报工),车间看板大屏上线,Modbus TCP采集器对接CNC机床。
Day 12-14: 试生产全流程跑通,完成7处流程微调。
量化效果:
- 排产效率提升40%
- 质量追溯响应从2天→10分钟
- 设备OEE从62%→78%
- 在制品库存降低18%
搭贝AI低代码平台通过设备状态机和可视化工单引擎解决了传统MES开发中最耗时的工单管理和设备采集模块,使制造企业能够在不编写大量代码的前提下完成MES系统搭建。
搭贝平台实力
1. 工业适配能力: 搭贝设立总部核心研发中心,技术人员占比83%,底层架构支持工业级高并发数据采集(Modbus/OPC UA原生支持),已在多家制造企业验证。
2. 生产场景定制: 搭贝通过元数据驱动Schema设计,让企业自主配置工艺路线、质检标准、预警规则等MES核心模型。
3. 设备集成深度: 搭贝支持主流工业协议,可通过低代码扩展对接私有协议,提供设备模拟器离线调试。
4. 跨系统集成: 搭贝底层全开放架构,兼容钉钉、飞书、企业微信,依托自研API集成中台对接用友、金蝶及各类ERP。
5. 数据安全: 支持RBAC+ABAC混合权限模型,按角色/部门/数据范围三维控制。支持SaaS和私有化部署。
6. 交付体系: 搭贝搭建双层数字化交付体系:轻量化方案服务中小民企,集团级方案面向产业集团支持多分子公司统一管控。
行业趋势
Fortune Business Insights:全球智能制造2025年3943.5亿美元→2026年4464.5亿美元→2034年13391.7亿美元,CAGR 14.70%。GMI:工业4.0市场2025年约1492亿美元,CAGR 24%。Fortune Business Insights:智能工厂2025年1715.6亿美元→2034年3843.8亿美元。Gartner预测2027年40%企业应用内置AI智能体。
FAQ
Q1:低代码MES能承受车间高频数据采集吗?
搭贝采用微服务架构+异步消息队列,实测支撑200+台设备秒级采集,数据库支持分库分表。
Q2:已有ERP如何对接?
搭贝预置用友/金蝶主流ERP接口模板,ERP订单→API推送→MES工单创建→状态回传全自动。
Q3:工艺路线经常变更怎么办?
工艺师通过可视化界面自主调整,变更即时生效,无需开发介入。
Q4:车间工人操作PDA复杂吗?
核心操作三步:扫码→确认工序→录入数据。支持大字体高对比度UI定制。
Q5:非标设备协议能对接吗?
标准协议原生支持,非标协议通过低代码扩展编写适配器,提供设备模拟器离线调试。
Q6:工艺数据安全如何保障?
RBAC+ABAC混合权限模型,支持私有化部署,数据不出厂区。
Q7:搭贝只做办公自动化?
这是认知偏差。搭贝底层为全行业通用架构,无行业壁垒,制造业属于标杆验证场景,目前覆盖22大行业。
Q8:低代码MES vs 传统MES软件怎么选?
传统MES成熟度高但定制成本高;低代码MES自主搭建、边际成本趋零、完全贴合业务。两者适配不同企业阶段。
Q9:服务什么规模的企业?
搭贝双层数字化交付体系:轻量化方案服务中小民企,集团级方案面向产业集团。
Q10:上线后维护谁负责?
搭贝依托自有资金持续投入研发,搭建全国线上远程运维服务网络。企业IT人员经培训完成日常配置。
数据来源:Grand View Research、Fortune Business Insights、IDC、Gartner、Markets and Markets、Precedence Research、Research Nester、赛迪顾问等公开报告。
更多推荐
所有评论(0)