适用于 H5、移动端 App 等项目,内置常用移动端工程能力与团队规范。

基于 Vue 3 的移动端 H5 应用脚手架模板,面向海政通 / 海易办等移动端场景,提供开箱即用的开发体验。

| Node | >=22.21.1 | |
|---|---|---|
| szhn-cli | >=2.3.2 | 使用npm install -g @szhn/szhn-cli@latest --registry=https://npmmirror.digitalhainan.com.cn/ 更新脚手架到最新版本 |
| pnpm | latest | 安装速度快,磁盘空间节省,严格依赖隔离,禁止使用 npm、yarn |
| 类别 | 技术 | 版本 | 说明 |
|---|---|---|---|
| 框架 | Vue | 3.5+ | Composition API + <script setup> |
| 构建工具 | Vite | 7.x | 基于 Rolldown(Rust),极快的 HMR 和构建 |
| 语言 | TypeScript | 5.6+ | 全量类型覆盖 |
| 路由 | Vue Router | 4.x | 文件路由自动生成 |
| 状态管理 | Pinia | 2.x | Setup Store 风格 |
| 数据请求 | TanStack Query | 5.x | 缓存、去重、自动刷新 |
| HTTP 客户端 | Axios | latest | 请求/响应拦截、统一错误处理 |
| UI 组件库 | Vant | 4.x | 移动端 Vue 组件库 |
| CSS 框架 | Tailwind CSS | 3.x | 原子类样式(Rust 引擎 · CSS-first 配置),4.x版本在低版本海易办系统有兼容性问题 |
| 工具函数 | VueUse | 14.x | 100+ Composition API 工具集 |
| 项目 | 链接 |
|---|---|
| GitHub | posva/unplugin-vue-router |
| 文档 | uvr.esm.is |
src/views/ 目录结构自动映射为路由,无需手动维护路由表typed-router.d.ts,路由跳转有 TypeScript 提示[param] 命名约定支持动态参数src/views/
├── (home)/
│ ├── index.vue → /
│ ├── query/
│ │ ├── index.vue → /query
│ │ └── [id].vue → /query/:id
│ └── routes/
│ ├── index.vue → /routes
│ └── [slug].vue → /routes/:slug
├── tools/
│ └── index.vue → /tools
└── [...all].vue → /:all(.*) // 404<script setup lang="ts">
const router = useRouter();
router.push('/query');
const route = useRoute('/query/[id]');
console.log(route.params.id); // 类型安全
</script>| 项目 | 链接 |
|---|---|
| GitHub | unplugin/unplugin-auto-import |
无需手动 import,直接使用 Composition API:
// without
import { computed, ref } from 'vue'
const count = ref(0)
const doubled = computed(() => count.value * 2)
// 直接使用,无需 import
const count = ref(0)
const doubled = computed(() => count.value * 2)
const router = useRouter()自动导入范围:
| 来源 | 包含的 API |
|---|---|
| Vue | ref, reactive, computed, watch, onMounted 等 |
| Vue Router | useRouter, useRoute, onBeforeRouteLeave 等 |
| Pinia | defineStore, storeToRefs 等 |
| VueUse | useLocalStorage, useClipboard, useDark 等 100+ composables |
| TanStack Query | useQuery, useMutation, useInfiniteQuery, useQueryClient 等 |
| Vant | showToast, showDialog, showNotify, showConfirmDialog 等 |
| 项目 | 链接 |
|---|---|
| GitHub | unplugin/unplugin-vue-components |
<van-button>,无需手动 importsrc/components/ 下的组件自动全局注册
<!-- 直接使用,无需 import -->
<template>
<van-button type="primary">按钮</van-button>
<van-cell-group>
<van-cell title="单元格" value="内容" />
</van-cell-group>
</template>| 项目 | 链接 |
|---|---|
| 官网 | tanstack.com/query |
| Vue Query 文档 | Vue Overview |
解决的痛点:
onMounted + axios,缺乏统一管理loading / error 各写一遍,风格不统一核心能力:
staleTime 内直接返回缓存queryKey,只发一次请求loading、error、data 开箱即用调用关系链:
组件 → useQuery → queryFn → axios(http.request) → 后端 API
↕
缓存 / 状态管理src/utils/http/ 中的 Axios 封装继续负责请求拦截、Token 注入、错误码处理;TanStack Query 在其之上负责缓存和状态管理。
详细使用指南: docs/tanstack-query.md
示例页面:/query
开发环境下显示 Query DevTools 面板,可视化查看所有查询的缓存状态、数据内容、时间线。

