跳到主要内容

221 篇博文 含有标签「iCoding」

个人简介

查看所有标签

🍎 macOS Python 最佳安装与配置指南(2026版)

· 阅读需 6 分钟
Quany
软件工程师

基于当前最佳实践,推荐 pyenv + pipx + venv 组合方案,完美适配 Intel 和 Apple Silicon 芯片。

📋 方案对比

方案优点缺点推荐度
pyenv + pipx + venv版本隔离、工具隔离、项目隔离、最灵活配置稍复杂⭐⭐⭐⭐⭐
官网 .pkg 安装包简单直接无法多版本管理、可能污染系统⭐⭐
Homebrew 直接安装更新方便只能安装一个版本⭐⭐⭐
Conda科学计算友好体积大、生态相对封闭⭐⭐⭐

🚀 完整安装配置流程

第1步:安装 Homebrew(包管理器)

# 如果已安装可跳过
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# 验证安装
brew --version

第2步:安装 pyenv(Python 版本管理)

# 安装 pyenv
brew update
brew install pyenv

# 配置 shell 环境(macOS Catalina 及以后默认使用 zsh)
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(pyenv init -)"' >> ~/.zshrc

# 使配置生效
source ~/.zshrc

# 验证安装
pyenv --version

第3步:安装编译依赖(防止编译失败)

# 安装 Python 编译所需依赖
brew install openssl readline sqlite3 xz zlib tcl-tk

# Apple Silicon 芯片额外配置(M1/M2/M3)
if [[ $(uname -m) == 'arm64' ]]; then
echo 'export LDFLAGS="-L/opt/homebrew/opt/zlib/lib -L/opt/homebrew/opt/openssl/lib"' >> ~/.zshrc
echo 'export CPPFLAGS="-I/opt/homebrew/opt/zlib/include -I/opt/homebrew/opt/openssl/include"' >> ~/.zshrc
source ~/.zshrc
fi

第4步:安装 Python 3(推荐最新稳定版)

# 查看可安装版本
pyenv install --list | grep "^\s*3\.[0-9]\+"

# 安装 Python 3.13.3(2026年4月最新稳定版)
pyenv install 3.13.3

# 设置为全局默认版本
pyenv global 3.13.3

# 验证安装
python --version # 应显示 Python 3.13.3
which python # 应显示 ~/.pyenv/shims/python

第5步:安装 pipx(全局命令行工具管理)

# 安装 pipx
brew install pipx
pipx ensurepath

# 或使用 pip 安装(如果 brew 不可用)
# python -m pip install --user pipx
# python -m pipx ensurepath

# 验证安装
pipx --version

第6步:安装常用开发工具

# 代码质量工具
pipx install black # 代码格式化
pipx install flake8 # 代码检查
pipx install mypy # 类型检查
pipx install isort # import 排序
pipx install ruff # 更快的代码检查(推荐)

# 项目工具
pipx install poetry # 现代依赖管理(推荐)
# 或 pipx install pdm # 另一种选择

# 实用工具
pipx install httpie # 现代 HTTP 客户端
pipx install cookiecutter # 项目模板生成器
pipx install jupyter # Jupyter Notebook

# 验证安装
black --version
poetry --version

🛠️ 项目级虚拟环境配置

使用 venv(Python 内置,推荐)

# 创建项目
mkdir myproject && cd myproject

# 创建虚拟环境
python -m venv .venv

# 激活虚拟环境
source .venv/bin/activate
# 激活后提示符前会显示 (.venv)

# 安装项目依赖
pip install requests flask pandas

# 退出虚拟环境
deactivate

使用 Poetry(现代项目管理)

# 创建新项目
poetry new myproject
cd myproject

# 添加依赖
poetry add requests
poetry add --dev pytest black

# 安装所有依赖
poetry install

# 进入虚拟环境
poetry shell

# 运行脚本
poetry run python main.py

📁 目录结构示例

~/
├── .pyenv/ # pyenv 安装的 Python 版本
│ ├── versions/
│ │ ├── 3.13.3/
│ │ └── 3.12.5/
│ └── shims/ # 命令重定向
├── .local/share/pipx/ # pipx 安装的工具
│ ├── venvs/
│ └── bin/
└── projects/
├── project1/
│ └── .venv/ # 项目虚拟环境
└── project2/
└── .venv/

🔄 多版本管理命令

pyenv 常用命令

# 查看所有可用版本
pyenv install --list

# 安装特定版本
pyenv install 3.12.5
pyenv install 3.11.9

# 查看已安装版本
pyenv versions
# 带 * 的是当前激活版本

# 切换版本
pyenv global 3.13.3 # 全局默认
pyenv local 3.12.5 # 当前目录生效
pyenv shell 3.11.9 # 当前终端会话生效

# 卸载版本
pyenv uninstall 3.10.0

# 刷新缓存
pyenv rehash

pipx 常用命令

# 安装工具
pipx install <package>

# 临时运行(不安装)
pipx run <package> [args]

# 列出已安装工具
pipx list

# 升级工具
pipx upgrade <package>
pipx upgrade-all

# 卸载工具
pipx uninstall <package>

# 查看工具环境
pipx environment

⚙️ 配置文件示例

~/.zshrc 配置

# Python 配置
export PYENV_ROOT="$HOME/.pyenv"
command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"

# pipx 配置(如果使用 pip 安装)
export PATH="$HOME/.local/bin:$PATH"

# 虚拟环境提示符
export VIRTUAL_ENV_DISABLE_PROMPT=0

.gitignore 配置

# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

# 虚拟环境
.venv/
venv/
env/
ENV/
env.bak/
venv.bak/

# IDE
.vscode/
.idea/
*.swp
*.swo
*~

🎯 最佳实践建议

1. 版本选择策略

  • 生产环境:Python 3.12.x(LTS,长期支持)
  • 开发环境:Python 3.13.x(最新特性)
  • 兼容性要求:Python 3.8+(大多数库支持的最低版本)

2. 工具选择指南

场景推荐工具说明
代码格式化black + isort自动格式化,无需争论风格
代码检查ruff比 flake8 快 10-100 倍
类型检查mypy静态类型检查
依赖管理poetry现代、功能全面
虚拟环境venvPython 内置,简单可靠
CLI工具pipx全局工具隔离管理

3. 工作流示例

# 1. 创建新项目
mkdir awesome-project && cd awesome-project

# 2. 设置项目Python版本
pyenv local 3.13.3

# 3. 创建虚拟环境
python -m venv .venv
source .venv/bin/activate

# 4. 初始化项目(使用 poetry)
poetry init
poetry add fastapi uvicorn
poetry add --dev black ruff mypy pytest

