通过 VITE_AUTO_FILL_TEST 环境变量控制,在 .env.test 中启用, 使测试环境构建后登录框也能自动填充测试账号,方便测试人员使用。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
238 lines
4.7 KiB
Plaintext
238 lines
4.7 KiB
Plaintext
---
|
||
description: 前端特定的开发规范(仅作用于 frontend 目录)
|
||
globs:
|
||
alwaysApply: true
|
||
---
|
||
|
||
# 前端特定规范
|
||
|
||
本规则仅作用于 `frontend/` 目录。
|
||
|
||
## Ant Design Vue 组件使用
|
||
|
||
### 表格组件
|
||
|
||
```vue
|
||
<template>
|
||
<a-table
|
||
:columns="columns"
|
||
:data-source="dataSource"
|
||
:loading="loading"
|
||
:pagination="pagination"
|
||
@change="handleTableChange"
|
||
>
|
||
<template #bodyCell="{ column, record }">
|
||
<template v-if="column.key === 'action'">
|
||
<a-space>
|
||
<a-button type="link" @click="handleEdit(record)">编辑</a-button>
|
||
<a-popconfirm
|
||
title="确定要删除吗?"
|
||
@confirm="handleDelete(record.id)"
|
||
>
|
||
<a-button type="link" danger>删除</a-button>
|
||
</a-popconfirm>
|
||
</a-space>
|
||
</template>
|
||
</template>
|
||
</a-table>
|
||
</template>
|
||
```
|
||
|
||
### 表单组件
|
||
|
||
```vue
|
||
<template>
|
||
<a-form
|
||
:model="formState"
|
||
:rules="rules"
|
||
layout="vertical"
|
||
@finish="onFinish"
|
||
>
|
||
<a-form-item label="用户名" name="username">
|
||
<a-input v-model:value="formState.username" />
|
||
</a-form-item>
|
||
|
||
<a-form-item>
|
||
<a-button type="primary" html-type="submit">提交</a-button>
|
||
</a-form-item>
|
||
</a-form>
|
||
</template>
|
||
```
|
||
|
||
### Modal 弹窗
|
||
|
||
```vue
|
||
<template>
|
||
<a-modal
|
||
v-model:open="visible"
|
||
title="编辑用户"
|
||
@ok="handleOk"
|
||
>
|
||
<a-form :model="formState">
|
||
<!-- 表单内容 -->
|
||
</a-form>
|
||
</a-modal>
|
||
</template>
|
||
```
|
||
|
||
## 消息提示
|
||
|
||
```typescript
|
||
import { message, notification } from 'ant-design-vue';
|
||
|
||
// 成功提示
|
||
message.success('操作成功');
|
||
|
||
// 错误提示
|
||
message.error('操作失败');
|
||
|
||
// 通知
|
||
notification.success({
|
||
message: '成功',
|
||
description: '用户创建成功',
|
||
});
|
||
```
|
||
|
||
## Tailwind CSS 常用类
|
||
|
||
```html
|
||
<!-- 布局 -->
|
||
<div class="flex items-center justify-between">
|
||
<div class="grid grid-cols-3 gap-4">
|
||
<div class="p-4 m-2">
|
||
|
||
<!-- 响应式 -->
|
||
<div class="w-full md:w-1/2 lg:w-1/3">
|
||
|
||
<!-- 文本 -->
|
||
<p class="text-lg font-bold text-gray-800">
|
||
|
||
<!-- 状态 -->
|
||
<button class="hover:bg-blue-600 active:bg-blue-700">
|
||
```
|
||
|
||
## 权限指令
|
||
|
||
使用自定义指令 `v-permission`:
|
||
|
||
```vue
|
||
<template>
|
||
<a-button v-permission="'user:create'" type="primary">
|
||
创建用户
|
||
</a-button>
|
||
|
||
<a-button v-permission="['user:update', 'user:delete']" type="link">
|
||
编辑
|
||
</a-button>
|
||
</template>
|
||
```
|
||
|
||
## 租户路由
|
||
|
||
所有路由必须包含租户编码:
|
||
|
||
```typescript
|
||
// ✅ 正确
|
||
router.push(`/${tenantCode}/users`);
|
||
|
||
// ❌ 错误
|
||
router.push('/users');
|
||
```
|
||
|
||
获取租户编码:
|
||
|
||
```typescript
|
||
import { useRoute } from 'vue-router';
|
||
|
||
const route = useRoute();
|
||
const tenantCode = route.params.tenantCode as string;
|
||
```
|
||
|
||
## 常用组合式函数
|
||
|
||
### 使用权限检查
|
||
|
||
```typescript
|
||
import { useAuthStore } from '@/stores/auth';
|
||
|
||
const authStore = useAuthStore();
|
||
|
||
// 检查权限
|
||
const hasPermission = authStore.hasPermission('user:create');
|
||
|
||
// 检查多个权限(任一)
|
||
const hasAnyPermission = authStore.hasAnyPermission(['user:create', 'user:update']);
|
||
```
|
||
|
||
### 表格分页
|
||
|
||
```typescript
|
||
import { ref, reactive } from 'vue';
|
||
|
||
const loading = ref(false);
|
||
const dataSource = ref([]);
|
||
const pagination = reactive({
|
||
current: 1,
|
||
pageSize: 10,
|
||
total: 0,
|
||
});
|
||
|
||
const handleTableChange = (pag: any) => {
|
||
pagination.current = pag.current;
|
||
pagination.pageSize = pag.pageSize;
|
||
fetchData();
|
||
};
|
||
|
||
const fetchData = async () => {
|
||
loading.value = true;
|
||
try {
|
||
const { data, total } = await getUsers({
|
||
skip: (pagination.current - 1) * pagination.pageSize,
|
||
take: pagination.pageSize,
|
||
});
|
||
dataSource.value = data;
|
||
pagination.total = total;
|
||
} finally {
|
||
loading.value = false;
|
||
}
|
||
};
|
||
```
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
src/
|
||
├── api/ # API 接口
|
||
├── assets/ # 静态资源
|
||
├── components/ # 公共组件
|
||
├── composables/ # 组合式函数
|
||
├── directives/ # 自定义指令
|
||
├── layouts/ # 布局组件
|
||
├── router/ # 路由配置
|
||
├── stores/ # Pinia 状态
|
||
├── styles/ # 全局样式
|
||
├── types/ # TypeScript 类型
|
||
├── utils/ # 工具函数
|
||
└── views/ # 页面组件
|
||
├── auth/ # 认证相关
|
||
├── users/ # 用户管理
|
||
├── school/ # 学校管理
|
||
└── contests/ # 竞赛管理
|
||
```
|
||
|
||
## 常用脚本
|
||
|
||
```bash
|
||
# 开发
|
||
pnpm dev
|
||
|
||
# 构建
|
||
pnpm build
|
||
|
||
# 预览
|
||
pnpm preview
|
||
|
||
# 代码检查
|
||
pnpm lint
|
||
```
|