1、 标准目录结构
PC端项目架构
src/
├── api/
│ ├── index.js
│ ├── user.js
│ ├── payment.js
│ └── modules/
├── assets/
│ ├── css/
│ ├── images/
│ └── fonts/
├── components/
│ ├── common/
│ ├── tables/
│ └── forms/
├── config/
│ ├── index.js
│ └── url.js
├── directive/
├── filters/
├── libs/
│ ├── axios.js
│ ├── util.js
│ └── httpRequest.js
├── mock/
├── plugins/
├── router/
│ ├── index.js
│ ├── hooks.js
│ └── modules/
├── store/
│ ├── index.js
│ └── modules/
├── utils/
├── views/
│ ├── Layout.vue
│ ├── Home.vue
│ └── modules/
├── App.vue
└── main.js
移动端项目架构
src/
├── api/
├── assets/
├── components/
├── config/
├── router/
│ ├── index.js
│ ├── AccessPage.js
│ └── modules/
├── store/
├── utils/
│ ├── util.js
│ ├── storage.js
│ └── miniProgramJs.js
├── views/
├── App.vue
└── main.js
2. 状态管理架构
Vuex模式 (Vue 2)
import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user'
import app from './modules/app'
Vue.use(Vuex)
export default new Vuex.Store({
state: {},
mutations: {},
actions: {},
modules: {
user,
app
}
})
Pinia模式 (Vue 3)
import type { App } from 'vue'
import { createPinia } from 'pinia'
const store = createPinia()
export const setupStore = (app: App<Element>) => {
app.use(store)
}
export { store }
3. API架构模式
统一API管理
import { httpRequest } from '@/libs/httpRequest'
import { API_URL } from '@/config/url'
export const getUserInfo = (params) => {
return httpRequest({
url: API_URL.USER_INFO,
method: 'get',
params
})
}
export const getOrderList = (data) => {
return httpRequest({
url: API_URL.ORDER_LIST,
method: 'post',
data
})
}
2、项目技术栈
- 前端框架: Vue 2.5.10 + Vue Router 3.0.1 + Vuex 3.0.1
- UI组件库:
- Element UI 2.15.14 (辅助组件)
- @longfor/maia-ui 1.3.15 (龙湖内部UI库)
- @longfor/cm-components 0.2.15 (龙湖通用组件)
- 构建工具: Vue CLI 3.x + Webpack 4.x
- 样式预处理: Less 2.7.3
- 微前端: 乾坤(qiankun)架构
- 其他核心依赖: Axios、ECharts、Moment.js等
移动端项目特征
- postcss-pxtorem适配
- 支持触摸事件
- 移动端调试工具
- 性能优化配置
PC端项目特征
- Element UI组件库
- 复杂表格和表单处理
- 权限管理
- 数据可视化需求
AI对话基本原则
1. 技术栈一致性
- 所有代码建议必须基于Vue 2.x语法
- 优先使用项目已有的UI组件库(iView > Element UI > Maia UI)
- 遵循项目现有的目录结构和命名规范
- 使用Less作为样式预处理器
2. 代码风格规范
- 遵循ESLint Standard配置
- 使用2空格缩进
- 组件名采用PascalCase命名
- 文件名采用kebab-case命名
- 方法名采用camelCase命名
3. 组件开发规范
<template>
<div class="component-name">
</div>
</template>
<script>
export default {
name: 'ComponentName',
props: {
},
data () {
return {
}
},
computed: {
},
methods: {
},
mounted () {
}
}
</script>
<style lang="less" scoped>
.component-name {
// 样式定义
}
</style>
特殊场景处理
1. 微前端相关
- 涉及微前端的问题,需要考虑qiankun生命周期
- 注意基座应用的通信机制
- 考虑路由base配置的影响
2. 权限管理
- 基于菜单权限的页面访问控制
- 使用store中的authorization模块
- 考虑按钮级别的权限控制
3. 第三方组件集成
- 优先使用项目已集成的组件库
- 新增第三方依赖需要考虑项目兼容性
- 注意龙湖内部组件的使用规范
代码质量要求
1. 性能优化
- 合理使用Vue的响应式特性
- 避免不必要的重渲染
- 大列表使用虚拟滚动
2. 错误处理
- 统一的错误处理机制
- 用户友好的错误提示
- 完善的日志记录
3. 可维护性
禁止事项
- 不要建议使用Vue 3语法 - 项目基于Vue 2.x
- 不要推荐未集成的UI库 - 优先使用已有组件库
- 不要忽略微前端架构 - 考虑qiankun环境的特殊性
- 不要违反ESLint规范 - 遵循项目代码规范
- 不要建议大幅重构 - 保持项目架构稳定性
2、AI对话接口实现规范
1. 接口URL定义规范
常量定义方式
export const GET_USER_LIST = '/api/user/list'
export const CREATE_USER = '/api/user/create'
export const UPDATE_USER = '/api/user/update'
export const DELETE_USER = '/api/user/delete'
export const GET_ORDER_LIST = '/api/order/list'
命名规范
- 使用大写字母和下划线
- 动词在前:
GET_, CREATE_, UPDATE_, DELETE_
- 业务对象在后:
USER_LIST, ORDER_DETAIL
- 按业务模块分组,添加注释说明
2. 接口封装规范
基础接口封装模式
import axios from '@/libs/axios'
export const getUserList = (data) => {
return axios.request({
url: '/api/user/list',
data,
method: 'post'
})
}
export const getUserDetail = (params) => {
return axios.request({
url: '/api/user/detail',
params,
method: 'get'
})
}
export const createUser = (data) => {
return axios.request({
url: '/api/user/create',
data,
method: 'post',
loading: true,
loadingText: '创建中...'
})
}
多服务类型支持
export const getVasOrderList = (data) => {
return axios.request({
url: '/web/serviceOrder/getCouponOrderList',
data,
method: 'post',
type: 'vas'
})
}
export const getPaymentOrderList = (data) => {
return axios.request({
url: '/web/manage/order/searchReconciliationOrder',
data,
method: 'post',
type: 'payment'
})
}
3. HTTP请求配置规范
服务类型配置
const serviceTypeConfig = {
'todo': {
baseURL: todoBaseURL,
apiKey: process.env.VUE_APP_GAIA_KEY_TODO
},
'vas': {
baseURL: vasBaseURL,
apiKey: process.env.VUE_APP_GAIA_KEY_VAS
},
'payment': {
baseURL: payBaseURL,
apiKey: process.env.VUE_APP_GAIA_KEY_PAY,
headers: { 'menuPath': location.pathname }
},
'opo': {
baseURL: opoBaseURL,
apiKey: process.env.VUE_APP_GAIA_KEY_OPO
}
}
请求拦截器配置
instance.interceptors.request.use(config => {
config.headers['dynamicAppCode'] = 'YYZXPC'
if (config.type && serviceTypeConfig[config.type]) {
const serviceConfig = serviceTypeConfig[config.type]
config.baseURL = serviceConfig.baseURL
config.headers['X-Gaia-Api-Key'] = serviceConfig.apiKey
if (serviceConfig.headers) {
Object.assign(config.headers, serviceConfig.headers)
}
}
config.headers['CASTGC'] = Cookies.get('account') || Cookies.get('CASTGC')
config.withCredentials = true
if (config.loading) {
loadingInstance = Loading.service({
background: 'rgba(0, 0, 0, .5)',
text: config.loadingText || '加载中...'
})
}
return config
})
响应拦截器配置
instance.interceptors.response.use(
res => {
loadingInstance && loadingInstance.close()
let { code, resultCode } = res.data
if ((code && +code === 10002) || (resultCode && +resultCode === 10002)) {
localStorage.clear()
goToLoginPage()
return Promise.reject(new Error('登录过期'))
}
return res.data
},
error => {
loadingInstance && loadingInstance.close()
Message.error('服务内部错误')
return Promise.reject(error)
}
)
统一错误处理
async handleGetOrderList() {
try {
const res = await getOrderList(this.searchParams)
if (res.code === 200) {
this.orderList = res.data.list
this.total = res.data.total
} else {
this.$Message.error(res.message || '获取数据失败')
}
} catch (error) {
console.error('获取订单列表失败:', error)
this.$Message.error('网络错误,请稍后重试')
}
}
业务状态码处理
const handleApiResponse = (res, successCallback, errorCallback) => {
if (res.code === 200 || res.resultCode === 200) {
successCallback && successCallback(res.data)
} else if (res.code === 10002 || res.resultCode === 10002) {
goToLoginPage()
} else {
const errorMsg = res.message || res.resultMessage || '操作失败'
errorCallback ? errorCallback(errorMsg) : Message.error(errorMsg)
}
}
4、AI页面样式规范
1. 基础样式规范
1.1 CSS Reset 和 Normalize
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, "Microsoft Yahei", "Helvetica Neue", Helvetica, sans-serif;
color: #333;
font-size: 12px;
line-height: 1.5;
-webkit-text-size-adjust: none;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
.clearfix::after {
content: "";
height: 0;
line-height: 0;
display: block;
clear: both;
visibility: hidden;
}
1.2 滚动条样式统一
::-webkit-scrollbar {
width: 5px;
height: 10px;
}
::-webkit-scrollbar-track-piece {
background-color: rgba(0, 0, 0, 0.2);
border-radius: 6px;
}
::-webkit-scrollbar-thumb:vertical {
height: 5px;
background-color: rgba(125, 125, 125, 0.7);
border-radius: 6px;
}
2. 颜色规范
2.1 主色调定义
$longfor-blue: #003894;
$color-primary: #007AF5;
$color-success: #67C23A;
$color-warning: #E6A23C;
$color-danger: #F56C6C;
$color-info: #909399;
$color-text-primary: #303133;
$color-text-regular: #606266;
$color-text-secondary: #909399;
$color-text-placeholder: #C0C4CC;
$border-color-base: #DCDFE6;
$border-color-light: #E4E7ED;
$border-color-lighter: #EBEEF5;
$border-color-extra-light: #F2F6FC;
$background-color-base: #F5F7FA;
$background-color-light: #FAFAFA;
$background-color-white: #FFFFFF;
2.2 项目特定颜色
$menu-dark-title: #001529;
$menu-dark-active-bg: #000c17;
$layout-sider-background: #001529;
$namespace: 'optm';
$optm-main-bg: #f4f7fc;
$optm-card-bg: #ffffff;
$mobile-primary: #007AF5;
$mobile-background: #F5F5F5;
3. 布局规范
3.1 PC端布局模式
标准后台布局
<template>
<div class="admin-layout">
<!-- 侧边栏 -->
<aside class="sidebar" :class="{ collapsed: isCollapsed }">
<div class="logo-container">
<img src="@/assets/images/logo.png" alt="Logo">
</div>
<nav class="nav-menu">
<!-- 菜单内容 -->
</nav>
</aside>
<!-- 主内容区 -->
<main class="main-container">
<!-- 顶部导航 -->
<header class="header-bar">
<div class="header-left">
<button class="collapse-btn" @click="toggleSidebar">
<i class="icon-menu"></i>
</button>
</div>
<div class="header-right">
<!-- 用户信息、通知等 -->
</div>
</header>
<!-- 内容区域 -->
<section class="content-wrapper">
<router-view />
</section>
</main>
</div>
</template>
<style lang="less" scoped>
.admin-layout {
display: flex;
height: 100vh;
.sidebar {
width: 256px;
background: #001529;
transition: width 0.3s;
&.collapsed {
width: 64px;
}
.logo-container {
height: 64px;
padding: 10px;
text-align: center;
img {
height: 44px;
width: auto;
}
}
}
.main-container {
flex: 1;
display: flex;
flex-direction: column;
.header-bar {
height: 64px;
background: #fff;
border-bottom: 1px solid #f0f0f0;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
}
.content-wrapper {
flex: 1;
padding: 18px;
background: #f5f7fa;
overflow: auto;
}
}
}
</style>
页面容器规范
<template>
<div class="page-container">
<!-- 页面标题区 -->
<div class="page-header" v-if="showHeader">
<h1 class="page-title">{{ pageTitle }}</h1>
<div class="page-actions">
<slot name="actions"></slot>
</div>
</div>
<!-- 搜索区域 -->
<div class="search-container" v-if="showSearch">
<el-form :model="searchForm" inline class="search-form">
<slot name="search"></slot>
<el-form-item>
<el-button type="primary" @click="handleSearch">
<i class="el-icon-search"></i>
搜索
</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
</el-form>
</div>
<!-- 主要内容区 -->
<div class="content-container">
<slot></slot>
</div>
</div>
</template>
<style lang="less" scoped>
.page-container {
background: #fff;
border-radius: 4px;
padding: 16px;
.page-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
padding-bottom: 16px;
border-bottom: 1px solid #f0f0f0;
.page-title {
font-size: 18px;
font-weight: 500;
color: #303133;
margin: 0;
}
}
.search-container {
background: #fafafa;
padding: 16px;
border-radius: 4px;
margin-bottom: 16px;
.search-form {
.el-form-item {
margin-bottom: 0;
margin-right: 16px;
}
}
}
.content-container {
min-height: 400px;
}
}
</style>
3.2 移动端布局模式
H5页面布局
<template>
<div class="mobile-layout">
<!-- 顶部导航栏 -->
<header class="mobile-header" v-if="showHeader">
<div class="header-left">
<i class="icon-back" @click="goBack" v-if="showBack"></i>
</div>
<div class="header-center">
<h1 class="header-title">{{ title }}</h1>
</div>
<div class="header-right">
<slot name="header-right"></slot>
</div>
</header>
<!-- 主要内容 -->
<main class="mobile-content" :class="{ 'has-header': showHeader, 'has-footer': showFooter }">
<slot></slot>
</main>
<!-- 底部导航 -->
<footer class="mobile-footer" v-if="showFooter">
<slot name="footer"></slot>
</footer>
</div>
</template>
<style lang="less" scoped>
.mobile-layout {
height: 100vh;
display: flex;
flex-direction: column;
.mobile-header {
height: 44px;
background: #fff;
border-bottom: 1px solid #f0f0f0;
display: flex;
align-items: center;
padding: 0 16px;
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1000;
.header-left,
.header-right {
width: 60px;
}
.header-center {
flex: 1;
text-align: center;
.header-title {
font-size: 18px;
font-weight: 500;
color: #333;
margin: 0;
}
}
}
.mobile-content {
flex: 1;
overflow: auto;
-webkit-overflow-scrolling: touch;
&.has-header {
padding-top: 44px;
}
&.has-footer {
padding-bottom: 50px;
}
}
.mobile-footer {
height: 50px;
background: #fff;
border-top: 1px solid #f0f0f0;
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 1000;
}
}
</style>
4. 组件样式规范
4.1 表格组件样式
Element UI 表格规范
<template>
<div class="table-container">
<!-- 表格工具栏 -->
<div class="table-toolbar" v-if="showToolbar">
<div class="toolbar-left">
<el-button type="primary" @click="handleAdd" v-if="showAdd">
<i class="el-icon-plus"></i>
新增
</el-button>
<el-button type="danger" @click="handleBatchDelete" v-if="showBatchDelete">
<i class="el-icon-delete"></i>
批量删除
</el-button>
</div>
<div class="toolbar-right">
<el-button circle @click="handleRefresh">
<i class="el-icon-refresh"></i>
</el-button>
</div>
</div>
<!-- 数据表格 -->
<el-table
:data="tableData"
:loading="loading"
stripe
border
class="data-table"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" v-if="showSelection"></el-table-column>
<el-table-column type="index" label="序号" width="60" v-if="showIndex"></el-table-column>
<slot></slot>
<el-table-column label="操作" width="200" fixed="right" v-if="showActions">
<template #default="{ row }">
<el-button type="text" @click="handleEdit(row)">编辑</el-button>
<el-button type="text" @click="handleView(row)">查看</el-button>
<el-button type="text" class="danger-text" @click="handleDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<div class="pagination-container" v-if="showPagination">
<el-pagination
:current-page="pagination.current"
:page-size="pagination.size"
:total="pagination.total"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</div>
</template>
<style lang="less" scoped>
.table-container {
.table-toolbar {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
.toolbar-left {
.el-button + .el-button {
margin-left: 8px;
}
}
}
.data-table {
.danger-text {
color: #f56c6c;
&:hover {
color: #f78989;
}
}
}
.pagination-container {
margin-top: 16px;
text-align: right;
}
}
</style>
4.2 表单组件样式
标准表单布局
<template>
<div class="form-container">
<el-form
:model="formData"
:rules="formRules"
ref="formRef"
label-width="120px"
class="standard-form"
>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="用户名" prop="username">
<el-input v-model="formData.username" placeholder="请输入用户名" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="邮箱" prop="email">
<el-input v-model="formData.email" placeholder="请输入邮箱" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="24">
<el-form-item label="描述" prop="description">
<el-input
type="textarea"
v-model="formData.description"
:rows="4"
placeholder="请输入描述"
/>
</el-form-item>
</el-col>
</el-row>
<el-form-item class="form-actions">
<el-button type="primary" @click="handleSubmit">提交</el-button>
<el-button @click="handleReset">重置</el-button>
<el-button @click="handleCancel">取消</el-button>
</el-form-item>
</el-form>
</div>
</template>
<style lang="less" scoped>
.form-container {
background: #fff;
padding: 24px;
border-radius: 4px;
.standard-form {
.form-actions {
margin-top: 32px;
text-align: center;
.el-button + .el-button {
margin-left: 16px;
}
}
}
}
</style>
4.3 移动端组件样式
Vant 组件规范
<template>
<div class="mobile-form">
<van-cell-group>
<van-field
v-model="formData.name"
label="姓名"
placeholder="请输入姓名"
required
/>
<van-field
v-model="formData.phone"
label="手机号"
placeholder="请输入手机号"
type="tel"
required
/>
<van-field
v-model="formData.remark"
label="备注"
placeholder="请输入备注"
type="textarea"
rows="3"
/>
</van-cell-group>
<div class="form-actions">
<van-button type="primary" block @click="handleSubmit">
提交
</van-button>
</div>
</div>
</template>
<style lang="less" scoped>
.mobile-form {
padding: 16px;
.form-actions {
margin-top: 24px;
}
}
</style>
Cube UI 组件规范
<template>
<div class="cube-form">
<cube-form :model="formData" :schema="schema" ref="form"></cube-form>
<div class="form-actions">
<cube-button type="primary" @click="handleSubmit">提交</cube-button>
</div>
</div>
</template>
<style lang="stylus" scoped>
.cube-form
padding 16px
.form-actions
margin-top 24px
padding 0 16px
</style>
5. 响应式设计规范
5.1 响应式布局示例
<style lang="less" scoped>
.responsive-container {
padding: 16px;
// 移动端
@media (max-width: 767px) {
padding: 8px;
.el-col {
margin-bottom: 16px;
}
}
// 平板端
@media (min-width: 768px) and (max-width: 991px) {
padding: 12px;
}
// 桌面端
@media (min-width: 992px) {
padding: 24px;
}
}
</style>
6. 动画和过渡效果
6.1 标准过渡动画
.fade-enter-active, .fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
.slide-enter-active, .slide-leave-active {
transition: transform 0.3s ease;
}
.slide-enter, .slide-leave-to {
transform: translateX(100%);
}
.scale-enter-active, .scale-leave-active {
transition: transform 0.3s ease;
}
.scale-enter, .scale-leave-to {
transform: scale(0);
}
6.2 加载动画
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loading-spinner {
display: inline-block;
width: 20px;
height: 20px;
border: 2px solid #f3f3f3;
border-top: 2px solid #007AF5;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes pulse {
0% { opacity: 1; }
50% { opacity: 0.5; }
100% { opacity: 1; }
}
.loading-pulse {
animation: pulse 1.5s ease-in-out infinite;
}