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

This commit is contained in:
2026-03-26 16:11:12 +08:00
22 changed files with 468 additions and 282 deletions

View File

@@ -96,3 +96,10 @@ body,
--el-color-primary-dark-2: #565656; --el-color-primary-dark-2: #565656;
/* 深灰色加深20% */ /* 深灰色加深20% */
} }
.mini-scrollbar::-webkit-scrollbar {
width: 0.4rem;
}
.mini-scrollbar::-webkit-scrollbar-thumb {
border-radius: 0.4rem;
background: rgba(0, 0, 0, 0.2);
}

View File

@@ -105,3 +105,15 @@ body,
--el-color-primary-light-9: #e3e3e3; /* 极浅的灰色混合60%白) */ --el-color-primary-light-9: #e3e3e3; /* 极浅的灰色混合60%白) */
--el-color-primary-dark-2: #565656; /* 深灰色加深20% */ --el-color-primary-dark-2: #565656; /* 深灰色加深20% */
} }
// 迷你滚动条
.mini-scrollbar {
&::-webkit-scrollbar {
width: 0.4rem;
}
&::-webkit-scrollbar-thumb {
border-radius: 0.4rem;
background: rgba(0, 0, 0, 0.2);
}
}

View File

@@ -11,6 +11,7 @@
<span class="label">{{ item.label }}</span> <span class="label">{{ item.label }}</span>
</div> </div>
<button @click="onCreate">创建</button> <button @click="onCreate">创建</button>
<button @click="onReset">重置</button>
</div> </div>
</transition> </transition>
<brush-control-panel v-if="show" :currentTool="currentTool2" style="top: 14rem" /> <brush-control-panel v-if="show" :currentTool="currentTool2" style="top: 14rem" />
@@ -21,6 +22,8 @@
import depthSlider from './tools/depth-slider.vue' import depthSlider from './tools/depth-slider.vue'
import { OperationType } from '../tools/layerHelper' import { OperationType } from '../tools/layerHelper'
import brushControlPanel from './brush-control-panel.vue' import brushControlPanel from './brush-control-panel.vue'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const props = defineProps({ const props = defineProps({
currentTool: { required: true, type: [String, null] } currentTool: { required: true, type: [String, null] }
@@ -37,22 +40,22 @@
{ {
type: OperationType.AISELECT_ADD, type: OperationType.AISELECT_ADD,
name: 'dc-add_sb', name: 'dc-add_sb',
label: 'Add' label: t('DepthCanvas.add')
}, },
{ {
type: OperationType.AISELECT_REMOVE, type: OperationType.AISELECT_REMOVE,
name: 'dc-remove_sb', name: 'dc-remove_sb',
label: 'Remove' label: t('DepthCanvas.remove')
}, },
{ {
type: OperationType.AISELECT_DRAW, type: OperationType.AISELECT_DRAW,
name: 'dc-brush_sb', name: 'dc-brush_sb',
label: 'Brush' label: t('DepthCanvas.brush')
}, },
{ {
type: OperationType.AISELECT_ERASER, type: OperationType.AISELECT_ERASER,
name: 'dc-erase_sb', name: 'dc-erase_sb',
label: 'Erase' label: t('DepthCanvas.erase')
} }
]) ])
const onClickItem = (type: string) => { const onClickItem = (type: string) => {
@@ -61,6 +64,9 @@
const onCreate = () => { const onCreate = () => {
stateManager.aiSelectboxToolManager.createSelectbox() stateManager.aiSelectboxToolManager.createSelectbox()
} }
const onReset = () => {
stateManager.aiSelectboxToolManager.resetDemoObject()
}
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
// 淡入淡出动画 // 淡入淡出动画

View File

@@ -30,7 +30,7 @@
</template> </template>
<button class="export" @click="emit('export')"> <button class="export" @click="emit('export')">
<span class="icon"><svg-icon name="export" size="12" /></span> <span class="icon"><svg-icon name="export" size="12" /></span>
<span class="text">Export</span> <span class="text">{{ $t('DepthCanvas.export') }}</span>
</button> </button>
<!-- <button class="export" @click="emit('export-local')"> <!-- <button class="export" @click="emit('export-local')">
<span class="text">保存本地</span> <span class="text">保存本地</span>
@@ -40,7 +40,7 @@
</button> --> </button> -->
<button class="workbench" @click="onWorkbench"> <button class="workbench" @click="onWorkbench">
<span class="icon"><svg-icon name="dc-workbench" size="20" /></span> <span class="icon"><svg-icon name="dc-workbench" size="20" /></span>
<span class="text">Workbench</span> <span class="text">{{ $t('DepthCanvas.save') }}</span>
</button> </button>
</div> </div>
</template> </template>
@@ -49,6 +49,8 @@
import { ref, inject, computed } from 'vue' import { ref, inject, computed } from 'vue'
import { exportCanvasToImage } from '../tools/exportMethod' import { exportCanvasToImage } from '../tools/exportMethod'
import { OperationType, BlendMode } from '../tools/layerHelper' import { OperationType, BlendMode } from '../tools/layerHelper'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const props = defineProps({ const props = defineProps({
zoom: { default: 1, type: Number }, zoom: { default: 1, type: Number },
step: { default: 0.1, type: Number } step: { default: 0.1, type: Number }
@@ -86,37 +88,37 @@
child: [ child: [
{ {
name: OperationType.RECTANGLE, name: OperationType.RECTANGLE,
label: 'Rectangle', label: t('DepthCanvas.rectangle'),
icon: 'dc-rectangle', icon: 'dc-rectangle',
iconSize: 13 iconSize: 13
}, },
{ {
name: OperationType.LINE, name: OperationType.LINE,
label: 'Line', label: t('DepthCanvas.line'),
icon: 'dc-line', icon: 'dc-line',
iconSize: 10 iconSize: 10
}, },
{ {
name: OperationType.ARROW, name: OperationType.ARROW,
label: 'Arrow', label: t('DepthCanvas.arrow'),
icon: 'dc-arrow', icon: 'dc-arrow',
iconSize: 11 iconSize: 11
}, },
{ {
name: OperationType.ELLIPSE, name: OperationType.ELLIPSE,
label: 'Ellipse', label: t('DepthCanvas.ellipse'),
icon: 'dc-ellipse', icon: 'dc-ellipse',
iconSize: 15 iconSize: 15
}, },
{ {
name: OperationType.TRIANGLE, name: OperationType.TRIANGLE,
label: 'Polygon', label: t('DepthCanvas.triangle'),
icon: 'dc-triangle', icon: 'dc-triangle',
iconSize: 14 iconSize: 14
}, },
{ {
name: OperationType.STAR, name: OperationType.STAR,
label: 'Star', label: t('DepthCanvas.star'),
icon: 'dc-star', icon: 'dc-star',
iconSize: 15 iconSize: 15
} }

View File

@@ -1,64 +1,153 @@
<template> <template>
<div class="basic-info"> <div class="basic-info h">
<div> <div>
<span class="label">X:</span> <div class="title">{{ $t('DepthCanvas.position') }}</div>
<span class="value">{{ object.left }}</span> <div class="content">
<div>
<depth-input
before="X"
type="number"
v-model="data.left"
@input="onInpot"
@change="onChange"
/>
</div>
<div>
<depth-input
before="Y"
type="number"
v-model="data.top"
@input="onInpot"
@change="onChange"
/>
</div>
</div>
<div class="content">
<div>
<depth-input
before="W"
type="number"
v-model="data.width"
@input="onInpot"
@change="onChange"
/>
</div>
<div>
<depth-input
before="H"
type="number"
v-model="data.height"
@input="onInpot"
@change="onChange"
/>
</div>
</div>
</div> </div>
<div> <div>
<span class="label">Y:</span> <div class="title">{{ $t('DepthCanvas.scale') }}</div>
<span class="value">{{ object.top }}</span> <div class="content">
</div> <div>
<div> <depth-input
<span class="label">Width:</span> type="number"
<span class="value">{{ object.width }}</span> before="X"
</div> after="%"
<div> v-model="data.scaleX"
<span class="label">Height:</span> @input="onInpot"
<span class="value">{{ object.height }}</span> @change="onChange"
</div> />
<div> </div>
<span class="label">缩放X:</span> <div>
<span class="value">{{ object.scaleX }}</span> <depth-input
</div> type="number"
<div> before="Y"
<span class="label">缩放Y:</span> after="%"
<span class="value">{{ object.scaleY }}</span> v-model="data.scaleY"
</div> @input="onInpot"
<div> @change="onChange"
<span class="label">Angle:</span> />
<span class="value">{{ object.angle }}</span> </div>
</div>
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, inject, computed, watch, onMounted } from 'vue' import { ref, inject, computed, nextTick, onBeforeUnmount, reactive, watch } from 'vue'
import DepthInput from '../tools/depth-input.vue'
const objectManager = inject('objectManager') as any
const stateManager = inject('stateManager') as any
const props = defineProps({ const props = defineProps({
object: { object: {
type: Object, type: Object,
default: () => ({}) default: () => ({})
} }
}) })
onMounted(() => {}) const id = computed(() => props.object.info.id)
const data = reactive({
top: 0,
left: 0,
width: 0,
height: 0,
scaleX: 1,
scaleY: 1
})
const updateData = async () => {
await nextTick()
data.top = Math.round(props.object.top)
data.left = Math.round(props.object.left)
data.width = Math.round(props.object.width)
data.height = Math.round(props.object.height)
data.scaleX = Math.round(props.object.scaleX * 100)
data.scaleY = Math.round(props.object.scaleY * 100)
}
updateData()
watch(() => props.object, updateData)
const onInpot = () => setPriority(false)
const onChange = () => setPriority(true)
const setPriority = (isRecord: boolean) => {
const options = {
...data,
scaleX: data.scaleX / 100,
scaleY: data.scaleY / 100
}
objectManager.updateProperty(id.value, options, isRecord)
}
stateManager.event.add('canvas:undo', updateData)
stateManager.event.add('canvas:redo', updateData)
onBeforeUnmount(() => {
stateManager.event.remove('canvas:undo', updateData)
stateManager.event.remove('canvas:redo', updateData)
})
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.basic-info { .basic-info {
--details-item-margin-bottom: 1.6rem;
> div { > div {
padding: 0.8rem 0; > .content {
display: flex; display: flex;
align-items: center; align-items: center;
> .label { justify-content: center;
font-size: 1.6rem; > div {
color: #000; flex: 1;
font-weight: bold; margin-right: 3rem;
min-width: 7rem; display: flex;
text-align: right; flex-direction: column;
margin-right: 0.8rem; --depth-input-height: 2.4rem;
} --depth-input-bg-color: rgba(249, 249, 250, 1);
> .value { --depth-input-border-color: rgba(230, 230, 231, 1);
font-size: 1.6rem; --depth-input-decorate-color: rgba(69, 71, 84, 0.1);
color: #333; &:last-child {
margin-right: 0;
}
> .label {
font-size: 1.2rem;
margin-bottom: 0.5rem;
}
}
} }
} }
} }

View File

@@ -1,16 +1,16 @@
<template> <template>
<div class="fill-repeat h"> <div class="fill-repeat h">
<div> <div>
<div class="title">Image</div> <div class="title">{{ $t('DepthCanvas.image') }}</div>
<div class="content"> <div class="content">
<img :src="object.info.fill.source" alt="" /> <img :src="object.info.fill.source" alt="" />
</div> </div>
</div> </div>
<div> <div>
<div class="title">Sttings</div> <div class="title">{{ $t('DepthCanvas.settings') }}</div>
<div class="content"> <div class="content">
<div> <div>
<div class="label">Rotation</div> <div class="label">{{ $t('DepthCanvas.rotation') }}</div>
<div class="value"> <div class="value">
<depth-input <depth-input
icon="dc-angle" icon="dc-angle"
@@ -23,7 +23,7 @@
</div> </div>
</div> </div>
<div> <div>
<div class="label">Scale</div> <div class="label">{{ $t('DepthCanvas.scale') }}</div>
<div class="value"> <div class="value">
<depth-slider <depth-slider
v-model="scale" v-model="scale"
@@ -36,7 +36,7 @@
</div> </div>
</div> </div>
<div> <div>
<div class="label">Opacity</div> <div class="label">{{ $t('DepthCanvas.opacity') }}</div>
<div class="value"> <div class="value">
<depth-slider <depth-slider
v-model="opacity" v-model="opacity"
@@ -49,7 +49,7 @@
</div> </div>
</div> </div>
<div> <div>
<div class="label">Gap X</div> <div class="label">{{ $t('DepthCanvas.gapX') }}</div>
<div class="value"> <div class="value">
<depth-slider <depth-slider
v-model="gapX" v-model="gapX"
@@ -62,7 +62,7 @@
</div> </div>
</div> </div>
<div> <div>
<div class="label">Gap Y</div> <div class="label">{{ $t('DepthCanvas.gapY') }}</div>
<div class="value"> <div class="value">
<depth-slider <depth-slider
v-model="gapY" v-model="gapY"
@@ -75,7 +75,7 @@
</div> </div>
</div> </div>
<div> <div>
<div class="label">Offset</div> <div class="label">{{ $t('DepthCanvas.offset') }}</div>
<div class="value"> <div class="value">
<depth-offset-tool <depth-offset-tool
v-model="offset" v-model="offset"
@@ -99,7 +99,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, inject, computed, nextTick, onBeforeUnmount } from 'vue' import { ref, inject, computed, nextTick, onBeforeUnmount, watch } from 'vue'
import DepthOffsetTool from '../tools/depth-offset-tool.vue' import DepthOffsetTool from '../tools/depth-offset-tool.vue'
import DepthSlider from '../tools/depth-slider.vue' import DepthSlider from '../tools/depth-slider.vue'
import DepthInput from '../tools/depth-input.vue' import DepthInput from '../tools/depth-input.vue'
@@ -134,6 +134,7 @@
opacity.value = Math.round(props.object.opacity * 100) opacity.value = Math.round(props.object.opacity * 100)
} }
updateData() updateData()
watch(() => props.object, updateData)
const inputFillTransform = () => setFillTransform(false) const inputFillTransform = () => setFillTransform(false)
const changeFillTransform = () => setFillTransform(true) const changeFillTransform = () => setFillTransform(true)

View File

@@ -2,13 +2,13 @@
<div class="details-panel"> <div class="details-panel">
<div class="header" @click="show = !show"> <div class="header" @click="show = !show">
<span class="icon"><svg-icon name="dc-details_edit" size="17" /></span> <span class="icon"><svg-icon name="dc-details_edit" size="17" /></span>
<span class="title">Edit Details</span> <span class="title">{{ $t('DepthCanvas.editDetails') }}</span>
<span class="arrow" :class="{ show }"> <span class="arrow" :class="{ show }">
<svg-icon name="dc-down_arrow2" size="10" /> <svg-icon name="dc-down_arrow2" size="10" />
</span> </span>
</div> </div>
<div class="content" v-if="isShow" v-show="show"> <div class="content mini-scrollbar" v-if="isShow" v-show="show">
<!-- <basic-info :object="activeObject" /> --> <basic-info :object="activeObject" />
<fill-repeat :object="activeObject" v-if="isRepeat" /> <fill-repeat :object="activeObject" v-if="isRepeat" />
<shape-setting :object="activeObject" v-if="isShape && !isRepeat" /> <shape-setting :object="activeObject" v-if="isShape && !isRepeat" />
</div> </div>
@@ -17,6 +17,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, inject, computed, watch, onMounted } from 'vue' import { ref, inject, computed, watch, onMounted } from 'vue'
import BasicInfo from './basic-info.vue'
import FillRepeat from './fill-repeat.vue' import FillRepeat from './fill-repeat.vue'
import ShapeSetting from './shape-setting.vue' import ShapeSetting from './shape-setting.vue'
const props = defineProps({}) const props = defineProps({})
@@ -27,10 +28,11 @@
const layers = computed(() => layerManager.layers.value) const layers = computed(() => layerManager.layers.value)
const activeObject = ref(null) const activeObject = ref(null)
const shapes = ['rect', 'line', 'path', 'triangle', 'polygon', 'ellipse'] const shapes = ['rect', 'path', 'triangle', 'polygon', 'ellipse']
const isImage = computed(() => activeObject.value?.type === 'image')
const isShape = computed(() => shapes.includes(activeObject.value?.type)) const isShape = computed(() => shapes.includes(activeObject.value?.type))
const isRepeat = computed(() => activeObject.value?.fill?.repeat === 'repeat') const isRepeat = computed(() => activeObject.value?.fill?.repeat === 'repeat')
const isShow = computed(() => isRepeat.value || isShape.value) const isShow = computed(() => isImage.value || isRepeat.value || isShape.value)
const updateActiveObject = () => { const updateActiveObject = () => {
const layer = layerManager.getActiveLayer() const layer = layerManager.getActiveLayer()
@@ -49,7 +51,7 @@
top: 2.2rem; top: 2.2rem;
right: 3rem; right: 3rem;
width: 28.8rem; width: 28.8rem;
max-height: 80%; max-height: 90%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 1.6rem; gap: 1.6rem;
@@ -87,6 +89,12 @@
padding: 1.6rem; padding: 1.6rem;
overflow: hidden; overflow: hidden;
overflow-y: auto; overflow-y: auto;
> * {
margin-bottom: 1.6rem;
&:last-child {
margin-bottom: 0;
}
}
&:deep(> div) { &:deep(> div) {
> div { > div {
margin-bottom: var(--details-item-margin-bottom, 1.6rem); margin-bottom: var(--details-item-margin-bottom, 1.6rem);

View File

@@ -1,79 +1,10 @@
<template> <template>
<div class="shape-setting h"> <div class="shape-setting h">
<div> <div>
<div class="title">Position</div> <div class="title">{{ $t('DepthCanvas.appearance') }}</div>
<div class="content"> <div class="content">
<div> <div>
<depth-input <span class="label">{{ $t('DepthCanvas.opacity') }}</span>
before="X"
type="number"
v-model="data.left"
@input="onInpot"
@change="onChange"
/>
</div>
<div>
<depth-input
before="Y"
type="number"
v-model="data.top"
@input="onInpot"
@change="onChange"
/>
</div>
</div>
<div class="content">
<div>
<depth-input
before="W"
type="number"
v-model="data.width"
@input="onInpot"
@change="onChange"
/>
</div>
<div>
<depth-input
before="H"
type="number"
v-model="data.height"
@input="onInpot"
@change="onChange"
/>
</div>
</div>
</div>
<div>
<div class="title">Scale</div>
<div class="content">
<div>
<depth-input
type="number"
before="X"
after="%"
v-model="data.scaleX"
@input="onInpot"
@change="onChange"
/>
</div>
<div>
<depth-input
type="number"
before="Y"
after="%"
v-model="data.scaleY"
@input="onInpot"
@change="onChange"
/>
</div>
</div>
</div>
<div>
<div class="title">Appearance</div>
<div class="content">
<div>
<span class="label">Opacity</span>
<depth-input <depth-input
type="number" type="number"
after="%" after="%"
@@ -86,7 +17,7 @@
/> />
</div> </div>
<div v-if="object.type === 'rect'"> <div v-if="object.type === 'rect'">
<span class="label">Corner Radius</span> <span class="label">{{ $t('DepthCanvas.cornerRadius') }}</span>
<depth-input <depth-input
type="number" type="number"
v-model="data.radius" v-model="data.radius"
@@ -96,12 +27,32 @@
@change="onChange" @change="onChange"
/> />
</div> </div>
<div v-else-if="object.type === 'path'">
<span class="label">{{ $t('DepthCanvas.strokeWidth') }}</span>
<depth-input
type="number"
v-model="data.strokeWidth"
min="0"
step="1"
@input="onInpot"
@change="onChange"
/>
</div>
<div v-else></div> <div v-else></div>
</div> </div>
<div class="content"> <div class="content">
<div> <div>
<span class="label">Color</span> <span class="label">{{ $t('DepthCanvas.color') }}</span>
<depth-input <depth-input
v-if="object.type === 'path'"
type="color"
v-model="data.stroke"
after="%"
@input="onInpot"
@change="onChange"
/>
<depth-input
v-else
type="color" type="color"
v-model="data.fill" v-model="data.fill"
after="%" after="%"
@@ -116,10 +67,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, inject, computed, nextTick, onBeforeUnmount, reactive, watch } from 'vue' import { ref, inject, computed, nextTick, onBeforeUnmount, reactive, watch } from 'vue'
import { ElColorPicker } from 'element-plus'
import { getTransformScaleAngle } from '../../manager/ObjectManager'
import DepthOffsetTool from '../tools/depth-offset-tool.vue'
import DepthSlider from '../tools/depth-slider.vue'
import DepthInput from '../tools/depth-input.vue' import DepthInput from '../tools/depth-input.vue'
const objectManager = inject('objectManager') as any const objectManager = inject('objectManager') as any
const stateManager = inject('stateManager') as any const stateManager = inject('stateManager') as any
@@ -132,32 +79,20 @@
const id = computed(() => props.object.info.id) const id = computed(() => props.object.info.id)
const data = reactive({ const data = reactive({
top: 0,
left: 0,
width: 0,
height: 0,
scaleX: 1,
scaleY: 1,
opacity: 100, opacity: 100,
radius: 0, radius: 0,
fill: '' fill: '',
// stroke: '', stroke: '',
// strokeWidth: 0 strokeWidth: 0
}) })
const updateData = async () => { const updateData = async () => {
await nextTick() await nextTick()
data.top = Math.round(props.object.top)
data.left = Math.round(props.object.left)
data.width = Math.round(props.object.width)
data.height = Math.round(props.object.height)
data.scaleX = Math.round(props.object.scaleX * 100)
data.scaleY = Math.round(props.object.scaleY * 100)
data.opacity = Math.round(props.object.opacity * 100) data.opacity = Math.round(props.object.opacity * 100)
data.radius = Math.round(props.object.rx) data.radius = Math.round(props.object.rx)
data.fill = props.object.fill data.fill = props.object.fill
// data.stroke = props.object.stroke data.stroke = props.object.stroke
// data.strokeWidth = props.object.strokeWidth data.strokeWidth = props.object.strokeWidth
} }
updateData() updateData()
watch(() => props.object, updateData) watch(() => props.object, updateData)
@@ -167,14 +102,16 @@
const setPriority = (isRecord: boolean) => { const setPriority = (isRecord: boolean) => {
const options = { const options = {
...data, ...data,
opacity: data.opacity / 100, opacity: data.opacity / 100
scaleX: data.scaleX / 100,
scaleY: data.scaleY / 100
} }
if (props.object.type === 'rect') { if (props.object.type === 'rect') {
options['rx'] = data.radius options['rx'] = data.radius
options['ry'] = data.radius options['ry'] = data.radius
} }
if (props.object.type !== 'path') {
delete options.stroke
delete options.strokeWidth
}
delete options.radius delete options.radius
objectManager.updateProperty(id.value, options, isRecord) objectManager.updateProperty(id.value, options, isRecord)
} }

View File

@@ -20,7 +20,7 @@
width: 0; width: 0;
top: 2.2rem; top: 2.2rem;
left: 3rem; left: 3rem;
max-height: 80%; max-height: 90%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 1.6rem; gap: 1.6rem;

View File

@@ -3,13 +3,13 @@
<div class="header"> <div class="header">
<div class="left"> <div class="left">
<span class="icon"><svg-icon name="dc-layer" size="16" /></span> <span class="icon"><svg-icon name="dc-layer" size="16" /></span>
<span class="title">Layer</span> <span class="title">{{ $t('DepthCanvas.layer') }}</span>
</div> </div>
<div class="right"> <div class="right">
<span class="icon" @click="addLayer"><svg-icon name="add" size="14" /></span> <span class="icon" @click="addLayer"><svg-icon name="add" size="14" /></span>
</div> </div>
</div> </div>
<div class="content"> <div class="content mini-scrollbar">
<VueDraggable <VueDraggable
:model-value="list" :model-value="list"
@start="(e) => handleDragStart(e)" @start="(e) => handleDragStart(e)"
@@ -173,13 +173,6 @@
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
min-height: 20rem; min-height: 20rem;
&::-webkit-scrollbar {
width: 4px;
}
&::-webkit-scrollbar-thumb {
border-radius: 4px;
background: rgba(0, 0, 0, 0.2);
}
} }
} }
.sortable-layers-child { .sortable-layers-child {

View File

@@ -2,7 +2,7 @@
<div class="depth-input" :class="{ color: isColor }"> <div class="depth-input" :class="{ color: isColor }">
<span class="decorate"></span> <span class="decorate"></span>
<span v-show="icon" class="icon"> <span v-show="icon" class="icon">
<svg-icon :name="icon" :size="iconSize" size-unit="px" /> <svg-icon :name="icon" :size="iconSize" />
</span> </span>
<span v-show="before" class="before">{{ before }}</span> <span v-show="before" class="before">{{ before }}</span>
<input <input
@@ -220,45 +220,45 @@
display: flex; display: flex;
align-items: center; align-items: center;
width: 100%; width: 100%;
border: 1px solid var(--depth-input-border-color, rgba(230, 230, 231, 1)); border: 0.1rem solid var(--depth-input-border-color, rgba(230, 230, 231, 1));
border-radius: 2px; border-radius: 0.2rem;
height: var(--depth-input-height, 20px); height: var(--depth-input-height, 2rem);
background-color: var(--depth-input-bg-color, #fff); background-color: var(--depth-input-bg-color, #fff);
padding: 0 4px 0 2px; padding: 0 0.4rem 0 0.2rem;
&.color { &.color {
--depth-input-decorate-margin-right: 10px; --depth-input-decorate-margin-right: 1rem;
--depth-input-input-margin-right: 10px; --depth-input-input-margin-right: 1rem;
--depth-input-input-font-align: left; --depth-input-input-font-align: left;
--depth-input-after-color: rgba(181, 181, 181, 1); --depth-input-after-color: rgba(181, 181, 181, 1);
} }
> .decorate { > .decorate {
width: 2px; width: 0.2rem;
background-color: var(--depth-input-decorate-color, rgba(230, 230, 231, 1)); background-color: var(--depth-input-decorate-color, rgba(230, 230, 231, 1));
border-radius: 2px; border-radius: 0.2rem;
height: 75%; height: 75%;
margin-right: var(--depth-input-decorate-margin-right, 4px); margin-right: var(--depth-input-decorate-margin-right, 0.4rem);
} }
> .iconfont { > .iconfont {
font-size: 12px; font-size: 1.2rem;
color: #000; color: #000;
margin-right: 4px; margin-right: 0.4rem;
} }
> .before { > .before {
font-size: 12px; font-size: 1.2rem;
color: #000; color: #000;
margin-right: 4px; margin-right: 0.4rem;
} }
> .after { > .after {
font-size: 12px; font-size: 1.2rem;
color: var(--depth-input-after-color, #000); color: var(--depth-input-after-color, #000);
margin-left: 2px; margin-left: 0.2rem;
} }
> input { > input {
font-size: 12px; font-size: 1.2rem;
width: 0; width: 0;
height: 100%; height: 100%;
flex: 1; flex: 1;
margin-right: var(--depth-input-input-margin-right, 0); margin-right: var(--depth-input-input-margin-right, 0rem);
text-align: var(--depth-input-input-font-align, right); text-align: var(--depth-input-input-font-align, right);
outline: none; outline: none;
border: none; border: none;
@@ -277,9 +277,9 @@
} }
&[type='color'] { &[type='color'] {
flex: 0.5; flex: 0.5;
border-radius: 2px; border-radius: 0.2rem;
height: 70%; height: 70%;
border: 1px solid rgb(42, 42, 42); border: 0.1rem solid rgb(42, 42, 42);
display: block; display: block;
&::-webkit-color-swatch-wrapper { &::-webkit-color-swatch-wrapper {
padding: 0; padding: 0;

View File

@@ -152,52 +152,52 @@
justify-content: center; justify-content: center;
> * { > * {
flex: 1; flex: 1;
margin-right: 10px; margin-right: 1rem;
&:last-child { &:last-child {
margin-right: 0; margin-right: 0;
} }
} }
} }
> .dish { > .dish {
width: 115px; width: 11.5rem;
height: 115px; height: 11.5rem;
border: 1px solid #eaeaea; border: 0.1rem solid #eaeaea;
border-radius: 3.4px; border-radius: 0.4rem;
cursor: pointer; cursor: pointer;
position: relative; position: relative;
background-color: #f6f6f6; background-color: #f6f6f6;
margin-top: 20px; margin-top: 2rem;
> * { > * {
position: absolute; position: absolute;
pointer-events: none; pointer-events: none;
user-select: none; user-select: none;
} }
> img { > img {
width: 12px; width: 1.2rem;
height: 12px; height: 1.2rem;
bottom: 3.5px; bottom: 0.35rem;
right: 3.5px; right: 0.35rem;
} }
> .ball { > .ball {
top: 50%; top: 50%;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
width: 8.5px; width: 0.85rem;
height: 8.5px; height: 0.85rem;
border: 1px solid #fff; border: 0.1rem solid #fff;
background-color: #333; background-color: #333;
border-radius: 50%; border-radius: 50%;
box-shadow: 0px 0.68px 0.17px 0px rgba(0, 0, 0, 0.26); box-shadow: 9 0.07rem 0.02rem 0 rgba(0, 0, 0, 0.26);
} }
> .tip { > .tip {
font-size: 8.5px; font-size: 0.85rem;
color: #000; color: #000;
line-height: 24px; line-height: 2.4rem;
&.x { &.x {
top: 50%; top: 50%;
right: 0%; right: 0%;
transform: translate(100%, -50%); transform: translate(100%, -50%);
padding-left: 6px; padding-left: 0.6rem;
} }
&.y { &.y {
top: 0%; top: 0%;
@@ -216,15 +216,15 @@
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
&.x { &.x {
width: 100%; width: 100%;
border-top-width: 1px; border-top-width: 0.1rem;
} }
&.y { &.y {
height: 100%; height: 100%;
border-left-width: 1px; border-left-width: 0.1rem;
} }
&.z { &.z {
width: 50%; width: 50%;
border-top-width: 1px; border-top-width: 0.1rem;
border-color: #454754; border-color: #454754;
transform: translate(0%, -50%) rotateZ(var(--rotateZ)); transform: translate(0%, -50%) rotateZ(var(--rotateZ));
transform-origin: left center; transform-origin: left center;

View File

@@ -22,12 +22,12 @@
<style scoped lang="less"> <style scoped lang="less">
.depth-select { .depth-select {
&:deep(.el-select) { &:deep(.el-select) {
--el-select-input-font-size: 12px; --el-select-input-font-size: 1.2rem;
.el-select__wrapper { .el-select__wrapper {
font-size: 12px; font-size: 1.2rem;
min-height: 0; min-height: 0;
height: 28px; height: 2.8rem;
padding: 0 8px; padding: 0 0.8rem;
} }
.el-select__selected-item, .el-select__selected-item,
.el-select__input-wrapper, .el-select__input-wrapper,
@@ -35,17 +35,17 @@
line-height: normal; line-height: normal;
} }
.el-select__input { .el-select__input {
height: 24px; height: 2.4rem;
} }
} }
} }
.el-popper { .el-popper {
.el-select-dropdown { .el-select-dropdown {
li { li {
padding-left: 8px; padding-left: 0.8rem;
height: 30px; height: 3rem;
line-height: 30px; line-height: 3rem;
font-size: 12px; font-size: 1.2rem;
} }
} }
} }

View File

@@ -86,7 +86,7 @@
position: relative; position: relative;
display: flex; display: flex;
align-items: center; align-items: center;
--input-thumb-size: 1.4rem; --input-thumb-size: 1.2rem;
--backcolor1: var(--depth-slider-thumb-color1, #000); --backcolor1: var(--depth-slider-thumb-color1, #000);
--backcolor2: var(--depth-slider-thumb-color2, #d3d3d3); --backcolor2: var(--depth-slider-thumb-color2, #d3d3d3);
&:hover { &:hover {
@@ -121,7 +121,7 @@
background: var(--backcolor1); /* 蓝色滑块 */ background: var(--backcolor1); /* 蓝色滑块 */
cursor: pointer; cursor: pointer;
transition: all 0.2s; transition: all 0.2s;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); box-shadow: 0 0.1rem 0.2rem rgba(0, 0, 0, 0.1);
} }
&::-webkit-slider-thumb:hover { &::-webkit-slider-thumb:hover {
transform: scale(1.1); transform: scale(1.1);
@@ -153,9 +153,9 @@
transform: translateX(-50%); transform: translateX(-50%);
width: 0; width: 0;
height: 0; height: 0;
border-left: 5px solid transparent; border-left: 0.5rem solid transparent;
border-right: 5px solid transparent; border-right: 0.5rem solid transparent;
border-top: 5px solid rgba(0, 0, 0, 0.8); border-top: 0.5rem solid rgba(0, 0, 0, 0.8);
} }
} }
} }

View File

@@ -37,6 +37,7 @@ export class AISelectboxToolManager {
if (!oldIsAAA && newIsAAA) { if (!oldIsAAA && newIsAAA) {
// 普通工具切换到智能框选工具 // 普通工具切换到智能框选工具
this.init() this.init()
this.canvasManager.discardActiveObject()
} else if (oldIsAAA && !newIsAAA) { } else if (oldIsAAA && !newIsAAA) {
// 智能框选工具切换到普通工具 // 智能框选工具切换到普通工具
this.clear() this.clear()
@@ -101,6 +102,10 @@ export class AISelectboxToolManager {
this.canvasManager.canvas.remove(this.indicatorObject) this.canvasManager.canvas.remove(this.indicatorObject)
this.indicatorObject = null this.indicatorObject = null
} }
resetDemoObject() {
this.clearDemoObject()
this.createDemoObject()
}
// 创建临时画布对象 // 创建临时画布对象
async createStaticCanvas(object: fabric.Object) { async createStaticCanvas(object: fabric.Object) {
if (!this.demoObject) this.createDemoObject() if (!this.demoObject) this.createDemoObject()

View File

@@ -3,7 +3,9 @@ import { fabric } from 'fabric-with-all'
import { createId } from '../../tools/tools' import { createId } from '../../tools/tools'
import { exportObjectsToImage, exportObjectToThumbnail } from '../tools/exportMethod' import { exportObjectsToImage, exportObjectToThumbnail } from '../tools/exportMethod'
import { OperationType, BlendMode } from '../tools/layerHelper' import { OperationType, BlendMode } from '../tools/layerHelper'
import { getArrowPath, cloneObjects, getStarArr } from '../tools/canvasMethod' import { getArrowPath, getLinePath, cloneObjects, getStarArr } from '../tools/canvasMethod'
import i18n from '@/lang/index'
const t = i18n.global.t
export class LayerManager { export class LayerManager {
stateManager: any stateManager: any
@@ -206,7 +208,7 @@ export class LayerManager {
fill: 'transparent', fill: 'transparent',
info: { info: {
id: createId("image"), id: createId("image"),
name: '空图层', name: t('DepthCanvas.emptyLayer'),
} }
}) })
this.setLayerPosition(emptyObject) this.setLayerPosition(emptyObject)
@@ -226,7 +228,7 @@ export class LayerManager {
evented: false, evented: false,
info: { info: {
id: createId("group"), id: createId("group"),
name: '智能选区组', name: t('DepthCanvas.aiGroupLayer'),
showChildren: true, showChildren: true,
...(options?.info || {}), ...(options?.info || {}),
} }
@@ -245,7 +247,7 @@ export class LayerManager {
...(options || {}), ...(options || {}),
info: { info: {
id: createId("text"), id: createId("text"),
name: '文本图层', name: t('DepthCanvas.textLayer'),
...(options?.info || {}), ...(options?.info || {}),
} }
}) })
@@ -263,7 +265,7 @@ export class LayerManager {
...(options || {}), ...(options || {}),
info: { info: {
id: createId("rect"), id: createId("rect"),
name: '矩形图层', name: t('DepthCanvas.rectLayer'),
...(options?.info || {}), ...(options?.info || {}),
} }
}) })
@@ -274,25 +276,27 @@ export class LayerManager {
} }
/** 创建直线图层 */ /** 创建直线图层 */
async createLineLayer(options?: any, isRecord = true, isActive = true) { async createLineLayer(options?: any, isRecord = true, isActive = true) {
const line = [options?.x1 || 0, options?.y1 || 0, options?.x2 || 100, options?.y2 || 0] const width = options?.width || 100
delete options.x1 const height = options?.height || 2
delete options.y1 delete options.width
delete options.x2 delete options.height
delete options.y2 const arrowObject = new fabric.Path(getLinePath(width, height), {
const lineObject = new fabric.Line(line, { stroke: '#000', // 只设置边框颜色
stroke: 'black', // 线条颜色 strokeWidth: 2, // 边框宽度
strokeWidth: 2, // 线条粗细 fill: 'transparent', // 不填充
strokeLineCap: 'round',
strokeLineJoin: 'round',
...(options || {}), ...(options || {}),
info: { info: {
id: createId("line"), id: createId("line"),
name: '直线图层', name: t('DepthCanvas.lineLayer'),
...(options?.info || {}), ...(options?.info || {}),
} }
}) });
this.setLayerPosition(lineObject, options) this.setLayerPosition(arrowObject, options)
await this.canvasManager.add(lineObject, isRecord) await this.canvasManager.add(arrowObject, isRecord)
if (isActive) this.setActiveID(lineObject.info.id) if (isActive) this.setActiveID(arrowObject.info.id)
return lineObject return arrowObject
} }
/** 创建椭圆图层 */ /** 创建椭圆图层 */
async createEllipseLayer(options?: any, isRecord = true, isActive = true) { async createEllipseLayer(options?: any, isRecord = true, isActive = true) {
@@ -302,7 +306,7 @@ export class LayerManager {
...(options || {}), ...(options || {}),
info: { info: {
id: createId("ellipse"), id: createId("ellipse"),
name: '椭圆图层', name: t('DepthCanvas.ellipseLayer'),
...(options?.info || {}), ...(options?.info || {}),
} }
}) })
@@ -321,7 +325,7 @@ export class LayerManager {
...(options || {}), ...(options || {}),
info: { info: {
id: createId("triangle"), id: createId("triangle"),
name: '三角形图层', name: t('DepthCanvas.triangleLayer'),
...(options?.info || {}), ...(options?.info || {}),
} }
}) })
@@ -341,7 +345,7 @@ export class LayerManager {
...(options || {}), ...(options || {}),
info: { info: {
id: createId("star"), id: createId("star"),
name: '五角星图层', name: t('DepthCanvas.starLayer'),
...(options?.info || {}), ...(options?.info || {}),
} }
}) })
@@ -353,19 +357,19 @@ export class LayerManager {
/** 创建箭头图层 */ /** 创建箭头图层 */
async createArrowLayer(options?: any, isRecord = true, isActive = true) { async createArrowLayer(options?: any, isRecord = true, isActive = true) {
const width = options?.width || 100 const width = options?.width || 100
const height = options?.height || 10 const strokeWidth = options?.strokeWidth || 4
delete options.width delete options.width
delete options.height delete options.strokeWidth
const arrowObject = new fabric.Path(getArrowPath(width, height), { const arrowObject = new fabric.Path(getArrowPath(width, strokeWidth), {
stroke: '#000', // 只设置边框颜色 stroke: '#000', // 只设置边框颜色
strokeWidth: 3, // 边框宽度 strokeWidth, // 边框宽度
fill: 'transparent', // 不填充 fill: 'transparent', // 不填充
strokeLineCap: 'round', strokeLineCap: 'round',
strokeLineJoin: 'round', strokeLineJoin: 'round',
...(options || {}), ...(options || {}),
info: { info: {
id: createId("star"), id: createId("arrow"),
name: '箭头图层', name: t('DepthCanvas.arrowLayer'),
...(options?.info || {}), ...(options?.info || {}),
} }
}); });
@@ -395,7 +399,7 @@ export class LayerManager {
...(options || {}), ...(options || {}),
info: { info: {
id: createId("image"), id: createId("image"),
name: "图片图层", name: t('DepthCanvas.imageLayer'),
...(options?.info || {}), ...(options?.info || {}),
} }
}) })
@@ -419,7 +423,7 @@ export class LayerManager {
info: { info: {
...(targetLayer?.info || {}), ...(targetLayer?.info || {}),
id: createId("image"), id: createId("image"),
name: targetLayer?.info?.name || "合并图层", name: targetLayer?.info?.name || t('DepthCanvas.mergeLayer'),
} }
}) })
resolve(img) resolve(img)

