Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite

This commit is contained in:
李志鹏
2026-01-14 11:26:53 +08:00
15 changed files with 442 additions and 266 deletions

View File

@@ -163,7 +163,7 @@
/>
</template>
<div class="btn">
<i class="iconfont icon-gengduo"></i>
<SvgIcon name="overallMore" size="18" />
</div>
</a-popover>
</div>

View File

@@ -2,26 +2,26 @@
<div class="demo">
<div
class="control"
:class="{ active: item.id === activeId }"
:class="{ active: item.token === activeToken }"
v-for="(item, index) in list"
:key="item.id"
@click="onSelect(item.id)"
:key="item.token"
@click="onSelect(item.token)"
>
<div>
<b>{{ item.name }}</b>
<button
v-if="index !== 0"
@click="onMove(item.id, list[index - 1].id)"
@click="onMove(item.token, list[index - 1].token)"
>
</button>
<button
v-if="index !== list.length - 1"
@click="onMove(item.id, list[index + 1].id)"
@click="onMove(item.token, list[index + 1].token)"
>
</button>
<button @click.stop="onDelete(item.id)">删除</button>
<button @click.stop="onDelete(item.token)">删除</button>
</div>
<div>
<span>偏移X</span>
@@ -105,10 +105,10 @@
const convertDotNotationToBracket = (str) =>
str.replace(/(?:^|\.)(\d+)(?=\.|$)/g, "[#$1]").replace(/\[#/g, "[");
const activeId = ref("1");
const activeToken = ref("1");
const list = ref([
{
id: "1",
token: "1",
ifSingle: false,
level2Type: "Pattern",
designType: "Library",
@@ -133,7 +133,7 @@
},
},
{
id: "2",
token: "2",
ifSingle: false,
level2Type: "Pattern",
designType: "Library",
@@ -163,42 +163,35 @@
const oldList = ref(deepCopy(list.value));
const pingpuRef = ref(null);
const updateCanvas = (arr) => {
console.log(arr);
oldList.value = deepCopy(list.value);
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 (v.id === item.id) {
if (item.action === ACTIONS.UPDATE) {
try {
const key = item.key;
const str = /^\[/.test(item.key)
? "v" + key
: "v." + key;
eval(`${str} = item.value`);
} catch (error) {
console.error(error);
}
}
try {
const key = item.key;
const str = /^\[/.test(item.key)
? "obj" + key
: "obj." + key;
eval(`${str} = item.value`);
} 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) => {
activeId.value = id;
pingpuRef.value.updataList([
{
id: id,
action: ACTIONS.SELECT,
},
]);
const onSelect = (token) => {
activeToken.value = token;
pingpuRef.value.updataList([{ token, action: ACTIONS.SELECT }]);
};
const onMove = (id, id2) => {
const obj1 = list.value.find((v) => v.id === id);
const obj2 = list.value.find((v) => v.id === id2);
const onMove = (token1, token2) => {
const obj1 = list.value.find((v) => v.token === token1);
const obj2 = list.value.find((v) => v.token === token2);
const index1 = list.value.indexOf(obj1);
const index2 = list.value.indexOf(obj2);
if (index1 < index2) {
@@ -206,26 +199,16 @@
} else {
list.value.splice(index1, 0, list.value.splice(index2, 1)[0]);
}
const ids = list.value.map((v) => v.id);
pingpuRef.value.updataList([
{
action: ACTIONS.SORT,
ids,
},
]);
const tokens = list.value.map((v) => v.token);
pingpuRef.value.updataList([{ action: ACTIONS.SORT, tokens }]);
};
const onDelete = (id) => {
list.value = list.value.filter((v) => v.id !== id);
pingpuRef.value.updataList([
{
id: id,
action: ACTIONS.DELETE,
},
]);
const onDelete = (token) => {
list.value = list.value.filter((v) => v.token !== token);
pingpuRef.value.updataList([{ token, action: ACTIONS.DELETE }]);
};
const onAdd = () => {
const obj = {
id: Date.now().toString(),
token: Date.now().toString(),
ifSingle: false,
level2Type: "Pattern",
designType: "Library",
@@ -250,12 +233,7 @@
},
};
list.value.push(obj);
pingpuRef.value.updataList([
{
action: ACTIONS.ADD,
data: obj,
},
]);
pingpuRef.value.updataList([{ action: ACTIONS.ADD, data: obj }]);
};
watch(
() => list.value,
@@ -266,20 +244,20 @@
const updateList = () => {
const changeList = [];
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) {
const arr = findDiffProps(oldItem, newItem);
arr.forEach((item) => {
changeList.push({
...item,
id: oldItem.id,
token: oldItem.token,
action: ACTIONS.UPDATE,
key: convertDotNotationToBracket(item.key),
});
});
} else {
changeList.push({
id: oldItem.id,
token: oldItem.token,
action: ACTIONS.DELETE,
});
}

View File

@@ -1,5 +1,5 @@
<template>
<div class="pingpu" ref="el"><canvas ref="canvasRef"></canvas></div>
<div class="overall-canvas" ref="el"><canvas ref="canvasRef"></canvas></div>
</template>
<script setup>
@@ -100,23 +100,23 @@
const object = e.target;
const action = e.action;
const list = [];
const id = object.id;
const token = object.token;
if (action === "drag" || action === "rotate") {
list.push({
id: id,
token,
action: ACTIONS.UPDATE,
key: KEYS.O_TOP,
value: object.top,
});
list.push({
id: id,
token,
action: ACTIONS.UPDATE,
key: KEYS.O_LEFT,
value: object.left,
});
if (action === "rotate") {
list.push({
id: id,
token,
action: ACTIONS.UPDATE,
key: KEYS.O_ANGLE,
value: object.angle,
@@ -124,13 +124,13 @@
}
} else if (action === "scale") {
list.push({
id: id,
token,
action: ACTIONS.UPDATE,
key: KEYS.O_SCALE_X,
value: object.scaleX,
});
list.push({
id: id,
token,
action: ACTIONS.UPDATE,
key: KEYS.O_SCALE_Y,
value: object.scaleY,
@@ -140,13 +140,8 @@
};
// 对象选中
const onObjectSelected = (e) => {
const id = e.selected[0].id;
const list = [
{
id: id,
action: ACTIONS.SELECT,
},
];
const token = e.selected[0].token;
const list = [{ token, action: ACTIONS.SELECT }];
emit("change-canvas", list);
};
const urlToCanvas = (url) => {
@@ -181,7 +176,7 @@
const cheight = canvas.height;
let pattern = await setFill(item);
let rect = new fabric.Rect({
id: item.id,
token: item.token,
width: cwidth,
height: cheight,
fill: pattern,
@@ -191,7 +186,6 @@
};
const setFill = async (item) => {
if (!item) return null;
console.log(item.scale);
const cwidth = canvas.width;
const cheight = canvas.height;
let image = await urlToCanvas(item.path);
@@ -225,12 +219,13 @@
return pattern;
};
const updataList = async (list) => {
console.log(list);
const objects = canvas.getObjects();
// list.forEach((item) => {
for (let i = 0; i < list.length; 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 (!object) continue;
let value = item.value;
switch (item.key) {
case KEYS.O_TOP:
@@ -274,18 +269,17 @@
break;
}
} else if (item.action === ACTIONS.SELECT) {
canvas.setActiveObject(object);
if (object) canvas.setActiveObject(object);
} else if (item.action === ACTIONS.SORT) {
let ids = item.ids;
let tokens = item.tokens;
canvas.clear();
for (let j = 0; j < ids.length; j++) {
let id = ids[j];
let object = objects.find((o) => o.id === id);
canvas.add(object);
for (let j = 0; j < tokens.length; j++) {
let object = objects.find((o) => o.token === tokens[j]);
if (object) canvas.add(object);
}
canvas.renderAll();
} else if (item.action === ACTIONS.DELETE) {
canvas.remove(object);
if (object) canvas.remove(object);
} else if (item.action === ACTIONS.ADD) {
await addObject(item.data);
}
@@ -298,7 +292,7 @@
</script>
<style lang='less' scoped>
.pingpu {
.overall-canvas {
width: 100%;
height: 100%;
}

View File

@@ -1,14 +1,16 @@
<template>
<div class="test" ref="testRef">
<!-- <div class="test" ref="testRef">
<div class="canvas-container">
<canvas id="canvas"></canvas>
</div>
</div>
</div> -->
<overall-canvas-demo />
</template>
<script lang="ts" setup>
import { fabric } from "fabric-with-all";
import { ref, watch, onMounted } from "vue";
import OverallCanvasDemo from "./OverallCanvas/demo.vue";
const imageUrl = "/src/assets/images/canvas/xiangaofenge.png";
const testRef = ref(null);

View File

@@ -42,15 +42,14 @@
</div>
</div>
<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"
:min="20"
:max="1000"
v-model:value="systemDesignerPercentage"
:tip-formatter="formatter"
>
</a-slider>
</a-slider> -->
<a-popover
trigger="click"
destroyTooltipOnHide
@@ -67,7 +66,7 @@
/>
</template>
<div class="btn">
<i class="iconfont icon-gengduo"></i>
<SvgIcon name="overallMore" size="20" />
</div>
</a-popover>
</div>

View File

@@ -102,23 +102,36 @@
<style scoped lang="less">
.repeat-setting {
user-select: none;
width: 228px;
> .title {
line-height: 35px;
font-size: 14px;
text-align: center;
margin-top: -12px;
margin-bottom: 3px;
}
> .repeat-setting-item {
display: flex;
align-items: center;
//虚线
margin-bottom: 10px;
&:last-child {
margin-bottom: 0;
}
&.offset {
justify-content: center;
}
> .label {
min-width: 50px;
font-size: 14px;
min-width: 68px;
font-size: 12px;
}
> .angle-tool {
&:not(.offset) > div {
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>

View File

@@ -1,38 +1,73 @@
<template>
<div class="angle-tool">
<div
ref="dishRef"
class="dish"
@mousedown.stop="mousedown"
@touchmove.stop="mousedown"
>
<div class="pointer" :style="{ transform: `rotate(${angle}deg)` }">
<span></span>
<div class="angle-tool" :disabled="disabled">
<template v-if="styleType === '1'">
<div
ref="dishRef"
class="dish"
@mousedown.stop="mousedown"
@touchmove.stop="mousedown"
>
<div
class="pointer"
:style="{ transform: `rotate(${angle}deg)` }"
>
<span></span>
</div>
</div>
</div>
<div class="input">
<input type="number" v-model="angle" @input="onInput" @change="onChange" />
</div>
<div class="input">
<input
type="number"
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>
</template>
<script setup lang="ts">
import { ref, defineProps, defineEmits, watch } from "vue";
import { calculateAngle } from "@/component/Canvas/CanvasEditor/utils/helper";
import MyInput from "./MyInput.vue";
// Props
const props = defineProps({
styleType: {
type: String,
default: "1",
},
angle: {
type: Number,
default: 0,
},
disabled: {
type: Boolean,
default: false,
},
});
const emit = defineEmits(["change", "input"]);
const angle = ref(props.angle);
watch(() => props.angle, (value) => {
angle.value = value;
});
watch(
() => props.angle,
(value) => {
angle.value = value;
}
);
const dishRef = ref<HTMLDivElement>();
const mousedown = (e: MouseEvent | TouchEvent) => {
if (props.disabled) return;
const mousemove = (e: MouseEvent | TouchEvent) => {
if (!dishRef.value) return;
const { left, top, width, height } =
@@ -41,7 +76,6 @@
const centerY = top + height / 2;
const { clientX, clientY } = e?.touches?.[0] || e;
angle.value = calculateAngle(centerX, centerY, clientX, clientY, true);
console.log(angle.value)
onInput();
};
mousemove(e);
@@ -57,9 +91,10 @@
document.addEventListener("mouseup", mouseup);
document.addEventListener("touchend", mouseup);
};
const onInput = () => emit("input", angle.value);
const onInput = () => !props.disabled && emit("input", angle.value);
var changeTime: any = null;
const onChange = () => {
if (props.disabled) return;
clearTimeout(changeTime);
changeTime = setTimeout(() => emit("change", angle.value), 500);
};
@@ -80,10 +115,17 @@
display: flex;
align-items: center;
width: 100%;
--color: #000;
&[disabled="true"] {
--color: #b2b2b2;
> .dish {
cursor: not-allowed;
}
}
> .dish {
width: 24px;
height: 24px;
border: 1px solid #000;
border: 1px solid var(--color);
border-radius: 50%;
cursor: pointer;
> .pointer {
@@ -99,7 +141,7 @@
transform: translate(-50%, 0);
width: 35%;
height: 35%;
background-color: #000;
background-color: var(--color);
border-radius: 50%;
}
}
@@ -107,7 +149,7 @@
> .input {
margin-left: 5px;
font-size: 14px;
color: #000;
color: var(--color);
flex: 1;
// min-width: 45px;
// max-width: 80px;
@@ -118,5 +160,8 @@
outline: none;
}
}
> .my-input {
flex: 1;
}
}
</style>

View File

@@ -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>

View File

@@ -5,6 +5,7 @@
@change="change"
:defaultValue="defaultValue"
@dropdownVisibleChange="dropdownVisibleChange"
:disabled="disabled"
>
<a-select-option
v-for="v in list"
@@ -21,6 +22,10 @@
<script setup lang="ts">
import { ref, defineProps, defineEmits, watch } from "vue";
const props = defineProps({
disabled: {
type: Boolean,
default: false,
},
defaultValue: {
default: "",
},

View File

@@ -1,84 +1,100 @@
<template>
<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
class="dish"
@mousedown="mousedown"
@touchstart="mousedown"
ref="dishRef"
v-show="showDish"
>
<span
:style="{ top: data.top + '%', left: data.left + '%' }"
></span>
<img src="/src/assets/images/icon/xyz.png" />
<span class="ball" :style="ballStyle"></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>
<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>
</template>
<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({
top: {
type: Number,
default: 50,
},
left: {
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 data = reactive({
top: tofix(props.top),
left: tofix(props.left),
});
watch(
() => props.top,
(v) => (data.top = tofix(v))
);
// 工具的实际坐标 -100 ~ 100
const top = ref(Math.round(props.top));
const left = ref(Math.round(props.left));
// 原点的坐标 0 ~ 100
const ballStyle = computed(() => ({
top: 50 + Number(top.value) / 2 + "%",
left: 50 + Number(left.value) / 2 + "%",
}));
watch(
() => 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 mousedown = (e: MouseEvent | TouchEvent) => {
if (!dishRef.value) return;
const mousemove = (e: MouseEvent | TouchEvent) => {
if (!dishRef.value) return;
const { left, top, width, height } =
dishRef.value.getBoundingClientRect();
const rect = dishRef.value.getBoundingClientRect();
const X = e.clientX || (e as TouchEvent).touches[0].clientX;
const Y = e.clientY || (e as TouchEvent).touches[0].clientY;
var x = ((X - left) / width) * 100;
var y = ((Y - top) / height) * 100;
var x = ((X - rect.left) / rect.width) * 100;
var y = ((Y - rect.top) / rect.height) * 100;
if (x < 0) x = 0;
if (x > 100) x = 100;
if (y < 0) y = 0;
if (y > 100) y = 100;
data.left = tofix(x);
data.top = tofix(y);
left.value = Math.round((x - 50) * 2);
top.value = Math.round((y - 50) * 2);
onInput();
};
mousemove(e);
@@ -94,96 +110,125 @@
document.addEventListener("mouseup", mouseup);
document.addEventListener("touchend", mouseup);
};
const onInput = () => emit("input", { ...data });
const onInput = () => {
emit("input", { left: left.value, top: top.value });
};
var changeTime: any = null;
const onChange = () => {
clearTimeout(changeTime);
changeTime = setTimeout(() => emit("change", { ...data }), 500);
changeTime = setTimeout(() => {
emit("change", {
left: left.value,
top: top.value,
});
}, 500);
};
// var offsetTime = null;
// watch(data, (v) => {
// const obj = { ...v };
// emit("input", obj);
// clearTimeout(offsetTime);
// offsetTime = setTimeout(() => emit("change", obj), 50);
// });
// defineExpose({
// open,
// close,
// });
const lineZStyle = computed(() => ({
"--rotateZ": calculateAngle(0, 0, left.value, top.value) + "deg",
width: calculateDistance(0, 0, left.value, top.value) / 2 + "%",
}));
// 计算角度
function calculateAngle(x1: number, y1: number, x2: number, y2: number) {
const deltaX = x2 - x1;
const deltaY = y1 - y2;
let angle = Math.atan2(deltaX, deltaY) * (180 / Math.PI) - 90;
return angle;
}
// 计算距离
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>
<style scoped lang="less">
.offset-tool {
width: 125px;
height: 125px;
display: flex;
position: relative;
overflow: hidden;
--gap: 15px;
> .input {
display: flex;
align-items: center;
justify-content: center;
> * {
flex: 1;
margin-right: 12px;
&:last-child {
margin-right: 0;
}
}
}
> .dish {
margin: var(--gap) 0 0 var(--gap);
flex: 1;
border: 1px solid #000;
border-radius: 5px;
width: 135px;
height: 135px;
border: 1px solid #eaeaea;
border-radius: 4px;
cursor: pointer;
position: relative;
background-color: #fff;
> span {
background-color: #f6f6f6;
margin-top: 24px;
> * {
position: absolute;
pointer-events: none;
user-select: none;
position: absolute;
top: 0%;
left: 0%;
}
> img {
width: 15px;
height: 15px;
bottom: 4px;
right: 4px;
}
> .ball {
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 8px;
height: 8px;
background-color: #000;
width: 10px;
height: 10px;
border: 1px solid #fff;
background-color: #333;
border-radius: 50%;
box-shadow: 0px 0.68px 1.7px 0px rgba(0, 0, 0, 0.26);
}
}
> .tip {
position: absolute;
right: 4px;
bottom: 0;
font-size: 10px;
pointer-events: none;
user-select: none;
color: #666;
}
> input.left {
right: 0;
}
> input.top {
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);
> .tip {
font-size: 10px;
color: #000;
line-height: 24px;
&.x {
top: 50%;
right: 0%;
transform: translate(100%, -50%);
padding-left: 6px;
}
&.y {
top: 0%;
left: 50%;
transform: translate(-50%, -100%);
}
}
&::-webkit-slider-thumb:hover {
background: #3b77db;
transform: scale(1.1);
> .line {
border-color: #d9d9d9;
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;
}
}
}
}

View File

@@ -1,13 +1,12 @@
<template>
<div class="slider">
<div class="input-range">
<span
class="tip"
:style="{
'--progress': (value - props.min) / (props.max - props.min),
}"
>{{ props.tipFormatter(value) }}</span
>
<div class="slider" :disabled="disabled">
<div
class="input-range"
:style="{
'--progress': (value - props.min) / (props.max - props.min),
}"
>
<span class="tip">{{ props.tipFormatter(value) }}</span>
<input
type="range"
v-model="value"
@@ -16,17 +15,19 @@
:step="props.step"
@input="onInput"
@change="onChange"
:disabled="disabled"
/>
</div>
<div class="input" v-show="isInput">
<input
type="number"
<my-input
v-model="value"
:min="props.min"
:max="props.max"
:step="props.step"
@input="onInput"
@change="onChange"
:disabled="disabled"
type="number"
/>
</div>
</div>
@@ -34,7 +35,12 @@
<script setup lang="ts">
import { ref, defineProps, defineEmits, watch } from "vue";
import MyInput from "./MyInput.vue";
const props = defineProps({
disabled: {
type: Boolean,
default: false,
},
value: {
type: Number,
default: 0,
@@ -66,9 +72,10 @@
() => props.value,
(v) => (value.value = v)
);
const onInput = () => emit("input", Number(value.value));
const onInput = () => !props.disabled && emit("input", Number(value.value));
var changeTime: any = null;
const onChange = () => {
if (props.disabled) return;
clearTimeout(changeTime);
changeTime = setTimeout(() => emit("change", Number(value.value)), 500);
};
@@ -79,9 +86,10 @@
position: relative;
display: flex;
align-items: center;
--input-thumb-size: 12px;
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 {
> .input-range > .tip {
display: block;
@@ -96,21 +104,26 @@
appearance: none;
height: 5px;
border-radius: 5px;
background: rgba(0, 0, 0, 0.1); /* 更柔和的颜色 */
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-appearance: none;
appearance: none;
width: var(--input-thumb-size);
height: var(--input-thumb-size);
border-radius: 50%;
background: #4285f4; /* 蓝色滑块 */
background: var(--backcolor1); /* 蓝色滑块 */
cursor: pointer;
transition: all 0.2s;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
&::-webkit-slider-thumb:hover {
background: #3b77db;
transform: scale(1.1);
}
}

View File

@@ -640,6 +640,12 @@ export default defineComponent({
:deep(.moveable-origin){
opacity: 0;
}
:deep(.moveable-control){
border-radius: 0;
}
:deep(.moveable-rotation-control){
border-radius: 50%;
}
}
> .designOpenrtion_imgMask{
width: auto;

View File

@@ -1074,10 +1074,10 @@ export default defineComponent({
const scrollTop = textarea.scrollTop
// 2. 计算单行高度
const lineHeight = parseInt(getComputedStyle(textarea).lineHeight) || 20 // 默认20px
const lineHeight:any = parseInt(getComputedStyle(textarea).lineHeight) || 20 // 默认20px
// 3. 重置高度为1行
textarea.style.height = lineHeight + 'px'
textarea.style.height = (parseInt(lineHeight)+4) + 'px'
// 4. 计算实际需要的高度
const newHeight = Math.max(lineHeight, textarea.scrollHeight)

View File

@@ -476,9 +476,9 @@ export default defineComponent({
if(!textarea)return
const scrollTop = textarea.scrollTop;
// 2. 计算单行高度
const lineHeight = parseInt(getComputedStyle(textarea).lineHeight) || 20; // 默认20px
const lineHeight:any = parseInt(getComputedStyle(textarea).lineHeight) || 20; // 默认20px
// 3. 重置高度为1行
textarea.style.height = lineHeight + 'px';
textarea.style.height = (parseInt(lineHeight)+4) + 'px'
// 4. 计算实际需要的高度
const newHeight = Math.max(lineHeight, textarea.scrollHeight);
textarea.style.height = newHeight + 'px';