# 5. 配置开发环境
echo ".venv/" >> .gitignore
echo "__pycache__/" >> .gitignore

# 6. 开始开发!

🔧 故障排除

常见问题解决

  1. pyenv 安装 Python 失败

    # 确保编译依赖已安装
    brew install openssl readline sqlite3 xz zlib tcl-tk

    # Apple Silicon 芯片设置
    export SDKROOT=$(xcrun --show-sdk-path)
  2. pipx 命令找不到

    # 重新配置 PATH
    pipx ensurepath
    source ~/.zshrc

    # 或手动添加
    echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc
  3. 虚拟环境激活失败

    # 检查 Python 版本
    python --version

    # 重新创建虚拟环境
    deactivate 2>/dev/null
    rm -rf .venv
    python -m venv .venv
    source .venv/bin/activate

📊 环境验证检查表

# 运行以下命令验证环境
echo "=== Python 环境验证 ==="
python --version
which python
pyenv versions
pipx list
pip --version
echo "=== 完成 ==="

🎁 一键安装脚本

#!/bin/bash
# macOS Python 环境一键安装脚本

echo "安装 Homebrew..."
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

echo "安装 pyenv..."
brew install pyenv

echo "配置 pyenv..."
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(pyenv init -)"' >> ~/.zshrc
source ~/.zshrc

echo "安装编译依赖..."
brew install openssl readline sqlite3 xz zlib tcl-tk

echo "安装 Python 3.13.3..."
pyenv install 3.13.3
pyenv global 3.13.3

echo "安装 pipx..."
brew install pipx
pipx ensurepath

echo "安装开发工具..."
pipx install black ruff poetry httpie

echo "环境配置完成!"
python --version

📈 后续优化建议

  1. 配置 IDE:VS Code 安装 Python 扩展,配置使用 pyenv 环境
  2. 设置别名:在 ~/.zshrc 中添加常用命令别名
  3. 定期更新:每月运行 brew update && brew upgradepipx upgrade-all
  4. 备份配置:将 ~/.zshrc 和项目 requirements.txtpyproject.toml 加入版本控制

这套方案在 2026 年仍然是 macOS 上 Python 开发的最佳实践,兼顾了灵活性、隔离性和易用性。开始享受现代 Python 开发吧!🚀

🧪 软件测试分类详解

· 阅读需 8 分钟
Quany
软件工程师

📊 测试分类全景图

软件测试
├── 按测试方法分类
│ ├── 黑盒测试 (Black-box Testing)
│ ├── 白盒测试 (White-box Testing)
│ └── 灰盒测试 (Gray-box Testing) - 两者结合

├── 按测试阶段分类
│ ├── 单元测试 (Unit Testing)
│ ├── 集成测试 (Integration Testing)
│ ├── 系统测试 (System Testing)
│ └── 验收测试 (Acceptance Testing)

├── 按测试目的分类
│ ├── 功能测试 (Functional Testing)
│ ├── 性能测试 (Performance Testing)
│ ├── 安全测试 (Security Testing)
│ ├── 兼容性测试 (Compatibility Testing)
│ └── 可用性测试 (Usability Testing)

└── 按执行方式分类
├── 手动测试 (Manual Testing)
└── 自动化测试 (Automation Testing)

🔲 黑盒测试 vs 白盒测试

黑盒测试 (Black-box Testing)

核心思想:只关注输入输出,不关心内部实现

维度说明
测试视角用户视角,测试软件功能
关注点功能是否按需求工作
测试依据需求文档、规格说明书
测试人员测试工程师、用户
优点1. 从用户角度验证
2. 无需了解代码实现
3. 容易发现需求不一致问题
缺点1. 测试覆盖率难以量化
2. 无法测试内部逻辑
3. 可能遗漏代码路径
常用技术等价类划分、边界值分析、决策表、状态转换
适用阶段集成测试、系统测试、验收测试

典型场景

  • 测试登录功能:输入用户名密码,验证能否成功登录
  • 测试购物流程:添加商品、结算、支付,验证订单生成
  • 测试API接口:发送请求,验证响应数据和状态码

白盒测试 (White-box Testing)

核心思想:深入代码内部,测试逻辑结构和路径

维度说明
测试视角开发者视角,测试代码逻辑
关注点代码覆盖率、逻辑正确性
测试依据源代码、设计文档
测试人员开发工程师、测试开发工程师
优点1. 能发现深层次代码错误
2. 可量化测试覆盖率
3. 能测试所有逻辑路径
缺点1. 需要编程能力
2. 可能过度关注实现细节
3. 无法验证需求符合性
常用技术语句覆盖、分支覆盖、路径覆盖、条件覆盖
适用阶段单元测试、集成测试

典型场景

  • 测试函数的所有if-else分支
  • 验证循环边界条件
  • 检查异常处理逻辑
  • 确保所有代码行都被执行到

🔗 串测(集成测试/端到端测试)

串测通常指集成测试端到端测试,主要验证多个模块/系统串联工作的正确性。

集成测试 (Integration Testing)

目的:验证模块/组件之间的接口和交互

测试策略说明优点缺点
大爆炸式所有模块一次性集成后测试快速、简单错误定位困难
自顶向下从顶层模块开始,逐步向下集成早期验证主要功能需要大量桩模块
自底向上从底层模块开始,逐步向上集成早期验证基础功能需要大量驱动模块
三明治式结合自顶向下和自底向上平衡效率和质量实现较复杂
持续集成每次代码变更都自动集成测试快速发现问题需要完善的自动化

端到端测试 (End-to-End Testing)

目的:模拟真实用户场景,验证完整业务流程

典型串测场景

  1. 用户注册流程

    前端页面 → API网关 → 用户服务 → 数据库 → 邮件服务 → 短信服务
  2. 电商下单流程

    浏览商品 → 加入购物车 → 填写地址 → 选择支付 → 扣减库存 → 生成订单 → 物流通知
  3. 微服务架构串测

    订单服务 → 支付服务 → 库存服务 → 物流服务 → 通知服务

🎯 三种测试的对比与应用

对比表格

测试类型测试对象测试人员测试依据关注点典型工具
黑盒测试完整系统/功能测试工程师需求文档功能正确性Postman, Selenium, JMeter
白盒测试代码/模块开发工程师源代码代码质量JUnit, pytest, JaCoCo
串测模块间交互测试/开发工程师接口文档流程完整性Postman, Cypress, K6

实际应用策略

1. 测试金字塔模型(推荐)

        ╱╲        UI测试/端到端测试 (少量)
