@campus-admin/ui

面向智慧校园后台场景的 Vue 3 组件库
143
Install
npm install @campus-admin/ui
Latest Version:1.0.0
Vue:3
License:MIT
Last Updated:Sep 12, 2026
Links: npm
Maintainer: unionschool

@campus-admin/ui

面向智慧校园后台管理场景的 Vue 3 组件库,共 27 个组件,分原子 / 基础 / 功能三层。

组件只负责渲染,不访问接口、不读全局状态:数据通过 Props 传入, 用户操作通过 Events 抛出。

主题支持明暗两套配色与运行时品牌换色:一行代码切换暗色,一行代码把主色换成学校品牌色。

安装

pnpm add @campus-admin/ui

通常不需要单独安装——@campus-admin/core 已包含它。

依赖:vue@^3.5.42、@lucide/vue@^1.44.0(均为 peerDependency)。

两种引入方式

按需引入(推荐)

<script setup lang="ts">
import { CaButton, CaTable, toast } from '@campus-admin/ui'
import type { TableColumn } from '@campus-admin/ui'
import '@campus-admin/ui/style.css'
</script>

全局注册

import { createApp } from 'vue'
import CampusUI from '@campus-admin/ui'
import '@campus-admin/ui/style.css'

createApp(App).use(CampusUI).mount('#app')

注册后模板里直接写 <CaButton>,无需 import。

组件清单

原子(src/atom) —— 元素级,不占版面,多为其他组件的零件

组件 用途
CaButton 操作按钮
CaIcon 单色图标容器
CaTag 状态/分类标记
CaAvatar 用户/学生头像
CaInput 单行文本
CaTextarea 多行文本
CaSelect 下拉选择
CaCheckbox 勾选 / 半选
CaSwitch 开关
CaProgress 进度条 / 环形进度
CaAttendanceBadge 考勤状态标签

基础(src/base) —— 区域级,可直接放进页面布局,与业务无关

组件 用途
CaTable 数据表格(泛型 + 排序)
CaPagination 分页
CaStatistic 指标数值
CaModal 对话框
CaDrawer 抽屉
CaEmpty 空状态
CaSkeleton 骨架屏
CaToastContainer + toast 轻提示(挂载式)
CaBreadcrumb 面包屑
CaSideMenu 侧边多级菜单
CaPageHeader 页面标题栏
CaSearchForm 查询表单
CaClassTree 年级班级树

功能(src/feature) —— 多个组件组合起来完成一件事,不区分角色

组件 用途
CaStudentPicker 学生选择器
CaWeeklyTimetable 课程表
CaDailyAgenda 日程安排

每个组件的 .vue 文件顶部都有使用说明(用法、Props、事件、插槽), 各层的判据与目录约定见 src/atom/README.md、src/base/README.md、src/feature/README.md。

快速示例

数据表格

<script setup lang="ts">
import { ref } from 'vue'
import { CaPagination, CaTable } from '@campus-admin/ui'
import type { TableColumn } from '@campus-admin/ui'

interface StudentRow {
  id: string
  name: string
  className: string
  balance: number
}

const columns: TableColumn<StudentRow>[] = [
  { key: 'name', title: '姓名' },
  { key: 'className', title: '班级' },
  { key: 'balance', title: '余额', numeric: true, sortable: true },
]

const rows = ref<StudentRow[]>([])
const total = ref(0)
const page = ref(1)
</script>

<template>
  <CaTable :columns="columns" :data="rows" row-key="id" stripe>
    <!-- 单元格插槽命名为 cell-<列 key>,参数是 row / index / column -->
    <template #cell-name="{ row }">
      <CaAvatar :name="row.name" size="small" />
      <b>{{ row.name }}</b>
    </template>
  </CaTable>

  <CaPagination v-model:current="page" :total="total" />
</template>

要点:

  • columns 是普通数组,可来自后端下发
  • rowKey 必须是稳定字段或函数,不要用数组下标
  • 单元格插槽名为 cell-<列 key>;泛型会跟着 columns 推导,row 自动获得具体字段类型
  • 排序有两种模式:不传 sort-key / sort-order 时组件内部排序(点击表头按 升序 → 降序 → 取消 循环); 传入这两个 prop 且监听 sort 事件时用于服务端排序

