Files
xiaotutongxue/frontend-pc/README.md
T
lovife 87ece5a971 feat(frontend): 管理端改用 Gi Admin Pro 框架 + 腾讯云主题
前端此前只有本地实现、从未入库,本次首次纳入版本管理。

框架切换
  · 以 Gi Admin Pro(Vue3 + Vite + TS + Arco Design Vue + Pinia)为底
  · 剥离 14 个演示页面目录 / 121 个文件(demo 28、file 20、form 19、system 18…)
  · 依赖 dependencies 35 → 19,devDependencies 31 → 27
  · 保留框架核心:layout、Gi* 组件库、hooks、权限指令、错误页、登录页

主题:腾讯云 / TDesign 官方色板
  · 主色 #0052D9(腾讯蓝)、成功 #00A870、警告 #ED7B2F、危险 #E34D59
  · 页面底色 #f3f3f3、文字 rgba(0,0,0,90/60/40/26%)
  · 覆盖 Arco 底层色板 + 显式语义别名(primary/success/warning/danger/link/neutral)
  · 三个改了不生效也不报错的坑已记入注释:
      1) Arco 色值是逗号分隔 RGB 三元组,不是 #RRGGBB
      2) Arco 把色板定义在 body 而非 :root,必须写 `:root, body`
      3) setting.json 的 themeColor 会以内联样式写进 body,优先级高于样式表

对接后端(三处契约差异在 @/utils/http 统一适配)
  · 响应信封 {code,msg,data} → {code,success,message,data}
  · Token 头 token → Authorization: Bearer
  · 分页 {list,total} → 补一份 records,list 原样保留
  · 40101 → 登录页;登录密码 RSA 加密(公钥走 /auth/public-key,轮换无需重建前端)
  · 路由:后端只下发菜单键,前端在本地路由表上过滤(有哪些页面归代码,谁能看归后端)

已实现页面(浏览器实测通过)
  · 登录:RSA 加密 + 自适应验证码/租户码 + 账号锁定提示
  · 工作台:真实数据(组织 6 个 / 角色 1 个 / 权限 25 项)
  · 组织架构:三级树 + CRUD + 占用校验
  · 租户管理:开通租户 + 初始密码只显示一次的强确认
  · 待建页:未实现菜单显示所属里程碑
  · 权限菜单:学校管理员看不到「租户管理」

视觉资产按腾讯云主题重做
  · logo.svg(渐变圆角方 + 填)、favicon.svg(小尺寸做减法)、login-hero.svg(材料归集)
  · 登录页点阵纹理走主题变量,换主色自动跟随
  · 文案改为产品实际能力:自动改名 / 强制压缩 / 隐私保护

清理模板遗留(约 17MB + 三处外部依赖)
  · 百度统计脚本(上报到 gi-demo 作者的统计账号)
  · 用户菜单「项目地址」(跳转模板作者的 Gitee 仓库)
  · 两份 8.8MB mp3、388KB favicon.ico、57KB 模板插画、未引用字体与 loading.gif
  · 「个人中心」指向已删除的 /system/account(点了 404)
  · 头部头像在无 avatarUrl 时渲染成裂图 → 改为姓名首字兜底

后端修复
  · 新增 GET /auth/public-key(前端加密登录密码用)
  · DataSeeder.ancestor_path 生成错误:子节点本该是 /16/17/ 却写成 /17/
    该字段是「按院系统计」的索引,错了会漏人/多人且不报错 —— 改为从库里读父节点路径
  · seedDemoOrgs 曾放在租户作用域外 + admin 早退分支之后,导致启动失败 / 永不执行
  · 示范租户补一套三级组织树(1 学校 / 2 院系 / 3 班级),供界面演示
2026-09-28 20:49:55 +08:00

17 KiB
Raw Blame History

Gi Admin Pro

