diff --git a/.tmp.modal.print-config.json b/.tmp.modal.print-config.json new file mode 100644 index 0000000..b845737 Binary files /dev/null and b/.tmp.modal.print-config.json differ diff --git a/STEP_NAVIGATION_REDESIGN.md b/STEP_NAVIGATION_REDESIGN.md deleted file mode 100644 index 0519ecb..0000000 --- a/STEP_NAVIGATION_REDESIGN.md +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/eslint.config.ts b/eslint.config.ts index 4fb5b97..b539dfd 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -13,13 +13,16 @@ export default defineConfig([ rules: { 'vue/multi-word-component-names': 'off', '@typescript-eslint/no-unused-vars': 'warn', - '@typescript-eslint/no-explicit-any': 'warn', + '@typescript-eslint/no-explicit-any': 'off', // 完全禁用 any 检查 // 关闭所有需要类型信息的规则 '@typescript-eslint/no-unsafe-assignment': 'off', '@typescript-eslint/no-unsafe-member-access': 'off', '@typescript-eslint/no-unsafe-call': 'off', '@typescript-eslint/no-unsafe-return': 'off', - '@typescript-eslint/no-unsafe-argument': 'off' + '@typescript-eslint/no-unsafe-argument': 'off', + '@typescript-eslint/no-empty-object-type': 'off', // 允许空接口 + '@typescript-eslint/no-unused-expressions': 'warn', // 改为警告而非错误 + 'no-unused-expressions': 'off' } } ]) diff --git a/src/assets/images/afterditing/color/卡片-日落增色.png b/src/assets/images/afterditing/color/卡片-日落增色.png new file mode 100644 index 0000000..80a0199 Binary files /dev/null and b/src/assets/images/afterditing/color/卡片-日落增色.png differ diff --git a/src/assets/images/afterditing/color/卡片-智能调色.png b/src/assets/images/afterditing/color/卡片-智能调色.png index fb6b998..6d94ad9 100644 Binary files a/src/assets/images/afterditing/color/卡片-智能调色.png and b/src/assets/images/afterditing/color/卡片-智能调色.png differ diff --git a/src/assets/images/afterditing/color/卡片-落日火烧云.png b/src/assets/images/afterditing/color/卡片-落日火烧云.png new file mode 100644 index 0000000..70ca195 Binary files /dev/null and b/src/assets/images/afterditing/color/卡片-落日火烧云.png differ diff --git a/src/assets/images/afterditing/color/原图.png b/src/assets/images/afterditing/color/原图.png index 54ca147..ba64a09 100644 Binary files a/src/assets/images/afterditing/color/原图.png and b/src/assets/images/afterditing/color/原图.png differ diff --git a/src/assets/images/afterditing/color/日落增色.png b/src/assets/images/afterditing/color/日落增色.png new file mode 100644 index 0000000..c675394 Binary files /dev/null and b/src/assets/images/afterditing/color/日落增色.png differ diff --git a/src/assets/images/afterditing/color/智能调色.png b/src/assets/images/afterditing/color/智能调色.png index e857c99..e5f2535 100644 Binary files a/src/assets/images/afterditing/color/智能调色.png and b/src/assets/images/afterditing/color/智能调色.png differ diff --git a/src/assets/images/afterditing/color/落日火烧云.png b/src/assets/images/afterditing/color/落日火烧云.png new file mode 100644 index 0000000..7093bcc Binary files /dev/null and b/src/assets/images/afterditing/color/落日火烧云.png differ diff --git a/src/assets/images/equipment/内容-安卓小米.png b/src/assets/images/equipment/内容-安卓小米.png index 7d27721..b542753 100644 Binary files a/src/assets/images/equipment/内容-安卓小米.png and b/src/assets/images/equipment/内容-安卓小米.png differ diff --git a/src/assets/images/equipment/内容-苹果.png b/src/assets/images/equipment/内容-苹果.png index 3c055f2..8444bef 100644 Binary files a/src/assets/images/equipment/内容-苹果.png and b/src/assets/images/equipment/内容-苹果.png differ diff --git a/src/assets/images/home/guide/action-btn.png b/src/assets/images/home/guide/action-btn.png index 4f619d3..bc2bd8e 100644 Binary files a/src/assets/images/home/guide/action-btn.png and b/src/assets/images/home/guide/action-btn.png differ diff --git a/src/assets/images/home/guide/bg.png b/src/assets/images/home/guide/bg.png index ec7b3a2..271e4bc 100644 Binary files a/src/assets/images/home/guide/bg.png and b/src/assets/images/home/guide/bg.png differ diff --git a/src/assets/images/home/guide/cz-btn.png b/src/assets/images/home/guide/cz-btn.png index a91f40b..b10c8af 100644 Binary files a/src/assets/images/home/guide/cz-btn.png and b/src/assets/images/home/guide/cz-btn.png differ diff --git a/src/assets/images/home/guide/kc-btn.png b/src/assets/images/home/guide/kc-btn.png index cd57231..d4e2a39 100644 Binary files a/src/assets/images/home/guide/kc-btn.png and b/src/assets/images/home/guide/kc-btn.png differ diff --git a/src/assets/images/shooting/对角线构图1.png b/src/assets/images/shooting/对角线构图1.png new file mode 100644 index 0000000..a894c39 Binary files /dev/null and b/src/assets/images/shooting/对角线构图1.png differ diff --git a/src/assets/images/shooting/对角线构图2.png b/src/assets/images/shooting/对角线构图2.png new file mode 100644 index 0000000..187022f Binary files /dev/null and b/src/assets/images/shooting/对角线构图2.png differ diff --git a/src/assets/images/shooting/居中构图1.png b/src/assets/images/shooting/居中构图1.png new file mode 100644 index 0000000..fe535a4 Binary files /dev/null and b/src/assets/images/shooting/居中构图1.png differ diff --git a/src/assets/images/shooting/居中构图2.png b/src/assets/images/shooting/居中构图2.png new file mode 100644 index 0000000..1f9635b Binary files /dev/null and b/src/assets/images/shooting/居中构图2.png differ diff --git a/src/assets/images/shooting/示意图-对角线.png b/src/assets/images/shooting/示意图-对角线.png new file mode 100644 index 0000000..7221a79 Binary files /dev/null and b/src/assets/images/shooting/示意图-对角线.png differ diff --git a/src/assets/images/shooting/示意图-居中.png b/src/assets/images/shooting/示意图-居中.png new file mode 100644 index 0000000..0797db3 Binary files /dev/null and b/src/assets/images/shooting/示意图-居中.png differ diff --git a/src/assets/images/work/专业剖析小屏.png b/src/assets/images/work/专业剖析小屏.png new file mode 100644 index 0000000..162be95 Binary files /dev/null and b/src/assets/images/work/专业剖析小屏.png differ diff --git a/src/components/KnowledgeCard/KnowledgeCard.vue b/src/components/KnowledgeCard/KnowledgeCard.vue new file mode 100644 index 0000000..c317513 --- /dev/null +++ b/src/components/KnowledgeCard/KnowledgeCard.vue @@ -0,0 +1,137 @@ + + + + + diff --git a/src/components/Video/Video.vue b/src/components/Video/Video.vue new file mode 100644 index 0000000..730e6ad --- /dev/null +++ b/src/components/Video/Video.vue @@ -0,0 +1,486 @@ + + + + + diff --git a/src/components/Video/index.ts b/src/components/Video/index.ts new file mode 100644 index 0000000..218cfb5 --- /dev/null +++ b/src/components/Video/index.ts @@ -0,0 +1,2 @@ +export { default as Video } from './Video.vue' +export type {} from './Video.vue' diff --git a/src/components/index.ts b/src/components/index.ts index 9b069e7..ccbbfb6 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -22,3 +22,6 @@ export * from './Modal' // 遮罩层组件 export * from './Overlay' + +// 视频组件 +export * from './Video' diff --git a/src/views/afterditing/color.vue b/src/views/afterditing/color.vue index 64418d0..92a991a 100644 --- a/src/views/afterditing/color.vue +++ b/src/views/afterditing/color.vue @@ -20,15 +20,15 @@ const colorBarList = ref([ }, { id: 2, - name: '滤镜-冬日物语', - image: getStaticImage('afterditing/color/冬日物语.jpg'), - Screenshot: getStaticImage('afterditing/color/卡片-冬日物语.png') + name: '滤镜-日落增色', + image: getStaticImage('afterditing/color/日落增色.png'), + Screenshot: getStaticImage('afterditing/color/卡片-日落增色.png') }, { id: 3, - name: '滤镜-日落电影', - image: getStaticImage('afterditing/color/落日余晖.jpg'), - Screenshot: getStaticImage('afterditing/color/卡片-落日余晖.png') + name: '滤镜-落日火烧云', + image: getStaticImage('afterditing/color/落日火烧云.png'), + Screenshot: getStaticImage('afterditing/color/卡片-落日火烧云.png') } ]) diff --git a/src/views/home/index.vue b/src/views/home/index.vue index 23f7012..f02e18a 100644 --- a/src/views/home/index.vue +++ b/src/views/home/index.vue @@ -12,15 +12,15 @@ import { ImgButton } from '@/components/Button' > -
+
-
+
-
+
diff --git a/src/views/midterm-shooting/equipment/index.vue b/src/views/midterm-shooting/equipment/index.vue index 36d82b0..4ef0c5d 100644 --- a/src/views/midterm-shooting/equipment/index.vue +++ b/src/views/midterm-shooting/equipment/index.vue @@ -237,7 +237,7 @@ const currentHighlight = computed(() => stepIndex.value === 0 ? '.img-switch-item--vlog' : '.work-border' ) - diff --git a/src/views/skill/components/IconLayer.vue b/src/views/skill/components/IconLayer.vue new file mode 100644 index 0000000..a29b484 --- /dev/null +++ b/src/views/skill/components/IconLayer.vue @@ -0,0 +1,24 @@ + + + diff --git a/src/views/skill/components/ModuleSwitcher.vue b/src/views/skill/components/ModuleSwitcher.vue new file mode 100644 index 0000000..872704a --- /dev/null +++ b/src/views/skill/components/ModuleSwitcher.vue @@ -0,0 +1,40 @@ + + + + + diff --git a/src/views/skill/index.vue b/src/views/skill/index.vue index 80f3c42..5f8d635 100644 --- a/src/views/skill/index.vue +++ b/src/views/skill/index.vue @@ -1,239 +1,155 @@ diff --git a/src/views/skill/useSkillState.ts b/src/views/skill/useSkillState.ts new file mode 100644 index 0000000..d4bef74 --- /dev/null +++ b/src/views/skill/useSkillState.ts @@ -0,0 +1,214 @@ +import { ref, computed } from 'vue' + +// 分类配置 +interface CategoryConfig { + icons: string[] + positions: { top: string; left: string }[] +} + +// 模块配置 +interface ModuleConfig { + name: string + value: number + categories: Record +} + +// 知识卡片按钮数据结构(与 shooting/index.vue 对齐) +export type KnowledgeBtn = { + key: string + name: string + btnImage: string + images: string[] + desc: string +} + +export function useSkillState() { + // 模块/分类/图标层级状态(仅保留必要业务状态) + const selectedModule = ref(1) + const selectedCategory = ref('') + const showSubIcons = ref(false) + const selectedPrimaryIcon = ref(null) + + const moduleList = ref([ + { + name: '技能树-新手启航', + value: 1, + categories: { + 拍摄基础: { + icons: ['skill/画面构图未选中', 'skill/景别', 'skill/运镜技巧', 'skill/光线运用'], + positions: [ + { top: '36%', left: '23%' }, + { top: '15%', left: '34%' }, + { top: '20%', left: '45%' }, + { top: '28%', left: '58%' } + ] + }, + 内容策划: { + icons: ['skill/画面构图未选中', 'skill/三分法构图', 'skill/居中构图', 'skill/对角线构图'], + positions: [ + { top: '36%', left: '23%' }, + { top: '15%', left: '34%' }, + { top: '20%', left: '45%' }, + { top: '28%', left: '58%' } + ] + }, + 拍摄执行: { + icons: ['skill/画面构图未选中', 'skill/景别', 'skill/运镜技巧', 'skill/光线运用'], + positions: [ + { top: '36%', left: '23%' }, + { top: '15%', left: '34%' }, + { top: '20%', left: '45%' }, + { top: '28%', left: '58%' } + ] + }, + 后期制作: { + icons: ['skill/画面构图未选中', 'skill/三分法构图', 'skill/居中构图', 'skill/对角线构图'], + positions: [ + { top: '36%', left: '23%' }, + { top: '15%', left: '34%' }, + { top: '20%', left: '45%' }, + { top: '28%', left: '58%' } + ] + }, + 版权伦理意识: { + icons: ['skill/画面构图未选中', 'skill/景别', 'skill/运镜技巧', 'skill/光线运用'], + positions: [ + { top: '36%', left: '23%' }, + { top: '15%', left: '34%' }, + { top: '20%', left: '45%' }, + { top: '28%', left: '58%' } + ] + } + } + }, + { + name: '技能树-vlog', + value: 2, + categories: { + 拍摄基础: { + icons: ['skill/画面构图未选中', 'skill/景别', 'skill/运镜技巧', 'skill/光线运用'], + positions: [ + { top: '36%', left: '23%' }, + { top: '15%', left: '34%' }, + { top: '20%', left: '45%' }, + { top: '28%', left: '58%' } + ] + }, + 内容策划: { + icons: ['skill/画面构图未选中', 'skill/三分法构图', 'skill/居中构图', 'skill/对角线构图'], + positions: [ + { top: '36%', left: '23%' }, + { top: '15%', left: '34%' }, + { top: '20%', left: '45%' }, + { top: '28%', left: '58%' } + ] + }, + 拍摄执行: { + icons: ['skill/画面构图未选中', 'skill/景别', 'skill/运镜技巧', 'skill/光线运用'], + positions: [ + { top: '36%', left: '23%' }, + { top: '15%', left: '34%' }, + { top: '20%', left: '45%' }, + { top: '28%', left: '58%' } + ] + }, + 后期制作: { + icons: ['skill/画面构图未选中', 'skill/三分法构图', 'skill/居中构图', 'skill/对角线构图'], + positions: [ + { top: '36%', left: '23%' }, + { top: '15%', left: '34%' }, + { top: '20%', left: '45%' }, + { top: '28%', left: '58%' } + ] + }, + 版权伦理意识: { + icons: ['skill/画面构图未选中', 'skill/景别', 'skill/运镜技巧', 'skill/光线运用'], + positions: [ + { top: '36%', left: '23%' }, + { top: '15%', left: '34%' }, + { top: '20%', left: '45%' }, + { top: '28%', left: '58%' } + ] + } + } + } + ]) + + const currentModule = computed(() => { + return moduleList.value.find(item => item.value === selectedModule.value) || moduleList.value[0] + }) + + const nextModule = () => { + if (selectedModule.value === moduleList.value.length) { + selectedModule.value = 1 + } else { + selectedModule.value++ + } + } + + const prevModule = () => { + if (selectedModule.value === 1) { + selectedModule.value = moduleList.value.length + } else { + selectedModule.value-- + } + } + + const handleCategoryClick = (categoryName: string) => { + selectedCategory.value = categoryName + showSubIcons.value = false + selectedPrimaryIcon.value = null + } + + const currentCategoryConfig = computed(() => { + if (!selectedCategory.value) return null + return currentModule.value.categories[selectedCategory.value] || null + }) + + const displayedIcons = computed(() => { + const cfg = currentCategoryConfig.value + if (!cfg) return [] as string[] + if (showSubIcons.value && selectedPrimaryIcon.value) { + return ['skill/画面构图选中', 'skill/三分法构图', 'skill/居中构图', 'skill/对角线构图'] + } + return cfg.icons + }) + + type IconAction = + | { type: 'navigate'; payload: { name: string } } + | { type: 'expand' } + | { type: 'openKnowledge'; payload: { name: '三分法构图' | '居中构图' | '对角线构图' } } + | null + + const getIconAction = (icon: string): IconAction => { + if (icon === 'skill/画面构图未选中' && selectedCategory.value === '拍摄执行') { + if (selectedModule.value === 1) return { type: 'navigate', payload: { name: 'SkillVdieo' } } + if (selectedModule.value === 2) return { type: 'expand' } + } + if (showSubIcons.value && selectedModule.value === 2 && selectedCategory.value === '拍摄执行') { + const map: Record = { + 'skill/三分法构图': '三分法构图', + 'skill/居中构图': '居中构图', + 'skill/对角线构图': '对角线构图' + } + if (icon in map) return { type: 'openKnowledge', payload: { name: map[icon] } } + } + return null + } + + return { + // module switcher + currentModule, + nextModule, + prevModule, + // category & icons + selectedCategory, + handleCategoryClick, + currentCategoryConfig, + displayedIcons, + selectedModule, + showSubIcons, + selectedPrimaryIcon, + getIconAction + } +} diff --git a/src/views/test-step-navigation.vue b/src/views/test-step-navigation.vue deleted file mode 100644 index 0519ecb..0000000 --- a/src/views/test-step-navigation.vue +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/views/vlog/video/index.vue b/src/views/vlog/video/index.vue index 7c67b46..c78b4d0 100644 --- a/src/views/vlog/video/index.vue +++ b/src/views/vlog/video/index.vue @@ -3,6 +3,7 @@ import { computed, nextTick, onMounted, ref } from 'vue' import { useRouter, useRoute } from 'vue-router' import ImgButton from '@/components/Button/ImgButton.vue' import { GuideSteps, StepNavigation } from '@/components/Guide' +import { Video } from '@/components' import { getStaticImage, IMAGE_PATHS } from '@/utils' import second from '/video/Vlog模块_任务取景框_专业剖析_基础景别运用.mp4' import third from '/video/Vlog模块_任务取景框_专业剖析_画面构图.mp4' @@ -13,7 +14,8 @@ import six from '/video/Vlog模块_任务取景框_专业剖析_素材导入、 const router = useRouter() const route = useRoute() -const videoRef = ref() +// 受控播放开关(用于切换到下一个视频时自动播放) +const playing = ref(false) const status = ref(false) //引导步骤 @@ -68,6 +70,11 @@ const currentVideoIndex = ref(0) //按顺序播放 const currentVideo = computed(() => videoList[currentVideoIndex.value]) +const resolvedSrc = computed(() => { + if (key.value === 'case') return '/video/案例赏析-美食小确幸:桂花酒酿小圆子.mp4' + if (key.value === 'profession') return currentVideo.value + return '' +}) const handleVideoChange = () => { if (currentVideoIndex.value < videoList.length - 1) { currentVideoIndex.value++ @@ -83,10 +90,8 @@ const handleVideoChange = () => { return } nextTick(() => { - if (!videoRef.value) return - videoRef.value.muted = false - videoRef.value.volume = 1 - videoRef.value.play() + // 使用受控播放来触发下一个视频自动播放 + playing.value = true }) } @@ -97,16 +102,12 @@ const handleClose = () => { const image = computed(() => route.query.image as string) const key = computed(() => route.query.key as string) -const handleClick = () => { - if (!videoRef.value) return - videoRef.value.muted = false - videoRef.value.volume = 1 -} +const handleClick = () => {} -const handlePlay = () => { - if (!videoRef.value) return - videoRef.value.muted = false - videoRef.value.volume = 1 +const handlePlay = () => {} + +const onEnded = () => { + if (key.value === 'profession') handleVideoChange() } const handleComplete = () => { @@ -132,10 +133,7 @@ const handleStepClick = (index: number) => { currentVideoIndex.value = index currentNavigationStep.value = index nextTick(() => { - if (!videoRef.value) return - videoRef.value.muted = false - videoRef.value.volume = 1 - videoRef.value.play() + playing.value = true }) } @@ -152,12 +150,14 @@ onMounted(() => {