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

3.8 KiB
Raw Blame History

name, description
name description
code-vue Vue 3 Composition API、SFC 块顺序、Naive UI 组件显式导入、props/emits 与模板约定。编写或修改 .vue 文件时加载本技能。

Vue 规范(Vue 3 + Naive UI)

适用于 Composition API + <script setup lang="ts">。样式见 code-css。

基础

  • 新组件一律 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)

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 —— 筛选功能等于消失,且不报错。

<!-- ✅ 正确 -->
<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) 处理;插槽那条分支返回数组,所以正常。

权限与状态色

const user = useUserStore()
// 没有 v-hasPerm 指令,权限判断就是一次函数调用
const canManage = computed(() => user.has('org:manage'))
<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 通信,避免访问父组件实例。