원클릭으로
frontend-development
前端开发指南与模式,涵盖 `apps/admin`(Vue 3 + TypeScript)的页面结构、列表页、表单页、弹窗和 i18n 的最新标准写法。
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
前端开发指南与模式,涵盖 `apps/admin`(Vue 3 + TypeScript)的页面结构、列表页、表单页、弹窗和 i18n 的最新标准写法。
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
使用 Nitro v3 框架和 H3 编写服务端 API 的技能。适用于后端接口开发、Mock 数据迁移到 Neon 数据库、以及编写符合 Drizzle ORM 标准的查询逻辑。当需要开发新的 CRUD 接口或修复现有后端逻辑时使用此技能。
规范类型项目(apps/type)的代码组织方式、导出语法和文件结构。用于解决类型导出冲突、创建统一导出入口、处理重复导出等问题。适用于类型项目开发、类型错误修复、代码规范实施场景。在处理类型项目的代码写法时,请使用本技能。
当你修改数据库结构或种子生成脚本时,请务必阅读并遵循此指南,以防止性能问题、数据一致性崩溃和部署失败。新 Schema 应在 apps/type 中创建。
数据库 Schema 变更时的全项目同步检查清单。当修改 apps/type 中 schema.ts 的表字段、新增数据库表、或删除表时,使用此技能确保类型项目、数据库迁移、后端接口、前端页面、种子数据和技能文档全部同步更新,避免遗漏。
当用户要求在 bug 已经定位并修复后,记录排错经验、事故结论、AI 记忆更新、复盘摘要或本地 MCP 记忆时使用。这个技能只负责沉淀"发生了什么、为什么会发生、如何修好、以后要记住什么",不要把它用于实际修复 bug。
新建公共组件规范专家 - 指导在 src/components/common 目录下创建符合项目规范的公共组件,包括文件结构、TypeScript 类型、Vue 组件、文档和测试页面。 触发条件(满足任意一项即触发): - 任务包含"新建组件"、"公共组件"、"common 组件"、"创建组件"等关键词 - 需要在 src/components/common 目录下创建新组件 - 需要创建可复用的业务组件(如表单分区标题、操作按钮组、信息展示卡片) - 需要编写组件的 TypeScript 类型定义 - 需要编写组件使用文档(index.md) - 需要创建组件测试页面(src/pages/test-use/) - 用户提及"组件规范"、"组件文档"、"组件测试"等关键词 必须协同的技能: - beautiful-component-design(组件美化时)- 图标、响应式设计、表单分区标题 - component-migration(从旧组件迁移时)- ColorUI → wot-design-uni - use-wd-form(组件内包含表单时)- 表单结构、wd-picker、校验规则 禁止事项: - 禁止在 components 目录外创建公共组件 - 禁止不编写组件文档(index.md) - 禁止不提供使用示例和测试页面 - 禁止组件命名不规范(必须使用短横线命名法) - 禁止不定义 TypeScript 类型(types.ts) - 禁止在组件文件顶部不添加说明注释 - 禁止不使用 withDefaults 设置 props 默认值 覆盖场景:所有需要跨页面复用的业务组件,包括表单分区标题(FormSectionTitle)、操作按钮组(ActivityActions)、信息展示卡片(ActivityInfo)、加载状态组件(ZPagingLoading)等。
| name | frontend-development |
| description | 前端开发指南与模式,涵盖 `apps/admin`(Vue 3 + TypeScript)的页面结构、列表页、表单页、弹窗和 i18n 的最新标准写法。 |
| license | MIT |
本技能用于指导 apps/admin 内的 Vue 3 页面、表单、弹窗和列表页开发。
如果你要修改现有页面,必须优先遵守当前仓库已经落地的写法,而不是继续复制旧页面里的过时模式。
apps/admin/src/pages/**/index.vueapps/admin/src/pages/**/components/form.vueapps/admin/src/pages/**/components/dialog.tsapps/admin/src/api/**apps/admin/src/composables/**references/list-page-pattern.md、references/form-standards.md、references/api-data-fetching.md(须与本节及 §5、§6 的 cloneDeep / 禁止 structuredClone 约定一致)script setup + TypeScript。@01s-11comm/type 导入。computed 或 useI18nConfig().withLocale(),不要继续堆静态 ref。$t("xxx.xxx"),不要再二次封装 $t。headerRenderer,不要继续写静态 label。cloneDeep(import { cloneDeep } from "@pureadmin/utils"),禁止 structuredClone(对 Vue reactive/proxy 不安全,弹窗场景易报错)。index.vue 默认遵循以下顺序:
definePagecolumnspureTableBarPropsplusSearchColumnsplusSearchProps页面标题改成 i18n key 后,title 正上方必须保留中文注释,注释内容就是原本的中文标题。
示例:
definePage({
meta: {
// 菜单目录
title: "devTeam.menuManage.catalog.pageTitle",
icon: "mdi:folder",
roles: ["开发团队"],
rank: getRouteRank("devTeam.menuManage.catalog"),
},
});
列表页默认这样引入:
import { useI18nConfig } from "@/composables/use-i18n-config";
import { $t, transformI18n } from "@/plugins/i18n";
const { locale, withLocale, createHeaderRenderer, searchProps } = useI18nConfig();
transformI18n 与动态配置刷新的边界transformI18n 只负责翻译,把 key 解析成当前语言文本。transformI18n($t("..."))。computed(...)、withLocale(...)、函数型 title / footerButtons.label,不要再新建本地 renderI18n helper。useI18n().t(...) 或 i18n.global.t(...)。约束:
useI18nConfig 只负责结构层的动态刷新。$t("key")。createHeaderRenderer 只接收已经翻译好的文本。searchProps 只接收已经翻译好的 searchText、resetText。标准顺序:
import { cloneDeep } from "@pureadmin/utils";
const plusSearchModelRef: FieldValues & Partial<QueryParams> = {
name: "",
status: "",
};
const plusSearchDefaultValues = cloneDeep(plusSearchModelRef);
const plusSearchModel = ref(plusSearchModelRef);
列表数据统一通过 query hook 获取:
const {
pureTableProps,
isFetching,
updateParams,
resetParams,
doFetch,
handlePageSizeChange,
handleCurrentPageChange,
} = useXxxListQuery(plusSearchDefaultValues);
以下对象默认都写成 withLocale:
columnspureTableBarPropsplusSearchColumnstranslatedOptionsplusSearchProps 默认走 searchProps(...)。
PlusSearch 的按钮文本默认再补 plusSearchButtonTexts。
示例:
const columns = withLocale<TableColumnList>(() => [
defaultPureTableIndexColumn,
{
headerRenderer: createHeaderRenderer(transformI18n($t("devTeam.menuManage.catalog.fields.name"))),
prop: "name",
},
{
headerRenderer: createHeaderRenderer(transformI18n($t("common.table.operation"))),
slot: "operation",
},
]);
const { plusSearchButtonTexts } = useI18nConfig();
const plusSearchProps = searchProps(plusSearchDefaultValues);
错误写法:
{
label: transformI18n($t("devTeam.menuManage.catalog.fields.name")),
prop: "name",
}
正确写法:
{
headerRenderer: createHeaderRenderer(transformI18n($t("devTeam.menuManage.catalog.fields.name"))),
prop: "name",
}
涉及 PlusSearch、表格列、第三方表单配置时,页面根节点和 PlusSearch 默认补 :key="locale",保证切语言后整块结构重算:
<section :key="locale" class="index-root">
<PlusSearch
:key="locale"
v-model="plusSearchModel"
:="plusSearchProps"
:columns="plusSearchColumns"
:search-text="plusSearchButtonTexts.searchText"
:reset-text="plusSearchButtonTexts.resetText"
/>
</section>
说明:
searchProps(...) 负责搜索栏结构配置。plusSearchButtonTexts.searchText/resetText 负责 PlusSearch 的按钮文案动态切换。useI18nConfig 的固定 computed,不再在每个页面重复写额外 helper。当前项目里部分 PureTable props 类型仍有噪音。
如果页面本身沿用仓库现状,需要在模板上保留:
<PureTable ... />
不要为了消除这类历史噪音而擅自改掉页面正常工作的现有接口结构。
treeProps 类型现状useListQuery 或 defaultPureTableProps + ListPureTableProps 的页面,不要再添加 <!-- @vue-ignore --> 来忽略 treeProps.checkStrictly。ref<PureTableProps> / computed<PureTableProps>,应先切到统一的 ListPureTableProps,再删除注释;不要只删注释不修类型。treeProps 的默认值统一放在 apps/admin/src/config/constant.ts,类型别名统一放在 apps/admin/types/pure-table.d.ts。form.ts 只负责:
defaultFormProps 类型mode?: Mode不要把表单渲染逻辑写到 form.ts。
标准写法:
const props = defineProps<FormProps>();
const defaultValues = props.defaultValues as FieldValues & XxxFormVO;
const plusFormInstance = useTemplateRef("plusFormRef");
usePlusFormReset(plusFormInstance);
const form = ref(cloneDeep(props.form) as FieldValues & XxxFormVO);
const formComputed = computed(() => form.value);
约束:
cloneDeep(props.form);禁止 structuredClone(props.form)(Vue proxy 下不稳定)。formComputed 暴露给弹窗关闭前比较逻辑。以下对象默认写成 withLocale:
translatedOptionsplusFormColumnsplusFormRules示例:
const translatedStatusOptions = withLocale(() =>
statusOptions.map((option) => ({
...option,
label: transformI18n($t("xxx.form.options.status.enabled")),
})),
);
const plusFormColumns = withLocale<PlusColumn[]>(() => [
{
label: transformI18n($t("xxx.fields.status")),
prop: "status",
valueType: "select",
options: translatedStatusOptions.value,
fieldProps: {
placeholder: transformI18n($t("xxx.placeholders.status")),
},
},
]);
强制规则:
ref({...})。ref 的严重后果是:切语言后表单 label、placeholder、校验信息和下拉选项经常停留在旧语言。表单校验信息也必须跟随语言切换:
const plusFormRules = withLocale<PlusFormRules>(() => ({
status: [
{
required: true,
message: transformI18n($t("xxx.validation.statusRequired")),
trigger: "change",
},
],
}));
弹窗标题与 footer 按钮文案默认使用函数:
addDialog({
title: () => transformI18n($t("devTeam.menuManage.catalog.dialogs.addTitle")),
footerButtons: [
{
label: () => transformI18n($t("common.buttons.cancel")),
type: "info",
},
{
label: () => transformI18n($t("common.buttons.reset")),
type: "warning",
},
{
label: () => transformI18n($t("common.buttons.submit")),
type: "success",
},
],
});
原因:
ref 容易导致弹窗标题、footer 按钮不刷新。默认写法:
async doBeforeClose({ options, index }) {
const formComputed = formInstance.value?.formComputed;
if (formComputed) {
await useDoBeforeClose({ defaultValues, formComputed, index, options });
}
}
$t("key")错误:
const { tLabel } = useI18nConfig();
const title = computed(() => tLabel("devTeam.configManage.center.pageTitle"));
正确:
const title = computed(() => transformI18n($t("devTeam.configManage.center.pageTitle")));
transformI18n($t("..."))computed(...) / withLocale(...) 后,仍直接写 transformI18n($t("..."))renderI18n(...)tLabel、ht、dialogTitleT 这类二次包装 $t 的 helper<ElButton type="primary">
{{ transformI18n($t("common.buttons.add")) }}
</ElButton>
参数化翻译不要发明新的 helper。
需要插值时,直接使用 i18n.global.t($t("key"), params) 或项目当前统一方式。
很多 @01s-11comm/type 导出的 options 仍然带静态中文 label。
页面和表单里必须重新映射 label,不要直接原样渲染。
type="primary"type="warning"type="danger"type="info"不要额外加 icon、link、size,除非页面已有明确既有模式必须保持一致。
修改列表页或表单页后,默认至少做这些检查:
vue-tsc 检查。apps/admin 的 pnpm dev 并用 Chrome MCP 实测。当你接手一个旧页面做 i18n/结构重构时,默认按这个顺序推进:
definePage.meta.title 改成 key,并补中文注释。useI18nConfig,把脚本配置统一收进 computed(...) / withLocale(...)。headerRenderer。withLocale/computed。tLabel、ht、dialogTitleT、renderI18n 这类旧 helper 写法。本技能和以下文档联动:
.claude/skills/code-style/SKILL.md如果两者发生冲突:
code-style 里的强约束。