多级侧边菜单

<script setup lang="ts">
import { CaSideMenu } from '@campus-admin/ui'
import type { SideMenuItem } from '@campus-admin/ui'

const items: SideMenuItem[] = [
  { label: '学校概况', icon: LayoutDashboard, children: [
    { label: '我的首页', value: '/home' },
    { label: '学生管理', value: '/students' },
  ] },
  { label: '教学教务', icon: BookOpen, children: [
    { label: '课程管理', children: [
      { label: '课程表', value: '/teach/course/schedule' },
    ] },
  ] },
]

function go(item: SideMenuItem) {
  if (item.value) router.push(item.value)
}
</script>

<template>
  <CaSideMenu :items="items" :model-value="route.path" :indent="2" :indent-step="32" @select="go" />
</template>

菜单组件不认识路由:value 是业务数据,跳转由使用方决定。 这样同一组件也能用于小程序或纯链接场景。

轻提示

import { toast } from '@campus-admin/ui'

toast.success('保存成功')
toast.error('保存失败', '请检查网络')

挂载式用法:在模板里放一个 <CaToastContainer />。 如果用 @campus-admin/core,推荐改用全局的 ca.toast()(见下方"与 ca 的关系")。

与 ca 的关系

@campus-admin/core 提供全局命令式 API ca,与本库的 toast 共用同一份消息队列:

ca.toast('保存成功')        // 与 toast.success('保存成功') 等效

本库的 toast 保留了描述文案等扩展能力;ca.toast 更简洁,适合在任意 JS 里调用。

主题与样式

引入样式

import '@campus-admin/ui/style.css'

明暗主题

import { setTheme } from '@campus-admin/ui'

setTheme('dark')   // 暗色
setTheme('light')  // 亮色
setTheme('auto')   // 跟随系统,系统切换时自动更新

setTheme 只是在 <html> 上写 data-ca-theme,配色由 Token 决定, 组件样式不区分主题。也可以不用 JS,直接写 <html data-ca-theme="dark">。

品牌换色(运行时)

学校品牌色不是蓝色时,只给一个主色,其余色阶自动推导:

import { setPrimaryColor, resetPrimaryColor } from '@campus-admin/ui'

setPrimaryColor('#7c4dff')   // 紫色品牌
resetPrimaryColor()          // 恢复默认蓝色

会自动生成并写入以下变量:--ca-color-primary、-hover、-active、-soft、-text、-contrast。 推导规则是:

  • 亮色下 hover / active 变深,暗色下变亮;
  • -soft 浅底跟随当前主题(亮色混合白、暗色混合深色卡片底);
  • -text 用于浅底上的文字,品牌色过浅时自动加深(暗色下自动提亮)以满足对比度;
  • -contrast 是主色实心背景上的文字色,浅色品牌(如黄色)自动切换成深色文字。

因此按钮、标签、菜单选中态、表格悬停、课表色块都会一起跟着变,不需要逐个组件配置。

覆盖 Token(更细粒度的换肤)

所有视觉都走 CSS 变量,改变量即可换肤,不要写深层选择器覆盖:

:root {
  --ca-color-primary: #1f6fe0;    /* 主色(等价于 setPrimaryColor) */
  --ca-color-success: #2fae85;
  --ca-radius-md: 6px;
  --ca-control-height-md: 32px;   /* 控件高度,可用于调整信息密度 */
}

Token 分三层,完整清单见 src/styles/token.css:

基础色 palette   --ca-color-blue-500、--ca-space-4、--ca-radius-md
品牌与语义色     --ca-color-primary-soft、--ca-color-success-text、--ca-text-secondary、--ca-surface-card
文字层级         --ca-text-primary、--ca-text-regular、--ca-text-secondary、--ca-text-placeholder、--ca-text-menu
主题覆盖         :root[data-ca-theme='dark'] 覆盖语义与中性色

层级 Token 同样可覆盖:--ca-z-index-modal、--ca-z-index-message。

国际化

组件库内置 zh-CN / en-US 两套词条,不需要额外安装 i18n 库。单独使用 @campus-admin/ui 时, 在入口建一个语言实例并注入应用:

import { CampusUI, createLocale, installLocale } from '@campus-admin/ui'
import { createApp } from 'vue'