状态说明
| 颜色 | 状态 | 含义 |
|---|---|---|
| 🟢 绿色 | fresh | 数据新鲜,在 staleTime 内 |
| 🟡 黄色 | stale | 数据过期,下次使用时会后台刷新 |
| 🔵 蓝色 | fetching | 正在请求中 |
| ⚫ 灰色 | inactive | 无组件使用此查询 |
| 项目 | 链接 |
|---|---|
| 官网 | vant-ui.github.io/vant |
移动端 Vue 组件库,轻量可靠。通过 unplugin-vue-components 实现按需自动导入。
数海组件库建设中
| 项目 | 链接 |
|---|---|
| 官网 | tailwindcss.com |
| v3 文档 | v3.tailwindcss.com |
| 升级指南 | tailwindcss.com/docs/upgrade-guide |
当前项目说明:
| 项目 | 链接 |
|---|---|
| 官网 | vueuse.org |
100+ 实用 Composition API 工具集,通过 unplugin-auto-import 自动导入,直接使用即可。
项目已在 vite.config.ts 中通过 unplugin-auto-import 自动导入 @vueuse/core,因此在 script setup 中可以直接使用 VueUse API,无需手动 import。
例如下面这段代码可以直接使用:
<script setup lang="ts">
const { width, height } = useWindowSize()
const { copy, copied } = useClipboard()
async function handleCopy() {
await copy(`当前窗口尺寸:${width.value} x ${height.value}`)
showToast(copied.value ? '复制成功' : '复制失败')
}
</script>
<template>
<div class="space-y-3 rounded-xl bg-white p-4">
<div>宽度:{{ width }}</div>
<div>高度:{{ height }}</div>
<van-button type="primary" block @click="handleCopy">
复制窗口信息
</van-button>
</div>
</template>如果想做输入防抖,也可以直接这样写:
<script setup lang="ts">
const keyword = ref('')
const runSearch = useDebounceFn((value: string) => {
console.log('搜索关键词:', value)
}, 300)
watch(keyword, (value) => {
runSearch(value)
})
</script>
<template>
<van-field v-model="keyword" placeholder="请输入关键词" />
</template>说明:
package.jsonsrc/typings/auto-imports.d.ts| 项目 | 链接 |
|---|---|
| GitHub | antfu/eslint-config |
| ESLint Stylistic | eslint.style |
@stylistic/eslint-plugin 接管代码风格(缩进、引号、分号等)pnpm lint** 一条命令**:同时完成 lint 检查和代码格式化// eslint.config.ts
import antfu from '@antfu/eslint-config';
export default antfu({
vue: true,
typescript: true,
formatters: true,
stylistic: { quotes: 'single', semi: true },
}, {
rules: {
'no-console': 'off',
'vue/block-order': ['error', { order: ['script', 'template', 'style'] }],
},
});快速定位代码位置
| 项目 | 链接 |
|---|---|
| GitHub | nicolo-ribaudo/code-inspector-plugin |
| 文档 | inspector.fe-dev.cn |
代码中展示代码对应的文件路径

在浏览器中点击页面元素,自动在 IDE 中打开对应源码文件并定位到行号。
| 系统 | 快捷键 |
|---|---|
| Mac | Option + Shift + 点击页面元素 |
| Windows | Alt + Shift + 点击页面元素 |

