一键导入
v3-upsert-store
创建或更新全局状态(Store)。当用户提到以下任何场景时都应触发:新建状态管理、新增 Pinia Store、给 Store 加字段。即使用户没有明确说 Store,只要意图是和状态管理器有关就应该使用此 Skill。使用时需提供 Store 名称、State 字段和 Actions 描述。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
创建或更新全局状态(Store)。当用户提到以下任何场景时都应触发:新建状态管理、新增 Pinia Store、给 Store 加字段。即使用户没有明确说 Store,只要意图是和状态管理器有关就应该使用此 Skill。使用时需提供 Store 名称、State 字段和 Actions 描述。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
创建增删改查(CRUD)页面,基于 Element Plus 组件库,包含表格、搜索、分页、新增/编辑弹窗、删除确认等功能。当用户提到以下任何场景时都应触发:创建管理页面、创建列表页、创建表格页。即使用户没有明确说 CRUD,只要意图是创建带表格和表单操作的后台页面就应该使用此 Skill。使用时需提供模块名称和字段信息。
创建或更新路由表(Router)。当用户提到以下任何场景时都应触发:新建页面路由、新增菜单项、修改路由权限、调整路由结构。即使用户没有明确说路由,只要意图是导航菜单和访问控制就应该使用此 Skill。使用时需提供路由路径、名称和类型等必要信息。
项目内置工具函数使用教程,涵盖验证、日期格式化、CSS 变量、权限判断、本地存储等工具。当用户提到以下任何场景时都应触发:使用工具函数、调用 utils、格式化日期、判断权限、操作 localStorage、获取/设置 CSS 变量、验证数据类型、判断外链、获取/存储 Token。即使用户没有明确说 Utils,只要意图是使用项目内置的通用工具函数就应该使用此 Skill。
项目内置组合式函数使用教程,涵盖设备检测、异步下拉、全屏加载、分页、路由监听、主题切换、动态标题、水印等组合式函数。当用户提到以下任何场景时都应触发:使用组合式函数、调用 Composables、判断设备类型、异步加载下拉选项、全屏 Loading、分页逻辑、监听路由变化、切换主题、设置页面标题、添加水印。即使用户没有明确说 Composables,只要意图是使用项目内置的组合式函数就应该使用此 Skill。
| name | v3-upsert-store |
| description | 创建或更新全局状态(Store)。当用户提到以下任何场景时都应触发:新建状态管理、新增 Pinia Store、给 Store 加字段。即使用户没有明确说 Store,只要意图是和状态管理器有关就应该使用此 Skill。使用时需提供 Store 名称、State 字段和 Actions 描述。 |
| metadata | {"author":"pany","version":"2026.06.01"} |
根据用户提供的 Store 名称、State 字段和 Actions 描述,生成或更新 Pinia Store 文件。
本 Skill 定义的是项目默认 Store 模式,当用户的实际需求与本 Skill 约定冲突时,以用户需求为准。
用户需提供:
counter、notification)— 用于文件名和命名如果用户信息不完整,主动询问补全后再生成。
当 src/pinia/stores/<store名>.ts 不存在时,生成完整的 Store 文件。
当文件已存在时,在已有代码中追加新的 State 字段和 Actions,保留原有代码不动。追加时:
// #region 分组则放在对应区域)return 语句,追加新导出的字段和方法路径:src/pinia/stores/<store名>.ts
src/common/constants/cache-key.ts 的 CacheKey 类中追加新的 Keysrc/common/utils/local-storage.ts 中追加对应的 get/set 函数完整的 Store 文件结构如下(以一个带持久化和辅助函数的 Store 为例):
import type { XxxType } from "@@/types/xxx"
import { getXxx, setXxx } from "@@/utils/local-storage"
import { pinia } from "@/pinia"
interface Sidebar {
opened: boolean
withoutAnimation: boolean
}
/** 辅助函数的用途描述 */
function helperFunction(param: string) {
// ...
}
export const useXxxStore = defineStore("xxx", () => {
// Token
const token = ref<string>(getToken() || "")
// 侧边栏状态
const sidebar: Sidebar = reactive({
opened: true,
withoutAnimation: false
})
// 设置 Token
const setToken = (value: string) => {
token.value = value
}
// 切换侧边栏
const toggleSidebar = (withoutAnimation: boolean) => {
sidebar.opened = !sidebar.opened
sidebar.withoutAnimation = withoutAnimation
}
return { token, sidebar, setToken, toggleSidebar }
})
/**
* @description 在 SPA 应用中可用于在 pinia 实例被激活前使用 store
* @description 在 SSR 应用中可用于在 setup 外使用 store
*/
export function useXxxStoreOutside() {
return useXxxStore(pinia)
}
defineStore("id", () => { ... })),不使用 Options APIuseXxxStoreOutside 函数,且 JSDoc 注释原样保留(见上方模板)defineStore 第一个参数(Store ID):单词用小写(如 "user"),多词用 kebab-case(如 "tags-view")ref 用泛型:ref<string>("")、ref<number>(0)、ref<string[]>([])reactive 在变量上标注类型:const sidebar: Sidebar = reactive({...})const xxx = (param: Type) => { ... }// 单行注释,描述具体用途(如 // 切换侧边栏、// 设置 Token)/** */ JSDoc 注释 Store 内部成员// state、// actions),每条注释直接描述对应内容/** */ JSDoc 注释// #region / // #endregion 仅在同一类操作有多组变体时使用(如 tags-view 的 add/del/delOthers/delAll),普通 Store 不需要defineStore、ref、reactive、watch、watchEffect、computed 无需手动 importimport type { Ref } from "vue"1. import type 语句(类型导入)
2. import 语句(运行时导入,Pinia 实例必须导入)
3. interface / type 声明(Store 需要的本地类型)
4. 模块级辅助函数(不需要响应式访问的纯函数,用 /** */ 注释)
5. export const useXxxStore = defineStore(...)
6. export function useXxxStoreOutside()
当字段需要持久化时,遵循项目已有模式:
1. CacheKey 常量(src/common/constants/cache-key.ts):
static readonly XXX_DATA = `${SYSTEM_NAME}-xxx-data-key`
命名规则:大写下划线 + -key 后缀。
2. localStorage 工具函数(src/common/utils/local-storage.ts):
简单字符串值:
// #region Xxx 描述
export function getXxx() {
return localStorage.getItem(CacheKey.XXX_DATA)
}
export function setXxx(value: string) {
localStorage.setItem(CacheKey.XXX_DATA, value)
}
// #endregion
对象/数组值:
// #region Xxx 描述
export function getXxx() {
const json = localStorage.getItem(CacheKey.XXX_DATA)
return json ? (JSON.parse(json) as XxxType) : null
}
export function setXxx(data: XxxType) {
localStorage.setItem(CacheKey.XXX_DATA, JSON.stringify(data))
}
// #endregion
3. Store 中使用:
import { getXxx, setXxx } from "@@/utils/local-storage"
// Xxx 数据
const data = ref<XxxType>(getXxx() ?? defaultValue)
// 监听变化并持久化
watch(data, (newVal) => {
setXxx(newVal)
})
当需要同时监听多个持久化字段时,用 watchEffect 代替多个 watch:
watchEffect(() => {
setVisitedViews(visitedViews.value)
setCachedViews(cachedViews.value)
})
interface 或 type 声明(定义在 Store 函数之前)export(如 export type TagView = Partial<RouteLocationNormalizedGeneric>)types 目录或就近放置Store 名为 notification 时:
| 位置 | 命名 |
|---|---|
| 文件 | src/pinia/stores/notification.ts |
| Store ID | "notification" |
| Composable | useNotificationStore |
| Outside | useNotificationStoreOutside |
| CacheKey(如需) | NOTIFICATION_DATA |
| localStorage 函数(如需) | getNotificationData / setNotificationData |
多词 Store 名使用 kebab-case 文件名和 Store ID(如 user-preference → "user-preference" → useUserPreferenceStore)。
// 类型导入
import type { Ref } from "vue"
import type { RouteRecordRaw } from "vue-router"
// 运行时导入:常量和工具函数
import { SIDEBAR_CLOSED, SIDEBAR_OPENED } from "@@/constants/app-key"
import { getSidebarStatus, setSidebarStatus } from "@@/utils/local-storage"
// 运行时导入:Pinia 实例(必需)
import { pinia } from "@/pinia"
// 运行时导入:其他 Store(当需要跨 Store 交互时)
import { useSettingsStore } from "./settings"
注意导入顺序:类型导入在前,运行时导入在后;@@ 路径在前,@ 路径在后。
ref vs reactive — 当 State 是一个有结构的对象且字段间关联紧密时用 reactive(如 sidebar 的 opened + withoutAnimation),否则每个独立状态用 ref。大多数情况下用 ref。
watch vs watchEffect — 监听单个字段变化时用 watch;监听多个字段且都需要持久化时用 watchEffect(自动追踪依赖,代码更简洁)。
辅助函数放在 Store 内还是外 — 不依赖响应式状态的纯逻辑函数放在 Store 外部(如权限过滤、格式化),需要访问 Store 内 ref / reactive 的函数放在内部作为 Action。
是否需要 Reset Action — 如果 Store 管理的是临时状态(如表单数据、UI 状态),通常需要一个 Reset 方法恢复初始值。如果是用户身份等持久数据,通常不需要通用 Reset。
是否需要 Outside 函数 — 始终生成。这是项目约定,确保在路由守卫、Axios 拦截器等 setup 外场景可用。