6 Commits

Author SHA1 Message Date
rjl
3d3f7afcd2 style(results): Remove unnecessary blank line in results detail view
- Remove extra blank line between variable declarations for cleaner code formatting
- Improve code consistency and readability in the component
2026-03-20 17:05:39 +08:00
rjl
18e3f6f7f2 feat(admin): 优化大屏开发体验并完善用户界面组件
- 新增大屏开发调试指南文档,包含设计基准、调试方法和字体配置说明
- 添加字体大小预览工具,支持多分辨率视口切换(2048x1080/1920x1080/3840x2160)
- 新增字体资源 README 文档和团队标题背景图片
- 优化用户界面背景图片(title-bg3.png、title-bg4.png)
- 更新 ActionButton 和 CompetitionLayout 组件样式
- 完善用户模块各页面布局(分析、封面、抽签、游戏、规则、团队)
- 优化题目渲染器组件和成绩详情页面
- 更新 UnoCSS 配置以支持大屏字体缩放方案
2026-03-20 17:05:23 +08:00
rjl
e061f46e66 chore(config): 优化Kiro配置并调整UI组件样式
- 更新Kiro AI助手配置,新增强制语言和中文模式设置
- 添加用户排名背景框图片资源
- 优化CompetitionLayout组件标题样式(字体大小和字间距调整)
- 优化用户封面页面卡片布局,根据屏幕尺寸动态调整顶部padding
- 删除联想对对碰题库数据文件
2026-03-19 14:52:36 +08:00
rjl
7d49143ae0 feat(admin): 新增UUID生成工具并优化模板管理
- 新增 uuid.ts 工具函数,提供原生和兼容性 UUID 生成方案
- 更新模板详情页面,使用 generateUUID() 替代 crypto.randomUUID()
- 模板列表新增页码字段显示
- 优化模板列表组件代码格式,改进可读性
- 更新 Git 提交消息规范文档,强制使用中文描述和具体要求
2026-03-19 11:16:01 +08:00
rjl
d1f6044a6c chore(config): 配置 Kiro AI 助手并规范化 Git 提交消息
- 新增 .kiro/settings/kiro.json 配置文件,设置 AI 助手语言为中文
- 新增 .kiro/steering/chinese-commit-messages.md 文档,规范化项目 Git 提交消息格式
- 更新 .vscode/settings.json,添加 Kiro AI 助手和 Git 相关配置
- 优化 QuestionConfigCard.vue 中时间选项的排序逻辑
- 重新启用 cover/index.vue 中的 watch 监听器并优化代码格式
- 优化 teams/index.vue 的代码结构和可读性
2026-03-19 09:35:34 +08:00
rjl
9a80fd9fa1 feat(question-importer): Replace poetry knowledge with association game questions
- Add new association game question bank (联想对对碰.json) with 25 classical poetry matching questions
- Remove outdated poetry knowledge question set (诗词常识.json)
- Update store with new association game data
- Expand question variety to include poetry-based word association challenges
2026-03-18 17:52:44 +08:00
28 changed files with 930 additions and 329 deletions

9
.kiro/settings/kiro.json Normal file
View File

@ -0,0 +1,9 @@
{
"kiro.ai.language": "zh-CN",
"kiro.ai.commitMessage.language": "chinese",
"kiro.ai.commitMessage.forceLanguage": "zh-CN",
"kiro.git.commitMessageLanguage": "zh-CN",
"kiro.assistant.locale": "zh-CN",
"kiro.assistant.language": "chinese",
"kiro.assistant.alwaysUseChinese": true
}

View File

@ -0,0 +1,110 @@
---
inclusion: auto
---
# Git 提交消息规范
**重要:所有提交消息必须使用中文!**
本项目严格遵循 [Conventional Commits](https://www.conventionalcommits.org/) 规范。
## 提交消息格式
```
<type>(<scope>): <subject>
<body>
<footer>
```
### 必需部分
#### Type (类型)
提交的类型必须是以下之一:
- **feat**: 新功能 (feature)
- **fix**: 修复 bug
- **docs**: 仅文档更改
- **style**: 不影响代码含义的更改(空格、格式化、缺少分号等)
- **refactor**: 既不修复 bug 也不添加功能的代码更改
- **perf**: 提高性能的代码更改
- **test**: 添加缺失的测试或更正现有测试
- **build**: 影响构建系统或外部依赖的更改示例范围webpack, npm, vite
- **ci**: 对 CI 配置文件和脚本的更改示例范围GitHub Actions, GitLab CI
- **chore**: 其他不修改 src 或测试文件的更改
- **revert**: 回退之前的提交
#### Subject (主题)
- **必须使用中文描述**
- 使用简洁的语言描述本次提交的更改
- 不超过 50 个字符
- 首字母小写
- 结尾不加句号
### 可选部分
#### Scope (范围)
用于说明提交影响的范围,例如:
- **component**: 组件相关
- **api**: API 相关
- **router**: 路由相关
- **store**: 状态管理相关
- **utils**: 工具函数相关
- **styles**: 样式相关
- **deps**: 依赖项相关
#### Body (正文)
- 详细描述本次提交的动机和更改内容
- 可以分多行
- 应该说明"是什么"和"为什么",而不是"怎么做"
#### Footer (页脚)
- 用于关闭 Issue 或描述破坏性变更
- Breaking Changes 必须在页脚中以 `BREAKING CHANGE:` 开头
- 关闭 Issue 使用 `Closes #issue号`
## 示例(必须使用中文)
### 简单的功能添加
```
feat(article): 添加文章搜索功能
```
### 修复 bug
```
fix(login): 修复登录状态未持久化的问题
```
### 包含详细描述
```
feat(editor): 支持 markdown 实时预览
添加了一个新的编辑器组件,支持 markdown 的实时预览功能。
用户在编辑时可以同时看到渲染后的效果,提升编辑体验。
Closes #123
```
### 破坏性变更
```
feat(api): 重构用户认证 api
BREAKING CHANGE: 用户认证接口从 /api/auth 迁移到 /api/v2/auth
旧接口将在下一个版本中移除。客户端需要更新 API 端点。
```
## 重要规则
1. **严格遵循格式**: `<type>(<scope>): <subject>`
2. **type 必须小写**: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
3. **subject 必须使用中文**: 不要使用英文描述
4. **subject 首字母小写**: 不要大写开头
5. **subject 不加句号**: 结尾不要加标点符号
6. **不超过 50 字符**: subject 部分要简洁
7. **破坏性变更**: 必须在 body 中以 `BREAKING CHANGE:` 开头说明
## 生成提交消息时的要求
- 始终使用中文
- 动词开头(如:添加、修复、更新、优化、重构)
- 描述要具体,避免模糊的表述
- 如果有多个更改,选择最主要的作为 subject

14
.vscode/settings.json vendored
View File

@ -42,5 +42,17 @@
"Echarts",
"Typeit"
],
"kiroAgent.configureMCP": "Disabled" // `
// Kiro AI 助手配置
"kiroAgent.configureMCP": "Disabled",
"kiro.ai.language": "zh-CN",
"kiro.ai.commitMessage.language": "chinese",
"kiro.git.commitMessageLanguage": "zh-CN",
"kiro.assistant.locale": "zh-CN",
// Git 配置
"git.inputValidationLength": 72,
// GitHub Copilot 语言设置(如果安装了)
"github.copilot.chat.localeOverride": "zh-CN"
}

View File

