-
-
- {{ titleLabel }}:
-
- {{ item[titleField] }}
-
-
+
+
+
+
+
+
+
+
+
+ {{ info1Label }}:
+
+ {{ item[info1Field] }}
+
+
+
-
+
+
+
+ {{ info2Label }}:
+ {{ item[info2Field] }}
+
+
+
+
+
+
+ {{ info3Label }}:
+ {{ item[info3Field] }}
+
+
+
+
+
+
+
+
+
+ {{ info4Label }}:
+ {{ item[info4Field] }}
+
+
+
+
+
+
+ {{ info5Label }}:
+ {{ item[info5Field] }}
+
+
+
+
+
+
+ {{ info6Label }}:
+ {{ item[info6Field] }}
+
+
+
+
+
+
-
+
@@ -42,33 +84,18 @@ export default {
name: "KLPList",
components: {},
props: {
+ // ---------------------- 原有核心Props(保留) ----------------------
/** 列表数据源(必传) */
listData: {
type: Array,
required: true,
default: () => []
},
-
- /** 列表项唯一标识字段(必传,如orderId、id) */
+ /** 列表项唯一标识字段(必传) */
listKey: {
type: String,
required: true
},
-
- /** 列表标题前置标签(如"订单编号:") */
- titleLabel: {
- type: String,
- required: true,
- default: "标题"
- },
-
- /** 列表项标题对应的字段名(如orderCode、name) */
- titleField: {
- type: String,
- required: true,
- default: "title"
- },
-
/** 列表加载状态 */
loading: {
type: Boolean,
@@ -76,67 +103,128 @@ export default {
default: false
},
- /** 标题最大宽度占容器的百分比(0-100),控制文字溢出 */
- titleMaxPercent: {
+ // ---------------------- 新增:6个信息位配置 ----------------------
+ // 信息位1(主标题,兼容原titleField)
+ info1Field: {
+ type: String,
+ required: false,
+ default: "title" // 默认对应原titleField
+ },
+ info1Label: {
+ type: String,
+ required: false,
+ default: "" // 兼容原titleLabel
+ },
+ // 信息位2(副标题)
+ info2Field: {
+ type: String,
+ required: false,
+ default: ""
+ },
+ info2Label: {
+ type: String,
+ required: false,
+ default: ""
+ },
+ // 信息位3(状态)
+ info3Field: {
+ type: String,
+ required: false,
+ default: ""
+ },
+ info3Label: {
+ type: String,
+ required: false,
+ default: ""
+ },
+ // 信息位4(时间)
+ info4Field: {
+ type: String,
+ required: false,
+ default: ""
+ },
+ info4Label: {
+ type: String,
+ required: false,
+ default: ""
+ },
+ // 信息位5(数量/金额)
+ info5Field: {
+ type: String,
+ required: false,
+ default: ""
+ },
+ info5Label: {
+ type: String,
+ required: false,
+ default: ""
+ },
+ // 信息位6(备注)
+ info6Field: {
+ type: String,
+ required: false,
+ default: ""
+ },
+ info6Label: {
+ type: String,
+ required: false,
+ default: ""
+ },
+
+ // ---------------------- 新增:样式控制Props ----------------------
+ /** 每行内部信息位的间距(px) */
+ rowGap: {
type: Number,
required: false,
- default: 80 // 默认占容器80%宽度
+ default: 16 // 默认间距16px
+ },
+ /** 两行之间的垂直间距(px) */
+ rowMarginBottom: {
+ type: Number,
+ required: false,
+ default: 4 // 默认4px
+ },
+ /** 主标题最大宽度占内容区的百分比(控制溢出) */
+ info1MaxPercent: {
+ type: Number,
+ required: false,
+ default: 60 // 主标题占比下调,给其他信息位留空间
}
},
data() {
return {
- // 内部管理选中状态:存储当前选中项的唯一键值(单选中)
- selectedKey: null,
- // 文字溢出检测临时元素(避免重复创建)
- overflowCheckElements: {},
- // 容器宽度缓存
- containerWidth: 0
+ selectedKey: null, // 选中状态(不变)
+ overflowCheckElements: {}, // 溢出检测临时元素(不变)
+ containerWidth: 0 // 容器宽度缓存(不变)
};
},
methods: {
- /**
- * 判断当前列表项是否被选中
- * @param {Object} item - 列表项数据
- * @returns {Boolean} 选中状态
- */
+ // ---------------------- 原有核心方法(保留+微调) ----------------------
+ /** 判断列表项是否选中(不变) */
isSelected(item) {
const itemKey = item[this.listKey];
return this.selectedKey === itemKey;
},
- /**
- * 列表项点击事件:切换选中状态(单选中逻辑)
- * @param {Object} item - 点击的列表项数据
- */
+ /** 列表项点击事件(不变) */
handleItemClick(item) {
- const itemKey = item[this.listKey];
- // 单选中逻辑:点击已选中项取消选中,点击未选中项切换选中(取消其他项)
- // this.selectedKey = this.selectedKey === itemKey ? null : itemKey;
+ const itemKey = item[this.listKey];
this.selectedKey = itemKey;
-
- // 向父组件触发事件:传递当前选中项(null表示无选中)
const selectedItem = this.selectedKey ? item : null;
this.$emit("item-click", selectedItem, item);
},
- /**
- * 清空选中状态(支持父组件通过ref调用)
- */
+ /** 清空选中状态(不变) */
clearSelection() {
this.selectedKey = null;
- // 触发清空选中事件
this.$emit("selection-cleared");
},
- /**
- * 主动设置选中项(支持父组件通过ref调用)
- * @param {String/Number} targetKey - 要选中项的唯一键值
- */
+ /** 主动设置选中项(不变) */
setSelection(targetKey) {
const isExist = this.listData.some(item => item[this.listKey] === targetKey);
if (isExist) {
this.selectedKey = targetKey;
- // 触发选中事件
const selectedItem = this.listData.find(item => item[this.listKey] === targetKey);
this.$emit("item-click", selectedItem);
} else {
@@ -145,31 +233,55 @@ export default {
}
},
+ // ---------------------- 新增:信息位控制方法 ----------------------
/**
- * 判断文字是否溢出(控制Tooltip显示/隐藏)
+ * 判断信息位是否需要显示(插槽存在 或 字段有值)
+ * @param {String} infoKey - 信息位标识(info1~info6)
* @param {Object} item - 列表项数据
+ * @returns {Boolean} 是否显示
+ */
+ showInfoItem(infoKey, item) {
+ // 前置容错:避免item为undefined导致报错
+ if (!item) return false;
+
+ // 1. Vue 3 插槽判断:用 $slots 替代 $scopedSlots,且先判断 $slots 是否存在
+ const hasSlot = this.$slots && this.$slots[infoKey];
+ if (hasSlot) return true;
+
+ // 2. 无插槽时,判断字段配置是否存在 + 字段值是否有效
+ const field = this[`${infoKey}Field`];
+ // 容错:字段未配置(如没传info1Field)则不显示
+ if (!field) return false;
+ // 字段值有效判断(排除 undefined/null/空字符串)
+ return item[field] !== undefined && item[field] !== null && item[field] !== "";
+ },
+
+ /**
+ * 信息位1(主标题)溢出检测(适配新字段)
+ * @param {Object} item - 列表项数据
+ * @param {String} infoKey - 信息位标识(仅info1需要)
* @returns {Boolean} 是否溢出
*/
- isContentOverflow(item) {
+ isContentOverflow(item, infoKey) {
const itemKey = item[this.listKey];
- const content = item[this.titleField] || "";
+ const field = this[`${infoKey}Field`];
+ const content = item[field] || "";
- // 内容为空时不显示Tooltip
- if (!content) return false;
+ // 内容为空或无字段时不显示Tooltip
+ if (!content || !field) return false;
- // 获取容器宽度并增加存在性检查
- const container = this.$el.querySelector('.klp-list-container');
- if (!container) return false; // 容器不存在时直接返回
- this.containerWidth = container.clientWidth;
-
- // 计算标题内容最大可用宽度(减去标签和边距)
- const labelWidth = this.$el.querySelector('.title-label')?.offsetWidth || 60;
- const availableWidth = (this.containerWidth * this.titleMaxPercent / 100) - labelWidth - 20;
+ // 获取内容区宽度(原容器宽度改为内容区宽度)
+ const contentEl = this.$el.querySelector(`.klp-list-item:nth-child(${this.listData.indexOf(item) + 1}) .klp-list-content`);
+ if (!contentEl) return false;
+ const contentWidth = contentEl.clientWidth;
- // 创建临时元素测量文字实际宽度(复用元素避免性能问题)
+ // 计算信息位1的最大可用宽度(减去标签宽度)
+ const labelWidth = this.$el.querySelector(`.klp-list-item:nth-child(${this.listData.indexOf(item) + 1}) .info-label`)?.offsetWidth || 40;
+ const maxWidth = (contentWidth * this.info1MaxPercent) / 100 - labelWidth - 12;
+
+ // 复用临时元素检测宽度(不变)
if (!this.overflowCheckElements[itemKey]) {
const tempEl = document.createElement("span");
- // 复制title-value的样式(确保测量准确)
tempEl.style.cssText = `
visibility: hidden;
position: absolute;
@@ -183,26 +295,21 @@ export default {
this.overflowCheckElements[itemKey] = tempEl;
}
- // 比较文字实际宽度与可用宽度
const tempEl = this.overflowCheckElements[itemKey];
- return tempEl.offsetWidth > availableWidth;
+ return tempEl.offsetWidth > maxWidth;
},
- /**
- * 监听容器宽度变化
- */
+ /** 窗口 resize 重新计算(不变) */
handleResize() {
- // 宽度变化时重新计算溢出状态
this.$forceUpdate();
}
},
watch: {
- /** 列表数据变化时,重置选中状态和溢出检测元素 */
+ /** 列表数据变化时清理临时元素(不变) */
listData: {
deep: true,
handler() {
this.clearSelection();
- // 清理临时测量元素
Object.values(this.overflowCheckElements).forEach(el => {
document.body.removeChild(el);
});
@@ -210,112 +317,138 @@ export default {
}
},
- /** 标题最大百分比变化时,重新计算溢出 */
- titleMaxPercent() {
+ /** 主标题占比变化时重新计算溢出(适配新prop) */
+ info1MaxPercent() {
this.$forceUpdate();
}
},
mounted() {
+ // 初始化内容区宽度(适配新结构)
this.$nextTick(() => {
- const container = this.$el.querySelector('.klp-list-container');
- // 增加存在性检查
- this.containerWidth = container ? container.clientWidth : 0;
+ const contentEl = this.$el.querySelector('.klp-list-content');
+ this.containerWidth = contentEl ? contentEl.clientWidth : 0;
});
-
- // 监听窗口大小变化
window.addEventListener('resize', this.handleResize);
},
beforeDestroy() {
- // 清理临时元素
+ // 清理临时元素和事件监听(不变)
Object.values(this.overflowCheckElements).forEach(el => {
document.body.removeChild(el);
});
-
- // 移除事件监听
window.removeEventListener('resize', this.handleResize);
}
};
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/gear-ui3/src/views/oms/order/panels/detail.vue b/gear-ui3/src/views/oms/order/panels/detail.vue
index eb76b9e..bb6b0ec 100644
--- a/gear-ui3/src/views/oms/order/panels/detail.vue
+++ b/gear-ui3/src/views/oms/order/panels/detail.vue
@@ -16,6 +16,26 @@
导出
+
+
+
+ 含税金额:
+ {{ orderInfo?.taxAmount }}
+ -
+ {{ actualAmount }}
+ =
+ {{ amountDifference }}
+
+
+
+
+ 无税金额:
+ {{ orderInfo?.noTaxAmount }}
+ -
+ {{ noTaxAmount }}
+ =
+ {{ noTaxAmountDifference }}
+
@@ -145,6 +165,22 @@ export default {
// 是否可以编辑(订单状态为新建时才能编辑)
canEdit() {
return this.orderInfo && this.orderInfo.orderStatus === EOrderStatus.NEW;
+ },
+ actualAmount() {
+ return this.orderDetailList?.reduce((total, item) => {
+ return total + (item.taxPrice || 0) * (item.quantity || 0);
+ }, 0) || 0;
+ },
+ amountDifference() {
+ return ((this.orderInfo?.taxAmount || 0) - this.actualAmount);
+ },
+ noTaxAmount() {
+ return this.orderDetailList?.reduce((total, item) => {
+ return total + (item.noTaxPrice || 0) * (item.quantity || 0);
+ }, 0) || 0;
+ },
+ noTaxAmountDifference() {
+ return ((this.orderInfo?.noTaxAmount || 0) - this.noTaxAmount);
}
},
watch: {
diff --git a/gear-ui3/src/views/oms/order/panels/orderPage.vue b/gear-ui3/src/views/oms/order/panels/orderPage.vue
index 673724f..eadfbc1 100644
--- a/gear-ui3/src/views/oms/order/panels/orderPage.vue
+++ b/gear-ui3/src/views/oms/order/panels/orderPage.vue
@@ -15,17 +15,32 @@
-
-
+
+
+
+ {{ item.taxAmount }}元(含税)
+
+
+
+
+
+ {{ item.salesManager }}【{{ item.orderCode }}】
+
+
+
+
+
+
+
+
-
-
+
@@ -90,6 +105,8 @@
更新订单信息
+ 复制订单ID
@@ -106,6 +123,18 @@