feat: 画风选择卡片用静态图片替换 emoji 占位,支持选中/未选中状态切换
- 导入 8 张画风图片(卡通/水彩/水墨/彩铅 × 选中/未选中) - 根据选中状态动态切换预览图 - 删除 emoji SVG fallback 逻辑 - 隐藏油画、剪贴画(hidden: true) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
BIN
frontend/src/assets/images/style-cartoon-active.png
Normal file
|
After Width: | Height: | Size: 187 KiB |
BIN
frontend/src/assets/images/style-cartoon-normal.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
frontend/src/assets/images/style-ink-active.png
Normal file
|
After Width: | Height: | Size: 223 KiB |
BIN
frontend/src/assets/images/style-ink-normal.png
Normal file
|
After Width: | Height: | Size: 236 KiB |
BIN
frontend/src/assets/images/style-pencil-active.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
frontend/src/assets/images/style-pencil-normal.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
frontend/src/assets/images/style-watercolor-active.png
Normal file
|
After Width: | Height: | Size: 234 KiB |
BIN
frontend/src/assets/images/style-watercolor-normal.png
Normal file
|
After Width: | Height: | Size: 247 KiB |
@ -1,3 +1,6 @@
|
||||
<script lang="ts">
|
||||
export default { name: 'StyleSelectView' }
|
||||
</script>
|
||||
<template>
|
||||
<div class="style-page page-fullscreen">
|
||||
<PageHeader title="选择画风" subtitle="为绘本挑选一种你喜欢的画风" :step="3" />
|
||||
@ -11,7 +14,7 @@
|
||||
|
||||
<div class="style-grid">
|
||||
<div
|
||||
v-for="s in styles"
|
||||
v-for="s in visibleStyles"
|
||||
:key="s.styleId"
|
||||
class="style-card"
|
||||
:class="{ selected: selected === s.styleId }"
|
||||
@ -24,10 +27,9 @@
|
||||
|
||||
<div class="style-preview">
|
||||
<img
|
||||
:src="previewUrl(s.styleId)"
|
||||
:src="selected === s.styleId ? s.imgActive : s.img"
|
||||
:alt="s.styleName"
|
||||
class="style-preview-img"
|
||||
@error="(e) => onPreviewError(e, s.hue)"
|
||||
/>
|
||||
</div>
|
||||
<div class="style-info">
|
||||
@ -58,6 +60,16 @@ import {
|
||||
import PageHeader from '@/components/aicreate/PageHeader.vue'
|
||||
import { useAicreateStore } from '@/stores/aicreate'
|
||||
|
||||
// 导入画风图片:{style}-normal.png 未选中,{style}-active.png 选中
|
||||
import styleCartoonNormal from '@/assets/images/style-cartoon-normal.png'
|
||||
import styleCartoonActive from '@/assets/images/style-cartoon-active.png'
|
||||
import styleWatercolorNormal from '@/assets/images/style-watercolor-normal.png'
|
||||
import styleWatercolorActive from '@/assets/images/style-watercolor-active.png'
|
||||
import styleInkNormal from '@/assets/images/style-ink-normal.png'
|
||||
import styleInkActive from '@/assets/images/style-ink-active.png'
|
||||
import stylePencilNormal from '@/assets/images/style-pencil-normal.png'
|
||||
import stylePencilActive from '@/assets/images/style-pencil-active.png'
|
||||
|
||||
const router = useRouter()
|
||||
const store = useAicreateStore()
|
||||
const selected = ref('')
|
||||
@ -66,40 +78,26 @@ interface StyleItem {
|
||||
styleId: string
|
||||
styleName: string
|
||||
desc: string
|
||||
/** 用于预览图加载失败时的 fallback 渐变色调(HSL 色相) */
|
||||
hue: number
|
||||
/** 未选中态图片 */
|
||||
img: string
|
||||
/** 选中态图片 */
|
||||
imgActive: string
|
||||
/** hidden=true 时暂不展示,后续开发开放 */
|
||||
hidden?: boolean
|
||||
}
|
||||
|
||||
const styles: StyleItem[] = [
|
||||
{ styleId: 'style_cartoon', styleName: '卡通风格', desc: '色彩鲜明,充满童趣', hue: 30 },
|
||||
{ styleId: 'style_watercolor', styleName: '水彩风格', desc: '柔和透明,梦幻浪漫', hue: 200 },
|
||||
{ styleId: 'style_ink', styleName: '水墨国风', desc: '古韵悠长,意境深远', hue: 270 },
|
||||
{ styleId: 'style_pencil', styleName: '彩铅风格', desc: '细腻温暖,自然亲切', hue: 50 },
|
||||
{ styleId: 'style_oilpaint', styleName: '油画风格', desc: '色彩浓郁,质感丰富', hue: 25 },
|
||||
{ styleId: 'style_collage', styleName: '剪贴画', desc: '趣味拼贴,创意满满', hue: 320 },
|
||||
{ styleId: 'style_cartoon', styleName: '卡通风格', desc: '色彩鲜明,充满童趣', img: styleCartoonNormal, imgActive: styleCartoonActive },
|
||||
{ styleId: 'style_watercolor', styleName: '水彩风格', desc: '柔和透明,梦幻浪漫', img: styleWatercolorNormal, imgActive: styleWatercolorActive },
|
||||
{ styleId: 'style_ink', styleName: '水墨国风', desc: '古韵悠长,意境深远', img: styleInkNormal, imgActive: styleInkActive },
|
||||
{ styleId: 'style_pencil', styleName: '彩铅风格', desc: '细腻温暖,自然亲切', img: stylePencilNormal, imgActive: stylePencilActive },
|
||||
// 油画、剪贴画暂不开放,后续开发后去掉 hidden 即可
|
||||
{ styleId: 'style_oilpaint', styleName: '油画风格', desc: '色彩浓郁,质感丰富', img: '', imgActive: '', hidden: true },
|
||||
{ styleId: 'style_collage', styleName: '剪贴画', desc: '趣味拼贴,创意满满', img: '', imgActive: '', hidden: true },
|
||||
]
|
||||
|
||||
/** 预览图路径约定:/public/aicreate/styles/{styleId}.jpg */
|
||||
const previewUrl = (id: string) => `/aicreate/styles/${id}.jpg`
|
||||
|
||||
/** 加载失败时切换为对应色调的 SVG 渐变占位 */
|
||||
const fallbackSvg = (hue: number) =>
|
||||
'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(
|
||||
`<svg xmlns="http://www.w3.org/2000/svg" width="240" height="240" viewBox="0 0 240 240">` +
|
||||
`<defs><linearGradient id="g" x1="0" y1="0" x2="1" y2="1">` +
|
||||
`<stop offset="0" stop-color="hsl(${hue},65%,84%)"/>` +
|
||||
`<stop offset="1" stop-color="hsl(${(hue + 30) % 360},70%,66%)"/>` +
|
||||
`</linearGradient></defs>` +
|
||||
`<rect width="240" height="240" fill="url(#g)"/>` +
|
||||
`</svg>`
|
||||
)
|
||||
|
||||
const onPreviewError = (e: Event, hue: number) => {
|
||||
const img = e.target as HTMLImageElement
|
||||
if (img.dataset.fallback === '1') return // 防止 fallback 也失败导致死循环
|
||||
img.dataset.fallback = '1'
|
||||
img.src = fallbackSvg(hue)
|
||||
}
|
||||
/** 页面可见的风格列表 */
|
||||
const visibleStyles = styles.filter(s => !s.hidden)
|
||||
|
||||
const goNext = () => {
|
||||
store.selectedStyle = selected.value
|
||||
|
||||