AI 驱动-前端源码生成测试

提示词:

复制代码
你是一名资深前端工程师,需按照以下规范生成代码:
1. 技术栈:Vue3 + TypeScript + Setup 语法 + Tailwind CSS;
2. 代码规范:符合 ESLint 规则,包含完整注释,支持响应式;
3. 功能要求:实现 登录的 表单 组件;
4. 输出格式:先说明组件逻辑,再给出完整代码(模板+脚本+样式)
5. 我需要打包成标准的项目结构

登录表单组件标准化项目结构(Vue3 + TS + Vite + Tailwind CSS)

以下是符合工业级标准的 Vue3 项目结构,包含登录组件、完整的工程配置、依赖管理等,可直接克隆/搭建并运行。

一、整体项目结构

复制代码
vue3-login-template/
├── public/                  # 静态资源(不会被打包处理)
│   └── favicon.ico          # 网站图标
├── src/                     # 源码目录
│   ├── assets/              # 静态资源(会被打包处理)
│   │   ├── styles/          # 全局样式
│   │   │   ├── main.css     # 全局基础样式
│   │   │   └── tailwind.css # Tailwind 入口样式
│   │   └── images/          # 图片资源(如登录页背景图)
│   ├── components/          # 公共组件
│   │   └── LoginForm/       # 登录表单组件(独立目录便于维护)
│   │       ├── index.vue    # 登录组件核心代码
│   │       └── type.ts      # 组件类型定义(拆分更清晰)
│   ├── views/               # 页面视图
│   │   └── Login/           # 登录页面
│   │       └── index.vue    # 登录页面(集成LoginForm组件)
│   ├── router/              # 路由配置
│   │   └── index.ts         # 路由定义
│   ├── utils/               # 工具函数
│   │   ├── validate.ts      # 校验工具(抽离通用校验逻辑)
│   │   └── request.ts       # 请求封装(Axios)
│   ├── App.vue              # 根组件
│   ├── main.ts              # 入口文件
│   └── env.d.ts             # TS类型声明(Vite自动生成)
├── .eslintrc.cjs            # ESLint配置
├── .prettierrc.cjs          # Prettier配置
├── index.html               # HTML入口
├── package.json             # 依赖配置
├── tsconfig.json            # TS配置
├── vite.config.ts           # Vite配置
└── tailwind.config.js       # Tailwind配置

二、核心文件代码实现

1. 项目初始化依赖(package.json)

json 复制代码
{
  "name": "vue3-login-template",
  "private": true,
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc && vite build",
    "preview": "vite preview",
    "lint": "eslint . --ext .vue,.js,.ts,.jsx,.tsx --fix",
    "format": "prettier --write src/"
  },
  "dependencies": {
    "axios": "^1.6.8",
    "vue": "^3.4.21",
    "vue-router": "^4.3.0"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^5.0.4",
    "@vue/eslint-config-prettier": "^9.0.0",
    "@vue/eslint-config-typescript": "^12.0.0",
    "autoprefixer": "^10.4.19",
    "eslint": "^8.57.0",
    "eslint-plugin-vue": "^9.23.0",
    "postcss": "^8.4.38",
    "prettier": "^3.2.5",
    "tailwindcss": "^3.4.3",
    "typescript": "^5.2.2",
    "vite": "^5.2.8",
    "vue-tsc": "^2.0.11"
  }
}

2. 入口文件(src/main.ts)

typescript 复制代码
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
// 全局样式
import './assets/styles/main.css'
import './assets/styles/tailwind.css'

// 创建Vue实例
const app = createApp(App)

// 挂载路由
app.use(router)

// 挂载到DOM
app.mount('#app')

3. 根组件(src/App.vue)

vue 复制代码
<template>
  <router-view />
</template>

<script setup lang="ts">
// 根组件仅作为路由出口
</script>

<style scoped>
#app {
  @apply font-sans antialiased text-gray-900 bg-gray-50 min-h-screen;
}
</style>

4. 路由配置(src/router/index.ts)

typescript 复制代码
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
import Login from '../views/Login/index.vue'

// 路由规则
const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    redirect: '/login' // 默认跳转到登录页
  },
  {
    path: '/login',
    name: 'Login',
    component: Login,
    meta: {
      title: '用户登录' // 页面标题
    }
  }
]

// 创建路由实例
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes
})

// 路由守卫:设置页面标题
router.afterEach((to) => {
  if (to.meta.title) {
    document.title = to.meta.title as string
  }
})

export default router

5. Tailwind 配置