View File

@@ -1,5 +1,5 @@
import { OperationType, OperationTypes } from "../tools/layerHelper"; import { OperationType, OperationTypes } from "../tools/layerHelper";
import { getStarArr, getArrowPath, distance, angleBetweenPointsDegrees } from "../tools/canvasMethod"; import { getStarArr, getArrowPath, getLinePath, distance, angleBetweenPointsDegrees } from "../tools/canvasMethod";
import { fabric } from 'fabric-with-all' import { fabric } from 'fabric-with-all'
/** 形状管理器 */ /** 形状管理器 */
export class ShapeToolManager { export class ShapeToolManager {
@@ -136,22 +136,47 @@ export class ShapeToolManager {
/** 绘制直线 */ /** 绘制直线 */
downLine() { downLine() {
const line = new fabric.Line([this.startX, this.startY, this.startX, this.startY], { // const line = new fabric.Line([this.startX, this.startY, this.startX, this.startY], {
stroke: 'black', // 线条颜色 // stroke: 'black', // 线条颜色
strokeWidth: 2 // 线条粗细 // strokeWidth: 2 // 线条粗细
}) // })
return line // return line
return new fabric.Path();
} }
moveLine({ x, y }) { moveLine({ x, y }) {
this.demoObject.set({ // this.demoObject.set({
x1: this.startX, // x1: this.startX,
y1: this.startY, // y1: this.startY,
x2: x, // x2: x,
y2: y, // y2: y,
}) // })
const width = distance(this.startX, this.startY, x, y)
const angle = angleBetweenPointsDegrees(this.startX, this.startY, x, y)
this.canvasManager.canvas.remove(this.demoObject)
const arrow = new fabric.Path(getLinePath(width, 2), {
left: this.startX,
top: this.startY,
stroke: '#000', // 只设置边框颜色
strokeWidth: 2, // 边框宽度
fill: 'transparent', // 不填充
strokeLineCap: 'round',
strokeLineJoin: 'round',
originY: 'center',
angle: angle,
});
this.canvasManager.canvas.add(arrow)
this.demoObject = arrow
} }
upLine(object) { upLine(object) {
this.layerManager.createLineLayer(object) if (object.originY !== "center") {
this.layerManager.createLineLayer({
left: this.startX,
top: this.startY,
})
} else {
this.layerManager.createLineLayer(object)
}
// this.layerManager.createLineLayer(object)
} }
/** 绘制椭圆 */ /** 绘制椭圆 */
@@ -228,11 +253,11 @@ export class ShapeToolManager {
const width = distance(this.startX, this.startY, x, y) const width = distance(this.startX, this.startY, x, y)
const angle = angleBetweenPointsDegrees(this.startX, this.startY, x, y) const angle = angleBetweenPointsDegrees(this.startX, this.startY, x, y)
this.canvasManager.canvas.remove(this.demoObject) this.canvasManager.canvas.remove(this.demoObject)
const arrow = new fabric.Path(getArrowPath(width, 10), { const arrow = new fabric.Path(getArrowPath(width, 4), {
left: this.startX, left: this.startX,
top: this.startY, top: this.startY,
stroke: '#000', // 只设置边框颜色 stroke: '#000', // 只设置边框颜色
strokeWidth: 3, // 边框宽度 strokeWidth: 4, // 边框宽度
fill: 'transparent', // 不填充 fill: 'transparent', // 不填充
strokeLineCap: 'round', strokeLineCap: 'round',
strokeLineJoin: 'round', strokeLineJoin: 'round',
@@ -247,7 +272,7 @@ export class ShapeToolManager {
this.layerManager.createArrowLayer({ this.layerManager.createArrowLayer({
left: this.startX, left: this.startX,
top: this.startY, top: this.startY,
}, true) })
} else { } else {
this.layerManager.createArrowLayer(object) this.layerManager.createArrowLayer(object)
} }

View File

@@ -73,7 +73,6 @@ export class StateManager {
/** 记录状态 */ /** 记录状态 */
recordState() { recordState() {
if (this.running.value) return if (this.running.value) return
console.log("recordState")
this.running.value = true this.running.value = true
if (this.historyIndex.value < this.historyList.value.length - 1) { if (this.historyIndex.value < this.historyList.value.length - 1) {
this.historyList.value.splice(this.historyIndex.value + 1) this.historyList.value.splice(this.historyIndex.value + 1)

View File

@@ -61,13 +61,26 @@ export function getStarArr(width = 0, height = 0) {
})) }))
} }
/** 获取箭头路径 */ /** 获取箭头路径 */
export function getArrowPath(width = 0, height = 0) { export function getArrowPath(width = 0, strokeWidth = 4) {
const height = strokeWidth * 4
const arr = [ const arr = [
["M", 0, height / 2], ["M", 0, height / 2],
["L", width, height / 2], ["L", width, height / 2],
["M", width - 8, 0], ["M", width - height, 0],
["L", width, height / 2],
["L", width - height, height],
]
var path = ""
arr.forEach(item => {
path += item.join(" ") + " "
})
return path
}
/** 获取直线路径 */
export function getLinePath(width = 0, height = 0) {
const arr = [
["M", 0, height / 2],
["L", width, height / 2], ["L", width, height / 2],
["L", width - 8, height],
] ]
var path = "" var path = ""
arr.forEach(item => { arr.forEach(item => {

View File

@@ -200,5 +200,47 @@ export default {
threeModel: { threeModel: {
loading: 'Loading', loading: 'Loading',
download: 'Download' download: 'Download'
},
DepthCanvas: {
layer: "Layer",
editDetails: "Edit Details",
export: "Export",
save: "Save",
workbench: "Workbench",
position: "Position",
size: "Size",
appearance: "Appearance",
opacity: "Opacity",
cornerRadius: "Cor Radius",
strokeWidth: "Stroke Width",
color: "Color",
image: "Image",
settings: "Settings",
rotation: "Rotation",
scale: "Scale",
gapX: "Gap X",
gapY: "Gap Y",
offset: "Offset",
emptyLayer: "Empty Layer",
aiGroupLayer: "AI Group Layer",
textLayer: "Text Layer",
rectLayer: "Rect Layer",
lineLayer: "Line Layer",
ellipseLayer: "Ellipse Layer",
triangleLayer: "Triangle Layer",
starLayer: "Star Layer",
arrowLayer: "Arrow Layer",
imageLayer: "Image Layer",
mergeLayer: "Merge Layer",
rectangle: "Rectangle",
line: "Line",
arrow: "Arrow",
ellipse: "Ellipse",
triangle: "Triangle",
star: "Star",
add: "Add",
remove: "Remove",
brush: "Brush",
erase: "Erase",
} }
} }

View File

@@ -153,7 +153,7 @@ export default {
quote: '引用', quote: '引用',
delete: '删除', delete: '删除',
edit: '编辑', edit: '编辑',
generatingReport:'正在为您生成报告,可能需要几分钟时间,生成期间你可以继续进行其他任务' generatingReport: '正在为您生成报告,可能需要几分钟时间,生成期间你可以继续进行其他任务'
}, },
// Version Tree // Version Tree
@@ -197,5 +197,47 @@ export default {
threeModel: { threeModel: {
loading: '加载中', loading: '加载中',
download: '下载' download: '下载'
},
DepthCanvas: {
layer: "图层",
editDetails: "编辑详情",
export: "导出",
save: "保存",
workbench: "工作台",
position: "位置",
size: "大小",
appearance: "外观",
opacity: "透明度",
cornerRadius: "圆角半径",
strokeWidth: "边框宽度",
color: "颜色",
image: "图片",
settings: "设置",
rotation: "旋转角度",
scale: "缩放",
gapX: "水平间距",
gapY: "垂直间距",
offset: "偏移量",
emptyLayer: "空图层",
aiGroupLayer: "智能选区组",
textLayer: "文本图层",
rectLayer: "矩形图层",
lineLayer: "直线图层",
ellipseLayer: "椭圆图层",
triangleLayer: "三角形图层",
starLayer: "五角星图层",
arrowLayer: "箭头图层",
imageLayer: "图片图层",
mergeLayer: "合并图层",
rectangle: "矩形",
line: "直线",
arrow: "箭头",
ellipse: "椭圆",
triangle: "三角形",
star: "五角星",
add: "添加",
remove: "删除",
brush: "画笔",
erase: "擦除",
} }
} }

View File

@@ -22,7 +22,7 @@
><svg-icon name="arrow-right" size="14" /> ><svg-icon name="arrow-right" size="14" />
</span> </span>
</div> </div>
<div class="history-list" v-show="!isCollapse && showHistory"> <div class="history-list mini-scrollbar" v-show="!isCollapse && showHistory">
<div v-for="item in list" :key="item.name" class="history-item"> <div v-for="item in list" :key="item.name" class="history-item">
<div v-if="item.title" class="title">{{ item.name }}</div> <div v-if="item.title" class="title">{{ item.name }}</div>
<div <div
@@ -307,7 +307,8 @@
> .history-list { > .history-list {
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
width: 23.2rem; width: 26.4rem;
padding: 0 1.5rem;
margin: 1rem auto 0; margin: 1rem auto 0;
> .history-item { > .history-item {
width: 100%; width: 100%;