fix: 111
This commit is contained in:
commit
d22dde58fc
|
@ -0,0 +1,28 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
|
||||
**/cert/
|
|
@ -0,0 +1,296 @@
|
|||
# 项目改动日志
|
||||
|
||||
## 版本: v1.2.0 - 界面全面美化与作业管理 (2024-01-30)
|
||||
|
||||
### 🎉 新增功能
|
||||
|
||||
#### 1. 小学作业管理系统
|
||||
- **完整的作业管理界面** - 基于AboutView重构
|
||||
- **作业统计面板** - 4个统计卡片展示完成情况
|
||||
- **作业列表管理** - 支持筛选、添加、完成、删除操作
|
||||
- **预设作业内容** - 包含数学、语文、英语、科学四个科目
|
||||
- **响应式设计** - 适配不同屏幕尺寸的美观界面
|
||||
|
||||
#### 2. 美观对话框系统
|
||||
- **精美提示框** - 复杂功能展示的大型对话框
|
||||
- **简单提示框** - 轻量级确认对话框
|
||||
- **美化表单对话框** - 添加作业的高级表单界面
|
||||
|
||||
### 🎨 界面美化升级
|
||||
|
||||
#### 1. 数据表格全面美化
|
||||
- **渐变表头** - 蓝紫色渐变背景,白色文字
|
||||
- **圆角设计** - 12px圆角,现代化外观
|
||||
- **悬停效果** - 行悬停时轻微放大和彩色阴影
|
||||
- **图标装饰** - 日期、姓名、邮箱列都添加了对应图标
|
||||
- **操作按钮美化** - 渐变色按钮,悬停上浮效果
|
||||
- **标签美化** - 部门标签使用圆角胶囊设计
|
||||
|
||||
#### 2. 添加作业对话框美化
|
||||
- **渐变头部设计** - 蓝紫色渐变 + 脉冲动画图标
|
||||
- **表单输入美化** - 圆角输入框,悬停和聚焦效果
|
||||
- **科目选择器** - 带图标的选项设计
|
||||
- **难度按钮组** - 渐变激活状态,悬停动画
|
||||
- **底部按钮** - 渐变背景,上浮动画效果
|
||||
|
||||
#### 3. 作业管理界面设计
|
||||
- **渐变背景** - 整体页面使用柔和渐变
|
||||
- **统计卡片** - 彩色图标 + 悬停上浮效果
|
||||
- **作业项目** - 左侧彩色边框,悬停右移效果
|
||||
- **科目标签** - 每个科目不同的渐变色彩
|
||||
- **筛选按钮** - 活跃状态高亮显示
|
||||
|
||||
### 🔧 交互体验提升
|
||||
|
||||
#### 1. 导航系统完善
|
||||
- **路由跳转** - 菜单项正确连接到对应页面
|
||||
- **自动高亮** - 根据当前路由自动高亮菜单项
|
||||
- **前进后退支持** - 浏览器导航按钮正确更新菜单状态
|
||||
|
||||
#### 2. 用户反馈系统
|
||||
- **消息提示** - 所有操作都有即时反馈
|
||||
- **状态变化** - 作业完成状态实时更新
|
||||
- **视觉反馈** - 按钮点击、悬停的视觉效果
|
||||
|
||||
#### 3. 表格交互增强
|
||||
- **行点击事件** - 点击表格行显示信息提示
|
||||
- **按钮防冲突** - 操作按钮阻止行点击事件冒泡
|
||||
- **图标表意** - 每列都有对应的图标说明
|
||||
|
||||
### 📱 响应式设计改进
|
||||
|
||||
#### 1. 作业管理页面
|
||||
- **弹性布局** - 统计卡片自适应排列
|
||||
- **移动端优化** - 小屏幕下的合理间距
|
||||
- **卡片悬停** - 不同设备的交互适配
|
||||
|
||||
#### 2. 对话框适配
|
||||
- **居中显示** - 所有对话框完美居中
|
||||
- **宽度自适应** - 根据内容和屏幕自动调整
|
||||
- **触摸友好** - 移动设备上的操作体验
|
||||
|
||||
### 🎯 样式系统重构
|
||||
|
||||
#### 1. 全局宽度优化 (已完成)
|
||||
- **移除宽度限制** - 应用可以使用全屏宽度
|
||||
- **响应式间距** - 不同屏幕尺寸的合适内边距
|
||||
- **布局优化** - 移除网格限制,使用正常流布局
|
||||
|
||||
#### 2. 组件样式统一
|
||||
- **颜色主题** - 统一的蓝紫色主题色彩
|
||||
- **圆角标准** - 12-16px的统一圆角规范
|
||||
- **阴影层次** - 不同深度的阴影效果
|
||||
- **动画规范** - 0.3s的统一过渡时间
|
||||
|
||||
### 🛠️ 技术优化
|
||||
|
||||
#### 1. Vue 3 组合式API应用
|
||||
- **响应式数据** - 使用ref和computed管理状态
|
||||
- **生命周期** - 合理使用watch监听路由变化
|
||||
- **类型支持** - TypeScript类型定义完善
|
||||
|
||||
#### 2. ElementPlus深度定制
|
||||
- **样式穿透** - 使用:deep()修改组件内部样式
|
||||
- **主题定制** - 覆盖默认样式实现个性化设计
|
||||
- **组件扩展** - 在ElementPlus基础上增强功能
|
||||
|
||||
### 📦 新增依赖和配置
|
||||
```json
|
||||
{
|
||||
"features": {
|
||||
"作业管理": "完整的学生作业管理系统",
|
||||
"表格美化": "全面美化的数据表格组件",
|
||||
"对话框美化": "多种风格的美观对话框",
|
||||
"导航增强": "完善的路由导航系统"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 🚀 用户体验提升
|
||||
- **视觉冲击力** - 现代化的渐变色彩和动画效果
|
||||
- **操作便捷性** - 直观的图标和清晰的交互反馈
|
||||
- **功能完整性** - 从数据展示到作业管理的完整流程
|
||||
- **响应速度** - 流畅的动画和即时的状态更新
|
||||
|
||||
### 🎨 设计亮点
|
||||
1. **色彩搭配** - 蓝紫色主题 + 功能性彩色图标
|
||||
2. **动画效果** - 悬停上浮、脉冲动画、渐变过渡
|
||||
3. **层次结构** - 通过阴影和颜色建立清晰的视觉层次
|
||||
4. **一致性** - 统一的设计语言和交互模式
|
||||
|
||||
### 📋 功能清单
|
||||
- ✅ 用户数据表格美化
|
||||
- ✅ 作业管理系统完成
|
||||
- ✅ 多种风格对话框
|
||||
- ✅ 导航路由修复
|
||||
- ✅ 响应式布局优化
|
||||
- ✅ 交互动画增强
|
||||
- ✅ 主题色彩统一
|
||||
|
||||
### 🎯 下一步计划
|
||||
- [ ] 添加设置页面功能
|
||||
- [ ] 数据持久化存储
|
||||
- [ ] 用户权限管理
|
||||
- [ ] 暗黑模式支持
|
||||
- [ ] 国际化多语言
|
||||
- [ ] 移动端App化
|
||||
- [ ] 数据导出功能
|
||||
|
||||
---
|
||||
|
||||
## 版本: v1.0.0 - ElementPlus 集成 (2024-01-30)
|
||||
|
||||
### 🎉 新增功能
|
||||
|
||||
#### 1. ElementPlus 组件库集成
|
||||
- **安装依赖包**
|
||||
- `element-plus` - Vue 3 的企业级 UI 组件库
|
||||
- `@element-plus/icons-vue` - ElementPlus 官方图标库
|
||||
|
||||
#### 2. 全新的用户界面设计
|
||||
- **导航栏**: 使用 ElementPlus 水平菜单组件
|
||||
- **卡片布局**: 响应式卡片展示系统特性
|
||||
- **数据表格**: 完整的用户管理表格,支持编辑和删除
|
||||
- **表单组件**: 带验证的用户添加表单
|
||||
- **统计面板**: 数据统计和进度展示
|
||||
- **时间线**: 系统通知时间线展示
|
||||
|
||||
### 🔧 文件修改详情
|
||||
|
||||
#### 1. `src/main.ts` - 应用入口配置
|
||||
```typescript
|
||||
// 新增内容:
|
||||
import ElementPlus from 'element-plus'
|
||||
import 'element-plus/dist/index.css'
|
||||
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
|
||||
|
||||
// 注册所有 ElementPlus 图标
|
||||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||
app.component(key, component)
|
||||
}
|
||||
|
||||
app.use(ElementPlus)
|
||||
```
|
||||
|
||||
#### 2. `src/App.vue` - 主应用组件重构
|
||||
- **移除原有**: `HelloWorld` 组件引用
|
||||
- **新增组件**:
|
||||
- `el-menu` - 水平导航菜单
|
||||
- `el-card` - 欢迎卡片和功能展示
|
||||
- `el-button` - 各种类型的按钮组件
|
||||
- `el-alert` - 成功提示组件
|
||||
- `el-row/el-col` - 响应式栅格布局
|
||||
- `el-icon` - 图标组件集成
|
||||
|
||||
#### 3. `src/views/HomeView.vue` - 首页完全重构
|
||||
- **移除**: `TheWelcome` 组件
|
||||
- **新增功能模块**:
|
||||
|
||||
**数据表格模块**:
|
||||
- `el-table` - 用户数据展示表格
|
||||
- `el-tag` - 部门标签显示
|
||||
- 编辑和删除操作按钮
|
||||
|
||||
**用户管理模块**:
|
||||
- `el-dialog` - 添加用户对话框
|
||||
- `el-form` - 表单组件与验证
|
||||
- `el-input` - 输入框组件
|
||||
- `el-select` - 下拉选择器
|
||||
- 完整的表单验证规则
|
||||
|
||||
**统计面板模块**:
|
||||
- `el-statistic` - 数据统计组件
|
||||
- `el-progress` - 进度条显示
|
||||
- `el-steps` - 项目步骤展示
|
||||
- `el-timeline` - 系统通知时间线
|
||||
|
||||
### 🎨 样式系统重构
|
||||
|
||||
#### 1. `src/assets/main.css` - 全局样式优化
|
||||
**问题修复**: 界面宽度受限问题
|
||||
|
||||
**修改前**:
|
||||
```css
|
||||
#app {
|
||||
max-width: 1280px; /* 限制最大宽度 */
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
#app {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr; /* 强制两列布局 */
|
||||
padding: 0 2rem;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**修改后**:
|
||||
```css
|
||||
#app {
|
||||
width: 100%; /* 使用全屏宽度 */
|
||||
min-height: 100vh; /* 最小高度为视窗高度 */
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
#app {
|
||||
display: block; /* 正常块级布局 */
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 组件样式优化
|
||||
- **App.vue**: 减少内边距,添加响应式设计
|
||||
- **HomeView.vue**: 优化容器宽度,确保表格全宽显示
|
||||
|
||||
### 📱 响应式设计改进
|
||||
- **移动端**: 优化小屏幕显示效果
|
||||
- **桌面端**: 充分利用大屏幕空间
|
||||
- **自适应**: 不同尺寸下的合适内边距
|
||||
|
||||
### 🛠️ 开发体验提升
|
||||
- **TypeScript 支持**: 完整的类型定义
|
||||
- **组件复用**: 模块化的组件结构
|
||||
- **代码规范**: 统一的编码风格
|
||||
- **注释完善**: 详细的中文注释
|
||||
|
||||
### 📦 依赖变更
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"element-plus": "^2.x.x",
|
||||
"@element-plus/icons-vue": "^2.x.x"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 🚀 使用说明
|
||||
1. **安装依赖**: `npm install`
|
||||
2. **启动开发**: `npm run dev`
|
||||
3. **构建生产**: `npm run build`
|
||||
|
||||
### 🔧 主要组件功能
|
||||
- **导航菜单**: 支持页面切换和路由跳转
|
||||
- **用户管理**: 完整的增删改查操作
|
||||
- **数据展示**: 美观的表格和统计图表
|
||||
- **表单验证**: 实时验证和错误提示
|
||||
- **消息反馈**: 操作成功/失败的消息提示
|
||||
|
||||
### 📋 技术栈
|
||||
- **Vue 3**: 最新的响应式框架
|
||||
- **TypeScript**: 类型安全的JavaScript超集
|
||||
- **ElementPlus**: 企业级UI组件库
|
||||
- **Vue Router**: 官方路由管理器
|
||||
- **Pinia**: 现代化状态管理
|
||||
- **Vite**: 快速的构建工具
|
||||
|
||||
---
|
||||
|
||||
**开发者**: AI Assistant
|
||||
**最新更新**: 2024-01-30
|
||||
**当前版本**: v1.2.0
|
|
@ -0,0 +1,33 @@
|
|||
# my-vue3-app
|
||||
|
||||
This template should help get you started developing with Vue 3 in Vite.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
|
||||
|
||||
## Type Support for `.vue` Imports in TS
|
||||
|
||||
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.
|
||||
|
||||
## Customize configuration
|
||||
|
||||
See [Vite Configuration Reference](https://vite.dev/config/).
|
||||
|
||||
## Project Setup
|
||||
|
||||
```sh
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compile and Hot-Reload for Development
|
||||
|
||||
```sh
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Type-Check, Compile and Minify for Production
|
||||
|
||||
```sh
|
||||
npm run build
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Vite App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"name": "my-vue3-app",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "run-p type-check \"build-only {@}\" --",
|
||||
"preview": "vite preview",
|
||||
"build-only": "vite build",
|
||||
"type-check": "vue-tsc --build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"element-plus": "^2.10.4",
|
||||
"pinia": "^3.0.3",
|
||||
"vue": "^3.5.18",
|
||||
"vue-router": "^4.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tsconfig/node22": "^22.0.2",
|
||||
"@types/node": "^22.16.5",
|
||||
"@vitejs/plugin-vue": "^6.0.1",
|
||||
"@vitejs/plugin-vue-jsx": "^5.0.1",
|
||||
"@vue/tsconfig": "^0.7.0",
|
||||
"npm-run-all2": "^8.0.4",
|
||||
"typescript": "~5.8.0",
|
||||
"vite": "^7.0.6",
|
||||
"vite-plugin-vue-devtools": "^8.0.0",
|
||||
"vue-tsc": "^3.0.4"
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
|
@ -0,0 +1,214 @@
|
|||
<script setup lang="ts">
|
||||
import { RouterLink, RouterView } from 'vue-router'
|
||||
import { ref, watch } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const activeIndex = ref('1')
|
||||
|
||||
// 根据当前路由设置活跃菜单项
|
||||
const updateActiveIndex = () => {
|
||||
switch(route.path) {
|
||||
case '/':
|
||||
activeIndex.value = '1'
|
||||
break
|
||||
case '/about':
|
||||
activeIndex.value = '2'
|
||||
break
|
||||
default:
|
||||
activeIndex.value = '1'
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化时设置活跃状态
|
||||
updateActiveIndex()
|
||||
|
||||
// 监听路由变化
|
||||
watch(() => route.path, () => {
|
||||
updateActiveIndex()
|
||||
})
|
||||
|
||||
const handleSelect = (key: string, keyPath: string[]) => {
|
||||
console.log(key, keyPath)
|
||||
// 根据菜单项跳转到对应路由
|
||||
switch(key) {
|
||||
case '1':
|
||||
router.push('/')
|
||||
break
|
||||
case '2':
|
||||
router.push('/about')
|
||||
break
|
||||
case '3':
|
||||
// 设置页面暂时跳转到首页
|
||||
router.push('/')
|
||||
break
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- ElementPlus 导航栏 -->
|
||||
<el-menu
|
||||
:default-active="activeIndex"
|
||||
class="el-menu-demo"
|
||||
mode="horizontal"
|
||||
@select="handleSelect"
|
||||
>
|
||||
<el-menu-item index="1">
|
||||
<el-icon><house /></el-icon>
|
||||
<span>首页</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="2">
|
||||
<el-icon><document /></el-icon>
|
||||
<span>作业</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="3">
|
||||
<el-icon><setting /></el-icon>
|
||||
<span>设置</span>
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
|
||||
<!-- 主要内容区域 -->
|
||||
<div class="main-content">
|
||||
<div class="welcome-section">
|
||||
<el-card class="welcome-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>欢迎使用 Vue 3 + ElementPlus</span>
|
||||
<el-button type="primary" class="button">
|
||||
<el-icon><plus /></el-icon>
|
||||
新建项目
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="demo-section">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<div class="demo-header">
|
||||
<el-icon><star /></el-icon>
|
||||
<span>组件丰富</span>
|
||||
</div>
|
||||
</template>
|
||||
<p>ElementPlus 提供了丰富的组件库,满足各种业务需求</p>
|
||||
<el-button type="primary" size="small">了解更多</el-button>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<div class="demo-header">
|
||||
<el-icon><magic-stick /></el-icon>
|
||||
<span>设计精美</span>
|
||||
</div>
|
||||
</template>
|
||||
<p>基于现代设计理念,提供美观的用户界面</p>
|
||||
<el-button type="success" size="small">查看设计</el-button>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<div class="demo-header">
|
||||
<el-icon><cpu /></el-icon>
|
||||
<span>高性能</span>
|
||||
</div>
|
||||
</template>
|
||||
<p>基于Vue 3构建,享受最新的响应式系统带来的性能提升</p>
|
||||
<el-button type="warning" size="small">性能测试</el-button>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<div class="demo-components">
|
||||
<h3>组件演示</h3>
|
||||
<el-divider />
|
||||
|
||||
<div class="component-demo">
|
||||
<el-space wrap>
|
||||
<el-button>默认按钮</el-button>
|
||||
<el-button type="primary">主要按钮</el-button>
|
||||
<el-button type="success">成功按钮</el-button>
|
||||
<el-button type="info">信息按钮</el-button>
|
||||
<el-button type="warning">警告按钮</el-button>
|
||||
<el-button type="danger">危险按钮</el-button>
|
||||
</el-space>
|
||||
|
||||
<el-divider />
|
||||
|
||||
<el-alert
|
||||
title="恭喜!ElementPlus 已成功引入到您的 Vue 3 项目中"
|
||||
type="success"
|
||||
:closable="false"
|
||||
show-icon>
|
||||
</el-alert>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 路由视图 -->
|
||||
<div class="router-view">
|
||||
<RouterView />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.app-container {
|
||||
min-height: 100vh;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
padding: 10px 15px; /* 减少内边距 */
|
||||
max-width: 100%; /* 确保使用全宽 */
|
||||
}
|
||||
|
||||
.welcome-card {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.demo-section {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.demo-components {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.component-demo {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.router-view {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
/* 优化大屏幕显示 */
|
||||
@media (min-width: 1200px) {
|
||||
.main-content {
|
||||
padding: 15px 30px; /* 大屏幕时稍微增加内边距 */
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>
|
After Width: | Height: | Size: 276 B |
|
@ -0,0 +1,38 @@
|
|||
@import './base.css';
|
||||
|
||||
#app {
|
||||
/* 移除最大宽度限制,让界面可以使用全屏宽度 */
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
a,
|
||||
.green {
|
||||
text-decoration: none;
|
||||
color: hsla(160, 100%, 37%, 1);
|
||||
transition: 0.4s;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
a:hover {
|
||||
background-color: hsla(160, 100%, 37%, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#app {
|
||||
/* 移除网格布局,使用正常的块级布局 */
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
msg: string
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="greetings">
|
||||
<h1 class="green">{{ msg }}</h1>
|
||||
<h3>
|
||||
You’ve successfully created a project with
|
||||
<a href="https://vite.dev/" target="_blank" rel="noopener">Vite</a> +
|
||||
<a href="https://vuejs.org/" target="_blank" rel="noopener">Vue 3</a>. What's next?
|
||||
</h3>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
h1 {
|
||||
font-weight: 500;
|
||||
font-size: 2.6rem;
|
||||
position: relative;
|
||||
top: -10px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.greetings h1,
|
||||
.greetings h3 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.greetings h1,
|
||||
.greetings h3 {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,94 @@
|
|||
<script setup lang="ts">
|
||||
import WelcomeItem from './WelcomeItem.vue'
|
||||
import DocumentationIcon from './icons/IconDocumentation.vue'
|
||||
import ToolingIcon from './icons/IconTooling.vue'
|
||||
import EcosystemIcon from './icons/IconEcosystem.vue'
|
||||
import CommunityIcon from './icons/IconCommunity.vue'
|
||||
import SupportIcon from './icons/IconSupport.vue'
|
||||
|
||||
const openReadmeInEditor = () => fetch('/__open-in-editor?file=README.md')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<DocumentationIcon />
|
||||
</template>
|
||||
<template #heading>Documentation</template>
|
||||
|
||||
Vue’s
|
||||
<a href="https://vuejs.org/" target="_blank" rel="noopener">official documentation</a>
|
||||
provides you with all information you need to get started.
|
||||
</WelcomeItem>
|
||||
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<ToolingIcon />
|
||||
</template>
|
||||
<template #heading>Tooling</template>
|
||||
|
||||
This project is served and bundled with
|
||||
<a href="https://vite.dev/guide/features.html" target="_blank" rel="noopener">Vite</a>. The
|
||||
recommended IDE setup is
|
||||
<a href="https://code.visualstudio.com/" target="_blank" rel="noopener">VSCode</a>
|
||||
+
|
||||
<a href="https://github.com/vuejs/language-tools" target="_blank" rel="noopener">Vue - Official</a>. If
|
||||
you need to test your components and web pages, check out
|
||||
<a href="https://vitest.dev/" target="_blank" rel="noopener">Vitest</a>
|
||||
and
|
||||
<a href="https://www.cypress.io/" target="_blank" rel="noopener">Cypress</a>
|
||||
/
|
||||
<a href="https://playwright.dev/" target="_blank" rel="noopener">Playwright</a>.
|
||||
|
||||
<br />
|
||||
|
||||
More instructions are available in
|
||||
<a href="javascript:void(0)" @click="openReadmeInEditor"><code>README.md</code></a
|
||||
>.
|
||||
</WelcomeItem>
|
||||
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<EcosystemIcon />
|
||||
</template>
|
||||
<template #heading>Ecosystem</template>
|
||||
|
||||
Get official tools and libraries for your project:
|
||||
<a href="https://pinia.vuejs.org/" target="_blank" rel="noopener">Pinia</a>,
|
||||
<a href="https://router.vuejs.org/" target="_blank" rel="noopener">Vue Router</a>,
|
||||
<a href="https://test-utils.vuejs.org/" target="_blank" rel="noopener">Vue Test Utils</a>, and
|
||||
<a href="https://github.com/vuejs/devtools" target="_blank" rel="noopener">Vue Dev Tools</a>. If
|
||||
you need more resources, we suggest paying
|
||||
<a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">Awesome Vue</a>
|
||||
a visit.
|
||||
</WelcomeItem>
|
||||
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<CommunityIcon />
|
||||
</template>
|
||||
<template #heading>Community</template>
|
||||
|
||||
Got stuck? Ask your question on
|
||||
<a href="https://chat.vuejs.org" target="_blank" rel="noopener">Vue Land</a>
|
||||
(our official Discord server), or
|
||||
<a href="https://stackoverflow.com/questions/tagged/vue.js" target="_blank" rel="noopener"
|
||||
>StackOverflow</a
|
||||
>. You should also follow the official
|
||||
<a href="https://bsky.app/profile/vuejs.org" target="_blank" rel="noopener">@vuejs.org</a>
|
||||
Bluesky account or the
|
||||
<a href="https://x.com/vuejs" target="_blank" rel="noopener">@vuejs</a>
|
||||
X account for latest news in the Vue world.
|
||||
</WelcomeItem>
|
||||
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<SupportIcon />
|
||||
</template>
|
||||
<template #heading>Support Vue</template>
|
||||
|
||||
As an independent project, Vue relies on community backing for its sustainability. You can help
|
||||
us by
|
||||
<a href="https://vuejs.org/sponsor/" target="_blank" rel="noopener">becoming a sponsor</a>.
|
||||
</WelcomeItem>
|
||||
</template>
|
|
@ -0,0 +1,87 @@
|
|||
<template>
|
||||
<div class="item">
|
||||
<i>
|
||||
<slot name="icon"></slot>
|
||||
</i>
|
||||
<div class="details">
|
||||
<h3>
|
||||
<slot name="heading"></slot>
|
||||
</h3>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.item {
|
||||
margin-top: 2rem;
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.details {
|
||||
flex: 1;
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
i {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
place-content: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 500;
|
||||
margin-bottom: 0.4rem;
|
||||
color: var(--color-heading);
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.item {
|
||||
margin-top: 0;
|
||||
padding: 0.4rem 0 1rem calc(var(--section-gap) / 2);
|
||||
}
|
||||
|
||||
i {
|
||||
top: calc(50% - 25px);
|
||||
left: -26px;
|
||||
position: absolute;
|
||||
border: 1px solid var(--color-border);
|
||||
background: var(--color-background);
|
||||
border-radius: 8px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.item:before {
|
||||
content: ' ';
|
||||
border-left: 1px solid var(--color-border);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: calc(50% + 25px);
|
||||
height: calc(50% - 25px);
|
||||
}
|
||||
|
||||
.item:after {
|
||||
content: ' ';
|
||||
border-left: 1px solid var(--color-border);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: calc(50% + 25px);
|
||||
height: calc(50% - 25px);
|
||||
}
|
||||
|
||||
.item:first-of-type:before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.item:last-of-type:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,7 @@
|
|||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
|
||||
<path
|
||||
d="M15 4a1 1 0 1 0 0 2V4zm0 11v-1a1 1 0 0 0-1 1h1zm0 4l-.707.707A1 1 0 0 0 16 19h-1zm-4-4l.707-.707A1 1 0 0 0 11 14v1zm-4.707-1.293a1 1 0 0 0-1.414 1.414l1.414-1.414zm-.707.707l-.707-.707.707.707zM9 11v-1a1 1 0 0 0-.707.293L9 11zm-4 0h1a1 1 0 0 0-1-1v1zm0 4H4a1 1 0 0 0 1.707.707L5 15zm10-9h2V4h-2v2zm2 0a1 1 0 0 1 1 1h2a3 3 0 0 0-3-3v2zm1 1v6h2V7h-2zm0 6a1 1 0 0 1-1 1v2a3 3 0 0 0 3-3h-2zm-1 1h-2v2h2v-2zm-3 1v4h2v-4h-2zm1.707 3.293l-4-4-1.414 1.414 4 4 1.414-1.414zM11 14H7v2h4v-2zm-4 0c-.276 0-.525-.111-.707-.293l-1.414 1.414C5.42 15.663 6.172 16 7 16v-2zm-.707 1.121l3.414-3.414-1.414-1.414-3.414 3.414 1.414 1.414zM9 12h4v-2H9v2zm4 0a3 3 0 0 0 3-3h-2a1 1 0 0 1-1 1v2zm3-3V3h-2v6h2zm0-6a3 3 0 0 0-3-3v2a1 1 0 0 1 1 1h2zm-3-3H3v2h10V0zM3 0a3 3 0 0 0-3 3h2a1 1 0 0 1 1-1V0zM0 3v6h2V3H0zm0 6a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1H0zm3 3h2v-2H3v2zm1-1v4h2v-4H4zm1.707 4.707l.586-.586-1.414-1.414-.586.586 1.414 1.414z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
|
@ -0,0 +1,7 @@
|
|||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" fill="currentColor">
|
||||
<path
|
||||
d="M11 2.253a1 1 0 1 0-2 0h2zm-2 13a1 1 0 1 0 2 0H9zm.447-12.167a1 1 0 1 0 1.107-1.666L9.447 3.086zM1 2.253L.447 1.42A1 1 0 0 0 0 2.253h1zm0 13H0a1 1 0 0 0 1.553.833L1 15.253zm8.447.833a1 1 0 1 0 1.107-1.666l-1.107 1.666zm0-14.666a1 1 0 1 0 1.107 1.666L9.447 1.42zM19 2.253h1a1 1 0 0 0-.447-.833L19 2.253zm0 13l-.553.833A1 1 0 0 0 20 15.253h-1zm-9.553-.833a1 1 0 1 0 1.107 1.666L9.447 14.42zM9 2.253v13h2v-13H9zm1.553-.833C9.203.523 7.42 0 5.5 0v2c1.572 0 2.961.431 3.947 1.086l1.107-1.666zM5.5 0C3.58 0 1.797.523.447 1.42l1.107 1.666C2.539 2.431 3.928 2 5.5 2V0zM0 2.253v13h2v-13H0zm1.553 13.833C2.539 15.431 3.928 15 5.5 15v-2c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM5.5 15c1.572 0 2.961.431 3.947 1.086l1.107-1.666C9.203 13.523 7.42 13 5.5 13v2zm5.053-11.914C11.539 2.431 12.928 2 14.5 2V0c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM14.5 2c1.573 0 2.961.431 3.947 1.086l1.107-1.666C18.203.523 16.421 0 14.5 0v2zm3.5.253v13h2v-13h-2zm1.553 12.167C18.203 13.523 16.421 13 14.5 13v2c1.573 0 2.961.431 3.947 1.086l1.107-1.666zM14.5 13c-1.92 0-3.703.523-5.053 1.42l1.107 1.666C11.539 15.431 12.928 15 14.5 15v-2z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
|
@ -0,0 +1,7 @@
|
|||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" fill="currentColor">
|
||||
<path
|
||||
d="M11.447 8.894a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm0 1.789a1 1 0 1 0 .894-1.789l-.894 1.789zM7.447 7.106a1 1 0 1 0-.894 1.789l.894-1.789zM10 9a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0H8zm9.447-5.606a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm2 .789a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zM18 5a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0h-2zm-5.447-4.606a1 1 0 1 0 .894-1.789l-.894 1.789zM9 1l.447-.894a1 1 0 0 0-.894 0L9 1zm-2.447.106a1 1 0 1 0 .894 1.789l-.894-1.789zm-6 3a1 1 0 1 0 .894 1.789L.553 4.106zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zm-2-.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 2.789a1 1 0 1 0 .894-1.789l-.894 1.789zM2 5a1 1 0 1 0-2 0h2zM0 7.5a1 1 0 1 0 2 0H0zm8.553 12.394a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 1a1 1 0 1 0 .894 1.789l-.894-1.789zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zM8 19a1 1 0 1 0 2 0H8zm2-2.5a1 1 0 1 0-2 0h2zm-7.447.394a1 1 0 1 0 .894-1.789l-.894 1.789zM1 15H0a1 1 0 0 0 .553.894L1 15zm1-2.5a1 1 0 1 0-2 0h2zm12.553 2.606a1 1 0 1 0 .894 1.789l-.894-1.789zM17 15l.447.894A1 1 0 0 0 18 15h-1zm1-2.5a1 1 0 1 0-2 0h2zm-7.447-5.394l-2 1 .894 1.789 2-1-.894-1.789zm-1.106 1l-2-1-.894 1.789 2 1 .894-1.789zM8 9v2.5h2V9H8zm8.553-4.894l-2 1 .894 1.789 2-1-.894-1.789zm.894 0l-2-1-.894 1.789 2 1 .894-1.789zM16 5v2.5h2V5h-2zm-4.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zm-2.894-1l-2 1 .894 1.789 2-1L8.553.106zM1.447 5.894l2-1-.894-1.789-2 1 .894 1.789zm-.894 0l2 1 .894-1.789-2-1-.894 1.789zM0 5v2.5h2V5H0zm9.447 13.106l-2-1-.894 1.789 2 1 .894-1.789zm0 1.789l2-1-.894-1.789-2 1 .894 1.789zM10 19v-2.5H8V19h2zm-6.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zM2 15v-2.5H0V15h2zm13.447 1.894l2-1-.894-1.789-2 1 .894 1.789zM18 15v-2.5h-2V15h2z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
|
@ -0,0 +1,7 @@
|
|||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
|
||||
<path
|
||||
d="M10 3.22l-.61-.6a5.5 5.5 0 0 0-7.666.105 5.5 5.5 0 0 0-.114 7.665L10 18.78l8.39-8.4a5.5 5.5 0 0 0-.114-7.665 5.5 5.5 0 0 0-7.666-.105l-.61.61z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
|
@ -0,0 +1,19 @@
|
|||
<!-- This icon is from <https://github.com/Templarian/MaterialDesign>, distributed under Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) license-->
|
||||
<template>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
class="iconify iconify--mdi"
|
||||
width="24"
|
||||
height="24"
|
||||
preserveAspectRatio="xMidYMid meet"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 18v-4h-3v1h-2v-1H9v1H7v-1H4v4h16M6.33 8l-1.74 4H7v-1h2v1h6v-1h2v1h2.41l-1.74-4H6.33M9 5v1h6V5H9m12.84 7.61c.1.22.16.48.16.8V18c0 .53-.21 1-.6 1.41c-.4.4-.85.59-1.4.59H4c-.55 0-1-.19-1.4-.59C2.21 19 2 18.53 2 18v-4.59c0-.32.06-.58.16-.8L4.5 7.22C4.84 6.41 5.45 6 6.33 6H7V5c0-.55.18-1 .57-1.41C7.96 3.2 8.44 3 9 3h6c.56 0 1.04.2 1.43.59c.39.41.57.86.57 1.41v1h.67c.88 0 1.49.41 1.83 1.22l2.34 5.39z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</svg>
|
||||
</template>
|
|
@ -0,0 +1,26 @@
|
|||
import './assets/main.css'
|
||||
|
||||
import { createApp } from 'vue'
|
||||
import { createPinia } from 'pinia'
|
||||
|
||||
// 引入ElementPlus
|
||||
import ElementPlus from 'element-plus'
|
||||
import 'element-plus/dist/index.css'
|
||||
// 引入ElementPlus图标
|
||||
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
|
||||
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
// 注册ElementPlus图标
|
||||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||
app.component(key, component)
|
||||
}
|
||||
|
||||
app.use(createPinia())
|
||||
app.use(router)
|
||||
app.use(ElementPlus)
|
||||
|
||||
app.mount('#app')
|
|
@ -0,0 +1,23 @@
|
|||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import HomeView from '../views/HomeView.vue'
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
name: 'home',
|
||||
component: HomeView,
|
||||
},
|
||||
{
|
||||
path: '/about',
|
||||
name: 'about',
|
||||
// route level code-splitting
|
||||
// this generates a separate chunk (About.[hash].js) for this route
|
||||
// which is lazy-loaded when the route is visited.
|
||||
component: () => import('../views/AboutView.vue'),
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
export default router
|
|
@ -0,0 +1,12 @@
|
|||
import { ref, computed } from 'vue'
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const useCounterStore = defineStore('counter', () => {
|
||||
const count = ref(0)
|
||||
const doubleCount = computed(() => count.value * 2)
|
||||
function increment() {
|
||||
count.value++
|
||||
}
|
||||
|
||||
return { count, doubleCount, increment }
|
||||
})
|
|
@ -0,0 +1,970 @@
|
|||
<template>
|
||||
<div class="homework-container">
|
||||
<!-- 作业页面头部 -->
|
||||
<div class="homework-header">
|
||||
<el-card class="header-card">
|
||||
<div class="header-content">
|
||||
<div class="header-left">
|
||||
<el-icon size="40" class="homework-icon"><reading /></el-icon>
|
||||
<div class="header-text">
|
||||
<h1 class="page-title">📚 小学作业管理</h1>
|
||||
<p class="page-subtitle">让学习变得更有趣</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<el-button type="primary" class="add-homework-btn" @click="showAddDialog = true">
|
||||
<el-icon><plus /></el-icon>
|
||||
添加作业
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 作业统计卡片 -->
|
||||
<el-row :gutter="20" class="stats-row">
|
||||
<el-col :span="6">
|
||||
<el-card class="stat-card">
|
||||
<div class="stat-content">
|
||||
<div class="stat-icon completed">
|
||||
<el-icon size="24"><select /></el-icon>
|
||||
</div>
|
||||
<div class="stat-text">
|
||||
<div class="stat-number">{{ completedCount }}</div>
|
||||
<div class="stat-label">已完成</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="6">
|
||||
<el-card class="stat-card">
|
||||
<div class="stat-content">
|
||||
<div class="stat-icon pending">
|
||||
<el-icon size="24"><clock /></el-icon>
|
||||
</div>
|
||||
<div class="stat-text">
|
||||
<div class="stat-number">{{ pendingCount }}</div>
|
||||
<div class="stat-label">待完成</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="6">
|
||||
<el-card class="stat-card">
|
||||
<div class="stat-content">
|
||||
<div class="stat-icon total">
|
||||
<el-icon size="24"><document /></el-icon>
|
||||
</div>
|
||||
<div class="stat-text">
|
||||
<div class="stat-number">{{ homeworkList.length }}</div>
|
||||
<div class="stat-label">总作业</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="6">
|
||||
<el-card class="stat-card">
|
||||
<div class="stat-content">
|
||||
<div class="stat-icon progress">
|
||||
<el-icon size="24"><trophy /></el-icon>
|
||||
</div>
|
||||
<div class="stat-text">
|
||||
<div class="stat-number">{{ completionRate }}%</div>
|
||||
<div class="stat-label">完成率</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 作业列表 -->
|
||||
<el-card class="homework-list-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="header-title">
|
||||
<el-icon><notebook /></el-icon>
|
||||
作业清单
|
||||
</span>
|
||||
<el-button-group>
|
||||
<el-button
|
||||
:type="filterStatus === 'all' ? 'primary' : ''"
|
||||
size="small"
|
||||
@click="filterStatus = 'all'"
|
||||
>
|
||||
全部
|
||||
</el-button>
|
||||
<el-button
|
||||
:type="filterStatus === 'pending' ? 'primary' : ''"
|
||||
size="small"
|
||||
@click="filterStatus = 'pending'"
|
||||
>
|
||||
待完成
|
||||
</el-button>
|
||||
<el-button
|
||||
:type="filterStatus === 'completed' ? 'primary' : ''"
|
||||
size="small"
|
||||
@click="filterStatus = 'completed'"
|
||||
>
|
||||
已完成
|
||||
</el-button>
|
||||
</el-button-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="homework-list">
|
||||
<div
|
||||
v-for="(homework, index) in filteredHomework"
|
||||
:key="homework.id"
|
||||
class="homework-item"
|
||||
:class="{ 'completed': homework.completed }"
|
||||
>
|
||||
<div class="homework-content">
|
||||
<div class="homework-left">
|
||||
<div class="subject-badge" :class="homework.subject.toLowerCase()">
|
||||
<el-icon size="20">
|
||||
<component :is="getSubjectIcon(homework.subject)" />
|
||||
</el-icon>
|
||||
<span>{{ homework.subject }}</span>
|
||||
</div>
|
||||
<div class="homework-details">
|
||||
<h3 class="homework-title">{{ homework.title }}</h3>
|
||||
<p class="homework-desc">{{ homework.description }}</p>
|
||||
<div class="homework-meta">
|
||||
<span class="due-date">
|
||||
<el-icon><calendar /></el-icon>
|
||||
截止日期: {{ homework.dueDate }}
|
||||
</span>
|
||||
<span class="difficulty" :class="homework.difficulty">
|
||||
<el-icon><star /></el-icon>
|
||||
{{ getDifficultyText(homework.difficulty) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="homework-actions">
|
||||
<el-button
|
||||
v-if="!homework.completed"
|
||||
type="success"
|
||||
size="small"
|
||||
@click="markCompleted(homework.id)"
|
||||
>
|
||||
<el-icon><check /></el-icon>
|
||||
完成
|
||||
</el-button>
|
||||
<el-button
|
||||
v-else
|
||||
type="info"
|
||||
size="small"
|
||||
disabled
|
||||
>
|
||||
<el-icon><select /></el-icon>
|
||||
已完成
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="viewDetails(homework)"
|
||||
>
|
||||
<el-icon><view /></el-icon>
|
||||
查看
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
@click="deleteHomework(homework.id)"
|
||||
>
|
||||
<el-icon><delete /></el-icon>
|
||||
删除
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 添加作业对话框 -->
|
||||
<el-dialog
|
||||
v-model="showAddDialog"
|
||||
width="600px"
|
||||
center
|
||||
:show-close="false"
|
||||
class="add-homework-dialog"
|
||||
>
|
||||
<template #header>
|
||||
<div class="dialog-header">
|
||||
<div class="header-icon">
|
||||
<el-icon size="32"><plus /></el-icon>
|
||||
</div>
|
||||
<div class="header-text">
|
||||
<h2 class="dialog-title">📝 添加新作业</h2>
|
||||
<p class="dialog-subtitle">为学习添加新的任务</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="dialog-body">
|
||||
<el-form :model="newHomework" label-width="0px" class="beautiful-form">
|
||||
<div class="form-section">
|
||||
<div class="form-item-wrapper">
|
||||
<div class="form-label">
|
||||
<el-icon><reading /></el-icon>
|
||||
<span>选择科目</span>
|
||||
</div>
|
||||
<el-select
|
||||
v-model="newHomework.subject"
|
||||
placeholder="请选择科目"
|
||||
class="form-input"
|
||||
size="large"
|
||||
>
|
||||
<el-option label="📚 语文" value="语文">
|
||||
<div class="option-content">
|
||||
<el-icon><reading /></el-icon>
|
||||
<span>语文</span>
|
||||
</div>
|
||||
</el-option>
|
||||
<el-option label="🔢 数学" value="数学">
|
||||
<div class="option-content">
|
||||
<el-icon><calculator /></el-icon>
|
||||
<span>数学</span>
|
||||
</div>
|
||||
</el-option>
|
||||
<el-option label="🌍 英语" value="英语">
|
||||
<div class="option-content">
|
||||
<el-icon><chat-line-round /></el-icon>
|
||||
<span>英语</span>
|
||||
</div>
|
||||
</el-option>
|
||||
<el-option label="🔬 科学" value="科学">
|
||||
<div class="option-content">
|
||||
<el-icon><magic-stick /></el-icon>
|
||||
<span>科学</span>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
<div class="form-item-wrapper">
|
||||
<div class="form-label">
|
||||
<el-icon><edit /></el-icon>
|
||||
<span>作业标题</span>
|
||||
</div>
|
||||
<el-input
|
||||
v-model="newHomework.title"
|
||||
placeholder="请输入作业标题"
|
||||
class="form-input"
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-item-wrapper">
|
||||
<div class="form-label">
|
||||
<el-icon><document /></el-icon>
|
||||
<span>作业描述</span>
|
||||
</div>
|
||||
<el-input
|
||||
v-model="newHomework.description"
|
||||
type="textarea"
|
||||
placeholder="请详细描述作业内容和要求"
|
||||
:rows="4"
|
||||
class="form-input"
|
||||
resize="none"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-item-wrapper half">
|
||||
<div class="form-label">
|
||||
<el-icon><star /></el-icon>
|
||||
<span>难度等级</span>
|
||||
</div>
|
||||
<el-radio-group v-model="newHomework.difficulty" class="difficulty-group">
|
||||
<el-radio-button label="easy" class="difficulty-easy">
|
||||
<el-icon><circle-check /></el-icon>
|
||||
简单
|
||||
</el-radio-button>
|
||||
<el-radio-button label="medium" class="difficulty-medium">
|
||||
<el-icon><warning /></el-icon>
|
||||
中等
|
||||
</el-radio-button>
|
||||
<el-radio-button label="hard" class="difficulty-hard">
|
||||
<el-icon><close /></el-icon>
|
||||
困难
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
|
||||
<div class="form-item-wrapper half">
|
||||
<div class="form-label">
|
||||
<el-icon><calendar /></el-icon>
|
||||
<span>截止日期</span>
|
||||
</div>
|
||||
<el-date-picker
|
||||
v-model="newHomework.dueDate"
|
||||
type="date"
|
||||
placeholder="选择截止日期"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
class="form-input"
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button
|
||||
size="large"
|
||||
@click="showAddDialog = false"
|
||||
class="cancel-btn"
|
||||
>
|
||||
<el-icon><close /></el-icon>
|
||||
取消
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="large"
|
||||
@click="addHomework"
|
||||
class="confirm-btn"
|
||||
>
|
||||
<el-icon><check /></el-icon>
|
||||
添加作业
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
// 作业数据
|
||||
const homeworkList = ref([
|
||||
{
|
||||
id: 1,
|
||||
subject: '数学',
|
||||
title: '口算练习',
|
||||
description: '完成课本第15页的加减法口算题,共20道题目',
|
||||
dueDate: '2024-02-01',
|
||||
difficulty: 'easy',
|
||||
completed: false
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
subject: '语文',
|
||||
title: '古诗背诵',
|
||||
description: '背诵《静夜思》并默写,注意字体工整',
|
||||
dueDate: '2024-02-02',
|
||||
difficulty: 'medium',
|
||||
completed: true
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
subject: '英语',
|
||||
title: '单词练习',
|
||||
description: '抄写Unit 1的新单词,每个单词写5遍',
|
||||
dueDate: '2024-02-03',
|
||||
difficulty: 'easy',
|
||||
completed: false
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
subject: '科学',
|
||||
title: '观察日记',
|
||||
description: '观察一种植物的生长变化,记录3天的观察日记',
|
||||
dueDate: '2024-02-05',
|
||||
difficulty: 'hard',
|
||||
completed: false
|
||||
}
|
||||
])
|
||||
|
||||
// 筛选状态
|
||||
const filterStatus = ref('all')
|
||||
|
||||
// 添加作业对话框
|
||||
const showAddDialog = ref(false)
|
||||
const newHomework = ref({
|
||||
subject: '',
|
||||
title: '',
|
||||
description: '',
|
||||
difficulty: 'easy',
|
||||
dueDate: ''
|
||||
})
|
||||
|
||||
// 计算属性
|
||||
const completedCount = computed(() =>
|
||||
homeworkList.value.filter(h => h.completed).length
|
||||
)
|
||||
|
||||
const pendingCount = computed(() =>
|
||||
homeworkList.value.filter(h => !h.completed).length
|
||||
)
|
||||
|
||||
const completionRate = computed(() => {
|
||||
if (homeworkList.value.length === 0) return 0
|
||||
return Math.round((completedCount.value / homeworkList.value.length) * 100)
|
||||
})
|
||||
|
||||
const filteredHomework = computed(() => {
|
||||
if (filterStatus.value === 'all') return homeworkList.value
|
||||
if (filterStatus.value === 'completed') return homeworkList.value.filter(h => h.completed)
|
||||
if (filterStatus.value === 'pending') return homeworkList.value.filter(h => !h.completed)
|
||||
return homeworkList.value
|
||||
})
|
||||
|
||||
// 方法
|
||||
const getSubjectIcon = (subject: string) => {
|
||||
const icons = {
|
||||
'数学': 'Calculator',
|
||||
'语文': 'Reading',
|
||||
'英语': 'ChatLineRound',
|
||||
'科学': 'MagicStick'
|
||||
}
|
||||
return icons[subject] || 'Document'
|
||||
}
|
||||
|
||||
const getDifficultyText = (difficulty: string) => {
|
||||
const texts = {
|
||||
'easy': '简单',
|
||||
'medium': '中等',
|
||||
'hard': '困难'
|
||||
}
|
||||
return texts[difficulty] || '未知'
|
||||
}
|
||||
|
||||
const markCompleted = (id: number) => {
|
||||
const homework = homeworkList.value.find(h => h.id === id)
|
||||
if (homework) {
|
||||
homework.completed = true
|
||||
ElMessage.success('作业已标记为完成!')
|
||||
}
|
||||
}
|
||||
|
||||
const viewDetails = (homework: any) => {
|
||||
ElMessage.info(`查看作业: ${homework.title}`)
|
||||
}
|
||||
|
||||
const deleteHomework = (id: number) => {
|
||||
const index = homeworkList.value.findIndex(h => h.id === id)
|
||||
if (index > -1) {
|
||||
homeworkList.value.splice(index, 1)
|
||||
ElMessage.success('作业已删除!')
|
||||
}
|
||||
}
|
||||
|
||||
const addHomework = () => {
|
||||
if (!newHomework.value.subject || !newHomework.value.title) {
|
||||
ElMessage.error('请填写完整信息')
|
||||
return
|
||||
}
|
||||
|
||||
const newId = Math.max(...homeworkList.value.map(h => h.id)) + 1
|
||||
homeworkList.value.push({
|
||||
id: newId,
|
||||
...newHomework.value,
|
||||
completed: false
|
||||
})
|
||||
|
||||
// 重置表单
|
||||
newHomework.value = {
|
||||
subject: '',
|
||||
title: '',
|
||||
description: '',
|
||||
difficulty: 'easy',
|
||||
dueDate: ''
|
||||
}
|
||||
|
||||
showAddDialog.value = false
|
||||
ElMessage.success('作业添加成功!')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.homework-container {
|
||||
padding: 20px;
|
||||
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.homework-header {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.header-card {
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.header-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.homework-icon {
|
||||
color: #667eea;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
margin: 0;
|
||||
color: #2c3e50;
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.page-subtitle {
|
||||
margin: 5px 0 0 0;
|
||||
color: #7f8c8d;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.add-homework-btn {
|
||||
background: linear-gradient(45deg, #667eea, #764ba2);
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
padding: 12px 20px;
|
||||
}
|
||||
|
||||
.stats-row {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.stat-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.stat-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.stat-icon {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.stat-icon.completed {
|
||||
background: linear-gradient(45deg, #67c23a, #85ce61);
|
||||
}
|
||||
|
||||
.stat-icon.pending {
|
||||
background: linear-gradient(45deg, #e6a23c, #f7ba2a);
|
||||
}
|
||||
|
||||
.stat-icon.total {
|
||||
background: linear-gradient(45deg, #409eff, #67c23a);
|
||||
}
|
||||
|
||||
.stat-icon.progress {
|
||||
background: linear-gradient(45deg, #f56c6c, #ff7875);
|
||||
}
|
||||
|
||||
.stat-number {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: #2c3e50;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 14px;
|
||||
color: #7f8c8d;
|
||||
}
|
||||
|
||||
.homework-list-card {
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.homework-item {
|
||||
padding: 20px;
|
||||
margin-bottom: 15px;
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
border-left: 4px solid #667eea;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.homework-item:hover {
|
||||
transform: translateX(5px);
|
||||
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.homework-item.completed {
|
||||
border-left-color: #67c23a;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.homework-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.homework-left {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.subject-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 12px;
|
||||
border-radius: 20px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: white;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.subject-badge.数学 {
|
||||
background: linear-gradient(45deg, #f56c6c, #ff7875);
|
||||
}
|
||||
|
||||
.subject-badge.语文 {
|
||||
background: linear-gradient(45deg, #67c23a, #85ce61);
|
||||
}
|
||||
|
||||
.subject-badge.英语 {
|
||||
background: linear-gradient(45deg, #409eff, #67c23a);
|
||||
}
|
||||
|
||||
.subject-badge.科学 {
|
||||
background: linear-gradient(45deg, #e6a23c, #f7ba2a);
|
||||
}
|
||||
|
||||
.homework-title {
|
||||
margin: 0 0 8px 0;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.homework-desc {
|
||||
margin: 0 0 10px 0;
|
||||
color: #5a6c7d;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.homework-meta {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.due-date, .difficulty {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
color: #7f8c8d;
|
||||
}
|
||||
|
||||
.difficulty.easy {
|
||||
color: #67c23a;
|
||||
}
|
||||
|
||||
.difficulty.medium {
|
||||
color: #e6a23c;
|
||||
}
|
||||
|
||||
.difficulty.hard {
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.homework-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.homework-actions .el-button {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
/* New styles for the dialog */
|
||||
:deep(.add-homework-dialog) {
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
:deep(.add-homework-dialog .el-dialog__header) {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border-bottom: none;
|
||||
border-radius: 16px 16px 0 0;
|
||||
padding: 25px 30px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 12px;
|
||||
padding: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% { transform: scale(1); }
|
||||
50% { transform: scale(1.05); }
|
||||
100% { transform: scale(1); }
|
||||
}
|
||||
|
||||
.header-icon .el-icon {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.header-text {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.dialog-subtitle {
|
||||
margin: 5px 0 0 0;
|
||||
font-size: 14px;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
:deep(.add-homework-dialog .el-dialog__body) {
|
||||
padding: 30px;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.form-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 25px;
|
||||
}
|
||||
|
||||
.form-item-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.form-item-wrapper.half {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #2c3e50;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.form-label .el-icon {
|
||||
color: #667eea;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.form-row {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
/* 输入框美化 */
|
||||
:deep(.form-input .el-input__wrapper) {
|
||||
border-radius: 12px;
|
||||
border: 2px solid #e8ecf4;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
transition: all 0.3s ease;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
:deep(.form-input .el-input__wrapper:hover) {
|
||||
border-color: #667eea;
|
||||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.1);
|
||||
}
|
||||
|
||||
:deep(.form-input .el-input__wrapper.is-focus) {
|
||||
border-color: #667eea;
|
||||
box-shadow: 0 4px 16px rgba(102, 126, 234, 0.2);
|
||||
}
|
||||
|
||||
:deep(.form-input .el-textarea__inner) {
|
||||
border-radius: 12px;
|
||||
border: 2px solid #e8ecf4;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
transition: all 0.3s ease;
|
||||
padding: 12px 16px;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
:deep(.form-input .el-textarea__inner:hover) {
|
||||
border-color: #667eea;
|
||||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.1);
|
||||
}
|
||||
|
||||
:deep(.form-input .el-textarea__inner:focus) {
|
||||
border-color: #667eea;
|
||||
box-shadow: 0 4px 16px rgba(102, 126, 234, 0.2);
|
||||
}
|
||||
|
||||
/* 选择器美化 */
|
||||
:deep(.form-input .el-select .el-input .el-input__wrapper) {
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.option-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* 难度按钮组美化 */
|
||||
.difficulty-group {
|
||||
display: flex;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
:deep(.difficulty-group .el-radio-button__inner) {
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
padding: 12px 20px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
background: #f8f9fc;
|
||||
color: #5a6c7d;
|
||||
}
|
||||
|
||||
:deep(.difficulty-group .el-radio-button:first-child .el-radio-button__inner) {
|
||||
border-radius: 12px 0 0 12px;
|
||||
}
|
||||
|
||||
:deep(.difficulty-group .el-radio-button:last-child .el-radio-button__inner) {
|
||||
border-radius: 0 12px 12px 0;
|
||||
}
|
||||
|
||||
:deep(.difficulty-group .el-radio-button.is-active .el-radio-button__inner) {
|
||||
background: linear-gradient(45deg, #667eea, #764ba2);
|
||||
color: white;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
|
||||
}
|
||||
|
||||
:deep(.difficulty-group .el-radio-button__inner:hover) {
|
||||
background: #e8ecf4;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
:deep(.difficulty-group .el-radio-button.is-active .el-radio-button__inner:hover) {
|
||||
background: linear-gradient(45deg, #667eea, #764ba2);
|
||||
}
|
||||
|
||||
/* 日期选择器美化 */
|
||||
:deep(.form-input .el-date-editor .el-input__wrapper) {
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
/* 底部按钮美化 */
|
||||
:deep(.add-homework-dialog .el-dialog__footer) {
|
||||
background: linear-gradient(135deg, #f8f9fc 0%, #e8ecf4 100%);
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.5);
|
||||
border-radius: 0 0 16px 16px;
|
||||
padding: 25px 30px;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
background: linear-gradient(45deg, #95a5a6, #bdc3c7);
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
padding: 12px 24px;
|
||||
font-weight: 600;
|
||||
color: white;
|
||||
transition: all 0.3s ease;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.cancel-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(149, 165, 166, 0.3);
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
background: linear-gradient(45deg, #667eea, #764ba2);
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
padding: 12px 24px;
|
||||
font-weight: 600;
|
||||
color: white;
|
||||
transition: all 0.3s ease;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.confirm-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(102, 126, 234, 0.4);
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,938 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([
|
||||
{
|
||||
date: '2024-01-20',
|
||||
name: '张三',
|
||||
email: 'zhangsan@example.com',
|
||||
tag: '开发'
|
||||
},
|
||||
{
|
||||
date: '2024-01-21',
|
||||
name: '李四',
|
||||
email: 'lisi@example.com',
|
||||
tag: '设计'
|
||||
},
|
||||
{
|
||||
date: '2024-01-22',
|
||||
name: '王五',
|
||||
email: 'wangwu@example.com',
|
||||
tag: '测试'
|
||||
},
|
||||
{
|
||||
date: '2024-01-23',
|
||||
name: '赵六',
|
||||
email: 'zhaoliu@example.com',
|
||||
tag: '产品'
|
||||
}
|
||||
])
|
||||
|
||||
// 表单数据
|
||||
const formRef = ref<FormInstance>()
|
||||
const form = ref({
|
||||
name: '',
|
||||
email: '',
|
||||
type: '',
|
||||
description: ''
|
||||
})
|
||||
|
||||
const rules = ref<FormRules>({
|
||||
name: [
|
||||
{ required: true, message: '请输入姓名', trigger: 'blur' },
|
||||
{ min: 2, max: 15, message: '长度在 2 到 15 个字符', trigger: 'blur' }
|
||||
],
|
||||
email: [
|
||||
{ required: true, message: '请输入邮箱地址', trigger: 'blur' },
|
||||
{ type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' }
|
||||
],
|
||||
type: [
|
||||
{ required: true, message: '请选择类型', trigger: 'change' }
|
||||
]
|
||||
})
|
||||
|
||||
// 对话框
|
||||
const dialogVisible = ref(false)
|
||||
|
||||
// 新增:美观提示框
|
||||
const beautifulDialogVisible = ref(false)
|
||||
|
||||
// 新增:简单美观提示框
|
||||
const simpleDialogVisible = ref(false)
|
||||
|
||||
// 表单提交
|
||||
const submitForm = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
ElMessage.success('提交成功!')
|
||||
console.log('表单数据:', form.value)
|
||||
} else {
|
||||
ElMessage.error('请检查表单输入')
|
||||
console.log('验证失败:', fields)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const resetForm = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
formEl.resetFields()
|
||||
}
|
||||
|
||||
// 编辑用户
|
||||
const handleEdit = (index: number, row: any) => {
|
||||
ElMessage.info(`编辑用户: ${row.name}`)
|
||||
console.log('编辑:', index, row)
|
||||
}
|
||||
|
||||
// 删除用户
|
||||
const handleDelete = (index: number, row: any) => {
|
||||
ElMessage.warning(`删除用户: ${row.name}`)
|
||||
tableData.value.splice(index, 1)
|
||||
console.log('删除:', index, row)
|
||||
}
|
||||
|
||||
// 新增:表格行点击事件
|
||||
const handleRowClick = (row: any) => {
|
||||
ElMessage.info(`点击行: ${row.name}`)
|
||||
console.log('点击行:', row)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="home-container">
|
||||
<el-row :gutter="20">
|
||||
<!-- 数据表格区域 -->
|
||||
<el-col :span="14">
|
||||
<el-card>
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>用户数据表格</span>
|
||||
<div class="header-buttons">
|
||||
<el-button type="primary" @click="dialogVisible = true">
|
||||
<el-icon><plus /></el-icon>
|
||||
添加用户
|
||||
</el-button>
|
||||
<el-button
|
||||
type="success"
|
||||
class="beautiful-btn"
|
||||
@click="beautifulDialogVisible = true"
|
||||
>
|
||||
<el-icon><magic-stick /></el-icon>
|
||||
精美提示
|
||||
</el-button>
|
||||
<el-button
|
||||
type="warning"
|
||||
class="simple-btn"
|
||||
@click="simpleDialogVisible = true"
|
||||
>
|
||||
<el-icon><bell /></el-icon>
|
||||
简单提示
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-table
|
||||
:data="tableData"
|
||||
style="width: 100%"
|
||||
stripe
|
||||
class="beautiful-table"
|
||||
:header-cell-style="{
|
||||
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
||||
color: 'white',
|
||||
fontWeight: '600',
|
||||
textAlign: 'center',
|
||||
border: 'none'
|
||||
}"
|
||||
:cell-style="{ textAlign: 'center', padding: '12px 0' }"
|
||||
:row-style="{ cursor: 'pointer' }"
|
||||
@row-click="handleRowClick"
|
||||
>
|
||||
<el-table-column prop="date" label="日期" width="120">
|
||||
<template #default="scope">
|
||||
<div class="date-cell">
|
||||
<el-icon class="date-icon"><calendar /></el-icon>
|
||||
<span class="date-text">{{ scope.row.date }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" label="姓名" width="120">
|
||||
<template #default="scope">
|
||||
<div class="name-cell">
|
||||
<el-icon class="user-icon"><user /></el-icon>
|
||||
<span class="name-text">{{ scope.row.name }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="email" label="邮箱">
|
||||
<template #default="scope">
|
||||
<div class="email-cell">
|
||||
<el-icon class="email-icon"><message /></el-icon>
|
||||
<span class="email-text">{{ scope.row.email }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="tag" label="部门" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag
|
||||
:type="scope.row.tag === '开发' ? '' : scope.row.tag === '设计' ? 'success' : scope.row.tag === '测试' ? 'warning' : 'info'"
|
||||
disable-transitions
|
||||
>
|
||||
{{ scope.row.tag }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="150">
|
||||
<template #default="scope">
|
||||
<div class="action-buttons">
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
class="edit-btn"
|
||||
@click.stop="handleEdit(scope.$index, scope.row)"
|
||||
>
|
||||
<el-icon><edit /></el-icon>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
size="small"
|
||||
type="danger"
|
||||
class="delete-btn"
|
||||
@click.stop="handleDelete(scope.$index, scope.row)"
|
||||
>
|
||||
<el-icon><delete /></el-icon>
|
||||
删除
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<!-- 侧边栏区域 -->
|
||||
<el-col :span="10">
|
||||
<el-card>
|
||||
<template #header>
|
||||
<span>快速统计</span>
|
||||
</template>
|
||||
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-statistic title="总用户数" :value="tableData.length" />
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-statistic title="活跃度" value="98.5%" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-divider />
|
||||
|
||||
<el-progress :percentage="85" color="#409eff" />
|
||||
<p style="margin-top: 10px; color: #666;">项目进度</p>
|
||||
|
||||
<el-divider />
|
||||
|
||||
<el-steps :active="2" finish-status="success">
|
||||
<el-step title="项目初始化" />
|
||||
<el-step title="功能开发" />
|
||||
<el-step title="测试部署" />
|
||||
<el-step title="上线运营" />
|
||||
</el-steps>
|
||||
</el-card>
|
||||
|
||||
<el-card style="margin-top: 20px;">
|
||||
<template #header>
|
||||
<span>系统通知</span>
|
||||
</template>
|
||||
|
||||
<el-timeline>
|
||||
<el-timeline-item timestamp="2024-01-20 10:18" type="primary">
|
||||
<el-card>
|
||||
<h4>ElementPlus 集成完成</h4>
|
||||
<p>成功将 ElementPlus 组件库集成到项目中</p>
|
||||
</el-card>
|
||||
</el-timeline-item>
|
||||
<el-timeline-item timestamp="2024-01-20 09:45" type="success">
|
||||
<el-card>
|
||||
<h4>Vue 3 项目创建</h4>
|
||||
<p>使用最新的 Vue 3 + TypeScript 技术栈</p>
|
||||
</el-card>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 添加用户对话框 -->
|
||||
<el-dialog v-model="dialogVisible" title="添加新用户" width="500px">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="80px"
|
||||
>
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input v-model="form.name" placeholder="请输入姓名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="邮箱" prop="email">
|
||||
<el-input v-model="form.email" placeholder="请输入邮箱" />
|
||||
</el-form-item>
|
||||
<el-form-item label="部门" prop="type">
|
||||
<el-select v-model="form.type" placeholder="请选择部门">
|
||||
<el-option label="开发" value="开发" />
|
||||
<el-option label="设计" value="设计" />
|
||||
<el-option label="测试" value="测试" />
|
||||
<el-option label="产品" value="产品" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="描述">
|
||||
<el-input
|
||||
v-model="form.description"
|
||||
type="textarea"
|
||||
placeholder="请输入描述"
|
||||
:rows="3"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button @click="resetForm(formRef)">重置</el-button>
|
||||
<el-button type="primary" @click="submitForm(formRef)">确定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 新增:美观提示框 -->
|
||||
<el-dialog
|
||||
v-model="beautifulDialogVisible"
|
||||
:show-close="false"
|
||||
width="600px"
|
||||
center
|
||||
class="beautiful-dialog"
|
||||
>
|
||||
<template #header>
|
||||
<div class="dialog-header">
|
||||
<div class="header-icon">
|
||||
<el-icon size="40"><star-filled /></el-icon>
|
||||
</div>
|
||||
<h2 class="header-title">🎉 欢迎体验精美界面</h2>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="dialog-content">
|
||||
<div class="content-section">
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon success">
|
||||
<el-icon size="24"><check /></el-icon>
|
||||
</div>
|
||||
<div class="feature-text">
|
||||
<h3>界面美观</h3>
|
||||
<p>精心设计的UI界面,带来愉悦的用户体验</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon primary">
|
||||
<el-icon size="24"><lightning /></el-icon>
|
||||
</div>
|
||||
<div class="feature-text">
|
||||
<h3>响应迅速</h3>
|
||||
<p>基于Vue 3构建,享受极速的响应体验</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon warning">
|
||||
<el-icon size="24"><trophy /></el-icon>
|
||||
</div>
|
||||
<div class="feature-text">
|
||||
<h3>功能丰富</h3>
|
||||
<p>ElementPlus组件库提供丰富的功能组件</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="message-box">
|
||||
<p class="message-text">
|
||||
✨ 这是一个精美设计的提示框示例,展示了现代化的UI设计理念。
|
||||
通过渐变背景、图标装饰和流畅动画,为用户带来视觉愉悦的交互体验。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer-beautiful">
|
||||
<el-button
|
||||
size="large"
|
||||
@click="beautifulDialogVisible = false"
|
||||
class="close-btn"
|
||||
>
|
||||
<el-icon><close /></el-icon>
|
||||
关闭
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="large"
|
||||
class="action-btn"
|
||||
@click="beautifulDialogVisible = false"
|
||||
>
|
||||
<el-icon><star /></el-icon>
|
||||
太棒了!
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 新增:简单美观提示框 -->
|
||||
<el-dialog
|
||||
v-model="simpleDialogVisible"
|
||||
:show-close="false"
|
||||
width="450px"
|
||||
center
|
||||
class="simple-dialog"
|
||||
>
|
||||
<template #header>
|
||||
<div class="simple-header">
|
||||
<div class="simple-icon">
|
||||
<el-icon size="32"><info-filled /></el-icon>
|
||||
</div>
|
||||
<h3 class="simple-title">温馨提示</h3>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="simple-content">
|
||||
<p class="simple-message">
|
||||
🌟 这是一个简洁而美观的提示框示例。通过精心的色彩搭配和简约的设计风格,
|
||||
在保持功能性的同时为用户提供清爽的视觉体验。简约不简单,美观又实用!
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="simple-footer">
|
||||
<el-button
|
||||
size="default"
|
||||
@click="simpleDialogVisible = false"
|
||||
class="simple-cancel-btn"
|
||||
>
|
||||
取消
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="default"
|
||||
class="simple-confirm-btn"
|
||||
@click="simpleDialogVisible = false"
|
||||
>
|
||||
确认
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.home-container {
|
||||
padding: 10px; /* 减少内边距 */
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.header-buttons {
|
||||
display: flex;
|
||||
gap: 10px; /* 按钮之间的间距 */
|
||||
}
|
||||
|
||||
.beautiful-btn {
|
||||
background-color: #67c23a; /* 设置按钮背景颜色 */
|
||||
border-color: #67c23a; /* 设置按钮边框颜色 */
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
/* 确保表格可以充分利用空间 */
|
||||
.el-table {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
/* 美化表格样式 */
|
||||
:deep(.beautiful-table) {
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.08);
|
||||
border: 1px solid #e8ecf4;
|
||||
}
|
||||
|
||||
:deep(.beautiful-table .el-table__header-wrapper) {
|
||||
border-radius: 12px 12px 0 0;
|
||||
}
|
||||
|
||||
:deep(.beautiful-table .el-table__body-wrapper) {
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
:deep(.beautiful-table .el-table__row) {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
:deep(.beautiful-table .el-table__row:hover) {
|
||||
background-color: #f8f9ff !important;
|
||||
transform: scale(1.01);
|
||||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.1);
|
||||
}
|
||||
|
||||
:deep(.beautiful-table .el-table__row--striped) {
|
||||
background-color: #fafbfc;
|
||||
}
|
||||
|
||||
:deep(.beautiful-table .el-table__row--striped:hover) {
|
||||
background-color: #f8f9ff !important;
|
||||
}
|
||||
|
||||
:deep(.beautiful-table .el-table__cell) {
|
||||
border-bottom: 1px solid #f0f2f5;
|
||||
padding: 16px 12px;
|
||||
}
|
||||
|
||||
:deep(.beautiful-table .el-table__header .el-table__cell) {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
|
||||
color: white !important;
|
||||
font-weight: 600 !important;
|
||||
text-align: center !important;
|
||||
border: none !important;
|
||||
padding: 18px 12px;
|
||||
}
|
||||
|
||||
/* 表格单元格美化 */
|
||||
.date-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.date-icon {
|
||||
color: #f56c6c;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.date-text {
|
||||
color: #5a6c7d;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.name-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.user-icon {
|
||||
color: #667eea;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.name-text {
|
||||
font-weight: 600;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.email-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.email-icon {
|
||||
color: #67c23a;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.email-text {
|
||||
color: #5a6c7d;
|
||||
}
|
||||
|
||||
/* 操作按钮美化 */
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.edit-btn {
|
||||
background: linear-gradient(45deg, #409eff, #67c23a);
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s ease;
|
||||
font-size: 12px;
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
.edit-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(64, 158, 255, 0.3);
|
||||
}
|
||||
|
||||
.delete-btn {
|
||||
background: linear-gradient(45deg, #f56c6c, #ff7875);
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s ease;
|
||||
font-size: 12px;
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
.delete-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(245, 108, 108, 0.3);
|
||||
}
|
||||
|
||||
/* 标签美化 */
|
||||
:deep(.el-tag) {
|
||||
border-radius: 20px;
|
||||
padding: 6px 12px;
|
||||
font-weight: 500;
|
||||
border: none;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
:deep(.el-tag--success) {
|
||||
background: linear-gradient(45deg, #67c23a, #85ce61);
|
||||
color: white;
|
||||
}
|
||||
|
||||
:deep(.el-tag--warning) {
|
||||
background: linear-gradient(45deg, #e6a23c, #f7ba2a);
|
||||
color: white;
|
||||
}
|
||||
|
||||
:deep(.el-tag--info) {
|
||||
background: linear-gradient(45deg, #909399, #b4bccc);
|
||||
color: white;
|
||||
}
|
||||
|
||||
:deep(.el-tag) {
|
||||
background: linear-gradient(45deg, #409eff, #67c23a);
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* 优化大屏幕显示 */
|
||||
@media (min-width: 1200px) {
|
||||
.home-container {
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 美化对话框样式 */
|
||||
:deep(.beautiful-dialog) {
|
||||
border-radius: 20px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
:deep(.beautiful-dialog .el-dialog__header) {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
:deep(.beautiful-dialog .el-dialog__body) {
|
||||
padding: 30px;
|
||||
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
||||
}
|
||||
|
||||
:deep(.beautiful-dialog .el-dialog__footer) {
|
||||
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
||||
padding: 20px 30px;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 30px;
|
||||
color: white;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
margin-right: 15px;
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% { transform: scale(1); }
|
||||
50% { transform: scale(1.1); }
|
||||
100% { transform: scale(1); }
|
||||
}
|
||||
|
||||
.header-title {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.content-section {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.feature-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
margin: 15px 0;
|
||||
background: white;
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
|
||||
transition: all 0.3s ease;
|
||||
animation: slideInUp 0.6s ease-out;
|
||||
}
|
||||
|
||||
.feature-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.feature-card:nth-child(1) { animation-delay: 0.1s; }
|
||||
.feature-card:nth-child(2) { animation-delay: 0.2s; }
|
||||
.feature-card:nth-child(3) { animation-delay: 0.3s; }
|
||||
|
||||
@keyframes slideInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.feature-icon {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 20px;
|
||||
color: white;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.feature-icon.success {
|
||||
background: linear-gradient(45deg, #4CAF50, #81C784);
|
||||
}
|
||||
|
||||
.feature-icon.primary {
|
||||
background: linear-gradient(45deg, #2196F3, #64B5F6);
|
||||
}
|
||||
|
||||
.feature-icon.warning {
|
||||
background: linear-gradient(45deg, #FF9800, #FFB74D);
|
||||
}
|
||||
|
||||
.feature-text {
|
||||
text-align: left;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.feature-text h3 {
|
||||
margin: 0 0 8px 0;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.feature-text p {
|
||||
margin: 0;
|
||||
color: #7f8c8d;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.message-box {
|
||||
background: white;
|
||||
border-radius: 15px;
|
||||
padding: 25px;
|
||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
|
||||
border-left: 5px solid #667eea;
|
||||
animation: fadeIn 0.8s ease-out;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
.message-text {
|
||||
font-size: 16px;
|
||||
line-height: 1.8;
|
||||
color: #2c3e50;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.dialog-footer-beautiful {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
background: #95a5a6;
|
||||
border-color: #95a5a6;
|
||||
color: white;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.close-btn:hover {
|
||||
background: #7f8c8d;
|
||||
border-color: #7f8c8d;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
background: linear-gradient(45deg, #667eea, #764ba2);
|
||||
border-color: #667eea;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.action-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
|
||||
}
|
||||
|
||||
.beautiful-btn {
|
||||
background: linear-gradient(45deg, #11998e, #38ef7d);
|
||||
border: none;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.beautiful-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 20px rgba(17, 153, 142, 0.4);
|
||||
}
|
||||
|
||||
/* 简单美观对话框样式 */
|
||||
.simple-btn {
|
||||
background: linear-gradient(45deg, #ff9a9e, #fecfef);
|
||||
border: none;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.simple-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 20px rgba(255, 154, 158, 0.4);
|
||||
}
|
||||
|
||||
:deep(.simple-dialog) {
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
:deep(.simple-dialog .el-dialog__header) {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
:deep(.simple-dialog .el-dialog__body) {
|
||||
padding: 25px 30px;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
:deep(.simple-dialog .el-dialog__footer) {
|
||||
background: #f8f9fc;
|
||||
padding: 20px 30px;
|
||||
border-top: 1px solid #e8ecf4;
|
||||
}
|
||||
|
||||
.simple-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 25px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.simple-icon {
|
||||
margin-right: 12px;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.simple-title {
|
||||
margin: 0;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.simple-content {
|
||||
text-align: center;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.simple-message {
|
||||
font-size: 15px;
|
||||
line-height: 1.6;
|
||||
color: #5a6c7d;
|
||||
margin: 0;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.simple-footer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.simple-cancel-btn {
|
||||
background: #f5f6fa;
|
||||
border-color: #ddd;
|
||||
color: #666;
|
||||
transition: all 0.3s ease;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
.simple-cancel-btn:hover {
|
||||
background: #e9ecef;
|
||||
border-color: #ccc;
|
||||
color: #555;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.simple-confirm-btn {
|
||||
background: linear-gradient(45deg, #667eea, #764ba2);
|
||||
border-color: #667eea;
|
||||
transition: all 0.3s ease;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
.simple-confirm-btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 6px 16px rgba(102, 126, 234, 0.3);
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
||||
"exclude": ["src/**/__tests__/*"],
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"extends": "@tsconfig/node22/tsconfig.json",
|
||||
"include": [
|
||||
"vite.config.*",
|
||||
"vitest.config.*",
|
||||
"cypress.config.*",
|
||||
"nightwatch.conf.*",
|
||||
"playwright.config.*",
|
||||
"eslint.config.*"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"noEmit": true,
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"types": ["node"]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import { fileURLToPath, URL } from 'node:url'
|
||||
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import vueJsx from '@vitejs/plugin-vue-jsx'
|
||||
import vueDevTools from 'vite-plugin-vue-devtools'
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
vueJsx(),
|
||||
vueDevTools(),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||
},
|
||||
},
|
||||
})
|
Loading…
Reference in New Issue