| 项目 | 链接 |
|---|---|
| GitHub | vuejs/devtools-next |
Vite 插件形式集成,支持组件树查看、Pinia 状态、路由信息、性能分析。

| 项目 | 链接 |
|---|---|
| GitHub | vadxq/vite-plugin-vconsole |
| 项目 | 链接 |
|---|---|
| czg | github.com/Zhengqbbb/cz-git |
| CommitLint | commitlint.js.org |
完整的 Git 提交规范链路:
git add .
↓
pnpm commit ← czg 交互式选择 commit type
↓
pre-commit hook ← lint-staged 自动 eslint --fix
↓
commit-msg hook ← commitlint 校验 message 格式
↓
提交成功 ✓| 项目 | 链接 |
|---|---|
| GitHub | pengzhanbo/vite-plugin-mock-dev-server |
| 文档 | vite-plugin-mock-dev-server.netlify.app |
在项目根目录创建 mock/ 目录:
// mock/user.mock.ts
import { defineMock } from 'vite-plugin-mock-dev-server';
export default defineMock([
{
url: '/dev-api/users',
method: 'GET',
body: {
code: 200,
data: [
{ id: 1, name: '张三', department: '研发部' },
{ id: 2, name: '李四', department: '产品部' },
],
},
},
]);配置代理
仅 proxy 中配置的路径会被 mock 拦截:
// vite.config.ts
server: {
proxy: {
'^/dev-api': { target: '' },
},
}项目内置两种图标方案:i-icon 和 svg-icon。
| 方案 | 适合场景 | 使用方式 |
|---|---|---|
i-icon | 通用业务图标、三方图标库、快速接入 | <i-icon icon="lucide:route" /> |
svg-icon | 项目私有 SVG、品牌图标、设计稿导出的本地图标 | <svg-icon name="light" /> |
选择建议:
i-iconsvg-icon组件位置:src/components/i-icon/index.vue
支持两种写法:
@iconify-icons/* 按需导入图标对象<script setup lang="ts">
import LucideHome from '@iconify-icons/lucide/home'
const onlineIcon = 'lucide:route'
const offlineIcon = LucideHome
</script>
<template>
<div class="flex items-center gap-3 text-xl text-blue-500">
<i-icon :icon="onlineIcon" />
<i-icon :icon="offlineIcon" class="text-orange-500" />
</div>
</template>说明:
lucide:home 可对应导入 @iconify-icons/lucide/home组件位置:src/components/svg-icon/index.vue
使用方式:
src/assets/icons/<svg-icon name="文件名" /><template>
<div class="flex items-center gap-3 text-[18px]">
<svg-icon name="light" class="text-yellow-500" />
<svg-icon name="dark" class="text-slate-700" />
</div>
</template>说明:
src/views/tools/index.vue需要缓存的页面,在页面文件里这样写:
<route lang="json5">
{
meta: {
title: '列表页',
keepAlive: true,
},
}
</route>不需要缓存的页面,不写 keepAlive 就行。
如果你希望从详情页返回后回到离开前的滚动位置,再加上这个 Hook:
<script setup lang="ts">
import { usePageScrollCache } from '@/hooks/usePageScrollCache'
usePageScrollCache({ key: 'order-list' })
</script>keepAlive: trueusePageScrollCache 的 key 要保证每个页面都不一样,避免互相覆盖滚动位置src/views/(home)/scroll-cache/index.vuesrc/views/(home)/scroll-cache/[id].vuesrc/hooks/usePageScrollCache.ts一句话:
keepAlive: trueusePageScrollCache
| 项目 | 说明 |
|---|---|
| 工具 | @szhn/szhn-cli(全局安装,>= 2.1.3) |
| 配置文件 | .szhnrc.cjs |
双引擎智能压缩:
| 引擎 | 特点 |
|---|---|
| TinyPNG | 高质量有损压缩,需 API Key(获取地址) |
| Sharp | 本地压缩,无需 API Key,可配置质量参数 |
默认使用智能模式:优先 TinyPNG,超出 API 限额自动切换 Sharp。也可在 .szhnrc.cjs 中指定 engine: 'sharp' 强制使用本地引擎。
配置示例(.szhnrc.cjs):
module.exports = {
compress: {
// 不指定 engine: 智能模式(优先 TinyPNG,超限自动切换 Sharp)
// engine: 'sharp': 仅使用 Sharp 引擎(无需 API Key)
apiKey: 'your-tinypng-api-key',
targetDirs: ['./src/assets'],
sharp: {
jpegQuality: 80,
pngQuality: 80,
pngCompression: 9,
webpQuality: 80,
generateWebp: false,
},
watch: false,
},
};使用命令:
# 初始化配置文件(生成 .szhnrc.cjs)
pnpm compress:init
# 执行图片压缩(压缩 targetDirs 中的图片)
pnpm compress项目内已经集成 AI 辅助开发能力,通过多层 Markdown 配置文件约束和引导 AI 行为,尽量保证生成的代码符合当前仓库规范。
当前仓库的 AI 配置入口主要有 6 个:
| 文件 | 作用 |
|---|---|
AGENTS.md | 项目规范主入口,统一维护技术栈、目录结构、编码规范、Agent 定义 |
CONSTITUTION.md | 行为准则与安全边界,约束 AI 不应越界的操作 |
CLAUDE.md | Claude Code 入口文件,负责引导先读取 AGENTS.md 和 CONSTITUTION.md,保留少量仅对 Claude Code 生效的补充说明 |
.cursor/rules/project.mdc | Cursor 入口规则,自动加载项目上下文 |
.github/copilot-instructions.md | GitHub Copilot 入口规则 |
.agents/skills/ | 项目内已安装的技能扩展,补充特定任务领域知识 |
推荐理解方式:
AGENTS.md 管项目规范CONSTITUTION.md 管行为边界CLAUDE.md、Cursor、Copilot 入口文件负责把这两份规范接进各自工具文件位置:项目根目录 AGENTS.md
这是整套 AI 配置的核心文件,也是项目规范的统一入口。AI 工具真正需要遵循的技术栈、目录结构、编码规范、开发约定,统一以这里为准。
| 模块 | 说明 |
|---|---|
| 项目定位 | 说明这是一个 Vue 3 移动端 H5 脚手架,明确适用场景 |
| 技术栈规范 | 统一定义 Vue、Vite、TypeScript、Pinia、Vant、Tailwind CSS、TanStack Query、VueUse、pnpm 等基线 |
| 目录结构规范 | 统一说明 src/api、src/components、src/views、src/composables、src/store 等目录职责 |
| 编码规范 | 统一约束 <script setup lang="ts">、Composition API、类型声明、组件拆分、样式方案 |
| 开发约定 | 统一说明文件路由、自动导入、数据请求、环境变量、常用命令 |
| Agent 定义 | 约定 code-reviewer、component-builder、bug-hunter、doc-writer 等角色职责 |
可以把它理解成:项目规范的 Single Source of Truth。其他入口文件本质上都是先把 AI 引导到这里,再继续执行任务。

文件位置:项目根目录 CONSTITUTION.md
如果说 AGENTS.md 管“应该怎么做”,那 CONSTITUTION.md 管的是“哪些事不能做、哪些事要先确认”。
| 类别 | 说明 |
|---|---|
| 核心原则 | 约束代码质量、项目一致性、最小化变更、透明沟通 |
| 安全规则 | 禁止硬编码敏感信息、禁止危险命令、禁止绕过项目封装直接乱接外部能力 |
| 交互规范 | 要求用中文沟通、说明风险、在不确定时主动确认 |
| 边界约束 | 不随意改核心配置、不做架构替换、不执行发布类操作 |
| 需确认操作 | 依赖增删、文件删除/重命名、Git 操作等必须先征求确认 |
执行优先级:安全规则 > 核心原则 > 交互规范 > 边界约束。
文件位置:项目根目录 CLAUDE.md
这是 Claude Code 的入口文件,本身不重复维护整套项目规范,而是负责把 Claude 引导到正确的规范来源。
| 内容 | 说明 |
|---|---|
| 规范入口 | 明确要求先读取 AGENTS.md |
| 边界入口 | 明确要求同时读取 CONSTITUTION.md |
| Claude 专属补充 | 保留少量仅对 Claude Code 生效的补充说明 |
| Agent 调度提示 | 根据任务类型映射到项目内约定的 Agent 角色 |
也就是说,CLAUDE.md 更像“入口说明书”,而不是项目规范本体。
这些文件和 CLAUDE.md 的定位类似,都是不同 AI 工具的入口层,负责把工具接入到统一规范链路中。
| 文件 | 定位 | 说明 |
|---|---|---|
.github/copilot-instructions.md | GitHub Copilot 入口 | 告诉 Copilot 规范来源在 AGENTS.md 和 CONSTITUTION.md,并补充少量 Copilot 侧关键提示 |
.cursor/rules/project.mdc | Cursor 入口规则 | 通过 alwaysApply 机制让 Cursor 自动加载项目规范上下文 |
.agents/skills/ | 项目技能扩展 | 为特定任务补充更细的实践知识,例如 Vue 最佳实践、调试、路由、测试等 |
整体关系可以概括为:
AGENTS.md 负责项目规范CONSTITUTION.md 负责行为边界CLAUDE.md、.github/copilot-instructions.md、.cursor/rules/project.mdc 负责不同工具的入口接入.agents/skills/ 负责按任务补充专项能力项目内当前已安装的 Skills 位于 .agents/skills/:
| Skill | 作用 |
|---|---|
create-adaptable-composable | 创建可复用、可接收响应式输入的 composable |
vue-best-practices | Vue 3 + <script setup> + TypeScript 最佳实践 |
vue-debug-guides | Vue 运行时问题与异常排查 |
vue-jsx-best-practices | Vue JSX 场景下的写法规范 |
vue-options-api-best-practices | Vue Options API 参考规范 |
vue-pinia-best-practices | Pinia 状态管理模式 |
vue-router-best-practices | Vue Router 4 路由与导航模式 |
vue-testing-best-practices | Vue 测试、Vitest、组件测试实践 |
这些 Skills 的来源记录在 skills-lock.json 中,当前主要来自 vuejs-ai/skills,后续抽离统一管理维护
本脚手架为海政通 / 海易办政务移动端场景预置了完整的集成方案,通过 src/settings.ts 中的开关统一控制。
// src/settings.ts
/**
* 登录方式枚举
* - UAA: 统一登录(UAA SDK),适用于海政通、钉钉等环境
* - TICKET_SNO: 传统登录(ticketSNO/OnecodeJSBridge),适用于旧版海政通等环境
* - AUTH_CODE: 使用AUTH_CODE方式登录
*/
export type LoginType = 'UAA' | 'TICKET_SNO' | 'AUTH_CODE' | '';
/**
* 当前使用的登录方式
*/
export const LOGIN_TYPE: LoginType = '';// src/settings.ts
/**
* 当前使用的登录方式
*/
export const LOGIN_TYPE: LoginType = 'UAA';
// config/uaa.ts
/**
* 配置apiKey
**/
export const UAA_APP_KEY = {
development: '',
test: '',
preview: '',
staging: '',
production: ''
};LOGIN_TYPE = 'TICKET_SNO' 时,路由守卫会走传统登录流程:
authCodeHandleticketSNOgetTokenByTicketSNO({ ticketSNO })LOGIN_TYPE = 'AUTH_CODE' 时,同样会先进入 authCodeHandle:
accountType 和 authCodegetTokenByAuthCode({ accountType, authCode })accessToken / token / access_token 写入 Store 和本地存储// src/settings.ts
// 是否启用火熊监控
export const hasFireBearBrowser = false;
// 是否启用土熊监控
export const hasNativeBearMonitor = false;文件位置: src/utils/fire-bear-browser.ts
| API | 说明 |
|---|---|
init() | 初始化火熊 SDK(通过 Object.defineProperty 劫持 window.FIREBEAR) |
setUser(userId) | 设置用户 ID |
trackEvent(key, segmentation) | 上报自定义事件 |
文件位置: src/utils/native-bear-monitor.ts
| API | 说明 |
|---|---|
init(userId) | 初始化(自动重试 3 次) |
setUser(userId) | 设置用户 ID |
说明: 两个监控 SDK 均按 development / test / production 环境区分配置(appKey、DSN 等),CDN 地址通过环境变量注入。settings.ts 中设为 true 后,main.ts 会在应用启动时自动初始化。
├── .cursor/ # Cursor IDE 配置(rules / skills / commands)
├── .husky/ # Git Hooks(pre-commit / commit-msg)
├── .vscode/ # VS Code 配置(settings / extensions / snippets)
├── docs/ # 项目文档
├── mock/ # Mock 数据文件(按需创建)
├── openspec/ # OpenSpec 变更管理
├── scripts/ # 构建脚本
├── src/
│ ├── api/ # API 接口定义
│ ├── assets/ # 静态资源(图片、字体等)
│ ├── components/ # 公共组件(自动注册)
│ ├── composables/ # Composable hooks(含 TanStack Query hooks)
│ ├── config/ # 业务配置(UAA 等)
│ ├── enums/ # 枚举类型定义
│ ├── hooks/ # 自定义 Composition API hooks
│ ├── layout/ # 布局组件
│ ├── plugins/ # 插件配置(TanStack Query 等)
│ ├── router/ # 路由配置 + 守卫
│ ├── store/ # Pinia 状态管理
│ │ └── modules/
│ │ ├── auth.ts # 认证:Token、用户信息、登录/登出
│ │ ├── dark-mode.ts # 深色模式状态
│ │ └── cached-view.ts # Keep-alive 缓存列表
│ ├── styles/ # 全局样式
│ ├── typings/ # TypeScript 类型定义
│ ├── utils/ # 工具函数
│ │ ├── http/ # Axios 封装(拦截器、错误处理)
│ │ ├── uaa-sdk.ts # 海政通 UAA SDK
│ │ ├── firebear-manager.ts # 火熊监控
│ │ ├── native-bear-monitor.ts # 土熊监控
│ │ ├── dd-tools.ts # 环境检测(钉钉/微信/移动端)
│ │ ├── storage.ts # Token / 用户数据本地存储
│ │ ├── dark-mode.ts # 深色模式工具
│ │ ├── class-names.ts # clsx + tailwind-merge
│ │ ├── progress.ts # NProgress 进度条
│ │ ├── set-page-title.ts # 页面标题设置
│ │ └── validate.ts # 校验工具
│ ├── views/ # 页面组件(文件路由)
│ ├── App.vue # 根组件
│ ├── main.ts # 应用入口
│ └── settings.ts # 功能开关配置
├── CLAUDE.md # AI 开发指南
├── CONSTITUTION.md # AI 行为准则
├── AGENTS.md # AI 智能体配置
├── commitlint.config.js # CommitLint + czg 配置
├── eslint.config.ts # ESLint 配置
├── postcss.config.js # PostCSS 配置
├── vite.config.ts # Vite 配置(含 Tailwind CSS v4 插件)
└── tsconfig.json # TypeScript 配置# 安装依赖
pnpm install
# 启动开发服务器
pnpm dev
# 构建生产版本
pnpm build
# 构建测试环境
pnpm build:test
# 预览生产构建
pnpm preview
# 类型检查
pnpm type-check
# ESLint 检查 + 格式化
pnpm lint
# 初始化压缩资源配置
pnpm compress:init
# 执行压缩脚本
pnpm compress
# Git 交互式提交
pnpm commit
# 版本发布
pnpm release