feat: 更新机器人图片设置模态框,重命名图片标签为自定义图片,移除激活状态图片设置,优化图片上传和删除逻辑,增强用户交互体验

This commit is contained in:
xudan 2025-09-10 16:45:15 +08:00
parent 689ecb4f0c
commit 874c3fade3
3 changed files with 113 additions and 109 deletions

View File

@ -31,8 +31,8 @@
<div v-if="selectedRobot" class="image-settings-section">
<a-divider>图片设置</a-divider>
<!-- 普通状态图片 -->
<a-form-item label="普通状态图片">
<!-- 自定义图片 -->
<a-form-item label="自定义图片">
<div class="image-upload-container">
<a-upload
:file-list="[]"
@ -44,12 +44,12 @@
<template #icon>
<UploadOutlined />
</template>
选择普通状态图片
选择自定义图片
</a-button>
</a-upload>
<div v-if="formData.images.normal" class="image-preview">
<img :src="formData.images.normal" alt="普通状态" />
<img :src="formData.images.normal" alt="自定义图片" />
<div class="image-actions">
<a-button size="small" @click="removeImage('normal')">删除</a-button>
</div>
@ -57,63 +57,11 @@
</div>
</a-form-item>
<!-- 激活状态图片 -->
<a-form-item label="激活状态图片">
<div class="image-upload-container">
<a-upload
:file-list="[]"
:before-upload="(file) => handleImageUpload(file, 'active')"
accept="image/*"
:show-upload-list="false"
>
<a-button :loading="uploading.active">
<template #icon>
<UploadOutlined />
</template>
选择激活状态图片
</a-button>
</a-upload>
<div v-if="formData.images.active" class="image-preview">
<img :src="formData.images.active" alt="激活状态" />
<div class="image-actions">
<a-button size="small" @click="removeImage('active')">删除</a-button>
</div>
</div>
</div>
</a-form-item>
<!-- 图片尺寸设置 -->
<a-form-item label="图片尺寸">
<a-row :gutter="16">
<a-col :span="12">
<a-input-number
v-model:value="formData.imageWidth"
:min="20"
:max="200"
placeholder="宽度"
style="width: 100%"
/>
<span class="size-label">宽度 (px)</span>
</a-col>
<a-col :span="12">
<a-input-number
v-model:value="formData.imageHeight"
:min="20"
:max="200"
placeholder="高度"
style="width: 100%"
/>
<span class="size-label">高度 (px)</span>
</a-col>
</a-row>
</a-form-item>
<!-- 操作按钮 -->
<a-form-item>
<a-space>
<a-button @click="resetImages">重置图片</a-button>
<a-button danger @click="clearAllImages">清除所有图片</a-button>
<a-button danger @click="clearAllImages">清除图片</a-button>
</a-space>
</a-form-item>
</div>
@ -125,9 +73,10 @@
<script setup lang="ts">
import { UploadOutlined } from '@ant-design/icons-vue';
import { message } from 'ant-design-vue';
import { computed, onMounted, ref, watch } from 'vue';
import { computed, inject, onMounted, ref, watch } from 'vue';
import colorConfig from '../../services/color/color-config.service';
import { EditorService } from '../../services/editor.service';
interface RobotInfo {
name: string;
@ -159,19 +108,19 @@ const emit = defineEmits<Emits>();
const selectedRobot = ref<string>(props.selectedRobotName);
const loading = ref(false);
const uploading = ref({
normal: false,
active: false
normal: false
});
const formData = ref({
images: {
normal: '',
active: ''
},
imageWidth: 42,
imageHeight: 76
normal: ''
}
});
//
const EDITOR_KEY = Symbol('editor-key');
const editor = inject<{ value: EditorService }>(EDITOR_KEY);
//
const availableRobots = computed(() => props.robots);
@ -193,22 +142,18 @@ watch(selectedRobot, (newRobot) => {
// props
watch(() => props.selectedRobotName, (newName) => {
console.log('模态框接收到selectedRobotName变化:', newName);
if (newName && newName !== selectedRobot.value) {
selectedRobot.value = newName;
console.log('设置selectedRobot为:', newName);
}
});
// open
watch(() => props.open, (isOpen) => {
console.log('模态框open状态变化:', isOpen);
if (isOpen) {
//
if (props.selectedRobotName) {
selectedRobot.value = props.selectedRobotName;
loadRobotImages(props.selectedRobotName);
console.log('模态框打开设置selectedRobot为:', props.selectedRobotName);
}
} else {
//
@ -219,15 +164,10 @@ watch(() => props.open, (isOpen) => {
//
const loadRobotImages = (robotName: string) => {
formData.value.images.normal = colorConfig.getRobotCustomImage(robotName, 'normal') || '';
formData.value.images.active = colorConfig.getRobotCustomImage(robotName, 'active') || '';
//
formData.value.imageWidth = Number(colorConfig.getColor('robot.imageWidth')) || 42;
formData.value.imageHeight = Number(colorConfig.getColor('robot.imageHeight')) || 76;
};
//
const handleImageUpload = async (file: File, state: 'normal' | 'active') => {
const handleImageUpload = async (file: File, state: 'normal') => {
if (!selectedRobot.value) {
message.error('请先选择机器人');
return false;
@ -250,7 +190,13 @@ const handleImageUpload = async (file: File, state: 'normal' | 'active') => {
try {
await colorConfig.saveRobotCustomImage(selectedRobot.value, state, file);
formData.value.images[state] = colorConfig.getRobotCustomImage(selectedRobot.value, state) || '';
message.success(`${state === 'normal' ? '普通状态' : '激活状态'}图片上传成功`);
// pen
if (editor?.value && typeof editor.value.updateRobotImage === 'function') {
editor.value.updateRobotImage(selectedRobot.value);
}
message.success('自定义图片上传成功');
} catch (error) {
console.error('图片上传失败:', error);
message.error('图片上传失败,请重试');
@ -262,12 +208,18 @@ const handleImageUpload = async (file: File, state: 'normal' | 'active') => {
};
//
const removeImage = (state: 'normal' | 'active') => {
const removeImage = (state: 'normal') => {
if (!selectedRobot.value) return;
colorConfig.removeRobotCustomImage(selectedRobot.value, state);
formData.value.images[state] = '';
message.success(`${state === 'normal' ? '普通状态' : '激活状态'}图片已删除`);
// pen
if (editor?.value && typeof editor.value.updateRobotImage === 'function') {
editor.value.updateRobotImage(selectedRobot.value);
}
message.success('自定义图片已删除');
};
//
@ -276,18 +228,28 @@ const resetImages = () => {
colorConfig.removeRobotCustomImage(selectedRobot.value);
formData.value.images.normal = '';
formData.value.images.active = '';
// pen
if (editor?.value && typeof editor.value.updateRobotImage === 'function') {
editor.value.updateRobotImage(selectedRobot.value);
}
message.success('图片已重置');
};
//
//
const clearAllImages = () => {
if (!selectedRobot.value) return;
colorConfig.removeRobotCustomImage(selectedRobot.value);
formData.value.images.normal = '';
formData.value.images.active = '';
message.success('所有图片已清除');
// pen
if (editor?.value && typeof editor.value.updateRobotImage === 'function') {
editor.value.updateRobotImage(selectedRobot.value);
}
message.success('图片已清除');
};
//
@ -300,19 +262,9 @@ const handleSave = async () => {
loading.value = true;
try {
//
if (formData.value.imageWidth !== Number(colorConfig.getColor('robot.imageWidth'))) {
colorConfig.setColor('robot.imageWidth', formData.value.imageWidth.toString());
}
if (formData.value.imageHeight !== Number(colorConfig.getColor('robot.imageHeight'))) {
colorConfig.setColor('robot.imageHeight', formData.value.imageHeight.toString());
}
emit('save', {
robotName: selectedRobot.value,
images: formData.value.images,
imageWidth: formData.value.imageWidth,
imageHeight: formData.value.imageHeight
images: formData.value.images
});
message.success('设置保存成功');
@ -332,11 +284,8 @@ const handleCancel = () => {
selectedRobot.value = '';
formData.value = {
images: {
normal: '',
active: ''
},
imageWidth: 42,
imageHeight: 76
normal: ''
}
};
};
</script>
@ -385,11 +334,6 @@ const handleCancel = () => {
opacity: 1;
}
.size-label {
font-size: 12px;
color: #666;
margin-left: 8px;
}
.ant-form-item {
margin-bottom: 16px;
@ -398,4 +342,15 @@ const handleCancel = () => {
.ant-divider {
margin: 16px 0;
}
/* 确保模态框层级低于机器人菜单 (机器人菜单 z-index: 9999) */
:deep(.ant-modal) {
z-index: 1000 !important;
}
:deep(.ant-modal-mask) {
z-index: 999 !important;
}
</style>

View File

@ -890,10 +890,14 @@ class ColorConfigService {
fillWarning: theme.robot['fill-warning'] || DEFAULT_COLORS.robot.fillWarning,
strokeFault: theme.robot['stroke-fault'] || DEFAULT_COLORS.robot.strokeFault,
fillFault: theme.robot['fill-fault'] || DEFAULT_COLORS.robot.fillFault,
imageWidth: DEFAULT_COLORS.robot.imageWidth,
imageHeight: DEFAULT_COLORS.robot.imageHeight,
customImages: DEFAULT_COLORS.robot.customImages,
useCustomImages: DEFAULT_COLORS.robot.useCustomImages
imageWidth: theme.robot.imageWidth || DEFAULT_COLORS.robot.imageWidth,
imageHeight: theme.robot.imageHeight || DEFAULT_COLORS.robot.imageHeight,
customImages: theme.robot.customImages || DEFAULT_COLORS.robot.customImages,
useCustomImages: theme.robot.useCustomImages !== undefined ?
(typeof theme.robot.useCustomImages === 'string' ?
theme.robot.useCustomImages === 'true' :
theme.robot.useCustomImages) :
DEFAULT_COLORS.robot.useCustomImages
};
}
@ -1109,10 +1113,20 @@ class ColorConfigService {
*/
public getRobotCustomImage(robotName: string, state: 'normal' | 'active'): string | null {
const customImages = this.config.value.robot.customImages;
if (!customImages || !customImages[robotName]) {
return null;
}
return customImages[robotName][state] || null;
// 优先获取请求状态的图片,如果不存在则回退到 normal 状态
let result = customImages[robotName][state] || null;
// 如果请求的是 active 状态但没有 active 图片,回退到 normal 状态
if (!result && state === 'active') {
result = customImages[robotName]['normal'] || null;
}
return result;
}
/**
@ -1169,6 +1183,41 @@ class ColorConfigService {
customImages[robotName].normal || customImages[robotName].active
);
}
/**
*
*/
public debugConfig(): void {
console.log('🔧 当前颜色配置状态:', {
robot: {
useCustomImages: this.config.value.robot.useCustomImages,
imageWidth: this.config.value.robot.imageWidth,
imageHeight: this.config.value.robot.imageHeight,
customImages: this.config.value.robot.customImages
},
fullConfig: this.config.value
});
}
/**
*
* @param userConfig
*/
public applyUserConfig(userConfig: any): void {
console.log('📝 应用用户配置:', userConfig);
// 合并用户配置到当前配置
this.config.value = this.mergeConfig(this.config.value, userConfig);
// 保存到本地存储
this.saveToLocalStorage(this.config.value);
// 触发重新渲染
this.triggerRender();
console.log('✅ 用户配置已应用并保存');
}
}
export default new ColorConfigService();

View File

@ -1223,8 +1223,8 @@ export class EditorService extends Meta2d {
// 检查是否启用自定义图片且有机器人名称
const useCustomImages = colorConfig.getColor('robot.useCustomImages') === 'true';
let image: string;
let image: string;
if (useCustomImages && robotName) {
// 尝试获取自定义图片
const customImage = colorConfig.getRobotCustomImage(robotName, active ? 'active' : 'normal');