Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite
This commit is contained in:
@@ -1,12 +1,6 @@
|
|||||||
<<<<<<< HEAD
|
|
||||||
VITE_USER_NODE_ENV = 'development'
|
VITE_USER_NODE_ENV = 'development'
|
||||||
VITE_APP_BASE_URL = 'https://test.api.aida.com.hk'
|
VITE_APP_BASE_URL = 'https://test.api.aida.com.hk'
|
||||||
# VITE_APP_BASE_URL = 'https://api.aida.com.hk'
|
# VITE_APP_BASE_URL = 'https://api.aida.com.hk'
|
||||||
=======
|
|
||||||
NODE_ENV = 'development'
|
|
||||||
# VUE_APP_BASE_URL = 'https://api.aida.com.hk'
|
|
||||||
VUE_APP_BASE_URL = 'https://test.api.aida.com.hk'
|
|
||||||
>>>>>>> 5d8304ce3ece21dd3200ffffb0c76e3ef55dd213
|
|
||||||
|
|
||||||
# VITE_APP_BASE_URL = 'http://18.167.251.121:10086'
|
# VITE_APP_BASE_URL = 'http://18.167.251.121:10086'
|
||||||
# VITE_APP_BASE_URL = 'http://192.168.1.9:5567'
|
# VITE_APP_BASE_URL = 'http://192.168.1.9:5567'
|
||||||
|
|||||||
BIN
src/assets/images/icon/selected.png
Normal file
BIN
src/assets/images/icon/selected.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 582 B |
@@ -362,6 +362,11 @@ watch(
|
|||||||
setBrushSize(newSize);
|
setBrushSize(newSize);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
watch(()=>isVisible.value, (newVisible) => {
|
||||||
|
if (newVisible) {
|
||||||
|
setBrushSize(brushSize.value);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// 监听brushOpacity的变化,更新到BrushStore
|
// 监听brushOpacity的变化,更新到BrushStore
|
||||||
watch(
|
watch(
|
||||||
|
|||||||
@@ -258,6 +258,23 @@ const setClosePanel = ()=>{
|
|||||||
closePanel.value = !closePanel.value
|
closePanel.value = !closePanel.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 工具管理器和画布管理器
|
||||||
|
const toolManager = inject("toolManager");
|
||||||
|
const canvasManager = inject("canvasManager");
|
||||||
|
|
||||||
|
watch(size, (newSize, oldSize) => {
|
||||||
|
setBrushIndicatorSize(newSize)
|
||||||
|
|
||||||
|
})
|
||||||
|
// 设置笔刷指示器大小
|
||||||
|
function setBrushIndicatorSize(size) {
|
||||||
|
// 如果工具管理器存在,立即应用此更改
|
||||||
|
console.log(`=========== ${size}`,toolManager);
|
||||||
|
if (toolManager) {
|
||||||
|
toolManager.updateBrushIndicatorSize(size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 监听当前工具变化 - 参考 SelectionPanel 的实现方式
|
// 监听当前工具变化 - 参考 SelectionPanel 的实现方式
|
||||||
watch(
|
watch(
|
||||||
() => props.activeTool,
|
() => props.activeTool,
|
||||||
@@ -273,6 +290,7 @@ watch(
|
|||||||
// 检查是否有可液化的对象
|
// 检查是否有可液化的对象
|
||||||
checkAndShowPanel();
|
checkAndShowPanel();
|
||||||
}
|
}
|
||||||
|
setBrushIndicatorSize(size.value)
|
||||||
} else {
|
} else {
|
||||||
visible.value = false; // 切换到其他工具时隐藏面板
|
visible.value = false; // 切换到其他工具时隐藏面板
|
||||||
// 切换到其他工具,隐藏液化面板
|
// 切换到其他工具,隐藏液化面板
|
||||||
@@ -1641,15 +1659,17 @@ function stopPressTimer() {
|
|||||||
transform: rotate(90deg);
|
transform: rotate(90deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
> .btn{
|
> .btn{
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
> i{
|
> i{
|
||||||
font-size: 1.4rem;
|
font-size: 1.4rem;
|
||||||
display: block;
|
|
||||||
transform: rotate(270deg);
|
transform: rotate(270deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { fabric } from "fabric-with-all";
|
import { fabric } from "fabric-with-all";
|
||||||
|
import { OperationType } from "../utils/layerHelper";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 笔刷指示器
|
* 笔刷指示器
|
||||||
@@ -94,6 +95,7 @@ export class BrushIndicator {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_syncCanvasProperties() {
|
_syncCanvasProperties() {
|
||||||
|
console.log("==========","笔刷同步大小")
|
||||||
if (!this.staticCanvas || !this.canvas) return;
|
if (!this.staticCanvas || !this.canvas) return;
|
||||||
|
|
||||||
// 检查是否为笔刷或橡皮擦模式,非相关模式直接返回
|
// 检查是否为笔刷或橡皮擦模式,非相关模式直接返回
|
||||||
@@ -103,10 +105,8 @@ export class BrushIndicator {
|
|||||||
this.canvas.isDrawingMode &&
|
this.canvas.isDrawingMode &&
|
||||||
this.canvas.freeDrawingBrush &&
|
this.canvas.freeDrawingBrush &&
|
||||||
this.canvas.freeDrawingBrush.type === "eraser";
|
this.canvas.freeDrawingBrush.type === "eraser";
|
||||||
|
const isLiquifyMode = this.canvas.toolId === OperationType.LIQUIFY;// 检查是否在液化模式
|
||||||
if (!isBrushMode && !isEraserMode) {
|
if ([isBrushMode,isEraserMode,isLiquifyMode].every(v => !v)) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let hasChanges = false;
|
let hasChanges = false;
|
||||||
|
|
||||||
@@ -471,8 +471,12 @@ export class BrushIndicator {
|
|||||||
* @returns {Boolean} 是否显示
|
* @returns {Boolean} 是否显示
|
||||||
*/
|
*/
|
||||||
_shouldShowIndicator() {
|
_shouldShowIndicator() {
|
||||||
// 检查画布是否在绘图模式
|
const isDrawingMode = this.canvas.isDrawingMode;// 检查画布是否在绘图模式
|
||||||
if (!this.canvas.isDrawingMode) return false;
|
const isLiquifyMode = this.canvas.toolId === OperationType.LIQUIFY;// 检查是否在液化模式
|
||||||
|
|
||||||
|
// console.log(`笔刷指示器\n绘图模式:${isDrawingMode}\n液化模式:${isLiquifyMode}`)
|
||||||
|
// 检查画布是否在绘图模式OR液化模式
|
||||||
|
if ([isDrawingMode, isLiquifyMode].every(v => !v)) return false;
|
||||||
|
|
||||||
// 检查是否有笔刷
|
// 检查是否有笔刷
|
||||||
if (!this.canvas.freeDrawingBrush) return false;
|
if (!this.canvas.freeDrawingBrush) return false;
|
||||||
|
|||||||
@@ -373,6 +373,8 @@ export class ToolManager {
|
|||||||
// 设置工具特定的状态
|
// 设置工具特定的状态
|
||||||
const tool = this.tools[toolId];
|
const tool = this.tools[toolId];
|
||||||
if (tool && typeof tool.setup === "function") {
|
if (tool && typeof tool.setup === "function") {
|
||||||
|
console.log(`画布切换工具:${tool.name}(${toolId})`)
|
||||||
|
this.canvas.toolId = toolId;
|
||||||
tool.setup();
|
tool.setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,6 +452,7 @@ export class ToolManager {
|
|||||||
if (!this.canvas) return;
|
if (!this.canvas) return;
|
||||||
this.canvas.isDrawingMode = false;
|
this.canvas.isDrawingMode = false;
|
||||||
this.canvas.selection = true;
|
this.canvas.selection = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -750,6 +753,7 @@ export class ToolManager {
|
|||||||
detail: panelDetail,
|
detail: panelDetail,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
this._enableBrushIndicator();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1465,6 +1469,7 @@ export class ToolManager {
|
|||||||
OperationType.ERASER,
|
OperationType.ERASER,
|
||||||
OperationType.RED_BRUSH,
|
OperationType.RED_BRUSH,
|
||||||
OperationType.GREEN_BRUSH,
|
OperationType.GREEN_BRUSH,
|
||||||
|
OperationType.LIQUIFY,
|
||||||
];
|
];
|
||||||
|
|
||||||
return brushTools.includes(currentTool);
|
return brushTools.includes(currentTool);
|
||||||
|
|||||||
@@ -22,13 +22,13 @@ export class EnhancedLiquifyManager {
|
|||||||
// 是否强制使用WebGL模式
|
// 是否强制使用WebGL模式
|
||||||
forceWebGL: options.forceWebGL || false,
|
forceWebGL: options.forceWebGL || false,
|
||||||
// 网格大小
|
// 网格大小
|
||||||
gridSize: options.gridSize || 15,
|
gridSize: options.gridSize || 8,
|
||||||
// 最大变形强度
|
// 最大变形强度
|
||||||
maxStrength: options.maxStrength || 100,
|
maxStrength: options.maxStrength || 200,
|
||||||
// 平滑迭代次数
|
// 平滑迭代次数
|
||||||
smoothingIterations: options.smoothingIterations || 2,
|
smoothingIterations: options.smoothingIterations || 1,
|
||||||
// 网格弹性因子
|
// 网格弹性因子
|
||||||
relaxFactor: options.relaxFactor || 0.25,
|
relaxFactor: options.relaxFactor || 0.05,
|
||||||
// WebGL网格精度
|
// WebGL网格精度
|
||||||
meshResolution: options.meshResolution || 64,
|
meshResolution: options.meshResolution || 64,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,17 +5,20 @@
|
|||||||
export class LiquifyCPUManager {
|
export class LiquifyCPUManager {
|
||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
this.config = {
|
this.config = {
|
||||||
gridSize: options.gridSize || 16, // 稍微增大网格提高性能
|
gridSize: 8, // 稍微增大网格提高性能
|
||||||
maxStrength: options.maxStrength || 200, // 适度降低最大强度
|
maxStrength: 200, // 适度降低最大强度
|
||||||
smoothingIterations: options.smoothingIterations || 1, // 增加平滑处理
|
smoothingIterations: 1, // 增加平滑处理
|
||||||
relaxFactor: options.relaxFactor || 0.1, // 适度松弛
|
relaxFactor: 0.05, // 适度松弛
|
||||||
|
sharpenAmount: 0.3, // 添加锐化强度参数
|
||||||
|
...options,
|
||||||
};
|
};
|
||||||
|
console.log("CPU版本的液化管理器config",this.config);
|
||||||
|
|
||||||
this.params = {
|
this.params = {
|
||||||
size: 80, // 增大默认尺寸
|
size: 60, // 增大默认尺寸
|
||||||
pressure: 0.8, // 增大默认压力
|
pressure: 0.6, // 增大默认压力
|
||||||
distortion: 0,
|
distortion: 0,
|
||||||
power: 0.8, // 增大默认动力
|
power: 0.7, // 增大默认动力
|
||||||
};
|
};
|
||||||
|
|
||||||
this.modes = {
|
this.modes = {
|
||||||
@@ -132,6 +135,10 @@ export class LiquifyCPUManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setParam(param, value) {
|
setParam(param, value) {
|
||||||
|
if (param === 'sharpness') {
|
||||||
|
this.config.sharpenAmount = Math.max(0, Math.min(1, value));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (param in this.params) {
|
if (param in this.params) {
|
||||||
this.params[param] = value;
|
this.params[param] = value;
|
||||||
return true;
|
return true;
|
||||||
@@ -140,15 +147,19 @@ export class LiquifyCPUManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getParams() {
|
getParams() {
|
||||||
return { ...this.params };
|
return { ...this.params, sharpness: this.config.sharpenAmount, };
|
||||||
|
}
|
||||||
|
// 添加清晰度控制方法
|
||||||
|
setSharpness(amount) {
|
||||||
|
this.config.sharpenAmount = Math.max(0, Math.min(1, amount));
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
resetParams() {
|
resetParams() {
|
||||||
this.params = {
|
this.params = {
|
||||||
size: 80, // 增大默认尺寸
|
size: 60, // 增大默认尺寸
|
||||||
pressure: 0.8, // 增大默认压力
|
pressure: 0.6, // 增大默认压力
|
||||||
distortion: 0,
|
distortion: 0,
|
||||||
power: 0.8, // 增大默认动力
|
power: 0.7, // 增大默认动力
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -645,53 +656,69 @@ export class LiquifyCPUManager {
|
|||||||
* @returns {Array|null} RGBA颜色值数组或null
|
* @returns {Array|null} RGBA颜色值数组或null
|
||||||
*/
|
*/
|
||||||
_bilinearSample(data, width, height, x, y) {
|
_bilinearSample(data, width, height, x, y) {
|
||||||
if (x < 0 || x >= width - 1 || y < 0 || y >= height - 1) {
|
return this._bicubicInterpolate(data, width, height, x, y);
|
||||||
return null;
|
}
|
||||||
|
/**
|
||||||
|
* 双三次插值实现 - 确保正确处理Alpha通道
|
||||||
|
* @param {Uint8ClampedArray} data 图像数据
|
||||||
|
* @param {number} width 图像宽度
|
||||||
|
* @param {number} height 图像高度
|
||||||
|
* @param {number} x X坐标
|
||||||
|
* @param {number} y Y坐标
|
||||||
|
* @returns {Array|null} RGBA颜色值数组或null
|
||||||
|
*/
|
||||||
|
_bicubicInterpolate(data, width, height, x, y) {
|
||||||
|
// 获取周围16个像素点
|
||||||
|
const x1 = Math.floor(x) - 1;
|
||||||
|
const y1 = Math.floor(y) - 1;
|
||||||
|
|
||||||
|
// 创建16个采样点的颜色数组
|
||||||
|
const pixels = [];
|
||||||
|
for (let ky = 0; ky < 4; ky++) {
|
||||||
|
for (let kx = 0; kx < 4; kx++) {
|
||||||
|
const px = Math.max(0, Math.min(width - 1, x1 + kx));
|
||||||
|
const py = Math.max(0, Math.min(height - 1, y1 + ky));
|
||||||
|
const idx = (py * width + px) * 4;
|
||||||
|
pixels[ky * 4 + kx] = [data[idx], data[idx + 1], data[idx + 2], data[idx + 3]];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const x1 = Math.floor(x);
|
// 计算小数部分
|
||||||
const y1 = Math.floor(y);
|
const fx = x - (x1 + 1);
|
||||||
const x2 = x1 + 1;
|
const fy = y - (y1 + 1);
|
||||||
const y2 = y1 + 1;
|
|
||||||
|
|
||||||
const fx = x - x1;
|
// 计算行插值
|
||||||
const fy = y - y1;
|
const row0 = this._cubicInterpolateRow(pixels[0], pixels[1], pixels[2], pixels[3], fx);
|
||||||
|
const row1 = this._cubicInterpolateRow(pixels[4], pixels[5], pixels[6], pixels[7], fx);
|
||||||
|
const row2 = this._cubicInterpolateRow(pixels[8], pixels[9], pixels[10], pixels[11], fx);
|
||||||
|
const row3 = this._cubicInterpolateRow(pixels[12], pixels[13], pixels[14], pixels[15], fx);
|
||||||
|
|
||||||
const getPixel = (px, py) => {
|
// 计算最终结果
|
||||||
const idx = (py * width + px) * 4;
|
return this._cubicInterpolateRow(row0, row1, row2, row3, fy);
|
||||||
return [data[idx], data[idx + 1], data[idx + 2], data[idx + 3]];
|
}
|
||||||
};
|
// 三次插值辅助方法 - 单行插值
|
||||||
|
_cubicInterpolateRow(p0, p1, p2, p3, t) {
|
||||||
|
// 使用三次多项式插值公式
|
||||||
|
const a = [0, 0, 0, 0];
|
||||||
|
const b = [0, 0, 0, 0];
|
||||||
|
const c = [0, 0, 0, 0];
|
||||||
|
|
||||||
const p1 = getPixel(x1, y1);
|
// 为每个通道计算插值系数
|
||||||
const p2 = getPixel(x2, y1);
|
for (let i = 0; i < 4; i++) {
|
||||||
const p3 = getPixel(x1, y2);
|
a[i] = -0.5 * p0[i] + 1.5 * p1[i] - 1.5 * p2[i] + 0.5 * p3[i];
|
||||||
const p4 = getPixel(x2, y2);
|
b[i] = p0[i] - 2.5 * p1[i] + 2 * p2[i] - 0.5 * p3[i];
|
||||||
|
c[i] = -0.5 * p0[i] + 0.5 * p2[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用三次多项式
|
||||||
|
const t2 = t * t;
|
||||||
|
const t3 = t * t2;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
Math.round(
|
Math.round(a[0] * t3 + b[0] * t2 + c[0] * t + p1[0]),
|
||||||
(1 - fx) * (1 - fy) * p1[0] +
|
Math.round(a[1] * t3 + b[1] * t2 + c[1] * t + p1[1]),
|
||||||
fx * (1 - fy) * p2[0] +
|
Math.round(a[2] * t3 + b[2] * t2 + c[2] * t + p1[2]),
|
||||||
(1 - fx) * fy * p3[0] +
|
Math.round(a[3] * t3 + b[3] * t2 + c[3] * t + p1[3]) // 确保Alpha通道也被正确插值
|
||||||
fx * fy * p4[0]
|
|
||||||
),
|
|
||||||
Math.round(
|
|
||||||
(1 - fx) * (1 - fy) * p1[1] +
|
|
||||||
fx * (1 - fy) * p2[1] +
|
|
||||||
(1 - fx) * fy * p3[1] +
|
|
||||||
fx * fy * p4[1]
|
|
||||||
),
|
|
||||||
Math.round(
|
|
||||||
(1 - fx) * (1 - fy) * p1[2] +
|
|
||||||
fx * (1 - fy) * p2[2] +
|
|
||||||
(1 - fx) * fy * p3[2] +
|
|
||||||
fx * fy * p4[2]
|
|
||||||
),
|
|
||||||
Math.round(
|
|
||||||
(1 - fx) * (1 - fy) * p1[3] +
|
|
||||||
fx * (1 - fy) * p2[3] +
|
|
||||||
(1 - fx) * fy * p3[3] +
|
|
||||||
fx * fy * p4[3]
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -928,31 +955,40 @@ export class LiquifyCPUManager {
|
|||||||
const srcData = this.originalImageData.data;
|
const srcData = this.originalImageData.data;
|
||||||
const dstData = result.data;
|
const dstData = result.data;
|
||||||
|
|
||||||
// 性能优化:使用步长采样减少计算量
|
// 移除步长采样,始终使用1:1采样
|
||||||
const step = width > 1000 || height > 1000 ? 2 : 1;
|
for (let y = 0; y < height; y++) {
|
||||||
|
for (let x = 0; x < width; x++) {
|
||||||
for (let y = 0; y < height; y += step) {
|
|
||||||
for (let x = 0; x < width; x += step) {
|
|
||||||
const srcPos = this._mapPointBack(x, y);
|
const srcPos = this._mapPointBack(x, y);
|
||||||
|
const dstIdx = (y * width + x) * 4;
|
||||||
|
|
||||||
if (srcPos.x >= 0 && srcPos.x < width && srcPos.y >= 0 && srcPos.y < height) {
|
if (srcPos.x >= 0 && srcPos.x < width && srcPos.y >= 0 && srcPos.y < height) {
|
||||||
const color = this._bilinearInterpolate(srcData, width, height, srcPos.x, srcPos.y);
|
// 使用双三次插值获取颜色
|
||||||
|
const color = this._bicubicInterpolate(srcData, width, height, srcPos.x, srcPos.y);
|
||||||
// 如果使用步长采样,需要填充相邻像素
|
|
||||||
for (let dy = 0; dy < step && y + dy < height; dy++) {
|
|
||||||
for (let dx = 0; dx < step && x + dx < width; dx++) {
|
|
||||||
const dstIdx = ((y + dy) * width + (x + dx)) * 4;
|
|
||||||
dstData[dstIdx] = color[0];
|
dstData[dstIdx] = color[0];
|
||||||
dstData[dstIdx + 1] = color[1];
|
dstData[dstIdx + 1] = color[1];
|
||||||
dstData[dstIdx + 2] = color[2];
|
dstData[dstIdx + 2] = color[2];
|
||||||
dstData[dstIdx + 3] = color[3];
|
dstData[dstIdx + 3] = color[3]; // 确保Alpha通道值被正确设置
|
||||||
}
|
} else {
|
||||||
}
|
// 对于边界外的点,使用最近的有效像素或保持原Alpha通道
|
||||||
|
// 这里我们确保Alpha通道不为0,防止出现透明区域
|
||||||
|
const nearestX = Math.max(0, Math.min(width - 1, Math.round(srcPos.x)));
|
||||||
|
const nearestY = Math.max(0, Math.min(height - 1, Math.round(srcPos.y)));
|
||||||
|
const nearestIdx = (nearestY * width + nearestX) * 4;
|
||||||
|
|
||||||
|
// 复制最近像素的颜色,但保持Alpha通道为不透明
|
||||||
|
dstData[dstIdx] = srcData[nearestIdx];
|
||||||
|
dstData[dstIdx + 1] = srcData[nearestIdx + 1];
|
||||||
|
dstData[dstIdx + 2] = srcData[nearestIdx + 2];
|
||||||
|
dstData[dstIdx + 3] = 255; // 强制设置为完全不透明
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.currentImageData = result;
|
this.currentImageData = result;
|
||||||
|
// 添加锐化处理
|
||||||
|
if (this.config.sharpenAmount > 0) {
|
||||||
|
this.currentImageData = this._sharpenImage(this.currentImageData, this.config.sharpenAmount);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1066,21 +1102,122 @@ export class LiquifyCPUManager {
|
|||||||
const originalX = x1 * gridSize + fx * gridSize;
|
const originalX = x1 * gridSize + fx * gridSize;
|
||||||
const originalY = y1 * gridSize + fy * gridSize;
|
const originalY = y1 * gridSize + fy * gridSize;
|
||||||
|
|
||||||
// 计算偏移量并应用反向映射
|
// 检查是否接近边缘,如果是则减少偏移量
|
||||||
const offsetX = deformedX - originalX;
|
const isNearEdge = this._isNearEdge(originalX, originalY);
|
||||||
const offsetY = deformedY - originalY;
|
const edgeProtectionFactor = isNearEdge ? 0.2 : 1.0; // 边缘区域减少变形量
|
||||||
|
|
||||||
// 限制偏移量,防止过度扭曲
|
// 计算偏移量并应用反向映射
|
||||||
const maxOffset = gridSize * 0.5;
|
const offsetX = (deformedX - originalX) * edgeProtectionFactor;
|
||||||
const limitedOffsetX = Math.max(-maxOffset, Math.min(maxOffset, offsetX));
|
const offsetY = (deformedY - originalY) * edgeProtectionFactor;
|
||||||
const limitedOffsetY = Math.max(-maxOffset, Math.min(maxOffset, offsetY));
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
x: Math.max(0, Math.min(this.mesh.width - 1, x - limitedOffsetX)),
|
x: Math.max(0, Math.min(this.mesh.width - 1, x - offsetX)),
|
||||||
y: Math.max(0, Math.min(this.mesh.height - 1, y - limitedOffsetY)),
|
y: Math.max(0, Math.min(this.mesh.height - 1, y - offsetY)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// 边缘检测辅助方法
|
||||||
|
_isNearEdge(x, y, threshold = 10) {
|
||||||
|
if (!this.originalImageData) return false;
|
||||||
|
|
||||||
|
const data = this.originalImageData.data;
|
||||||
|
const width = this.originalImageData.width;
|
||||||
|
const height = this.originalImageData.height;
|
||||||
|
|
||||||
|
// 检查像素是否在边缘
|
||||||
|
if (x <= 0 || x >= width - 1 || y <= 0 || y >= height - 1) return true;
|
||||||
|
|
||||||
|
// 简单的Sobel边缘检测
|
||||||
|
const getPixelBrightness = (px, py) => {
|
||||||
|
const idx = (py * width + px) * 4;
|
||||||
|
return (data[idx] + data[idx + 1] + data[idx + 2]) / 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
const kernelX = [
|
||||||
|
[-1, 0, 1],
|
||||||
|
[-2, 0, 2],
|
||||||
|
[-1, 0, 1]
|
||||||
|
];
|
||||||
|
|
||||||
|
const kernelY = [
|
||||||
|
[-1, -2, -1],
|
||||||
|
[0, 0, 0],
|
||||||
|
[1, 2, 1]
|
||||||
|
];
|
||||||
|
|
||||||
|
let gradientX = 0;
|
||||||
|
let gradientY = 0;
|
||||||
|
|
||||||
|
for (let ky = -1; ky <= 1; ky++) {
|
||||||
|
for (let kx = -1; kx <= 1; kx++) {
|
||||||
|
const px = Math.min(Math.max(0, x + kx), width - 1);
|
||||||
|
const py = Math.min(Math.max(0, y + ky), height - 1);
|
||||||
|
const brightness = getPixelBrightness(px, py);
|
||||||
|
gradientX += brightness * kernelX[ky + 1][kx + 1];
|
||||||
|
gradientY += brightness * kernelY[ky + 1][kx + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const gradientMagnitude = Math.sqrt(gradientX * gradientX + gradientY * gradientY);
|
||||||
|
return gradientMagnitude > threshold;
|
||||||
|
}
|
||||||
|
// 图像锐化方法
|
||||||
|
_sharpenImage(imageData, amount = 0.5) {
|
||||||
|
if (!imageData) return imageData;
|
||||||
|
|
||||||
|
const data = new Uint8ClampedArray(imageData.data);
|
||||||
|
const width = imageData.width;
|
||||||
|
const height = imageData.height;
|
||||||
|
const result = new ImageData(width, height);
|
||||||
|
const dstData = result.data;
|
||||||
|
|
||||||
|
// 锐化核 - 中心为5,周围为-1
|
||||||
|
const kernel = [
|
||||||
|
[0, -1, 0],
|
||||||
|
[-1, 5, -1],
|
||||||
|
[0, -1, 0]
|
||||||
|
];
|
||||||
|
|
||||||
|
for (let y = 0; y < height; y++) {
|
||||||
|
for (let x = 0; x < width; x++) {
|
||||||
|
// 边缘像素不处理
|
||||||
|
if (x === 0 || x === width - 1 || y === 0 || y === height - 1) {
|
||||||
|
const idx = (y * width + x) * 4;
|
||||||
|
for (let c = 0; c < 4; c++) {
|
||||||
|
dstData[idx + c] = data[idx + c];
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sharpened = [0, 0, 0, 0];
|
||||||
|
|
||||||
|
// 应用锐化核
|
||||||
|
for (let ky = -1; ky <= 1; ky++) {
|
||||||
|
for (let kx = -1; kx <= 1; kx++) {
|
||||||
|
const px = x + kx;
|
||||||
|
const py = y + ky;
|
||||||
|
const idx = (py * width + px) * 4;
|
||||||
|
const weight = kernel[ky + 1][kx + 1];
|
||||||
|
|
||||||
|
for (let c = 0; c < 3; c++) { // 只锐化RGB通道
|
||||||
|
sharpened[c] += data[idx + c] * weight;
|
||||||
|
}
|
||||||
|
sharpened[3] = data[idx + 3]; // 保持Alpha通道不变
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用锐化强度并裁剪值范围
|
||||||
|
const idx = (y * width + x) * 4;
|
||||||
|
for (let c = 0; c < 3; c++) {
|
||||||
|
const original = data[idx + c];
|
||||||
|
const diff = sharpened[c] - original;
|
||||||
|
dstData[idx + c] = Math.max(0, Math.min(255, original + diff * amount));
|
||||||
|
}
|
||||||
|
dstData[idx + 3] = sharpened[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
_bilinearInterpolate(data, width, height, x, y) {
|
_bilinearInterpolate(data, width, height, x, y) {
|
||||||
const x1 = Math.floor(x);
|
const x1 = Math.floor(x);
|
||||||
const y1 = Math.floor(y);
|
const y1 = Math.floor(y);
|
||||||
@@ -1253,8 +1390,9 @@ export class LiquifyCPUManager {
|
|||||||
// 应用变形
|
// 应用变形
|
||||||
this._applyDeformation(x, y, radius, finalStrength, mode, this.params.distortion);
|
this._applyDeformation(x, y, radius, finalStrength, mode, this.params.distortion);
|
||||||
|
|
||||||
// 平滑处理
|
// 有条件地应用平滑处理,仅在特定模式下应用
|
||||||
if (this.config.smoothingIterations > 0) {
|
const smoothingModes = [this.modes.CRYSTAL, this.modes.EDGE];
|
||||||
|
if (smoothingModes.includes(mode) && this.config.smoothingIterations > 0) {
|
||||||
this._smoothMesh();
|
this._smoothMesh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ export class LiquifyManager {
|
|||||||
// 创建增强版液化管理器实例
|
// 创建增强版液化管理器实例
|
||||||
this.enhancedManager = new EnhancedLiquifyManager({
|
this.enhancedManager = new EnhancedLiquifyManager({
|
||||||
// 配置选项
|
// 配置选项
|
||||||
gridSize: options.gridSize || 15,
|
gridSize: options.gridSize || 8,
|
||||||
maxStrength: options.maxStrength || 100,
|
maxStrength: options.maxStrength || 200,
|
||||||
smoothingIterations: options.smoothingIterations || 2,
|
smoothingIterations: options.smoothingIterations || 1,
|
||||||
relaxFactor: options.relaxFactor || 0.25,
|
relaxFactor: options.relaxFactor || 0.05,
|
||||||
meshResolution: options.meshResolution || 64,
|
meshResolution: options.meshResolution || 64,
|
||||||
// 根据环境选择合适的渲染模式
|
// 根据环境选择合适的渲染模式
|
||||||
forceCPU: true, // 默认不强制使用CPU
|
forceCPU: true, // 默认不强制使用CPU
|
||||||
|
|||||||
@@ -56,9 +56,14 @@
|
|||||||
<span class="image-name">{{ item.name || "未命名" }}</span>
|
<span class="image-name">{{ item.name || "未命名" }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="image-select" v-show="selectList.includes(item.url)">
|
<!-- <div class="image-select" v-show="selectList.includes(item.url)">
|
||||||
<i class="fi fi-sr-check-circle"></i>
|
<i class="fi fi-sr-check-circle"></i>
|
||||||
</div>
|
</div> -->
|
||||||
|
<img
|
||||||
|
src="@/assets/images/icon/selected.png"
|
||||||
|
class="image-select"
|
||||||
|
v-show="selectList.includes(item.url)"
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -16,14 +16,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="detailText">{{$t('DesignPrintOperation.Colorfromimage')}}</div>
|
<div class="detailText">{{$t('DesignPrintOperation.Colorfromimage')}}</div>
|
||||||
<div class="uploadImage flex flex-align-center flex-justify-around">
|
<div class="uploadImage flex flex-align-center flex-justify-center">
|
||||||
<div class="upload-container flex flex-column flex-align-center" :class="{'hide': !showLibrary}">
|
<div class="upload-container" :class="{'hide': !showLibrary}">
|
||||||
<upload ref="uploadRef" @selectUplpadColor="selectUplpadColor" @selectFile="showLibrary = false" @deleteColor="showLibrary = true"></upload>
|
<upload ref="uploadRef" @selectUplpadColor="selectUplpadColor" @selectFile="showLibrary = false" @deleteColor="showLibrary = true"></upload>
|
||||||
<div class="upload-text" v-show="showLibrary"> {{ $t('LibraryPage.Upload') }} </div>
|
<div class="upload-text" v-show="showLibrary"> {{ $t('LibraryPage.Upload') }} </div>
|
||||||
</div>
|
</div>
|
||||||
<div class="upload-container flex flex-column flex-align-center" v-show="showLibrary">
|
<div class="upload-container " v-show="showLibrary">
|
||||||
<!-- <i class="fi fi-rr-followcollection"></i> -->
|
<!-- <i class="fi fi-rr-followcollection"></i> -->
|
||||||
<SvgIcon name="CLibrary" size="40" @click="handleOpenLibrary" />
|
<SvgIcon name="CLibrary" class="svg-btn" size="20" @click="handleOpenLibrary" />
|
||||||
<div class="upload-text"> {{ $t('LibraryPage.library') }} </div>
|
<div class="upload-text"> {{ $t('LibraryPage.library') }} </div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -268,9 +268,7 @@ export default defineComponent({
|
|||||||
selectImages.value.init()
|
selectImages.value.init()
|
||||||
}
|
}
|
||||||
const handleImageSelect = (item:any)=>{
|
const handleImageSelect = (item:any)=>{
|
||||||
console.log('item',item)
|
|
||||||
UrlToFile(item.url,item.name).then((file:any)=>{
|
UrlToFile(item.url,item.name).then((file:any)=>{
|
||||||
console.log('file',file)
|
|
||||||
// 构造符合 fileUploadChange 期望的数据结构
|
// 构造符合 fileUploadChange 期望的数据结构
|
||||||
const fileData = {
|
const fileData = {
|
||||||
file: {
|
file: {
|
||||||
@@ -280,7 +278,6 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
uploadRef.value.fileUploadChange(fileData)
|
uploadRef.value.fileUploadChange(fileData)
|
||||||
})
|
})
|
||||||
// uploadRef.value.selectColor(item)
|
|
||||||
}
|
}
|
||||||
const handleShowListChange=(val:boolean)=>{
|
const handleShowListChange=(val:boolean)=>{
|
||||||
console.log('val',val)
|
console.log('val',val)
|
||||||
@@ -451,12 +448,17 @@ export default defineComponent({
|
|||||||
height: 10rem;
|
height: 10rem;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-radius: .5rem;
|
border-radius: .5rem;
|
||||||
|
column-gap: 2rem;
|
||||||
.upload-container{
|
.upload-container{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
align-items: center;
|
||||||
background-color: #EDEDED;
|
background-color: #EDEDED;
|
||||||
padding: 1rem 2rem;
|
|
||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
width: 8rem;
|
width: 7rem;
|
||||||
height: 8rem;
|
height: 7rem;
|
||||||
|
// row-gap: 1rem;
|
||||||
&.hide{
|
&.hide{
|
||||||
width: initial;
|
width: initial;
|
||||||
height: initial;
|
height: initial;
|
||||||
@@ -466,6 +468,11 @@ export default defineComponent({
|
|||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
padding-left: 1rem;
|
padding-left: 1rem;
|
||||||
}
|
}
|
||||||
|
.svg-btn{
|
||||||
|
cursor: pointer;
|
||||||
|
width: initial;
|
||||||
|
height: initial;
|
||||||
|
}
|
||||||
:deep(.ant-upload){
|
:deep(.ant-upload){
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,8 +181,8 @@ export default defineComponent({
|
|||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.upload{
|
.upload{
|
||||||
// width: 34rem;
|
// width: 34rem;
|
||||||
width: 100%;
|
// width: 100%;
|
||||||
height: 100%;
|
// height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
:deep(.ant-upload-picture-card-wrapper){
|
:deep(.ant-upload-picture-card-wrapper){
|
||||||
@@ -204,7 +204,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
.upload_tip_block{
|
.upload_tip_block{
|
||||||
i{
|
i{
|
||||||
font-size: 4rem;
|
font-size: 2rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,9 +38,10 @@
|
|||||||
<span class="image-name">{{ item.name || '未命名' }}</span>
|
<span class="image-name">{{ item.name || '未命名' }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="image-select" v-show="selectList.includes(item.url)">
|
<img class="selected-icon image-select" src="@/assets/images/icon/selected.png" v-show="selectList.includes(item.url)">
|
||||||
|
<!-- <div class="" v-show="selectList.includes(item.url)">
|
||||||
<i class="fi fi-sr-check-circle"></i>
|
<i class="fi fi-sr-check-circle"></i>
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -242,8 +243,8 @@ const resetAndLoad = (category = selectedCategory.value) => {
|
|||||||
list.value = []
|
list.value = []
|
||||||
hasMore.value = true
|
hasMore.value = true
|
||||||
currentPage.value = 0
|
currentPage.value = 0
|
||||||
console.log('默认选择----',getDefaultCategory())
|
// console.log('默认选择----',getDefaultCategory())
|
||||||
selectedCategory.value = getDefaultCategory()
|
selectedCategory.value =category || getDefaultCategory()
|
||||||
fetchImages(1, category, true)
|
fetchImages(1, category, true)
|
||||||
|
|
||||||
// 检查是否需要自动加载更多数据
|
// 检查是否需要自动加载更多数据
|
||||||
@@ -280,6 +281,7 @@ const handleImageClick = item => {
|
|||||||
|
|
||||||
// 处理分类切换
|
// 处理分类切换
|
||||||
const handleChangeCategory = category => {
|
const handleChangeCategory = category => {
|
||||||
|
// console.log('handleChangeCategory',category)
|
||||||
selectedCategory.value = category
|
selectedCategory.value = category
|
||||||
|
|
||||||
// 如果提供了API,则重新加载数据
|
// 如果提供了API,则重新加载数据
|
||||||
@@ -508,8 +510,9 @@ defineExpose({
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
min-height: 20rem;
|
min-height: 22rem;
|
||||||
max-height: 50rem;
|
max-height: 50rem;
|
||||||
|
padding-bottom: 2rem;
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
@media screen and (max-width: 768px) {
|
||||||
grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
|
||||||
@@ -574,12 +577,16 @@ defineExpose({
|
|||||||
|
|
||||||
.image-select {
|
.image-select {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: -1.25rem;
|
||||||
right: 0;
|
right: -1.25rem;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
transform: translate(50%, 50%);
|
// transform: translate(50%, 50%);
|
||||||
i {
|
// i {
|
||||||
font-size: 2.5rem;
|
// font-size: 2.5rem;
|
||||||
|
// }
|
||||||
|
&.selected-icon{
|
||||||
|
width:2.5rem;
|
||||||
|
height: 2.5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="table_search_bar flex flex-justify-between flex-align-center">
|
<div class="table_search_bar flex flex-align-center flex-justify-between">
|
||||||
<div class="search_preset flex flex-1">
|
<div class="search_preset flex ">
|
||||||
<div
|
<div
|
||||||
class="preset_item gallery_btn white"
|
class="preset_item gallery_btn white"
|
||||||
v-for="item in buttonList"
|
v-for="item in buttonList"
|
||||||
@@ -11,15 +11,15 @@
|
|||||||
{{ item.label }}
|
{{ item.label }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="search_input flex flex-align-center">
|
<div class="search_input flex flex-align-center" :style="{ width: inputWidth }">
|
||||||
<input
|
<input
|
||||||
class="search_input_inner flex-1"
|
class="search_input_inner"
|
||||||
v-model="searchParams.searchText"
|
v-model="searchParams.searchText"
|
||||||
:bordered="false"
|
:bordered="false"
|
||||||
@keydown.enter="handleSearch"
|
@keydown.enter="handleSearch"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
/>
|
/>
|
||||||
<SearchOutlined @click="handleSearch" />
|
<SearchOutlined class="search_input_icon" @click="handleSearch" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -36,6 +36,7 @@ interface ButtonItem {
|
|||||||
interface Props {
|
interface Props {
|
||||||
buttonList: ButtonItem[]
|
buttonList: ButtonItem[]
|
||||||
placeholder?: string
|
placeholder?: string
|
||||||
|
inputWidth?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SearchParams {
|
interface SearchParams {
|
||||||
@@ -91,11 +92,13 @@ const handleSearch = () => {
|
|||||||
line-height: 4rem;
|
line-height: 4rem;
|
||||||
min-width: 10rem;
|
min-width: 10rem;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
|
border-width: 0.1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.search_input {
|
.search_input {
|
||||||
height: 4rem;
|
height: 4rem;
|
||||||
|
width: 23rem; // 默认宽度
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border: 0.1rem solid #000;
|
border: 0.1rem solid #000;
|
||||||
border-radius: 43rem;
|
border-radius: 43rem;
|
||||||
@@ -106,6 +109,10 @@ const handleSearch = () => {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
padding-left: 3rem;
|
padding-left: 3rem;
|
||||||
border-radius: 4rem;
|
border-radius: 4rem;
|
||||||
|
width: calc(100% - 2rem);
|
||||||
|
}
|
||||||
|
.search_input_icon {
|
||||||
|
font-size: 2rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -403,6 +403,10 @@ export default defineComponent({
|
|||||||
homeMainData.openType = Object.keys(query)[0]
|
homeMainData.openType = Object.keys(query)[0]
|
||||||
homeMainData.openTypeChild = query[Object.keys(query)[0]]
|
homeMainData.openTypeChild = query[Object.keys(query)[0]]
|
||||||
}
|
}
|
||||||
|
if(homeMainData.openType === 'history' && route.path !== '/home/history'){
|
||||||
|
homeMainData.openTypeChild = ''
|
||||||
|
homeMainData.openType = ''
|
||||||
|
}
|
||||||
if((query?.id || query?.history) && !await getIdExistToHistory()){
|
if((query?.id || query?.history) && !await getIdExistToHistory()){
|
||||||
router.push('/home')
|
router.push('/home')
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -30,20 +30,14 @@
|
|||||||
<div class="operate_list" v-if="column?.Operations">
|
<div class="operate_list" v-if="column?.Operations">
|
||||||
<div
|
<div
|
||||||
class="operate_item"
|
class="operate_item"
|
||||||
v-if="
|
:class="{ 'operate_item_hidden': !(record.process ==='SERIES_DESIGN' || record.process ==='SINGLE_DESIGN') }"
|
||||||
record.process ==='SERIES_DESIGN' ||
|
|
||||||
record.process ==='SINGLE_DESIGN'
|
|
||||||
"
|
|
||||||
@click="turnToDetail(record)"
|
@click="turnToDetail(record)"
|
||||||
>
|
>
|
||||||
{{ $t('HistoryPage.Detail') }}
|
{{ $t('HistoryPage.Detail') }}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="operate_item"
|
class="operate_item"
|
||||||
v-if="
|
:class="{ 'operate_item_hidden': !(record.process ==='SERIES_DESIGN' || record.process ==='SINGLE_DESIGN') }"
|
||||||
record.process ==='SERIES_DESIGN' ||
|
|
||||||
record.process ==='SINGLE_DESIGN'
|
|
||||||
"
|
|
||||||
@click="renameCollection(record, index)"
|
@click="renameCollection(record, index)"
|
||||||
>
|
>
|
||||||
{{ $t('LibraryPage.Rename') }}
|
{{ $t('LibraryPage.Rename') }}
|
||||||
@@ -725,6 +719,11 @@ export default defineComponent({
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
color: #007ee5;
|
color: #007ee5;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
&.operate_item_hidden {
|
||||||
|
visibility: hidden;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user