const app = createApp(App)
const locale = createLocale({
  locale: 'zh-CN',
  // 业务词条放在自己的根键下,ca 是组件库保留的命名空间
  messages: { 'zh-CN': zhCN, 'en-US': enUS },
})

app.use(CampusUI)          // 已自带一份默认语言实例,可省略下一行
installLocale(app, locale)

取词与切换:

import { setLocale, useLocale } from '@campus-admin/ui'

const { t, te } = useLocale()    // 组件内取词
t('ca.pagination.total', { total: 12 })   // 共 12 条

setLocale('en-US')               // 非 setup 场景

日期与数字格式化走内置的 Intl 封装,不要自己拼中文:

import { formatDay, formatMonth, formatNumber, weekdayLabels } from '@campus-admin/ui'

formatMonth(new Date(2026, 8, 11), 'en-US')   // September 2026
weekdayLabels('zh-CN')                        // ['周一', ...]
formatNumber(3286, 'en-US')                   // 3,286

已经用 vue-i18n 的项目不要再装第二个实例,把内置词条合并进自己的实例即可:

import { caMessages } from '@campus-admin/ui'

i18n.global.mergeLocaleMessage('zh-CN', caMessages['zh-CN'])
i18n.global.mergeLocaleMessage('en-US', caMessages['en-US'])

完整约定(命名空间、覆盖组件文案、后端文案对接、加语言)见 Campus Admin 国际化使用指南。

类名约定

块        .ca-button
元素      .ca-button__icon
修饰符    .ca-button--primary

组件样式是统一 ca- 前缀的 BEM 类名,只有 Token 是稳定的公共契约,类名不作为 API。 业务侧换肤请覆盖变量,不要写深层选择器。

开发约定

三层目录结构(atom / base / feature),每个组件目录结构统一:

src/<层>/<组件名>/
├── src/core.ts           纯逻辑,不依赖 Vue(可单测)
├── src/data.ts           演示数据(可选)
├── src/<组件名>.vue      只做渲染
├── style/index.css       样式,由 .vue 通过 `<style src="../style/index.css">` 引入
└── index.ts              导出 Ca 前缀组件与公开类型

新增组件只需要改两处:组件自己的目录 + 所属层的 index.ts(加入命名导出与注册表)。 顶层 builtInComponents 由三层合并,@campus-admin/core 会自动纳入全局注册表。

设计要求

  • 组件不访问接口。数据用 Props 传入,操作通过 Events 抛出。
  • 不写死颜色。任何颜色都必须来自 --ca-* Token,否则暗色主题与品牌换色会失效。
  • 主色实心背景上的文字用 --ca-color-primary-contrast,保证浅色品牌色下仍可读。
  • 所有 ID 使用字符串,避免后端大整数在 JavaScript 中丢失精度。
  • 覆盖默认、Hover、Focus、Disabled、Loading、Empty、Error 等状态。
  • 弹层类组件需处理 Esc 关闭、焦点锁定、关闭后焦点恢复。
  • 组件卸载时清理事件、计时器、Observer。

相关包

包 关系
@campus-admin/locale 被本包依赖,组件通过它取词与格式化
@campus-admin/core 依赖本包并统一出口

版权

使用本项目时请保留版权信息(MIT 许可要求随副本保留版权声明):

  • 保留包内的 LICENSE 文件与版权声明;
  • 保留页面页脚中的「Powered By 众校通 ®」与联系方式(示例用 Copyright 组件统一渲染);
  • 二次分发或修改后的版本,请在显著位置保留同样的版权声明。

Powered By 众校通 ®

Related Packages

@campus-admin/icon

面向智慧校园的语义图标集:校园业务图标别名与后端图标名解析

180 1
@campus-admin/core

Campus Admin 框架层与装配入口:应用生命周期、服务容器、Vue 适配、命令式 API 与组...

0 1
vue3-admin-layout

一个灵活的 Vue 管理后台布局组件

3,929 2
@xdmp-open/ui-admin

XDMP platform admin business page components (Vue 3 + Element Plus)

2,419
@tnzi/ui-admin

Tnzi admin panel UI components and pages, built on @tnzi/ui and @tnzi/core.

404 1

Version History

Version Released Vue License
1.0.0 ^3.5.42 MIT