修改样式
This commit is contained in:
parent
d9abd6939c
commit
8210bf0ad3
@ -62,6 +62,10 @@ export class AI3DService {
|
|||||||
const externalTaskId = await this.ai3dProvider.submitTask(
|
const externalTaskId = await this.ai3dProvider.submitTask(
|
||||||
dto.inputType,
|
dto.inputType,
|
||||||
dto.inputContent,
|
dto.inputContent,
|
||||||
|
{
|
||||||
|
generateType: dto.generateType,
|
||||||
|
faceCount: dto.faceCount,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// 4. 更新状态为处理中
|
// 4. 更新状态为处理中
|
||||||
|
|||||||
@ -1,4 +1,22 @@
|
|||||||
import { IsString, IsIn, IsNotEmpty, MaxLength } from 'class-validator';
|
import {
|
||||||
|
IsString,
|
||||||
|
IsIn,
|
||||||
|
IsNotEmpty,
|
||||||
|
MaxLength,
|
||||||
|
IsOptional,
|
||||||
|
IsInt,
|
||||||
|
Min,
|
||||||
|
Max,
|
||||||
|
} from 'class-validator';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模型生成类型
|
||||||
|
* Normal: 带纹理
|
||||||
|
* LowPoly: 低多边形
|
||||||
|
* Geometry: 白模
|
||||||
|
* Sketch: 草图
|
||||||
|
*/
|
||||||
|
export type GenerateType = 'Normal' | 'LowPoly' | 'Geometry' | 'Sketch';
|
||||||
|
|
||||||
export class CreateTaskDto {
|
export class CreateTaskDto {
|
||||||
@IsString()
|
@IsString()
|
||||||
@ -9,4 +27,17 @@ export class CreateTaskDto {
|
|||||||
@IsNotEmpty({ message: '输入内容不能为空' })
|
@IsNotEmpty({ message: '输入内容不能为空' })
|
||||||
@MaxLength(2000, { message: '输入内容最多2000个字符' })
|
@MaxLength(2000, { message: '输入内容最多2000个字符' })
|
||||||
inputContent: string;
|
inputContent: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
@IsIn(['Normal', 'LowPoly', 'Geometry', 'Sketch'], {
|
||||||
|
message: '模型类型必须是 Normal、LowPoly、Geometry 或 Sketch',
|
||||||
|
})
|
||||||
|
generateType?: GenerateType;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsInt({ message: '模型面数必须是整数' })
|
||||||
|
@Min(10000, { message: '模型面数最小为10000' })
|
||||||
|
@Max(1500000, { message: '模型面数最大为1500000' })
|
||||||
|
faceCount?: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,16 @@ export interface AI3DGenerateResult {
|
|||||||
errorMessage?: string; // 错误信息
|
errorMessage?: string; // 错误信息
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模型生成配置选项
|
||||||
|
*/
|
||||||
|
export interface AI3DGenerateOptions {
|
||||||
|
/** 模型生成类型:Normal-带纹理, LowPoly-低多边形, Geometry-白模, Sketch-草图 */
|
||||||
|
generateType?: 'Normal' | 'LowPoly' | 'Geometry' | 'Sketch';
|
||||||
|
/** 模型面数:10000-1500000,默认500000 */
|
||||||
|
faceCount?: number;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AI 3D 服务提供者接口
|
* AI 3D 服务提供者接口
|
||||||
* 支持 Mock、腾讯混元、Meshy 等实现
|
* 支持 Mock、腾讯混元、Meshy 等实现
|
||||||
@ -20,11 +30,13 @@ export interface AI3DProvider {
|
|||||||
* 提交生成任务
|
* 提交生成任务
|
||||||
* @param inputType 输入类型:text | image
|
* @param inputType 输入类型:text | image
|
||||||
* @param inputContent 输入内容:文字描述或图片URL
|
* @param inputContent 输入内容:文字描述或图片URL
|
||||||
|
* @param options 可选配置项(仅文生3D支持)
|
||||||
* @returns 外部任务ID
|
* @returns 外部任务ID
|
||||||
*/
|
*/
|
||||||
submitTask(
|
submitTask(
|
||||||
inputType: 'text' | 'image',
|
inputType: 'text' | 'image',
|
||||||
inputContent: string,
|
inputContent: string,
|
||||||
|
options?: AI3DGenerateOptions,
|
||||||
): Promise<string>;
|
): Promise<string>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
import { Injectable, Logger } from '@nestjs/common';
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { AI3DProvider, AI3DGenerateResult } from './ai-3d-provider.interface';
|
import {
|
||||||
|
AI3DProvider,
|
||||||
|
AI3DGenerateResult,
|
||||||
|
AI3DGenerateOptions,
|
||||||
|
} from './ai-3d-provider.interface';
|
||||||
import { TencentCloudSigner } from '../utils/tencent-cloud-sign';
|
import { TencentCloudSigner } from '../utils/tencent-cloud-sign';
|
||||||
import { ZipHandler } from '../utils/zip-handler';
|
import { ZipHandler } from '../utils/zip-handler';
|
||||||
|
|
||||||
@ -43,6 +47,7 @@ export class HunyuanAI3DProvider implements AI3DProvider {
|
|||||||
async submitTask(
|
async submitTask(
|
||||||
inputType: 'text' | 'image',
|
inputType: 'text' | 'image',
|
||||||
inputContent: string,
|
inputContent: string,
|
||||||
|
options?: AI3DGenerateOptions,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
try {
|
try {
|
||||||
// 构造请求参数
|
// 构造请求参数
|
||||||
@ -51,7 +56,19 @@ export class HunyuanAI3DProvider implements AI3DProvider {
|
|||||||
if (inputType === 'text') {
|
if (inputType === 'text') {
|
||||||
// 文生3D:使用 Prompt
|
// 文生3D:使用 Prompt
|
||||||
payload.Prompt = inputContent;
|
payload.Prompt = inputContent;
|
||||||
this.logger.log(`提交文生3D任务: ${inputContent.substring(0, 50)}...`);
|
|
||||||
|
// 文生3D支持额外参数
|
||||||
|
if (options?.generateType) {
|
||||||
|
payload.GenerateType = options.generateType;
|
||||||
|
}
|
||||||
|
if (options?.faceCount) {
|
||||||
|
payload.FaceCount = options.faceCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.log(
|
||||||
|
`提交文生3D任务: ${inputContent.substring(0, 50)}... ` +
|
||||||
|
`[类型: ${options?.generateType || 'Normal'}, 面数: ${options?.faceCount || 500000}]`,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// 图生3D:使用 ImageUrl 或 ImageBase64
|
// 图生3D:使用 ImageUrl 或 ImageBase64
|
||||||
if (
|
if (
|
||||||
@ -59,14 +76,20 @@ export class HunyuanAI3DProvider implements AI3DProvider {
|
|||||||
inputContent.startsWith('https://')
|
inputContent.startsWith('https://')
|
||||||
) {
|
) {
|
||||||
payload.ImageUrl = inputContent;
|
payload.ImageUrl = inputContent;
|
||||||
this.logger.log(`提交图生3D任务 (URL): ${inputContent}`);
|
|
||||||
} else {
|
} else {
|
||||||
// 假设是 Base64 编码的图片
|
// 假设是 Base64 编码的图片
|
||||||
payload.ImageBase64 = inputContent;
|
payload.ImageBase64 = inputContent;
|
||||||
this.logger.log(
|
|
||||||
`提交图生3D任务 (Base64): ${inputContent.substring(0, 30)}...`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 图生3D也支持模型类型
|
||||||
|
if (options?.generateType) {
|
||||||
|
payload.GenerateType = options.generateType;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.log(
|
||||||
|
`提交图生3D任务: ${inputContent.substring(0, 50)}... ` +
|
||||||
|
`[类型: ${options?.generateType || 'Normal'}]`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成签名和请求头
|
// 生成签名和请求头
|
||||||
|
|||||||
@ -40,12 +40,21 @@ export interface AI3DTask {
|
|||||||
completeTime?: string;
|
completeTime?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模型生成类型
|
||||||
|
*/
|
||||||
|
export type AI3DGenerateType = "Normal" | "LowPoly" | "Geometry" | "Sketch";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建任务参数
|
* 创建任务参数
|
||||||
*/
|
*/
|
||||||
export interface CreateAI3DTaskParams {
|
export interface CreateAI3DTaskParams {
|
||||||
inputType: AI3DInputType;
|
inputType: AI3DInputType;
|
||||||
inputContent: string;
|
inputContent: string;
|
||||||
|
/** 模型生成类型:Normal-带纹理, LowPoly-低多边形, Geometry-白模, Sketch-草图 */
|
||||||
|
generateType?: AI3DGenerateType;
|
||||||
|
/** 模型面数:10000-1500000,默认500000 */
|
||||||
|
faceCount?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -567,10 +567,15 @@ $gradient-card: linear-gradient(
|
|||||||
// ==========================================
|
// ==========================================
|
||||||
.model-grid {
|
.model-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fit, 300px);
|
grid-template-columns: repeat(2, 300px);
|
||||||
gap: 24px;
|
gap: 24px;
|
||||||
margin-bottom: 40px;
|
margin-bottom: 40px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
|
// 只有1个卡片时居中
|
||||||
|
&:has(.model-card:only-child) {
|
||||||
|
grid-template-columns: 300px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==========================================
|
// ==========================================
|
||||||
|
|||||||
@ -43,14 +43,17 @@
|
|||||||
<div class="input-hint">
|
<div class="input-hint">
|
||||||
用文字描述你的想法,AI 将为你生成精美的 3D 模型
|
用文字描述你的想法,AI 将为你生成精美的 3D 模型
|
||||||
</div>
|
</div>
|
||||||
<a-textarea
|
<div class="textarea-wrapper">
|
||||||
v-model:value="textContent"
|
<a-textarea
|
||||||
placeholder="例如:一只卡通风格的橙色小猫,蓝色的大眼睛,尾巴卷曲..."
|
v-model:value="textContent"
|
||||||
:rows="6"
|
placeholder="例如:一只卡通风格的橙色小猫,蓝色的大眼睛,尾巴卷曲..."
|
||||||
:maxlength="150"
|
:rows="5"
|
||||||
show-count
|
:maxlength="1024"
|
||||||
class="text-input"
|
class="text-input"
|
||||||
/>
|
/>
|
||||||
|
<span class="char-count">{{ textContent.length }}/1024</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="sample-section">
|
<div class="sample-section">
|
||||||
<div class="sample-header">
|
<div class="sample-header">
|
||||||
<span class="sample-title">灵感推荐</span>
|
<span class="sample-title">灵感推荐</span>
|
||||||
@ -67,6 +70,31 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 模型设置 -->
|
||||||
|
<div class="model-settings">
|
||||||
|
<div class="setting-row">
|
||||||
|
<div class="setting-item">
|
||||||
|
<span class="setting-label">模型类型</span>
|
||||||
|
<a-select v-model:value="generateType" class="setting-select">
|
||||||
|
<a-select-option value="Normal">带纹理</a-select-option>
|
||||||
|
<a-select-option value="LowPoly">低多边形</a-select-option>
|
||||||
|
<a-select-option value="Geometry">白模</a-select-option>
|
||||||
|
<a-select-option value="Sketch">草图</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</div>
|
||||||
|
<div class="setting-item">
|
||||||
|
<span class="setting-label">模型面数</span>
|
||||||
|
<a-select v-model:value="faceCount" class="setting-select">
|
||||||
|
<a-select-option :value="50000">5万面</a-select-option>
|
||||||
|
<a-select-option :value="100000">10万面</a-select-option>
|
||||||
|
<a-select-option :value="300000">30万面</a-select-option>
|
||||||
|
<a-select-option :value="500000">50万面</a-select-option>
|
||||||
|
<a-select-option :value="1000000">100万面</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 图生3D上传 -->
|
<!-- 图生3D上传 -->
|
||||||
@ -79,18 +107,40 @@
|
|||||||
上传参考图片,AI 将智能识别并生成 3D 模型
|
上传参考图片,AI 将智能识别并生成 3D 模型
|
||||||
</div>
|
</div>
|
||||||
<a-upload-dragger
|
<a-upload-dragger
|
||||||
v-model:file-list="imageFileList"
|
:file-list="[]"
|
||||||
:before-upload="handleBeforeUpload"
|
:before-upload="handleBeforeUpload"
|
||||||
|
:show-upload-list="false"
|
||||||
:max-count="1"
|
:max-count="1"
|
||||||
accept="image/*"
|
accept="image/*"
|
||||||
class="image-upload"
|
class="image-upload"
|
||||||
>
|
>
|
||||||
<p class="upload-icon">
|
<template v-if="imageUrl">
|
||||||
<PictureOutlined />
|
<img :src="imageUrl" alt="预览" class="upload-preview-image" />
|
||||||
</p>
|
<div class="upload-change-hint">点击更换图片</div>
|
||||||
<p class="upload-text">点击或拖拽图片到此处</p>
|
</template>
|
||||||
<p class="upload-hint">支持 JPG、PNG 格式,最大 10MB</p>
|
<template v-else>
|
||||||
|
<p class="upload-icon">
|
||||||
|
<PictureOutlined />
|
||||||
|
</p>
|
||||||
|
<p class="upload-text">点击或拖拽图片到此处</p>
|
||||||
|
<p class="upload-hint">支持 JPG、PNG 格式,最大 10MB</p>
|
||||||
|
</template>
|
||||||
</a-upload-dragger>
|
</a-upload-dragger>
|
||||||
|
|
||||||
|
<!-- 模型类型选择 -->
|
||||||
|
<div class="model-settings">
|
||||||
|
<div class="setting-row">
|
||||||
|
<div class="setting-item full-width">
|
||||||
|
<span class="setting-label">模型类型</span>
|
||||||
|
<a-select v-model:value="generateType" class="setting-select">
|
||||||
|
<a-select-option value="Normal">带纹理</a-select-option>
|
||||||
|
<a-select-option value="LowPoly">低多边形</a-select-option>
|
||||||
|
<a-select-option value="Geometry">白模</a-select-option>
|
||||||
|
<a-select-option value="Sketch">草图</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -309,7 +359,6 @@ import {
|
|||||||
ArrowLeftOutlined,
|
ArrowLeftOutlined,
|
||||||
ClockCircleOutlined,
|
ClockCircleOutlined,
|
||||||
} from "@ant-design/icons-vue"
|
} from "@ant-design/icons-vue"
|
||||||
import type { UploadFile } from "ant-design-vue"
|
|
||||||
import {
|
import {
|
||||||
createAI3DTask,
|
createAI3DTask,
|
||||||
getAI3DTasks,
|
getAI3DTasks,
|
||||||
@ -358,11 +407,14 @@ const samplePrompts = [
|
|||||||
// 状态
|
// 状态
|
||||||
const inputType = ref<"text" | "image">("text")
|
const inputType = ref<"text" | "image">("text")
|
||||||
const textContent = ref("")
|
const textContent = ref("")
|
||||||
const imageFileList = ref<UploadFile[]>()
|
|
||||||
const imageUrl = ref("")
|
const imageUrl = ref("")
|
||||||
const generating = ref(false)
|
const generating = ref(false)
|
||||||
const currentSampleIndex = ref(0)
|
const currentSampleIndex = ref(0)
|
||||||
|
|
||||||
|
// 模型设置
|
||||||
|
const generateType = ref<"Normal" | "LowPoly" | "Geometry" | "Sketch">("Normal")
|
||||||
|
const faceCount = ref(500000)
|
||||||
|
|
||||||
// 历史记录
|
// 历史记录
|
||||||
const historyList = ref<AI3DTask[]>([])
|
const historyList = ref<AI3DTask[]>([])
|
||||||
const historyLoading = ref(false)
|
const historyLoading = ref(false)
|
||||||
@ -448,12 +500,18 @@ const handleBeforeUpload = async (file: File) => {
|
|||||||
|
|
||||||
// 上传图片
|
// 上传图片
|
||||||
try {
|
try {
|
||||||
const result = await uploadFile(file)
|
const result: any = await uploadFile(file)
|
||||||
imageUrl.value = result.url
|
// 兼容不同的响应格式
|
||||||
message.success("图片上传成功")
|
const url = result.data?.url || result.url
|
||||||
|
if (url) {
|
||||||
|
imageUrl.value = url
|
||||||
|
message.success("图片上传成功")
|
||||||
|
} else {
|
||||||
|
message.error("上传失败:无法获取图片地址")
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.error("上传失败:", error)
|
||||||
message.error("图片上传失败")
|
message.error("图片上传失败")
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false // 阻止默认上传行为
|
return false // 阻止默认上传行为
|
||||||
@ -468,16 +526,24 @@ const handleGenerate = async () => {
|
|||||||
const content =
|
const content =
|
||||||
inputType.value === "text" ? textContent.value.trim() : imageUrl.value
|
inputType.value === "text" ? textContent.value.trim() : imageUrl.value
|
||||||
|
|
||||||
const task = await createAI3DTask({
|
// 构建请求参数
|
||||||
|
const params: any = {
|
||||||
inputType: inputType.value,
|
inputType: inputType.value,
|
||||||
inputContent: content,
|
inputContent: content,
|
||||||
})
|
generateType: generateType.value,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文生3D时添加模型面数参数
|
||||||
|
if (inputType.value === "text") {
|
||||||
|
params.faceCount = faceCount.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const task = await createAI3DTask(params)
|
||||||
|
|
||||||
// 清空输入
|
// 清空输入
|
||||||
if (inputType.value === "text") {
|
if (inputType.value === "text") {
|
||||||
textContent.value = ""
|
textContent.value = ""
|
||||||
} else {
|
} else {
|
||||||
imageFileList.value = []
|
|
||||||
imageUrl.value = ""
|
imageUrl.value = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -943,6 +1009,19 @@ $gradient-secondary: linear-gradient(135deg, $accent 0%, $primary 100%);
|
|||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.textarea-wrapper {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.char-count {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 8px;
|
||||||
|
right: 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: $text-muted;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.text-input {
|
.text-input {
|
||||||
background: rgba($surface-light, 0.6) !important;
|
background: rgba($surface-light, 0.6) !important;
|
||||||
border: 2px solid rgba($primary, 0.15) !important;
|
border: 2px solid rgba($primary, 0.15) !important;
|
||||||
@ -950,6 +1029,7 @@ $gradient-secondary: linear-gradient(135deg, $accent 0%, $primary 100%);
|
|||||||
color: $text;
|
color: $text;
|
||||||
resize: none;
|
resize: none;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
|
padding-bottom: 28px !important;
|
||||||
|
|
||||||
&::placeholder {
|
&::placeholder {
|
||||||
color: rgba($text-muted, 0.5);
|
color: rgba($text-muted, 0.5);
|
||||||
@ -964,14 +1044,67 @@ $gradient-secondary: linear-gradient(135deg, $accent 0%, $primary 100%);
|
|||||||
box-shadow: 0 0 0 4px rgba($primary, 0.1) !important;
|
box-shadow: 0 0 0 4px rgba($primary, 0.1) !important;
|
||||||
background: rgba($surface-light, 0.8) !important;
|
background: rgba($surface-light, 0.8) !important;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
:deep(.ant-input-data-count) {
|
// 模型设置
|
||||||
color: $text-muted;
|
.model-settings {
|
||||||
|
margin-top: 16px;
|
||||||
|
padding: 16px;
|
||||||
|
background: rgba($primary, 0.05);
|
||||||
|
border: 1px solid rgba($primary, 0.15);
|
||||||
|
border-radius: 12px;
|
||||||
|
|
||||||
|
.setting-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-item {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
&.full-width {
|
||||||
|
flex: none;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-label {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: $text-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-select {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
:deep(.ant-select-selector) {
|
||||||
|
background: rgba($surface, 0.8) !important;
|
||||||
|
border: 1px solid rgba($primary, 0.2) !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
height: 36px !important;
|
||||||
|
|
||||||
|
.ant-select-selection-item {
|
||||||
|
line-height: 34px !important;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover :deep(.ant-select-selector) {
|
||||||
|
border-color: rgba($primary, 0.4) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ant-select-focused :deep(.ant-select-selector) {
|
||||||
|
border-color: $primary !important;
|
||||||
|
box-shadow: 0 0 0 2px rgba($primary, 0.1) !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.sample-section {
|
.sample-section {
|
||||||
margin-top: 20px;
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sample-header {
|
.sample-header {
|
||||||
@ -1028,28 +1161,51 @@ $gradient-secondary: linear-gradient(135deg, $accent 0%, $primary 100%);
|
|||||||
border: 2px dashed rgba($primary, 0.3) !important;
|
border: 2px dashed rgba($primary, 0.3) !important;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
border-color: $primary-light !important;
|
border-color: $primary-light !important;
|
||||||
background: rgba($surface-light, 0.8) !important;
|
background: rgba($surface-light, 0.8) !important;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.upload-icon {
|
:deep(.ant-upload) {
|
||||||
color: $primary-light;
|
padding: 24px !important;
|
||||||
font-size: 56px;
|
}
|
||||||
margin-bottom: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.upload-text {
|
:deep(.upload-icon) {
|
||||||
color: $text;
|
color: $primary-light;
|
||||||
font-size: 15px;
|
font-size: 56px;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.upload-hint {
|
:deep(.upload-text) {
|
||||||
color: $text-muted;
|
color: $text;
|
||||||
font-size: 12px;
|
font-size: 15px;
|
||||||
}
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.upload-hint) {
|
||||||
|
color: $text-muted;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.upload-preview-image) {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 180px;
|
||||||
|
object-fit: contain;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.upload-change-hint) {
|
||||||
|
margin-top: 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: $text-muted;
|
||||||
|
transition: color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-upload-drag:hover .upload-change-hint) {
|
||||||
|
color: $primary-light;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user