StudentPreview.vue 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. <template>
  2. <div class="student-preview" :class="{ 'fullscreen': fullscreen }">
  3. <!-- PPT 预览模式:16:9 比例容器 -->
  4. <div v-if="!fullscreen" class="preview-wrapper">
  5. <div class="preview-card">
  6. <!-- 标题区 -->
  7. <div v-if="title || subtitle || progress" class="title-area">
  8. <h1 v-if="title" class="preview-title">
  9. <span v-if="titleIcon" class="title-icon">{{ titleIcon }}</span>
  10. {{ title }}
  11. </h1>
  12. <p v-if="subtitle" class="preview-subtitle">{{ subtitle }}</p>
  13. <p v-if="progress" class="preview-progress">{{ progress }}</p>
  14. </div>
  15. <!-- 内容区 -->
  16. <div class="content-area">
  17. <slot />
  18. </div>
  19. <!-- 操作区 -->
  20. <div v-if="$slots.action" class="action-area">
  21. <slot name="action" />
  22. </div>
  23. </div>
  24. </div>
  25. <!-- 全屏模式 -->
  26. <div v-else class="fullscreen-wrapper">
  27. <div v-if="title || subtitle || progress" class="title-area">
  28. <h1 v-if="title" class="preview-title">
  29. <span v-if="titleIcon" class="title-icon">{{ titleIcon }}</span>
  30. {{ title }}
  31. </h1>
  32. <p v-if="subtitle" class="preview-subtitle">{{ subtitle }}</p>
  33. <p v-if="progress" class="preview-progress">{{ progress }}</p>
  34. </div>
  35. <div class="content-area fullscreen-content">
  36. <slot />
  37. </div>
  38. <div v-if="$slots.action" class="action-area">
  39. <slot name="action" />
  40. </div>
  41. </div>
  42. </div>
  43. </template>
  44. <script lang="ts" setup>
  45. interface Props {
  46. title?: string
  47. subtitle?: string
  48. titleIcon?: string
  49. progress?: string
  50. fullscreen?: boolean
  51. }
  52. withDefaults(defineProps<Props>(), {
  53. fullscreen: false,
  54. })
  55. </script>
  56. <style lang="scss" scoped>
  57. .student-preview {
  58. flex: 1;
  59. display: flex;
  60. flex-direction: column;
  61. background: #fff;
  62. overflow: hidden;
  63. border-radius: 16px;
  64. }
  65. .preview-wrapper {
  66. flex: 1;
  67. display: flex;
  68. align-items: center;
  69. justify-content: center;
  70. padding: 24px;
  71. background: #f9fafb;
  72. }
  73. .preview-card {
  74. width: 100%;
  75. max-width: 900px;
  76. aspect-ratio: 16 / 9;
  77. background: #fff;
  78. border-radius: 12px;
  79. box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
  80. overflow: hidden;
  81. display: flex;
  82. flex-direction: column;
  83. }
  84. .fullscreen-wrapper {
  85. flex: 1;
  86. display: flex;
  87. flex-direction: column;
  88. background: #fff;
  89. overflow: hidden;
  90. }
  91. .title-area {
  92. padding: 24px 32px 16px;
  93. text-align: center;
  94. border-bottom: 1px solid #f9fafb;
  95. }
  96. .preview-title {
  97. font-size: 20px;
  98. font-weight: 600;
  99. color: #111827;
  100. display: flex;
  101. align-items: center;
  102. justify-content: center;
  103. gap: 8px;
  104. margin: 0;
  105. }
  106. .title-icon {
  107. font-size: 24px;
  108. }
  109. .preview-subtitle {
  110. font-size: 14px;
  111. color: #9ca3af;
  112. margin: 4px 0 0;
  113. }
  114. .preview-progress {
  115. font-size: 12px;
  116. color: #9ca3af;
  117. margin: 8px 0 0;
  118. }
  119. .content-area {
  120. flex: 1;
  121. display: flex;
  122. flex-direction: column;
  123. align-items: center;
  124. justify-content: center;
  125. padding: 24px 32px;
  126. overflow: auto;
  127. }
  128. .fullscreen-content {
  129. overflow: auto;
  130. }
  131. .action-area {
  132. padding: 16px 32px;
  133. border-top: 1px solid #f9fafb;
  134. background: #fafbfc;
  135. }
  136. </style>