canvas语言适配
This commit is contained in:
@@ -281,7 +281,7 @@ onMounted(() => {
|
||||
" -->
|
||||
<div class="canvas-settings" v-if="!props.enabledRedGreenMode">
|
||||
<div class="setting-group">
|
||||
<span class="setting-label">{{ $t("宽度") }}</span>
|
||||
<span class="setting-label">{{ $t("Canvas.width") }}</span>
|
||||
<a-input-number
|
||||
:value="canvasWidth"
|
||||
class="setting-input"
|
||||
@@ -297,7 +297,7 @@ onMounted(() => {
|
||||
/>
|
||||
</div>
|
||||
<div class="setting-group">
|
||||
<span class="setting-label">{{ $t("高度") }}</span>
|
||||
<span class="setting-label">{{ $t("Canvas.height") }}</span>
|
||||
<a-input-number
|
||||
:value="canvasHeight"
|
||||
class="setting-input"
|
||||
@@ -313,7 +313,7 @@ onMounted(() => {
|
||||
/>
|
||||
</div>
|
||||
<div class="setting-group">
|
||||
<span class="setting-label">{{ $t("颜色") }}</span>
|
||||
<span class="setting-label">{{ $t("Canvas.color") }}</span>
|
||||
<div class="color-picker-wrapper">
|
||||
<input
|
||||
type="color"
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<script setup>
|
||||
import { ref, inject, onMounted } from "vue";
|
||||
import { Skeleton } from "ant-design-vue";
|
||||
import { useI18n } from 'vue-i18n'
|
||||
const {t} = useI18n()
|
||||
|
||||
const loading = ref(true);
|
||||
const shortcuts = ref([]);
|
||||
@@ -44,17 +46,17 @@ function convertShortcuts(managerShortcuts) {
|
||||
|
||||
// 基本的Action到显示名称的映射
|
||||
const actionDisplayMap = {
|
||||
undo: "撤销",
|
||||
redo: "重做",
|
||||
delete: "删除选中元素",
|
||||
undo: t('Canvas.Undo'),
|
||||
redo: t('Canvas.Redo'),
|
||||
delete: t('Canvas.DeleteSelectedElement'),
|
||||
selectAll: "全选",
|
||||
copy: "复制",
|
||||
paste: "粘贴",
|
||||
cut: "剪切",
|
||||
copy: t('Canvas.Copy'),
|
||||
paste: t('Canvas.Pase'),
|
||||
cut: t('Canvas.Cut'),
|
||||
save: "保存",
|
||||
selectTool: "选择工具",
|
||||
increaseBrushSize: "增加笔触大小",
|
||||
decreaseBrushSize: "减小笔触大小",
|
||||
increaseBrushSize: t('Canvas.DecreaseBrush'),
|
||||
decreaseBrushSize: t('Canvas.IncreaseBrush'),
|
||||
toggleTempTool: "临时切换工具",
|
||||
// newLayer: "新建图层",
|
||||
// groupLayers: "组合图层",
|
||||
@@ -64,15 +66,15 @@ function convertShortcuts(managerShortcuts) {
|
||||
|
||||
// 工具ID到显示名称的映射
|
||||
const toolDisplayMap = {
|
||||
select: "选择模式",
|
||||
draw: "绘画模式",
|
||||
eraser: "橡皮擦模式",
|
||||
// eyedropper: "吸色工具",
|
||||
pan: "移动画布",
|
||||
lasso: "套索工具",
|
||||
// area_custom: "自由选区工具",
|
||||
// wave: "波浪工具",
|
||||
liquify: "液化工具",
|
||||
select: t('Canvas.SelectionMode'),
|
||||
draw: t('Canvas.PaintingMode'),
|
||||
eraser: t('Canvas.EraserMode'),
|
||||
// eyedropper: t('Canvas.Cut'),
|
||||
pan: '移动画布',
|
||||
lasso: t('Canvas.LassoTool'),
|
||||
// area_custom: t('Canvas.Cut'),
|
||||
// wave: t('Canvas.Cut'),
|
||||
liquify: t('Canvas.LiquifyTool'),
|
||||
};
|
||||
|
||||
// 处理每个快捷键
|
||||
@@ -95,9 +97,9 @@ function convertShortcuts(managerShortcuts) {
|
||||
|
||||
// 添加一些组件特定的快捷键
|
||||
result.push({
|
||||
action: "缩放画布",
|
||||
windows: "鼠标滚轮",
|
||||
mac: "鼠标滚轮 或 触控板缩放手势",
|
||||
action: t('Canvas.ZoomCanvas'),
|
||||
windows: t('Canvas.MouseWheel'),
|
||||
mac: t('Canvas.MacZoomCanvas'),
|
||||
touch: "双指捏合",
|
||||
});
|
||||
|
||||
@@ -268,11 +270,11 @@ function getShortcutsByCategory(category) {
|
||||
|
||||
<template>
|
||||
<div class="keyboard-shortcut-help">
|
||||
<h2>键盘快捷键 & 操作指南</h2>
|
||||
<h2>{{ $t('Canvas.KeyboardShortcutsOperationGuide') }}</h2>
|
||||
|
||||
<Skeleton active :loading="loading">
|
||||
<div class="platform-info">
|
||||
检测到的平台:
|
||||
{{$t('Canvas.TheDetectedPlatform')}}:
|
||||
<span v-if="platform.isMac">MacOS</span>
|
||||
<span v-else-if="platform.isWindows">Windows</span>
|
||||
<span v-else-if="platform.isIPad">iPad</span>
|
||||
@@ -283,12 +285,12 @@ function getShortcutsByCategory(category) {
|
||||
</div>
|
||||
|
||||
<div class="shortcuts-category">
|
||||
<h3>基本操作</h3>
|
||||
<h3> {{$t('Canvas.BasicOperations')}}</h3>
|
||||
<table class="shortcuts-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>操作</th>
|
||||
<th>快捷键/手势</th>
|
||||
<th>{{$t('Canvas.BasicOperations')}}</th>
|
||||
<th>{{$t('Canvas.ShortcutGesture')}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -301,12 +303,12 @@ function getShortcutsByCategory(category) {
|
||||
</div>
|
||||
|
||||
<div class="shortcuts-category">
|
||||
<h3>视图操作</h3>
|
||||
<h3>{{ $t('Canvas.viewOperations') }}</h3>
|
||||
<table class="shortcuts-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>操作</th>
|
||||
<th>快捷键/手势</th>
|
||||
<th>{{ $t('Canvas.Operation') }}</th>
|
||||
<th>{{ $t('Canvas.ShortcutGesture') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -319,12 +321,12 @@ function getShortcutsByCategory(category) {
|
||||
</div>
|
||||
|
||||
<div class="shortcuts-category">
|
||||
<h3>工具切换</h3>
|
||||
<h3>{{ $t('Canvas.toolSwitching') }}</h3>
|
||||
<table class="shortcuts-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>操作</th>
|
||||
<th>快捷键/手势</th>
|
||||
<th>{{ $t('Canvas.Operation') }}</th>
|
||||
<th>{{ $t('Canvas.ShortcutGesture') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -337,12 +339,12 @@ function getShortcutsByCategory(category) {
|
||||
</div>
|
||||
|
||||
<div class="shortcuts-category">
|
||||
<h3>笔刷调整</h3>
|
||||
<h3>{{ $t('Canvas.toolSwitching') }}</h3>
|
||||
<table class="shortcuts-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>操作</th>
|
||||
<th>快捷键/手势</th>
|
||||
<th>{{ $t('Canvas.Operation') }}</th>
|
||||
<th>{{ $t('Canvas.ShortcutGesture') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
@@ -3,7 +3,8 @@ import { ref, nextTick, computed, inject } from "vue";
|
||||
import { Checkbox } from "ant-design-vue";
|
||||
import { VueDraggable } from "vue-draggable-plus";
|
||||
import { isGroupLayer } from "../../utils/layerHelper";
|
||||
|
||||
import { useI18n } from 'vue-i18n'
|
||||
const {t} = useI18n()
|
||||
// 设置组件名称,用于递归渲染
|
||||
defineOptions({
|
||||
name: "LayerItem",
|
||||
@@ -393,7 +394,7 @@ function findParentLayerId() {
|
||||
v-if="layer.thumbnailUrl"
|
||||
:src="layer.thumbnailUrl"
|
||||
class="layer-thumbnail"
|
||||
:alt="$t('图层预览')"
|
||||
:alt="$t('Canvas.preview')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -423,7 +424,7 @@ function findParentLayerId() {
|
||||
<div
|
||||
class="visibility-btn"
|
||||
@click.stop="handleToggleVisibility"
|
||||
:title="$t('显示/隐藏图层')"
|
||||
:title="$t('Canvas.showHiddenLayer')"
|
||||
>
|
||||
<SvgIcon v-if="layer.visible" name="CEye" :size="16"></SvgIcon>
|
||||
<SvgIcon v-else name="CUnEye" :size="16"></SvgIcon>
|
||||
@@ -447,7 +448,7 @@ function findParentLayerId() {
|
||||
<div
|
||||
class="delete-btn"
|
||||
:class="{ disabled: !canDelete }"
|
||||
:title="$t('删除图层')"
|
||||
:title="$t('Canvas.deleteLayer')"
|
||||
@click.stop="handleDelete"
|
||||
>
|
||||
<SvgIcon name="CDelete" size="14"></SvgIcon>
|
||||
@@ -460,7 +461,7 @@ function findParentLayerId() {
|
||||
class="group-expand-icon"
|
||||
@click.stop="toggleGroupExpanded"
|
||||
@dblclick.stop=""
|
||||
:title="isGroupExpanded ? $t('收起组') : $t('展开组')"
|
||||
:title="isGroupExpanded ? $t('Canvas.CollapseUp') : $t('Canvas.CollapseDown')"
|
||||
>
|
||||
<SvgIcon
|
||||
name="CRight"
|
||||
|
||||
@@ -5,6 +5,8 @@ import ContextMenu from "./ContextMenu.vue";
|
||||
import LayerItem from "./LayerItem.vue";
|
||||
import LayersList from "./LayersList.vue"; // 引入 LayersList 组件
|
||||
import { createCrossLevelMoveCommand } from "../../commands/CrossLevelMoveCommands";
|
||||
import { useI18n } from 'vue-i18n'
|
||||
const {t} = useI18n()
|
||||
// // 导入命令类
|
||||
// import {
|
||||
// ReorderLayersCommand,
|
||||
@@ -1523,7 +1525,7 @@ async function moveGroupToGroup(draggedLayer, fromParentId, toParentId, newIndex
|
||||
style="width: 0; height: 0; opacity: 0"
|
||||
/> -->
|
||||
<h3>
|
||||
{{ $t("图层") }}
|
||||
{{ $t("Canvas.layer") }}
|
||||
{{ selectedLayerIds.length > 0 ? `(${selectedLayerIds.length})` : "" }}
|
||||
</h3>
|
||||
<div class="layer-actions-group">
|
||||
@@ -1533,7 +1535,7 @@ async function moveGroupToGroup(draggedLayer, fromParentId, toParentId, newIndex
|
||||
class="group-btn action-btn"
|
||||
:class="{ disabled: !canGroupLayers }"
|
||||
@click="groupSelectedLayers"
|
||||
:title="$t('创建组')"
|
||||
:title="$t('Canvas.createGroup')"
|
||||
>
|
||||
<SvgIcon name="CCreateGroup" size="20"></SvgIcon>
|
||||
</div>
|
||||
@@ -1542,7 +1544,7 @@ async function moveGroupToGroup(draggedLayer, fromParentId, toParentId, newIndex
|
||||
class="ungroup-btn action-btn"
|
||||
:class="{ disabled: !canUngroupLayers }"
|
||||
@click="ungroupSelectedLayer"
|
||||
:title="$t('解组')"
|
||||
:title="$t('Canvas.slutionGroup')"
|
||||
>
|
||||
<SvgIcon name="CCancelGroup" size="20"></SvgIcon>
|
||||
</div>
|
||||
@@ -1550,7 +1552,7 @@ async function moveGroupToGroup(draggedLayer, fromParentId, toParentId, newIndex
|
||||
<div
|
||||
class="delete-selected-btn action-btn"
|
||||
@click="deleteSelectedLayers"
|
||||
:title="$t('删除选中图层')"
|
||||
:title="$t('Canvas.deleteLayer')"
|
||||
>
|
||||
<SvgIcon name="CDelete" size="16"></SvgIcon>
|
||||
</div>
|
||||
@@ -1558,7 +1560,7 @@ async function moveGroupToGroup(draggedLayer, fromParentId, toParentId, newIndex
|
||||
<div
|
||||
class="clear-selection-btn action-btn"
|
||||
@click="clearSelection"
|
||||
:title="$t('清除选择')"
|
||||
:title="$t('Canvas.clearSelection')"
|
||||
>
|
||||
<SvgIcon name="CCloseNo" size="14"></SvgIcon>
|
||||
</div>
|
||||
@@ -1570,7 +1572,7 @@ async function moveGroupToGroup(draggedLayer, fromParentId, toParentId, newIndex
|
||||
v-if="isChildLayerActive"
|
||||
class="add-layer-btn action-btn"
|
||||
@click="addTopLayer"
|
||||
:title="$t('添加顶级图层')"
|
||||
:title="$t('Canvas.AddPinnedLayer')"
|
||||
>
|
||||
<SvgIcon name="CPlusTop" size="16"></SvgIcon>
|
||||
</div>
|
||||
@@ -1587,8 +1589,8 @@ async function moveGroupToGroup(draggedLayer, fromParentId, toParentId, newIndex
|
||||
|
||||
<!-- 多选提示条 -->
|
||||
<div v-if="isMultiSelectMode" class="multi-select-info">
|
||||
<span>已选择 {{ selectedLayerIds.length }} 个图层</span>
|
||||
<small>提示:按住 Ctrl/Cmd 多选,Shift 范围选择,长按进入多选模式</small>
|
||||
<span>{{ $t('Canvas.Hint') }}{{ selectedLayerIds.length }}</span>
|
||||
<small>{{ $t('Canvas.Hint') }}</small>
|
||||
</div>
|
||||
|
||||
<!-- 图层列表组件 -->
|
||||
|
||||
@@ -36,6 +36,8 @@ import { ToolManager } from "./managers/toolManager.js";
|
||||
// import { fabric } from "fabric-with-all";
|
||||
import { uploadImageAndCreateLayer, loadImageUrlToLayer, loadImage } from "./utils/imageHelper.js";
|
||||
// import MinimapPanel from "./components/MinimapPanel.vue";
|
||||
import { useI18n } from 'vue-i18n'
|
||||
const {t} = useI18n()
|
||||
const KeyboardShortcutHelp = defineAsyncComponent(
|
||||
() => import("./components/KeyboardShortcutHelp.vue")
|
||||
);
|
||||
@@ -514,7 +516,7 @@ function updateCanvasColor() {
|
||||
}
|
||||
|
||||
async function addLayer() {
|
||||
await layerManager.createLayer("空图层");
|
||||
await layerManager.createLayer(t('Canvas.EmptyLayer'));
|
||||
}
|
||||
async function addTopLayer() {
|
||||
await layerManager.createLayer("空图层", LayerType.EMPTY, {
|
||||
@@ -980,9 +982,9 @@ defineExpose({
|
||||
/>
|
||||
|
||||
<div class="zoom-info">
|
||||
缩放: {{ currentZoom }}%
|
||||
<button class="reset-zoom" @click="resetZoom">重置视图</button>
|
||||
<button class="help-btn" @click="toggleShortcutHelp" title="查看快捷键和触控操作">
|
||||
{{ t('Canvas.Scale') }}: {{ currentZoom }}%
|
||||
<button class="reset-zoom" @click="resetZoom">{{ $t('Canvas.ResetLayer') }}</button>
|
||||
<button class="help-btn" @click="toggleShortcutHelp" :title="$t('Canvas.Help')">
|
||||
?
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -62,7 +62,8 @@ import { fabric } from "fabric-with-all";
|
||||
import { getOriginObjectInfo } from "../utils/layerUtils";
|
||||
import { restoreFabricObject } from "../utils/objectHelper";
|
||||
import { UpdateGroupMaskPositionCommand } from "../commands/UpdateGroupMaskPositionCommand";
|
||||
|
||||
import { useI18n } from 'vue-i18n'
|
||||
const {t} = useI18n()
|
||||
/**
|
||||
* 图层管理器 - 负责管理画布上的所有图层
|
||||
* 包含图层的创建、删除、修改、排序等操作
|
||||
@@ -579,7 +580,7 @@ export class LayerManager {
|
||||
this.createFixedLayer();
|
||||
|
||||
// 创建一个空白图层(默认位于背景图层和固定图层之上)
|
||||
await this.createLayer("图层 1");
|
||||
await this.createLayer(t('Canvas.Layer1'));
|
||||
} else {
|
||||
// 检查是否已有背景层
|
||||
const hasBackgroundLayer = this.layers.value.some((layer) => layer.isBackground);
|
||||
@@ -601,7 +602,7 @@ export class LayerManager {
|
||||
);
|
||||
|
||||
if (!hasNormalLayer) {
|
||||
await this.createLayer("图层 1");
|
||||
await this.createLayer(t('Canvas.Layer1'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -546,7 +546,7 @@ setup(props:any,{emit}) {
|
||||
productimg.selectGenerate.listType = listType
|
||||
productimg.selectGenerate.isIndex = index
|
||||
|
||||
if(!list[index]?.id &&( (list[index].resultType == 'PoseTransfer' && !list[index].gifUrl) || (list[index].resultType == 'PoseTransfer' && !list[index].url))){
|
||||
if(( (list[index].resultType == 'PoseTransfer' && !list[index].gifUrl) || (list[index].resultType !== 'PoseTransfer' && !list[index].url))){
|
||||
productimg.productimgIsProductimg = true
|
||||
productimg.productimgRemProductimg = true
|
||||
setPrductimg([list[index].taskId])
|
||||
@@ -626,14 +626,15 @@ setup(props:any,{emit}) {
|
||||
// productimg.likeDesignCollectionList[index].childList[childIndex] = productimg.generateCourse
|
||||
// }
|
||||
}
|
||||
let emitData = {
|
||||
|
||||
}
|
||||
let emitData = {
|
||||
status:productimg.openType,
|
||||
generateCourse:[{
|
||||
...productimg.generateCourse,
|
||||
}]
|
||||
}
|
||||
emit('upDataDesignLikeList',emitData)
|
||||
}
|
||||
productimg.openType = ''
|
||||
|
||||
scaleImage.value = false
|
||||
|
||||
@@ -1069,6 +1069,7 @@ export default defineComponent({
|
||||
}
|
||||
const generateLoad = async (data:any)=>{
|
||||
// return
|
||||
console.log(data)
|
||||
clearInterval(prductimgTime.ToProductImage)
|
||||
clearInterval(prductimgTime.PoseTransfer)
|
||||
clearInterval(prductimgTime.Relight)
|
||||
|
||||
@@ -69,6 +69,7 @@ export default defineComponent({
|
||||
dataDom.editCanvas.addImageToLayer(url,{layerId:dataDom.editCanvas.layers[0].id,imageMode:'contains',undoable:false})
|
||||
}
|
||||
const canvasInit = (value)=>{
|
||||
if(!props.imgUrl)return
|
||||
canvasLoadAddImg(props.imgUrl,value.layers.value[0].id)
|
||||
}
|
||||
const getCanvasData = ()=>{
|
||||
@@ -89,10 +90,40 @@ export default defineComponent({
|
||||
|
||||
}
|
||||
const exportElement = ()=>{
|
||||
canvasEditor.value.exportImage({isContainBg:true,isContainFixed:false,isCropByBg:true}).then((rv)=>{
|
||||
dataDom.editCanvas.exportImage({isContainBg:true,isContainFixed:false,isCropByBg:true}).then((rv)=>{
|
||||
downloadBase64Image(rv,'canvas')
|
||||
})
|
||||
}
|
||||
function downloadBase64Image(base64Data, filename) {
|
||||
// 1. 提取MIME类型(自动处理各种Base64前缀)
|
||||
const mimeMatch = base64Data.match(/^data:(.+?);base64,/);
|
||||
if (!mimeMatch) {
|
||||
console.error('Invalid Base64 data');
|
||||
return;
|
||||
}
|
||||
// 2. 获取扩展名
|
||||
const mimeType = mimeMatch[1];
|
||||
const extension = mimeType.split('/')[1] || 'png';
|
||||
|
||||
// 3. 转换Base64为Blob
|
||||
const byteString = atob(base64Data.split(',')[1]);
|
||||
const ab = new ArrayBuffer(byteString.length);
|
||||
const ia = new Uint8Array(ab);
|
||||
for (let i = 0; i < byteString.length; i++) {
|
||||
ia[i] = byteString.charCodeAt(i);
|
||||
}
|
||||
const blob = new Blob([ab], { type: mimeType });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `${filename}.${extension}`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
setTimeout(() => {
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
}, 100);
|
||||
}
|
||||
const changeCanvas = ()=>{
|
||||
emit('canvasChangeGetJSON',{canvasJSON:dataDom.editCanvas.getJSON(),submitDate:5000})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user