(1)tailwind.config.js
javascript 复制代码
/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{vue,js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {
      colors: {
        primary: '#3b82f6', // 自定义主题色(蓝色)
      },
    },
  },
  plugins: [],
}
(2)src/assets/styles/tailwind.css
css 复制代码
@tailwind base;
@tailwind components;
@tailwind utilities;

/* Tailwind 基础样式扩展 */
@layer base {
  body {
    @apply bg-gray-50;
  }
}

/* 自定义组件样式 */
@layer components {
  .form-input {
    @apply w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent;
  }
  .btn-primary {
    @apply w-full py-2 px-4 bg-primary text-white font-medium rounded-md hover:bg-primary/90 focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 disabled:opacity-70 disabled:cursor-not-allowed;
  }
}
(3)src/assets/styles/main.css
css 复制代码
/* 全局重置样式 */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

/* 滚动条优化 */
::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}
::-webkit-scrollbar-thumb {
  background-color: #d1d5db;
  border-radius: 3px;
}
::-webkit-scrollbar-track {
  background-color: #f9fafb;
}

6. 工具函数

(1)src/utils/validate.ts(通用校验工具)
typescript 复制代码
/**
 * 校验手机号
 * @param phone 手机号
 * @returns 是否有效
 */
export const isPhoneValid = (phone: string): boolean => {
  const reg = /^1[3-9]\d{9}$/
  return reg.test(phone)
}

/**
 * 校验邮箱
 * @param email 邮箱
 * @returns 是否有效
 */
export const isEmailValid = (email: string): boolean => {
  const reg = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
  return reg.test(reg)
}

/**
 * 校验密码(6-16位,字母+数字组合)
 * @param password 密码
 * @returns 是否有效
 */
export const isPasswordValid = (password: string): boolean => {
  const reg = /^(?=.*[a-zA-Z])(?=.*\d).{6,16}$/
  return reg.test(password)
}
(2)src/utils/request.ts(Axios 请求封装)
typescript 复制代码
import axios from 'axios'

// 创建Axios实例
const request = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL, // 从环境变量读取接口前缀
  timeout: 10000, // 超时时间
  headers: {
    'Content-Type': 'application/json;charset=utf-8'
  }
})

// 请求拦截器:添加token
request.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem('token')
    if (token) {
      config.headers.Authorization = `Bearer ${token}`
    }
    return config
  },
  (error) => {
    return Promise.reject(error)
  }
)

// 响应拦截器:统一处理错误
request.interceptors.response.use(
  (response) => {
    const res = response.data
    // 假设接口返回code=200为成功
    if (res.code !== 200) {
      ElMessage.error(res.message || '请求失败') // 需安装element-plus
      return Promise.reject(res)
    }
    return res
  },
  (error) => {
    ElMessage.error(error.message || '网络异常')
    return Promise.reject(error)
  }
)

export default request

7. 登录组件拆分

(1)src/components/LoginForm/type.ts(类型定义)
typescript 复制代码
/**
 * 登录表单数据类型
 */
export interface LoginForm {
  account: string // 账号(手机号/邮箱)
  password: string // 密码
  remember: boolean // 是否记住密码
}

/**
 * 表单错误信息类型
 */
export interface FormErrors {
  account?: string
  password?: string
}
(2)src/components/LoginForm/index.vue(组件核心)
vue 复制代码
<template>
  <!-- 登录表单容器 -->
  <div class="login-form-container w-full max-w-md mx-auto p-6 bg-white rounded-lg shadow-md">
    <h2 class="text-2xl font-bold text-center text-gray-800 mb-6">用户登录</h2>
    
    <!-- 登录表单 -->
    <form @submit.prevent="handleSubmit" class="space-y-4">
      <!-- 账号输入框 -->
      <div class="form-item">
        <label for="account" class="block text-sm font-medium text-gray-700 mb-1">
          账号(手机号/邮箱)
        </label>
        <input
          id="account"
          v-model="form.account"
          type="text"
          :class="[
            'form-input',
            formErrors.account ? 'border-red-500' : 'border-gray-300'
          ]"
          placeholder="请输入手机号或邮箱"
          @blur="validateField('account')"
        />
        <p v-if="formErrors.account" class="mt-1 text-sm text-red-500">{{ formErrors.account }}</p>
      </div>

      <!-- 密码输入框 -->
      <div class="form-item">
        <label for="password" class="block text-sm font-medium text-gray-700 mb-1">
          密码
        </label>
        <input
          id="password"
          v-model="form.password"
          type="password"
          :class="[
            'form-input',
            formErrors.password ? 'border-red-500' : 'border-gray-300'
          ]"
          placeholder="请输入密码(6-16位)"
          @blur="validateField('password')"
        />
        <p v-if="formErrors.password" class="mt-1 text-sm text-red-500">{{ formErrors.password }}</p>
      </div>

      <!-- 记住密码 & 忘记密码 -->
      <div class="flex items-center justify-between">
        <label class="flex items-center">
          <input
            v-model="form.remember"
            type="checkbox"
            class="w-4 h-4 text-primary focus:ring-primary border-gray-300 rounded"
          />
          <span class="ml-2 text-sm text-gray-700">记住密码</span>
        </label>
        <a href="#" class="text-sm text-primary hover:text-primary/80">忘记密码?</a>
      </div>

      <!-- 提交按钮 -->
      <button
        type="submit"
        :disabled="isSubmitting"
        class="btn-primary"
      >
        <span v-if="!isSubmitting">登录</span>
        <span v-else class="flex items-center justify-center">
          <svg class="animate-spin -ml-1 mr-2 h-4 w-4 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
            <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
            <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
          </svg>
          登录中...
        </span>
      </button>
    </form>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue'