star
[![license](https://img.shields.io/badge/license-MIT-green.svg)](./LICENSE)

简介

Gi Admin Pro 是一个基于 Vue3、Vite、TypeScript、Arco Design Vue、Pinia、VueUse 等的免费中后台模版,它使用了最新的前端技术栈,内置丰富的主题配置,有着极高的代码规范,基于 mock 实现的动态数据展示,开箱即用的模板,也可用于学习参考。

Gi 前缀含义: G:代表全局 i:代表我的

Gi 用来定义全局组件前缀,如 GiTable、GiForm、GiPageLayout等

特性

  • 最新技术栈:使用 Vue3 / Vite 等前端前沿技术开发,使用高效率的 npm 包管理器
  • TypeScript:应用程序级 JavaScript 的语言
  • 主题:丰富可配置的主题、暗黑模式
  • 代码规范:丰富的规范插件及极高的代码规范

预览

平台 预览地址
github Gi Admin Pro 预览地址
账号 密码
管理员 admin 123456
用户 user 123456

代码仓库

平台 预览地址 仓库地址
gitee(码云) -- Gitee 仓库地址
github Gi Admin Pro 预览地址 Github 仓库地址

项目示例图

安装使用

  • 安装依赖
npm install
  • 运行
npm run dev
  • 打包
npm run build

开源作者

Lin

常见问题

为什么安装依赖不成功?

检查node版本,最好使用原生镜像npm

还原镜像

npm config set registry https://registry.npmjs.org/

为什么选择 Arco 组件库,而不是 Element Plus?

Element Plus 对比 Arco design

为什么全局组件使用前缀 Gi?

全局组件设置了按需引入,使用前缀,方便和局部组件做区分

为什么组件使用单词大写开头 (PascalCase)命名写法?

本项目.vue文件名以及在模板使用中,均采用大写开头 (PascalCase)命名方式

参考 Vue2 官网-风格指南: https://v2.cn.vuejs.org/v2/style-guide/

组件命名:单文件组件的文件名应该要么始终是单词大写开头 (PascalCase),要么始终是横线连接 (kebab-case)

其他优点:方便搜索(横线连接 (kebab-case)对搜索没那么方便)

为什么 css 类名推荐横线连接 (kebab-case)

参考大部分大网站,都是这个命名规则,不使用: .myClass这种

页面显示异常?

页面必须要保留一个根元素!!!

Vue3 权限管理对路由进行排序和格式化处理方式

使用 xe-utils 这个 js 库,简化数据处理

文章地址

页面无法缓存?

请检查页面是否配置了name,且名称是否与数据一致

defineOptions({ name: 'AboutIndex' })
{
  path: '/about/index',
  name: 'AboutIndex', // 检查name是否一致
  component: () => import('@/views/about/index.vue')
}

项目规范

.vue 文件行数规范

一般来说,一个 .vue 文件行数建议不超过 400 行,超过建议组件化拆分

vue 相关的命名

<script setup lang="ts">
const isEdit = ref(false)

// 不推荐
const title = computed(() => {
  return isEdit.value ? '编辑' : '新增'
})

// 推荐 能一行就尽量写一行
const title = computed(() => (isEdit.value ? '编辑' : '新增'))
</script>
<script setup lang="ts">
// 表单建议使用 form 命名(简洁),不必要使用 formData, 同时使用 reactive
const form = reactive({
  name: '',
  phone: ''
})
</script>
<script setup lang="ts">
// 如果属性比较多
const getInitForm = () => ({
  name: '',
  phone: '',
  email: '',
  sex: 1,
  age: ''
})

const form = reactive(getInitForm())

// 重置form
const resetForm = () => {
  for (const key in form) {
    delete form[key]
  }
  Object.assign(form, getInitForm())
}
</script>
<script setup lang="ts">
import { useAppStore, useUserStore } from '@/stores'
import { useLoading } from '@/hooks'

// stores 或 hooks 的使用命名规则定义
const appStore = useAppStore()
const userStore = useUserStore()

const { loading, setLoading } = useLoading()
</script>

写法技巧

尽量使用三元表达式

// 优化前
let isEdit = true
let title = ''
if (isEdit) {
  title = '编辑'
} else {
  title = '新增'
}

// 优化后
let title = isEdit ? '编辑' : '新增'

善用 includes 方法

// 优化前
if (type === 1 || type === 2 || type === 3) {
}

// 优化后,此种方式在vue模板也可使用
if ([1, 2, 3].includes(type)) {
}

使用箭头函数简化函数

// 优化前
function add(num1, num2) {
  return num1 + num2
}

// 优化后
const add = (num1, num2) => num1 + num2

尽量减少 if else if

<script setup lang="ts">
// 比例进度条颜色 尽量减少 if else if
const getProportionColor = (proportion: number) => {
  if (proportion < 30) return 'danger'
  if (proportion < 60) return 'warning'
  return 'success'
}
</script>
// 优化前
const status = 200
const message = ''
if (status === 200) {
  message = '请求成功'
} else if (status === 404) {
  message = '请求出错'
} else if (status === 500) {
  message = '服务器错误'
}

// 优化后
const status = 200
const messageMap = {
  200: '请求成功',
  404: '请求出错',
  500: '服务器错误'
}
const message = messageMap[status]

如果函数参数超过两个,建议优化

<script setup lang="ts">
function createUser(name, phone, age) {
  console.log('姓名', name)
  console.log('手机', phone)
  console.log('年龄', age)
}

// 这种方式在使用的时候可读性很差,扩展性差,而且不易于维护
createUser('张三', '178****2828', 20)

function createUser2({ name, phone, age }) {
  console.log('姓名', name)
  console.log('手机', phone)
  console.log('年龄', age)
}

// 以对象传参更直观,更好扩展和维护
createUser2({ name: '张三', phone: '178****2828', age: 20 })
</script>

接口调用书写

写法一

不需要 loading,不需要错误打印的 情况

<script setup lang="ts">
import { ref } from 'vue'
import { getUserList as getUserListApi, type UserItem } from '@/apis' // 同名可以使用别名

const userList = ref<UserItem[]>([])
const getUserList = async () => {
  const res = await getUserListApi()
  console.log('如果异步成功,则会打印这行文字,否则不会打印这行文字,也不会往下执行')
  userList.value = res.data
}
</script>

// getUserListApi 是一个 Promise 异步函数,Promise 最后只有 成功 / 失败 两种状态 // getUserListApi 是基于 axios
封装的,在 axios 响应拦截器做了处理 // 当 res.success === false 的时候 Promise.reject(),
也就异步失败,异步失败不会往下执行

写法二

需要 loading,需要错误打印的情况

<script setup lang="ts">
import { ref } from 'vue'
import { getUserList as getUserListApi, type UserItem } from '@/apis' // 同名可以使用别名

const loading = ref(false)
const userList = ref<UserItem[]>([])
const getUserList = async () => {
  try {
    loading.value = true
    const res = await getUserListApi()
    console.log('如果异步成功,则会打印这行文字,否则不会打印这行文字,也不会往下执行')
    userList.value = res.data
  } catch (error) {
    console.log('如果异步失败,会打印这行文字')
    // 由于 axios 在封装的时候,已经在异步失败给了失败的提示弹窗处理
    // 所以这里没必要再写 Message.error(error)
  } finally {
    console.log('如果异步或者失败,都会打印这行代码')
    loading.value = false // 可以用来处理 loading
  }
}
</script>

写法三

需要 loading, 不需要错误打印(不进行错误处理)的情况

<script setup lang="ts">
import { ref } from 'vue'
import { getUserList as getUserListApi, type UserItem } from '@/apis' // 同名可以使用别名

const loading = ref(false)
const userList = ref<UserItem[]>([])
const getUserList = async () => {
  try {
    loading.value = true
    const res = await getUserListApi()
    console.log('如果异步成功,则会打印这行文字,否则不会打印这行文字,也不会往下执行')
    userList.value = res.data
  } finally {
    console.log('如果异步或者失败,都会打印这行代码')
    loading.value = false // 可以用来处理 loading
  }
}
</script>

// catch 可以省略

全局组件--命名规范

组件命名:单文件组件的文件名应该要么始终是单词大写开头 (PascalCase),要么始终是横线连接 (kebab-case)

可参考 Vue2 官网-风格指南: https://v2.cn.vuejs.org/v2/style-guide/

GiForm.vue
GiTable.vue
GiPageLayout.vue

局部组件--命名规范

组件命名:单文件组件的文件名应该要么始终是单词大写开头 (PascalCase),要么始终是横线连接 (kebab-case)

可参考 Vue2 官网-风格指南: https://v2.cn.vuejs.org/v2/style-guide/

Pane1.vue
Pane2.vue
PaneQuota1.vue
PaneQuota2.vue
Step1.vue
Step2.vue
AddModal.vue
EditDrawer.vue
DetailModal.vue

文件夹命名--命名规范 (采用中划线-)

1、文件名建议只使用小写字母,不使用大写字母

2、名称较长时采用半角连接符(-)分隔

home/index.vue
user/index.vue
user-detail/index.vue

弹窗组件 Modal、抽屉组件 Drawer 的一般封装

<template>
  <a-modal v-model:visible="visible" :title="title" @ok="confirm">
    <!-- 内容 -->
  </a-modal>
</template>

<script setup lang="ts">
import { computed, reactive, ref } from 'vue'

const visible = ref(false)
const detailId = ref('')
const isEdit = computed(() => !!detailId.value) // 判断是新增还是编辑模式
const title = computed(() => (isEdit.value ? '编辑' : '新增'))

const add = () => {
  detailId.value = ''
  visible.value = true
}

// 如果这里的参数超过两个,建议优化成对象形式
// const edit = ({ id, taskId }) = {
//   console.log(id, taskId)
// }

const edit = (id: string) => {
  detailId.value = id
  visible.value = true
  // getDetail() 回显操作
}

defineExpose({ add, edit })

const confirm = () => {
  console.log('点击了确认按钮')
}
</script>

使用

模板里使用自定义组件:使用大写开头驼峰,双击好复制,对于搜索便利

<template>
  <EditModal ref="EditModalRef"></EditModal>
</template>

<script setup lang="ts">
import EditModal from './EditModal.vue'

const EditModalRef = ref<InstanceType<typeof EditModal>>()

// 新增
const onAdd = () => {
  EditModalRef.value?.add()
}

// 编辑
const onEdit = (item: PersonItem) => {
  EditModalRef.value?.edit(item.id)
}
</script>

CSS 命名规范

建议采用全小写,多单词使用-连接符(参考大部分网站,包括掘金,码云等,都是采用这个规则)

或者采用BEM命名规范 BEM 命名规范

BEM 命名规范

<div class="article">
  <div class="article__body">
    <button class="article__button--primary"></button>
    <button class="article__button--success"></button>
  </div>
</div>

其他:

位置 1: 使用 var(--margin) 全局 css 变量

位置 2:使用 var(--padding) 全局 css 变量

建议尽量使用全局 css 变量来开发,可以有效提高效率和团队协作

其他规范

可参考 Vue2 官网-风格指南: https://v2.cn.vuejs.org/v2/style-guide/ , 其中一些规范也可借鉴

可参考 Gi Admin Pro 源码,如有更好的规范建议,可以联系作者本人

Vue 相关

Vue3 官网

Vue-Router

Vite

Pinia

插件推荐

Arco Design 组件库

Day.js 一个极简的 JavaScript 库,可以为现代浏览器解析、验证、操作和显示日期和时间 2K 大小

Lodash 一个一致性、模块化、高性能的 JavaScript 实用工具库

Xe-utils 一个 JavaScript 函数库、工具类

VueUse 一个 Vue3 Hooks 库

VueRequest 一个 Vue 请求库

V-Viewer 基于 viewer.js 的 vue 图像查看器组件,支持旋转、缩放等操作

Vue-Color-Kit 一个 vue3 颜色选择器组件

Vxe-Table

vue3-request 一个专为 Vue 3 设计的异步请求处理库,它通过统一的 useRequest Hook 和强大的插件生态,彻底简化了异步操作和 API 调用的复杂性

其他

VCalendar 日历组件

Vue Cal 日历组件

VueDraggablePlus 支持 Vue2 和 Vue3 的拖拽组件

推荐书籍

Vue 入门指南与实战案例

深入理解 TypeScript

前端宝典

Web 开发人员需要知道的 CSS 技巧

阮一峰 ES6

阮一峰 flex 布局

开源项目集合

Vue3 开源项目集合

React 开源项目集合

工具

菜鸟工具

代码生成图片

JSON-TO-ANY 对象转 ts 类型

在线三角形样式生成器

iTab

捐赠