@@ -57,7 +57,7 @@
{
+ this.closeFloatImage(true);
+ });
},
- computed:{
-
+ destroyed() {
+ // 组件销毁(切换路由)不移除浮窗,保留悬浮效果
},
methods: {
// 获取水单列表
async getReceiptList() {
try {
this.loading = true;
-
- // if (!orderId) {
- // this.$message.warning('缺少订单ID,无法获取水单数据')
- // this.loading = false
- // return
- // }
-
- // 2. 调用接口获取水单列表
const res = await getReceiptDetailList({
current: 1,
size: 100000,
orderId: this.orderId,
});
-
- // 3. 处理接口返回数据
if (res.data.code === 200) {
this.receiptList = res.data.data.records;
} else {
@@ -152,18 +144,15 @@ export default {
this.loading = false;
}
},
- // 获取水单列表
+ // 更新水单状态
async handleUpdateStatus() {
try {
- const res = await updateStatus({
- orderId: this.orderId,
- });
+ await updateStatus({ orderId: this.orderId });
} catch (err) {}
},
- // 新增:删除水单逻辑
+ // 删除水单
async handleDelete(waterBillId) {
try {
- // 1. 二次确认删除操作
await this.$confirm(
"确定要删除此水单吗?删除后将无法恢复!",
"删除确认",
@@ -174,34 +163,282 @@ export default {
dangerMode: true,
}
);
- // 2. 调用删除接口
const res = await deleteWaterBill({ id: waterBillId });
- // 3. 处理删除结果
if (res.data.code === 200) {
this.$message.success("水单删除成功");
- // 4. 重新加载水单列表
this.getReceiptList();
} else {
this.$message.error("删除失败:" + (res.data.msg || "接口返回异常"));
}
} catch (err) {
- // 取消删除时不报错
if (err !== "cancel") {
console.error("删除水单失败:", err);
this.$message.error("删除水单异常,请重试");
}
}
},
- // 放大查看图片
- previewImage(imgUrl) {
+ // 打开图片浮窗(核心:悬浮+缩放+最大化)
+ openFloatImage(imgUrl, imgName = "水单图片") {
if (!imgUrl) {
this.$message.warning("暂无水单图片可查看");
return;
}
- const imageDom = document.querySelector(`[src="${imgUrl}"]`);
- if (imageDom) {
- imageDom.click();
+ // 重置缩放比例和最大化状态
+ this.imgScale = 1;
+ this.isWindowMax = false;
+ // 防重复创建:如果浮窗已存在,直接更新图片并显示
+ if (this.floatWindow) {
+ this.floatWindow.style.display = "block";
+ const floatImg = this.floatWindow.querySelector(".float-img");
+ floatImg.src = imgUrl;
+ floatImg.style.transform = `scale(1)`; // 重置图片缩放
+ this.floatWindow.querySelector(".float-title").innerText = imgName;
+ return;
}
+
+ // 1. 创建浮窗外层容器(自适应宽度,无遮罩)
+ const floatBox = document.createElement("div");
+ floatBox.className = "water-bill-float-window";
+ // 存储原始样式,用于最大化还原
+ this.originalWindowStyle = {
+ width: '800px',
+ height: '600px',
+ top: '20px',
+ right: '20px',
+ left: 'auto' // 初始右定位,拖动后会变成left,需记录
+ };
+ floatBox.style.cssText = `
+ position: fixed;
+ top: 20px;
+ right: 20px;
+ z-index: 9999999;
+ background: #fff;
+ border-radius: 8px;
+ box-shadow: 0 2px 12px rgba(0,0,0,0.2);
+ padding: 8px;
+ width: 800px;
+ height: 600px;
+ box-sizing: border-box;
+ cursor: move;
+ transition: all 0.2s ease;
+ `;
+
+ // 2. 创建浮窗头部(标题+最大化+关闭按钮)
+ const floatHeader = document.createElement("div");
+ floatHeader.className = "float-header";
+ floatHeader.style.cssText = `
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 6px;
+ padding-bottom: 6px;
+ border-bottom: 1px solid #f0f0f0;
+ user-select: none;
+ `;
+ // 标题(精简)
+ const floatTitle = document.createElement("div");
+ floatTitle.className = "float-title";
+ floatTitle.style.cssText = `font-size: 14px; font-weight: 500; color: #333; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;`;
+ floatTitle.innerText = imgName;
+ floatTitle.title = imgName; // 鼠标悬浮显示完整标题
+
+ // 新增:最大化/还原按钮
+ const maxBtn = document.createElement("button");
+ maxBtn.className = "float-max-btn";
+ maxBtn.style.cssText = `
+ border: none;
+ background: #f5f5f5;
+ border-radius: 50%;
+ width: 30px;
+ height: 30px;
+ cursor: pointer;
+ color: #666;
+ font-size: 16px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0;
+ margin-right: 8px;
+ `;
+ maxBtn.innerText = "□";
+ maxBtn.title = "最大化/还原";
+ maxBtn.onclick = () => this.toggleMaxWindow(floatBox);
+
+ // 关闭按钮
+ const closeBtn = document.createElement("button");
+ closeBtn.className = "float-close-btn";
+ closeBtn.style.cssText = `
+ border: none;
+ background: #f5f5f5;
+ border-radius: 50%;
+ width: 30px;
+ height: 30px;
+ cursor: pointer;
+ color: #666;
+ font-size: 20px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0;
+ `;
+ closeBtn.innerText = "×";
+ closeBtn.onclick = () => this.closeFloatImage();
+
+ // 头部组装:标题 + 最大化按钮 + 关闭按钮
+ const headerRight = document.createElement("div");
+ headerRight.style.display = "flex";
+ headerRight.style.alignItems = "center";
+ headerRight.appendChild(maxBtn);
+ headerRight.appendChild(closeBtn);
+ floatHeader.appendChild(floatTitle);
+ floatHeader.appendChild(headerRight);
+
+ // 3. 创建图片容器(自适应图片大小,溢出隐藏)
+ const imgContainer = document.createElement("div");
+ imgContainer.className = "float-img-container";
+ imgContainer.style.cssText = `
+ width: 100%;
+ height: calc(100% - 34px);
+ text-align: center;
+ overflow: auto;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ `;
+ const floatImg = document.createElement("img");
+ floatImg.className = "float-img";
+ floatImg.style.cssText = `
+ max-width: 100%;
+ max-height: 100%;
+ object-fit: contain;
+ border-radius: 4px;
+ transition: transform 0.1s ease;
+ transform-origin: center center; /* 缩放以图片中心为原点 */
+ `;
+ floatImg.src = imgUrl;
+ floatImg.alt = imgName;
+ // 图片加载失败占位
+ floatImg.onerror = function () {
+ this.src = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIwIiBoZWlnaHQ9IjEyMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjRjVGNUY1Ii8+PHBhdGggZD0iTTEwIDMySDEwMFYxMEgxMFYzMnoiIGZpbGw9IiM5OTkiLz48cGF0aCBkPSJNMzAgODBIMjBWNTBIMzBWNzBaIiBmaWxsPSIjOTk5Ii8+PHBhdGggZD0iTTUwIDgwSDRWNTBIMDVWNzBaIiBmaWxsPSIjOTk5Ii8+PHBhdGggZD0iTTcwIDgwSDYwVjUwSDcwVjcwWiIgZmlsbD0iIzkkIi8+PC9zdmc+";
+ this.alt = "图片加载失败";
+ };
+ // 绑定图片滑轮缩放事件(仅鼠标悬浮图片时触发)
+ floatImg.addEventListener("wheel", (e) => this.imgWheelZoom(e, floatImg));
+ imgContainer.appendChild(floatImg);
+
+ // 4. 组装浮窗
+ floatBox.appendChild(floatHeader);
+ floatBox.appendChild(imgContainer);
+ // 5. 挂载到body(脱离Vue组件,全局悬浮)
+ document.body.appendChild(floatBox);
+ // 存储浮窗节点,用于后续操作
+ this.floatWindow = floatBox;
+
+ // 6. 实现整个弹窗可拖动
+ this.draggableFloatWindow(floatBox, floatBox);
+ },
+ // 新增:弹窗最大化/还原切换
+ toggleMaxWindow(floatBox) {
+ if (!floatBox) return;
+ this.isWindowMax = !this.isWindowMax;
+ const imgContainer = floatBox.querySelector(".float-img-container");
+ if (this.isWindowMax) {
+ // 最大化:占满屏幕(留10px边距)
+ floatBox.style.width = `calc(100% - 20px)`;
+ floatBox.style.height = `calc(100% - 20px)`;
+ floatBox.style.top = `10px`;
+ floatBox.style.left = `10px`;
+ floatBox.style.right = `auto`;
+ // 更新图片容器高度
+ imgContainer.style.height = `calc(100% - 34px)`;
+ // 最大化按钮样式变化
+ floatBox.querySelector(".float-max-btn").innerText = "▢";
+ floatBox.querySelector(".float-max-btn").title = "还原";
+ } else {
+ // 还原:恢复原始样式
+ floatBox.style.width = this.originalWindowStyle.width;
+ floatBox.style.height = this.originalWindowStyle.height;
+ floatBox.style.top = this.originalWindowStyle.top;
+ floatBox.style.right = this.originalWindowStyle.right;
+ floatBox.style.left = this.originalWindowStyle.left;
+ // 更新图片容器高度
+ imgContainer.style.height = `calc(100% - 34px)`;
+ // 还原按钮样式
+ floatBox.querySelector(".float-max-btn").innerText = "□";
+ floatBox.querySelector(".float-max-btn").title = "最大化";
+ }
+ },
+ // 新增:图片滑轮缩放(核心)
+ imgWheelZoom(e, img) {
+ // 阻止事件冒泡,避免影响页面滚动
+ e.preventDefault();
+ e.stopPropagation();
+ // 判断滚轮方向:向上滚=放大,向下滚=缩小
+ const delta = e.deltaY < 0 ? 0.1 : -0.1;
+ // 更新缩放比例,限制0.5-3倍(可自行调整)
+ this.imgScale = Math.max(0.5, Math.min(3, this.imgScale + delta));
+ // 应用缩放,以图片中心为原点
+ img.style.transform = `scale(${this.imgScale})`;
+ },
+ // 关闭图片浮窗(isRemove:是否彻底移除DOM,默认仅隐藏)
+ closeFloatImage(isRemove = false) {
+ if (this.floatWindow) {
+ if (isRemove) {
+ // 移除前解绑事件,避免内存泄漏
+ const floatImg = this.floatWindow.querySelector(".float-img");
+ floatImg && floatImg.removeEventListener("wheel", this.imgWheelZoom);
+ document.body.removeChild(this.floatWindow);
+ this.floatWindow = null;
+ // 重置状态
+ this.imgScale = 1;
+ this.isWindowMax = false;
+ } else {
+ this.floatWindow.style.display = "none";
+ }
+ }
+ // 遮罩层已弃用,直接清空
+ if (this.floatMask) {
+ document.body.removeChild(this.floatMask);
+ this.floatMask = null;
+ }
+ },
+ // 实现浮窗拖动:整个弹窗可拖动
+ draggableFloatWindow(wrapEl, dragEl) {
+ let isDown = false;
+ let startX, startY, wrapLeft, wrapTop;
+ // 鼠标按下
+ dragEl.addEventListener("mousedown", (e) => {
+ // 点击按钮时不触发拖动(关闭/最大化)
+ if (e.target.className.includes("float-close-btn") || e.target.className.includes("float-max-btn")) {
+ return;
+ }
+ isDown = true;
+ startX = e.clientX;
+ startY = e.clientY;
+ wrapLeft = wrapEl.offsetLeft;
+ wrapTop = wrapEl.offsetTop;
+ wrapEl.style.zIndex = "10000";
+ e.preventDefault();
+ });
+ // 鼠标移动时更新浮窗位置
+ document.addEventListener("mousemove", (e) => {
+ if (!isDown) return;
+ const moveX = e.clientX - startX;
+ const moveY = e.clientY - startY;
+ wrapEl.style.left = `${wrapLeft + moveX}px`;
+ wrapEl.style.top = `${wrapTop + moveY}px`;
+ wrapEl.style.right = "auto"; // 拖动后固定左定位,避免右定位冲突
+ wrapEl.style.transform = "none";
+ });
+ // 鼠标松开/离开,停止拖动
+ const stopDrag = () => {
+ if (isDown) {
+ isDown = false;
+ wrapEl.style.zIndex = "9999"; // 恢复原层级
+ }
+ };
+ document.addEventListener("mouseup", stopDrag);
+ document.addEventListener("mouseleave", stopDrag);
},
},
};
@@ -231,7 +468,6 @@ export default {
.receipt-info {
display: flex;
- // justify-content: space-between;
align-items: center;
.info-left {
@@ -276,9 +512,8 @@ export default {
text-align: center;
width: 40%;
}
- // 删除按钮容器
+
.delete-btn-box {
- // 按钮和右侧的间距
margin-right: 10px;
.delete-btn {
@@ -296,7 +531,6 @@ export default {
}
}
- // 无数据提示样式
.empty-tip {
text-align: center;
padding: 50px 0;
@@ -310,7 +544,6 @@ export default {
}
}
- // 图片错误占位样式
.image-slot {
display: flex;
justify-content: center;
@@ -322,3 +555,43 @@ export default {
}
}
+
+
+
\ No newline at end of file
diff --git a/src/views/order/category.vue b/src/views/order/category.vue
index 34464f6..a892c11 100644
--- a/src/views/order/category.vue
+++ b/src/views/order/category.vue
@@ -268,6 +268,7 @@ export default {
font-size: 1.5vw;
margin-top: 2.1vw;
margin-left: 3.4vw;
+ color: #101010;
}
diff --git a/src/views/order/orderAddEdit.vue b/src/views/order/orderAddEdit.vue
index 37ff3b5..08844b2 100644
--- a/src/views/order/orderAddEdit.vue
+++ b/src/views/order/orderAddEdit.vue
@@ -174,10 +174,11 @@
@@ -201,18 +202,18 @@
-
+
-
+
-
+
@@ -358,7 +359,7 @@ export default {
standardPrice: "",
sellingPrice: "",
splitPrice: "",
- discountAmount: "",
+ discountAmount: 0,
},
monetaryUnitList: [],
categoryShow: false,
@@ -801,7 +802,7 @@ export default {
standardPrice: "",
sellingPrice: "",
splitPrice: "",
- discountAmount: "",
+ discountAmount: 0,
};
// 重置项目列表
this.projectList = [];
diff --git a/src/views/order/orderList.vue b/src/views/order/orderList.vue
index 97f35a0..896cc88 100644
--- a/src/views/order/orderList.vue
+++ b/src/views/order/orderList.vue
@@ -149,7 +149,12 @@
-
+
+
+
+ {{ getMonetaryUnitText(scope.row.monetaryUnit) }}
+
+
@@ -313,6 +318,9 @@