Compare commits

...

4 Commits

Author SHA1 Message Date
Ironsp
f1e64ef864 Merge branch 'wzp' 2026-09-28 10:02:13 +08:00
Ironsp
4e1bb0f82a feat skills配置 2026-09-28 09:21:34 +08:00
Ironsp
7a2efa3fea feat 搭建架构骨架 2026-09-24 09:09:47 +08:00
Ironsp
dd9f6b77a4 feat init 2026-09-16 11:06:56 +08:00
20 changed files with 10354 additions and 5 deletions

View File

@@ -0,0 +1,240 @@
---
name: auto-dev
description: zc-web 自动化开发全流程 skill。覆盖从原型图/PRD → 蓝湖 MCP 设计稿读取 → API 接口文档 → 页面代码生成 → 组件拆分 → store/api 生成 → 自动验证修正的完整链路。当用户提到"自动化开发"、"从原型生成代码"、"蓝湖设计稿生成页面"、"PRD生成页面"、"虫子开发"、"自动拆分组件"、"生成store"时使用。
version: 1.0.0
---
# zc-web 自动化开发全流程
> 本 skill 驱动从设计稿/PRD 到可运行代码的完整自动化管线。所有生成的代码必须严格遵循 [vue-project-structure](vue-project-structure) skill 的规范。
## 前置条件
1. **项目结构确认**:用 `codegraph_files` 确认 `src/` 目录现有结构
2. **加载 vue-project-structure skill**:所有代码生成必须遵循其分层架构和数据流规范
3. **蓝湖 MCP 就绪**:确认 `lanhu` MCP 服务已启动(`curl http://localhost:8000/mcp`)
---
## 阶段一:PRD 生成
### 从原型图生成 PRD 文档
使用项目根目录的 `read_prototype.js` 读取原型文件:
```bash
node read_prototype.js [原型文件路径]
```
然后根据原型中的布局和交互逻辑,生成 PRD 文档放入 `doc/` 文件夹。
**PRD 内容要求**:
- 页面清单及功能描述
- 每个页面的交互逻辑
- 数据字段定义
- 组件拆分建议
**提示词模板**:
```
运行 ./read_prototype.js [原型文件路径] 读取原型代码,然后根据其中的布局和交互逻辑,为我生成一份 PRD 文档。放在doc文件夹中
```
---
## 阶段二:蓝湖 MCP 设计稿读取
### 连接验证
```javascript
请帮我用 MCP 看看这个蓝湖设计稿:[蓝湖链接]
```
### 批量读取设计稿数据
```javascript
请通过蓝湖 MCP 读取以下设计稿的结构化数据,提取每个页面的:
- 组件尺寸、间距、色值、字体等标注参数
- 全局设计规范(颜色变量、字号体系)
- 切图资源(SVG/PNG),按图层语义化命名
- 布局嵌套结构和循环体检测
蓝湖链接:[蓝湖项目链接]
```
**输出要求**:
- 设计参数表(色值、字号、间距、圆角、阴影)
- 组件结构树(嵌套关系、循环体标记)
- 资源清单(图片/图标路径及语义化命名)
---
## 阶段三:PRD → 页面结构规划
```javascript
以下是我的产品需求文档,请帮我:
- 梳理出所有需要的页面清单,按功能模块分组
- 规划 uni-app / Vue3 项目的页面路由结构
- 识别哪些模块可以复用,哪些是页面独有
- 输出每个页面的核心功能点和数据字段
PRD 内容:[PRD文件路径或内容]
```
**输出物**:
- 页面清单表(模块 → 页面 → 功能点 → 数据字段)
- 路由规划(`pages.json` 或 `router/routes.ts` 结构)
- 复用性分析(哪些组件/逻辑可抽取为公共)
---
## 阶段四:AI 生成页面代码并自动拆分组件
基于 PRD 页面规划和蓝湖 MCP 设计稿数据,生成完整页面代码。
### 目录结构规范(zc-web)
```
views/<page>/
├── index.vue # 页面主组件(路由入口)
├── index.ts # 页面出口 barrel
└── cpns/ # 页面独有组件
├── <ComponentName>.vue
└── ...
```
配套文件:
```
api/<page>.ts # 接口层
stores/modules/<page>.ts # 数据层(Pinia)
types/business/<page>.d.ts # 实体类型
```
### 组件拆分原则
1. **单一职责**:一个组件只做一件事,超过 300 行必须拆分
2. **三层架构**:
- 页面容器(`index.vue`):只负责调度和数据分发,不写业务逻辑
- 业务子组件(`cpns/`):当前页面私有,只接收 props + emit 事件
- 公共基础组件(`components/`):全局复用
3. **按数据维度拆分**:同一批接口数据渲染的区域放一个组件,不同数据源必须拆分
4. **弹窗/抽屉/复杂表单**:一律单独抽离为子组件
### 生成要求
- 父页面只做组件引入、props 分发、事件中转
- 子组件只接收 props 和通过 emit 向上抛事件,不直接调接口
- 样式使用 `<style lang="less" scoped>`,色值从蓝湖数据中精确提取
- 图片和图标使用蓝湖 MCP 导出的本地资源路径
- 组件统一 `<script setup lang="ts">`,props 用 `defineProps<Props>()` + `withDefaults`,emits 用 `defineEmits<{事件名: [参数类型]}>()`
### 提示词模板
```javascript
基于蓝湖 MCP 返回的设计稿数据和 PRD 页面规划,帮我生成 uni-app + Vue3 + TypeScript 的完整页面代码,并按以下原则自动拆分组件:
拆分原则:
1.单一职责:一个组件只做一件事,超过 300 行必须拆分
2.三层架构:页面容器(只负责调度和数据分发)→ 业务子组件(当前页面私有)→ 公共基础组件(全局复用)
3.按数据维度拆分:同一批接口数据渲染的区域放一个组件,不同数据源的模块必须拆分
4.弹窗、抽屉、复杂表单一律单独抽离为子组件
目录结构规范:
pages/
└── <page>/
├── index.vue # 父页面(控制器层,零业务逻辑)
└── components/
├── <Page>Search.vue # 搜索筛选组件(纯 UI,只抛回调)
├── <Page>List.vue # 列表组件(纯 UI,只渲染+抛事件)
├── <Page>Card.vue # 卡片组件(可复用)
└── <Page>Detail.vue # 详情弹窗组件
生成要求:
1.父页面只做组件引入、props 分发、事件中转,不写业务逻辑
2.子组件只接收 props 和通过 emit 向上抛事件,不直接调接口
3.样式使用vue支持的写法,色值从蓝湖数据中精确提取
4.图片和图标使用蓝湖 MCP 导出的本地资源路径
```
---
## 阶段五:生成 API + Store(逻辑层)
为每个页面生成对应的 api 和 store 文件,遵循 zc-web 三层数据流规范(页面 → store → api)。
### 规范
| 层级 | 文件 | 职责 |
| ----- | -------------------------- | ------------------------------------------------------------------ |
| API | `api/<page>.ts` | 封装 axios 接口,定义路径/方法/参数类型/响应类型,不写业务逻辑 |
| Store | `stores/modules/<page>.ts` | 管理状态 + 业务逻辑(请求、loading、分页、数据格式化),不操作 DOM |
| Views | `views/<page>/` | 纯 UI 展示,调用 Store 获取数据,用户交互调用 Store 方法 |
### 生成要求
- **store 使用 Pinia setup 写法**:`ref` 状态 + `computed` getters + 普通函数 actions
- **api 使用 `request<T>`**:统一 axios 实例,不直接 import axios
- **页面禁止直接 import api**:获取数据必须调对应 store 的 action
- **类型定义**:`types/business/<page>.d.ts` 定义实体类型
### 提示词模板
```javascript
为每个页面生成对应的 api, store 文件,放在 api/ ,stores/modules/ 目录下,遵循以下规范:
- store文件统一管理状态 + 业务逻辑(请求、loading、分页、数据格式化),不直接操作 DOM、不写 UI 代码
- api文件封装 axios,定义接口路径、方法、参数类型、响应类型,不写业务逻辑、不操作状态
- views文件纯 UI 展示,调用 Store 获取数据,用户交互调用 Store 方法,不调用 API、尽量不写业务逻辑
- api, store与 UI 组件完全解耦,只通过返回值暴露数据和方法
- store 使用 Pinia setup 写法,api 使用 request<T>
```
---
## 阶段六:自动识别并提取公共组件
```javascript
请扫描整个项目的 pages 目录,识别跨多个页面重复出现的 UI 模块(如导航栏、底部 Tab、空状态、加载动画、通用弹窗等),将它们提取到 components/common/ 目录下作为全局公共组件,并替换所有页面中的引用。
```
**提取判定规则**(与 vue-project-structure skill 一致):
- 被 ≥2 个页面使用 → 放 `components/`
- 仅 1 个页面使用 → 放 `views/<page>/cpns/`
---
## 阶段七:自动化验证与修正
逐页对比蓝湖设计稿和生成的代码,自动检查并修复:
1. **间距、色值、字号**是否与设计稿一致
2. **布局**是否正确(flex 方向、对齐方式)
3. **圆角、阴影、渐变**是否还原
4. **图片资源路径**是否正确
5. **组件拆分**是否合理(是否有超过 300 行的组件需要进一步拆分)
6. **规范合规**:是否有 `as any`、`@ts-ignore`、直接 import api 等违规
**验证命令**:
```bash
pnpm build # 含 vue-tsc 类型检查,零错误才算通过
```
---
## 完整工作流调用顺序
```
阶段一(PRD) → 阶段二(蓝湖MCP) → 阶段三(页面规划) → 阶段四(代码生成) → 阶段五(API+Store) → 阶段六(公共组件) → 阶段七(验证修正)
```
每个阶段可独立调用,也支持一键全流程。
---
## 注意事项
1. **始终先加载 vue-project-structure skill**:所有代码必须符合项目规范
2. **每次动手前先读取项目目录**:确认目标文件存在与现状
3. **命名一致性**:页面 `home` → `api/home.ts` + `stores/modules/home.ts` + `types/business/home.d.ts` + `views/home/` 四者同名
4. **不创建新顶层目录**:在既有职责目录中创建文件
5. **蓝湖 MCP 不可用时**:提示用户检查 Docker 容器和 Cookie 配置,降级为手动提供设计参数

View File