@ -0,0 +1,110 @@
# 大屏开发调试指南
## 项目配置
- **设计基准**: 2048 x 1080
- **缩放方案**: VScaleScreen
- **目标设备**: 超级大屏(投屏显示)
## 开发调试方法
### 方法 1: Chrome DevTools 自定义设备(推荐)
1. 打开 Chrome DevTools (F12)
2. 点击设备模拟按钮 (Ctrl/Cmd + Shift + M)
3. 在设备下拉菜单中选择 "Edit..."
4. 添加自定义设备:
- Device Name: `Large Screen 2048x1080`
- Width: `2048`
- Height: `1080`
- Device pixel ratio: `1`
- User agent string: (保持默认)
5. 选择刚创建的设备进行调试
### 方法 2: 浏览器窗口缩放
1. 将浏览器窗口调整为合适大小
2. 使用浏览器缩放功能 (Ctrl/Cmd + 鼠标滚轮)
3. 调整到能看到完整布局的比例
### 方法 3: 响应式设计模式
在 DevTools 中:
1. 选择 "Responsive" 模式
2. 手动输入宽度: `2048`
3. 手动输入高度: `1080`
## 字体大小说明
当前字体配置已针对 2048x1080 优化:
| Class | 实际大小 | 适用场景 |
|-------|---------|---------|
| `text-xs` | 12.8px | 辅助文字、标注 |
| `text-sm` | 15.2px | 次要文字 |
| `text-base` | 17.6px | 正文 |
| `text-lg` | 20.8px | 小标题 |
| `text-xl` | 24px | 中标题 |
| `text-2xl` | 28px | 大标题 |
| `text-3xl` | 33.6px | 特大标题 |
| `text-4xl` | 40px | 主标题 |
| `text-5xl` | 51.2px | 超大标题 |
| `text-6xl` | 64px | 巨大标题 |
## VScaleScreen 工作原理
```
设计基准 (2048x1080)
VScaleScreen 自动缩放
实际显示设备 (任意分辨率)
```
**示例:**
- 在 1920x1080 屏幕上:内容会略微缩小
- 在 3840x2160 (4K) 屏幕上:内容会放大约 2 倍
- 在更大的 LED 屏上:内容会等比例放大
## 常见问题
### Q: 在我的电脑上字体看起来太大了?
A: 这是正常的!因为你的设计基准 (2048x1080) 比普通电脑屏幕大。请使用上述方法在正确的分辨率下调试。
### Q: 如何确认实际大屏的分辨率?
A:
1. 询问现场技术人员
2. 常见大屏分辨率:
- 1920x1080 (Full HD)
- 2560x1440 (2K)
- 3840x2160 (4K)
- 7680x4320 (8K)
### Q: 需要修改 VScaleScreen 的尺寸吗?
A: 通常不需要。保持 2048x1080 即可VScaleScreen 会自动适配。除非:
- 实际大屏比例不是 16:9
- 需要针对特定分辨率优化
### Q: 如何微调字体大小?
A: 修改 `uno.config.ts` 中的 `fontSize` 配置,然后重启开发服务器。
## 测试清单
部署前请确认:
- [ ] 在 2048x1080 分辨率下所有文字清晰可读
- [ ] 所有布局元素位置正确
- [ ] 动画效果流畅
- [ ] 图片清晰不模糊(建议使用 2x 或 3x 分辨率的图片)
- [ ] 在实际大屏上测试(如果可能)
## 性能优化建议
1. **图片资源**: 使用 WebP 格式,准备高分辨率版本
2. **字体**: 使用 Web Font确保在大屏上渲染清晰
3. **动画**: 使用 CSS transform 和 opacity避免触发重排
4. **测试**: 在接近实际大屏的设备上测试性能
## 联系与支持
如有问题,请联系开发团队。

View File

