| | |
| | | <div v-if="selectedOrder.length > 0" class="selection-order-display"> |
| | | <span class="order-label">服务执行顺序:</span> |
| | | <span |
| | | v-for="(value, index) in selectedOrder" |
| | | :key="value" |
| | | v-for="(item, index) in selectedOrder" |
| | | :key="item.value" |
| | | class="order-item" |
| | | > |
| | | {{ getSelectedIndex(index) }}.{{ getLabelByValue(value) }} |
| | | {{ getSelectedIndex(index) }}.{{ getLabelByValue(item.value) }} |
| | | <el-tooltip content="设置补偿时间" placement="top"> |
| | | <el-input-number |
| | | v-model="item.compensateTime" |
| | | :min="0" |
| | | :max="60" |
| | | size="mini" |
| | | controls-position="right" |
| | | class="compensate-time-input" |
| | | @change="handleCompensateTimeChange(item.value, $event)" |
| | | /> |
| | | </el-tooltip> |
| | | <span v-if="index < selectedOrder.length - 1">、</span> |
| | | </span> |
| | | </div> |
| | |
| | | type: Array, |
| | | default: () => [], |
| | | }, |
| | | // selectedOrder: { |
| | | // type: Array, |
| | | // default: () => [], |
| | | // }, |
| | | valueKey: { |
| | | type: String, |
| | | default: "value", |
| | |
| | | type: String, |
| | | default: "label", |
| | | }, |
| | | // 新增:默认补偿时间 |
| | | defaultCompensateTime: { |
| | | type: Number, |
| | | default: 0, |
| | | }, |
| | | }, |
| | | data() { |
| | | return { |
| | | checkedValues: [], |
| | | selectedOrder: [], |
| | | selectedOrder: [], // 现在格式为 [{value, compensateTime}] |
| | | }; |
| | | }, |
| | | watch: { |
| | | value: { |
| | | immediate: true, |
| | | handler(newVal) { |
| | | if (JSON.stringify(newVal) !== JSON.stringify(this.checkedValues)) { |
| | | this.checkedValues = [...newVal]; |
| | | this.selectedOrder = [...newVal]; |
| | | if ( |
| | | Array.isArray(newVal) && |
| | | newVal.length > 0 && |
| | | typeof newVal[0] === "object" |
| | | ) { |
| | | // 1. 传入的是对象数组 [{ sort, preachform, compensateTime }] |
| | | this.checkedValues = newVal.map((item) => item.preachform); // 提取 preachform 组成选中值数组 |
| | | // 构建 selectedOrder,优先使用传入的 compensateTime,否则用默认值 |
| | | this.selectedOrder = newVal.map((item) => ({ |
| | | value: item.preachform, |
| | | compensateTime: item.hasOwnProperty("compensateTime") |
| | | ? item.compensateTime |
| | | : this.defaultCompensateTime, |
| | | })); |
| | | } else { |
| | | // 2. 传入的是字符串数组 (如 ["1", "3", "4"],兼容之前的用法) |
| | | if (JSON.stringify(newVal) !== JSON.stringify(this.checkedValues)) { |
| | | this.checkedValues = [...newVal]; |
| | | // 构建或更新 selectedOrder,保留已有的 compensateTime |
| | | const newOrder = []; |
| | | newVal.forEach((value) => { |
| | | const existingItem = this.selectedOrder.find( |
| | | (item) => item.value === value |
| | | ); |
| | | if (existingItem) { |
| | | newOrder.push(existingItem); |
| | | } else { |
| | | newOrder.push({ |
| | | value, |
| | | compensateTime: this.defaultCompensateTime, |
| | | }); |
| | | } |
| | | }); |
| | | this.selectedOrder = newOrder; |
| | | } |
| | | } |
| | | }, |
| | | deep: true // 建议添加 deep: true 以确保对象数组内的变化能被捕获 |
| | | }, |
| | | checkedValues(newVal, oldVal) { |
| | | // 处理选中项的变化 |
| | | const added = newVal.filter((item) => !oldVal.includes(item)); |
| | | const removed = oldVal.filter((item) => !newVal.includes(item)); |
| | | |
| | | added.forEach((value) => { |
| | | if (!this.selectedOrder.includes(value)) { |
| | | this.selectedOrder.push(value); |
| | | if (!this.selectedOrder.find((item) => item.value === value)) { |
| | | this.selectedOrder.push({ |
| | | value, |
| | | compensateTime: this.defaultCompensateTime, |
| | | }); |
| | | } |
| | | }); |
| | | |
| | | removed.forEach((value) => { |
| | | const index = this.selectedOrder.indexOf(value); |
| | | const index = this.selectedOrder.findIndex( |
| | | (item) => item.value === value |
| | | ); |
| | | if (index > -1) { |
| | | this.selectedOrder.splice(index, 1); |
| | | } |
| | | }); |
| | | |
| | | // 更新父组件的 v-model 绑定值(选中值数组) |
| | | this.$emit("input", [...newVal]); |
| | | this.$emit("change", [...newVal], [...this.selectedOrder]); |
| | | // 触发 change 事件,传递完整的业务数据 |
| | | this.emitChangeEvent(); |
| | | }, |
| | | }, |
| | | methods: { |
| | |
| | | return typeof option === "object" ? option[this.labelKey] : option; |
| | | }, |
| | | getLabelByValue(value) { |
| | | const option = this.options.find( |
| | | (opt) => this.getValue(opt) === value |
| | | ); |
| | | const option = this.options.find((opt) => this.getValue(opt) === value); |
| | | return option ? this.getLabel(option) : value; |
| | | }, |
| | | getSelectedIndex(index) { |
| | |
| | | return `(${index + 1})`; |
| | | } |
| | | }, |
| | | getSelectionOrder() { |
| | | return [...this.selectedOrder]; |
| | | // 处理补偿时间变化 |
| | | handleCompensateTimeChange(value, newTime) { |
| | | const item = this.selectedOrder.find((item) => item.value === value); |
| | | if (item) { |
| | | item.compensateTime = newTime; |
| | | // 补偿时间变化时,只触发 change 事件,不触动 v-model |
| | | this.emitChangeEvent(); |
| | | } |
| | | }, |
| | | // 发射变化事件 |
| | | emitChangeEvent() { |
| | | // 转换数据格式为父组件需要的格式 |
| | | const outputData = this.selectedOrder.map((item, index) => ({ |
| | | sort: index + 1, |
| | | preachform: item.value, |
| | | compensateTime: item.compensateTime, |
| | | })); |
| | | this.$emit("change", outputData); // 发射 change 事件,传递完整数据 |
| | | }, |
| | | // 获取当前选择顺序和补偿时间 |
| | | getSelectionOrder() { |
| | | return this.selectedOrder.map((item, index) => ({ |
| | | sort: index + 1, |
| | | preachform: item.value, |
| | | compensateTime: item.compensateTime, |
| | | })); |
| | | }, |
| | | // 设置选择顺序和补偿时间 |
| | | setSelectionOrder(orderedValues) { |
| | | this.selectedOrder = [...orderedValues]; |
| | | this.checkedValues = [...orderedValues]; |
| | | this.selectedOrder = orderedValues.map((item) => ({ |
| | | value: item.preachform, |
| | | compensateTime: item.compensateTime || this.defaultCompensateTime, |
| | | })); |
| | | |
| | | this.checkedValues = orderedValues.map((item) => item.preachform); |
| | | this.emitChangeEvent(); |
| | | }, |
| | | }, |
| | | }; |
| | |
| | | background-color: #f5f7fa; |
| | | border-radius: 4px; |
| | | border: 1px solid #ebeef5; |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | align-items: center; |
| | | } |
| | | |
| | | .order-label { |
| | |
| | | .order-item { |
| | | color: #409eff; |
| | | font-weight: 500; |
| | | display: inline-flex; |
| | | align-items: center; |
| | | margin-right: 8px; |
| | | } |
| | | |
| | | .compensate-time-input { |
| | | width: 90px; |
| | | margin-left: 8px; |
| | | } |
| | | |
| | | /* 响应式设计:小屏幕时换行 */ |
| | |
| | | |
| | | .selection-order-display { |
| | | padding: 8px; |
| | | flex-direction: column; |
| | | align-items: flex-start; |
| | | } |
| | | |
| | | .order-item { |
| | | margin-bottom: 8px; |
| | | } |
| | | } |
| | | </style> |