╱ ╲
╱ ╲ 集成测试/串测 (适量)
╱ ╲
╱________╲ 单元测试/白盒测试 (大量)
  • 底层(最多):单元测试(白盒)
  • 中层(适量):集成测试(串测)
  • 顶层(最少):UI测试(黑盒)

2. 测试选择指南

场景推荐测试类型理由
新功能开发白盒测试 → 黑盒测试 → 串测先保证代码质量,再验证功能,最后验证流程
API接口测试黑盒测试为主,白盒为辅关注输入输出,适当检查边界条件
业务流程测试串测为主,黑盒验证确保端到端流程通畅
性能测试黑盒测试从用户角度评估系统性能
安全测试黑盒+白盒结合外部攻击测试+代码安全审计

3. 测试用例设计示例

用户登录功能测试:

# 白盒测试用例(单元测试)
def test_login_logic():
# 测试各种分支
assert login("valid_user", "correct_pwd") == True
assert login("valid_user", "wrong_pwd") == False
assert login("", "any_pwd") == False # 空用户名
assert login("user", "") == False # 空密码
assert login(None, "pwd") == False # None处理
assert login("a"*101, "pwd") == False # 用户名超长

# 黑盒测试用例(功能测试)
"""
测试场景:
1. 正确用户名密码 → 登录成功,跳转首页
2. 错误密码 → 提示"密码错误"
3. 不存在的用户 → 提示"用户不存在"
4. 连续错误5次 → 账户锁定
5. 登录后刷新 → 保持登录状态
6. 不同浏览器登录 → 功能一致
"""

# 串测试用例(集成测试)
"""
测试流程:
1. 前端输入 → API调用 → 用户服务验证 → 数据库查询
2. 登录成功 → 生成token → 返回前端 → 存储cookie
3. 后续请求 → 携带token → 网关验证 → 访问资源
"""

🛠️ 测试工具推荐

黑盒测试工具

  • 功能测试:Selenium, Cypress, Playwright
  • API测试:Postman, Insomnia, REST Assured
  • 性能测试:JMeter, LoadRunner, Gatling
  • 安全测试:OWASP ZAP, Burp Suite

白盒测试工具

  • 单元测试:JUnit, pytest, Mocha, Jest
  • 代码覆盖率:JaCoCo, Istanbul, coverage.py
  • 静态分析:SonarQube, ESLint, Pylint
  • 调试工具:Chrome DevTools, PyCharm Debugger

串测/集成测试工具

  • API集成:Postman Collections, Karate DSL
  • 端到端:Cypress, TestCafe, Selenium Grid
  • 微服务测试:Pact, Mountebank, WireMock
  • CI/CD集成:Jenkins, GitLab CI, GitHub Actions

📈 测试最佳实践

1. 测试策略制定

项目阶段: 开发初期
重点测试:
- 白盒测试: 70% (单元测试、代码审查)
- 黑盒测试: 20% (核心功能验证)
- 串测: 10% (主要流程验证)

项目阶段: 测试阶段
重点测试:
- 黑盒测试: 50% (功能完整测试)
- 串测: 30% (集成流程测试)
- 白盒测试: 20% (重点模块深度测试)

项目阶段: 上线前
重点测试:
- 串测: 50% (端到端回归测试)
- 黑盒测试: 30% (用户场景测试)
- 白盒测试: 20% (关键路径测试)

2. 测试用例设计原则

  • 黑盒测试:基于需求,覆盖所有功能点
  • 白盒测试:基于代码,覆盖所有逻辑路径
  • 串测:基于业务流程,覆盖主要用户场景

3. 测试自动化策略

# 自动化测试金字塔
test_automation = {
"unit_tests": { # 白盒测试
"coverage": ">80%",
"tools": ["pytest", "JUnit"],
"execution": "每次提交"
},
"integration_tests": { # 串测
"coverage": "核心流程",
"tools": ["Postman", "Cypress"],
"execution": "每日构建"
},
"e2e_tests": { # 黑盒测试
"coverage": "关键用户旅程",
"tools": ["Selenium", "Playwright"],
"execution": "发布前"
}
}

🚀 实际工作建议

对于测试工程师

  1. 掌握黑盒测试技术:等价类、边界值、场景法等
  2. 学习自动化工具:Selenium、Postman、JMeter
  3. 理解业务流程:能够设计端到端测试用例
  4. 了解白盒基础:能看懂代码,与开发更好协作

对于开发工程师

  1. 重视白盒测试:编写高质量单元测试
  2. 参与代码审查:提前发现代码问题
  3. 理解黑盒思维:从用户角度思考问题
  4. 关注集成测试:确保模块间协作正常

对于团队

  1. 建立测试金字塔:合理分配测试资源
  2. 实施持续集成:自动化执行测试
  3. 定期回归测试:确保功能稳定
  4. 测试左移:在开发早期介入测试

💡 关键要点总结

  1. 黑盒测试外部视角,验证功能是否符合需求
  2. 白盒测试内部视角,验证代码逻辑是否正确
  3. 串测流程视角,验证系统间协作是否顺畅
  4. 三者互补而非互斥,应结合使用
  5. 遵循测试金字塔原则,基础测试要扎实
  6. 自动化是提高测试效率的关键

在实际项目中,通常需要混合使用这些测试方法:开发阶段以白盒测试为主,测试阶段以黑盒和串测为主,形成完整的质量保障体系。

端到端(E2E)测试

· 阅读需 1 分钟
Quany
软件工程师

通过AI写脚本

主要全量测试,集成测试,逐步提高 AI 编写测试;

通过测试用列编写脚本

  • 提示语:

/opsx-explore 硬件履约 e2e 测试脚本编写 请按照这个@硬件履约_测试用例1.1.md ,编写e2e 测试脚本,编写技术请参考: https://playwright.net.cn/docs e2e 测试脚本编写路径:yunfun-ui-admin-vben/apps/web-antd/e2e

在需求中分析测试用例(TDD)

  • 提示语:

/opsx-explore 硬件履约 @docs/订单管理/硬件履约需求设计文档.md 编写技术请参考: https://playwright.net.cn/docs,e2e 测试脚本编写路径:yunfun-ui-admin-vben/apps/web-antd/e2e

用他们设计的智能体编写测试脚本 (效果不好)

https://playwright.net.cn/docs/test-agents

定时任务

每天晚上跑全量测试脚本,如果有 bug,先 AI 修复一版,再让人工确认后提交;

报告可以推送到前端公共库;或者 netlify;

人工生成

主要为了复现 bug,精细化测试,补充全量测试脚本;

文档:https://playwright.net.cn/docs/codegen-intro 作业目录:e2e

详细地址组件

· 阅读需 2 分钟
Quany
软件工程师