@ -0,0 +1,239 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>字体大小预览 - 2048x1080</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family:
-apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei',
sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 40px;
min-height: 100vh;
}
.container {
max-width: 2048px;
margin: 0 auto;
background: white;
border-radius: 20px;
padding: 60px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
}
h1 {
text-align: center;
color: #333;
margin-bottom: 20px;
font-size: 3rem;
}
.info {
text-align: center;
color: #666;
margin-bottom: 60px;
font-size: 1.2rem;
}
.preview-item {
display: flex;
align-items: center;
padding: 20px;
margin-bottom: 20px;
background: #f8f9fa;
border-radius: 10px;
border-left: 4px solid #667eea;
}
.label {
width: 200px;
font-weight: bold;
color: #667eea;
font-size: 1.1rem;
}
.size-info {
width: 150px;
color: #999;
font-size: 0.95rem;
}
.sample {
flex: 1;
color: #333;
}
/* UnoCSS 字体大小映射 */
.text-xs {
font-size: 0.8rem;
}
.text-sm {
font-size: 0.95rem;
}
.text-base {
font-size: 1.1rem;
}
.text-lg {
font-size: 1.3rem;
}
.text-xl {
font-size: 1.5rem;
}
.text-2xl {
font-size: 1.75rem;
}
.text-3xl {
font-size: 2.1rem;
}
.text-4xl {
font-size: 2.5rem;
}
.text-5xl {
font-size: 3.2rem;
}
.text-6xl {
font-size: 4rem;
}
.text-7xl {
font-size: 5rem;
}
.text-8xl {
font-size: 6.5rem;
}
.text-9xl {
font-size: 8.5rem;
.controls {
position: fixed;
top: 20px;
right: 20px;
background: white;
padding: 20px;
border-radius: 10px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.controls button {
display: block;
width: 100%;
padding: 10px 20px;
margin-bottom: 10px;
background: #667eea;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 1rem;
}
.controls button:hover {
background: #5568d3;
}
.current-size {
text-align: center;
color: #666;
font-size: 0.9rem;
margin-top: 10px;
}
</style>
</head>
<body>
<div class="controls">
<button onclick="setViewport(2048, 1080)">2048x1080 (设计基准)</button>
<button onclick="setViewport(1920, 1080)">1920x1080 (Full HD)</button>
<button onclick="setViewport(3840, 2160)">3840x2160 (4K)</button>
<div class="current-size" id="currentSize">当前窗口: <span id="sizeDisplay"></span></div>
</div>
<div class="container">
<h1>字体大小预览</h1>
<div class="info">设计基准: 2048 x 1080 | 使用 VScaleScreen 自动缩放</div>
<div class="preview-item">
<div class="label">text-xs</div>
<div class="size-info">0.8rem (12.8px)</div>
<div class="sample text-xs">辅助文字、标注信息 - The quick brown fox jumps over the lazy dog</div>
</div>
<div class="preview-item">
<div class="label">text-sm</div>
<div class="size-info">0.95rem (15.2px)</div>
<div class="sample text-sm">次要文字内容 - The quick brown fox jumps over the lazy dog</div>
</div>
<div class="preview-item">
<div class="label">text-base</div>
<div class="size-info">1.1rem (17.6px)</div>
<div class="sample text-base">正文内容 - The quick brown fox jumps over the lazy dog</div>
</div>
<div class="preview-item">
<div class="label">text-lg</div>
<div class="size-info">1.3rem (20.8px)</div>
<div class="sample text-lg">小标题 - The quick brown fox jumps over the lazy dog</div>
</div>
<div class="preview-item">
<div class="label">text-xl</div>
<div class="size-info">1.5rem (24px)</div>
<div class="sample text-xl">中标题 - The quick brown fox jumps over the lazy dog</div>
</div>
<div class="preview-item">
<div class="label">text-2xl</div>
<div class="size-info">1.75rem (28px)</div>
<div class="sample text-2xl">大标题 - 重庆市教育学会</div>
</div>
<div class="preview-item">
<div class="label">text-3xl</div>
<div class="size-info">2.1rem (33.6px)</div>
<div class="sample text-3xl">特大标题 - 阅读之星展示活动</div>
</div>
<div class="preview-item">
<div class="label">text-4xl</div>
<div class="size-info">2.5rem (40px)</div>
<div class="sample text-4xl">主标题 - 队伍名单</div>
</div>
<div class="preview-item">
<div class="label">text-5xl</div>
<div class="size-info">3.2rem (51.2px)</div>
<div class="sample text-5xl">超大标题 - 星辞海遨游</div>
</div>
<div class="preview-item">
<div class="label">text-6xl</div>
<div class="size-info">4rem (64px)</div>
<div class="sample text-6xl">巨大标题 - 开始答题</div>
</div>
</div>
<script>
function setViewport(width, height) {
// 这个函数只是提示,实际需要在浏览器 DevTools 中手动设置
alert(
`请在浏览器 DevTools 中设置视口为 ${width}x${height}\n\n步骤:\n1. 按 F12 打开 DevTools\n2. 按 Ctrl+Shift+M 进入响应式模式\n3. 输入宽度: ${width}\n4. 输入高度: ${height}`,
)
function updateSize() {
const width = window.innerWidth
const height = window.innerHeight
document.getElementById('sizeDisplay').textContent = `${width}x${height}`
}
updateSize();
window.addEventListener('resize', updateSize)
</script>
</body>
</html>

View File

@ -0,0 +1,33 @@
# 拼音字体说明
## 需要的字体文件
为了正确显示拼音声调符号,需要使用支持拼音的字体。
### 推荐字体:
1. **GB Pinyinok-B** - 专业拼音字体
2. **方正楷体拼音** - 楷体风格拼音字体
3. **华文楷体拼音** - 华文系列拼音字体
### 字体文件放置位置:
```
apps/admin/src/assets/fonts/
├── GBPinyinok-B.ttf
├── GBPinyinok-B.woff2
└── GBPinyinok-B.woff
```
### 如何获取字体:
1. 从系统字体库复制macOS: /Library/Fonts/
2. 从字体网站下载(需要商业授权)
3. 使用开源拼音字体
### 字体格式转换:
如果只有 .ttf 文件,可以使用在线工具转换为 woff2 格式:
- https://cloudconvert.com/ttf-to-woff2
- https://www.fontsquirrel.com/tools/webfont-generator
### 注意事项:
- 确保字体文件有合法的使用授权
- woff2 格式文件最小,加载最快
- 字体文件较大时考虑使用 CDN

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

After

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 306 KiB

After

Width:  |  Height:  |  Size: 533 KiB

View File

@ -2,39 +2,42 @@
import { computed } from 'vue'
import defaultBtnBg from '@/assets/imgs/user/btn-bg.png'
const props = defineProps({
text: {
type: String,
default: '下一步',
},
disabled: {
type: Boolean,
default: false,
},
theme: {
type: String as () => 'primary' | 'light',
default: 'primary',
},
type: {
type: String as () => 'button' | 'text' | 'custom',
default: 'button',
},
btnBg: {
type: String,
default: defaultBtnBg,
},
fontSize: {
type: Number,
default: 30,
},
interface Props {
text?: string
disabled?: boolean
theme?: 'primary' | 'light'
type?: 'button' | 'text' | 'custom'
btnBg?: string
fontSize?: number | string
}
const props = withDefaults(defineProps<Props>(), {
text: '下一步',
disabled: false,
theme: 'primary',
type: 'button',
btnBg: defaultBtnBg,
fontSize: '2.4rem',
})
const emits = defineEmits(['click'])
const emits = defineEmits<{
click: []
}>()
const isCustom = computed(() => props.type === 'custom')
const customBg = computed(() => `url(${props.btnBg}) no-repeat center / 100% 100%`)
const fontSizeValue = computed(() => {
// 如果已经是带单位的字符串(如 '2.4rem', '30px'),直接返回
if (typeof props.fontSize === 'string' && /^[\d.]+(?:px|rem|em)$/.test(props.fontSize)) {
return props.fontSize
}
// 如果是纯数字或数字字符串,添加 px 单位
const size = typeof props.fontSize === 'number' ? props.fontSize : Number.parseFloat(props.fontSize)
return Number.isNaN(size) ? '2.4rem' : `${size}px`
})
function handleClick() {
if (!props.disabled) {
emits('click')
@ -68,11 +71,13 @@ function handleClick() {
border: none;
outline: none;
font-family: inherit;
user-select: none;
&.is-disabled {
cursor: not-allowed;
filter: grayscale(1);
// filter: grayscale(1);
opacity: 0.7;
pointer-events: none;
&:hover,
&:active {
@ -82,7 +87,7 @@ function handleClick() {
}
}
// standard: type="button" | type="text"
// Standard button styles: type="button" | type="text"
.standard-btn {
width: 50px;
height: 50px;
@ -91,13 +96,13 @@ function handleClick() {
background: #eb5e55;
box-shadow: 0 8px 0 #fcc64f;
&:hover {
&:hover:not(.is-disabled) {
transform: translateY(-2px);
filter: brightness(1.05);
box-shadow: 0 10px 0 #fcc64f;
}
&:active {
&:active:not(.is-disabled) {
transform: translateY(4px);
box-shadow: 0 2px 0 #fcc64f;
}
@ -107,7 +112,7 @@ function handleClick() {
color: #eb5e55;
border: 2px solid #eb5e55;
&:hover {
&:hover:not(.is-disabled) {
background-color: #fff;
}
}
@ -126,7 +131,7 @@ function handleClick() {
}
}
// custom: type="custom",背景完全由 btnBg 决定
// Custom button: type="custom" - background controlled by btnBg prop
.custom-btn {
background: v-bind(customBg);
background-color: transparent;
@ -136,9 +141,10 @@ function handleClick() {
padding: 0 20px;
box-shadow: none;
color: rgb(0, 94, 174);
font-weight: bold;
.btn-text {
font-size: v-bind('`${fontSize}px`');
font-size: v-bind(fontSizeValue);
font-weight: bold;
letter-spacing: 2px;
margin-bottom: 7px;
@ -146,15 +152,15 @@ function handleClick() {
&.is-disabled {
color: #eb5e55;
filter: none;
opacity: 1;
filter: grayscale(0.5);
opacity: 0.6;
}
&:hover {
&:hover:not(.is-disabled) {
transform: scale(1.05);
}
&:active {
&:active:not(.is-disabled) {
transform: scale(0.95);
}
}

View File

@ -363,10 +363,10 @@ watch(titleBgUrl, (newUrl) => {
}
.main-title {
font-size: 2.5rem;
font-size: 2.6rem;
color: $text-color;
margin: 0;
letter-spacing: 4px;
letter-spacing: 3px;
text-align: center;
white-space: nowrap;
/* Prevent text wrapping */

View File

@ -0,0 +1,16 @@
/**
* 生成UUID的兼容函数
* 优先使用原生 crypto.randomUUID如果不支持则使用兼容方案
*/
export function generateUUID(): string {
if (typeof crypto !== 'undefined' && crypto.randomUUID) {
return crypto.randomUUID()
}
// 兼容性回退方案 - 生成符合 UUID v4 格式的字符串
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = Math.random() * 16 | 0
const v = c === 'x' ? r : (r & 0x3 | 0x8)
return v.toString(16)
})
}

View File

@ -41,8 +41,10 @@ const modelValue = ref<{
const { options: roundTypeOptions } = useDict('round_type')
const { options: scoreTypeOptions } = useDict('score_type')
const { options: timeOptions } = useDict('time_out')
// const { options: uiTypeOptions } = useDict('ui_type', 'string')
const { options: timeOptionsRaw } = useDict('time_out')
const timeOptions = computed(() =>
[...timeOptionsRaw.value].sort((a, b) => Number(a.value) - Number(b.value)),
)
const { options: uiTypeOptions } = useDict('question_category_name', 'string')
const hookProps = reactive({

View File

@ -32,6 +32,7 @@ const currentQuestion = ref<Api.Competition.GetCurrentQuestionInfo>() // 当前
const questionInfo = ref<Api.Competition.QuestionListDetailRound>() // 题目详情
const currentQuestionDetailID = ref<number | string>('') // 当前选中的题目详情 ID
const nowTs = ref(Date.now())
// 判断当前activityId是正在比赛的活动
const isActiveActivityId = computed(() => {
if (!currentQuestion.value)
@ -465,6 +466,9 @@ async function handleNexCurrentQuestion() {
currentQuestionId.value = currentQuestion.value?.QuestionID || currentQuestionId.value
currentGroupId.value = currentQuestion.value?.TeamGroupID || currentGroupId.value
}
// 更新当前时间戳,以便重新计算 canPublish
nowTs.value = Date.now()
}
function handlePublish() {
@ -580,7 +584,6 @@ function handlePublish() {
* 消费并发布当前题目
*/
const pollingTimer = ref<NodeJS.Timeout | null>(null)
const nowTs = ref(Date.now())
const canPublish = computed(() => {
const endTime = (currentQuestion.value as any)?.EndTime
if (!endTime)
@ -808,27 +811,29 @@ onUnmounted(() => {
</div>
</div>
<!-- 图片展示 -->
<div class="flex items-center justify-center">
<div class="relative min-h-30 flex items-center justify-center">
<NImage
:src="item.AnswerValuePicture || item.imageUrl" object-fit="contain"
class="max-h-[300px] w-full"
:src="item.AnswerValuePicture || item.imageUrl"
object-fit="contain"
class="pointer-events-auto max-h-[300px] w-full cursor-pointer"
show-toolbar-tooltip
/>
</div>
<!-- Toggle Button Overlay (Center) -->
<div
class="absolute inset-0 flex flex-col items-center justify-center gap-2 opacity-0 transition-opacity duration-200 hover:opacity-100"
class="pointer-events-none absolute inset-0 flex flex-col items-center justify-center gap-2 opacity-0 transition-opacity duration-200 hover:opacity-100"
>
<!-- 如果未校准显示两个按钮 -->
<template v-if="!item._isManual">
<NButton
strong secondary round size="medium" type="success" class="shadow-xl"
strong secondary round size="medium" type="success" class="pointer-events-auto shadow-xl"
@click="setStatus(team, item, 1)"
>
确认正确 (绿)
</NButton>
<NButton
strong secondary round size="medium" type="error" class="shadow-xl"
strong secondary round size="medium" type="error" class="pointer-events-auto shadow-xl"
@click="setStatus(team, item, 0)"
>
确认错误 ()
@ -839,7 +844,7 @@ onUnmounted(() => {
<template v-else>
<NButton
strong secondary round size="large" :type="item.Status === 1 ? 'error' : 'success'"
class="shadow-xl" @click="setStatus(team, item, item.Status === 1 ? 0 : 1)"
class="pointer-events-auto shadow-xl" @click="setStatus(team, item, item.Status === 1 ? 0 : 1)"
>
切换为 {{ item.Status === 1 ? '错误 (红)' : '正确 (绿)' }}
</NButton>
@ -891,8 +896,10 @@ onUnmounted(() => {
<div class="h-full flex items-center justify-center">
<NImage
v-if="item.AnswerValuePicture || item.imageUrl"
:src="item.AnswerValuePicture || item.imageUrl" object-fit="contain"
class="max-h-[800px] w-full"
:src="item.AnswerValuePicture || item.imageUrl"
object-fit="contain"
class="pointer-events-auto max-h-[800px] w-full cursor-pointer"
show-toolbar-tooltip
/>
<div v-else class="text-gray-300">
<div class="i-carbon-no-image text-6xl" />

View File

@ -7,6 +7,7 @@ import { onMounted, ref } from 'vue'
import { useRoute } from 'vue-router'
import { useRouterPush } from '@/hooks/common/router'
import { fetchAddTemplate, fetchTemplateDetail } from '@/service/api/template'
import { generateUUID } from '@/utils/uuid'
import { useUpload } from './hooks/useUpload'
import TemplateCanvas from './modules/TemplateCanvas.vue'
import TemplateSettings from './modules/TemplateSettings.vue'
@ -64,7 +65,7 @@ function handleUploadTrigger() {
* 处理区域生成
*/
function handleGenerate() {
const groupId = crypto.randomUUID()
const groupId = generateUUID()
const newRegions: Region[] = []
// 计算起始编号:查找现有的最大 Qx 编号
@ -85,7 +86,7 @@ function handleGenerate() {
for (let c = 0; c < genSettings.value.cols; c++) {
const index = maxNum + r * genSettings.value.cols + c + 1 // 计算当前区域的编号
newRegions.push({
id: crypto.randomUUID(),
id: generateUUID(),
groupId,
x: currentX + c * (genSettings.value.w + genSettings.value.gapX),
y: currentY + r * (genSettings.value.h + genSettings.value.gapY),

View File

@ -66,6 +66,11 @@ const { columns, columnChecks, data, getData, getDataByPage, loading, mobilePagi
title: '模板ID',
align: 'center',
},
{
key: 'PageNo',
title: '页码',
align: 'center',
},
{
key: 'competitionId',
title: '关联比赛',

View File

@ -127,7 +127,17 @@ async function fetchGetGameStatisticsData() {
QuestionDetaiID: Number(QuestionDetailID.value),
}
const { data } = await fetchGetGameStatistics(_params)
teams.value = (data?.data as any[]) || []
const rawTeams = (data?.data as any[]) || []
// 为每个队伍的图片 URL 添加时间戳,防止缓存
teams.value = rawTeams.map((team) => {
if (team.UserAnswerPicture) {
const timestamp = Date.now()
const separator = team.UserAnswerPicture.includes('?') ? '&' : '?'
team.UserAnswerPicture = `${team.UserAnswerPicture}${separator}_t=${timestamp}`
}
return team
})
}
catch (error: any) {
console.error('Failed to fetch game statistics', error)
@ -150,7 +160,7 @@ onBeforeUnmount(() => {
<template>
<CompetitionLayout
:show-title="true" :show-back="false" :show-next="showNextBtn" title="答题图解" action-position="top"
:show-title="true" :show-back="false" :show-next="showNextBtn" :title-bg-type="3" title-text-color="#ffffff" title="答题图解" action-position="top"
back-btn-text="返回" :next-btn-text="isCompleted ? '该组已完成回到选组' : '下一题'" btn-theme="light" @back="handleBack"
@next="handleNext"
>
@ -170,11 +180,12 @@ onBeforeUnmount(() => {
class="mb-3 flex items-center gap-2 rounded-full from-sky-300 to-cyan-200 bg-gradient-to-r px-4 py-2 shadow-sm"
>
<span class="text-lg text-white font-bold drop-shadow">{{ team.TeamName }}</span>
<span class="ml-2 rounded-full bg-white/40 px-2 py-0.5 text-sm">正确 <span class="text-md text-blue">{{
team.correctCount }}</span> </span>
<span class="text-s rounded-full bg-white/40 px-2 py-0.5">积分 <span class="text-md text-blue">{{
team.Points
}}</span></span>
<span class="rounded-full bg-orange-100/60 px-5 py-2 text-sm">
AI评分 <span class="text-md text-orange-600 font-bold">{{ team.Points }}</span>
</span>
<span class="rounded-full bg-green-100/60 px-5 py-2 text-sm">
评委评分 <span class="text-md text-green-600 font-bold">{{ team.ResultPotins }}</span>
</span>
</div>
<!-- Answer Image Area -->

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { computed, onMounted, ref, watch } from 'vue'
import { useRoute } from 'vue-router'
import CompetitionLayout from '@/components/custom/user/CompetitionLayout.vue'
import { PublishStatus } from '@/enum/business'
@ -30,12 +30,12 @@ const activityName = computed(() => activityInfo.value?.ActivityTitle || '星·
const flippedCards = ref<Set<number>>(new Set())
// 计算是否所有卡片都已翻转 (当前显示4张卡片)
// eslint-disable-next-line unused-imports/no-unused-vars
const isAllFlipped = computed(() => flippedCards.value.size === questions.value.length)
// 控制下一步按钮的显示(带延迟)
const showNextButton = ref(true)
// eslint-disable-next-line prefer-const, unused-imports/no-unused-vars
let timer: ReturnType<typeof setTimeout> | null = null
// 获取路由参数
@ -77,21 +77,21 @@ async function getQuestions() {
}
}
// 测试先注释掉
// watch(isAllFlipped, (val) => {
// if (timer) {
// clearTimeout(timer)
// timer = null
// }
watch(isAllFlipped, (val) => {
if (timer) {
clearTimeout(timer)
timer = null
}
// if (val) {
// timer = setTimeout(() => {
// showNextButton.value = true
// }, 1500)
// }
// else {
// showNextButton.value = false
// }
// })
if (val) {
timer = setTimeout(() => {
showNextButton.value = true
}, 1500)
}
else {
showNextButton.value = false
}
})
function handleBack() {
routerBack()
@ -150,6 +150,16 @@ async function initSyncRouteParams() {
const showCards = ref(false)
// 计算每排卡片数量(根据不同屏幕尺寸)
// 默认按最小屏幕2列计算如果超过2排则调整padding
const needCompactPadding = computed(() => {
// 假设最小屏幕每排2个卡片w-[44%]
// const cardsPerRow = 2
// const totalRows = Math.ceil(questions.value.length / cardsPerRow)
// return totalRows >= 2
return questions.value.length > 7 // 如果超过8张卡片就使用紧凑间距
})
// 3D 悬停效果逻辑
const cardStyles = ref<Record<number, any>>({})
@ -196,12 +206,11 @@ onMounted(async () => {
<template>
<CompetitionLayout
:show-back="true" :show-next="showNextButton" next-btn-text="下一步" :title="activityName"
:title-bg-type="2" back-btn-text="返回" @back="handleBack"
@next="handleNext"
:title-bg-type="2" back-btn-text="返回" @back="handleBack" @next="handleNext"
>
<div class="h-screen w-full overflow-y-auto font-sans">
<div class="relative z-10 min-h-full w-full">
<div class="min-h-full w-full flex flex-col items-center pb-12 pt-24">
<div class="min-h-full w-full flex flex-col items-center pb-12" :class="needCompactPadding ? 'pt-4' : 'pt-24'">
<!-- 卡片列表 -->
<TransitionGroup
tag="div" name="card-anim"

View File

@ -143,7 +143,7 @@ const titleBgTypeNum = computed(() => RoundType.value === 0 ? 3 : 4)
@next="handleCardClick(question as Api.Competition.CurrentQuestionResponse)" @back="handleBack"
>
<div class="h-full w-full flex flex-col items-center pt-10 font-sans">
<div v-if="question" class="mb-10 max-w-4xl text-center">
<div v-if="question" class="mb-10 max-w-85% text-center">
<div class="text-4xl text-gray-800 font-medium leading-relaxed tracking-wide">
{{ questionTitle || '' }}
</div>

View File

@ -284,12 +284,8 @@ const titleBgTypeNum = computed(() => RoundType.value === 0 ? 3 : 4) || 3
class="relative z-20 h-64 max-w-5xl w-full flex flex-col shrink-0 border-2 border-blue-300 rounded-xl bg-white/90 p-4 shadow-lg backdrop-blur"
>
<!-- 图表标题栏 -->
<div v-if="isStarted" class="mb-4 flex items-center justify-between px-2">
<div class="flex items-center gap-2">
<div class="h-3 w-3 rotate-45 bg-orange-400" />
<span class="text-lg text-blue-800 font-bold">答题进度</span>
<span class="text-md text-gray-400">仅为ai判定不代表最终结果</span>
</div>
<div v-if="isStarted" class="z-index-999 relative mb-4">
<img src="@/assets/imgs/user/rank-bg-kuang.png" alt="答题进度" class="z-index-999 absolute left--26px top--22px h-auto max-h-16 w-auto">
</div>
<!-- 柱状图ECharts -->

View File

@ -24,6 +24,35 @@ const dictationParts = computed(() => {
return []
})
// 动态计算第二个框的样式(根据文字长度)
const secondPartStyle = computed(() => {
if (dictationParts.value.length < 2)
return { fontSize: 'text-5xl', letterSpacing: 'tracking-widest' }
const secondPart = dictationParts.value[1]
const length = secondPart.length
// 根据文字长度返回不同的样式配置
if (length <= 16) {
return {
fontSize: 'text-5xl', // 51.2px - 保持大字体
letterSpacing: 'tracking-widest', // 0.4em - 正常字间距
}
}
else if (length <= 20) {
return {
fontSize: 'text-4xl', // 40px - 稍微缩小
letterSpacing: 'tracking-wide', // 0.2em - 缩小字间距
}
}
else {
return {
fontSize: 'text-3xl', // 33.6px - 更小一点
letterSpacing: 'tracking-normal', // 0.05em - 最小字间距
}
}
})
// 联想对对碰:上方词组
const associationWords = computed(() => {
const name = currentQuestionDetail.value?.Name || ''
@ -71,13 +100,18 @@ watch(
<!-- 模板A: 汉字听写1-提示 (拼音+提示) -->
<div v-if="template === QuestionCategoryEnum.ChineseCharacterDictation1" class="text-center">
<div class="mb-6 inline-block text-5xl font-bold leading-none">
<div class="flex items-center justify-center gap-4">
<div class="flex items-center justify-start gap-4">
<!-- 第一个框拼音 -->
<div class="short-content-bg pinyin-text text-6xl">
{{ dictationParts[0] }}
</div>
<!-- 第二个框意思提示 -->
<div
v-for="(part, index) in dictationParts" :key="`part-${index}`"
class="text-4xl"
:class="index === 0 ? 'short-content-bg' : 'content-with-bg'"
v-if="dictationParts.length > 1" class="content-with-bg pinyin-text !max-w-85%"
:class="[secondPartStyle.fontSize, secondPartStyle.letterSpacing]"
>
{{ part }}
{{ dictationParts[1] }}
</div>
</div>
</div>
@ -88,8 +122,11 @@ watch(
v-else-if="template === QuestionCategoryEnum.ChineseCharacterDictation2 || template === QuestionCategoryEnum.WordDictation"
class="flex flex-col items-center"
>
<div class="mb-1 text-3xl text-gray-800 font-bold leading-relaxed">
<div class="rich-content content-with-bg ml-3 mt-4 flex text-6xl !px-16 !py-10 !tracking-[0.1em]">
<div class="mb-2 text-center text-2xl">
{{ title }}
</div>
<div class="mb-1 text-gray-800 font-bold leading-relaxed">
<div class="rich-content content-with-bg pinyin-text ml-3 mt-4 flex text-7xl !max-w-100% !px-16 !py-8 !tracking-[0.08em]">
{{ content }}
</div>
</div>
@ -98,7 +135,7 @@ watch(
<!-- 模板C: 汉字加一加 (提示+部件) -->
<div v-else-if="template === QuestionCategoryEnum.CharacterRadicalAddition" class="text-center">
<div class="mb-6 inline-block text-5xl font-bold leading-none">
<div class="rich-content ml-3 mt-4 flex gap-1 text-5xl tracking-[0.1em]">
<div class="rich-content ml-3 mt-4 flex gap-1 text-6xl tracking-[0.06em]">
请写出含有 <span class="text-color-red !text-6xl">{{ content }}</span>的汉字书写时间为60秒
</div>
</div>
@ -107,7 +144,7 @@ watch(
<!-- 模板D: 成语写一写1 (拼音+提示) -->
<div v-else-if="template === QuestionCategoryEnum.IdiomWriting1" class="flex flex-col items-center">
<div class="mb-1 text-gray-800 font-bold leading-relaxed">
<div class="rich-content ml-3 mt-4 flex gap-1 text-4xl">
<div class="rich-content ml-3 mt-4 flex gap-1 text-5xl">
{{ content }}
</div>
</div>
@ -115,8 +152,8 @@ watch(
<!-- 模板E: 成语-文字要求 -->
<div v-else-if="template === QuestionCategoryEnum.IdiomWriting2" class="text-center">
<div class="mb-8 text-4xl text-gray-800 font-bold">
<NImage :src="ImageUrl" preview-disabled width="300" object-fit="contain" />
<div class="mb-2">
<img :src="ImageUrl" preview-disabled class="max-h-380px max-w-700px" object-fit="cover">
</div>
</div>
@ -173,7 +210,7 @@ watch(
v-else-if="template === QuestionCategoryEnum.CharacterWordFlowerDrinkingGame"
class="w-full flex flex-col items-center"
>
<div class="options-container text-5xl">
<div class="options-container text-6xl">
请回答带有{{ content }}的诗词
</div>
</div>
@ -408,7 +445,8 @@ watch(
:deep(p),
:deep(span),
:deep(div) {
font-size: 2rem; /* text-5xl */
font-size: 2.2rem;
/* text-5xl */
}
}
@ -416,16 +454,41 @@ watch(
background: url('@/assets/imgs/user/content-bg.png') no-repeat center;
background-size: 100% 100%;
border-radius: 12px;
padding: 20px 30px;
letter-spacing: 0.4em;
padding: 30px 50px;
/* 优化长文本显示 */
max-width: 80%;
/* 限制最大宽度 */
min-height: 120px;
/* 最小高度,与 short-content-bg 保持一致 */
word-break: keep-all;
/* 避免中文单词被截断 */
white-space: normal;
/* 允许换行 */
line-height: 1.5;
/* 行高,让换行更美观 */
display: inline-flex;
/* 使用 flex 布局 */
align-items: center;
/* 垂直居中 */
justify-content: center;
/* 水平居中 */
text-align: center;
/* 文字居中 */
}
.short-content-bg {
background: url('@/assets/imgs/user/short-content-bg.png') no-repeat center;
background-size: 100% 100%;
border-radius: 12px;
padding: 20px 30px;
letter-spacing: 0.1em;
padding: 20px 80px;
min-height: 120px;
/* 最小高度,与 content-with-bg 保持一致 */
display: inline-flex;
/* 使用 flex 布局 */
align-items: center;
/* 垂直居中 */
justify-content: center;
/* 水平居中 */
}
.association-word {
@ -453,4 +516,35 @@ watch(
font-weight: bold;
color: white;
}
/* 拼音字体样式 - 支持声调符号 */
.pinyin-text {
/* 字体回退顺序:
1. GB Pinyinok-B - 专业拼音字体
2. Microsoft YaHei - 微软雅黑Windows 系统自带,支持拼音)
3. PingFang SC - 苹方macOS 系统自带,支持拼音)
4. STHeiti - 华文黑体(支持拼音)
5. sans-serif - 系统默认无衬线字体
*/
font-family: 'GB Pinyinok-B', 'Microsoft YaHei', 'PingFang SC', 'STHeiti', 'SimHei', sans-serif;
font-weight: bold;
letter-spacing: 0.08em;
/* 确保拼音声调符号不被截断 */
line-height: 1.5;
}
/* 如果需要加载自定义拼音字体 */
@font-face {
font-family: 'GB Pinyinok-B';
/* 优先使用本地已安装的字体 */
src: local('GB Pinyinok-B'), local('GBPinyinok-B'), local('GB Pinyinok B');
/* 如果本地没有,则加载项目中的字体文件(需要先添加字体文件)*/
/* src: url('@/assets/fonts/GBPinyinok-B.woff2') format('woff2'),
url('@/assets/fonts/GBPinyinok-B.woff') format('woff'),
url('@/assets/fonts/GBPinyinok-B.ttf') format('truetype'); */
font-weight: normal;
font-style: normal;
font-display: swap;
/* 字体加载时先显示系统字体,加载完成后切换 */
}
</style>

View File

@ -49,7 +49,7 @@ function handleNext() {
<template>
<CompetitionLayout
:show-back="true" back-btn-text="返回" :show-next="true" :title="activityName" next-btn-text="下一步"
:show-back="true" :title-bg-type="2" back-btn-text="返回" :show-next="true" :title="activityName" next-btn-text="下一步"
@back="handleBack" @next="handleNext"
>
<div class="items-flex-start h-full w-full flex justify-center font-sans">

View File

@ -87,7 +87,10 @@ onMounted(() => {
</script>
<template>
<CompetitionLayout :show-back="true" back-btn-text="返回" :show-next="true" next-btn-text="下一步" :show-title="false" @next="handleNext" @back="handleBack">
<CompetitionLayout
:show-back="true" back-btn-text="返回" :show-next="false" next-btn-text="下一步" :show-title="false"
@next="handleNext" @back="handleBack"
>
<!-- Scroll Content -->
<div class="scroll-container">
<!-- 卷轴背景动画容器 -->
@ -113,7 +116,7 @@ onMounted(() => {
<div class="icon-wrapper">
<img src="@/assets/imgs/user/team-title-icon.webp" alt="team-icon" class="h-full w-full object-cover">
</div>
<div class="team-name">
<div class="team-name text-3xl">
{{ item.name }}
</div>
</div>
@ -181,6 +184,7 @@ onMounted(() => {
100% {
transform: translateY(0px);
}
50% {
transform: translateY(-15px);
}
@ -189,7 +193,7 @@ onMounted(() => {
.title-section {
position: absolute;
top: 130px; // 使用固定像素值,确保在卷轴内部
left: 40px; // 距离左边缘的固定距离
left: 47px; // 距离左边缘的固定距离
z-index: 10;
.scroll-bg {
@ -207,8 +211,8 @@ onMounted(() => {
// 添加响应式适配
@media (max-width: 1920px) {
.title-section {
top: 70px;
left: 50px;
top: 140px;
left: 45px;
}
}
@ -316,14 +320,20 @@ onMounted(() => {
}
.team-name {
font-size: 1.5rem;
// min-width: 130px;
// width: 300px;
// height: 120px;
min-height: 60px;
min-width: 250px;
line-height: 60px;
color: #333;
font-weight: bold;
text-shadow: 0 1px 2px rgba(255, 255, 255, 0.8);
background: url('@/assets/imgs/user/team-title-bg.svg') no-repeat center center;
background-size: contain;
background: url('@/assets/imgs/user/team-title-bg.png') no-repeat center center;
background-size: 100% 100%;
padding: 15px 30px;
border-radius: 10px;
text-align: center;
box-sizing: border-box;
}
}
</style>

View File

@ -1,100 +0,0 @@
{
"question_bank": [
{
"QuestionId": 34,
"Name": "<p>诗人袁枚写的与<strong>美食</strong>有关的书是(&nbsp; &nbsp;)。</p><p><strong>&nbsp; &nbsp;A.《食经》&nbsp; &nbsp; B.《食珍录》&nbsp; &nbsp; C.《红楼梦》&nbsp; &nbsp; D.《随园食单》</strong></p>",
"Answer": "D",
"Type": "text",
"IsGood": 0,
"ImageUrl": ""
},
{
"QuestionId": 34,
"Name": "<p>“我家洗砚池头树”引用了一位<strong>书法家</strong>的典故,这位书法家是(&nbsp; &nbsp;)。</p><p><strong>&nbsp; &nbsp;A.王献之&nbsp; &nbsp; B.王羲之&nbsp; &nbsp; C.王冕&nbsp; &nbsp; D.柳公权</strong></p>",
"Answer": "B",
"Type": "text",
"IsGood": 0,
"ImageUrl": ""
},
{
"QuestionId": 34,
"Name": "<p>“诗中有画,画中有诗”评价的是(&nbsp; &nbsp;)。</p><p><strong>&nbsp; &nbsp;A.杜牧的诗画风格</strong></p><p><strong>&nbsp; &nbsp;B.刘禹锡的诗画风格</strong></p><p><strong>&nbsp; &nbsp;C.苏轼的诗画风格</strong></p><p><strong>&nbsp; &nbsp;D.王维的诗画风格</strong></p>",
"Answer": "D",
"Type": "text",
"IsGood": 0,
"ImageUrl": ""
},
{
"QuestionId": 34,
"Name": "<p>被闻一多称为“<strong>诗中的诗</strong>,顶峰上的顶峰”的诗歌作品是(&nbsp; &nbsp;)。</p><p><strong>&nbsp; &nbsp;A.刘希夷的《代悲白头翁》</strong></p><p><strong>&nbsp; &nbsp;B.杨广的《春江花月夜》</strong></p><p><strong>&nbsp; &nbsp;C.张若虚的《春江花月夜》</strong></p><p><strong>&nbsp; &nbsp;D.李白的《蜀道难》</strong></p>",
"Answer": "C",
"Type": "text",
"IsGood": 0,
"ImageUrl": ""
},
{
"QuestionId": 34,
"Name": "<p>“<strong>梅妻鹤子</strong>”指的是(&nbsp; &nbsp;)。</p><p><strong>&nbsp; &nbsp;A.林逋&nbsp; &nbsp; B.梅尧臣&nbsp; &nbsp; C.苏舜钦&nbsp; &nbsp; D.王安石</strong></p>",
"Answer": "A",
"Type": "text",
"IsGood": 0,
"ImageUrl": ""
},
{
"QuestionId": 34,
"Name": "<p>“一门父子三词客,千古文章八大家。”这副对联中提到的“<strong>三父子</strong>”是(&nbsp; &nbsp;)。</p><p><strong>&nbsp; &nbsp;A.曹操、曹丕、曹植</strong></p><p><strong>&nbsp; &nbsp;B.苏洵、苏轼、苏辙</strong></p><p><strong>&nbsp; &nbsp;C.班彪、班固、班超</strong></p><p><strong>&nbsp; &nbsp;D.阮瑀、阮籍、阮咸</strong></p>",
"Answer": "B",
"Type": "text",
"IsGood": 0,
"ImageUrl": ""
},
{
"QuestionId": 34,
"Name": "<p>诗人刘禹锡被<strong>称</strong>为(&nbsp; &nbsp;)。</p><p><strong>&nbsp; &nbsp;A.“诗鬼”&nbsp; &nbsp; B.“诗豪”&nbsp; &nbsp; C.“诗圣”&nbsp; &nbsp; D.“诗仙”</strong></p>",
"Answer": "B",
"Type": "text",
"IsGood": 0,
"ImageUrl": ""
},
{
"QuestionId": 34,
"Name": "<p>有关诗人卢钺的信息,<strong>不正确</strong>的一项是(&nbsp; &nbsp;)。</p><p><strong>&nbsp; &nbsp;A.别号梅坡</strong></p><p><strong>&nbsp; &nbsp;B.代表作《雪梅》</strong></p><p><strong>&nbsp; &nbsp;C.与辛派词人陈亮是好友</strong></p><p><strong>&nbsp; &nbsp;D.宋朝人</strong></p>",
"Answer": "C",
"Type": "text",
"IsGood": 0,
"ImageUrl": ""
},
{
"QuestionId": 34,
"Name": "<p>诗人王昌龄被<strong>称</strong>为(&nbsp; &nbsp;)。</p><p><strong>&nbsp; &nbsp;A.“五言圣手”&nbsp; &nbsp; B.“七绝圣手”&nbsp; &nbsp; C.“七言圣手”&nbsp; &nbsp; D.“七绝诗人”</strong></p>",
"Answer": "B",
"Type": "text",
"IsGood": 0,
"ImageUrl": ""
},
{
"QuestionId": 34,
"Name": "<p>李商隐与杜牧<strong>合称</strong>&nbsp; &nbsp;)。</p><p><strong>&nbsp; &nbsp;A.“李杜”&nbsp; &nbsp; B.“杜李”&nbsp; &nbsp; C.“小李杜”&nbsp; &nbsp; D.“唐诗双杰”</strong></p>",
"Answer": "C",
"Type": "text",
"IsGood": 0,
"ImageUrl": ""
},
{
"QuestionId": 34,
"Name": "<p>“南朝四百八十寺”中,“<strong>南朝</strong>”指的是(&nbsp; &nbsp;)。</p><p><strong>&nbsp; &nbsp;A.在南方建都的王朝</strong></p><p><strong>&nbsp; &nbsp;B.宋、齐、魏、陈四个朝代的总称</strong></p><p><strong>&nbsp; &nbsp;C.宋、齐、梁、陈四个朝代的总称</strong></p><p><strong>&nbsp; &nbsp;D.在南京建都的王朝</strong></p>",
"Answer": "C",
"Type": "text",
"IsGood": 0,
"ImageUrl": ""
},
{
"QuestionId": 34,
"Name": "<p>“<strong>初唐四杰</strong>”是指(&nbsp; &nbsp;)。</p><p><strong>&nbsp; &nbsp;A.张若虚、张旭、孔融和贺知章</strong></p><p><strong>&nbsp; &nbsp;B.王勃、杨炯、卢照邻和骆宾王</strong></p><p><strong>&nbsp; &nbsp;C.高适、王昌龄、岑参和王之涣</strong></p><p><strong>&nbsp; &nbsp;D.贺知章、张若虚、张旭和包融</strong></p>",
"Answer": "B",
"Type": "text",
"IsGood": 0,
"ImageUrl": ""
}
]
}

View File

@ -2,7 +2,7 @@
"question_bank": [
{
"QuestionId": 5,
"Name": "表示团结的四字成语",
"Name": "请写出表示团结的四字成语",
"Answer": "万众一心、众志成城、精诚团结、风雨同舟、患难与共、群策群力、和衷共济、同舟共济、齐心协力、守望相助……",
"Type": "text",
"IsGood": 0,
@ -10,7 +10,7 @@
},
{
"QuestionId": 5,
"Name": "含有“足”的四字成语",
"Name": "请写出含有“足”的四字成语",
"Answer": "美中不足、捷足先登、足不出户、酒足饭饱、无足轻重、心满意足、画蛇添足、手足无措、足智多谋、不足挂齿……",
"Type": "text",
"IsGood": 0,
@ -18,7 +18,7 @@
},
{
"QuestionId": 5,
"Name": "含有“语”和“言”两个字的四字成语",
"Name": "请写出含有“语”和“言”两个字的四字成语",
"Answer": "不言不语、只言片语、三言两语、千言万语、豪言壮语、少言寡语、自言自语、甜言蜜语、花言巧语、风言风语……",
"Type": "text",
"IsGood": 0,
@ -26,15 +26,15 @@
},
{
"QuestionId": 5,
"Name": "表示关系好的四字成语",
"Answer": "形影不离、情同手足、亲密无间、莫逆之交、刎颈之交、肝胆照、八拜之交、情深似海、如胶似漆、深情厚谊……",
"Name": "请写出表示关系好的四字成语",
"Answer": "形影不离、情同手足、亲密无间、莫逆之交、刎颈之交、肝胆照、八拜之交、情深似海、如胶似漆、深情厚谊……",
"Type": "text",
"IsGood": 0,
"ImageUrl": ""
},
{
"QuestionId": 5,
"Name": "含有“马”的四字成语",
"Name": "请写出含有“马”的四字成语",
"Answer": "害群之马、车水马龙、万马齐喑、兵荒马乱、马马虎虎、人仰马翻、走马观花、马到成功、千军万马、单枪匹马……",
"Type": "text",
"IsGood": 0,
@ -42,7 +42,7 @@
},
{
"QuestionId": 5,
"Name": "含有“安”的四字成语",
"Name": "请写出含有“安”的四字成语",
"Answer": "随遇而安、安居乐业、安身立命、一路平安、国泰民安、惴惴不安、局促不安、坐卧不安、忐忑不安、安然无恙……",
"Type": "text",
"IsGood": 0,
@ -50,7 +50,7 @@
},
{
"QuestionId": 5,
"Name": "表示学习刻苦的四字成语",
"Name": "请写出表示学习刻苦的四字成语",
"Answer": "废寝忘食、勤学苦练、闻鸡起舞、牛角挂书、凿壁偷光、焚膏继晷、囊萤映雪、韦编三绝、孜孜不倦、悬梁刺股……",
"Type": "text",
"IsGood": 0,
@ -58,7 +58,7 @@
},
{
"QuestionId": 5,
"Name": "表示看的四字成语",
"Name": "请写出表示看的四字成语",
"Answer": "东张西望、察言观色、走马观花、左顾右盼、侧目而视、目不转睛、极目远眺、目不暇接、一目十行、探头探脑……",
"Type": "text",
"IsGood": 0,
@ -66,7 +66,7 @@
},
{
"QuestionId": 5,
"Name": "含有两种颜色的四字成语",
"Name": "请写出含有两种颜色的四字成语",
"Answer": "姹紫嫣红、万紫千红、金碧辉煌、桃红柳绿、黑白分明、青山绿水、唇红齿白、青出于蓝、青黄不接、白纸黑字……",
"Type": "text",
"IsGood": 0,
@ -74,7 +74,7 @@
},
{
"QuestionId": 5,
"Name": "表示珍贵的四字成语",
"Name": "请写出表示珍贵的四字成语",
"Answer": "无价之宝、奇珍异宝、凤毛麟角、绝无仅有、价值连城、和璧隋珠、金玉良言、沧海遗珠、千金难买、吉光片羽……",
"Type": "text",
"IsGood": 0,
@ -82,7 +82,7 @@
},
{
"QuestionId": 5,
"Name": "含有“星”的四字成语",
"Name": "请写出含有“星”的四字成语",
"Answer": "星星点点、众星拱月、月明星稀、吉星高照、披星戴月、星光灿烂、星罗棋布、星月交辉、斗转星移、大步流星……",
"Type": "text",
"IsGood": 0,
@ -90,7 +90,7 @@
},
{
"QuestionId": 5,
"Name": "含有“风”和“雨”两个字的四字成语",
"Name": "请写出含有“风”和“雨”两个字的四字成语",
"Answer": "风雨同舟、春风化雨、和风细雨、呼风唤雨、狂风暴雨、血雨腥风、凄风苦雨、风雨无阻、风雨交加、风吹雨打……",
"Type": "text",
"IsGood": 0,
@ -98,7 +98,7 @@
},
{
"QuestionId": 5,
"Name": "表示不安的四字成语",
"Name": "请写出表示不安的四字成语",
"Answer": "心惊肉跳、忐忑不安、坐立不安、惊慌失措、胆战心惊、诚惶诚恐、惊弓之鸟、七上八下、如坐针毡、提心吊胆……",
"Type": "text",
"IsGood": 0,

View File

@ -1,254 +1,254 @@
{
"question_bank": [
{
"name": "重阳、习俗、思念",
"answer": "遥知兄弟登高处,遍插茱萸少一人。",
"imageUrl": "",
"Name": "重阳、习俗、思念",
"Answer": "遥知兄弟登高处,遍插茱萸少一人。",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "处",
"KeyWordsIndex": 6,
"questionId": 32
"QuestionId": 32
},
{
"name": "边塞、征战、思乡",
"answer": "秦时明月汉时关,万里长征人未还。",
"imageUrl": "",
"Name": "边塞、征战、思乡",
"Answer": "秦时明月汉时关,万里长征人未还。",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "关",
"KeyWordsIndex": 6,
"questionId": 32
"QuestionId": 32
},
{
"name": "军中、饮酒、欢快",
"answer": "葡萄美酒夜光杯,欲饮琵琶马上催。",
"imageUrl": "",
"Name": "军中、饮酒、欢快",
"Answer": "葡萄美酒夜光杯,欲饮琵琶马上催。",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "催",
"KeyWordsIndex": 13,
"questionId": 32
"QuestionId": 32
},
{
"name": "初夏、田园、蔬果",
"answer": "梅子金黄杏子肥,麦花雪白菜花稀。",
"imageUrl": "",
"Name": "初夏、田园、蔬果",
"Answer": "梅子金黄杏子肥,麦花雪白菜花稀。",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "肥",
"KeyWordsIndex": 6,
"questionId": 32
"QuestionId": 32
},
{
"name": "童趣、追跑、田野",
"answer": "儿童急走追黄蝶,飞入菜花无处寻。",
"imageUrl": "",
"Name": "童趣、追跑、田野",
"Answer": "儿童急走追黄蝶,飞入菜花无处寻。",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "蝶",
"KeyWordsIndex": 6,
"questionId": 32
"QuestionId": 32
},
{
"name": "送别、赤诚、朋友",
"answer": "洛阳亲友如相问,一片冰心在玉壶。",
"imageUrl": "",
"Name": "送别、赤诚、朋友",
"Answer": "洛阳亲友如相问,一片冰心在玉壶。",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "心",
"KeyWordsIndex": 10,
"questionId": 32
"QuestionId": 32
},
{
"name": "梅花、香气、傲骨",
"answer": "不要人夸好颜色,只留清气满乾坤。",
"imageUrl": "",
"Name": "梅花、香气、傲骨",
"Answer": "不要人夸好颜色,只留清气满乾坤。",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "好",
"KeyWordsIndex": 4,
"questionId": 32
"QuestionId": 32
},
{
"name": "遗愿、爱国、失地",
"answer": "死去元知万事空,但悲不见九州同。",
"imageUrl": "",
"Name": "遗愿、爱国、失地",
"Answer": "死去元知万事空,但悲不见九州同。",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "悲",
"KeyWordsIndex": 8,
"questionId": 32
"QuestionId": 32
},
{
"name": "水滨、笙乐、忧愁",
"answer": "山外青山楼外楼,西湖歌舞几时休?",
"imageUrl": "",
"Name": "水滨、笙乐、忧愁",
"Answer": "山外青山楼外楼,西湖歌舞几时休?",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "休",
"KeyWordsIndex": 13,
"questionId": 32
"QuestionId": 32
},
{
"name": "祈求、变革、贤能",
"answer": "我劝天公重抖擞,不拘一格降人材。",
"imageUrl": "",
"Name": "祈求、变革、贤能",
"Answer": "我劝天公重抖擞,不拘一格降人材。",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "公",
"KeyWordsIndex": 3,
"questionId": 32
"QuestionId": 32
},
{
"name": "深夜、羁客、寒冷",
"answer": "月落乌啼霜满天,江枫渔火对愁眠。",
"imageUrl": "",
"Name": "深夜、羁客、寒冷",
"Answer": "月落乌啼霜满天,江枫渔火对愁眠。",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "愁",
"KeyWordsIndex": 12,
"questionId": 32
"QuestionId": 32
},
{
"name": "登科、飞驰、盛景",
"answer": "春风得意马蹄疾,一日看尽长安花。",
"imageUrl": "",
"Name": "登科、飞驰、盛景",
"Answer": "春风得意马蹄疾,一日看尽长安花。",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "花",
"KeyWordsIndex": 13,
"questionId": 32
"QuestionId": 32
},
{
"name": "耕地、纺织、协作",
"answer": "昼出耘田夜绩麻,村庄儿女各当家。",
"imageUrl": "",
"Name": "耕地、纺织、协作",
"Answer": "昼出耘田夜绩麻,村庄儿女各当家。",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "村",
"KeyWordsIndex": 7,
"questionId": 32
"QuestionId": 32
},
{
"name": "悠闲、放牧、吹奏",
"answer": "牧童归去横牛背,短笛无腔信口吹。",
"imageUrl": "",
"Name": "悠闲、放牧、吹奏",
"Answer": "牧童归去横牛背,短笛无腔信口吹。",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "背",
"KeyWordsIndex": 6,
"questionId": 32
"QuestionId": 32
},
{
"name": "童趣、玩耍、敲击",
"answer": "稚子金盆脱晓冰,彩丝穿取当银钲。",
"imageUrl": "",
"Name": "童趣、玩耍、敲击",
"Answer": "稚子金盆脱晓冰,彩丝穿取当银钲。",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "脱",
"KeyWordsIndex": 4,
"questionId": 32
"QuestionId": 32
},
{
"name": "欣喜、回家、畅饮",
"answer": "白日放歌须纵酒,青春作伴好还乡。",
"imageUrl": "",
"Name": "欣喜、回家、畅饮",
"Answer": "白日放歌须纵酒,青春作伴好还乡。",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "须",
"KeyWordsIndex": 4,
"questionId": 32
"QuestionId": 32
},
{
"name": "雄师、豪迈、跋涉",
"answer": "红军不怕远征难,万水千山只等闲。",
"imageUrl": "",
"Name": "雄师、豪迈、跋涉",
"Answer": "红军不怕远征难,万水千山只等闲。",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "怕",
"KeyWordsIndex": 3,
"questionId": 32
"QuestionId": 32
},
{
"name": "中秋、怀人、月亮",
"answer": "今夜月明人尽望,不知秋思落谁家。",
"imageUrl": "",
"Name": "中秋、怀人、月亮",
"Answer": "今夜月明人尽望,不知秋思落谁家。",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "思",
"KeyWordsIndex": 10,
"questionId": 32
"QuestionId": 32
},
{
"name": "无畏、高尚、咏物",
"answer": "粉骨碎身浑不怕,要留清白在人间。",
"imageUrl": "",
"Name": "无畏、高尚、咏物",
"Answer": "粉骨碎身浑不怕,要留清白在人间。",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "浑",
"KeyWordsIndex": 4,
"questionId": 32
"QuestionId": 32
},
{
"name": "坚韧、勇气、咏物",
"answer": "咬定青山不放松,立根原在破岩中。",
"imageUrl": "",
"Name": "坚韧、勇气、咏物",
"Answer": "咬定青山不放松,立根原在破岩中。",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "根",
"KeyWordsIndex": 8,
"questionId": 32
"QuestionId": 32
},
{
"name": "送别、边塞、畅饮",
"answer": "劝君更尽一杯酒,西出阳关无故人。",
"imageUrl": "",
"Name": "送别、边塞、畅饮",
"Answer": "劝君更尽一杯酒,西出阳关无故人。",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "关",
"KeyWordsIndex": 10,
"questionId": 32
"QuestionId": 32
},
{
"name": "细雨、嫩绿、朦胧",
"answer": "天街小雨润如酥,草色遥看近却无。",
"imageUrl": "",
"Name": "细雨、嫩绿、朦胧",
"Answer": "天街小雨润如酥,草色遥看近却无。",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "街",
"KeyWordsIndex": 1,
"questionId": 32
"QuestionId": 32
},
{
"name": "哭泣、沦陷、期盼",
"answer": "遗民泪尽胡尘里,南望王师又一年。",
"imageUrl": "",
"Name": "哭泣、沦陷、期盼",
"Answer": "遗民泪尽胡尘里,南望王师又一年。",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "师",
"KeyWordsIndex": 10,
"questionId": 32
"QuestionId": 32
},
{
"name": "酒菜、好客、乡村",
"answer": "莫笑农家腊酒浑,丰年留客足鸡豚。",
"imageUrl": "",
"Name": "酒菜、好客、乡村",
"Answer": "莫笑农家腊酒浑,丰年留客足鸡豚。",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "足",
"KeyWordsIndex": 11,
"questionId": 32
"QuestionId": 32
},
{
"name": "初夏、喧闹、江南",
"answer": "黄梅时节家家雨,青草池塘处处蛙。",
"imageUrl": "",
"Name": "初夏、喧闹、江南",
"Answer": "黄梅时节家家雨,青草池塘处处蛙。",
"ImageUrl": "",
"IsGood": 0,
"IsDisabled": false,
"KeyWord": "池",
"KeyWordsIndex": 9,
"questionId": 32
"QuestionId": 32
}
]
}

View File

@ -15,11 +15,42 @@ export default defineConfig<Theme>({
theme: {
...themeVars,
fontSize: {
// 图标字体大小
'icon-xs': '0.875rem',
'icon-small': '1rem',
'icon': '1.125rem',
'icon-large': '1.5rem',
'icon-xl': '2rem',
// 针对 2048x1080 设计基准优化的字体大小
// 相比默认值适当放大,适配大屏显示
// 'xs': '0.8rem', // 12.8px (原 0.75rem = 12px)
// 'sm': '0.95rem', // 15.2px (原 0.875rem = 14px)
// 'base': '1.1rem', // 17.6px (原 1rem = 16px)
// 'lg': '1.3rem', // 20.8px (原 1.125rem = 18px)
// 'xl': '1.5rem', // 24px (原 1.25rem = 20px)
// '2xl': '1.75rem', // 28px (原 1.5rem = 24px)
// '3xl': '2.1rem', // 33.6px (原 1.875rem = 30px)
// '4xl': '2.5rem', // 40px (原 2.25rem = 36px)
// '5xl': '3.2rem', // 51.2px (原 3rem = 48px)
// '6xl': '4rem', // 64px (原 3.75rem = 60px)
// '7xl': '5rem', // 80px (原 4.5rem = 72px)
// '8xl': '6.5rem', // 104px (原 6rem = 96px)
// '9xl': '8.5rem', // 136px (原 8rem = 128px)
'xs': '0.875rem', // 原 0.75rem
'sm': '1rem', // 原 0.875rem
'base': '1.125rem', // 原 1rem
'lg': '1.25rem', // 原 1.125rem
'xl': '1.5rem', // 原 1.25rem
'2xl': '1.875rem', // 原 1.5rem
'3xl': '2.25rem', // 原 1.875rem
'4xl': '2.75rem', // 原 2.25rem
'5xl': '3.5rem', // 原 3rem
'6xl': '4.5rem', // 原 3.75rem
'7xl': '5.5rem', // 原 4.5rem
'8xl': '7rem', // 原 6rem
'9xl': '9rem', // 原 8rem
},
},
shortcuts: {