Merge branch 'main' of ssh://18.167.251.121:10002/aidlab/FiDA_Front

This commit is contained in:
2026-04-01 14:53:28 +08:00
7 changed files with 101 additions and 56 deletions

View File

@@ -85,6 +85,7 @@
import { ref, inject, computed, nextTick, onBeforeUnmount, reactive, watch } from 'vue' import { ref, inject, computed, nextTick, onBeforeUnmount, reactive, watch } from 'vue'
import DepthInput from '../tools/depth-input.vue' import DepthInput from '../tools/depth-input.vue'
import DepthSelect from '../tools/depth-select.vue' import DepthSelect from '../tools/depth-select.vue'
import { BlendMode } from '../../tools/layerHelper'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
const { t } = useI18n() const { t } = useI18n()
const objectManager = inject('objectManager') as any const objectManager = inject('objectManager') as any
@@ -104,7 +105,7 @@
height: 0, height: 0,
scaleX: 1, scaleX: 1,
scaleY: 1, scaleY: 1,
globalCompositeOperation: 'source-over' globalCompositeOperation: BlendMode.NORMAL
}) })
const updateData = async () => { const updateData = async () => {
await nextTick() await nextTick()
@@ -139,87 +140,91 @@
const layerCompositeOptions = ref([ const layerCompositeOptions = ref([
{ {
value: 'source-over', value: BlendMode.NORMAL,
label: t('DepthCanvas.compositeNormal'), label: t('DepthCanvas.compositeNormal'),
tip: t('DepthCanvas.compositeNormalTip') tip: t('DepthCanvas.compositeNormalTip')
}, // 正常 }, // 正常
{ {
value: 'darken', value: BlendMode.DARKEN,
label: t('DepthCanvas.compositeDarken'), label: t('DepthCanvas.compositeDarken'),
tip: t('DepthCanvas.compositeDarkenTip') tip: t('DepthCanvas.compositeDarkenTip')
}, // 变暗 }, // 变暗
{ {
value: 'multiply', value: BlendMode.MULTIPLY,
label: t('DepthCanvas.compositeMultiply'), label: t('DepthCanvas.compositeMultiply'),
tip: t('DepthCanvas.compositeMultiplyTip') tip: t('DepthCanvas.compositeMultiplyTip')
}, // 正片叠底 }, // 正片叠底
{ {
value: 'color-burn', value: BlendMode.COLOR_BURN,
label: t('DepthCanvas.compositeColorBurn'), label: t('DepthCanvas.compositeColorBurn'),
tip: t('DepthCanvas.compositeColorBurnTip') tip: t('DepthCanvas.compositeColorBurnTip')
}, // 颜色加深 }, // 颜色加深
{ {
value: 'lighten', value: BlendMode.LIGHTEN,
label: t('DepthCanvas.compositeLighten'), label: t('DepthCanvas.compositeLighten'),
tip: t('DepthCanvas.compositeLightenTip') tip: t('DepthCanvas.compositeLightenTip')
}, // 颜色减淡 }, // 变亮
{ {
value: 'screen', value: BlendMode.SCREEN,
label: t('DepthCanvas.compositeScreen'), label: t('DepthCanvas.compositeScreen'),
tip: t('DepthCanvas.compositeScreenTip') tip: t('DepthCanvas.compositeScreenTip')
}, // 滤色 }, // 滤色
{ {
value: 'color-dodge', value: BlendMode.COLOR_DODGE,
label: t('DepthCanvas.compositeColorDodge'), label: t('DepthCanvas.compositeColorDodge'),
tip: t('DepthCanvas.compositeColorDodgeTip') tip: t('DepthCanvas.compositeColorDodgeTip')
}, // 颜色减淡 }, // 颜色减淡
{ {
value: 'lighter', value: BlendMode.LIGHTER,
label: t('DepthCanvas.compositeLighter'), label: t('DepthCanvas.compositeLighter'),
tip: t('DepthCanvas.compositeLighterTip') tip: t('DepthCanvas.compositeLighterTip')
}, // 颜色减淡 }, // 颜色减淡(添加)
{ {
value: 'overlay', value: BlendMode.OVERLAY,
label: t('DepthCanvas.compositeOverlay'), label: t('DepthCanvas.compositeOverlay'),
tip: t('DepthCanvas.compositeOverlayTip') tip: t('DepthCanvas.compositeOverlayTip')
}, // 叠加 }, // 叠加
{ {
value: 'soft-light', value: BlendMode.SOFT_LIGHT,
label: t('DepthCanvas.compositeSoftLight'), label: t('DepthCanvas.compositeSoftLight'),
tip: t('DepthCanvas.compositeSoftLightTip') tip: t('DepthCanvas.compositeSoftLightTip')
}, // 柔光 }, // 柔光
{ {
value: 'hard-light', value: BlendMode.HARD_LIGHT,
label: t('DepthCanvas.compositeHardLight'), label: t('DepthCanvas.compositeHardLight'),
tip: t('DepthCanvas.compositeHardLightTip') tip: t('DepthCanvas.compositeHardLightTip')
}, // 强光 }, // 强光
{ {
value: 'difference', value: BlendMode.DIFFERENCE,
label: t('DepthCanvas.compositeDifference'), label: t('DepthCanvas.compositeDifference'),
tip: t('DepthCanvas.compositeDifferenceTip') tip: t('DepthCanvas.compositeDifferenceTip')
}, // 差值 }, // 差值
{ {
value: 'exclusion', value: BlendMode.EXCLUSION,
label: t('DepthCanvas.compositeExclusion'), label: t('DepthCanvas.compositeExclusion'),
tip: t('DepthCanvas.compositeExclusionTip') tip: t('DepthCanvas.compositeExclusionTip')
}, // 排除 }, // 排除
{ value: 'hue', label: t('DepthCanvas.compositeHue'), tip: t('DepthCanvas.compositeHueTip') }, // 色相
{ {
value: 'saturation', value: BlendMode.HUE,
label: t('DepthCanvas.compositeHue'),
tip: t('DepthCanvas.compositeHueTip')
}, // 色相
{
value: BlendMode.SATURATION,
label: t('DepthCanvas.compositeSaturation'), label: t('DepthCanvas.compositeSaturation'),
tip: t('DepthCanvas.compositeSaturationTip') tip: t('DepthCanvas.compositeSaturationTip')
}, // 饱和度 }, // 饱和度
{ {
value: 'color', value: BlendMode.COLOR,
label: t('DepthCanvas.compositeColor'), label: t('DepthCanvas.compositeColor'),
tip: t('DepthCanvas.compositeColorTip') tip: t('DepthCanvas.compositeColorTip')
}, // 颜色 }, // 颜色
{ {
value: 'luminosity', value: BlendMode.LUMINOSITY,
label: t('DepthCanvas.compositeLuminosity'), label: t('DepthCanvas.compositeLuminosity'),
tip: t('DepthCanvas.compositeLuminosityTip') tip: t('DepthCanvas.compositeLuminosityTip')
} // 亮度 } // 亮度

View File

@@ -88,7 +88,7 @@
provide('toolManager', toolManager) provide('toolManager', toolManager)
//键盘事件管理器 //键盘事件管理器
const keyEventManager = new KeyEventManager({ stateManager, onWorkbench }) const keyEventManager = new KeyEventManager({ stateManager, onWorkbench, layerManager })
stateManager.setManager({ keyEventManager }) stateManager.setManager({ keyEventManager })
provide('keyEventManager', keyEventManager) provide('keyEventManager', keyEventManager)
@@ -163,15 +163,7 @@
input.addEventListener('change', (e: any) => { input.addEventListener('change', (e: any) => {
const file = e.target.files[0] const file = e.target.files[0]
if (!file) return if (!file) return
const reader = new FileReader() layerManager.createFileImageLayer(file, isRecord).then((v) => resolve(v))
reader.readAsDataURL(file)
reader.onload = () => {
toolManager.setTool(OperationType.SELECT)
const url = reader.result as string
layerManager
.createImageLayer(url, { info: { name: file.name } }, isRecord)
.then((v) => resolve(v))
}
}) })
}) })
} }

View File

@@ -21,7 +21,13 @@
import { getDepthCanvas, saveDepthCanvas } from '@/api/depth-canvas' import { getDepthCanvas, saveDepthCanvas } from '@/api/depth-canvas'
import FullscreenDialog from '../components/fullscreen-dialog.vue' import FullscreenDialog from '../components/fullscreen-dialog.vue'
import depthCanvas from './depth-canvas.vue' import depthCanvas from './depth-canvas.vue'
import { ref } from 'vue' import { ref, watch } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
watch(
() => route.path,
() => dialogVisible.value && (dialogVisible.value = false)
)
const dialogVisible = ref(false) const dialogVisible = ref(false)
const config = ref({ const config = ref({
canvasId: '', canvasId: '',
@@ -77,7 +83,9 @@
defineExpose({ defineExpose({
open, open,
close close: () => {
dialogVisible.value = false
}
}) })
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@@ -419,6 +419,18 @@ export class LayerManager {
if (isActive) this.setActiveID(imageObject.info.id) if (isActive) this.setActiveID(imageObject.info.id)
return imageObject return imageObject
} }
createFileImageLayer(file: File, isRecord = true) {
return new Promise((resolve) => {
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = () => {
this.stateManager.toolManager.setTool(OperationType.SELECT)
const url = reader.result as string
this.createImageLayer(url, { info: { name: file.name } }, isRecord)
.then((v) => resolve(v))
}
})
}
/** 合并图层 */ /** 合并图层 */
async imageMergeToLayer(targetLayer: fabric.Object, fabricImage: fabric.Object) { async imageMergeToLayer(targetLayer: fabric.Object, fabricImage: fabric.Object) {

View File

@@ -1,24 +1,37 @@
export class KeyEventManager { export class KeyEventManager {
stateManager: any stateManager: any
layerManager: any
onWorkbench: any onWorkbench: any
constructor(options) { constructor(options) {
this.stateManager = options.stateManager; this.stateManager = options.stateManager;
this.layerManager = options.layerManager;
this.onWorkbench = options.onWorkbench; this.onWorkbench = options.onWorkbench;
this._handleKeyDown = this.handleKeyDown.bind(this) this._handleKeyDown = this.handleKeyDown.bind(this)
this._handlePaste = this.handlePaste.bind(this)
} }
onMounted() { } onMounted() { }
/** 注册事件 */
registerEvents() {
document.addEventListener('keydown', this._handleKeyDown)
document.addEventListener("paste", this._handlePaste);
}
/** 删除事件 */
removeEvents() {
document.removeEventListener('keydown', this._handleKeyDown)
document.removeEventListener("paste", this._handlePaste)
}
/** 处理键盘事件 */ /** 处理键盘事件 */
_handleKeyDown: any _handleKeyDown: any
handleKeyDown(event: any) { handleKeyDown(event: any) {
const activeID = this.stateManager.layerManager.activeID.value const activeID = this.layerManager.activeID.value
const ctrl = event.ctrlKey ? 'ctrl-' : ""; const ctrl = event.ctrlKey ? 'ctrl-' : "";
const shift = event.shiftKey ? 'shift-' : ""; const shift = event.shiftKey ? 'shift-' : "";
const key = event.key; const key = event.key;
const reg = new RegExp(`^${ctrl}${shift}${key}$`, 'i') const reg = new RegExp(`^${ctrl}${shift}${key}$`, 'i')
const list = [ const list = [
{ key: "ctrl-c", handler: () => this.stateManager.layerManager.copyLayerById(activeID) }, { key: "ctrl-c", handler: () => this.layerManager.copyLayerById(activeID) },
{ key: "delete", handler: () => this.stateManager.layerManager.deleteLayerById(activeID) }, { key: "delete", handler: () => this.layerManager.deleteLayerById(activeID) },
{ key: "ctrl-z", handler: () => this.stateManager.undoState() }, { key: "ctrl-z", handler: () => this.stateManager.undoState() },
{ key: "ctrl-s", handler: () => this.onWorkbench() }, { key: "ctrl-s", handler: () => this.onWorkbench() },
{ key: "ctrl-shift-z", handler: () => this.stateManager.redoState() }, { key: "ctrl-shift-z", handler: () => this.stateManager.redoState() },
@@ -28,14 +41,28 @@ export class KeyEventManager {
if (reg.test(v.key)) v.handler(event) if (reg.test(v.key)) v.handler(event)
}) })
} }
/** 注册事件 */ /** 处理粘贴事件 */
registerEvents() { _handlePaste: any
document.addEventListener('keydown', this._handleKeyDown) handlePaste(event: any) {
} event.preventDefault(); // 阻止默认粘贴行为
/** 删除事件 */ const text = event.clipboardData?.getData("text/plain") || "";
removeEvents() { if (/^aida_copy_canvas_layer/.test(text)) return;
document.removeEventListener('keydown', this._handleKeyDown) const items = event.clipboardData?.items || [];
for (const item of items) {
if (item.type.indexOf("text/plain") !== -1) {
item.getAsString((text) => {
console.log('粘贴文本', text);
});
} else if (item.type.indexOf("image") !== -1) {
const file = item.getAsFile();
this.layerManager.createFileImageLayer(file, false).then(layer => {
const id = layer?.info?.id
this.stateManager.objectManager.setFillRepeat(id)
})
}
}
} }
/** 销毁事件管理器 */
dispose() { dispose() {
this.removeEvents() this.removeEvents()
} }

View File

@@ -29,7 +29,7 @@ export const OperationType = {
PAN: "pan", // 拖拽模式 PAN: "pan", // 拖拽模式
DRAW: "draw", // 绘画模式 DRAW: "draw", // 绘画模式
ERASER: "eraser", // 橡皮擦模式 ERASER: "eraser", // 橡皮擦模式
AISELECT_ADD: "aiSelectAdd",// 智能框选添加模式 AISELECT_ADD: "aiSelectAdd",// 智能框选添加模式
AISELECT_REMOVE: "aiSelectRemove",// 智能框选删除模式 AISELECT_REMOVE: "aiSelectRemove",// 智能框选删除模式
AISELECT_DRAW: "aiSelectDraw",// 智能框选绘制模式 AISELECT_DRAW: "aiSelectDraw",// 智能框选绘制模式
@@ -54,21 +54,23 @@ export const OperationTypes = Object.values(OperationType);
*/ */
export const BlendMode = { export const BlendMode = {
NORMAL: "source-over", // 正常模式 NORMAL: "source-over", // 正常模式
MULTIPLY: "multiply", // 正片叠底
SCREEN: "screen", // 滤色
OVERLAY: "overlay", // 叠加
DARKEN: "darken", // 变暗 DARKEN: "darken", // 变暗
LIGHTEN: "lighten", // 变亮 MULTIPLY: "multiply", // 正片叠底
COLOR_DODGE: "color-dodge", // 颜色减淡
COLOR_BURN: "color-burn", // 颜色加深 COLOR_BURN: "color-burn", // 颜色加深
HARD_LIGHT: "hard-light", // 强光 LIGHTEN: "lighten", // 变亮
SCREEN: "screen", // 滤色
COLOR_DODGE: "color-dodge", // 颜色减淡
LIGHTER: "lighter", // 颜色减淡(添加)
OVERLAY: "overlay", // 叠加
SOFT_LIGHT: "soft-light", // 柔光 SOFT_LIGHT: "soft-light", // 柔光
HARD_LIGHT: "hard-light", // 强光
DIFFERENCE: "difference", // 差值 DIFFERENCE: "difference", // 差值
EXCLUSION: "exclusion", // 排除 EXCLUSION: "exclusion", // 排除
HUE: "hue", // 色相 HUE: "hue", // 色相
SATURATION: "saturation", // 饱和度 SATURATION: "saturation", // 饱和度
COLOR: "color", // 颜色 COLOR: "color", // 颜色
LUMINOSITY: "luminosity", // 明度 LUMINOSITY: "luminosity", // 明度
DESTINATION_IN: "destination-in", // 目标内 DESTINATION_IN: "destination-in", // 目标内
DESTINATION_OUT: "destination-out", // 目标外 DESTINATION_OUT: "destination-out", // 目标外
}; };

View File

@@ -32,16 +32,11 @@ axios.defaults.withCredentials = true //跨域携带cookie
// request拦截器 // request拦截器
service.interceptors.request.use( service.interceptors.request.use(
(config: any) => { (config: any) => {
removePending(config) if (removePending(config) && config.loading) closeLoading()
// 如果repeatRequest不配置那么默认该请求就取消重复接口请求 // 如果repeatRequest不配置那么默认该请求就取消重复接口请求
!config.repeatRequest && addPending(config) !config.repeatRequest && addPending(config)
// 打开loading // 打开loading
if (config.loading) { if (config.loading) openLoading(config.loadingDom)
LoadingInstance._count++
if (LoadingInstance._count === 1) {
openLoading(config.loadingDom)
}
}
// 如果登录了有token则请求携带token // 如果登录了有token则请求携带token
// Do something before request is sent // Do something before request is sent
const token = useUserInfoStore().state.token const token = useUserInfoStore().state.token
@@ -165,6 +160,7 @@ function removePending(config: any) {
const cancelToken = pendingMap.get(pendingKey) const cancelToken = pendingMap.get(pendingKey)
cancelToken(pendingKey) cancelToken(pendingKey)
pendingMap.delete(pendingKey) pendingMap.delete(pendingKey)
return true
} }
} }
// ----------------------------------loading的函数------------------------------- // ----------------------------------loading的函数-------------------------------
@@ -172,7 +168,10 @@ const LoadingInstance: { _count: number } = {
_count: 0 _count: 0
} }
function openLoading(loadingDom: any) { function openLoading(loadingDom: any) {
LoadingInstance._count++
// if(LoadingInstance._count === 1) {
useGlobalStore().setLoading(true) useGlobalStore().setLoading(true)
// }
} }
function closeLoading() { function closeLoading() {
if (LoadingInstance._count > 0) LoadingInstance._count-- if (LoadingInstance._count > 0) LoadingInstance._count--