Compare commits

..

1 Commits
dev2 ... main

Author SHA1 Message Date
yangdongbit
1d7079e779 教师端 2025-08-20 13:43:43 +08:00
828 changed files with 105955 additions and 211047 deletions

View File

@ -4,4 +4,3 @@ type: "manual"
1、在接下来的每一个步骤当中请帮我实现对页面的响应式设计 1、在接下来的每一个步骤当中请帮我实现对页面的响应式设计
2、必须严格执行我给你的指令一步一步执行不得有缩减 2、必须严格执行我给你的指令一步一步执行不得有缩减
3、我们用的是naive UI组件 TSvue3

2
.env
View File

@ -1,5 +1,5 @@
# API配置 # API配置
VITE_API_BASE_URL=http://103.40.14.23:25526/jeecgboot VITE_API_BASE_URL=http://110.42.96.65:55510/api
# Mock配置 - 禁用Mock使用真实API # Mock配置 - 禁用Mock使用真实API
VITE_ENABLE_MOCK=false VITE_ENABLE_MOCK=false

View File

@ -1,7 +1,7 @@
# 开发环境配置 # 开发环境配置
# API配置 # API配置
VITE_API_BASE_URL=http://103.40.14.23:25526/jeecgboot VITE_API_BASE_URL=http://110.42.96.65:55510/api
# Mock配置 # Mock配置
# 设置为 true 使用Mock数据false 使用真实API # 设置为 true 使用Mock数据false 使用真实API

View File

@ -1,7 +1,7 @@
# 生产环境配置 # 生产环境配置
# API配置 # API配置
VITE_API_BASE_URL=http://103.40.14.23:25526/jeecgboot VITE_API_BASE_URL=http://110.42.96.65:55510/api
# Mock配置 - 生产环境禁用Mock使用真实API # Mock配置 - 生产环境禁用Mock使用真实API
VITE_ENABLE_MOCK=false VITE_ENABLE_MOCK=false

View File

@ -6,6 +6,6 @@ services:
context: . context: .
dockerfile: Dockerfile dockerfile: Dockerfile
ports: ports:
- "25527:80" - "55514:80"
container_name: vue3-nginx container_name: vue3-nginx
restart: unless-stopped restart: unless-stopped

View File