@@ -0,0 +1,77 @@
---
name: karpathy-guidelines
description: Behavioral guidelines to reduce common LLM coding mistakes. Use when writing, reviewing, or refactoring code to avoid overcomplication, make surgical changes, surface assumptions, and define verifiable success criteria.
license: MIT
---
# Karpathy Guidelines
Behavioral guidelines to reduce common LLM coding mistakes, derived from [Andrej Karpathy's observations](https://x.com/karpathy/status/2015883857489522876) on LLM coding pitfalls.
**Tradeoff:** These guidelines bias toward caution over speed. For trivial tasks, use judgment.
## 1. Think Before Coding
**Don't assume. Don't hide confusion. Surface tradeoffs.**
Before implementing:
- State your assumptions explicitly. If uncertain, ask.
- If multiple interpretations exist, present them - don't pick silently.
- If a simpler approach exists, say so. Push back when warranted.
- If something is unclear, stop. Name what's confusing. Ask.
## 2. Simplicity First
**Minimum code that solves the problem. Nothing speculative.**
- No features beyond what was asked.
- No abstractions for single-use code.
- No "flexibility" or "configurability" that wasn't requested.
- No error handling for impossible scenarios.
- If you write 200 lines and it could be 50, rewrite it.
Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.
## 3. Surgical Changes
**Touch only what you must. Clean up only your own mess.**
When editing existing code:
- Don't "improve" adjacent code, comments, or formatting.
- Don't refactor things that aren't broken.
- Match existing style, even if you'd do it differently.
- If you notice unrelated dead code, mention it - don't delete it.
When your changes create orphans:
- Remove imports/variables/functions that YOUR changes made unused.
- Don't remove pre-existing dead code unless asked.
The test: Every changed line should trace directly to the user's request.
## 4. Goal-Driven Execution
**Define success criteria. Loop until verified.**
Transform tasks into verifiable goals:
- "Add validation" → "Write tests for invalid inputs, then make them pass"
- "Fix the bug" → "Write a test that reproduces it, then make it pass"
- "Refactor X" → "Ensure tests pass before and after"
Test file placement:
- Put test files in the dedicated `src/tests/` directory, never next to the source files they test.
- Mirror the source structure inside `src/tests/` (e.g. `src/utils/format.ts` → `src/tests/utils/format.test.ts`).
For multi-step tasks, state a brief plan:
```
1. [Step] → verify: [check]
2. [Step] → verify: [check]
3. [Step] → verify: [check]
```
Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.

View File

@@ -0,0 +1,382 @@
---
name: vue-project-structure
description: cz-web 项目(Vue 3 + TypeScript + Vite 网页端站点)的目录结构与编码规范强制 skill。当在本项目中新增、创建、移动、重构或修改任何 src/ 下的代码文件(.vue/.ts/.less)、路由、store、API、组件、页面时,必须加载本 skill,先读取项目目录、再按本规范确定文件归属与写法。本项目是**网页端站点(非中后台)**:页面按名称组织(home/news/product…),接口层在 api/、数据层在 Pinia、页面只经 store 取数,样式使用**less**。凡是涉及"新文件放哪"、"页面数据怎么拿"、"页面/公共组件归属"、"命名"、"功能对应哪些文件"的任务也必须使用本 skill。
version: 2.0.0
---
# cz-web 项目目录结构规范(强制 · 网页端)
> 完整版调试文档见 `docs/vue-project-guide.md`(其中中后台相关部分已废弃),**本 skill 为唯一现行规范,以其为准**;未覆盖场景参照 Vue 3 官方目录约定。
## 第一步:读取项目目录(每次加载必做)
动手写任何代码前,先用工具映射当前项目结构,确认正在操作的正确层级:
1. 用 `codegraph_files` 或 `glob` 列出 `src/` 下的现行目录结构(如某目录尚不存在,应在对应职责目录创建,而不是自创新顶层目录)。
2. 读取目标文件及其同级文件,确认现有命名风格与组织方式(页面名、store 名、api 名必须一致)。
3. 只有在目录树确认完毕后,才允许创建/修改文件。
## 核心原则
1. **三层数据流(页面 → store → api)**:页面组件只通过 **Pinia store** 获取数据;store 是数据层,负责调用 **api 层**接口取数并维护状态;api 层只发请求。**页面禁止直接 import api**。
2. **按页面/页面名组织(一页一套)**:`views/<page>/`、`api/<page>.ts`、`stores/modules/<page>.ts`、`types/business/<page>.d.ts` 四者同名对应,方便分层查看。
3. **组件两级归属**:`components/` 只放**跨页面复用的公共组件**;`views/<page>/cpns/` 放**该页面独有的组件**。
4. **网页端(非中后台)**:无侧边栏菜单/权限路由/TabsBar 体系;页面以业务(首页、新闻、产品、关于我们…)划分。
5. **样式使用 less**:全局样式为 `.less` 文件,组件内 `<style lang="less" scoped>`。
## 数据流架构(强约束)
```text
页面组件 (views/home/index.vue)
│ ① 页面只调用 store 的 action / 读取 store 的 state(模板渲染数据)
▼
Pinia store (stores/modules/home.ts) —— 数据层
│ ② store 的 action 内部调用 api 接口函数 → await → 写入 state / 返回结果
▼
API (api/home.ts) —— 接口层
│ ③ 经 utils/request.ts 发 HTTP 请求
▼
后端服务器
```
铁律:
- **页面禁止 `import` api 层文件**;获取数据必须调对应页面 store 的方法。
- **api 层是纯接口层**:只发请求、返回数据(带类型),不做业务状态处理、不缓存。
- **store 承担取数 + 数据状态 + 页面间共享 + 缓存**;与页面同名的 store 责任边界即该页面。
- 调用链必须是 `页面 → store → api` 单向,禁止跳过 store 或反向依赖。
## src/ 目录结构(强制划分)
```
src/
├── api/ # ★ 接口层:按页面命名,一页一文件(home.ts、news.ts、product.ts、about.ts)
├── assets/ # 参与构建的静态资源(images/、icons/、fonts/)
├── components/ # ★ 公共组件:仅跨页面复用的全站通用组件(禁含具体页面业务)
│ ├── AppHeader.vue # 全站头部(导航)
│ ├── AppFooter.vue # 全站页脚
│ ├── AppButton.vue # 通用按钮
│ ├── AppSwiper.vue # 通用轮播
│ └── index.ts # 统一导出
├── composables/ # 通用组合式逻辑(useScroll、useLoading、useCountDown、useIntersection)
├── directives/ # 自定义指令(lazy 图片懒加载、debounce、throttle + index.ts 统一注册)
├── layout/ # 全站布局骨架:index.vue = <AppHeader/> + <router-view/> + <AppFooter/>
├── router/ # 路由:index.ts(入口)、routes.ts(静态路由表)、guard.ts(守卫,可选)
├── stores/ # ★ 数据层(Pinia):按页面命名,一页一 store
│ ├── index.ts # pinia 实例(main.ts 中 app.use(pinia))
│ └── modules/
│ ├── home.ts # useHomeStore:首页数据(banner、推荐、公告)
│ ├── news.ts # useNewsStore:新闻列表/分页/详情
│ ├── product.ts # useProductStore:产品列表/详情
│ └── site.ts # useSiteStore:站点公共数据(站点配置、全局 loading),非页面级
├── styles/ # ★ 全局样式(less)
│ ├── index.less # 样式入口(main.ts 引入),组织以下文件
│ ├── variables.less # ★ less 变量唯一来源(颜色/间距/字号/圆角),禁止组件内魔法色值
│ ├── mixins.less # 混合宏(flex、文本省略、滚动条)
│ ├── reset.less # 样式重置
│ └── common.less # 通用工具类(容器宽度、间距类)
├── types/ # 类型定义
│ ├── global.d.ts # 全局声明(Window 扩展、import.meta.env 兜底)
│ ├── api.d.ts # 接口通用结构:ApiResponse<T>、PageResult<T>
│ ├── router.d.ts # RouteMeta 扩展
│ └── business/ # 按页面与 api 对应:home.d.ts / news.d.ts / product.d.ts
├── utils/ # 纯函数工具(无 Vue 依赖):request.ts、storage.ts、validate.ts、format.ts
└── views/ # ★ 页面:一页一目录
├── home/
│ ├── index.vue # 页面主组件(路由通过 index.ts 加载)
│ ├── index.ts # 页面出口(barrel):export default 页面 + 导出本页独有组件
│ └── cpns/ # 页面独有组件(head、banner、news-list 等,仅本页面使用)
│ ├── Head.vue
│ └── Banner.vue
├── news/
│ ├── index.vue # 列表页
│ ├── detail.vue # 详情页
│ ├── index.ts
│ └── cpns/
├── product/ # 同上结构
├── about/ # 同上结构
└── login/ # 登录(仅存在会员体系时)
```
**命名一致性(可分层互查)**:页面 `home` → `api/home.ts` + `stores/modules/home.ts`(`useHomeStore`) + `types/business/home.d.ts` + `views/home/`,四者同名。
## src/ 每个文件的作用(新建/修改文件前先对照本节定位)
### 入口与根文件
| 文件 | 作用 |
| -------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `src/main.ts` | 应用入口:`createApp(App)`,注册 `pinia`、`router`、自定义指令(`setupDirectives`)、引入全局 `styles/index.less`。不写业务逻辑。 |
| `src/App.vue` | 根组件,承载 `<router-view/>` 与全局过渡;不含业务代码。 |
| `src/env.d.ts` | Vite 环境变量类型声明(`ImportMetaEnv` / `ImportMeta`)。 |
### `api/` —— 接口层(一页一文件,与页面同名)
| 文件 | 作用 |
| ---------------- | ------------------------------------------------------ |
| `api/home.ts` | 首页接口:`getHomeBanner`、`getRecommend`、`getNotice` |
| `api/news.ts` | 新闻接口:`getNewsList`、`getNewsDetail` |
| `api/product.ts` | 产品接口:`getProductList`、`getProductDetail` |
| `api/about.ts` | 关于我们/公司介绍接口 |
| `api/auth.ts` | 登录/注册/用户信息(仅会员体系需要时) |
> **纯接口层**:函数只负责 `request<T>({ url, method, params/data })`,不做数据加工、不维护状态。新增页面 → 新建 `api/<page>.ts`。
### `components/` —— 公共组件(仅跨页面复用)
| 文件 | 作用 |
| -------------------------- | ------------------------------------------------------------ |
| `components/AppHeader.vue` | 全站头部:logo、导航菜单(路由跳转) |
| `components/AppFooter.vue` | 全站页脚:版权、友链 |
| `components/AppButton.vue` | 通用按钮(disabled/loading/类型统一) |
| `components/AppSwiper.vue` | 通用轮播(首页 banner、产品图) |
| `components/index.ts` | 统一导出(barrel),页面与页面组件统一从 `@/components` 导入 |
> 判定:被 ≥2 个页面使用 → 放这里;仅 1 个页面使用 → 放 `views/<page>/cpns/`。
### `composables/` —— 通用组合式逻辑(与 UI 解耦)
| 文件 | 作用 |
| -------------------------------- | ------------------------ |
| `composables/useScroll.ts` | 滚动监听/吸顶/回到顶部 |
| `composables/useLoading.ts` | 请求 loading 状态管理 |
| `composables/useCountDown.ts` | 倒计时(验证码等) |
| `composables/useIntersection.ts` | 元素可见性(配合懒加载) |
### `directives/` —— 自定义指令
| 文件 | 作用 |
| ------------------------ | --------------------------------------------- |
| `directives/lazy.ts` | `v-lazy` 图片懒加载(网页端常用) |
| `directives/debounce.ts` | `v-debounce` 防抖 |
| `directives/throttle.ts` | `v-throttle` 节流 |
| `directives/index.ts` | `setupDirectives(app)` 统一注册,main.ts 调用 |
### `layout/` —— 全站布局骨架
| 文件 | 作用 |
| -------------------- | -------------------------------------------------------------------------- |
| `layout/index.vue` | 全站公共布局:`<AppHeader/>` + `<router-view/>` + `<AppFooter/>`,仅此一层 |
| `layout/components/` | 布局内部组件(如返回顶部按钮);需要全站复用的上移 `components/` |
### `router/` —— 路由系统(网页端:静态路由为主)
| 文件 | 作用 |
| ------------------ | ------------------------------------------------------------------------- |
| `router/index.ts` | 创建 `createRouter`(createWebHistory)+ 注册静态路由 + 挂守卫 |
| `router/routes.ts` | 静态路由表:`/home`、`/news`、`/news/:id`、`/product`、`/about`、404 兜底 |
| `router/guard.ts` | 路由守卫(可选):登录态校验(会员页)、滚动位置恢复、document.title |
```ts
// 路由加载页面(指向 views/home/index.ts —— 页面出口)
{
path: '/home',
name: 'Home',
component: () => import('@/views/home'), // 解析到 index.ts 的 default(index.vue)
meta: { title: '首页' },
}
```
### `stores/modules/` —— 数据层(Pinia,一页一 store,与页面同名)
| 文件 | 作用 |
| --------------------------- | ------------------------------------------------------------------------------------------- |
| `stores/modules/home.ts` | `useHomeStore`:state(banner/推荐/公告)+ actions(`fetchHomeData`,内部调 `api/home.ts`) |
| `stores/modules/news.ts` | `useNewsStore`:列表/分页/详情 state + `fetchNewsList`、`fetchNewsDetail` |
| `stores/modules/product.ts` | `useProductStore`:产品列表/详情/分类筛选 |
| `stores/modules/site.ts` | `useSiteStore`:站点配置、全局 loading、主题(非页面级公共数据) |
| `stores/modules/user.ts` | `useUserStore`:登录态/token(仅会员体系需要时) |
```ts
// stores/modules/home.ts —— 数据层写法示例(页面 → store → api)
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { getHomeBanner, getRecommend } from '@/api/home'
import type { Banner, RecommendItem } from '@/types/business/home'
export const useHomeStore = defineStore('home', () => {
const banners = ref<Banner[]>([])
const recommends = ref<RecommendItem[]>([])
async function fetchHomeData() {
// ① store 调 api 层拿数据
const [bannerData, recommendData] = await Promise.all([
getHomeBanner(),
getRecommend(),
])
// ② 写入 state——完成页面所需数据
banners.value = bannerData
recommends.value = recommendData
}
return { banners, recommends, fetchHomeData }
})
```
### `styles/` —— 全局样式(less)
| 文件 | 作用 |
| ----------------------- | ------------------------------------------------------------------------------------ |
| `styles/index.less` | 入口,main.ts `import '@/styles/index.less'` |
| `styles/variables.less` | ★ 变量唯一来源:`@primary-color`、`@text-color`、`@font-size-base`、`@spacing-base`… |
| `styles/mixins.less` | 混合宏(flex、文本省略) |
| `styles/reset.less` | 重置 |
| `styles/common.less` | 通用工具类 |
组件内样式:`<style lang="less" scoped>`,变量经 vite `css.preprocessorOptions.less.additionalData` 自动注入 `@import '@/styles/variables.less';`,组件内直接使用 `@primary-color`。
### `types/` —— 类型定义
| 文件 | 作用 |
| -------------------------- | --------------------------------------------------------------------- |
| `types/api.d.ts` | `ApiResponse<T> { code, msg, data }`、`PageResult<T> { list, total }` |
| `types/router.d.ts` | `declare module 'vue-router'` 扩展 `RouteMeta`(title 等) |
| `types/business/home.d.ts` | 首页实体类型(Banner/RecommendItem),与 `api/home.ts` 对应 |
| `types/business/news.d.ts` | 新闻实体(NewsItem/NewsQuery),与 `api/news.ts` 对应 |
> 新页面 → 新建 `types/business/<page>.d.ts`;禁止在组件内散落实体类型。
### `utils/` —— 纯函数工具
| 文件 | 作用 |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `utils/request.ts` | ★ 唯一 axios 实例:拦截器注入 token/统一解包 `ApiResponse`/统一错误提示,导出 `request<T>`。组件与页面禁止再 import axios |
| `utils/storage.ts` | localStorage/sessionStorage 泛型封装 |
| `utils/validate.ts` | 校验规则(手机号/邮箱/URL) |
| `utils/format.ts` | 格式化(金额/日期/千分位) |
### `views/` —— 页面(一页一目录,三件套:index.vue + index.ts + cpns/)
| 文件/目录 | 作用 |
| ---------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| `views/home/index.vue` | 首页主组件:组合 `cpns/` 的独有组件,数据由 `useHomeStore` 提供 |
| `views/home/index.ts` | **页面出口(barrel)**:`export { default } from './index.vue'` + 导出 `cpns/` 组件;路由与外部引用统一走它"展示"页面 |
| `views/home/cpns/Head.vue` | 首页独有头部区块(banner 下导航条等),仅本页使用 |
| `views/home/cpns/Banner.vue` | 首页独有轮播区块(渲染 store 的 banners) |
| `views/news/index.vue` | 新闻列表页 |
| `views/news/detail.vue` | 新闻详情页(与 index.vue 同目录,同页面模块) |
| `views/news/index.ts` | 出口 barrel(同上) |
| `views/news/cpns/` | 新闻页独有组件(筛选栏、列表项卡片) |
```ts
// views/home/index.ts —— 页面出口(barrel)写法
export { default } from './index.vue' // 页面主组件(default)
export { default as HomeHead } from './cpns/Head.vue'
export { default as HomeBanner } from './cpns/Banner.vue'
```
> 页面独有组件的归属判定:**只属于某一个页面 → 进该页面 `cpns/`;被 ≥2 个页面共用 → 上移 `components/`**。
## 项目功能模块图(功能 → 涉及文件)
| 功能 | 涉及文件 | 说明 |
| --------------------- | --------------------------------------------------------------------------------------- | ------------------------------ |
| 全站布局(头部/页脚) | `layout/index.vue` + `components/AppHeader.vue` + `components/AppFooter.vue` | 路由首层挂在 layout 下 |
| 首页 | `api/home.ts` + `stores/modules/home.ts` + `views/home/`(index.vue + index.ts + cpns) | 页面 → store → api 取数 |
| 新闻中心 | `api/news.ts` + `stores/modules/news.ts` + `views/news/` | 列表 + 详情 |
| 产品展示 | `api/product.ts` + `stores/modules/product.ts` + `views/product/` | 列表 + 详情 + 分类 |
| 关于我们 | `api/about.ts` + `stores/modules/about.ts` + `views/about/` | 公司介绍内容 |
| 会员登录(可选) | `api/auth.ts` + `stores/modules/user.ts` + `views/login/` + `router/guard.ts` | 登录态/token |
| 轮播/动效 | `components/AppSwiper.vue` + `composables/useScroll.ts` + `directives/lazy.ts` | 首页 banner、图片懒加载 |
| 站点公共数据 | `stores/modules/site.ts` + `styles/variables.less` | 站点配置、全局 loading、主题色 |
## 统一规范速查
### 路由规范
- 路由 `component` 指向页面出口:`() => import('@/views/<page>')`(解析到 `index.ts` 的 default = `index.vue`)
- 每个路由必须声明 `meta.title`;`RouteMeta` 扩展在 `src/types/router.d.ts`
- 网页端以静态路由为主,无需动态权限路由;嵌套页面(news 列表/详情)在同一页面目录下
- 公共页面挂载在 `layout/index.vue` 下,页面自身不重复写 header/footer
### 状态管理(Pinia)规范 —— 数据层
- store 文件:`src/stores/modules/<page>.ts`,命名 `use<Page>Store`(PascalCase),与 api/views 同名
- **统一组合式(setup)写法**:state 用 `ref`,getters 用 `computed`,actions 用普通函数,最后 return 全部
- **store 的 action 负责调用对应页面 api 层的接口取数**,页面只调 action
- 组件内:state/getters 用 `storeToRefs` 解构;actions 直接解构调用
- 简单展示型数据也走 store(保持数据层统一),页面禁止直接 import api
### 接口 API 规范 —— 接口层
- **全项目唯一 axios 实例**在 `src/utils/request.ts`,禁止页面/组件 import axios
- 统一响应结构 `ApiResponse<T> { code, msg, data }`(见 `types/api.d.ts`)
- 接口函数名 = 动词 + 资源:`getHomeBanner` / `getNewsList` / `getNewsDetail` / `getProductList`
- `api/<page>.ts` 只做请求分发,不做数据处理;处理与状态归 store
- baseURL 用环境变量 `import.meta.env.VITE_API_BASE_URL` 区分环境(.env / .env.development / .env.production)
- 错误统一由拦截器兜底,store/页面仅在需特殊处理时 catch
### 组件规范
- 公共组件 `components/`:文件 PascalCase(AppHeader.vue);被 ≥2 页面使用才放这里
- 页面独有组件 `views/<page>/cpns/`:**严禁被其他页面 import**;语义化命名(Head.vue、Banner.vue)
- 页面结构三件套:`index.vue`(页面) + `index.ts`(出口 barrel) + `cpns/`(独有组件)
- 组件统一 `<script setup lang="ts">`;props 用 `defineProps<Props>()` + `withDefaults`;emits 用 `defineEmits<{ 事件名: [参数类型] }>()`
- 组件事件 camelCase 命名;模板内不放复杂表达式;样式默认 `<style lang="less" scoped>`
- 单文件超 400 行即拆分到 `cpns/`
### 样式规范(less)
- 全项目使用 **less**,禁止新增 `.scss/.css` 业务样式
- 全局变量统一在 `styles/variables.less`;组件内禁止魔法色值
- vite `css.preprocessorOptions.less` 配置 `additionalData` 自动注入 variables
- 依赖:`pnpm add -D less`(vite 内置 less 编译支持)
### 工程化硬性约定
- **导入一律 `@/` 别名**;禁止跨目录相对路径(`../` 超过一层即违规)
- utils 与 composables 判据:**需要响应式状态或生命周期 → composables;否则 → utils**
- 类型归位:实体类型 → `types/business/<page>.d.ts`(与 api 同名);接口结构 → `types/api.d.ts`
- **禁止 `as any` / `@ts-ignore` / `@ts-expect-error`**
## 后续使用方式(工作流)
### 场景速查:想做什么 → 去找哪个文件
| 想做的事 | 动哪个文件 | 注意 |
| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- |
| 给首页加一块新数据 | `api/home.ts` 加接口函数 → `stores/modules/home.ts` 加 action/state → `views/home/index.vue` 调 store action,结构放 `views/home/cpns/` 新组件 | 遵循数据流:页面 → store → api |
| 新增一个页面模块(如 news) | `types/business/news.d.ts` → `api/news.ts` → `stores/modules/news.ts` → `views/news/`(index.vue+index.ts+cpns) → `router/routes.ts` 注册 | 四者同名,走七步流程 |
| 页面要取数据 | 调对应 `use<Page>Store` 的 action(`storeToRefs` 取 state) | **禁止直接 import api** |
| 一个组件多个页面要用 | 放 `components/`(公共组件) | 从 `@/components` 导入 |
| 一个组件只有本页面用 | 放 `views/<page>/cpns/` | 禁止其他页面引用 |
| 改全站颜色/字体/间距 | `styles/variables.less` | 禁止组件内魔法值 |
| 图片懒加载 | 模板 `v-lazy`(`directives/lazy.ts`) | 勿手写滚动判断 |
| 通用逻辑(响应式) | `composables/` | 纯函数则 `utils/` |
| 弹窗/表单等小块 | 页面内 `cpns/` | 复用时上移 components/ |
| 路由新增页面 | `router/routes.ts` 注册 | component 指向 `@/views/<page>` |
### 新增页面模块七步流程(以"新闻 news"为例)
1. **类型**:`types/business/news.d.ts` 定义 `NewsItem / NewsQuery / PageResult`
2. **接口层**:`api/news.ts`(`getNewsList`、`getNewsDetail`,走 `request<T>`)
3. **数据层**:`stores/modules/news.ts`(`useNewsStore`,action 内调用 api 函数取数)
4. **页面**:`views/news/index.vue`(列表)+ `views/news/detail.vue`(详情)+ `views/news/index.ts`(出口 barrel)+ `views/news/cpns/`(独有组件)
5. **路由**:`router/routes.ts` 注册(`component: () => import('@/views/news')`,配 `meta.title`)
6. **复用检查**:被 ≥2 页面使用的组件上移 `components/`
7. **验证**:`pnpm build`(含 vue-tsc 类型检查)零错误
### 日常开发姿势
- **每次动手前**:按"第一步"读取目录,确认目标文件存在与现状,再决定新建还是修改。
- **新建文件前**:对照"src/ 每个文件的作用"确认归属(api/stores/views 四者同名)。
- **改数据相关代码**:先确认数据流方向——页面只碰 store,store 只碰 api,api 只发请求。
- **组件归属**:先自问"有几个页面用它"——1 个 → cpns/;≥2 个 → components/。
- **规格冲突时**:本 skill 为唯一现行规范;未覆盖场景 → 询问用户或按最贴近的既有模式执行后复述假设。
## 修改代码时的强制检查清单
修改任何已存在文件时,逐条核对(不满足即视为违反规范,必须先修正再继续):
- [ ] 文件是否位于其职责对应的目录(接口在 api/、数据在 stores/modules/、页面在 views/<page>/ 等)
- [ ] **页面是否直接 import 了 api 层?(违规——数据必须经 store)**
- [ ] **store 名 / api 文件名 / 页面目录名 / 类型文件名 是否与页面一致(可分层互查)**
- [ ] 导入是否使用 `@/` 别名
- [ ] 组件归属是否正确:≥2 页面共用 → components/;单页面独有 → views/<page>/cpns/
- [ ] 不在组件里直接 new axios 实例 / 直接调用原生 fetch
- [ ] 样式是否使用 **less**(`<style lang="less" scoped>` / \*.less),颜色是否取自 variables.less
- [ ] 类型是否齐全(无 `as any`、无 `@ts-ignore`)
- [ ] 新页面是否有完整三件套(index.vue + index.ts + cpns/)并在 router 注册
- [ ] 运行时 `pnpm build`(含 vue-tsc 类型检查)零错误
> 本规范为项目强约束:**新增与修改的代码必须严格遵循**。发现不符合结构约定的代码,应指出问题并要求按规范调整,而不是放任通过。

3
.gitignore vendored
View File

@@ -11,9 +11,6 @@ node_modules
dist
dist-ssr
*.local
docs
.claude
read_prototype.js
RTK.md
.playwright-mcp
.omo

65
AGENTS.md Normal file
View File

@@ -0,0 +1,65 @@
# AGENTS.md — cz-web 代码开发流程
本项目所有 AI 编码任务统一走以下流程。三个 skill 各司其职,**冲突时以 auto-dev 流程为主线、vue-project-structure 为结构裁决、karpathy-guidelines 为编码底线**。
## 一、三个 skill 的分工
| 角色 | Skill | 职责 | 何时加载 |
| ---- | ----- | ---- | -------- |
| **主流程** | [auto-dev](.claude/skills/auto-dev/SKILL.md) | 从原型/PRD/设计稿到可运行代码的完整管线(7 个阶段) | 提到"自动化开发、从原型生成代码、蓝湖生成页面、PRD 生成页面"时 |
| **项目规则** | [vue-project-structure](.claude/skills/vue-project-structure/SKILL.md) | 目录归属、三层数据流(页面 → store → api)、命名与文件作用 | **任何**新建/移动/修改 `src/` 下文件之前,必读 |
| **编码规则** | [karpathy-guidelines](.claude/skills/karpathy-guidelines/SKILL.md) | 少代码、外科手术式修改、可验证的成功标准 | 写代码、review、重构时始终生效 |
优先级:**项目规则(结构归属)> 编码规则(写法底线)**;auto-dev 只决定"做什么、按什么顺序做",不覆盖前两者的规范。
## 二、标准代码流程
```
① 读取现状
└─ 用 codegraph_files/glob 映射 src/ 结构,读目标文件及同级文件
→ verify: 能说出目标文件该放哪个目录、同名文件是否已存在
② 明确需求(karpathy §1)
└─ 陈述假设;多种解释时先列出并确认;不清楚就停下来问
→ verify: 无隐含假设,成功标准可验证
③ 规划文件落位(vue-project-structure)
└─ 对照"src/ 每个文件的作用"定位:
接口 api/<page>.ts、数据 stores/modules/<page>.ts、
页面 views/<page>/、类型 types/business/<page>.d.ts 四者同名
→ verify: 目录归属正确,不新建顶层目录
④ 编写/修改代码(auto-dev 阶段四~五 + karpathy §2/§3)
└─ 数据流铁律:页面 → store → api 单向,页面禁止 import api
组件两级归属:≥2 页面复用 → components/;单页独有 → views/<page>/cpns/
最小改动:只改与需求相关的行,不顺手重构
→ verify: 每一行改动都能追溯到用户需求
⑤ 测试(karpathy §4)
└─ 测试文件统一放 src/tests/,镜像源码结构
(src/utils/format.ts → src/tests/utils/format.test.ts)
→ verify: 测试通过
⑥ 验证与修正(auto-dev 阶段七)
└─ pnpm build(含 vue-tsc 类型检查)零错误
逐条核对 vue-project-structure 的"修改代码强制检查清单"
→ verify: build 退出码 0、检查清单全过
```
## 三、硬性约束(任一违反即返工)
1. 页面禁止 `import` api 层;数据必须经 store。
2. 禁止 `as any` / `@ts-ignore` / `@ts-expect-error`。
3. 导入一律 `@/` 别名,禁止跨目录相对路径(`../` 超过一层即违规)。
4. 样式只用 less,色值取自 `styles/variables.less`,禁止魔法值。
5. 不顺手"改进"无关代码;与本次需求无关的死代码只报告、不删除。
6. 测试文件只放 `src/tests/`,不与源码混放。
7. 收尾必须跑 `pnpm build`,零错误才算完成。
## 四、触发速查
| 用户说 | 加载 |
| ------ | ---- |
| 自动化开发 / 原型生成代码 / 蓝湖 / PRD 生成页面 | auto-dev(主)+ vue-project-structure |
| 新增/修改 `src/` 下任何文件、新文件放哪 | vue-project-structure |
| 写代码 / 改代码 / 重构 / review | karpathy-guidelines |

412
docs/PRD.md Normal file
View File

@@ -0,0 +1,412 @@
# PRD — 虫子智造 研发智造一体化平台(Web 端)
> 来源:`docs/prototype/` 共 10 个墨刀演示原型(无蓝湖设计稿、无接口文档,本文档为唯一需求基线)。
> 项目定位:一站式研发智造一体化服务平台,打通需求提报 → 项目管控 → 合同签署 → 财务结算 → 售后迭代全流程。平台自营,对项目质量全权兜底。
## 1. 全局框架
### 1.1 顶部导航(AppHeader,全站公共)
| 导航项 | 路由 | 说明 |
| --- | --- | --- |
| 首页 | `/` | 门户首页 |
| 案例库 | `/cases` | 成功案例展示 |
| 需求提报 | `/demand` | 需求填报表单 |
| 项目中心 | `/project` | 项目列表/详情 |
| 合同中心 | `/contract` | 合同列表/详情/签署 |
| 财务中心 | `/finance` | 账单/支付/发票 |
| 个人中心 | `/profile` | 账号与资料管理 |
- 右侧:用户头像/昵称、消息铃铛(未读数角标,示例 3)、搜索等。
- 未登录访问受保护路由 → 跳转 `/login`(支持游客模式的部分页面除外)。
### 1.2 全局浮动组件
- **快捷提报**(右侧悬浮按钮):一键跳转 `/demand`。
- **在线客服**(右侧悬浮按钮):一键跳转 `/service`。
### 1.3 全局页脚(AppFooter)
- 版权声明:©2026 虫子智造 研发智造一体化平台,源码/图纸受平台知识产权保护。
- ICP 备案号、公安备案号。
- 联系方式:商务合作 business@chongzizhizao.com、技术支持 support@chongzizhizao.com、客服热线 400-XXX-XXXX、工作时间 周一–周五 9:00–18:00。
- 快速导航:首页 / 案例中心 / 需求提报 / 下载 APP / 帮助中心。
- 核心业务:互联网软件开发 / 硬件电路开发 / 物联网软硬一体化全案 / PCB 制版 & SMT 贴片生产 / 元器件集采与整机装配。
- 平台简介文案(研发智造一体化自营平台…)。
## 2. 页面清单及功能描述
| # | 模块 | 页面 | 原型文件 | 访问权限 |
| --- | --- | --- | --- | --- |
| 1 | home | 首页 | 首页-演示.html | 公开 |
| 2 | home | 业务详情 | 首页-演示.html(业务详情画板) | 公开 |
| 3 | cases | 案例库列表 | 案例库-演示.html | 公开 |
| 4 | cases | 案例详情 | 案例库-演示.html | 公开 |
| 5 | demand | 需求提报 | 需求填报-演示.html | 公开(提交需登录) |
| 6 | login | 登录/注册/找回密码 | 登录-演示.html | 游客 |
| 7 | project | 项目中心列表 | 项目中心-演示.html | 登录 |
| 8 | project | 项目详情 | 项目中心-演示.html | 登录 |
| 9 | project | 申请售后 | 项目中心-演示.html | 登录 |
| 10 | contract | 合同中心列表 | 合同管理-演示.html | 登录 |
| 11 | contract | 合同详情 | 合同管理-演示.html | 登录 |
| 12 | contract | 签署合同 | 合同管理-演示.html | 登录 |
| 13 | finance | 财务中心概览 | 财务中心-演示.html | 登录 |
| 14 | finance | 账单明细 | 财务中心-演示.html | 登录 |
| 15 | finance | 账单详情 | 财务中心-演示.html | 登录 |
| 16 | finance | 扫码支付/支付结果 | 财务中心-演示.html | 登录 |
| 17 | finance | 发票申请 | 财务中心-演示.html | 登录 |
| 18 | finance | 发票抬头管理 | 财务中心-演示.html | 登录 |
| 19 | message | 消息中心 | 消息中心-演示.html | 登录 |
| 20 | message | 系统通知详情 | 消息中心-演示.html | 登录 |
| 21 | service | 在线客服 | 在线客服-演示.html | 登录 |
| 22 | profile | 账号安全 | 个人中心-演示.html | 登录 |
| 23 | profile | 地址管理 | 个人中心-演示.html | 登录 |
| 24 | profile | 收藏列表 | 个人中心-演示.html | 登录 |
| 25 | profile | 资质列表 | 个人中心-演示.html | 登录 |
| 26 | profile | 意见反馈 | 个人中心-演示.html | 登录 |
| 27 | profile | 帮助中心 | 个人中心-演示.html | 登录 |
| 28 | profile | 关于我们 | 个人中心-演示.html | 登录 |
| 29 | profile | 专属客服热线 | 个人中心-演示.html | 登录 |
---
## 3. 各页面交互逻辑
### 3.1 首页(home)
- **欢迎区(登录后)**:问候语「中午好」+ 当日摘要「今天有2个项目正在进行」。
- **数据看板**:待您处理 3 / 进行中 3 / 累计项目 6。
- **快捷入口**:财务台账、合同台账、客服工作台、案例库管理、工单需求池(跳对应模块)。
- **业务服务**:4 张卡片(互联网软件 / 硬件电路 / 物联网全案 / 生产制造),每张含描述 + 「了解详细 >」→ 业务详情页。
- **案例库精选**:按业务类型 Tab(全部/互联网软件/硬件电路/物联网全案/生产制造)筛选案例卡片,「查看更多 >」→ 案例库,「查看详情 >」→ 案例详情。
- **服务区(Tab 切换)**:服务类型(Web应用/小程序/APP/二次开发/桌面工具)与服务内容(五类服务条款富文本 + 视频)。
### 3.2 业务详情(home detail)
- 面包屑「首页 > 业务详情」。
- 业务线介绍(标题 + slogan,如「专业的软件定制开发服务,从需求到上线全流程保障」)。
- 服务内容富文本 + 视频(预览播放)。
- 服务类型子项切换(Web/小程序/APP/二次开发/桌面工具)。
### 3.3 案例库列表(cases)
- 头部:标题「成功案例库」+ 副文案。
- **筛选面板**:
- 业务类型:全部/互联网软件/硬件电路/物联网全案/生产制造(单选,带计数 25/25/25/25/100)。
- 所属行业:全部/电商零售/教育培训/医疗健康/硬件电路/能源环保/房地产(多选按钮组)。
- 项目规模:全部/50万以下/50-100万/100-300万/300-500万/500万以上(多选)。
- 完成时间:全部/近3个月/近半年/近一年/开始时间—结束时间(日期范围)。
- 关键字搜索 + 重置。
- 已选条件回显(「已选条件(4个)」+ 条件 chip × 移除 + 清空)、「确定筛选(100个结果)」。
- **案例卡片**:封面图、业务类型标签、标题、查看详情 >;字段:完成时间/服务团队/规模/所属行业/项目周期/客户类型。
- 分页器(‹ 1 2 3 4 5 ›)。
- **收藏列表**(profile 模块复用):同卡片布局,展示已收藏案例。
### 3.4 案例详情(cases detail)
- 面包屑「案例库 > 案例详情」。
- 项目概览:标题、业务类型、完成时间/服务团队/规模/所属行业/项目周期/客户类型。
- 操作:**收藏**(收藏/已收藏切换)、**分享**。
- 视频区(预览播放)。
- 富文本区块:项目背景、客户痛点、需求描述、交付物清单。
- 底部 CTA:**一键填报类似案例** → 跳转 `/demand` 并预填业务类型。
### 3.5 需求提报(demand)
分步表单(1 选择业务类型 → 2 填写需求信息 → 3 确认信息并补充备注):
1. **选择业务类型***(单选 5 项):互联网软件 / 物联网全案 / 生产制造 / 硬件电路 / 其他(「若没有对应的服务内容请选择该选项」),每项含图标 + 描述。
2. **填写需求信息***:
- 项目名称*(文本)。
- 附件上传:支持图片/文档/压缩包,大小不超过 1G;支持上传按钮 + 文件列表(名称/大小/上传时间/预览/下载/删除)。
- 核心需求描述*(多行,0/500 字计数)。
- 预计开发周期(工作日,数字)。
- 预算范围(按钮单选:1万以下 / 1-5万 / 5-10万 / 10万+)。
3. **确认信息并补充备注**:
- 用户名称(默认当前登录用户「王永志」)。
- 用户手机号(脱敏 1866\*\*\*\*9618,可手填)。
- 补充备注(0/500 字计数)。
- 底部:提示语「提交后我们的专业顾问将在一个工作日内与您联系」。
- 操作按钮:**立即提报** / **保存草稿** / **重置** / 手填。
### 3.6 登录/注册/找回密码(login)
统一视觉:左侧品牌区(logo + 「虫子智造研发一体化平台」+ slogan「安全 · 高效 · 可控」),右侧表单区;顶部「游客模式」入口、「没有账号?立即注册 / 已有账号?立即登录」切换。
- **账号密码登录**:账号、密码、协议勾选(《用户协议》《隐私政策》)、登录按钮。
- **手机验证码登录**:手机号、验证码、「获取验证码 / 60秒后重新获取」倒计时、协议勾选、登录按钮。
- **注册**:手机号、验证码、设置密码(6-20 位,**密码强度指示:弱/中/强**,强度过低提示「密码等级过低,请重新输入」)、确认密码、协议勾选、注册按钮。
- **找回密码**:手机号、验证码、设置密码、确认密码、「确认修改」。
- 状态反馈:「注册成功,请登录」「修改成功,请登录」「登录失败,请先注册账号」,**3 秒后自动跳转**。
### 3.7 项目中心列表(project)
- 标题 + 副文案「查看和管理您的所有项目,实时跟踪项目进度」。
- 筛选:关键字搜索、业务类型(全部/互联网软件/硬件电路/物联网全案/生产制造)、项目状态(全部/待立项/进行中/待验收/已完成/售后中/已取消,带计数 25/25/25/25/100)、提交时间(全部/近3个月/近半年/近一年/起止日期)、已选条件回显、确定筛选/重置。
- 表格列:序号、项目编号、项目名称、业务类型、进度(64%)、状态、操作(详情;已完成时另有**申请售后**)。
- 状态枚举:待立项 / 进行中 / 待验收 / 已完成 / 售后中 / 已取消。
- 分页器。
### 3.8 项目详情(project detail)
- 面包屑「项目中心 > 项目详情」。
- 头部信息卡:项目名称(社区康养智能服务系统)、项目编号、业务类型、提交时间、状态标签。
- 项目团队:项目经理卡片(头像/姓名/角色,张三)。
- **Tab 四页签**:
1. **项目进度**:总体进度 65% + 开发进度滑杆;里程碑时间轴(需求确认 → 原型设计 → 开发实现 → 测试验收 → 项目交付),每节点状态(待开始/进行中/已完成)+ 完成时间;开始/结束时间。
2. **项目文件**:文件列表(项目需求规格说明书.pdf 等,2.4MB · 上传时间),操作:**预览 / 下载 / 删除**;**上传文档**按钮。
3. **合同财务**:付款计划卡片列表(第一期·预付款 比例33% / 第二期·付款 33% / 第三期·尾款 33%,含账单号、关联项目、金额 ¥20100,状态:已支付(含交易流水号)/待支付(**立即支付**按钮)/未到期);发票记录(预览/下载);合同文件(预览/下载)。
4. **售后信息**:售后工单状态卡(「售后工单处理中——工程师正在处理您的修改需求」);**申请售后 / 取消售后**按钮。
### 3.9 申请售后(project → after-sales)
- 分步表单:1 选择业务类型*、2 填写问题描述*、3 补充备注。
- 字段:项目名称*(默认当前项目)、售后类型*(推荐选项 + 手动输入,示例「BUG问题」)、问题描述*(0/500 字,「请详细描述您的问题...」)、附件上传(图片/文档/压缩包 ≤1G,文件列表预览/下载/删除)、补充备注(0/500 字)。
- 操作:**申请售后**(提交,生成售后工单) / **重置** / **取消**。
### 3.10 合同中心列表(contract)
- 标题「合同中心」+ 副文案「项目电子合同在线签署、归档与查询管理」。
- 关键字搜索 + 搜索/重置。
- 表格列:合同编号、合同名称、合同类型、合同金额、关联项目、项目编号、签署状态、生效时间、到期时间、操作(**去签署**(待签署时)/ 详情)。
- 签署状态枚举:履行中 / 已过期 / 待签署。
- 分页器。
### 3.11 合同详情(contract detail)
- 面包屑「合同中心 > 合同详情」。
- 合同信息(只读表单):合同名称、合同类型、合同编号、签订日期、生效日期、到期日期、合同状态。
- 关联项目:项目编号、项目名称、「查看详情」→ 项目详情。
- 合同文件:文件卡(预览/下载)。
- 操作:**返回**。
### 3.12 签署合同(contract sign)
- 面包屑「合同中心 > 合同详情 > 签署合同」。
- 左侧二维码(**04:32 倒计时失效**,过期可点击刷新)。
- 右侧「扫码验证签署操作步骤」四步引导:
1. 打开手机支付宝(右上角 + → 扫一扫)。
2. 验证身份信息(实名验证,确保本人操作)。
3. 确认合同内容并签署(指定位置签署)。
4. 完成签署(页面自动跳转至合同详情页)。
### 3.13 财务中心概览(finance)
- 标题「财务中心」+ 副文案「账单、支付、发票统一财务管理中心」。
- **累计消费总额**卡片(¥1,726,823,900)+ 月份选择(2026年1月 SELECT)+ 时间维度切换(本季度/本年)。
- **业务类型分布**图表(生产智造/物联网全案/硬件电路/互联网软件 饼图)。
- 待支付角标(3)。
- **快捷入口**:发票申请、账单明细、报表导出。
### 3.14 账单明细(finance bills)
- 面包屑「财务中心 > 账单明细」。
- 状态 Tab:全部 / 待支付 / 已支付 / 未到期(带计数)。
- 关键字搜索 + 搜索/重置。
- 表格列:多选框、序号、账单名称(第一期·预付款 比例33%)、账单号、交易流水号、项目名称、订单金额、状态、操作(**去支付**(待支付)/ 详情)。
- 汇总条:总笔数 10、总金额 123212、待支付 3。
- 多选后:「已选择1笔订单 · 合计:¥20000」+ **立即支付**。
- 分页器。
### 3.15 账单详情(finance bill detail)
- 面包屑「财务中心 > 账单明细 > 账单详情」。
- 订单信息卡:账单名称、账单号、关联项目、金额。
- 待支付订单态:**立即支付**入口。
- 已支付订单态:支付信息(付款金额、支付方式、支付时间、交易流水号)。
- 未到期态:状态提示。操作:**返回**。
### 3.16 扫码支付 + 支付结果(finance pay)
- 面包屑「财务中心 > 账单明细 > 账单详情 > 扫码支付」。
- 左侧支付二维码(**04:32 倒计时**,过期可刷新),安全提示「本页面已通过安全验证,请勿向他人泄露付款码」。
- 支付方式:微信支付 / 支付宝支付(**切换支付方式**弹窗:单选,「推荐使用」「其他用户选择」标签)。
- 右侧:支付金额(¥20000)+ 订单明细列表(账单号/关联项目/期数/金额)。
- 「扫码支付操作步骤」三步引导(微信/支付宝各自文案)。
- **支付结果页**:支付成功(✓、付款金额、共N个订单、支付信息:支付方式/支付时间/交易流水号、已支付订单列表)。
### 3.17 发票申请(finance invoices)
- 面包屑「财务中心 > 发票申请」。
- **发票抬头卡**:默认抬头(企业名称 + 税号 + 「企业」标签 + 「默认」标签)、「管理抬头 >」。
- 状态 Tab:全部 / 已开票 / 开票中 / 未开票。
- 表格列:多选框、序号、账单名称、账单号、交易流水号、项目名称、订单金额、状态、申请时间、操作:
- 已开票:**预览 / 下载 / 发送邮箱**;
- 开票中:无操作(进行中);
- 未开票:**申请开票**。
- 关键字搜索 + 分页器。
### 3.18 发票抬头管理(finance invoice-titles)
- 列表卡:抬头类型(企业单位/非企业单位)、发票抬头、税号、默认标签。
- 操作:**+ 新增抬头**、编辑、删除、设为默认 / 取消默认。
- 弹窗(新增/编辑):抬头类型(单选:企业单位/非企业单位)、发票抬头*、税号*。
- 删除二次确认弹窗:「删除后无法恢复,是否继续?」(取消/确认删除)。
### 3.19 消息中心(message)
- 标题「消息中心」+ 副文案「统一接收项目进度、售后工单、账单待办等站内消息,重要业务动态实时提醒」。
- 分类 Tab:全部 / 在线客服 / 状态通知 / 系统通知(未读数角标 3/3/3/9)。
- 关键字搜索 + 搜索/重置 + **全部已读**按钮。
- 消息条目:类型图标、类型标签(系统通知/合同生效/在线客服)、摘要、「刚刚」相对时间、未读标记。
- 分页器。
### 3.20 系统通知详情(message detail)
- 面包屑「消息中心 > 系统通知详情」。
- 标题 + 发布时间 + 富文本正文(功能亮点/使用场景/入口位置等)。
- 附件(PDF 2.5MB,预览/下载)。
- 操作:**返回**。
### 3.21 在线客服(service)
- 标题「在线客服」+ 副文案「在线客服为您提供需求咨询、项目进度查询、业务答疑…」。
- 聊天窗口:客服头像/名称(专属客服)、欢迎语、**历史消息分割线**、「未读」标记。
- 消息类型:文本、文件(物联网全案服务介绍.pdf 2.5MB)、时间戳(今天 10:23)。
- 输入区:多行输入(placeholder「输入消息,按Enter发送,Shift+Enter换行...」)、**Enter 发送**、**拖拽上传文件**、发送按钮。
### 3.22 个人中心(profile)— 左侧菜单布局
左侧菜单:账号安全 / 地址管理 / 收藏列表 / 资质列表 / 意见反馈 / 帮助中心 / 关于我们 / 专属客服热线。头部用户卡:默认名称 + 头像 + 手机号(脱敏,可编辑昵称)。
1. **账号安全**:
- 修改密码(上次修改:15天前;手机号 + 验证码 + 设置密码 + 确认密码 + 强度提示 + 协议勾选 + 确认修改)。
- 绑定手机(已绑定 186\*\*\*\*618;换绑流程:验证并换绑 → 新手机号 + 验证码,提示「换绑新手机号之后,可以用新的手机号及当前密码登录」)。
- 绑定邮箱(已绑定/未绑定 yongzh\*\*\*\*\*\*4@163.com;绑定/更换绑定邮箱/取消绑定,邮箱 + 邮箱验证码)。
- **注销账号**:注销条件校验(账号无未完成的订单/未结清的款项/进行中的合同/未处理的工单)→ 风险提示 4 条 → 同意《账号注销协议》→ 安全身份验证(发送验证码至 186\*\*\*\*9618)→ 二次确认弹窗「确定要注销账号吗?」(暂不注销/注销账号)→ 「注销成功」3 秒后返回登录页。
2. **地址管理**:地址卡列表(收货人姓名/联系方式/所在地区/详细地址/默认标签);+ 新增地址、编辑、删除(二次确认)、设为默认/取消默认;分页。
3. **收藏列表**:收藏的案例卡片(同 3.3 卡片),筛选面板同案例库。
4. **资质列表**:资质卡(资质类型/证书名称/证书编号/发证单位/有效期/状态:已认证、审核中、未通过);+ 新增资质/提交认证、编辑、删除(二次确认)、重新上传(未通过时);分页。
- 新增/编辑弹窗:资质类型*(SELECT:营业执照/生产许可证/体系认证/检测报告/授权书/其他资质)、证书名称*、证书编号*、发证单位*、有效期*(起止日期)、附件上传(图片/文档/压缩包,添加附件)。
5. **意见反馈**:反馈标题*、详细描述*(0/500 字)、附件上传(≤1G,预览/删除)、**提交反馈**/重置;「提交成功」提示。
6. **帮助中心**:FAQ 折叠组(1.账户与登录、2.功能使用指南、3.系统与权限,各含 Q/A)。
7. **关于我们**:平台简介、我们的使命、核心优势(4 条)、联系信息(客服热线/工作时间/平台官网链接 www.chongzizhizao.com/公司地址 山东省日照市)、版本信息(V1.0.0,更新时间 2026年09月)。
8. **专属客服热线**:电话 000-000-0000 + 工作时间(工作日 8:00-12:00 14:00-18:00)。
---
## 4. 数据字段定义(核心实体)
### 4.1 Case(案例)— `types/business/cases.d.ts`
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| id | string | 案例 ID |
| title | string | 项目名称 |
| category | BusinessType | 业务类型 |
| cover | string | 封面图 |
| finishDate | string | 完成时间 |
| teamSize | number | 服务团队(人) |
| scale | ScaleRange | 规模区间 |
| industry | string | 所属行业 |
| duration | string | 项目周期 |
| clientType | string | 客户类型 |
| background / painPoints / requirements / deliverables | string | 详情富文本 |
| video | string | 视频地址 |
| isFavorite | boolean | 是否收藏 |
### 4.2 Demand(需求)— `types/business/demand.d.ts`
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| businessType | BusinessType | 必填,单选(含「其他」) |
| projectName | string | 必填 |
| attachments | FileInfo[] | ≤1G |
| coreDescription | string | 必填,≤500 字 |
| expectedDuration | number | 预计开发周期(工作日) |
| budgetRange | 'lt1w' \| '1to5w' \| '5to10w' \| 'gt10w' | 预算范围 |
| userName / userPhone | string | 联系人 |
| remark | string | ≤500 字 |
| status | 'draft' \| 'submitted' | 草稿/已提交 |
### 4.3 Project(项目)— `types/business/project.d.ts`
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| projectNo | string | 项目编号 |
| projectName | string | 项目名称 |
| businessType | BusinessType | 业务类型 |
| progress | number | 进度 % |
| status | ProjectStatus | 待立项/进行中/待验收/已完成/售后中/已取消 |
| submitTime / startTime / endTime | string | 时间 |
| milestones | Milestone[] | 需求确认/原型设计/开发实现/测试验收/项目交付(status + time) |
| team | TeamMember[] | 项目经理等 |
| files | FileInfo[] | 项目文件 |
| paymentPlans | Bill[] | 付款计划 |
| invoiceRecords | Invoice[] | 发票记录 |
| contractFile | FileInfo | 合同文件 |
| afterSales | AfterSales | 售后工单 |
### 4.4 Contract(合同)— `types/business/contract.d.ts`
contractNo、contractName、contractType、contractAmount、relatedProject({ id, name })、projectNo、signStatus(履行中/已过期/待签署)、signDate、effectiveDate、expiryDate、files: FileInfo[]。
### 4.5 Bill / Payment / Invoice / InvoiceTitle — `types/business/finance.d.ts`
- **Bill**:billName(含期数与比例)、billNo、tradeNo、projectName、amount、status(待支付/已支付/未到期)、createTime。
- **Payment**:method(wechat/alipay)、amount、payTime、tradeNo、qrCode、expiresAt(倒计时)。
- **Invoice**:bill(关联账单)、status(已开票/开票中/未开票)、applyTime、file。
- **InvoiceTitle**:type(企业单位/非企业单位)、title、taxNo、isDefault。
### 4.6 Message(消息)— `types/business/message.d.ts`
id、type(在线客服/状态通知/系统通知)、title、summary、content(富文本)、publishTime、isRead、attachments: FileInfo[]。
### 4.7 用户与账号 — `types/business/user.d.ts` / `types/business/profile.d.ts`
- **User**:id、nickname、avatar、phone(脱敏展示)、email(脱敏展示)、passwordModifiedAt。
- **Address**:id、receiverName、phone、region、detailAddress、isDefault。
- **Qualification**:id、type(营业执照/生产许可证/体系认证/检测报告/授权书/其他)、certName、certNo、issuer、validFrom、validTo、status(已认证/审核中/未通过)、attachments: FileInfo[]。
### 4.8 通用 — `types/api.d.ts`
- `ApiResponse<T> { code, msg, data }`、`PageResult<T> { list, total }`、`FileInfo { name, size, uploadTime, url }`。
---
## 5. 组件拆分建议
### 5.1 公共组件(`src/components/`,≥2 页面使用)
| 组件 | 使用页面 |
| --- | --- |
| AppHeader.vue | 全站(导航 + 消息铃铛 + 用户入口) |
| AppFooter.vue | 全站 |
| AppButton.vue | 全站按钮统一 |
| AppSwiper.vue | 首页 banner、业务服务卡片轮播 |
| CaseCard.vue | 案例库、首页精选、收藏列表 |
| FilterPanel.vue | 案例库、项目中心、收藏列表(筛选 + 已选条件回显) |
| SearchBar.vue | 案例库/项目/合同/账单/发票/消息列表 |
| PaginationBar.vue | 所有列表页 |
| FileList.vue | 需求填报、项目文件、售后、资质、意见反馈(文件卡 + 预览/下载/删除) |
| UploadArea.vue | 同上(拖拽/点击上传 + 1G 限制提示) |
| SmsCodeInput.vue | 登录/注册/找回密码/账号安全 |
| PasswordStrength.vue | 注册/修改密码(弱/中/强指示) |
| QrCodePanel.vue | 合同签署、扫码支付(倒计时 + 刷新) |
| StatusTag.vue | 项目状态/签署状态/账单状态/发票状态/资质状态 |
| ConfirmDialog.vue | 删除二次确认、注销确认 |
| StepForm.vue | 需求提报、申请售后(分步表单骨架) |
### 5.2 页面独有组件(`views/<page>/cpns/`)
| 页面 | 组件 |
| --- | --- |
| home | HomeWelcome.vue、HomeStats.vue、HomeQuickEntries.vue、HomeBusinessCards.vue、HomeCaseShowcase.vue、HomeServiceTabs.vue、BusinessDetail.vue |
| cases | CasesFilter.vue、CasesGrid.vue、CaseDetailHeader.vue、CaseRichText.vue |
| demand | DemandStep1Business.vue、DemandStep2Info.vue、DemandStep3Confirm.vue |
| login | LoginForm.vue、SmsLoginForm.vue、RegisterForm.vue、ResetForm.vue |
| project | ProjectFilter.vue、ProjectTable.vue、ProjectInfoCard.vue、ProjectTeam.vue、ProjectMilestones.vue、ProjectFiles.vue、ProjectFinance.vue、ProjectAfterSales.vue、AfterSalesForm.vue |
| contract | ContractTable.vue、ContractInfoCard.vue、ContractSignPanel.vue、SignSteps.vue |
| finance | FinanceOverview.vue、FinanceChart.vue、BillTable.vue、BillSummaryBar.vue、BillPayPanel.vue、PayMethodDialog.vue、PayResult.vue、InvoiceTable.vue、InvoiceTitleCard.vue、InvoiceTitleDialog.vue |
| message | MessageTabs.vue、MessageList.vue、MessageItem.vue、NoticeDetail.vue |
| service | ChatWindow.vue、ChatMessageItem.vue、ChatFileCard.vue、ChatInput.vue |
| profile | ProfileSider.vue、ProfileUserCard.vue、SecurityPanel.vue、ChangePasswordDialog.vue、UnbindAccountDialog.vue、AddressCard.vue、AddressDialog.vue、FavoritesGrid.vue、QualificationCard.vue、QualificationDialog.vue、FeedbackForm.vue、HelpFaq.vue、AboutPanel.vue、HotlinePanel.vue |
---
## 6. 待决事项(接口文档/蓝湖到位后补充)
1. 接口路径/入参出参以接口文档为准;当前仅按本 PRD 定义前端实体类型。
2. 蓝湖视觉参数(色值/字号/间距/圆角/阴影)待设计稿提供,暂以原型提取值近似。
3. 支付(微信/支付宝)与电子签章(支付宝扫码)对接方式待后端确认。
4. 「下载 APP」「报表导出」「发送邮箱」的交互细节待确认。

170
docs/dev-plan.md Normal file
View File

@@ -0,0 +1,170 @@
# 开发规划 — cz-web(auto-dev 全流程跟踪表)
## 使用说明(工作规则)
1. **状态标记**:`[x]` = 开发完成并验证通过;`[~]` = 开发中;`[ ]` = 未开始;`[!]` = 阻塞(注明原因)。
2. **每完成一项立即打 `[x]`**(开发结束标记),不得批量补标。
3. **之后只做未完成(`[ ]`/`[~]`/`[!]`)的部分**,已完成项不再重做,除非回归失败。
4. 每个模块收尾必须过 `pnpm build`(vue-tsc 零错误)才算可打 `[x]`。
5. 当前约束:**无蓝湖设计稿、无接口文档** → 阶段二/接口细节 `[!]` 阻塞中;页面代码按 PRD + 原型降级开发(结构/交互先行,视觉参数用 `styles/variables.less` 近似值,接口用 store 层 mock 临时实现并集中标注 `// TODO(api)`,文档到位后仅替换 api 层)。
## 阶段总览
| 阶段 | 内容 | 状态 |
| --- | --- | --- |
| 阶段一 | PRD 生成(`docs/PRD.md`) | [x] |
| 阶段二 | 蓝湖 MCP 设计稿读取(标注参数/切图) | [!] 无设计稿,阻塞 |
| 阶段三 | 页面结构规划(`docs/page-architecture.md`) | [x] |
| 阶段四 | 页面代码生成 + 组件拆分 | [x] |
| 阶段五 | API + Store 逻辑层 | [x] |
| 阶段六 | 公共组件提取 | [x] |
| 阶段七 | 自动验证与修正(`pnpm build` 零错误) | [x] |
| 补齐 | 接口文档落地后替换 mock api 层 | [!] 无接口文档,阻塞 |
| 补齐 | 蓝湖到位后校准视觉(色值/间距/字号/切图) | [!] 无设计稿,阻塞 |
## P0 基础工程(全模块前置)
- [x] vite.config.ts:配置 `@/` 别名、`css.preprocessorOptions.less.additionalData` 注入 variables.less、安装 less
- [x] src/styles/:index.less + variables.less(色/字/间距/圆角近似值)+ mixins.less + reset.less + common.less
- [x] src/types/api.d.ts:ApiResponse\<T\>、PageResult\<T\>、FileInfo
- [x] src/types/router.d.ts:RouteMeta 扩展(title、requiresAuth)
- [x] src/types/global.d.ts + src/env.d.ts
- [x] src/utils/:request.ts(唯一 axios 实例 + 拦截器)、storage.ts、validate.ts、format.ts
- [x] src/composables/:useCountDown.ts、useLoading.ts、useScroll.ts、useIntersection.ts
- [x] src/directives/:lazy.ts、debounce.ts、throttle.ts、index.ts(setupDirectives)
- [x] src/stores/index.ts(pinia 实例)+ stores/modules/site.ts(全局 loading/站点配置)
- [x] src/router/index.ts + routes.ts + guard.ts(Home + 404 先行注册,其余路由随 M1–M10 各自注册步骤接入)
- [x] src/layout/index.vue(AppHeader + router-view + AppFooter 骨架)
- [x] src/components/:AppHeader.vue、AppFooter.vue、AppButton.vue、index.ts
- [x] src/main.ts:注册 pinia/router/指令、引入 styles/index.less
- [x] 验证:`pnpm build` 零错误(vue-tsc + vite build 通过;Playwright 冒烟:header/footer/占位页渲染正常,控制台 0 错误)
## 模块开发清单(每模块七步,完成即打 [x])
### M1 home(首页 + 业务详情)
- [x] types/business/home.d.ts(含 cases.d.ts 案例实体与 api.d.ts BusinessType 共享枚举,首页案例卡提前复用)
- [x] api/home.ts(getHomeStats、getBusinessLines、getFeaturedCases、getBusinessDetail)`// TODO(api)`
- [x] stores/modules/home.ts(useHomeStore)
- [x] views/home/index.vue + index.ts + cpns/(HomeWelcome、HomeStats、HomeQuickEntries、HomeBusinessCards、HomeCaseShowcase、HomeServiceTabs)
- [x] views/home/detail.vue(业务详情)
- [x] router 注册 `/` 与 `/business/:type`
- [x] 复用检查 + `pnpm build` 通过(Playwright QA:首页六区块渲染、Tab 筛选生效、业务详情页内容完整、控制台 0 错误)
### M2 cases(案例库)
- [x] types/business/cases.d.ts(M1 已建,M2 直接复用)
- [x] api/cases.ts(getCaseList、getCaseDetail、toggleFavorite、getCaseCounts)`// TODO(api)`(8 条 mock + 筛选/分页)
- [x] stores/modules/cases.ts(useCasesStore:列表/筛选/分页/收藏)
- [x] views/cases/index.vue + detail.vue + index.ts + cpns/(CasesFilter、CasesGrid、CaseDetailHeader、CaseRichText)
- [x] 公共组件 CaseCard(M1 已建)、FilterPanel、PaginationBar 上移 components/
- [x] router 注册 `/cases`、`/cases/:id`
- [x] 复用检查 + `pnpm build` 通过(Playwright QA:4 组筛选 + 计数 8/4/2/1、筛选 8→4 卡 + chip 回显、详情四段富文本、收藏切换 + toast、控制台 0 错误)
### M3 demand(需求提报)
- [x] types/business/demand.d.ts
- [x] api/demand.ts(submitDemand、saveDraft、uploadAttachment)`// TODO(api)`
- [x] stores/modules/demand.ts(useDemandStore:表单态/草稿/提交)
- [x] views/demand/index.vue + index.ts + cpns/(DemandStep1Business、DemandStep2Info、DemandStep3Confirm)
- [x] 公共组件 StepForm、FileList、UploadArea、CaseCard 复用接入
- [x] router 注册 `/demand`
- [x] 复用检查 + `pnpm build` 通过
### M4 login(登录/注册/找回密码)
- [x] types/business/user.d.ts
- [x] api/auth.ts(loginByAccount、loginBySms、sendSmsCode、register、resetPassword)`// TODO(api)`
- [x] stores/modules/user.ts(useUserStore:token/用户信息/登录态)
- [x] views/login/index.vue(登录)+ register.vue + reset.vue + index.ts + cpns/(LoginForm、SmsLoginForm、RegisterForm、ResetForm)
- [x] 公共组件 SmsCodeInput、PasswordStrength 上移
- [x] router 注册 `/login`、`/register`、`/reset-password` + guard.ts 登录守卫
- [x] 复用检查 + `pnpm build` 通过
### M5 project(项目中心)
- [x] types/business/project.d.ts
- [x] api/project.ts(getProjectList、getProjectDetail、uploadProjectFile、deleteProjectFile、submitAfterSales、cancelAfterSales)`// TODO(api)`
- [x] stores/modules/project.ts(useProjectStore:列表/筛选/详情/文件/售后)
- [x] views/project/index.vue + detail.vue + after-sales.vue + index.ts + cpns/(ProjectFilter、ProjectTable、ProjectInfoCard、ProjectTeam、ProjectMilestones、ProjectFiles、ProjectFinance、ProjectAfterSales、AfterSalesForm)
- [x] 公共组件 StatusTag、FileList、StepForm 复用接入
- [x] router 注册 `/project`、`/project/:id`、`/project/:id/after-sales`
- [x] 复用检查 + `pnpm build` 通过
### M6 contract(合同中心)
- [x] types/business/contract.d.ts
- [x] api/contract.ts(getContractList、getContractDetail、getSignQr、refreshSignQr)`// TODO(api)`
- [x] stores/modules/contract.ts(useContractStore:列表/详情/签署二维码倒计时)
- [x] views/contract/index.vue + detail.vue + sign.vue + index.ts + cpns/(ContractTable、ContractInfoCard、ContractSignPanel、SignSteps)
- [x] 公共组件 QrCodePanel、StatusTag 复用接入
- [x] router 注册 `/contract`、`/contract/:id`、`/contract/:id/sign`
- [x] 复用检查 + `pnpm build` 通过
### M7 finance(财务中心)
- [x] types/business/finance.d.ts
- [x] api/finance.ts(getFinanceStats、getBillList、getBillDetail、createPayment、getPayResult、getInvoiceList、applyInvoice、sendInvoiceEmail、getInvoiceTitles、createInvoiceTitle、updateInvoiceTitle、deleteInvoiceTitle、setDefaultTitle、exportReport)`// TODO(api)`
- [x] stores/modules/finance.ts(useFinanceStore:概览统计/账单/支付/发票/抬头)
- [x] views/finance/index.vue(概览)+ bills.vue + bill-detail.vue + pay.vue + pay-result.vue + invoices.vue + invoice-titles.vue + index.ts + cpns/(FinanceOverview、FinanceChart、BillTable、BillSummaryBar、BillPayPanel、PayMethodDialog、PayResult、InvoiceTable、InvoiceTitleCard、InvoiceTitleDialog)
- [x] 公共组件 QrCodePanel、StatusTag、ConfirmDialog、PaginationBar 复用接入
- [x] router 注册 `/finance` 及 6 个子路由
- [x] 复用检查 + `pnpm build` 通过
### M8 message(消息中心)
- [x] types/business/message.d.ts
- [x] api/message.ts(getMessageList、getMessageDetail、markAllRead、markRead)`// TODO(api)`
- [x] stores/modules/message.ts(useMessageStore:列表/分类未读数/详情)
- [x] views/message/index.vue + detail.vue + index.ts + cpns/(MessageTabs、MessageList、MessageItem、NoticeDetail)
- [x] AppHeader 消息铃铛角标接入 message store
- [x] router 注册 `/message`、`/message/:id`
- [x] 复用检查 + `pnpm build` 通过
### M9 service(在线客服)
- [x] types/business/service.d.ts
- [x] api/service.ts(getChatHistory、sendChatMessage、uploadChatFile)`// TODO(api)`
- [x] stores/modules/service.ts(useServiceStore:会话/消息/发送)
- [x] views/service/index.vue + index.ts + cpns/(ChatWindow、ChatMessageItem、ChatFileCard、ChatInput)
- [x] 全局浮动「在线客服」入口接入
- [x] router 注册 `/service`
- [x] 复用检查 + `pnpm build` 通过
### M10 profile(个人中心)
- [x] types/business/profile.d.ts
- [x] api/profile.ts(updateNickname、changePassword、bindPhone、unbindPhone、bindEmail、unbindEmail、deleteAccount、verifyIdentity、getAddresses、createAddress、updateAddress、deleteAddress、setDefaultAddress、getFavorites、getQualifications、createQualification、updateQualification、deleteQualification、submitFeedback)`// TODO(api)`
- [x] stores/modules/profile.ts(useProfileStore:账号/地址/收藏/资质/反馈)
- [x] views/profile/index.vue(左菜单布局)+ security.vue + address.vue + favorites.vue + qualifications.vue + feedback.vue + help.vue + about.vue + hotline.vue + index.ts + cpns/(ProfileSider、ProfileUserCard、SecurityPanel、ChangePasswordDialog、UnbindAccountDialog、AddressCard、AddressDialog、FavoritesGrid、QualificationCard、QualificationDialog、FeedbackForm、HelpFaq、AboutPanel、HotlinePanel)
- [x] 公共组件 SmsCodeInput、PasswordStrength、ConfirmDialog、FileList 复用接入
- [x] router 注册 `/profile` 嵌套 8 子路由
- [x] 复用检查 + `pnpm build` 通过
## 收尾阶段
- [x] 阶段六:全局扫描,跨页面重复 UI 上移 components/,更新 components/index.ts barrel
- [x] 阶段七:逐页对照 PRD/原型自检(布局/交互/字段/组件拆分/规范合规:无 as any、页面不直接 import api)
- [x] `pnpm build`(vue-tsc)全量零错误
- [ ] 蓝湖到位后:校准 variables.less 色值/字号/间距,替换切图,逐页对照设计稿修正 → 补打 [x]
- [ ] 接口文档到位后:逐 api 文件替换 `// TODO(api)` 为真实路径/入参出参,走真实联调 → 补打 [x]
## 完成度速查
| 单元 | 状态 |
| --- | --- |
| P0 基础工程 | [x] |
| M1 home | [x] |
| M2 cases | [x] |
| M3 demand | [x] |
| M4 login | [x] |
| M5 project | [x] |
| M6 contract | [x] |
| M7 finance | [x] |
| M8 message | [x] |
| M9 service | [x] |
| M10 profile | [x] |
| 阶段六 公共组件提取 | [x] |
| 阶段七 验证修正 | [x] |
| 蓝湖视觉补齐 | [!] |
| 接口联调补齐 | [!] |

206
docs/page-architecture.md Normal file
View File

@@ -0,0 +1,206 @@
# 页面架构规划 — cz-web(auto-dev 阶段三产出)
> 依据 `docs/PRD.md` 梳理。规范遵循 vue-project-structure skill:三层数据流(页面 → store → api)、四者同名(views/api/store/types)、less 样式、`@/` 别名。
## 1. 页面清单表(模块 → 页面 → 功能点 → 数据字段)
### 模块 home(首页)
| 页面 | 功能点 | 数据字段 |
| --- | --- | --- |
| 首页 `/` | 欢迎区、数据看板、快捷入口、业务服务卡片、案例精选、服务 Tab、页脚 | stats{pending,inProgress,total}、quickLinks[]、businessLines[]、cases[] |
| 业务详情 `/business/:type` | 面包屑、业务介绍、服务内容富文本+视频、服务类型子 Tab | businessLine{id,name,slogan,serviceContent,serviceTypes[],video} |
### 模块 cases(案例库)
| 页面 | 功能点 | 数据字段 |
| --- | --- | --- |
| 案例列表 `/cases` | 四维筛选(业务类型/行业/规模/完成时间)+关键字、已选条件回显、案例卡片网格、分页 | Case(见 PRD 4.1)、CaseQuery{category,industries[],scales[],dateRange,keyword,page} |
| 案例详情 `/cases/:id` | 概览、收藏/分享、视频、富文本四段、一键填报类似案例 | Case 全量、isFavorite |
### 模块 demand(需求提报)
| 页面 | 功能点 | 数据字段 |
| --- | --- | --- |
| 需求提报 `/demand` | 三步表单:业务类型单选→需求信息+附件→确认备注;立即提报/保存草稿/重置 | Demand(见 PRD 4.2) |
### 模块 login(认证)
| 页面 | 功能点 | 数据字段 |
| --- | --- | --- |
| 登录 `/login` | 账号密码/手机验证码双模式、游客模式、协议勾选 | account,password,phone,smsCode,agreeTerms |
| 注册 `/register` | 手机+验证码+密码(强度指示)+确认密码、协议勾选 | phone,smsCode,password,confirmPassword |
| 找回密码 `/reset-password` | 手机+验证码+新密码+确认、确认修改 | phone,smsCode,newPassword,confirmPassword |
### 模块 project(项目中心)
| 页面 | 功能点 | 数据字段 |
| --- | --- | --- |
| 项目列表 `/project` | 三维筛选+关键字、状态 Tab、项目表格、分页 | Project(PRD 4.3)、ProjectQuery{businessType,status,dateRange,keyword,page} |
| 项目详情 `/project/:id` | 信息卡、项目团队、四 Tab(进度里程碑/项目文件/合同财务/售后信息) | Project 全量(milestones,team,files,paymentPlans,invoiceRecords,afterSales) |
| 申请售后 `/project/:id/after-sales` | 三步表单(业务类型/问题描述+附件/备注)、提交生成工单 | AfterSales{type,description,attachments,remark} |
### 模块 contract(合同中心)
| 页面 | 功能点 | 数据字段 |
| --- | --- | --- |
| 合同列表 `/contract` | 关键字搜索、合同表格、去签署/详情、分页 | Contract(PRD 4.4)、ContractQuery{keyword,page} |
| 合同详情 `/contract/:id` | 合同信息只读表单、关联项目跳转、合同文件、返回 | Contract 全量 |
| 签署合同 `/contract/:id/sign` | 支付宝扫码二维码(04:32 倒计时+刷新)、四步签署指引、完成自动跳转 | signQr{url,expiresAt} |
### 模块 finance(财务中心)
| 页面 | 功能点 | 数据字段 |
| --- | --- | --- |
| 财务概览 `/finance` | 累计消费总额+月份/季度/年度切换、业务类型分布图、待支付角标、快捷入口 | financeStats{totalExpense,month,distribution[],pendingCount} |
| 账单明细 `/finance/bills` | 状态 Tab、搜索、账单表格(多选)、汇总条、批量立即支付、分页 | Bill(PRD 4.5)、BillQuery{status,keyword,page} |
| 账单详情 `/finance/bills/:id` | 订单信息卡、待支付/已支付/未到期三态展示、返回 | Bill 全量、Payment |
| 扫码支付 `/finance/bills/:id/pay` | 支付二维码(倒计时+刷新)、微信/支付宝切换弹窗、订单明细、三步指引 | Payment{method,qrCode,expiresAt,amount} |
| 支付结果 `/finance/bills/:id/pay/result` | 支付成功卡、支付信息、已支付订单列表 | Payment 结果 |
| 发票申请 `/finance/invoices` | 默认抬头卡、状态 Tab、发票表格、申请开票/预览/下载/发送邮箱、分页 | Invoice(PRD 4.5) |
| 发票抬头管理 `/finance/invoice-titles` | 抬头列表卡、新增/编辑/删除(二次确认)、设为默认 | InvoiceTitle(PRD 4.5) |
### 模块 message(消息中心)
| 页面 | 功能点 | 数据字段 |
| --- | --- | --- |
| 消息中心 `/message` | 分类 Tab(全部/在线客服/状态通知/系统通知+未读数)、搜索、全部已读、消息列表、分页 | Message(PRD 4.6)、MessageQuery{type,keyword,page} |
| 通知详情 `/message/:id` | 标题/发布时间/富文本正文/附件、返回 | Message 全量 |
### 模块 service(在线客服)
| 页面 | 功能点 | 数据字段 |
| --- | --- | --- |
| 在线客服 `/service` | 聊天窗、历史消息分割线、未读标记、文本/文件消息、Enter 发送、拖拽上传 | ChatMessage{id,role,content,file?,time} |
### 模块 profile(个人中心,左菜单嵌套布局)
| 页面 | 功能点 | 数据字段 |
| --- | --- | --- |
| 账号安全 `/profile/security` | 修改密码、绑定手机换绑、绑定/解绑邮箱、注销账号(条件校验→风险提示→身份验证→二次确认) | User(PRD 4.7) |
| 地址管理 `/profile/address` | 地址卡列表、新增/编辑/删除(二次确认)、设为默认、分页 | Address(PRD 4.7) |
| 收藏列表 `/profile/favorites` | 收藏案例卡片网格 + 筛选、分页 | Case[](复用 cases 实体) |
| 资质列表 `/profile/qualifications` | 资质卡列表、新增/编辑/删除/重新上传、审核状态、分页 | Qualification(PRD 4.7) |
| 意见反馈 `/profile/feedback` | 标题+描述+附件表单、提交反馈/重置 | Feedback{title,description,attachments} |
| 帮助中心 `/profile/help` | FAQ 折叠组(三类 Q/A) | FaqGroup[](静态) |
| 关于我们 `/profile/about` | 简介/使命/核心优势/联系信息/版本信息 | 静态+site 配置 |
| 专属客服热线 `/profile/hotline` | 热线电话+工作时间 | 静态 |
## 2. 路由规划(`src/router/routes.ts`)
```ts
export const routes = [
// ── 公开 ──
{ path: '/', name: 'Home', component: () => import('@/views/home'), meta: { title: '首页' } },
{ path: '/business/:type', name: 'BusinessDetail', component: () => import('@/views/home/detail.vue'), meta: { title: '业务详情' } },
{ path: '/cases', name: 'Cases', component: () => import('@/views/cases'), meta: { title: '成功案例库' } },
{ path: '/cases/:id', name: 'CaseDetail', component: () => import('@/views/cases/detail.vue'), meta: { title: '案例详情' } },
{ path: '/demand', name: 'Demand', component: () => import('@/views/demand'), meta: { title: '需求提报' } },
// ── 游客区 ──
{ path: '/login', name: 'Login', component: () => import('@/views/login'), meta: { title: '登录' } },
{ path: '/register', name: 'Register', component: () => import('@/views/login/register.vue'), meta: { title: '注册' } },
{ path: '/reset-password', name: 'ResetPassword', component: () => import('@/views/login/reset.vue'), meta: { title: '找回密码' } },
// ── 登录区(需守卫)──
{ path: '/project', name: 'Project', component: () => import('@/views/project'), meta: { title: '项目中心', requiresAuth: true } },
{ path: '/project/:id', name: 'ProjectDetail', component: () => import('@/views/project/detail.vue'), meta: { title: '项目详情', requiresAuth: true } },
{ path: '/project/:id/after-sales', name: 'AfterSales', component: () => import('@/views/project/after-sales.vue'), meta: { title: '申请售后', requiresAuth: true } },
{ path: '/contract', name: 'Contract', component: () => import('@/views/contract'), meta: { title: '合同中心', requiresAuth: true } },
{ path: '/contract/:id', name: 'ContractDetail', component: () => import('@/views/contract/detail.vue'), meta: { title: '合同详情', requiresAuth: true } },
{ path: '/contract/:id/sign', name: 'ContractSign', component: () => import('@/views/contract/sign.vue'), meta: { title: '签署合同', requiresAuth: true } },
{ path: '/finance', name: 'Finance', component: () => import('@/views/finance'), meta: { title: '财务中心', requiresAuth: true } },
{ path: '/finance/bills', name: 'Bills', component: () => import('@/views/finance/bills.vue'), meta: { title: '账单明细', requiresAuth: true } },
{ path: '/finance/bills/:id', name: 'BillDetail', component: () => import('@/views/finance/bill-detail.vue'), meta: { title: '账单详情', requiresAuth: true } },
{ path: '/finance/bills/:id/pay', name: 'BillPay', component: () => import('@/views/finance/pay.vue'), meta: { title: '扫码支付', requiresAuth: true } },
{ path: '/finance/bills/:id/pay/result', name: 'PayResult', component: () => import('@/views/finance/pay-result.vue'), meta: { title: '支付结果', requiresAuth: true } },
{ path: '/finance/invoices', name: 'Invoices', component: () => import('@/views/finance/invoices.vue'), meta: { title: '发票申请', requiresAuth: true } },
{ path: '/finance/invoice-titles', name: 'InvoiceTitles', component: () => import('@/views/finance/invoice-titles.vue'), meta: { title: '发票抬头', requiresAuth: true } },
{ path: '/message', name: 'Message', component: () => import('@/views/message'), meta: { title: '消息中心', requiresAuth: true } },
{ path: '/message/:id', name: 'MessageDetail', component: () => import('@/views/message/detail.vue'), meta: { title: '通知详情', requiresAuth: true } },
{ path: '/service', name: 'Service', component: () => import('@/views/service'), meta: { title: '在线客服', requiresAuth: true } },
// ── 个人中心(左菜单布局嵌套)──
{
path: '/profile', component: () => import('@/views/profile'), meta: { title: '个人中心', requiresAuth: true },
children: [
{ path: '', redirect: '/profile/security' },
{ path: 'security', name: 'ProfileSecurity', component: () => import('@/views/profile/security.vue'), meta: { title: '账号安全', requiresAuth: true } },
{ path: 'address', name: 'ProfileAddress', component: () => import('@/views/profile/address.vue'), meta: { title: '地址管理', requiresAuth: true } },
{ path: 'favorites', name: 'ProfileFavorites', component: () => import('@/views/profile/favorites.vue'), meta: { title: '收藏列表', requiresAuth: true } },
{ path: 'qualifications', name: 'ProfileQualifications', component: () => import('@/views/profile/qualifications.vue'), meta: { title: '资质列表', requiresAuth: true } },
{ path: 'feedback', name: 'ProfileFeedback', component: () => import('@/views/profile/feedback.vue'), meta: { title: '意见反馈', requiresAuth: true } },
{ path: 'help', name: 'ProfileHelp', component: () => import('@/views/profile/help.vue'), meta: { title: '帮助中心', requiresAuth: true } },
{ path: 'about', name: 'ProfileAbout', component: () => import('@/views/profile/about.vue'), meta: { title: '关于我们', requiresAuth: true } },
{ path: 'hotline', name: 'ProfileHotline', component: () => import('@/views/profile/hotline.vue'), meta: { title: '专属客服热线', requiresAuth: true } },
],
},
{ path: '/:pathMatch(.*)*', name: 'NotFound', component: () => import('@/views/404.vue'), meta: { title: '页面不存在' } },
]
```
> 路由守卫(`router/guard.ts`):`meta.requiresAuth` 未登录 → 重定向 `/login`;登录页已登录 → 重定向 `/`;切换路由时设置 `document.title`。
## 3. 四者同名映射表(模块 → 文件)
| 模块 | views/ | api/ | stores/modules/ | types/business/ | Store 名 |
| --- | --- | --- | --- | --- | --- |
| home | `views/home/`(index.vue + detail.vue) | `api/home.ts` | `stores/modules/home.ts` | `types/business/home.d.ts` | useHomeStore |
| cases | `views/cases/`(index.vue + detail.vue) | `api/cases.ts` | `stores/modules/cases.ts` | `types/business/cases.d.ts` | useCasesStore |
| demand | `views/demand/` | `api/demand.ts` | `stores/modules/demand.ts` | `types/business/demand.d.ts` | useDemandStore |
| login | `views/login/`(index.vue + register.vue + reset.vue) | `api/auth.ts` | `stores/modules/user.ts` | `types/business/user.d.ts` | useUserStore |
| project | `views/project/`(index.vue + detail.vue + after-sales.vue) | `api/project.ts` | `stores/modules/project.ts` | `types/business/project.d.ts` | useProjectStore |
| contract | `views/contract/`(index.vue + detail.vue + sign.vue) | `api/contract.ts` | `stores/modules/contract.ts` | `types/business/contract.d.ts` | useContractStore |
| finance | `views/finance/`(index.vue + bills.vue + bill-detail.vue + pay.vue + pay-result.vue + invoices.vue + invoice-titles.vue) | `api/finance.ts` | `stores/modules/finance.ts` | `types/business/finance.d.ts` | useFinanceStore |
| message | `views/message/`(index.vue + detail.vue) | `api/message.ts` | `stores/modules/message.ts` | `types/business/message.d.ts` | useMessageStore |
| service | `views/service/` | `api/service.ts` | `stores/modules/service.ts` | `types/business/service.d.ts` | useServiceStore |
| profile | `views/profile/`(index.vue 布局 + 8 子页) | `api/profile.ts` | `stores/modules/profile.ts` | `types/business/profile.d.ts` | useProfileStore |
| 站点公共 | — | — | `stores/modules/site.ts` | — | useSiteStore(全局 loading/站点配置) |
## 4. 复用性分析
### 4.1 跨页面复用 → `src/components/`
| 组件 | 复用范围 | 判定依据 |
| --- | --- | --- |
| AppHeader / AppFooter | 全站 | layout 挂载 |
| AppButton / AppSwiper | 全站 | 通用基础件 |
| CaseCard | 首页精选、案例库、收藏列表 | ≥3 页面 |
| FilterPanel(含已选条件回显) | 案例库、项目中心、收藏列表 | ≥2 页面 |
| SearchBar | 案例/项目/合同/账单/发票/消息 | ≥2 页面 |
| PaginationBar | 所有列表页 | ≥2 页面 |
| FileList + UploadArea | 需求填报、项目文件、售后、资质、意见反馈 | ≥2 页面 |
| SmsCodeInput | 登录/注册/找回/换绑手机/换绑邮箱/注销验证 | ≥2 页面 |
| PasswordStrength | 注册、修改密码 | ≥2 页面 |
| QrCodePanel | 合同签署、扫码支付 | ≥2 页面 |
| StatusTag | 项目/合同/账单/发票/资质状态 | ≥2 页面 |
| ConfirmDialog | 删除/注销等二次确认 | ≥2 页面 |
| StepForm 骨架 | 需求提报、申请售后 | ≥2 页面 |
### 4.2 页面独有 → `views/<page>/cpns/`
详见 `docs/PRD.md` 第 5.2 节组件清单。判定:仅 1 个页面使用即入 cpns/,严禁跨页面 import。
### 4.3 逻辑复用
| 逻辑 | 归属 | 使用方 |
| --- | --- | --- |
| useCountDown(验证码倒计时/二维码失效倒计时) | composables/ | SmsCodeInput、QrCodePanel |
| useLoading | composables/ | 各 store 请求态(可选) |
| useScroll(吸顶/回到顶部) | composables/ | 长列表页 |
| useIntersection(懒加载) | composables/ | 案例卡片图片 |
| v-lazy / v-debounce / v-throttle | directives/ | 图片懒加载、搜索防抖 |
| format.ts(金额/日期/千分位) | utils/ | 财务/项目展示 |
| validate.ts(手机号/邮箱) | utils/ | 表单校验 |
| storage.ts(token/草稿缓存) | utils/ | user store、需求草稿 |
## 5. 静态资源规划
```
src/assets/
├── images/ # 案例封面、业务卡片图、banner(原型导出切图后语义化命名)
├── icons/ # 业务类型图标、消息类型图标、状态图标
└── fonts/ # 如需自定义字体
```
> 切图来源:蓝湖到位前使用原型占位图;到位后按蓝湖图层语义化命名替换。

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

22
read_prototype.js Normal file
View File

@@ -0,0 +1,22 @@
const fs = require('node:fs')
const path = require('node:path')
const process = require('node:process')
const filePath = process.argv[2]
if (!filePath) {
console.error('Error: 请提供原型文件路径')
process.exit(1)
}
const fullPath = path.resolve(filePath)
if (fs.existsSync(fullPath)) {
console.log('=== START PROTOTYPE CONTENT ===')
console.log(fs.readFileSync(fullPath, 'utf-8'))
console.log('=== END PROTOTYPE CONTENT ===')
}
else {
console.error(`Error: 未找到原型文件 ${fullPath}`)
process.exit(1)
}

View File

@@ -10,7 +10,7 @@ export default defineConfig({
proxy: {
// 开发期把 /api 转发到 vermis-maker 后端(8080),并去掉 /api 前缀
'/api': {
target: 'http://localhost:8080',
target: 'http://192.168.0.43:8080',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
@@ -25,7 +25,8 @@ export default defineConfig({
preprocessorOptions: {
less: {
// 自动注入变量与混合宏,组件内可直接使用 @primary-color 等
additionalData: '@import "@/styles/variables.less";\n@import "@/styles/mixins.less";',
additionalData:
'@import "@/styles/variables.less";\n@import "@/styles/mixins.less";',
},
},
},