
1. 这不是“又一个项目管理工具教程”而是帮你绕开OpenProject部署里90%坑的实操笔记我第一次在客户现场装OpenProject是在2021年夏天。客户要上线一个跨部门协同平台预算卡得死明确要求“必须开源、必须能本地跑、必须带甘特图”。当时我扫了一眼官网文档觉得不就是个Docker Compose一键部署嘛——结果花了整整三天卡在docker-compose up后服务反复重启、Web界面打不开、PostgreSQL连接超时、甚至连基础的用户注册都报500错误。最后发现问题根本不在OpenProject本身而在于它对底层环境的隐性依赖Docker Desktop在Windows上的WSL2配置冲突、PostgreSQL 15与OpenProject 13.4的兼容性断层、Redis缓存未启用导致任务队列堆积、还有那个至今让我头皮发麻的virtualization support not detected报错——它根本不是Docker Desktop启动失败的真正原因而是CPU虚拟化开关被BIOS禁用后WSL2内核加载失败的伪装提示。所以这篇不是教你怎么敲docker-compose up的复制粘贴指南。它是我在给17家中小企业、3个政府单位、2所高校部署OpenProject后把所有踩过的坑、改过的配置、调过的参数、验证过的版本组合全部摊开写成的操作手册。核心关键词就五个OpenProject、开源项目管理、甘特图、Docker、部署——但每一个词背后我都给你拆解到硬件层、系统层、容器层和应用层。比如“Docker”不只是docker install而是你要确认CPU是否支持VT-x/AMD-V、BIOS里是否开启、Windows上是否关闭Hyper-V与WSL2共存冲突、Linux上是否配置了正确的cgroup v2“甘特图”也不只是界面上拖拽一下时间条而是要理解OpenProject底层用的是dhtmlxGantt库它的渲染性能直接受PostgreSQL索引策略和Redis缓存命中率影响。如果你正打算用它管一个5人小团队的APP开发或者一个30人跨地域的基建项目这篇能让你从建第一个项目开始就避开那些文档里绝不会写的、但会让你加班到凌晨三点的陷阱。2. 整体设计思路为什么坚持用Docker Compose而非一键脚本或云托管2.1 不选一键安装包它只适配Ubuntu 22.04而你很可能用的是CentOS 7或Windows 10OpenProject官方提供过.deb和.rpm安装包但2023年之后已停止维护。目前最新稳定版14.3的二进制包仅支持Ubuntu 22.04 LTS且默认绑定PostgreSQL 14。可现实是很多企业服务器还在跑CentOS 7EOL前最后一批或者运维习惯用Debian 11。我试过强行在CentOS 7上装.deb包结果systemd服务脚本里硬编码了/usr/lib/systemd/system/路径而CentOS 7用的是/etc/rc.d/init.d/服务根本起不来。更麻烦的是这些包把Nginx、Passenger、Ruby环境全打包进去一旦出问题日志分散在/var/log/openproject/、/var/log/nginx/、/var/log/passenger/三个目录排查像大海捞针。提示官方一键脚本curl -L https://raw.githubusercontent.com/opf/openproject/master/install.sh | bash本质是下载并执行一个Shell脚本它会自动检测系统发行版并选择对应包。但这个脚本在2024年3月更新后增加了对systemd-resolved服务的强依赖——而很多内网服务器为安全关闭了DNS解析服务导致脚本卡在resolvconf检测环节无限等待。2.2 不选SaaS云服务甘特图数据不出内网是硬性合规红线客户常问“你们有没有类似Trello的在线版”——OpenProject确实有Cloud SaaS服务但它的甘特图数据存储在德国法兰克福数据中心。当客户是电力调度中心或军工研究所时“项目里程碑节点、资源分配表、关键路径计算逻辑”这些数据连同员工姓名、工号、部门信息都属于敏感信息。我们签的等保三级测评报告里白纸黑字写着“项目管理平台核心数据必须本地化部署禁止任何形式的公有云同步”。SaaS版的甘特图导出功能也受限只能导出PNG图片不能导出.xlsx或.mpt格式无法对接客户已有的ERP排产系统。而本地部署的OpenProject通过/opt/openproject/config/initializers/export.rb文件可以自定义导出字段和模板我把甘特图导出逻辑重写成调用roo库读取Excel模板再填入gantt_tasks表数据最终生成带公司LOGO水印、符合国标GB/T 30668-2014格式的甘特图报表。2.3 为什么Docker Compose是唯一靠谱方案它把四层依赖锁死在一个声明式文件里Docker Compose的核心价值不是“省事”而是确定性。OpenProject的运行依赖五层组件硬件层CPU需支持AVX2指令集用于Ruby的JSON解析加速系统层内核需≥5.4WSL2最低要求ulimit -n需≥65536避免WebSocket连接数超限容器层PostgreSQL镜像必须用postgres:14-alpine而非:latest因为:latest在2024年4月已切到15.x而OpenProject 14.3的迁移脚本db:migrate在PG15下会因jsonb_set函数签名变更而报错应用层OpenProject镜像必须指定opf/openproject:14.3.0-ce完整tag不能用14-ce这种模糊tag否则Docker Hub缓存可能拉取到非预期的构建版本网络层Redis容器必须启用--appendonly yes持久化否则重启后甘特图任务状态丢失用户看到的进度条会回滚到初始值。这些依赖关系用docker-compose.yml一份文件就能固化。我把它拆成三个独立文件docker-compose.base.yml基础服务、docker-compose.prod.yml生产配置、docker-compose.dev.yml开发调试。比如生产环境强制启用restart: unless-stopped而开发环境设为restart: no方便快速定位崩溃原因。这种分层设计让同一套代码能在测试机8G内存和生产服务器64G内存上无缝切换只需覆盖加载不同的yml文件。2.4 镜像选型逻辑为什么不用官方opf/openproject而改用社区维护的openproject/community-edition官方镜像opf/openproject在2024年Q1已转向“订阅制优先”策略免费版功能阉割严重甘特图编辑器被降级为只读模式且禁用API导出接口。而社区维护的openproject/community-edition镜像由GitHub组织openproject-community维护完全基于MIT协议保留了全部甘特图交互功能包括拖拽调整工期、右键插入里程碑、双击打开任务详情页修改前置任务依赖关系。更重要的是它预编译了dhtmlxGantt的汉化语言包无需额外挂载/app/public/assets/i18n/zh-CN.js文件。我对比过两个镜像的启动耗时官方镜像首次启动需187秒含Ruby Gem安装Webpack编译社区镜像仅42秒所有静态资源已预构建。这是因为社区镜像在Dockerfile中执行了RUN bundle exec rake assets:precompile而官方镜像把这步推迟到容器启动时动态执行。对于需要快速恢复的灾备场景42秒和187秒的差距就是RTO恢复时间目标能否控制在5分钟内的关键。3. 核心细节解析从环境准备到甘特图落地的12个关键实操点3.1 硬件与系统准备BIOS设置、WSL2内核更新、ulimit调优三步定生死部署OpenProject最常被忽略的其实是硬件层。很多人以为只要Docker能跑OpenProject就能跑——但甘特图的实时渲染对CPU单核性能极其敏感。我遇到过一台i7-8700K服务器6核12线程但BIOS里关闭了Intel VT-x导致WSL2无法加载Linux内核Docker Desktop报错virtualization support not detected。这个错误提示极具误导性它让你以为是Docker Desktop坏了实际是CPU虚拟化开关没开。正确操作流程重启进入BIOS通常按Del/F2/F12找到Advanced → CPU Configuration → Intel Virtualization Technology设为EnabledWindows上以管理员身份运行PowerShell执行wsl --update升级WSL2内核到最新版当前为5.15.133.1执行wsl -l -v确认WSL2发行版状态若显示STOPPED运行wsl --shutdown再重启修改WSL2的.wslconfig文件位于C:\Users\用户名\添加以下内容强制分配资源[wsl2] kernelCommandLine systemd.unified_cgroup_hierarchy1 memory6GB processors4 swap2GB localhostForwardingtrue注意memory和processors必须显式声明否则WSL2默认只分配2GB内存和2核CPU而OpenProject最小推荐配置是4GB内存2核甘特图加载100任务时会触发OOM Killer杀掉PostgreSQL进程。系统级调优同样关键。OpenProject的WebSocket长连接池默认上限是1024当甘特图同时打开多个视图日视图周视图资源视图时连接数会突破阈值。在Linux服务器上执行echo fs.file-max 2097152 /etc/sysctl.conf echo * soft nofile 65536 /etc/security/limits.conf echo * hard nofile 65536 /etc/security/limits.conf sysctl -p这一步必须在Docker服务启动前完成否则容器内继承的ulimit仍是系统默认值65536甘特图缩放操作会卡顿。3.2 Docker环境验证绕过failed to connect to the docker api的七种真实场景failed to connect to the docker api at npipe:////./pipe/dockerdesktoplinuxen这个错误在Windows上出现频率极高。但它从来不是Docker Desktop没启动这么简单。我整理了七种真实场景及对应解法场景表现根本原因解决方案Hyper-V与WSL2共存冲突Docker Desktop图标灰色右键菜单无响应Windows 10/11同时启用Hyper-V和WSL2内核驱动冲突PowerShell管理员运行dism.exe /Online /Disable-Feature:Microsoft-Hyper-V /All重启后启用WSL2WSL2发行版损坏wsl -l -v显示STATE: STOPPED但wsl -t Ubuntu无效WSL2内核更新失败发行版文件系统损坏删除发行版wsl --unregister Ubuntu重新导入干净镜像Docker Desktop服务未注册services.msc中找不到com.docker.service安装包未正确注册Windows服务卸载后从Docker官网下载Docker Desktop Installer.exe右键“以管理员身份运行”防火墙拦截命名管道netstat -ano | findstr :2375无输出公司防火墙策略禁用npipe协议临时关闭防火墙测试确认后在防火墙入站规则中添加Docker Desktop例外用户权限不足docker info报错permission denied当前用户未加入docker-users组控制面板→用户账户→管理其他账户→更改账户类型→勾选docker-usersDocker Desktop配置损坏启动后立即崩溃日志显示panic: runtime error%APPDATA%\Docker\settings.json文件损坏重命名该文件夹重启Docker Desktop重建配置WSL2与Docker Desktop版本不匹配docker version显示客户端1.25服务端20.10Docker Desktop 4.28要求WSL2内核≥5.15.133执行wsl --update若失败则手动下载wsl_update_x64.msi安装实操心得我给客户部署时第一件事就是运行这个诊断脚本保存为docker-check.ps1Write-Host Docker环境诊断 wsl -l -v docker version docker info \| Select-String Server Version Get-Service com.docker.service -ErrorAction SilentlyContinue \| % Status netstat -ano \| findstr :2375它能在20秒内定位90%的环境问题比盲目重启Docker Desktop高效得多。3.3 docker-compose.yml核心配置PostgreSQL连接池、Redis持久化、Nginx反向代理三处必改参数这是经过17次生产环境验证的docker-compose.prod.yml精简版删减了监控和备份模块version: 3.8 services: db: image: postgres:14-alpine restart: unless-stopped environment: POSTGRES_DB: openproject POSTGRES_USER: openproject POSTGRES_PASSWORD: your_strong_password_here volumes: - ./data/db:/var/lib/postgresql/data command: postgres -c max_connections200 -c shared_buffers512MB -c effective_cache_size2GB -c work_mem16MB -c maintenance_work_mem256MB -c checkpoint_completion_target0.9 -c wal_buffers16MB -c default_statistics_target100 healthcheck: test: [CMD-SHELL, pg_isready -U openproject -d openproject] interval: 30s timeout: 10s retries: 5 redis: image: redis:7-alpine restart: unless-stopped command: redis-server --appendonly yes --save 60 1 --maxmemory 512mb --maxmemory-policy allkeys-lru volumes: - ./data/redis:/data healthcheck: test: [CMD, redis-cli, ping] interval: 30s timeout: 10s retries: 5 app: image: openproject/community-edition:14.3.0 restart: unless-stopped environment: SECRET_KEY_BASE: generated_by_rake_secret DATABASE_URL: postgresql://openproject:your_strong_password_heredb:5432/openproject REDIS_URL: redis://redis:6379/0 RAILS_ENV: production OPENPROJECT_HTTPS: false # 内网部署无需HTTPS OPENPROJECT_HOST: http://your-server-ip:8080 OPENPROJECT_PORT: 8080 OPENPROJECT_LOG_LEVEL: info depends_on: db: condition: service_healthy redis: condition: service_healthy ports: - 8080:8080 volumes: - ./data/app:/var/db/openproject - ./config/openproject.env:/etc/openproject/installer.env:ro healthcheck: test: [CMD, curl, -f, http://localhost:8080/login] interval: 60s timeout: 10s retries: 5 nginx: image: nginx:alpine restart: unless-stopped ports: - 80:80 - 443:443 volumes: - ./config/nginx.conf:/etc/nginx/nginx.conf:ro - ./data/nginx/logs:/var/log/nginx - ./data/nginx/html:/usr/share/nginx/html depends_on: - app关键参数说明db.command里的max_connections200OpenProject默认连接池是20但甘特图并发加载时每个用户会占用3-5个连接20个用户就爆了。设为200后配合pgbouncer中间件后续扩展用可支撑200并发redis.command的--appendonly yes必须开启AOF持久化否则容器重启后甘特图任务状态丢失用户看到的进度条会回滚app.environment.OPENPROJECT_HOST必须填内网IP而非localhost否则甘特图JS加载/assets/gantt.js时会请求http://localhost:8080/assets/gantt.js浏览器同源策略拦截nginx容器独立存在官方镜像内置Nginx但生产环境必须剥离。因为OpenProject的甘特图导出PDF功能依赖wkhtmltopdf而内置Nginx的容器里没有这个二进制文件独立Nginx可挂载宿主机的wkhtmltopdf二进制。3.4 初始化与数据库迁移rake db:setup为何总失败三个隐藏陷阱执行docker-compose run --rm app bundle exec rake db:setup时90%的人会卡在PG::ConnectionBad: FATAL: password authentication failed for user openproject。这不是密码错了而是三个隐藏陷阱陷阱一PostgreSQL的pg_hba.conf未生效Alpine镜像的PostgreSQL默认配置是host all all 0.0.0.0/0 md5但Docker网络里app容器访问db容器走的是内部DNSIP是172.20.0.2而0.0.0.0/0不匹配。解决方案在db.volumes里挂载自定义pg_hba.confvolumes: - ./config/pg_hba.conf:/var/lib/postgresql/data/pg_hba.confpg_hba.conf内容host all all 172.20.0.0/16 md5 host all all ::1/128 md5陷阱二DATABASE_URL环境变量里的密码含特殊字符如果密码是Pssw0rd!2024URL里的会被解析为URL分隔符导致用户名变成openproject:P密码变成ssw0rd!2024。解决方案对密码进行URL编码P%40ssw0rd%212024。陷阱三db:setup命令在容器内执行时bundle exec找不到GemOpenProject镜像的/app目录下Gemfile.lock锁定的pggem版本是1.5.3但PostgreSQL 14的libpq库版本是14.10ABI不兼容。解决方案在app服务里添加command覆盖command: sh -c bundle config set --local path .vendor/bundle bundle install bundle exec rake db:setup 实操心得我写了个自动化初始化脚本init-db.sh它会先检查db容器健康状态再执行迁移失败时自动清理并重试三次#!/bin/bash docker-compose up -d db redis sleep 30 for i in {1..3}; do if docker-compose run --rm app bundle exec rake db:setup 2/dev/null; then echo 数据库初始化成功 exit 0 else echo 第$i次初始化失败30秒后重试... sleep 30 fi done echo 初始化失败请检查db日志3.5 创建首个项目与甘特图从空白页面到可交互甘特图的六步操作链很多教程到这里就结束了但真正的坑在甘特图创建环节。以下是经过验证的六步操作链确保你第一次打开甘特图就流畅可用第一步登录后立即修改管理员密码默认账号admin密码admin但首次登录后必须修改否则甘特图编辑功能被锁定。路径右上角头像→My account→Change password。第二步创建项目时启用“计划”模块新建项目时在Modules选项卡里必须勾选Work packages和Gantt chart。注意Gantt chart不是默认启用的如果不勾选后续在项目设置里也无法开启。第三步添加至少3个任务并设置依赖关系甘特图默认不显示必须有任务数据。创建任务时务必填写Subject标题Start dateDue date起止日期Assignee负责人Type类型选Task然后点击Edit dependencies为任务B添加前置任务A这样甘特图才会计算关键路径。第四步进入甘特图视图并启用“计划模式”点击左侧菜单Gantt chart右上角切换按钮从Timeline切到Plan。Timeline模式只读Plan模式才能拖拽调整工期、右键插入里程碑。第五步调整时间刻度与任务分组默认显示“周”但项目周期短时需切到“天”。点击右上角Settings→Time scale→Days。再点击Group by→Assignee按负责人分组显示方便资源负荷分析。第六步导出为Excel并验证公式点击Export→Excel下载文件后打开检查Gantt Chart工作表里的Duration列是否为公式IF(ISBLANK(E2),,D2-C21)。这是OpenProject导出的智能公式会自动计算工期天数而非静态数值。注意事项甘特图首次加载慢约8-12秒是正常的因为要从PostgreSQL读取work_packages表、关联relations表计算依赖、再查custom_fields表获取自定义字段。但第二次加载应2秒如果仍慢说明Redis缓存未生效检查app容器日志是否有Redis connection refused报错。4. 实操过程全记录从零开始部署附每步耗时与异常处理4.1 环境准备阶段耗时12分钟操作清单Windows 10 Pro 22H2已启用WSL2wsl -l -v显示Ubuntu-22.04状态为Running下载Docker Desktop 4.28.0安装时勾选Use the WSL 2 based engine执行wsl --update内核版本升至5.15.133.1创建项目目录mkdir openproject-deploy cd openproject-deploy创建子目录mkdir -p config data/{db,redis,app,nginx/logs,nginx/html}。异常处理执行wsl --update时卡在Downloading update...。原因公司代理服务器拦截了https://wslstorestorage.blob.core.windows.net/wslupdates/域名。解决方案临时关闭代理或在PowerShell中设置$env:HTTP_PROXYhttp://proxy.company.com:8080 $env:HTTPS_PROXYhttp://proxy.company.com:8080 wsl --update4.2 配置文件编写阶段耗时28分钟关键文件内容docker-compose.prod.yml采用上文精简版特别注意db.command参数和redis.command的--appendonly yesconfig/pg_hba.conf按前述内容编写确保172.20.0.0/16网段可访问config/nginx.conf精简版只保留反向代理到app:8080禁用SSL内网无需config/openproject.env空文件仅作占位避免容器启动时报错/etc/openproject/installer.env: No such file。异常处理docker-compose config报错Unsupported config option for services.app: command。原因command字段在docker-compose.ymlv3.8中是合法的但旧版Docker Compose解析器不识别。解决方案升级Docker Compose CLI执行docker compose version确认≥2.24.0若低于此版本运行curl -L https://github.com/docker/compose/releases/download/v2.24.0/docker-compose-windows-x86_64.exe -o $env:ProgramFiles\Docker\Docker\resources\bin\docker-compose.exe。4.3 首次启动与初始化阶段耗时47分钟操作流程docker-compose up -d db redis启动数据库和缓存耗时2分钟docker-compose run --rm app bundle exec rake db:setup初始化数据库耗时18分钟docker-compose up -d app nginx启动应用和Nginx耗时3分钟浏览器访问http://localhost等待502 Bad Gateway消失Nginx等待app健康检查通过耗时24分钟。异常处理app容器日志持续输出FATAL: password authentication failed for user openproject。排查步骤docker-compose exec db psql -U openproject -d openproject -c \l确认数据库openproject存在docker-compose exec db cat /var/lib/postgresql/data/pg_hba.conf确认172.20.0.0/16网段已添加docker-compose exec app env \| grep DATABASE_URL确认密码已URL编码最终发现pg_hba.conf挂载路径错误./config/pg_hba.conf实际挂载到了/var/lib/postgresql/data/pg_hba.conf但PostgreSQL读取的是/var/lib/postgresql/data/pg_hba.conf路径正确但文件权限不对。解决方案chmod 644 ./config/pg_hba.conf再docker-compose restart db。4.4 甘特图功能验证阶段耗时15分钟验证清单登录admin/admin修改密码创建项目Test Project启用Work packages和Gantt chart模块添加3个任务需求分析2024-05-01至2024-05-05、UI设计2024-05-06至2024-05-10、前端开发2024-05-11至2024-05-20并设置UI设计依赖需求分析前端开发依赖UI设计进入甘特图确认关键路径高亮显示需求分析→UI设计→前端开发连线为红色拖拽UI设计结束日期到2024-05-12观察前端开发自动顺延到2024-05-13导出Excel打开后确认Duration列为公式且Gantt Chart工作表中Start date列与Due date列数据与界面一致。异常处理甘特图中任务条不显示日期只显示NaN。原因浏览器时区与服务器时区不一致。OpenProject默认读取服务器TZ环境变量而Alpine镜像默认UTC。解决方案在app.environment中添加TZ: Asia/Shanghai并docker-compose restart app。5. 常见问题与排查技巧实录12个高频问题的根因与速查表5.1 甘特图加载缓慢不是网络问题而是PostgreSQL索引缺失现象打开甘特图需30秒以上Chrome DevTools Network标签显示/api/v3/work_packages?...请求耗时28秒。根因分析OpenProject的甘特图API/api/v3/work_packages默认查询work_packages表所有字段并JOINrelations、custom_fields等5张表。当任务数500时若work_packages.project_id和work_packages.created_at无复合索引PostgreSQL会执行全表扫描。速查命令docker-compose exec db psql -U openproject -d openproject -c \ EXPLAIN ANALYZE SELECT * FROM work_packages wp JOIN relations r ON wp.id r.from_id WHERE wp.project_id 1;若输出包含Seq Scan on work_packages说明未走索引。解决方案在db容器内执行CREATE INDEX CONCURRENTLY IF NOT EXISTS index_work_packages_on_project_id_created_at ON work_packages (project_id, created_at); CREATE INDEX CONCURRENTLY IF NOT EXISTS index_relations_on_from_id ON relations (from_id);索引创建后甘特图加载时间从28秒降至1.2秒。5.2 甘特图任务无法拖拽WebSocket连接被意外关闭现象鼠标悬停任务条显示手型但点击拖拽无反应Console报错WebSocket is already in CLOSING or CLOSED state。根因分析OpenProject的甘特图实时协作依赖WebSocket而默认配置/config/initializers/websocket.rb中config.web_socket_timeout 60秒。当用户电脑休眠或网络波动WebSocket连接超时后未自动重连。解决方案修改app服务的environment添加OPENPROJECT_WEBSOCKET_TIMEOUT: 300 OPENPROJECT_WEBSOCKET_RECONNECT_INTERVAL: 5000并挂载自定义WebSocket配置文件volumes: - ./config/websocket.rb:/app/config/initializers/websocket.rb:rowebsocket.rb内容OpenProject::Configuration.configure do |config| config.web_socket_timeout 300 config.web_socket_reconnect_interval 5000 end5.3 Excel导出格式错乱字体与单元格宽度未适配中文现象导出的Excel中中文标题显示为方块甘特图时间轴列宽过窄日期重叠。根因分析OpenProject使用roo库导出Excel但默认字体是DejaVu Sans不支持中文。roo的write方法未设置列宽。解决方案在app容器内修改/app/app/views/export/excel/gantt.xlsx.erb模板% work_packages.each_with_index do |wp, i| % sheet.row(i2).font { name: Microsoft YaHei, size: 10 } sheet.column(1).width 20 # Subject列 sheet.column(2).width 15 # Start date列 sheet.column(3).width 15 # Due date列 % end %再重建镜像或挂载覆盖文件。5.4 Docker Desktop启动失败virtualization support not detected的终极排查现象Docker Desktop图标灰色日志显示virtualization support not detected但BIOS已开启VT-x。根因分析Windows 11的“基于虚拟化的安全”VBS功能会独占Intel VT-x导致WSL2无法使用。VBS默认开启且与Docker Desktop冲突。终极解决方案以管理员身份运行PowerShell# 关闭VBS Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Control\DeviceGuard\Scenarios\HypervisorEnforcedCodeIntegrity -Name Enabled -Value 0 # 重启系统 shutdown /r /t 0重启后执行dism.exe /online /disable-feature /featurename:VirtualMachinePlatform /norestart再执行wsl --update启动Docker Desktop。速查表12个高频问题根因与解决命令汇总问题现象根本原因解决命令/操作docker-compose up后app容器反复重启Redis未健康检查通过docker-compose exec redis redis-cli ping若失败则检查redis.command是否含--appendonly yes甘特图显示“Loading...”无限转圈Nginx未正确代理到app:8080docker-compose exec nginx curl -v http://app:8080/login确认返回200创建项目后看不到Gantt chart菜单项目模块