配置说明

  • fieldName: 字段必须是字符串,会塞入 json 格式的内容;
  • 必须搭配国家/地区(customerCountry)使用;

使用说明

模态框交互的详细地址组件

  • 组件代码路径:yunfun-ui-admin-vben/apps/web-antd/src/views/crm/customer/components/DetailByAddressFormat.vue

form-data.ts/data.ts 配置如下:

    {
fieldName: 'detailByAddressFormat',
label: $t('web.crmCustomer.create.form.detailByAddressFormat', {
defaultValue: '地址格式的地址',
}),
component: 'DetailByAddressFormat',
componentProps: {
countryCode: undefined,
},
dependencies: {
triggerFields: ['customerCountry'],
show: (values: any) => !!(values.customerCountry ?? '').trim(),
componentProps: (values: any) => ({
countryCode: (values.customerCountry ?? '').trim() || undefined,
}),
rules: () => z.string().optional(),
},
defaultValue: undefined,
rules: z.string().optional(),
formItemClass: 'col-span-2',
}

平铺详细地址组件

  • 组件代码路径:yunfun-ui-admin-vben/apps/web-antd/src/views/crm/customer/components/DetailByAddressFormatFlat.vue

form-data.ts/data.ts 配置如下:

  {
fieldName: 'detailByAddressFormatFlat',
component: 'DetailByAddressFormatFlat',
componentProps: {
countryCode: undefined,
},
dependencies: {
triggerFields: ['customerCountry'],
show: (values: any) => !!(values.customerCountry ?? '').trim(),
componentProps: (values: any) => ({
countryCode: (values.customerCountry ?? '').trim() || undefined,
}),
rules: () => z.string().optional(),
},
labelWidth: 0, // 这样可以对齐排版
defaultValue: undefined,
rules: z.string().optional(),
formItemClass: 'col-span-2',
},

相关解析函数

function parseDetailByAddressFormatValue(raw: unknown): null | {
components?: {
adminDiv?: string;
city?: string;
postalCode?: string;
};
fullText?: string;
} {
if (typeof raw !== 'string' || !raw.trim()) return null;
try {
const parsed = JSON.parse(raw);
if (!parsed || typeof parsed !== 'object') return null;
return parsed as {
components?: { adminDiv?: string; city?: string; postalCode?: string };
fullText?: string;
};
} catch {
return null;
}
}

function mergeDetailedAddressMl(
fullText: string | undefined,
currentMl: Record<string, string>,
) {
const next = { ...(currentMl || {}) } as Record<string, string>;
const zh = (fullText ?? '').trim();
if (zh) {
next['zh-CN'] = zh;
}
return next;
}

演示说明

行政区联动组件

· 阅读需 2 分钟
Quany
软件工程师

表单使用

  • 必须跟着一个国家选择器
  • 联动规则:
    • 当国家选择器值变化时,联动组件的 label 值会变化(如果接口有返回该国家的行政区名称的话),如果没有返回则显示默认文案「行政区」。
    • 当国家选择器有值时,联动组件必填;当国家选择器无值时,联动组件非必填。
  • 联动组件的 options 由接口返回,接口参数为国家选择器的值,接口返回的 options 中包含 label 和 value 两个字段。
  • 联动组件的 label 默认文案为「行政区」,可自定义文案。

{
fieldName: 'customerCountry',
label: $t('web.crmCustomer.create.form.customerCountry', {
defaultValue: '注册地国家/地区',
}),
component: 'ApiSelect',
componentProps: {
api: async () => {
const countries = await getSimpleCountryList();
return (countries || []).map((c) => ({
label: `${c.text} (${c.countryCode})`,
value: c.countryCode,
}));
},
labelField: 'label',
valueField: 'value',
placeholder: $t(
'web.crmCustomer.create.form.placeholder.selectCustomerCountry',
{ defaultValue: '请选择注册地国家/地区' },
),
showSearch: true,
optionFilterProp: 'label',
getPopupContainer: getSelectPopupContainer,
},
defaultValue: undefined,
rules: z
.string({
required_error: $t(
'web.crmCustomer.create.form.validation.customerCountryRequired',
{ defaultValue: '注册地国家/地区不能为空' },
),
invalid_type_error: $t(
'web.crmCustomer.create.form.validation.customerCountryRequired',
{ defaultValue: '注册地国家/地区不能为空' },
),
})
.trim()
.min(
1,
$t('web.crmCustomer.create.form.validation.customerCountryRequired', {
defaultValue: '注册地国家/地区不能为空',
}),
),
formItemClass: 'col-span-1',
},
{
fieldName: 'adminDiv',
label: getAdminDivDefaultName(),
component: 'AdminDivSelector',
componentProps: {
countryCode: undefined,
},
dependencies: {
triggerFields: ['customerCountry'],
show: (values: any) => !!(values.customerCountry ?? '').trim(),
trigger: async (values: any, actions: any) => {
const countryCode = (values?.customerCountry ?? '').trim();
const locale = preferences.app.locale || 'zh-CN';
const nextLabel = countryCode
? (
await getAdminDivDisplayName({
countryCode,
locale,
})
)?.displayName || getAdminDivDefaultName()
: getAdminDivDefaultName();

const currentSchema = actions?.state?.schema ?? [];
const currentLabel = currentSchema.find(
(item: any) => item?.fieldName === 'adminDiv',
)?.label;

// 仅在文案变化时更新,避免重复 setState 触发联动抖动
if (
typeof currentLabel === 'string' &&
currentLabel.trim() === nextLabel.trim()
) {
return;
}

actions?.updateSchema?.([
{
fieldName: 'adminDiv',
label: nextLabel,
},
]);
},
componentProps: (values: any) => ({
countryCode: (values.customerCountry ?? '').trim() || undefined,
}),
rules: (values: any) => {
// 提交时在 create.vue 中做显式校验,避免国家切换时即时触发必填报错
return z.string().optional();
},
},
defaultValue: undefined,
rules: z.string().optional(),
formItemClass: 'col-span-1',
},

表单详情使用

行政区的 code,拼装好传到接口,后端去查,然后把显示名称组织好返回前端 ,需要加个这样的接口,根据请求的语言,返回对应的内容

技能包管理模块与生成器 Skill 设计

· 阅读需 4 分钟
Quany
软件工程师

我来搜索关于 OpenSpec 和 Superpowers 的相关信息。Superpowers 可能指的是 Superpowers.js(JavaScript 解析器库)或其他相关技术。 这两个项目代表了 AI 辅助编程领域的两种截然不同的技术路径,它们并非竞品关系,而是分层协作的"兄弟俩"

核心定位对比