@ -1,320 +0,0 @@
# DPlayer 集成指南
## 什么是 DPlayer
**DPlayer** 是由 [DIYGod](https://github.com/DIYGod) 开发的一个开源的 HTML5 视频播放器,具有以下特点:
- 🎨 **界面美观**:现代化的设计风格
- 🎯 **轻量级**:体积小,加载快
- 🌏 **中文友好**:由中国开发者开发,中文文档完善
- 🎮 **功能丰富**:支持弹幕、快捷键、倍速播放等
- 📱 **移动端适配**:响应式设计,支持移动设备
## 主要功能特性
### 基础功能
- ✅ 播放/暂停控制
- ✅ 音量控制
- ✅ 进度条拖拽
- ✅ 全屏切换
- ✅ 倍速播放 (0.5x - 2x)
### 高级功能
- 🎯 键盘快捷键支持
- 🎨 自定义主题色
- 📝 右键菜单自定义
- 🎵 音频可视化
- 📱 移动端手势支持
### 格式支持
- MP4
- WebM
- Ogg
- HLS (.m3u8)
- FLV
- 更多格式通过插件支持
## 安装和集成
### 方法1CDN 引入(推荐用于快速测试)
```html
<!-- 在 index.html 中引入 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/dplayer@1.27.1/dist/DPlayer.min.css">
<script src="https://cdn.jsdelivr.net/npm/dplayer@1.27.1/dist/DPlayer.min.js"></script>
```
### 方法2NPM 安装(推荐用于生产环境)
```bash
npm install dplayer
```
然后在组件中导入:
```javascript
import DPlayer from 'dplayer'
import 'dplayer/dist/DPlayer.min.css'
```
## 基础使用
### 创建播放器
```javascript
const player = new DPlayer({
container: document.getElementById('dplayer'),
video: {
url: 'video.mp4',
type: 'auto'
},
autoplay: false,
theme: '#007bff',
lang: 'zh-cn'
})
```
### 事件监听
```javascript
player.on('play', () => {
console.log('视频开始播放')
})
player.on('pause', () => {
console.log('视频暂停')
})
player.on('ended', () => {
console.log('视频播放结束')
})
player.on('error', () => {
console.log('播放出错')
})
```
## 配置选项
### 基础配置
```javascript
const options = {
container: document.getElementById('dplayer'), // 容器元素
video: {
url: 'video.mp4', // 视频地址
type: 'auto', // 视频类型auto, normal, hls, flv
defaultQuality: 0, // 默认画质
pic: 'poster.jpg', // 封面图
thumbnails: 'thumbnails.jpg' // 缩略图
},
autoplay: false, // 自动播放
theme: '#007bff', // 主题色
lang: 'zh-cn', // 语言zh-cn, en
hotkey: true, // 启用快捷键
preload: 'auto', // 预加载auto, metadata, none
volume: 0.8, // 默认音量
playbackSpeed: [0.5, 0.75, 1, 1.25, 1.5, 2], // 倍速选项
contextmenu: [ // 右键菜单
{
text: '关于 DPlayer',
link: 'https://github.com/DIYGod/DPlayer'
}
]
}
```
### 高级配置
```javascript
const advancedOptions = {
// 弹幕配置
danmaku: {
id: 'dplayer-danmaku',
api: 'https://api.prprpr.me/dplayer/',
token: 'token',
maximum: 1000,
addition: ['https://api.prprpr.me/dplayer/bilibili?aid=4157142'],
user: 'DIYGod',
bottom: '15%',
unlimited: true
},
// 字幕配置
subtitle: {
url: 'subtitle.vtt',
type: 'webvtt',
fontSize: '20px',
bottom: '10%',
color: '#fff'
},
// 画质切换
video: {
url: [
{
name: '1080P',
url: 'video-1080p.mp4'
},
{
name: '720P',
url: 'video-720p.mp4'
}
],
defaultQuality: 0
}
}
```
## 在 Vue 项目中使用
### 创建 DPlayer 组件
```vue
<template>
<div class="video-player-wrapper">
<div ref="dplayerContainer" class="dplayer-container"></div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const dplayerContainer = ref()
let player = null
onMounted(() => {
// 确保 DPlayer 已加载
if (window.DPlayer) {
initPlayer()
} else {
loadDPlayer().then(() => {
initPlayer()
})
}
})
const loadDPlayer = () => {
return new Promise((resolve) => {
const cssLink = document.createElement('link')
cssLink.rel = 'stylesheet'
cssLink.href = 'https://cdn.jsdelivr.net/npm/dplayer@1.27.1/dist/DPlayer.min.css'
document.head.appendChild(cssLink)
const script = document.createElement('script')
script.src = 'https://cdn.jsdelivr.net/npm/dplayer@1.27.1/dist/DPlayer.min.js'
script.onload = resolve
document.head.appendChild(script)
})
}
const initPlayer = () => {
player = new window.DPlayer({
container: dplayerContainer.value,
video: {
url: '/video/first.mp4',
type: 'auto'
},
autoplay: false,
theme: '#007bff',
lang: 'zh-cn',
hotkey: true
})
}
onUnmounted(() => {
if (player) {
player.destroy()
}
})
</script>
<style scoped>
.video-player-wrapper {
width: 100%;
max-width: 800px;
margin: 0 auto;
}
.dplayer-container {
width: 100%;
aspect-ratio: 16/9;
}
</style>
```
## 样式定制
### 自定义主题色
```css
/* 修改播放器主题色 */
.dplayer {
--dplayer-theme: #007bff;
}
/* 自定义进度条颜色 */
.dplayer .dplayer-bar-wrap .dplayer-bar .dplayer-played {
background: #007bff;
}
/* 自定义控制按钮颜色 */
.dplayer .dplayer-icons .dplayer-icon {
color: #fff;
}
.dplayer .dplayer-icons .dplayer-icon:hover {
color: #007bff;
}
```
### 响应式设计
```css
/* 移动端适配 */
@media (max-width: 768px) {
.dplayer {
font-size: 14px;
}
.dplayer .dplayer-icons .dplayer-icon {
font-size: 16px;
}
}
```
## 快捷键支持
DPlayer 默认支持以下快捷键:
- `空格键` - 播放/暂停
- `←` - 后退 10 秒
- `→` - 前进 10 秒
- `↑` - 音量 +10%
- `↓` - 音量 -10%
- `F` - 全屏切换
- `M` - 静音切换
## 与 CKPlayer 对比
| 特性 | CKPlayer | DPlayer |
|------|----------|---------|
| 界面美观度 | ⭐⭐ | ⭐⭐⭐⭐⭐ |
| 功能丰富度 | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 移动端支持 | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 中文支持 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 社区活跃度 | ⭐⭐ | ⭐⭐⭐⭐ |
| 文档质量 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 学习成本 | ⭐⭐⭐⭐ | ⭐⭐⭐ |
## 总结
**DPlayer 是一个优秀的视频播放器选择**,特别适合:
- 🎯 需要美观界面的项目
- 🌏 中文用户群体
- 📱 重视移动端体验
- 🎨 需要自定义主题的项目
- ⚡ 追求轻量级解决方案
相比当前的 CKPlayerDPlayer 提供了更好的用户体验和更丰富的功能,是升级视频播放器的理想选择。

View File

@ -1,523 +0,0 @@
# 考试信息API使用文档
## 接口概述
`/aiol/aiolExam/getExamInfo` 接口用于获取教师名下的考试信息列表。
## 接口定义
### 请求方式
- **方法**: GET
- **路径**: `/aiol/aiolExam/getExamInfo`
- **参数**: `userId` (查询参数)
### 请求参数
| 参数名 | 类型 | 必选 | 说明 |
|--------|------|------|------|
| userId | string | 是 | 教师用户ID |
### 响应格式
```typescript
{
"success": boolean,
"message": string,
"code": number,
"result": ExamInfo[],
"timestamp": number
}
```
### ExamInfo 数据结构
```typescript
interface ExamInfo {
id: string // 考试ID
name: string // 考试名称
paperId: string // 试卷ID
startTime: string // 开始时间
endTime: string // 结束时间
totalTime: number // 考试时长(分钟)
type: number // 考试类型0=练习1=考试
status: number // 状态0=未发布1=发布中2=已结束
createBy: string // 创建人
createTime: string // 创建时间
updateBy: string // 更新人
updateTime: string // 更新时间
}
```
## 使用示例
### 1. 在API模块中调用
```typescript
import { ExamApi } from '@/api/modules/exam'
// 获取教师考试信息
const response = await ExamApi.getExamInfo('teacher_user_id')
console.log('考试信息:', response.data)
```
### 2. 在Vue组件中使用
```typescript
import { ExamApi } from '@/api/modules/exam'
import { useUserStore } from '@/stores/user'
export default {
setup() {
const userStore = useUserStore()
const loadExamInfo = async () => {
if (!userStore.user?.id) {
console.error('请先登录')
return
}
try {
const response = await ExamApi.getExamInfo(userStore.user.id.toString())
return response.data || []
} catch (error) {
console.error('加载考试信息失败:', error)
return []
}
}
return {
loadExamInfo
}
}
}
```
### 3. 在试卷管理页面中使用
```typescript
// 在 ExamLibrary.vue 中
import { ExamApi } from '@/api/modules/exam'
import { useUserStore } from '@/stores/user'
import type { ExamInfo } from '@/api/types'
const userStore = useUserStore()
const loadExamInfo = async () => {
loading.value = true
try {
const currentUser = userStore.user
if (!currentUser?.id) {
message.error('请先登录')
return
}
const response = await ExamApi.getExamInfo(currentUser.id.toString())
if (response.data && Array.isArray(response.data)) {
// 数据映射和显示逻辑
const mappedList = response.data.map((item: ExamInfo) => {
// 映射逻辑...
return {
id: item.id,
name: item.name,
// ... 其他字段映射
}
})
examData.value = mappedList
}
} catch (error) {
console.error('加载考试信息失败:', error)
message.error('加载考试信息失败')
} finally {
loading.value = false
}
}
```
## 数据映射说明
### 状态映射
```typescript
const statusMap: { [key: number]: string } = {
0: '未发布',
1: '发布中',
2: '已结束'
}
```
### 类型映射
```typescript
const categoryMap: { [key: number]: string } = {
0: '练习',
1: '考试'
}
```
### 难度映射
```typescript
const difficultyMap: { [key: number]: string } = {
0: '易',
1: '中',
2: '难'
}
```
## 错误处理
接口可能返回以下错误:
1. **401 Unauthorized**: 用户未登录或token过期
2. **403 Forbidden**: 没有权限访问
3. **500 Internal Server Error**: 服务器内部错误
建议在调用时添加适当的错误处理:
```typescript
try {
const response = await ExamApi.getExamInfo(userId)
// 处理成功响应
} catch (error) {
if (error.response?.status === 401) {
// 处理认证错误
console.error('登录已过期,请重新登录')
} else {
// 处理其他错误
console.error('获取考试信息失败:', error.message)
}
}
```
## 注意事项
1. 调用此接口前需要确保用户已登录
2. 只有教师用户才能调用此接口
3. 返回的考试信息按创建时间倒序排列
4. 建议在组件挂载时调用此接口加载数据
5. 可以根据需要添加分页、搜索等参数(需要后端支持)
## 相关文件
- API实现: `src/api/modules/exam.ts`
- 类型定义: `src/api/types.ts`
- 使用示例: `src/api/examples/getExamInfo-example.ts`
- 页面实现: `src/views/teacher/ExamPages/ExamLibrary.vue`
---
# 创建试卷API使用文档
## 接口概述
`POST /aiol/aiolPaper/add` 接口用于创建新的试卷。
## 接口定义
### 请求方式
- **方法**: POST
- **路径**: `/aiol/aiolPaper/add`
- **Content-Type**: `application/json`
### 请求参数
| 参数名 | 类型 | 必选 | 说明 |
|--------|------|------|------|
| title | string | 是 | 试卷标题 |
| generateMode | number | 否 | 组卷模式0=固定试卷组1=随机抽题组卷 |
| rules | string | 否 | 组卷规则(随机抽题时使用) |
| repoId | string | 否 | 题库ID随机抽题时使用 |
| totalScore | number | 是 | 试卷总分 |
| passScore | number | 否 | 及格分数默认总分的60% |
| requireReview | number | 否 | 是否需要批阅0=不需要1=需要 |
### 响应格式
```typescript
{
"success": boolean,
"message": string,
"code": number,
"result": string, // 试卷ID
"timestamp": number
}
```
## 使用示例
### 1. 在API模块中调用
```typescript
import { ExamApi } from '@/api/modules/exam'
// 创建固定试卷组
const response = await ExamApi.createExamPaper({
title: '数学期末考试试卷',
generateMode: 0,
totalScore: 100,
passScore: 60,
requireReview: 0
})
console.log('试卷ID:', response.data)
```
### 2. 在Vue组件中使用
```typescript
// 在 AddExam.vue 中
const saveExam = async () => {
try {
const apiData = {
title: examForm.title,
generateMode: examForm.type === 1 ? 0 : 1,
rules: '',
repoId: '',
totalScore: examForm.totalScore,
passScore: examForm.passScore || Math.floor(examForm.totalScore * 0.6),
requireReview: examForm.useAIGrading ? 1 : 0
}
const response = await ExamApi.createExamPaper(apiData)
console.log('创建试卷成功:', response.data)
} catch (error) {
console.error('创建试卷失败:', error)
}
}
```
### 3. 不同组卷模式示例
```typescript
// 固定试卷组
const fixedPaper = {
title: '固定试卷组示例',
generateMode: 0,
rules: '',
repoId: '',
totalScore: 100,
passScore: 60,
requireReview: 0
}
// 随机抽题组卷
const randomPaper = {
title: '随机抽题组卷示例',
generateMode: 1,
rules: '{"difficulty": [1, 2, 3], "types": [0, 1, 2], "count": 20}',
repoId: 'repo_123',
totalScore: 100,
passScore: 60,
requireReview: 1
}
```
## 相关文件
- API实现: `src/api/modules/exam.ts`
- 页面实现: `src/views/teacher/ExamPages/AddExam.vue`
- 使用示例: `src/api/examples/createPaper-example.ts`
---
# 删除试卷API使用文档
## 接口概述
删除试卷相关的API接口包括单个删除和批量删除功能。
## 接口定义
### 1. 删除单个试卷
- **方法**: DELETE
- **路径**: `/aiol/aiolPaper/delete?id={paperId}`
- **参数**: `id` (查询参数) - 试卷ID
### 2. 批量删除试卷
- **实现方式**: 循环调用单个删除接口(因为后端可能不支持批量删除接口)
- **方法**: 内部调用多个 `DELETE /aiol/aiolPaper/delete?id={paperId}`
- **参数**: `ids: string[]` - 试卷ID数组
### 响应格式
**单个删除响应**:
```typescript
{
"success": boolean,
"message": string,
"code": number,
"result": string,
"timestamp": number
}
```
**批量删除响应**:
```typescript
{
"success": boolean,
"message": string,
"code": number,
"result": {
"success": number, // 成功删除的数量
"failed": number, // 失败删除的数量
"total": number, // 总数量
"errors": string[] // 错误信息数组
},
"timestamp": number
}
```
## 使用示例
### 1. 删除单个试卷
```typescript
import { ExamApi } from '@/api/modules/exam'
// 删除单个试卷
const response = await ExamApi.deleteExamPaper('1962379646322384897')
console.log('删除结果:', response.data)
```
### 2. 批量删除试卷
```typescript
// 批量删除试卷
const paperIds = ['1962379646322384897', '1966450638717292545']
const response = await ExamApi.batchDeleteExamPapers(paperIds)
console.log('批量删除结果:', response.data)
```
### 3. 在Vue组件中使用使用 Naive UI 对话框组件)
```typescript
// 在 ExamLibrary.vue 中
import { useDialog, useMessage } from 'naive-ui'
const dialog = useDialog()
const message = useMessage()
const handleDeletePaper = async (row: any) => {
try {
// 使用 Naive UI 对话框组件
dialog.warning({
title: '确认删除',
content: `确定要删除试卷"${row.name}"吗?此操作不可撤销。`,
positiveText: '确定删除',
negativeText: '取消',
onPositiveClick: async () => {
try {
// 调用删除API
const response = await ExamApi.deleteExamPaper(row.id)
// 显示成功消息
message.success('试卷删除成功!')
// 重新加载试卷列表
await loadExamPaperList()
} catch (error) {
console.error('删除试卷失败:', error)
message.error('删除试卷失败,请重试')
}
}
})
} catch (error) {
console.error('删除试卷失败:', error)
message.error('删除试卷失败,请重试')
}
}
// 批量删除示例
const handleBatchDelete = async () => {
if (checkedRowKeys.value.length === 0) {
message.warning('请先选择要删除的试卷')
return
}
try {
// 使用 Naive UI 对话框组件
dialog.error({
title: '确认批量删除',
content: `确定要删除选中的 ${checkedRowKeys.value.length} 个试卷吗?此操作不可撤销。`,
positiveText: '确定删除',
negativeText: '取消',
onPositiveClick: async () => {
try {
// 调用批量删除API
const response = await ExamApi.batchDeleteExamPapers(checkedRowKeys.value as string[])
// 显示成功消息
message.success(`成功删除 ${checkedRowKeys.value.length} 个试卷!`)
// 清空选中状态
checkedRowKeys.value = []
// 重新加载试卷列表
await loadExamPaperList()
} catch (error) {
console.error('批量删除试卷失败:', error)
message.error('批量删除试卷失败,请重试')
}
}
})
} catch (error) {
console.error('批量删除试卷失败:', error)
message.error('批量删除试卷失败,请重试')
}
}
```
### 4. 错误处理
```typescript
const deletePaperWithErrorHandling = async (paperId: string) => {
try {
const response = await ExamApi.deleteExamPaper(paperId)
if (response.data === 'success') {
return { success: true, message: '删除成功' }
} else {
return { success: false, message: '删除失败,请重试' }
}
} catch (error: any) {
if (error.response?.status === 404) {
return { success: false, message: '试卷不存在' }
} else if (error.response?.status === 403) {
return { success: false, message: '没有权限删除此试卷' }
}
return { success: false, message: '删除失败,请检查网络连接' }
}
}
```
## 功能特性
### 单个删除
- 支持删除单个试卷
- 使用 Naive UI 警告对话框组件
- 删除成功后自动刷新列表
- 完整的错误处理
### 批量删除
- 支持同时删除多个试卷
- 循环调用单个删除接口(避免后端接口不存在的问题)
- 逐个删除,避免对服务器造成过大压力
- 详细的删除结果反馈(成功/失败数量)
- 使用 Naive UI 错误对话框组件(更醒目的警告)
- 删除后清空选中状态
### 用户体验
- **美观的确认对话框**: 使用 Naive UI 组件,样式统一美观
- **不同类型的对话框**: 单个删除使用 warning批量删除使用 error
- **成功/失败消息提示**: 使用 Naive UI 的 message 组件
- **按钮状态管理**: 批量删除按钮在未选中时禁用
- **实时更新选中数量显示**: 动态显示选中的试卷数量
- **异步操作处理**: 在对话框确认后才执行删除操作
## 相关文件
- API实现: `src/api/modules/exam.ts`
- 页面实现: `src/views/teacher/ExamPages/ExamLibrary.vue`
- 使用示例: `src/api/examples/deletePaper-example.ts`

View File

@ -2,15 +2,13 @@
<html lang="zh-CN"> <html lang="zh-CN">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<link rel="icon" href="/logo/logo1.png"> <link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>在线学习平台</title> <title>在线学习平台</title>
<meta name="description" content="专业的在线学习平台,提供优质的编程和技术课程"> <meta name="description" content="专业的在线学习平台,提供优质的编程和技术课程">
<meta name="keywords" content="在线学习,编程课程,技术培训,Vue.js,React,Node.js"> <meta name="keywords" content="在线学习,编程课程,技术培训,Vue.js,React,Node.js">
<!-- CKPlayer CSS --> <!-- CKPlayer CSS -->
<link rel="stylesheet" href="/ckplayer/css/ckplayer.css"> <link rel="stylesheet" href="/ckplayer/css/ckplayer.css">
<!-- HLS.js for m3u8 playback in CKPlayer -->
<script src="/ckplayer/hls.js/hls.min.js"></script>
<!-- CKPlayer JS --> <!-- CKPlayer JS -->
<script src="/ckplayer/js/ckplayer.js"></script> <script src="/ckplayer/js/ckplayer.js"></script>
</head> </head>

1094
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -13,28 +13,16 @@
"test:ui": "vitest --ui" "test:ui": "vitest --ui"
}, },
"dependencies": { "dependencies": {
"@types/sortablejs": "^1.15.8",
"@vicons/ionicons5": "^0.13.0", "@vicons/ionicons5": "^0.13.0",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.12",
"@wangeditor/plugin-upload-attachment": "^1.1.0",
"axios": "^1.11.0", "axios": "^1.11.0",
"ckplayer": "^3.1.2", "ckplayer": "^3.1.2",
"dplayer": "^1.27.1",
"echarts": "5.6.0",
"naive-ui": "^2.42.0", "naive-ui": "^2.42.0",
"naive-ui-editor": "^1.0.6",
"pinia": "^3.0.3", "pinia": "^3.0.3",
"quill": "^2.0.3",
"vue": "^3.5.17", "vue": "^3.5.17",
"vue-echarts": "7.0.3",
"vue-i18n": "^9.14.5", "vue-i18n": "^9.14.5",
"vue-quill-editor": "^3.0.6", "vue-router": "^4.5.1"
"vue-router": "^4.5.1",
"vuedraggable": "^4.1.0"
}, },
"devDependencies": { "devDependencies": {
"@types/dplayer": "^1.25.5",
"@types/node": "^24.0.15", "@types/node": "^24.0.15",
"@vitejs/plugin-vue": "^6.0.0", "@vitejs/plugin-vue": "^6.0.0",
"typescript": "^5.8.3", "typescript": "^5.8.3",

916
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 625 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 806 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 821 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 562 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 775 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 585 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 917 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 834 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1011 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 908 B

After

Width:  |  Height:  |  Size: 812 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 944 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 844 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 KiB

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 368 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 263 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 352 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 447 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 724 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 516 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 858 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 252 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 547 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 594 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 680 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 359 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 438 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 858 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 594 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 547 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 273 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 394 KiB

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 359 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 812 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Some files were not shown because too many files have changed in this diff Show More