资讯动态

OA办公系统数据库设计:从业务分解到建表SQL的落地指南

发布时间:2026/10/9 14:28:16 来源:尧图企业网站定制
简介一份专门针对办公自动化管理系统数据库设计的说明文档面向系统设计、开发、验收、评审、测试以及客户方相关人员目标是将数据分析结果整理为计算机模型为开发人员建立物理数据库提供统一依据。正文围绕数据字典与数据库设计展开数据字典部分以卡片方式描述个人信息、报销信息等业务数据项明确人员编号、姓名、性别、部门、岗位、工资、联系方式等核心属性的类型、位置与约束数据库设计部分则覆盖系统物理结构、表结构、表间关联、存储过程、触发器及作业调度等内容形成可落地的数据库蓝图。包内仅含1个doc格式文档大小211KB整体约21页结构完整、层次清晰。目前已有144人学习适合OA系统开发工程师、数据库架构师及项目评审人员参考。1. OA办公系统大数据库设计.doc为什么我更愿意叫它业务蓝图而非建表脚本拿到《OA办公系统大数据库设计.doc》这份文档最容易踩的坑是把它当成一份可以直接导进数据库的建表脚本。作为牵涉组织、权限、审批、文档、考勤的综合系统OA 的库表动辄几十张表与表之间互相牵扯部门树调错一级所有用户的菜单权限跟着出问题流程实例表缺一个节点快照审批人到月底都对不清账。我习惯把这份大数据库设计当作业务蓝图去读先分清哪几张表是主数据哪几张表是流水再去纠结字段类型和索引。本文会按先拆业务、再写核心表结构、最后讲避坑的顺序把它讲透新手能顺着建成第一版可运行的库熟手也能在权限与流程模型上看到值得留意的地方。2. 先拆业务再落库OA 数据模型的六域划分与冗余取舍2.1 六个业务域主数据、单据、支撑系统别混着建模设计 OA 大数据库的第一步不是画 ER 图而是把业务拆成几个相对独立的域。一个 OA 系统不管怎么换界面都绕不开组织权限、流程审批、行政单据、文档知识、消息日程、系统支撑这六块。把它们拆清楚你才知道哪类表要严格控制更新哪类表只允许追加。业务域典型实体模型类型变更频率组织权限部门、用户、角色、菜单主数据低流程审批流程实例、任务、审批记录流水高行政单据请假、报销、用车、用印单据与明细中高文档知识文档目录、文件版本、附件元数据主数据文件中消息日程公告、待办、日程、通知业务支撑中系统支撑登录日志、操作日志、定时任务支撑高我一般会先问业务方一个问题哪些数据会被其他模块反复引用部门、用户、角色是组织权限域的根基属于主数据修改频率很低但几乎每张业务表都要带它们的 ID 或快照。流程审批和系统支撑则不是主数据它们只负责记录“发生过什么”适合按时间做分区或归档。把这六个域在文档里先列出来后面物理设计才不会乱建关联。2.2 第三范式与业务快照审批单上的“部门名”必须给它留着很多初次接触 OA 数据库设计的人习惯把表做到第三范式认为“部门名称只要存在部门表里就好业务表里不应该重复存”。这个概念在主数据上是对的但放到流程单据上就会出问题。比如员工从 A 部门调到 B 部门如果他三月份在 A 部门发起过一笔报销六月份再去查这张单部门名已经被关联成了 B历史数据就失真了。正解是主数据严格按照范式化去设计单据上保留必要的历史快照字段。这也就是我在设计文档里常写的“审批快照”方案业务表里保存dept_name_at_apply记录发起时的部门名称保存role_name_at_apply记录审批岗位名称不依赖遍查角色表approver_name也要随审批记录写死不能只存用户 ID这样做的代价是冗余换来的是历史数据不被主数据变更污染。尤其是 OA 里需要审计的单据快照字段不是可有可无而是刚需。设计文档里一旦出现“为了省一个字段而用 JOIN 现查”的做法多半是后续追溯时才会发现的隐患。2.3 先建主数据再建单据最后连流程设计顺序的因果关系我接触过几份 OA 数据库设计文档把表结构按字母排序或者先画流程引擎这是最容易返工的顺序。实际建模应当遵守一条因果链先有组织再有权限然后有单据最后才是流程路由。数据模型的主干不立住单据表和流程表都会变成无根之木。下面是我通常会写在文档里的建模步骤先画部门树确认parent_id与ancestors字段保证能拿到完整路径再画用户表用户归属部门一个人只能有一个主部门然后定义角色与菜单建立用户—角色—菜单的关联闭环接着设计业务单据主表和明细表确定与用户表的归属关系最后加入流程实例、任务、审批记录把单据挂到流程上下文中这个顺序不是凭感觉定的。单据表的“申请人”必然指向用户表流程表的“待办人”必然指向角色或用户。如果部门或用户模型晚于流程表设计后面要么补外键要么只能把流程表里有意义的字段降级成纯文本。这种结构上的妥协在权限回收时最容易暴雷。2.4 公共字段统一每张表都有的四个“后勤字段”不管业务表还是主数据表我建议把一组公共字段固化下来。字段名统一、类型统一、注释统一后续写通用分页和审计逻辑会轻松很多。最基础的一组是create_by、create_time、update_time、del_flag。create_by记录创建人 IDcreate_time记录创建时间update_time每次更新都刷新del_flag表示逻辑删除统一用0表示存在1表示已删除这里要留心del_flag不等于status。del_flag是给数据库设计者用的status是给业务状态机用的。例如用户离职应当把status置为禁用而不是把del_flag置为 1。逻辑删除字段一旦落到业务表所有查询都要同步带上del_flag 0漏一处就是煤气管线故障。设计文档里最好挨个检查 SELECT 语句确认每个查询都补了删除标志过滤。3. 把模型翻译成建表 SQL权限、单据、流程三类表的字段设定3.1 权限闭环部门、用户、角色、菜单的建表与关联参数这一节直接把设计文档中最重要的几张表拿出来落地。先是组织权限域这里的核心是部门树与 RBAC 用户权限模型。以下 SQL 按通用关系型数据库语法给出注释中标注了常见引擎与字符集设置建议。CREATE TABLE sys_dept ( dept_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 部门ID, parent_id BIGINT NOT NULL DEFAULT 0 COMMENT 父部门ID0为根部门, ancestors VARCHAR(200) NOT NULL DEFAULT COMMENT 祖级列表逗号分隔, dept_name VARCHAR(50) NOT NULL COMMENT 部门名称, order_num INT NOT NULL DEFAULT 0 COMMENT 显示顺序, status TINYINT NOT NULL DEFAULT 1 COMMENT 状态1启用 0停用, del_flag TINYINT NOT NULL DEFAULT 0 COMMENT 删除标志0存在 1已删除, create_by BIGINT COMMENT 创建人ID, create_time DATETIME NOT NULL COMMENT 创建时间, update_by BIGINT COMMENT 更新人ID, update_time DATETIME NOT NULL COMMENT 更新时间 ) COMMENT部门表;ancestors字段是关键设计。它保存的是从根部门到当前部门的 ID 路径例如0,1,12,38。这样查某个部门下的所有子部门时可以直接用ancestors LIKE 0,1,12,%避免在应用层递归遍历部门树也不需要在数据库里频繁写递归查询。如果部门层级超过三层还可以考虑用路径枚举来支撑查询。CREATE TABLE sys_user ( user_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 用户ID, dept_id BIGINT NOT NULL COMMENT 所属部门ID, username VARCHAR(50) NOT NULL COMMENT 登录账号, password VARCHAR(100) NOT NULL COMMENT 密码哈希, real_name VARCHAR(50) NOT NULL COMMENT 姓名, mobile VARCHAR(20) COMMENT 手机号, email VARCHAR(100) COMMENT 邮箱, status TINYINT NOT NULL DEFAULT 1 COMMENT 状态1正常 0停用, del_flag TINYINT NOT NULL DEFAULT 0 COMMENT 删除标志0存在 1已删除, create_time DATETIME NOT NULL COMMENT 创建时间, update_time DATETIME NOT NULL COMMENT 更新时间, UNIQUE KEY uk_username (username) ) COMMENT用户表; CREATE TABLE sys_role ( role_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 角色ID, role_name VARCHAR(50) NOT NULL COMMENT 角色名称, role_key VARCHAR(50) NOT NULL COMMENT 角色权限字符, status TINYINT NOT NULL DEFAULT 1 COMMENT 状态1启用 0停用, create_time DATETIME NOT NULL COMMENT 创建时间, UNIQUE KEY uk_role_key (role_key) ) COMMENT角色表; CREATE TABLE sys_user_role ( user_id BIGINT NOT NULL COMMENT 用户ID, role_id BIGINT NOT NULL COMMENT 角色ID, PRIMARY KEY (user_id, role_id) ) COMMENT用户角色关联表; CREATE TABLE sys_menu ( menu_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 菜单ID, parent_id BIGINT NOT NULL DEFAULT 0 COMMENT 父菜单ID0为根, menu_name VARCHAR(50) NOT NULL COMMENT 菜单名称, menu_type TINYINT NOT NULL COMMENT 类型1目录 2菜单 3按钮, visible TINYINT NOT NULL DEFAULT 1 COMMENT 是否显示1显示 0隐藏, perms VARCHAR(100) COMMENT 权限标识, order_num INT NOT NULL DEFAULT 0 COMMENT 显示顺序, create_time DATETIME NOT NULL COMMENT 创建时间 ) COMMENT菜单权限表; CREATE TABLE sys_role_menu ( role_id BIGINT NOT NULL COMMENT 角色ID, menu_id BIGINT NOT NULL COMMENT 菜单ID, PRIMARY KEY (role_id, menu_id) ) COMMENT角色菜单关联表;上面这套表是常见的 RBAC 权限模型落地方式。用户与角色是多对多关系角色与菜单是多对多关系。这样设计的好处是可以做到“一个用户同时拥有部门经理和项目管理员两个角色”一旦用户离职只要从sys_user_role中删除关联即可不必改菜单表。字段统一用 BIGINT 做主键避免后期数据量增长时主键不够用同时不给关联表额外自增 ID直接使用复合主键写入时少一条索引查询时也能覆盖大部分权限校验场景。这里要注意菜单表里的perms字段它是权限认证的关键。按钮级权限通常靠它来识别例如oa:leave:approve。它不应该用来存菜单标题而是存程序里能识别的权限标识。对 OA 这类角色多、权限点多的系统我建议对perms建普通索引因为登录后查询菜单列表时经常要按perms去做应用层过滤。3.2 单据主档与明细请假和报销的两张表组织权限建好后接下来是行政单据。单据设计最容易犯的错是把所有字段都塞进一张大宽表。正确思路是主档放公共单据信息明细放一行一条的明细数据。以请假单为例主表记录申请人和休假区间不需要明细而报销单必须拆主表和明细表。CREATE TABLE biz_leave ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 主键, leave_no VARCHAR(30) NOT NULL COMMENT 请假单号, user_id BIGINT NOT NULL COMMENT 申请人ID, dept_name_at_apply VARCHAR(50) NOT NULL COMMENT 申请时部门名称, leave_type TINYINT NOT NULL COMMENT 请假类型1年假 2事假 3病假 4调休, begin_time DATETIME NOT NULL COMMENT 开始时间, end_time DATETIME NOT NULL COMMENT 结束时间, days DECIMAL(5,1) NOT NULL COMMENT 请假天数, reason VARCHAR(200) COMMENT 请假事由, form_status TINYINT NOT NULL DEFAULT 1 COMMENT 单据状态1草稿 2审批中 3通过 4驳回 5撤销, process_instance_id BIGINT COMMENT 流程实例ID, del_flag TINYINT NOT NULL DEFAULT 0 COMMENT 删除标志, create_by BIGINT COMMENT 创建人ID, create_time DATETIME NOT NULL COMMENT 创建时间, update_by BIGINT COMMENT 更新人ID, update_time DATETIME NOT NULL COMMENT 更新时间, UNIQUE KEY uk_leave_no (leave_no), KEY idx_user_status (user_id, form_status) ) COMMENT请假业务表;这里最值得解释的是dept_name_at_apply和form_status。前者是前文说的业务快照保证部门调整后历史单据依然能显示当时的部门后者是单据状态字段由后端在流程推进时回写。虽然流程实例表里也有状态但业务表的状态字段才直接决定能否被搜索到也决定列表页展示成“待审批”还是“已归档”不能省。报销单则需要再拆一张明细表。因为一张报销单里可能有差旅费、餐费、办公用品费好几类项目如果只用一个amount字段就无法按费用类型汇总。明细表挂在主表下面通过master_id外键关联。CREATE TABLE biz_reimburse ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 主键, reimburse_no VARCHAR(30) NOT NULL COMMENT 报销单号, user_id BIGINT NOT NULL COMMENT 报销人ID, dept_name_at_apply VARCHAR(50) NOT NULL COMMENT 申请时部门名称, total_amount DECIMAL(12,2) NOT NULL DEFAULT 0 COMMENT 报销总金额, form_status TINYINT NOT NULL DEFAULT 1 COMMENT 单据状态1草稿 2审批中 3通过 4驳回, process_instance_id BIGINT COMMENT 流程实例ID, del_flag TINYINT NOT NULL DEFAULT 0, create_time DATETIME NOT NULL, update_time DATETIME NOT NULL, UNIQUE KEY uk_reimburse_no (reimburse_no), KEY idx_user_status (user_id, form_status) ) COMMENT报销主表; CREATE TABLE biz_reimburse_line ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 明细主键, master_id BIGINT NOT NULL COMMENT 报销主表ID, expense_type TINYINT NOT NULL COMMENT 费用类型1交通 2餐饮 3住宿 4办公, expense_date DATE NOT NULL COMMENT 费用发生日期, amount DECIMAL(12,2) NOT NULL COMMENT 金额, invoice_no VARCHAR(50) COMMENT 发票号, remark VARCHAR(200) COMMENT 备注, KEY idx_master_id (master_id) ) COMMENT报销明细表;主表与明细表的关系是 1 对 N。total_amount这个字段看起来是冗余的但它价值很高它让报销列表页和审批待办页不需要每次都对明细表做 SUM 操作。设计文档里一定要写清楚主表金额由服务端在明细新增或删除后重新计算不能信任前端传过来的总额。明细表只存业务数据不做跨表单节点更新。3.3 流程引擎三张核心表实例、任务、审批记录怎么挂钩OA 系统如果把审批流程做在业务表里会越做越僵。常见做法是把流程实例与业务单据解耦用三张核心表承载流程运行状态流程实例表、任务表、审批记录表。流程实例表代表一次业务审批请求任务表代表当前待办审批记录表代表不可变的操作流水。CREATE TABLE oa_process_instance ( instance_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 流程实例ID, flow_code VARCHAR(50) NOT NULL COMMENT 流程定义编码, business_type VARCHAR(50) NOT NULL COMMENT 业务类型leave/reimburse, business_id BIGINT NOT NULL COMMENT 业务单据主键ID, applicant_id BIGINT NOT NULL COMMENT 发起人ID, current_node_id VARCHAR(30) COMMENT 当前节点ID, status TINYINT NOT NULL DEFAULT 1 COMMENT 流程状态1运行中 2通过 3驳回 4撤销, start_time DATETIME NOT NULL COMMENT 发起时间, end_time DATETIME COMMENT 结束时间 ) COMMENT流程实例表; CREATE TABLE oa_task ( task_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 任务ID, instance_id BIGINT NOT NULL COMMENT 流程实例ID, node_id VARCHAR(30) NOT NULL COMMENT 节点ID, node_name VARCHAR(50) NOT NULL COMMENT 节点名称快照, assignee_id BIGINT NOT NULL COMMENT 经办人ID, task_status TINYINT NOT NULL DEFAULT 1 COMMENT 任务状态1待办 2完成 3已取消, due_time DATETIME COMMENT 处理时限, create_time DATETIME NOT NULL COMMENT 创建时间, finish_time DATETIME COMMENT 完成时间, KEY idx_instance (instance_id), KEY idx_assignee (assignee_id, task_status) ) COMMENT流程任务表; CREATE TABLE oa_approval_record ( record_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 审批记录ID, instance_id BIGINT NOT NULL COMMENT 流程实例ID, task_id BIGINT COMMENT 关联任务ID, node_id VARCHAR(30) NOT NULL COMMENT 节点ID, node_name VARCHAR(50) COMMENT 节点名称快照, approver_id BIGINT NOT NULL COMMENT 审批人ID, action TINYINT NOT NULL COMMENT 动作1提交 2同意 3驳回 4转签 5撤销, comment VARCHAR(500) COMMENT 审批意见, create_time DATETIME NOT NULL COMMENT 操作时间, KEY idx_instance_time (instance_id, create_time) ) COMMENT审批记录表;这张流程实例表的business_type加business_id可以唯一定位到某条请假单或报销单避免在业务表里各加一堆流程字段。current_node_id是流程引擎实时判断状态的依据这个字段更新很频繁适合单独建索引。oa_task表里的node_name字段虽然和节点 ID 重复但它存的是审批人看到岗位名称时的快照流程定义改了老任务不会错乱。oa_approval_record的核心设计原则是只追加。无论审批人选择同意、驳回还是转签都生成一条新记录绝不 update 历史记录。这也是整套 OA 大数据库设计里审计可靠性的基石。如果业务需要撤回操作就新增一条action5的记录而不是删除或修改上一笔记录。3.4 索引与字符集参数排序规则、联合索引、前缀索引建表 SQL 最终要落到物理参数上。我建议在文档里单独留一节明确字符集、排序规则和索引约定。OA 系统一般会用到用户输入的中文内容字符集建议使用支持四字节 UTF-8 的utf8mb4不要用老旧的utf8。排序规则方面普通用户名字段用大小写不敏感的排序规则即可但登录账号和流程编码这类需要严格区分的字段要用utf8mb4_bin或显式指定大小写敏感。索引方面有四个固定做法所有外键字段都要建索引例如dept_id、user_id、master_id、instance_id联合索引把查询频率高的字段放前面例如(user_id, form_status)支持“某人待办单据列表”这类高频查询超长字符串字段用前缀索引例如报销单号reimburse_no如果超过 30 个字符可以对前 20 个字符建索引逻辑删除字段del_flag不要单独建索引而要与status或create_time组合使用这里给一个实际参数示例ALTER TABLE biz_leave ADD KEY idx_status_ctime (del_flag, form_status, create_time); ALTER TABLE biz_reimburse ADD KEY idx_status_ctime (del_flag, form_status, create_time);像idx_status_ctime这种联合索引可以直接支撑列表页“当前待审批单据按时间倒序”的常见需求。需要强调的是联合索引的字段顺序不是随意的应该把等值查询字段放前面范围查询字段放后面。如果顺序写反即使索引存在查询优化器也可能放弃最优执行计划看起来像“玄学”实际只是最左前缀原则没吃透。4. OA 数据库落地避坑权限空窗、流程断链、附件失效的 4 个翻车现场4.1 离职员工还能登录菜单权限却空一片现象某员工办理离职后管理员把账号del_flag改成 1但员工仍然可以通过旧 token 调接口登录后菜单却全是空的。查库发现用户确实在表中存在只是状态是停用。原因登录查询只判断了del_flag 0没有判断status 1。逻辑删除字段和业务停用字段被混淆了同时历史 token 没有在离职时被吊销。解决登录校验语句必须同时过滤del_flag 0 AND status 1并在用户离职的服务端逻辑里清掉该用户的 token 与角色关联。我在设计方案时会把sys_user的status当作业务开关del_flag只表示数据是否可见两者不能互相替代。系统里的菜单权限查询也要统一走角色链路避免用户表被删除后角色关联表还残留脏数据。4.2 流程卡在中间环节待办任务里的节点名对不上现象流程已经走到某一个审批节点但是待办列表里显示“节点不存在”或显示成旧节点名审批人不敢点任务始终无人处理。原因oa_task表只保存了node_id没保存node_name快照也没有保存流程定义版本。流程管理员后来改了节点名称历史任务查询时再去关联流程定义表结果关联不到旧版本数据。解决任务表必须冗余三个字段node_id、node_name、flow_version。审批历史和任务进入待办队列的那一瞬间就要把这些字段写死。流程引擎读取节点操作按钮时按flow_version读取对应版本的定义展示给审批人的名称用任务表里保存的快照。这个改动不需要前期整套流程引擎重构只要在新版本的流程实例创建时补全任务表快照即可。4.3 审批记录被覆盖写最后只剩一条“通过”现象业务方要查某个报销单的完整审批轨迹后台只有一条“通过”记录之前驳回意见和转办记录全没了。原因设计与开发把“最新审批意见”和“每一步审批流水”合在同一张表每次审批都按instance_id更新同一行。驳回后重新提交旧记录被覆盖审计数据丢失。解决审批记录表必须保持只追加语义。审批人提交意见时插入一条新记录不更新旧记录。如果要表达“用户撤回后重新审批”就插入一条action5的撤销记录再在新的节点下插入同一次审批的新记录。查询“最新状态”时只取oa_process_instance.status或current_node_id不依赖审批记录表来汇总。这是我在多套 OA 系统里验证过最可靠的做法也方便将来做审计分析。4.4 附件只存文件路径文件迁移后全部失效现象把附件存储从服务器磁盘迁移到对象存储后历史附件全部打不开列表页图片全部破图。原因附件表设计时只设计了file_path字段存的是类似于/uploads/2024/03/xxx.docx的相对路径。应用层拼 URL 时统一拼接了旧的服务器地址迁移后基础地址变了所有相对路径失效。解决附件表里要增加存储介质维度的字段至少要有storage_type、bucket、object_key、file_hash。查询附件时由应用层根据storage_type选择对应的 URL 拼装规则。文件内容本身迁移后object_key不变只需要在配置中心更新存储地址与认证信息历史数据可以平滑恢复。file_hash则用来做秒传与重复文件检测在 OA 文档模块里能省下不少存储空间。5. 让设计文档可验证一个查询就能找出外键缺口与索引盲区有了一份设计文档怎么确认它真的能落地而不是纸面模型我通常不会急着建库而是先把所有表的字段和索引扫一遍用系统视图找出三个问题外键列没有索引、逻辑删除标志没有进联合索引、字符集排序规则不一致。下面这个查询找出当前数据库里“列名以 ID 结尾且没有索引”的疑似外键字段。不用关心表里到底有没有显式外键只要它是带_id后缀的字段就应当有索引SELECT c.TABLE_NAME, c.COLUMN_NAME, c.COLUMN_TYPE FROM information_schema.COLUMNS c LEFT JOIN information_schema.STATISTICS s ON c.TABLE_NAME s.TABLE_NAME AND c.COLUMN_NAME s.COLUMN_NAME WHERE c.TABLE_SCHEMA DATABASE() AND c.COLUMN_NAME LIKE %\_id AND s.COLUMN_NAME IS NULL ORDER BY c.TABLE_NAME;这段 SQL 在几个主流关系型数据库的系统表里都能跑核心逻辑是把列名与索引列做左连接然后过滤掉已有索引的列。如果你手里的设计文档 SQL 是 Oracle 或 SQL Server 语法需要把information_schema.COLUMNS换成对应的字典视图。我一般在评审阶段跑一遍跑完会看到类似“biz_reimburse_line.master_id没索引”这样的结果。发现索引缺失后用一条ALTER TABLE补上远好过上线后慢查询再来排查。字符集检查也是容易被忽略的一环。假如sys_user.username用大小写不敏感排序而oa_task.node_id用大小写敏感排序两表关联时可能因为排序规则不一致而走不上索引。设计文档里最好附一张统一约定表写明主键、外键、单据编号、用户姓名字段各用什么排序规则避免“又是一场玄学性能问题”。这套文档值不值得投入我的判断标准其实很明确如果团队准备做一个会长期迭代的 OA 系统数据库设计文档就是后续所有功能的地基如果只是临时撑一个演示 Demo那也可以只写核心表 SQL。我自己的习惯是每次改表都要重跑一次索引检查把新增字段和变更索引写回文档备注页。这份文档不是写一次就封存的而是跟着系统一起生长的。希望帮到你少走几条弯路。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