维度OpenSpecSuperpowers
本质变更治理层(Change-centric)执行质量层(Behavior-centric)
核心目标对齐需求、沉淀规范、追溯变更拧紧执行过程、保障代码质量、强制纪律
解决痛点"变更一开始就走歪""方向对了,但执行做烂"
工作方式工件驱动(proposal/specs/design/tasks)行为驱动(skills + workflow)
关键产出可审计的规范文档 + 增量变更历史高质量代码 + 强制验证流程

OpenSpec:规范驱动的变更治理

由 Fission AI 开发,核心理念是**"先写规范,再写代码"**,通过 Delta 机制管理增量变更 。

核心特性:

  • 棕地优先(Brownfield-first):专为改造现有代码库设计,分离 openspec/specs/(当前事实)和 openspec/changes/(提案变更)
  • Delta 规范:用 ADDED/MODIFIED/REMOVED 标记追踪增量,而非重写全部规范
  • 四阶段工作流:Draft Proposal → Review → Apply → Archive
  • 多工具支持:兼容 Claude Code、Cursor、GitHub Copilot 等 20+ 种 AI 工具
  • 零依赖:MIT 开源,无需 API 密钥

适用场景:需求复杂、边界不清的老项目改造;需要长期维护、严格架构规范、强调团队协作的大型项目 。


Superpowers:流程强制的执行质量保障

由 Obra 开发,核心理念是**"流程即法律"**,通过不可跳过的"技能"约束 AI 行为,强制遵循 TDD、Code Review 等最佳实践 。

核心特性:

  • 强制技能调用brainstormingwriting-planstest-driven-developmentcode-reviewfinishing-a-development-branch
  • TDD 强制:必须遵循 Red-Green-Refactor 循环,即使是修小 Bug 也会触发全套流程
  • 任务细化与并发:自动拆分任务粒度,决定哪些适合并行推进
  • 系统化调试systematic-debugging 技能避免"胡试"式调 Bug
  • 验证与收尾纪律verification-before-completion 确保代码真正跑过验证

适用场景:从 0 到 1 的需求探索;对代码质量、测试覆盖有极高要求的项目;需要养成良好编码习惯的新手 。


关键差异:不是竞品,是分层互补

对比点OpenSpecSuperpowers
计划层级变更级规划(Why & What)执行级规划(How & When)
核心问题这次变更为什么要做?到底要改什么?任务拆得够不够细?有没有先写测试?
强项规格驱动、变更沉淀、影响可追溯任务细化、TDD、验证、review、收尾纪律
盲区不强制执行代码质量不天然沉淀变更工件与长期规格资产
最大优势适合老项目增量治理强制纪律避免执行偷懒

一句话总结

OpenSpec 负责"写清楚",Superpowers 负责"做干净"


组合使用:企业级 AI 编码工作流

真正复杂的项目往往需要两者配合 :

需求与变更对齐      → OpenSpec(/opsx:new → /opsx:ff)
执行质量控制 → Superpowers(brainstorming → TDD → review)
团队协作与长期沉淀 → OpenSpec + Superpowers 共同补位

典型组合场景

  1. 老项目重构:先用 OpenSpec 对齐 change 的范围和设计,再用 Superpowers 保证实施质量
  2. 中大型功能上线:OpenSpec 保证需求清楚,Superpowers 保证测试、验证不掉链子
  3. 又怕跑偏又怕返工:OpenSpec 稳住方向,Superpowers 稳住执行

选择建议

你的现状推荐工具
最缺"需求对齐、变更沉淀、团队协作规范"OpenSpec
最缺"TDD、调试方法、验证纪律"Superpowers
需求明确、追求快速验证OpenSpec
需求模糊、需要探索性开发Superpowers
已把 AI 真正用进工作项目两者组合

正如社区开发者所言:它们不是"谁更好"的关系,而是**"变更治理"与"执行质量"两个维度的互补** 。

技能包管理模块与生成器 Skill 设计

· 阅读需 8 分钟
Quany
软件工程师

日期:2025-02-09
状态:已确认


第一节:目标与范围

目标

  • 系统侧:在现有芋道后台中增加「技能包」管理能力,运营/管理员可创建、编辑、发布技能包(业务数据落库,供 AI Agent 或其它业务消费)。
  • 开发侧:在 Cursor 中提供一个「创建技能包(管理模块)」的 skill,能像 biz-crud-create-page 一样一键生成「技能包」的整条管理链路(表结构 + 字典 + 菜单 + 后端 CRUD + 前端列表/表单/详情),并遵循项目既有规范。

范围

  • 技能包在系统内视为一种业务实体:有名称、编码、描述、状态(草稿/已发布等)、版本、所属分类等可配置字段;具体字段在第二节数据模型中确定。
  • 管理能力:列表(含筛选)、新增、编辑、删除、发布/下架;详情页可展示包内「技能」列表或配置摘要(首期做简单列表,复杂编排可后期扩展)。
  • 生成器 skill:只负责生成「技能包管理」这条 CRUD 链路(含一个技能包表及必要字典/菜单),不生成「包内单个 skill 的 SKILL.md 文件」;若以后需要「从管理页导出为 Cursor skill 目录」,再单独做导出功能。
  • 消费方式本期只做数据就绪:表与 API 先有,供前端或内部调用;若已有或计划有 Agent 服务,可直接读同一套 API。

不包含(YAGNI)

  • 包内技能的在线编辑器、版本 diff、审批流、多租户隔离(除非现有项目已强依赖租户)。
  • 技能包市场、分享、权限到「包内单条技能」的细粒度控制。

成功标准

  • 用 skill 生成一遍后,能在后台看到技能包菜单,完成列表/增删改/发布状态切换。
  • 生成物符合现有数据库、后端、前端规则(与 lead/source 或 lead/personal 风格一致)。

第二节:数据模型与字典

主表 ai_skill_package

  • 与现有规范一致:主键 id(雪花)、creator/create_time/updater/update_time/deletedtenant_id(多租户)。
  • 业务字段:name(名称)、code(编码,租户内唯一,用于 API/导出)、description(描述,VARCHAR(500) 或 TEXT)、status(状态,见下)、sort(排序,INT 默认 0)、content(TEXT,可选,存包内技能摘要或 JSON,后续可扩展)。
  • 索引:uk_ai_skill_package_code_tenant (code, tenant_id, deleted)idx_ai_skill_package_status (status)idx_ai_skill_package_sort (sort)

字典

  • skill_package_status:草稿(DRAFT)、已发布(PUBLISHED)、已下架(OFFLINE)。列表筛选、详情、发布/下架操作均用该字典。
  • (可选)skill_package_category:如「业务生成」「Agent 技能」等,便于后续分类筛选;若首期不做分类,可不建该字典。

