feat: 更新机器人图片设置模态框,重命名图片标签为自定义图片,移除激活状态图片设置,优化图片上传和删除逻辑,增强用户交互体验
This commit is contained in:
parent
689ecb4f0c
commit
874c3fade3
@ -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>
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
@ -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');
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user