import type { LoginForm, FormErrors } from './type'
import { isPhoneValid, isEmailValid, isPasswordValid } from '../../utils/validate'

/**
 * 响应式表单数据
 */
const form = reactive<LoginForm>({
  account: '',
  password: '',
  remember: false
})

/**
 * 表单错误信息
 */
const formErrors = reactive<FormErrors>({})

/**
 * 提交状态标识
 */
const isSubmitting = ref(false)

/**
 * 自定义提交事件 - 向父组件传递登录参数
 */
const emit = defineEmits<{
  (e: 'submit', formData: LoginForm): void;
}>();

/**
 * 校验单个字段
 * @param field 要校验的字段名
 */
const validateField = (field: keyof LoginForm) => {
  switch (field) {
    case 'account':
      if (!form.account) {
        formErrors.account = '账号不能为空'
      } else if (!isPhoneValid(form.account) && !isEmailValid(form.account)) {
        formErrors.account = '请输入正确的手机号或邮箱'
      } else {
        delete formErrors.account
      }
      break
    case 'password':
      if (!form.password) {
        formErrors.password = '密码不能为空'
      } else if (!isPasswordValid(form.password)) {
        formErrors.password = '密码需6-16位,且包含字母和数字'
      } else {
        delete formErrors.password
      }
      break
    default:
      break
  }
}

/**
 * 全量校验表单
 * @returns 是否校验通过
 */
const validateForm = (): boolean => {
  // 校验所有字段
  validateField('account')
  validateField('password')
  // 判断是否有错误信息
  return Object.keys(formErrors).length === 0
}

/**
 * 处理表单提交
 */
const handleSubmit = async () => {
  // 全量校验
  if (!validateForm()) return

  // 设置提交状态
  isSubmitting.value = true

  try {
    // 向外触发提交事件,父组件可监听该事件处理登录逻辑
    emit('submit', { ...form })
  } catch (error) {
    console.error('登录提交失败:', error)
  } finally {
    // 重置提交状态
    isSubmitting.value = false
  }
}
</script>

<style scoped>
/* 基础样式补充(Tailwind 未覆盖的细节) */
.login-form-container {
  @apply mt-10;
}

.form-item {
  @apply transition-all duration-200;
}

/* 适配移动端小屏 */
@media (max-width: 480px) {
  .login-form-container {
    @apply p-4 mx-2;
  }
}
</style>

8. 登录页面(src/views/Login/index.vue)

vue 复制代码
<template>
  <div class="login-page min-h-screen flex items-center justify-center bg-gray-100">
    <!-- 登录表单组件 -->
    <LoginForm @submit="handleLogin" />
  </div>
</template>

<script setup lang="ts">
import LoginForm from '../../components/LoginForm/index.vue'
import request from '../../utils/request'

/**
 * 处理登录逻辑
 * @param formData 登录表单数据
 */
const handleLogin = async (formData: any) => {
  try {
    console.log('登录参数:', formData)
    // 对接登录接口
    // const res = await request.post('/api/login', formData)
    // if (res.success) {
    //   // 记住密码逻辑
    //   if (formData.remember) {
    //     localStorage.setItem('token', res.data.token)
    //   } else {
    //     sessionStorage.setItem('token', res.data.token)
    //   }
    //   // 跳转首页(需配置首页路由)
    //   // router.push('/home')
    //   ElMessage.success('登录成功')
    // }
  } catch (error) {
    console.error('登录失败:', error)
  }
}
</script>

<style scoped>
.login-page {
  @apply px-4;
}
</style>

9. 配置文件

