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

View File

@ -890,10 +890,14 @@ class ColorConfigService {
fillWarning: theme.robot['fill-warning'] || DEFAULT_COLORS.robot.fillWarning, fillWarning: theme.robot['fill-warning'] || DEFAULT_COLORS.robot.fillWarning,
strokeFault: theme.robot['stroke-fault'] || DEFAULT_COLORS.robot.strokeFault, strokeFault: theme.robot['stroke-fault'] || DEFAULT_COLORS.robot.strokeFault,
fillFault: theme.robot['fill-fault'] || DEFAULT_COLORS.robot.fillFault, fillFault: theme.robot['fill-fault'] || DEFAULT_COLORS.robot.fillFault,
imageWidth: DEFAULT_COLORS.robot.imageWidth, imageWidth: theme.robot.imageWidth || DEFAULT_COLORS.robot.imageWidth,
imageHeight: DEFAULT_COLORS.robot.imageHeight, imageHeight: theme.robot.imageHeight || DEFAULT_COLORS.robot.imageHeight,
customImages: DEFAULT_COLORS.robot.customImages, customImages: theme.robot.customImages || DEFAULT_COLORS.robot.customImages,
useCustomImages: DEFAULT_COLORS.robot.useCustomImages 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 { public getRobotCustomImage(robotName: string, state: 'normal' | 'active'): string | null {
const customImages = this.config.value.robot.customImages; const customImages = this.config.value.robot.customImages;
if (!customImages || !customImages[robotName]) { if (!customImages || !customImages[robotName]) {
return null; 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 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(); export default new ColorConfigService();

View File

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