Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite
This commit is contained in:
9
src/assets/icons/overallMore.svg
Normal file
9
src/assets/icons/overallMore.svg
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<rect width="24" height="24" fill="url(#pattern0_2641_12790)"/>
|
||||||
|
<defs>
|
||||||
|
<pattern id="pattern0_2641_12790" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||||
|
<use xlink:href="#image0_2641_12790" transform="scale(0.0078125)"/>
|
||||||
|
</pattern>
|
||||||
|
<image id="image0_2641_12790" width="128" height="128" preserveAspectRatio="none" xlink:href="data:image/png;base64,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"/>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.5 KiB |
@@ -163,7 +163,7 @@
|
|||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<div class="btn">
|
<div class="btn">
|
||||||
<i class="iconfont icon-gengduo"></i>
|
<SvgIcon name="overallMore" size="18" />
|
||||||
</div>
|
</div>
|
||||||
</a-popover>
|
</a-popover>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,26 +2,26 @@
|
|||||||
<div class="demo">
|
<div class="demo">
|
||||||
<div
|
<div
|
||||||
class="control"
|
class="control"
|
||||||
:class="{ active: item.id === activeId }"
|
:class="{ active: item.token === activeToken }"
|
||||||
v-for="(item, index) in list"
|
v-for="(item, index) in list"
|
||||||
:key="item.id"
|
:key="item.token"
|
||||||
@click="onSelect(item.id)"
|
@click="onSelect(item.token)"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<b>{{ item.name }}</b>
|
<b>{{ item.name }}</b>
|
||||||
<button
|
<button
|
||||||
v-if="index !== 0"
|
v-if="index !== 0"
|
||||||
@click="onMove(item.id, list[index - 1].id)"
|
@click="onMove(item.token, list[index - 1].token)"
|
||||||
>
|
>
|
||||||
←
|
←
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="index !== list.length - 1"
|
v-if="index !== list.length - 1"
|
||||||
@click="onMove(item.id, list[index + 1].id)"
|
@click="onMove(item.token, list[index + 1].token)"
|
||||||
>
|
>
|
||||||
→
|
→
|
||||||
</button>
|
</button>
|
||||||
<button @click.stop="onDelete(item.id)">删除</button>
|
<button @click.stop="onDelete(item.token)">删除</button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span>偏移X</span>
|
<span>偏移X</span>
|
||||||
@@ -105,10 +105,10 @@
|
|||||||
|
|
||||||
const convertDotNotationToBracket = (str) =>
|
const convertDotNotationToBracket = (str) =>
|
||||||
str.replace(/(?:^|\.)(\d+)(?=\.|$)/g, "[#$1]").replace(/\[#/g, "[");
|
str.replace(/(?:^|\.)(\d+)(?=\.|$)/g, "[#$1]").replace(/\[#/g, "[");
|
||||||
const activeId = ref("1");
|
const activeToken = ref("1");
|
||||||
const list = ref([
|
const list = ref([
|
||||||
{
|
{
|
||||||
id: "1",
|
token: "1",
|
||||||
ifSingle: false,
|
ifSingle: false,
|
||||||
level2Type: "Pattern",
|
level2Type: "Pattern",
|
||||||
designType: "Library",
|
designType: "Library",
|
||||||
@@ -133,7 +133,7 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "2",
|
token: "2",
|
||||||
ifSingle: false,
|
ifSingle: false,
|
||||||
level2Type: "Pattern",
|
level2Type: "Pattern",
|
||||||
designType: "Library",
|
designType: "Library",
|
||||||
@@ -163,42 +163,35 @@
|
|||||||
const oldList = ref(deepCopy(list.value));
|
const oldList = ref(deepCopy(list.value));
|
||||||
const pingpuRef = ref(null);
|
const pingpuRef = ref(null);
|
||||||
const updateCanvas = (arr) => {
|
const updateCanvas = (arr) => {
|
||||||
|
console.log(arr);
|
||||||
oldList.value = deepCopy(list.value);
|
oldList.value = deepCopy(list.value);
|
||||||
arr.forEach((item) => {
|
arr.forEach((item) => {
|
||||||
list.value.forEach((v) => {
|
const obj = list.value.find((v) => v.token === item.token);
|
||||||
|
if (item.action === ACTIONS.UPDATE) {
|
||||||
if (item.action === ACTIONS.UPDATE) {
|
if (item.action === ACTIONS.UPDATE) {
|
||||||
if (v.id === item.id) {
|
try {
|
||||||
if (item.action === ACTIONS.UPDATE) {
|
const key = item.key;
|
||||||
try {
|
const str = /^\[/.test(item.key)
|
||||||
const key = item.key;
|
? "obj" + key
|
||||||
const str = /^\[/.test(item.key)
|
: "obj." + key;
|
||||||
? "v" + key
|
eval(`${str} = item.value`);
|
||||||
: "v." + key;
|
} catch (error) {
|
||||||
eval(`${str} = item.value`);
|
console.error(error);
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (item.action === ACTIONS.SELECT) {
|
|
||||||
activeId.value = item.id;
|
|
||||||
}
|
}
|
||||||
});
|
} else if (item.action === ACTIONS.SELECT) {
|
||||||
|
activeToken.value = item.token;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSelect = (id) => {
|
const onSelect = (token) => {
|
||||||
activeId.value = id;
|
activeToken.value = token;
|
||||||
pingpuRef.value.updataList([
|
pingpuRef.value.updataList([{ token, action: ACTIONS.SELECT }]);
|
||||||
{
|
|
||||||
id: id,
|
|
||||||
action: ACTIONS.SELECT,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
};
|
};
|
||||||
const onMove = (id, id2) => {
|
const onMove = (token1, token2) => {
|
||||||
const obj1 = list.value.find((v) => v.id === id);
|
const obj1 = list.value.find((v) => v.token === token1);
|
||||||
const obj2 = list.value.find((v) => v.id === id2);
|
const obj2 = list.value.find((v) => v.token === token2);
|
||||||
const index1 = list.value.indexOf(obj1);
|
const index1 = list.value.indexOf(obj1);
|
||||||
const index2 = list.value.indexOf(obj2);
|
const index2 = list.value.indexOf(obj2);
|
||||||
if (index1 < index2) {
|
if (index1 < index2) {
|
||||||
@@ -206,26 +199,16 @@
|
|||||||
} else {
|
} else {
|
||||||
list.value.splice(index1, 0, list.value.splice(index2, 1)[0]);
|
list.value.splice(index1, 0, list.value.splice(index2, 1)[0]);
|
||||||
}
|
}
|
||||||
const ids = list.value.map((v) => v.id);
|
const tokens = list.value.map((v) => v.token);
|
||||||
pingpuRef.value.updataList([
|
pingpuRef.value.updataList([{ action: ACTIONS.SORT, tokens }]);
|
||||||
{
|
|
||||||
action: ACTIONS.SORT,
|
|
||||||
ids,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
};
|
};
|
||||||
const onDelete = (id) => {
|
const onDelete = (token) => {
|
||||||
list.value = list.value.filter((v) => v.id !== id);
|
list.value = list.value.filter((v) => v.token !== token);
|
||||||
pingpuRef.value.updataList([
|
pingpuRef.value.updataList([{ token, action: ACTIONS.DELETE }]);
|
||||||
{
|
|
||||||
id: id,
|
|
||||||
action: ACTIONS.DELETE,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
};
|
};
|
||||||
const onAdd = () => {
|
const onAdd = () => {
|
||||||
const obj = {
|
const obj = {
|
||||||
id: Date.now().toString(),
|
token: Date.now().toString(),
|
||||||
ifSingle: false,
|
ifSingle: false,
|
||||||
level2Type: "Pattern",
|
level2Type: "Pattern",
|
||||||
designType: "Library",
|
designType: "Library",
|
||||||
@@ -250,12 +233,7 @@
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
list.value.push(obj);
|
list.value.push(obj);
|
||||||
pingpuRef.value.updataList([
|
pingpuRef.value.updataList([{ action: ACTIONS.ADD, data: obj }]);
|
||||||
{
|
|
||||||
action: ACTIONS.ADD,
|
|
||||||
data: obj,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
};
|
};
|
||||||
watch(
|
watch(
|
||||||
() => list.value,
|
() => list.value,
|
||||||
@@ -266,20 +244,20 @@
|
|||||||
const updateList = () => {
|
const updateList = () => {
|
||||||
const changeList = [];
|
const changeList = [];
|
||||||
oldList.value.forEach((oldItem) => {
|
oldList.value.forEach((oldItem) => {
|
||||||
const newItem = list.value.find((v) => v.id === oldItem.id);
|
const newItem = list.value.find((v) => v.token === oldItem.token);
|
||||||
if (newItem) {
|
if (newItem) {
|
||||||
const arr = findDiffProps(oldItem, newItem);
|
const arr = findDiffProps(oldItem, newItem);
|
||||||
arr.forEach((item) => {
|
arr.forEach((item) => {
|
||||||
changeList.push({
|
changeList.push({
|
||||||
...item,
|
...item,
|
||||||
id: oldItem.id,
|
token: oldItem.token,
|
||||||
action: ACTIONS.UPDATE,
|
action: ACTIONS.UPDATE,
|
||||||
key: convertDotNotationToBracket(item.key),
|
key: convertDotNotationToBracket(item.key),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
changeList.push({
|
changeList.push({
|
||||||
id: oldItem.id,
|
token: oldItem.token,
|
||||||
action: ACTIONS.DELETE,
|
action: ACTIONS.DELETE,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="pingpu" ref="el"><canvas ref="canvasRef"></canvas></div>
|
<div class="overall-canvas" ref="el"><canvas ref="canvasRef"></canvas></div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -100,23 +100,23 @@
|
|||||||
const object = e.target;
|
const object = e.target;
|
||||||
const action = e.action;
|
const action = e.action;
|
||||||
const list = [];
|
const list = [];
|
||||||
const id = object.id;
|
const token = object.token;
|
||||||
if (action === "drag" || action === "rotate") {
|
if (action === "drag" || action === "rotate") {
|
||||||
list.push({
|
list.push({
|
||||||
id: id,
|
token,
|
||||||
action: ACTIONS.UPDATE,
|
action: ACTIONS.UPDATE,
|
||||||
key: KEYS.O_TOP,
|
key: KEYS.O_TOP,
|
||||||
value: object.top,
|
value: object.top,
|
||||||
});
|
});
|
||||||
list.push({
|
list.push({
|
||||||
id: id,
|
token,
|
||||||
action: ACTIONS.UPDATE,
|
action: ACTIONS.UPDATE,
|
||||||
key: KEYS.O_LEFT,
|
key: KEYS.O_LEFT,
|
||||||
value: object.left,
|
value: object.left,
|
||||||
});
|
});
|
||||||
if (action === "rotate") {
|
if (action === "rotate") {
|
||||||
list.push({
|
list.push({
|
||||||
id: id,
|
token,
|
||||||
action: ACTIONS.UPDATE,
|
action: ACTIONS.UPDATE,
|
||||||
key: KEYS.O_ANGLE,
|
key: KEYS.O_ANGLE,
|
||||||
value: object.angle,
|
value: object.angle,
|
||||||
@@ -124,13 +124,13 @@
|
|||||||
}
|
}
|
||||||
} else if (action === "scale") {
|
} else if (action === "scale") {
|
||||||
list.push({
|
list.push({
|
||||||
id: id,
|
token,
|
||||||
action: ACTIONS.UPDATE,
|
action: ACTIONS.UPDATE,
|
||||||
key: KEYS.O_SCALE_X,
|
key: KEYS.O_SCALE_X,
|
||||||
value: object.scaleX,
|
value: object.scaleX,
|
||||||
});
|
});
|
||||||
list.push({
|
list.push({
|
||||||
id: id,
|
token,
|
||||||
action: ACTIONS.UPDATE,
|
action: ACTIONS.UPDATE,
|
||||||
key: KEYS.O_SCALE_Y,
|
key: KEYS.O_SCALE_Y,
|
||||||
value: object.scaleY,
|
value: object.scaleY,
|
||||||
@@ -140,13 +140,8 @@
|
|||||||
};
|
};
|
||||||
// 对象选中
|
// 对象选中
|
||||||
const onObjectSelected = (e) => {
|
const onObjectSelected = (e) => {
|
||||||
const id = e.selected[0].id;
|
const token = e.selected[0].token;
|
||||||
const list = [
|
const list = [{ token, action: ACTIONS.SELECT }];
|
||||||
{
|
|
||||||
id: id,
|
|
||||||
action: ACTIONS.SELECT,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
emit("change-canvas", list);
|
emit("change-canvas", list);
|
||||||
};
|
};
|
||||||
const urlToCanvas = (url) => {
|
const urlToCanvas = (url) => {
|
||||||
@@ -181,7 +176,7 @@
|
|||||||
const cheight = canvas.height;
|
const cheight = canvas.height;
|
||||||
let pattern = await setFill(item);
|
let pattern = await setFill(item);
|
||||||
let rect = new fabric.Rect({
|
let rect = new fabric.Rect({
|
||||||
id: item.id,
|
token: item.token,
|
||||||
width: cwidth,
|
width: cwidth,
|
||||||
height: cheight,
|
height: cheight,
|
||||||
fill: pattern,
|
fill: pattern,
|
||||||
@@ -191,7 +186,6 @@
|
|||||||
};
|
};
|
||||||
const setFill = async (item) => {
|
const setFill = async (item) => {
|
||||||
if (!item) return null;
|
if (!item) return null;
|
||||||
console.log(item.scale);
|
|
||||||
const cwidth = canvas.width;
|
const cwidth = canvas.width;
|
||||||
const cheight = canvas.height;
|
const cheight = canvas.height;
|
||||||
let image = await urlToCanvas(item.path);
|
let image = await urlToCanvas(item.path);
|
||||||
@@ -225,12 +219,13 @@
|
|||||||
return pattern;
|
return pattern;
|
||||||
};
|
};
|
||||||
const updataList = async (list) => {
|
const updataList = async (list) => {
|
||||||
|
console.log(list);
|
||||||
const objects = canvas.getObjects();
|
const objects = canvas.getObjects();
|
||||||
// list.forEach((item) => {
|
|
||||||
for (let i = 0; i < list.length; i++) {
|
for (let i = 0; i < list.length; i++) {
|
||||||
let item = list[i];
|
let item = list[i];
|
||||||
let object = objects.find((o) => o.id === item.id);
|
let object = objects.find((o) => o.token === item.token);
|
||||||
if (item.action === ACTIONS.UPDATE) {
|
if (item.action === ACTIONS.UPDATE) {
|
||||||
|
if (!object) continue;
|
||||||
let value = item.value;
|
let value = item.value;
|
||||||
switch (item.key) {
|
switch (item.key) {
|
||||||
case KEYS.O_TOP:
|
case KEYS.O_TOP:
|
||||||
@@ -274,18 +269,17 @@
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (item.action === ACTIONS.SELECT) {
|
} else if (item.action === ACTIONS.SELECT) {
|
||||||
canvas.setActiveObject(object);
|
if (object) canvas.setActiveObject(object);
|
||||||
} else if (item.action === ACTIONS.SORT) {
|
} else if (item.action === ACTIONS.SORT) {
|
||||||
let ids = item.ids;
|
let tokens = item.tokens;
|
||||||
canvas.clear();
|
canvas.clear();
|
||||||
for (let j = 0; j < ids.length; j++) {
|
for (let j = 0; j < tokens.length; j++) {
|
||||||
let id = ids[j];
|
let object = objects.find((o) => o.token === tokens[j]);
|
||||||
let object = objects.find((o) => o.id === id);
|
if (object) canvas.add(object);
|
||||||
canvas.add(object);
|
|
||||||
}
|
}
|
||||||
canvas.renderAll();
|
canvas.renderAll();
|
||||||
} else if (item.action === ACTIONS.DELETE) {
|
} else if (item.action === ACTIONS.DELETE) {
|
||||||
canvas.remove(object);
|
if (object) canvas.remove(object);
|
||||||
} else if (item.action === ACTIONS.ADD) {
|
} else if (item.action === ACTIONS.ADD) {
|
||||||
await addObject(item.data);
|
await addObject(item.data);
|
||||||
}
|
}
|
||||||
@@ -298,7 +292,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang='less' scoped>
|
<style lang='less' scoped>
|
||||||
.pingpu {
|
.overall-canvas {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="test" ref="testRef">
|
<!-- <div class="test" ref="testRef">
|
||||||
<div class="canvas-container">
|
<div class="canvas-container">
|
||||||
<canvas id="canvas"></canvas>
|
<canvas id="canvas"></canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> -->
|
||||||
|
<overall-canvas-demo />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { fabric } from "fabric-with-all";
|
import { fabric } from "fabric-with-all";
|
||||||
import { ref, watch, onMounted } from "vue";
|
import { ref, watch, onMounted } from "vue";
|
||||||
|
import OverallCanvasDemo from "./OverallCanvas/demo.vue";
|
||||||
const imageUrl = "/src/assets/images/canvas/xiangaofenge.png";
|
const imageUrl = "/src/assets/images/canvas/xiangaofenge.png";
|
||||||
const testRef = ref(null);
|
const testRef = ref(null);
|
||||||
|
|
||||||
|
|||||||
@@ -42,15 +42,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="stateOverallSingle != 'single'" class="habit_System_Designer">
|
<div v-show="stateOverallSingle != 'single'" class="habit_System_Designer">
|
||||||
<div class="habit_System_Designer_text">{{ $t('DesignPrintOperation.Scale') }}</div>
|
<!-- <a-slider id="system_silder"
|
||||||
<a-slider id="system_silder"
|
|
||||||
class="system_silder"
|
class="system_silder"
|
||||||
:min="20"
|
:min="20"
|
||||||
:max="1000"
|
:max="1000"
|
||||||
v-model:value="systemDesignerPercentage"
|
v-model:value="systemDesignerPercentage"
|
||||||
:tip-formatter="formatter"
|
:tip-formatter="formatter"
|
||||||
>
|
>
|
||||||
</a-slider>
|
</a-slider> -->
|
||||||
<a-popover
|
<a-popover
|
||||||
trigger="click"
|
trigger="click"
|
||||||
destroyTooltipOnHide
|
destroyTooltipOnHide
|
||||||
@@ -67,7 +66,7 @@
|
|||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<div class="btn">
|
<div class="btn">
|
||||||
<i class="iconfont icon-gengduo"></i>
|
<SvgIcon name="overallMore" size="20" />
|
||||||
</div>
|
</div>
|
||||||
</a-popover>
|
</a-popover>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -102,23 +102,36 @@
|
|||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.repeat-setting {
|
.repeat-setting {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
width: 228px;
|
||||||
|
> .title {
|
||||||
|
line-height: 35px;
|
||||||
|
font-size: 14px;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: -12px;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
> .repeat-setting-item {
|
> .repeat-setting-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
//虚线
|
margin-bottom: 10px;
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
&.offset {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
> .label {
|
> .label {
|
||||||
min-width: 50px;
|
min-width: 68px;
|
||||||
font-size: 14px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
> .angle-tool {
|
&:not(.offset) > div {
|
||||||
width: 120px;
|
width: 120px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
> .slider {
|
||||||
|
--slider-thumb-color1: #000;
|
||||||
|
--slider-thumb-color2: #eee;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
> p {
|
|
||||||
margin: 10px 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 0;
|
|
||||||
border-bottom: 1px dashed #e5e5e5;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,38 +1,73 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="angle-tool">
|
<div class="angle-tool" :disabled="disabled">
|
||||||
<div
|
<template v-if="styleType === '1'">
|
||||||
ref="dishRef"
|
<div
|
||||||
class="dish"
|
ref="dishRef"
|
||||||
@mousedown.stop="mousedown"
|
class="dish"
|
||||||
@touchmove.stop="mousedown"
|
@mousedown.stop="mousedown"
|
||||||
>
|
@touchmove.stop="mousedown"
|
||||||
<div class="pointer" :style="{ transform: `rotate(${angle}deg)` }">
|
>
|
||||||
<span></span>
|
<div
|
||||||
|
class="pointer"
|
||||||
|
:style="{ transform: `rotate(${angle}deg)` }"
|
||||||
|
>
|
||||||
|
<span></span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="input">
|
||||||
<div class="input">
|
<input
|
||||||
<input type="number" v-model="angle" @input="onInput" @change="onChange" />
|
type="number"
|
||||||
</div>
|
v-model="angle"
|
||||||
|
@input="onInput"
|
||||||
|
@change="onChange"
|
||||||
|
:disabled="disabled"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<my-input
|
||||||
|
v-if="styleType === '2'"
|
||||||
|
v-model="angle"
|
||||||
|
@input="onInput"
|
||||||
|
@change="onChange"
|
||||||
|
:disabled="disabled"
|
||||||
|
type="number"
|
||||||
|
after="°"
|
||||||
|
icon="icon-angle"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, defineProps, defineEmits, watch } from "vue";
|
import { ref, defineProps, defineEmits, watch } from "vue";
|
||||||
import { calculateAngle } from "@/component/Canvas/CanvasEditor/utils/helper";
|
import { calculateAngle } from "@/component/Canvas/CanvasEditor/utils/helper";
|
||||||
|
import MyInput from "./MyInput.vue";
|
||||||
// Props
|
// Props
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
styleType: {
|
||||||
|
type: String,
|
||||||
|
default: "1",
|
||||||
|
},
|
||||||
angle: {
|
angle: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0,
|
default: 0,
|
||||||
},
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const emit = defineEmits(["change", "input"]);
|
const emit = defineEmits(["change", "input"]);
|
||||||
const angle = ref(props.angle);
|
const angle = ref(props.angle);
|
||||||
watch(() => props.angle, (value) => {
|
watch(
|
||||||
angle.value = value;
|
() => props.angle,
|
||||||
});
|
(value) => {
|
||||||
|
angle.value = value;
|
||||||
|
}
|
||||||
|
);
|
||||||
const dishRef = ref<HTMLDivElement>();
|
const dishRef = ref<HTMLDivElement>();
|
||||||
const mousedown = (e: MouseEvent | TouchEvent) => {
|
const mousedown = (e: MouseEvent | TouchEvent) => {
|
||||||
|
if (props.disabled) return;
|
||||||
const mousemove = (e: MouseEvent | TouchEvent) => {
|
const mousemove = (e: MouseEvent | TouchEvent) => {
|
||||||
if (!dishRef.value) return;
|
if (!dishRef.value) return;
|
||||||
const { left, top, width, height } =
|
const { left, top, width, height } =
|
||||||
@@ -41,7 +76,6 @@
|
|||||||
const centerY = top + height / 2;
|
const centerY = top + height / 2;
|
||||||
const { clientX, clientY } = e?.touches?.[0] || e;
|
const { clientX, clientY } = e?.touches?.[0] || e;
|
||||||
angle.value = calculateAngle(centerX, centerY, clientX, clientY, true);
|
angle.value = calculateAngle(centerX, centerY, clientX, clientY, true);
|
||||||
console.log(angle.value)
|
|
||||||
onInput();
|
onInput();
|
||||||
};
|
};
|
||||||
mousemove(e);
|
mousemove(e);
|
||||||
@@ -57,9 +91,10 @@
|
|||||||
document.addEventListener("mouseup", mouseup);
|
document.addEventListener("mouseup", mouseup);
|
||||||
document.addEventListener("touchend", mouseup);
|
document.addEventListener("touchend", mouseup);
|
||||||
};
|
};
|
||||||
const onInput = () => emit("input", angle.value);
|
const onInput = () => !props.disabled && emit("input", angle.value);
|
||||||
var changeTime: any = null;
|
var changeTime: any = null;
|
||||||
const onChange = () => {
|
const onChange = () => {
|
||||||
|
if (props.disabled) return;
|
||||||
clearTimeout(changeTime);
|
clearTimeout(changeTime);
|
||||||
changeTime = setTimeout(() => emit("change", angle.value), 500);
|
changeTime = setTimeout(() => emit("change", angle.value), 500);
|
||||||
};
|
};
|
||||||
@@ -80,10 +115,17 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
--color: #000;
|
||||||
|
&[disabled="true"] {
|
||||||
|
--color: #b2b2b2;
|
||||||
|
> .dish {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
}
|
||||||
> .dish {
|
> .dish {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
border: 1px solid #000;
|
border: 1px solid var(--color);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
> .pointer {
|
> .pointer {
|
||||||
@@ -99,7 +141,7 @@
|
|||||||
transform: translate(-50%, 0);
|
transform: translate(-50%, 0);
|
||||||
width: 35%;
|
width: 35%;
|
||||||
height: 35%;
|
height: 35%;
|
||||||
background-color: #000;
|
background-color: var(--color);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -107,7 +149,7 @@
|
|||||||
> .input {
|
> .input {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #000;
|
color: var(--color);
|
||||||
flex: 1;
|
flex: 1;
|
||||||
// min-width: 45px;
|
// min-width: 45px;
|
||||||
// max-width: 80px;
|
// max-width: 80px;
|
||||||
@@ -118,5 +160,8 @@
|
|||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
> .my-input {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
<template>
|
||||||
|
<div class="my-input">
|
||||||
|
<span class="decorate"></span>
|
||||||
|
<span v-show="icon" :class="['iconfont', icon]"></span>
|
||||||
|
<span v-show="before" class="before">{{ before }}</span>
|
||||||
|
<input v-bind="$attrs" :value="modelValue" @input="onInput" />
|
||||||
|
<span v-show="after" class="after">{{ after }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, defineProps, defineEmits, watch } from "vue";
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: { type: Number, default: 0 },
|
||||||
|
icon: { default: "", type: String },
|
||||||
|
before: { default: "", type: String },
|
||||||
|
after: { default: "", type: String },
|
||||||
|
});
|
||||||
|
const emit = defineEmits(["update:modelValue", "input"]);
|
||||||
|
const onInput = (e) => {
|
||||||
|
const value = e.target.value;
|
||||||
|
emit("update:modelValue", value);
|
||||||
|
emit("input", value);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style scoped lang="less">
|
||||||
|
.my-input {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid rgba(230, 230, 231, 1);
|
||||||
|
border-radius: 3px;
|
||||||
|
height: 20px;
|
||||||
|
padding: 0 4px 0 2px;
|
||||||
|
> .decorate {
|
||||||
|
width: 2px;
|
||||||
|
background-color: rgba(230, 230, 231, 1);
|
||||||
|
border-radius: 3px;
|
||||||
|
height: 85%;
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
> .iconfont {
|
||||||
|
font-size: 10px;
|
||||||
|
color: #000;
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
> .before {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #000;
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
> .after {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
> input {
|
||||||
|
font-size: 12px;
|
||||||
|
width: 0;
|
||||||
|
flex: 1;
|
||||||
|
text-align: right;
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
background-color: transparent;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
@change="change"
|
@change="change"
|
||||||
:defaultValue="defaultValue"
|
:defaultValue="defaultValue"
|
||||||
@dropdownVisibleChange="dropdownVisibleChange"
|
@dropdownVisibleChange="dropdownVisibleChange"
|
||||||
|
:disabled="disabled"
|
||||||
>
|
>
|
||||||
<a-select-option
|
<a-select-option
|
||||||
v-for="v in list"
|
v-for="v in list"
|
||||||
@@ -21,6 +22,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, defineProps, defineEmits, watch } from "vue";
|
import { ref, defineProps, defineEmits, watch } from "vue";
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
defaultValue: {
|
defaultValue: {
|
||||||
default: "",
|
default: "",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,84 +1,100 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="offset-tool">
|
<div class="offset-tool">
|
||||||
|
<div class="input" v-show="showInput">
|
||||||
|
<my-input
|
||||||
|
v-model="left"
|
||||||
|
@input="onInput"
|
||||||
|
@change="onChange"
|
||||||
|
type="number"
|
||||||
|
before="X"
|
||||||
|
after="%"
|
||||||
|
:min="-100"
|
||||||
|
:max="100"
|
||||||
|
/>
|
||||||
|
<my-input
|
||||||
|
v-model="top"
|
||||||
|
@input="onInput"
|
||||||
|
@change="onChange"
|
||||||
|
type="number"
|
||||||
|
before="Y"
|
||||||
|
after="%"
|
||||||
|
:min="-100"
|
||||||
|
:max="100"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
class="dish"
|
class="dish"
|
||||||
@mousedown="mousedown"
|
@mousedown="mousedown"
|
||||||
@touchstart="mousedown"
|
@touchstart="mousedown"
|
||||||
ref="dishRef"
|
ref="dishRef"
|
||||||
|
v-show="showDish"
|
||||||
>
|
>
|
||||||
<span
|
<img src="/src/assets/images/icon/xyz.png" />
|
||||||
:style="{ top: data.top + '%', left: data.left + '%' }"
|
<span class="ball" :style="ballStyle"></span>
|
||||||
></span>
|
<span class="tip x">X: {{ left }}%</span>
|
||||||
|
<span class="tip y">Y: {{ top }}%</span>
|
||||||
|
<span class="line x"></span>
|
||||||
|
<span class="line y"></span>
|
||||||
|
<span class="line z" :style="lineZStyle"></span>
|
||||||
</div>
|
</div>
|
||||||
<input
|
|
||||||
class="top"
|
|
||||||
type="range"
|
|
||||||
:min="0"
|
|
||||||
:max="100"
|
|
||||||
:step="0.1"
|
|
||||||
v-model="data.top"
|
|
||||||
@input="onInput"
|
|
||||||
@change="onChange"
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
class="left"
|
|
||||||
type="range"
|
|
||||||
:min="0"
|
|
||||||
:max="100"
|
|
||||||
:step="0.1"
|
|
||||||
v-model="data.left"
|
|
||||||
@input="onInput"
|
|
||||||
@change="onChange"
|
|
||||||
/>
|
|
||||||
<span class="tip"
|
|
||||||
>x:{{ tofix(data.left) }}% y:{{ tofix(data.top) }}%</span
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, defineProps, defineEmits, watch } from "vue";
|
import { ref, defineProps, defineEmits, watch, computed } from "vue";
|
||||||
|
import MyInput from "./MyInput.vue";
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
top: {
|
|
||||||
type: Number,
|
|
||||||
default: 50,
|
|
||||||
},
|
|
||||||
left: {
|
left: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 50,
|
default: 0,
|
||||||
|
},
|
||||||
|
top: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
showInput: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
showDish: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const tofix = (v: number | string) => Number(Number(v).toFixed(1));
|
|
||||||
const emit = defineEmits(["change", "input"]);
|
const emit = defineEmits(["change", "input"]);
|
||||||
const data = reactive({
|
// 工具的实际坐标 -100 ~ 100
|
||||||
top: tofix(props.top),
|
const top = ref(Math.round(props.top));
|
||||||
left: tofix(props.left),
|
const left = ref(Math.round(props.left));
|
||||||
});
|
|
||||||
watch(
|
// 原点的坐标 0 ~ 100
|
||||||
() => props.top,
|
const ballStyle = computed(() => ({
|
||||||
(v) => (data.top = tofix(v))
|
top: 50 + Number(top.value) / 2 + "%",
|
||||||
);
|
left: 50 + Number(left.value) / 2 + "%",
|
||||||
|
}));
|
||||||
watch(
|
watch(
|
||||||
() => props.left,
|
() => props.left,
|
||||||
(v) => (data.left = tofix(v))
|
(v) => (left.value = Math.round(v))
|
||||||
|
);
|
||||||
|
watch(
|
||||||
|
() => props.top,
|
||||||
|
(v) => (top.value = Math.round(v))
|
||||||
);
|
);
|
||||||
const dishRef = ref<HTMLDivElement>();
|
const dishRef = ref<HTMLDivElement>();
|
||||||
const mousedown = (e: MouseEvent | TouchEvent) => {
|
const mousedown = (e: MouseEvent | TouchEvent) => {
|
||||||
if (!dishRef.value) return;
|
if (!dishRef.value) return;
|
||||||
const mousemove = (e: MouseEvent | TouchEvent) => {
|
const mousemove = (e: MouseEvent | TouchEvent) => {
|
||||||
if (!dishRef.value) return;
|
if (!dishRef.value) return;
|
||||||
const { left, top, width, height } =
|
const rect = dishRef.value.getBoundingClientRect();
|
||||||
dishRef.value.getBoundingClientRect();
|
|
||||||
const X = e.clientX || (e as TouchEvent).touches[0].clientX;
|
const X = e.clientX || (e as TouchEvent).touches[0].clientX;
|
||||||
const Y = e.clientY || (e as TouchEvent).touches[0].clientY;
|
const Y = e.clientY || (e as TouchEvent).touches[0].clientY;
|
||||||
var x = ((X - left) / width) * 100;
|
var x = ((X - rect.left) / rect.width) * 100;
|
||||||
var y = ((Y - top) / height) * 100;
|
var y = ((Y - rect.top) / rect.height) * 100;
|
||||||
if (x < 0) x = 0;
|
if (x < 0) x = 0;
|
||||||
if (x > 100) x = 100;
|
if (x > 100) x = 100;
|
||||||
if (y < 0) y = 0;
|
if (y < 0) y = 0;
|
||||||
if (y > 100) y = 100;
|
if (y > 100) y = 100;
|
||||||
data.left = tofix(x);
|
left.value = Math.round((x - 50) * 2);
|
||||||
data.top = tofix(y);
|
top.value = Math.round((y - 50) * 2);
|
||||||
onInput();
|
onInput();
|
||||||
};
|
};
|
||||||
mousemove(e);
|
mousemove(e);
|
||||||
@@ -94,96 +110,125 @@
|
|||||||
document.addEventListener("mouseup", mouseup);
|
document.addEventListener("mouseup", mouseup);
|
||||||
document.addEventListener("touchend", mouseup);
|
document.addEventListener("touchend", mouseup);
|
||||||
};
|
};
|
||||||
const onInput = () => emit("input", { ...data });
|
const onInput = () => {
|
||||||
|
emit("input", { left: left.value, top: top.value });
|
||||||
|
};
|
||||||
var changeTime: any = null;
|
var changeTime: any = null;
|
||||||
const onChange = () => {
|
const onChange = () => {
|
||||||
clearTimeout(changeTime);
|
clearTimeout(changeTime);
|
||||||
changeTime = setTimeout(() => emit("change", { ...data }), 500);
|
changeTime = setTimeout(() => {
|
||||||
|
emit("change", {
|
||||||
|
left: left.value,
|
||||||
|
top: top.value,
|
||||||
|
});
|
||||||
|
}, 500);
|
||||||
};
|
};
|
||||||
// var offsetTime = null;
|
const lineZStyle = computed(() => ({
|
||||||
// watch(data, (v) => {
|
"--rotateZ": calculateAngle(0, 0, left.value, top.value) + "deg",
|
||||||
// const obj = { ...v };
|
width: calculateDistance(0, 0, left.value, top.value) / 2 + "%",
|
||||||
// emit("input", obj);
|
}));
|
||||||
// clearTimeout(offsetTime);
|
// 计算角度
|
||||||
// offsetTime = setTimeout(() => emit("change", obj), 50);
|
function calculateAngle(x1: number, y1: number, x2: number, y2: number) {
|
||||||
// });
|
const deltaX = x2 - x1;
|
||||||
|
const deltaY = y1 - y2;
|
||||||
// defineExpose({
|
let angle = Math.atan2(deltaX, deltaY) * (180 / Math.PI) - 90;
|
||||||
// open,
|
return angle;
|
||||||
// close,
|
}
|
||||||
// });
|
// 计算距离
|
||||||
|
function calculateDistance(x1: number, y1: number, x2: number, y2: number) {
|
||||||
|
const deltaX = x2 - x1;
|
||||||
|
const deltaY = y2 - y1;
|
||||||
|
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.offset-tool {
|
.offset-tool {
|
||||||
width: 125px;
|
|
||||||
height: 125px;
|
|
||||||
display: flex;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
> .input {
|
||||||
--gap: 15px;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
> * {
|
||||||
|
flex: 1;
|
||||||
|
margin-right: 12px;
|
||||||
|
&:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
> .dish {
|
> .dish {
|
||||||
margin: var(--gap) 0 0 var(--gap);
|
width: 135px;
|
||||||
flex: 1;
|
height: 135px;
|
||||||
border: 1px solid #000;
|
border: 1px solid #eaeaea;
|
||||||
border-radius: 5px;
|
border-radius: 4px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: relative;
|
position: relative;
|
||||||
background-color: #fff;
|
background-color: #f6f6f6;
|
||||||
> span {
|
margin-top: 24px;
|
||||||
|
> * {
|
||||||
|
position: absolute;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
position: absolute;
|
}
|
||||||
top: 0%;
|
> img {
|
||||||
left: 0%;
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
bottom: 4px;
|
||||||
|
right: 4px;
|
||||||
|
}
|
||||||
|
> .ball {
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
width: 8px;
|
width: 10px;
|
||||||
height: 8px;
|
height: 10px;
|
||||||
background-color: #000;
|
border: 1px solid #fff;
|
||||||
|
background-color: #333;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
box-shadow: 0px 0.68px 1.7px 0px rgba(0, 0, 0, 0.26);
|
||||||
}
|
}
|
||||||
}
|
> .tip {
|
||||||
> .tip {
|
font-size: 10px;
|
||||||
position: absolute;
|
color: #000;
|
||||||
right: 4px;
|
line-height: 24px;
|
||||||
bottom: 0;
|
&.x {
|
||||||
font-size: 10px;
|
top: 50%;
|
||||||
pointer-events: none;
|
right: 0%;
|
||||||
user-select: none;
|
transform: translate(100%, -50%);
|
||||||
color: #666;
|
padding-left: 6px;
|
||||||
}
|
}
|
||||||
> input.left {
|
&.y {
|
||||||
right: 0;
|
top: 0%;
|
||||||
}
|
left: 50%;
|
||||||
> input.top {
|
transform: translate(-50%, -100%);
|
||||||
bottom: 0;
|
}
|
||||||
left: 0;
|
|
||||||
transform-origin: left bottom;
|
|
||||||
transform: rotate(90deg) translateX(-100%);
|
|
||||||
}
|
|
||||||
> input {
|
|
||||||
position: absolute;
|
|
||||||
width: calc(100% - var(--gap));
|
|
||||||
-webkit-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
height: 8px;
|
|
||||||
border-radius: 8px;
|
|
||||||
background: rgba(0, 0, 0, 0.1); /* 更柔和的颜色 */
|
|
||||||
// outline: none;
|
|
||||||
&::-webkit-slider-thumb {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
width: 8px;
|
|
||||||
height: 8px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background: #4285f4; /* 蓝色滑块 */
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.2s;
|
|
||||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
}
|
||||||
&::-webkit-slider-thumb:hover {
|
> .line {
|
||||||
background: #3b77db;
|
border-color: #d9d9d9;
|
||||||
transform: scale(1.1);
|
border-style: dashed;
|
||||||
|
border-width: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
&.x {
|
||||||
|
width: 100%;
|
||||||
|
border-top-width: 1px;
|
||||||
|
}
|
||||||
|
&.y {
|
||||||
|
height: 100%;
|
||||||
|
border-left-width: 1px;
|
||||||
|
}
|
||||||
|
&.z {
|
||||||
|
width: 50%;
|
||||||
|
border-top-width: 1px;
|
||||||
|
border-color: #454754;
|
||||||
|
transform: translate(0%, -50%) rotateZ(var(--rotateZ));
|
||||||
|
transform-origin: left center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="slider">
|
<div class="slider" :disabled="disabled">
|
||||||
<div class="input-range">
|
<div
|
||||||
<span
|
class="input-range"
|
||||||
class="tip"
|
:style="{
|
||||||
:style="{
|
'--progress': (value - props.min) / (props.max - props.min),
|
||||||
'--progress': (value - props.min) / (props.max - props.min),
|
}"
|
||||||
}"
|
>
|
||||||
>{{ props.tipFormatter(value) }}</span
|
<span class="tip">{{ props.tipFormatter(value) }}</span>
|
||||||
>
|
|
||||||
<input
|
<input
|
||||||
type="range"
|
type="range"
|
||||||
v-model="value"
|
v-model="value"
|
||||||
@@ -16,17 +15,19 @@
|
|||||||
:step="props.step"
|
:step="props.step"
|
||||||
@input="onInput"
|
@input="onInput"
|
||||||
@change="onChange"
|
@change="onChange"
|
||||||
|
:disabled="disabled"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="input" v-show="isInput">
|
<div class="input" v-show="isInput">
|
||||||
<input
|
<my-input
|
||||||
type="number"
|
|
||||||
v-model="value"
|
v-model="value"
|
||||||
:min="props.min"
|
:min="props.min"
|
||||||
:max="props.max"
|
:max="props.max"
|
||||||
:step="props.step"
|
:step="props.step"
|
||||||
@input="onInput"
|
@input="onInput"
|
||||||
@change="onChange"
|
@change="onChange"
|
||||||
|
:disabled="disabled"
|
||||||
|
type="number"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -34,7 +35,12 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, defineProps, defineEmits, watch } from "vue";
|
import { ref, defineProps, defineEmits, watch } from "vue";
|
||||||
|
import MyInput from "./MyInput.vue";
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
value: {
|
value: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0,
|
default: 0,
|
||||||
@@ -66,9 +72,10 @@
|
|||||||
() => props.value,
|
() => props.value,
|
||||||
(v) => (value.value = v)
|
(v) => (value.value = v)
|
||||||
);
|
);
|
||||||
const onInput = () => emit("input", Number(value.value));
|
const onInput = () => !props.disabled && emit("input", Number(value.value));
|
||||||
var changeTime: any = null;
|
var changeTime: any = null;
|
||||||
const onChange = () => {
|
const onChange = () => {
|
||||||
|
if (props.disabled) return;
|
||||||
clearTimeout(changeTime);
|
clearTimeout(changeTime);
|
||||||
changeTime = setTimeout(() => emit("change", Number(value.value)), 500);
|
changeTime = setTimeout(() => emit("change", Number(value.value)), 500);
|
||||||
};
|
};
|
||||||
@@ -79,9 +86,10 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
--input-thumb-size: 12px;
|
|
||||||
width: 150px;
|
width: 150px;
|
||||||
// &:focus-within,
|
--input-thumb-size: 10px;
|
||||||
|
--backcolor1: var(--slider-thumb-color1, #4285f4);
|
||||||
|
--backcolor2: var(--slider-thumb-color2, rgba(0, 0, 0, 0.1));
|
||||||
&:hover {
|
&:hover {
|
||||||
> .input-range > .tip {
|
> .input-range > .tip {
|
||||||
display: block;
|
display: block;
|
||||||
@@ -96,21 +104,26 @@
|
|||||||
appearance: none;
|
appearance: none;
|
||||||
height: 5px;
|
height: 5px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
background: rgba(0, 0, 0, 0.1); /* 更柔和的颜色 */
|
|
||||||
outline: none;
|
outline: none;
|
||||||
|
background: linear-gradient(
|
||||||
|
to right,
|
||||||
|
var(--backcolor1) 0%,
|
||||||
|
var(--backcolor1) calc(var(--progress) * 100%),
|
||||||
|
var(--backcolor2) calc(var(--progress) * 100%),
|
||||||
|
var(--backcolor2) 100%
|
||||||
|
);
|
||||||
&::-webkit-slider-thumb {
|
&::-webkit-slider-thumb {
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
width: var(--input-thumb-size);
|
width: var(--input-thumb-size);
|
||||||
height: var(--input-thumb-size);
|
height: var(--input-thumb-size);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: #4285f4; /* 蓝色滑块 */
|
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 1px 2px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
&::-webkit-slider-thumb:hover {
|
&::-webkit-slider-thumb:hover {
|
||||||
background: #3b77db;
|
|
||||||
transform: scale(1.1);
|
transform: scale(1.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -640,6 +640,12 @@ export default defineComponent({
|
|||||||
:deep(.moveable-origin){
|
:deep(.moveable-origin){
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
:deep(.moveable-control){
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
:deep(.moveable-rotation-control){
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
> .designOpenrtion_imgMask{
|
> .designOpenrtion_imgMask{
|
||||||
width: auto;
|
width: auto;
|
||||||
|
|||||||
@@ -1074,10 +1074,10 @@ export default defineComponent({
|
|||||||
const scrollTop = textarea.scrollTop
|
const scrollTop = textarea.scrollTop
|
||||||
|
|
||||||
// 2. 计算单行高度
|
// 2. 计算单行高度
|
||||||
const lineHeight = parseInt(getComputedStyle(textarea).lineHeight) || 20 // 默认20px
|
const lineHeight:any = parseInt(getComputedStyle(textarea).lineHeight) || 20 // 默认20px
|
||||||
|
|
||||||
// 3. 重置高度为1行
|
// 3. 重置高度为1行
|
||||||
textarea.style.height = lineHeight + 'px'
|
textarea.style.height = (parseInt(lineHeight)+4) + 'px'
|
||||||
|
|
||||||
// 4. 计算实际需要的高度
|
// 4. 计算实际需要的高度
|
||||||
const newHeight = Math.max(lineHeight, textarea.scrollHeight)
|
const newHeight = Math.max(lineHeight, textarea.scrollHeight)
|
||||||
|
|||||||
@@ -476,9 +476,9 @@ export default defineComponent({
|
|||||||
if(!textarea)return
|
if(!textarea)return
|
||||||
const scrollTop = textarea.scrollTop;
|
const scrollTop = textarea.scrollTop;
|
||||||
// 2. 计算单行高度
|
// 2. 计算单行高度
|
||||||
const lineHeight = parseInt(getComputedStyle(textarea).lineHeight) || 20; // 默认20px
|
const lineHeight:any = parseInt(getComputedStyle(textarea).lineHeight) || 20; // 默认20px
|
||||||
// 3. 重置高度为1行
|
// 3. 重置高度为1行
|
||||||
textarea.style.height = lineHeight + 'px';
|
textarea.style.height = (parseInt(lineHeight)+4) + 'px'
|
||||||
// 4. 计算实际需要的高度
|
// 4. 计算实际需要的高度
|
||||||
const newHeight = Math.max(lineHeight, textarea.scrollHeight);
|
const newHeight = Math.max(lineHeight, textarea.scrollHeight);
|
||||||
textarea.style.height = newHeight + 'px';
|
textarea.style.height = newHeight + 'px';
|
||||||
|
|||||||
Reference in New Issue
Block a user