Files
xiaotutongxue/frontend-pc/.agents/skills/code-vue/SKILL.md
T
lovife 5b877451eb refactor(pc): 从 Gi Admin Pro + Arco 重搭为纯 Vue 3 + Naive UI
旧模板的 193 个文件整体删除,换成纯 Vue 3.5 + Naive UI 2.42 的树。

- 去掉 auto-import(组件与 API 全显式 import)、v-hasPerm(改 user.has('码'),全库 8 处)、
  Stylelint;n-tag 的 type 统一过 utils/tag.ts 转换(Arco 色词直接透传会静默变灰)
- 图标改为构建期抽取:scripts/extract-pc-icons.py -> icons/icon-data.ts(37 个),
  内网离线部署不会白屏
- 重搭后修掉 6 类"编译 / lint / typecheck 全绿、界面上就是坏的"故障:
  ① NGrid 的 cols 写成像素值(不是断点名 -> 永远只 1 列,工作台因此错乱)
  ② n-tab-pane 用 tab 属性(只渲染空注释节点,整排 tab 一个字都不显示)
  ③ 漏 import 被当未知自定义元素(样式整块丢) ④ .n-card__content 类名不存在
  (高度链第一环失效,表格行在 DOM 里但屏幕上没有) ⑤ 填报单状态映射错位一格
  ⑥ 有标题的卡片没有上内边距(naive 的 padding-top 只给"内容区是长子"的卡片)
- 卡片式版面提成全局基线:styles/index.scss 的 xt-* 令牌 + .page-card / .toolbar /
  .section-title,页面只引用、不再各写一套
- 品牌:改名「深学在线」,文字标换成几何标(方 = 卷宗 / 环 = 在线,不用文字字形);
  index.html 的页签图标从 404 的 /favicon.ico 改指真实存在的 /favicon.svg
2026-10-10 16:48:46 +08:00

93 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: code-vue
description: Vue 3 Composition API、SFC 块顺序、Naive UI 组件显式导入、props/emits 与模板约定。编写或修改 .vue 文件时加载本技能。
---
# Vue 规范(Vue 3 + Naive UI)
适用于 Composition API + `<script setup lang="ts">`。样式见 [code-css](../code-css/SKILL.md)。
## 基础
- 新组件一律 **Composition API** + `<script setup lang="ts">`,禁止 Options API。
- 块顺序:`<template>` → `<script setup>` → `<style scoped>`。
- 需要组件名时用 `defineOptions({ name: 'XxxYyy' })`。
## Script 内顺序
类型导入 → 第三方 → Vue API → 项目模块 → `defineOptions` → `defineProps` + `withDefaults` → `defineEmits` → 常量/函数 → `ref`/`reactive` → `computed` → 方法 → 生命周期/`watch`。
## ⚠️ 显式 import(本仓库没有 auto-import)
```ts
import type { DataTableColumns, FormInst } from 'naive-ui'
import { NButton, NCard, NDataTable, NForm, NFormItem, NInput, NModal, NTag, useMessage } from 'naive-ui'
import { computed, h, onMounted, reactive, ref } from 'vue'
import * as tenantApi from '@/apis/xt/tenant'
```
- 组件用 **PascalCase** 标签:`<NDataTable :columns="columns" :data="list" />`(**不是** `<a-table>`)。
- 弹窗/抽屉、表格、表单全部来自 **naive-ui**;主题与全局配置在 `utils/naive.ts` / `App.vue` 一侧。
### 漏 import 是**静默故障**(2026-10 实测踩到 4 个文件 6 处)
写小写标签(`<n-button>`)而忘了 import 时,Vue 把它当**未知自定义元素**渲染:
**不报错、不崩、`pnpm typecheck` 与 `pnpm lint` 全绿**,只是样式整块丢掉。
实测表现:`<n-button>` 变成无边框透明块、`<n-avatar>` 变成 18×29 的裸元素、`<n-form>` 的表单排版全丢 ——
用户看到的就是"这个页面样式坏了"。
> **统一写 PascalCase 标签**(`<NButton>`),漏 import 时 Vue 会给出
> `Failed to resolve component` 警告,比小写标签好排查。
> 另外 `python scripts/check-wiring.py` 的**第 ⑧ 项**会静态核对
> 「模板里用到的 `<n-*>` ↔ 本文件的 import」,改完 PC 端跑一下它。
## ⚠️ `n-tab-pane` 的标签必须用 `#tab` **插槽**
naive-ui 2.45.3 里,`tab="文字"` **属性**写法渲染不出任何文字(只留一个空注释节点),
表现是**整排 tab 一个字都不显示、整行高度只剩 12px** —— 筛选功能等于消失,且不报错。
```vue
<!-- ✅ 正确 -->
<NTabs v-model:value="node">
<NTabPane :name="1">
<template #tab>
初审(班主任)
</template>
</NTabPane>
</NTabs>
<!-- ❌ 不要:标签会静默消失 -->
<NTabPane :name="1" tab="初审(班主任)" />
```
原因:属性值走 `normalizeVNode(() => render(mergedTab ?? name))`,而这个 thunk 返回
Text VNode,被当成块 `createBlock(vnode)` 处理;插槽那条分支返回数组,所以正常。
## 权限与状态色
```ts
const user = useUserStore()
// 没有 v-hasPerm 指令,权限判断就是一次函数调用
const canManage = computed(() => user.has('org:manage'))
```
```vue
<NTag
:type="tagOf(row.status)"
size="small"
>
{{ STATUS_NAMES[row.status] }}
</NTag>
```
⚠️ **不要**把 `apis/xt/*.ts` 里的 `color`(Arco 色词 `green`/`arcoblue`/`gold`)直接传给 `n-tag` 的 `type` ——
会**静默变成默认灰色**且不报错;必须过 `@/utils/tag.ts` 的 `tagOf()`。
## 模板
- 事件名、插槽名 **kebab-case**;组件 **PascalCase**。
- 表格列用 `h()` 渲染(`NButton` / `NTag` / `AppIcon`),逻辑别堆在模板里。
- 受控表单优先 `v-model`;复杂逻辑抽到 `computed` 或方法。
- 图标统一用 `@/icons/AppIcon.vue`(缺图标是**空占位、不报错**)。
- 子组件通过 props/emits 通信,避免访问父组件实例。