包内技能(首期从简)

  • 不单独建「技能项」表,用主表 content 存一段文本或 JSON 即可(例如技能名称列表 + 简要说明),详情页只读展示。若后续需要逐条增删改「包内技能」,再增加 ai_skill_package_item 表与前后端。

菜单与权限

  • 一级菜单(示例):「AI 技能」或放在现有某父级下,path 如 /ai/skill-package
  • 二级:技能包管理,permission 前缀 ai:skill-package:query/create/update/delete,并可加 ai:skill-package:publish 控制发布/下架。

第三节:后端与前端实现要点

后端

  • 模块:放在现有 yudao-module-ai,若当前只有 pom,则在该模块下按规范建包:controller.admindal.dataobject.skilldal.mysql.skillservice.skillconvert.skillcontroller.admin.vo.skill(PageReqVO/RespVO/SaveReqVO,按需 SimpleRespVO)。
  • 接口约定:Base URL /admin-api/ai/skill-package。提供:分页查询 getPage、详情 get、新增 create、修改 update、删除 delete、发布 publish、下架 offline。权限标识:ai:skill-package:query/create/update/delete,发布/下架可用 ai:skill-package:publish 或复用 update。
  • 实现要点:DO 继承 TenantBaseDO,表名 ai_skill_package。发布/下架即把 status 置为 PUBLISHED/OFFLINE 并做幂等与状态校验(如仅草稿可发布、仅已发布可下架)。错误码在 yudao-module-ai 的 ErrorCodeConstants 中新增,Controller 用 @PreAuthorize 与现有风格一致。

前端

  • 路由:在 router/routes/modules 下新增 ai.ts(或并入已有 AI 路由),path 如 /ai/skill-package,组件 ai/skill-package/index;列表、新增/编辑、详情对应同一模块下的 index、create、edit、detail。
  • 列表页Page + useVbenVxeGrid,查询项:名称(Input)、编码(Input)、状态(Select,DICT_TYPE.skill_package_status)。表格列:名称、编码、状态(CellDict)、排序、更新时间、操作(编辑/删除/发布/下架,按状态显隐)。API 与后端分页约定一致(pageNo、pageSize、表单条件、排序)。
  • 表单(新增/编辑):名称、编码、描述、排序、状态(草稿时可选)、content(可选,Textarea)。编码新增时必填,编辑时只读或禁用。校验:编码格式、名称非空。
  • 详情页:只读展示上述字段;若有 content,以只读区块或简单 JSON/文本展示「包内技能」摘要。
  • 发布/下架:列表操作列按钮,调用 publish/offline 接口后刷新列表;可加二次确认(如「确认发布?」)。

与现有风格对齐

  • 后端 VO 命名、分页参数、统一返回与 CRM 模块一致;前端 data.ts 中 formSchema/columns、TableAction、权限 ai:skill-package:xxx、i18n key 前缀统一(如 ai.skillPackage.xxx)。组件与数据源遵守 .cursor/skills/biz-crud-create-page/component-data-mapping.md(本业务若无特殊下拉可仅用字典)。

第四节:生成器 Skill 设计

定位与触发

  • 新建项目内 skill:.cursor/skills/create-skill-package-module/,内含 SKILL.md。触发场景:用户说「生成技能包管理模块」「创建技能包管理页」「按 createPage 风格做技能包」等时,Agent 优先使用该 skill。
  • biz-crud-create-page 的关系:不替代,复用其规则与参考。本 skill 只针对「技能包」这一固定业务,产出表名、实体名、模块名、菜单/权限前缀、字典类型等均写死在 skill 内,无需用户再走「查询项→表格→功能清单」多步交互;若以后要支持「自定义实体名的技能包」,再考虑引入类似 create-page 的交互。

生成顺序(与 create-page 一致,严禁颠倒)

  1. SQLsql/mysql/ 下新增 ai_skill_package.sql(建表)、ai_skill_package_dict.sql(skill_package_status 等字典,幂等)、ai_skill_package_menu.sql(AI 技能 / 技能包管理菜单及 ai:skill-package:query 等按钮权限,含 role_id=1 的 system_role_menu)。
  2. 后端:在 yudao-module-ai 中生成 DO(TenantBaseDO)→ Mapper → Service 接口与 Impl → Controller(/admin-api/ai/skill-package)→ VO(PageReqVO、RespVO、SaveReqVO);ErrorCodeConstants 中新增错误码;发布/下架在 Service 内做状态流转与校验。
  3. 前端router/routes/modules/ai.ts 中注册列表与 detail/create/edit 路由;views/ai/skill-package/ 下 index.vue、data.ts、create.vue、edit.vue、detail.vue(弹窗 CRUD 则用 modules/form.vue);api/ai/skill-package/index.ts;i18n 键与菜单名称一致。

Skill 文档必须写清的内容

  • 本模块固定参数表:表名 ai_skill_package、模块名 ai、实体名 skillPackage(前端)、权限前缀 ai:skill-package、字典类型 skill_package_status、参考实现路径(可与本设计文档互相引用)。
  • 必读规则:.cursor/rules/backend/database.mdcbackend-project-structure.mdc.cursor/rules/frontend/biz-crud-page-standard.mdc;参考实现指向「技能包」生成后的代码或现有 lead/source 的目录结构说明。
  • 生成后校验:要求执行 node .cursor/skills/biz-crud-create-page/scripts/validate-page.mjs ai skill_package --backend(若 validate-page 支持 ai 模块);或在本 skill 下提供专用 validate-skill-package.mjs,检查 SQL、菜单、路由、views、API、后端 DO/Controller 是否存在且符合约定。

可选

  • 本 skill 的 reference.md 中列出「技能包管理」字段与接口清单,便于 Agent 一次生成完整;scripts/ 下仅保留校验脚本,不提供通用代码生成引擎。

第五节:错误处理与验收

错误处理

  • 后端:编码重复返回 400 及明确错误码;发布/下架状态不合法(如对已下架再下架)返回 400 并提示当前状态;删除前可做关联校验(若未来有包内技能表则先判空)。
  • 前端:接口失败用项目统一提示;列表加载失败可重试或空状态提示。
  • 生成器:校验脚本以非 0 退出并打印缺失项(如「缺少 ai_skill_package_menu.sql」),Agent 按提示补全后重新运行直至通过。

验收标准

  • 执行 skill 生成一遍后:执行 SQL、启动后端与前端,能在「AI 技能」下看到「技能包管理」,完成列表筛选、新增、编辑、删除、发布、下架、详情查看;数据落库且状态正确。
  • 生成代码通过项目既有 Lint/编译;菜单与权限与设计一致。

