diff --git a/gear-ui3/src/components/GearList/index.vue b/gear-ui3/src/components/GearList/index.vue index 427c7c9..477d7d4 100644 --- a/gear-ui3/src/components/GearList/index.vue +++ b/gear-ui3/src/components/GearList/index.vue @@ -2,34 +2,76 @@
- -
- -
- {{ 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 @@ - - + + + + + + + + - + @@ -90,6 +105,8 @@ 更新订单信息 + 复制订单ID @@ -106,6 +123,18 @@
+ + +
+ +
+
+ + +
+ +
+
@@ -131,6 +160,14 @@ + + + + + + + + import { getOrder, delOrder, addOrder, updateOrder, listOrder } from "@/api/oms/order"; + import OrderDetailPanel from './detail.vue'; import { EOrderStatus } from "@/utils/enums"; import CustomerSelect from '@/components/CustomerSelect/index.vue'; import klpList from "@/components/GearList/index.vue"; import { getCurrentInstance } from "vue"; + import ReturnExchange from './return.vue'; +import Pay from './pay.vue'; +import Receive from './receive.vue'; export default { name: "Order", - components: { OrderDetailPanel, CustomerSelect, klpList, ReturnExchange }, + components: { OrderDetailPanel, CustomerSelect, klpList, ReturnExchange, Pay, Receive }, props: { tradeType: { type: String, @@ -222,7 +263,8 @@ export default { orderCode: undefined, customerId: undefined, salesManager: undefined, - tradeType: this.tradeType + // tradeType: this.tradeType + taxAmount: undefined, }, // 表单参数 form: { @@ -230,7 +272,8 @@ export default { orderCode: undefined, customerId: undefined, salesManager: undefined, - tradeType: this.tradeType, + // tradeType: this.tradeType, + noTaxAmount: undefined, remark: undefined, delFlag: undefined, createTime: undefined, @@ -261,7 +304,7 @@ export default { }; }, created() { - this.queryParams.orderStatus = this.orderQueryStatus; + // this.queryParams.orderStatus = this.orderQueryStatus; this.getList(); }, methods: { @@ -327,7 +370,8 @@ export default { customerId: undefined, salesManager: undefined, orderStatus: this.orderQueryStatus, - tradeType: this.tradeType, + taxAmount: undefined, + // tradeType: this.tradeType, remark: undefined, taxAmount: 0, noTaxAmount: 0, diff --git a/gear-ui3/src/views/oms/order/panels/pay.vue b/gear-ui3/src/views/oms/order/panels/pay.vue new file mode 100644 index 0000000..450aa8a --- /dev/null +++ b/gear-ui3/src/views/oms/order/panels/pay.vue @@ -0,0 +1,354 @@ + + + diff --git a/gear-ui3/src/views/oms/order/panels/receive.vue b/gear-ui3/src/views/oms/order/panels/receive.vue new file mode 100644 index 0000000..5f3186b --- /dev/null +++ b/gear-ui3/src/views/oms/order/panels/receive.vue @@ -0,0 +1,356 @@ + + +