(1)vite.config.ts
typescript 复制代码
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  resolve: {
    // 路径别名
    alias: {
      '@': resolve(__dirname, 'src')
    }
  },
  server: {
    port: 3000, // 开发服务器端口
    open: true, // 启动后自动打开浏览器
    cors: true // 允许跨域
  },
  build: {
    outDir: 'dist', // 打包输出目录
    assetsDir: 'assets', // 静态资源目录
    minify: 'terser', // 压缩方式
    terserOptions: {
      // 移除console和debugger
      compress: {
        drop_console: true,
        drop_debugger: true
      }
    }
  }
})
(2)tsconfig.json
json 复制代码
{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "skipLibCheck": true,

    /* 路径别名 */
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    },

    /* 模块解析选项 */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve",

    /* 类型检查选项 */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
  "references": [{ "path": "./tsconfig.node.json" }]
}
(3).eslintrc.cjs
javascript 复制代码
module.exports = {
  root: true,
  env: {
    browser: true,
    es2021: true,
    node: true
  },
  extends: [
    'plugin:vue/vue3-essential',
    'eslint:recommended',
    '@vue/eslint-config-typescript',
    '@vue/eslint-config-prettier/skip-formatting'
  ],
  parserOptions: {
    ecmaVersion: 'latest',
    parser: '@typescript-eslint/parser'
  },
  plugins: ['vue', '@typescript-eslint'],
  rules: {
    'vue/multi-word-component-names': 'off', // 关闭组件名多单词校验(LoginForm已符合)
    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
  }
}

三、项目使用步骤

1. 初始化项目

bash 复制代码
# 创建项目目录
mkdir vue3-login-template && cd vue3-login-template

# 初始化package.json(按提示回车)
npm init -y

# 安装依赖
npm install vue vue-router axios
npm install -D vite @vitejs/plugin-vue typescript vue-tsc @vue/eslint-config-typescript @vue/eslint-config-prettier eslint prettier tailwindcss postcss autoprefixer

2. 创建上述目录和文件

按上面的项目结构,创建所有文件并写入对应代码。

3. 初始化Tailwind CSS

bash 复制代码
npx tailwindcss init -p

(生成的tailwind.config.js已在上面提供,可直接替换)

4. 运行项目

bash 复制代码
# 开发环境
npm run dev

# 打包构建
npm run build

# 预览打包结果
npm run preview

四、项目特性说明

  1. 标准化结构:遵循Vue3官方推荐的项目结构,便于团队协作和后期扩展;
  2. 类型安全:全流程TS类型覆盖,减少运行时错误;
  3. 工程化配置:集成ESLint+Prettier代码规范、Tailwind CSS样式方案;
  4. 可扩展性
    • 路由可直接添加首页、注册页等;
    • 工具函数抽离通用逻辑,便于复用;
    • 请求封装支持拦截器、环境变量,可直接对接后端接口;
  5. 生产级优化:打包时移除console/debugger,压缩代码,静态资源分类;
  6. 响应式适配:适配移动端/PC端,交互体验友好。

五、扩展建议

  1. 添加UI组件库:如Element Plus,替换手动写的按钮/提示框;
  2. 环境变量配置 :创建.env.development/.env.production区分开发/生产环境接口地址;
  3. 状态管理:如需全局状态(如用户信息),可集成Pinia;
  4. 单元测试:添加Vitest+@vue/test-utils编写组件测试用例;
  5. 部署配置:添加nginx.conf配置文件,适配生产环境部署。
相关推荐
飞Link2 小时前
GDN:深度学习时代的图偏差网络异常检测全解析
网络·人工智能·深度学习
喏喏心2 小时前
深度强化学习:价值迭代与Bellman方程实践
人工智能·python·学习·机器学习
阿杰学AI2 小时前
AI核心知识48——大语言模型之Synthetic Data(简洁且通俗易懂版)
人工智能·ai·语言模型·aigc·合成数据·synthetic data·模型崩溃
陈天伟教授2 小时前
人工智能应用-机器视觉:人脸识别(6)深度神经网络方法
人工智能·神经网络·dnn
千匠网络2 小时前
S2B供应链平台:优化资源配置,推动产业升级
大数据·人工智能·产品运营·供应链·s2b
JERRY. LIU3 小时前
大脑各组织类型及其电磁特性
人工智能·神经网络·计算机视觉
l木本I3 小时前
uv 技术详解
人工智能·python·深度学习·机器学习·uv
通义灵码3 小时前
在 IDEA 里用 AI 写完两个 Java 全栈功能,花了 7 分钟
人工智能·ai编程·qoder
AI营销快线3 小时前
AI如何每日自动生成大量高质量营销素材?
大数据·人工智能