如何节省 token

· 阅读需 3 分钟
Quany
软件工程师

总体思路

目标就是两件事:

  1. 减少「自动带进来但其实用不到」的上下文
  2. 减少「每次对话需要重复扫描的大文件/大结构」

一、项目结构 / 忽略规则层面

扩充 .cursorignore

把"永远不需要读"的东西都排掉(你已经忽略了 node_modulesbackend/target,不错):

可以考虑再加:

# 编译产物
frontend/web/dist
frontend/app/android
frontend/app/ios
*.log

# 大型静态资源(如果你几乎不会问这些)
**/*.png
**/*.jpg
**/*.mp4

# 测试快照、coverage
**/__snapshots__/**
coverage/**

文档/规范集中到少数文件

把"项目规范、工作流"集中到 CLAUDE.md + 少数 docs/plans/*.md,避免在很多散文件里重复长说明,每次都要被模型扫一遍。


二、Cursor / Claude 配置层面(减少自动上下文)

这些不需要改代码,只是你使用 Cursor 时的习惯:

少用/慎用「自动附加大 Skill」

这次聊天你手动附了 brainstorming,它本身字数不多还好。但类似 superpowers 的大 skill,如果不是每次都需要,可以:

  • 真要用时再贴;
  • 或者把你自己常用的 1–2 个写成更短版 Skill。

控制自动附加的文件数量与大小

在实际使用中:

  • 问问题前,尽量只打开/高亮与你问题最相关的 1–2 个文件;
  • Cursor 会优先把"当前打开文件 + 最近文件"丢给模型,开太多大文件会明显增大 token。

分阶段问问题,而不是一次性贴超长 diff / 多个大文件

比如 App 导航、某一模块的 UI、某个 API 层,尽量拆开问。

  • 对"结构性问题"先问高层(架构、目录),再 drill down 到具体实现。

三、日常使用习惯层面(你和我的交互方式)

这些是你现在就可以改变的操作方式,会立刻省 token:

尽量引用"路径 + 行号"而不是整文件粘贴

在 Cursor 里说:

看下 frontend/app/src/navigation/index.tsx 的路由结构

让我自己用只读工具去读,比你复制整个文件到聊天里便宜很多。

大文件只问一个点

不要说"帮我 review 整个线索模块",而是:

  • 先:"帮我理解 ClueOrigin 这块的筛选逻辑"
  • 再:"再看下它和 ClueMain 的关系"

这样每次只需要一小部分上下文。

控制回答详细程度

像你现在这样不要求超长讲解,其实就已经在省 token 了;如果后面你觉得"回答太长",可以直说:

"只给结论和关键代码引用,不要铺垫"

我会按你要求压缩输出。


四、如果你愿意再进阶一点的做法

给 Cursor/Claude 写更短的 RULE / Skill

例如专门为这个项目写一个 RULE.md

  • 只说明技术栈、目录结构、OpenSpec 工作流的"精简版";
  • 把长篇解释放在仓库的 docs/,需要时你再手动提示我去看。

把「经常要看的大文档」拆成多个小文件

比如一个 2000 行的 spec,可以拆成按模块的 3–4 个; 这样每次只会读到相关那一份。


简单总结

减少 token 的核心就是"缩小自动上下文 + 精准地引用需要看的文件/片段"。

如果你愿意,我可以帮你草拟一版更"节省 token"风格的 .cursorignore 和一个精简版的 RULE 模板,你自己手动去改就行。

Tailscale

· 阅读需 2 分钟
Quany
软件工程师

Tailscale 是一种基于 WireGuard 协议构建的**零配置虚拟专用网络(VPN)**解决方案,专注于为个人用户和企业提供简单、安全的网络连接。

核心功能

特性说明
Mesh VPN创建私有网络,让设备直接互联(P2P),不经过中心服务器
零配置无需手动管理 IP、防火墙规则,安装即用
跨平台支持 Linux、macOS、Windows、iOS、Android、BSD 等
SSO 集成支持 Google、Microsoft、GitHub、Okta 等身份提供商
MagicDNS自动为设备分配易记的主机名(如 my-laptop.tailscale
ACL 控制细粒度的访问控制列表,管理谁可以访问什么资源

典型使用场景

  • 远程访问内网服务:从外网安全访问家中的 NAS、Raspberry Pi、服务器等
  • 跨地域团队协作:将分布在全球的办公网络和员工设备组成统一网络
  • 开发测试环境:快速搭建安全的开发/测试网络,模拟生产环境
  • IoT 设备管理:统一管理分散的智能设备,无需公网 IP

技术原理

  1. 基于 WireGuard:使用现代加密协议,性能优于传统 VPN(如 OpenVPN、IPsec)
  2. Coordination Server:Tailscale 的控制平面仅负责密钥分发和 NAT 穿透协调
  3. DERP Relay:当 P2P 直连失败时,通过中继服务器转发流量(加密)
  4. NAT Traversal:自动处理各种 NAT 环境,最大化实现直连

定价模式

  • 个人免费版:最多 20 个设备,基础功能齐全
  • 个人 Pro:$4/月,无限设备 + 子网路由
  • Team/Business:按用户收费,提供 SSO、审计日志、API 等高级功能

与同类产品对比

产品特点
Tailscale最易用,个人版免费,企业级安全
ZeroTier开源,自托管友好,配置稍复杂
HeadscaleTailscale 的开源替代控制端,可完全私有化
Netbird/Netmaker更开源、自托管,生态较小

如果你是想搭建一个完全私有的 Tailscale 网络(不依赖 Tailscale 官方服务器),可以了解 Headscale —— 它是 Tailscale 控制服务器的开源实现,支持完全自托管。

Web → App 基于 OpenSpec 的开发流程

· 阅读需 6 分钟
Quany
软件工程师

Web → App 基于 OpenSpec 的开发流程

创建日期: 2026-02-04
适用范围: 线索 / 客户等 CRM 业务,从 Web 需求演进到 App 实现


1. 流程总览

从一个功能/改动诞生,到 App 上线闭环,推荐遵循下面的主流程:

  1. 需求进入(通常先在 Web 上提出或实现)
  2. 统一业务到主 Spec(openspec/specs/*
  3. 评估是否需要 App 跟进
  4. 为 App 创建 / 更新对应的 OpenSpec change(openspec/changes/app-*
  5. 在 change 的 design.md 中完成 App UX 设计(信息架构 + 页面流程 + 布局)
  6. design.md 拆分实施任务到 tasks.md
  7. 按任务开发、测试 App,并持续回填 Spec / 设计 / 任务
  8. 使用 openspec verify 验证,再 archive 完成变更归档

2. 需求进入 → 统一到主 Spec

目标: 无论 Web 或 App,所有业务规则以 openspec/specs/* 为唯一真源。

  • 当有新需求或 Web 行为变更时,先检查:
    • 当前业务是否已经有对应 Spec(例如:lead-poolpersonal-leadscustomer-conversion 等)。
    • Web 实际行为与 Spec 是否一致。
  • 若不一致:
    • 创建一个小的业务同步 change(如 2026-02-xx-sync-lead-spec)。
    • 在该 change 中仅做两件事:
      • 修正/补充主 Spec:更新 openspec/specs/* 中的字段、状态流转、规则说明。
      • 记录原因:在 proposal.md / design.md 中说明“为什么要改 Spec(与历史实现的差异)”。

完成后,Web 与 App 后续均以更新后的主 Spec 为准。


3. 决定是否需要 App 跟进

在业务 Spec 更新后,进行一次轻量评估:

  • 该改动是否影响移动端的核心场景?
    • 例如:线索列表字段调整、转化规则变化、客户关键信息修改等。
  • 评估结果:
    • 必须跟进:影响主流程或数据一致性,必须在 App 中同步。
    • 推荐跟进:改善体验,但不是硬性要求,可以合并到后续 App 迭代。
    • 暂不需要:仅 Web 端特有的桌面场景,可暂不做 App 支持。

当结论为“必须/推荐跟进”时,进入下一步,为 App 创建/更新 change。


4. 为 App 创建 / 更新 OpenSpec change

命名建议:

  • openspec/changes/app-<模块>-<目标>,例如:
    • app-lead-mobile-list(线索列表移动端版本)
    • app-customer-conversion-flow(客户转化流程)

proposal.md 建议内容:

  • 背景: 关联哪些业务 Spec(链接到 openspec/specs/*)。
  • 目标用户: 例如一线销售 / 经理。
  • 业务目标: 希望这次在 App 上达成的业务效果(而非技术细节)。
  • 范围边界: 这次 App 改动包含/不包含哪些屏幕和操作。

5. 在 design.md 中完成 App UX 设计(先设计再开发)

design.md 是这条 Web → App 变更在 App 侧的“设计真源”,推荐固定结构如下:

5.1 关联主 Spec 与场景

  • 列出本次改动关联的业务 Spec:
    • 例如:[lead-pool](../../specs/lead-pool/spec.md)[customer-conversion](../../specs/customer-conversion/spec.md)
  • 用 1–2 句话说明本次在 App 上解决的核心场景:
    • 如:“让销售在移动端快速筛选高意向线索并发起跟进/转化”。

5.2 信息架构(App IA)

  • 列出涉及的 App 屏幕及一句话职责,例如:
    • LeadListScreen:我的线索列表,帮助销售快速找到“现在最值得处理”的线索。
    • LeadDetailScreen:线索详情 + 跟进记录,集中展示决策所需信息。
    • LeadConvertScreen:转化流程,减少误操作,用最少步骤完成转客户。

5.3 用户流程(User Flow)

  • 用步骤方式描述从入口到完成任务的路径,例如:
    • 首页 → 点“线索”入口 → 线索列表 → 筛选 → 详情 → 新增跟进 → 转为客户。
  • 对应线索/客户等核心流程可以只写 1–2 条“标准路径”,其余放到 tasks.md 验收里。

5.4 屏幕布局与组件粒度

  • 关键屏幕(例如线索列表、线索详情)写到组件级:
    • 顶部搜索、快捷筛选 Chips、列表卡片的字段排布、底部主按钮等。
  • 次要屏幕可只写区块级:
    • 顶部标题区、中部表单区、底部操作区。
  • 不要求画高保真,只需说明信息密度、主次层级与主要交互。

5.5 状态与反馈

  • 加载中、空数据、错误、权限不足时的表现:
    • 是否有 Skeleton 占位、空态文案、重试按钮等。
  • 哪些操作需要 Toast,哪些需要确认弹窗。

5.6 与 Web 的 UX 对齐与差异

  • 明确哪些行为必须与 Web 一致(例如:校验规则、必填字段)。
  • 明确为移动端刻意做的差异(例如:字段裁剪、操作合并到底部按钮栏)。

6. 从 design.md 拆分到 tasks.md

tasks.md 用于驱动实施与测试,建议按以下维度拆分:

  1. 屏幕与导航
    • 创建/调整相应的 Screen 与路由。
    • 配置 Tab / Stack 结构与入口位置。
  2. 组件与状态
    • 列表卡片、详情块、过滤组件、表单等 UI 任务。
    • 本地 UI 状态(loading/error/selected item 等)。
  3. API 与数据流
    • 调用哪些后端接口,如何与 shared API 连接。
    • 使用 Jotai / Zustand 管理哪些业务状态。
  4. 验收与测试
    • design.md 的用户流程中抽取手工验收用例。
    • 设计 e2e 场景(登录 → 打开模块 → 执行核心路径)。

开发以 tasks.md 为 TODO 清单执行,过程中有变更应回填:

  • 业务规则问题 → 优先修改主 Spec(openspec/specs/*)。
  • 只是 UX/实现细节微调 → 更新 design.md / tasks.md

7. 开发、验证与归档

7.1 开发与自检

  • tasks.md 完成所有实现任务:
    • 屏幕/组件/导航/状态管理/API 调用。
  • 在 App 项目中执行基础自检:
    • npx tsc --noEmit
    • yarn lint
    • 关键路径的手工走查。

7.2 使用 openspec verify

  • 在 verify 阶段对照以下内容逐条检查:
    • proposal.md 中的业务目标是否达成。
    • design.md 中的信息架构、流程、关键 UX 是否已实现。
    • tasks.md 中的实施任务与测试任务是否全部完成。
    • 与主 Spec 的行为是否保持一致,差异是否在设计中有记录。

7.3 archive 归档

  • 验证通过后执行归档,将 change 移入 openspec/changes/archive
  • 归档后的 change 就是这次 Web → App 能力同步的完整“变更记录”,便于后续审计与演进。

8. 推荐落地顺序(线索 / 客户试点)

  1. 选择一条业务(推荐:线索列表 + 线索详情 + 转化)。
  2. 校准相关主 Spec(lead-poolpersonal-leadscustomer-conversion 等)。
  3. 新建 openspec/changes/app-<lead-module> change。
  4. 按本指南格式完善该 change 的 design.mdtasks.md
  5. 驱动一次完整的 App 实施与验收闭环。

完成这条试点后,可以将本文件作为团队在其他模块(待办、机会、Dashboard 等)的共用开发流程规范。