<template>
|
<div class="ordered-checkbox-container">
|
<!-- 横向排列的多选框组 -->
|
<el-checkbox-group
|
v-model="checkedValues"
|
class="horizontal-checkbox-group"
|
>
|
<el-checkbox
|
v-for="option in options"
|
:key="getValue(option)"
|
:label="getValue(option)"
|
>
|
{{ getLabel(option) }}
|
</el-checkbox>
|
</el-checkbox-group>
|
|
<!-- 选中顺序展示区域 -->
|
<div v-if="selectedOrder.length > 0" class="selection-order-display">
|
<span class="order-label">服务执行顺序:</span>
|
<span
|
v-for="(item, index) in selectedOrder"
|
:key="item.value"
|
class="order-item"
|
>
|
{{ 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>
|
<div v-else class="selection-order-display">
|
<span class="order-label">暂无选中项</span>
|
</div>
|
</div>
|
</template>
|
|
<script>
|
export default {
|
name: "OrderedCheckboxGroup",
|
props: {
|
options: {
|
type: Array,
|
default: () => [],
|
},
|
value: {
|
type: Array,
|
default: () => [],
|
},
|
// selectedOrder: {
|
// type: Array,
|
// default: () => [],
|
// },
|
valueKey: {
|
type: String,
|
default: "value",
|
},
|
labelKey: {
|
type: String,
|
default: "label",
|
},
|
// 新增:默认补偿时间
|
defaultCompensateTime: {
|
type: Number,
|
default: 0,
|
},
|
},
|
data() {
|
return {
|
checkedValues: [],
|
selectedOrder: [], // 现在格式为 [{value, compensateTime}]
|
};
|
},
|
watch: {
|
value: {
|
immediate: true,
|
handler(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.find((item) => item.value === value)) {
|
this.selectedOrder.push({
|
value,
|
compensateTime: this.defaultCompensateTime,
|
});
|
}
|
});
|
|
removed.forEach((value) => {
|
const index = this.selectedOrder.findIndex(
|
(item) => item.value === value
|
);
|
if (index > -1) {
|
this.selectedOrder.splice(index, 1);
|
}
|
});
|
|
// 更新父组件的 v-model 绑定值(选中值数组)
|
this.$emit("input", [...newVal]);
|
// 触发 change 事件,传递完整的业务数据
|
this.emitChangeEvent();
|
},
|
},
|
methods: {
|
getValue(option) {
|
return typeof option === "object" ? option[this.valueKey] : option;
|
},
|
getLabel(option) {
|
return typeof option === "object" ? option[this.labelKey] : option;
|
},
|
getLabelByValue(value) {
|
const option = this.options.find((opt) => this.getValue(opt) === value);
|
return option ? this.getLabel(option) : value;
|
},
|
getSelectedIndex(index) {
|
if (index < 20) {
|
return String.fromCharCode(0x2460 + index);
|
} else {
|
return `(${index + 1})`;
|
}
|
},
|
// 处理补偿时间变化
|
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.map((item) => ({
|
value: item.preachform,
|
compensateTime: item.compensateTime || this.defaultCompensateTime,
|
}));
|
|
this.checkedValues = orderedValues.map((item) => item.preachform);
|
this.emitChangeEvent();
|
},
|
},
|
};
|
</script>
|
|
<style scoped>
|
.ordered-checkbox-container {
|
display: flex;
|
flex-direction: column;
|
gap: 16px;
|
}
|
|
.horizontal-checkbox-group {
|
display: flex;
|
flex-wrap: wrap;
|
gap: 20px;
|
}
|
|
.selection-order-display {
|
padding: 12px;
|
background-color: #f5f7fa;
|
border-radius: 4px;
|
border: 1px solid #ebeef5;
|
display: flex;
|
flex-wrap: wrap;
|
align-items: center;
|
}
|
|
.order-label {
|
font-weight: bold;
|
color: #606266;
|
margin-right: 8px;
|
}
|
|
.order-item {
|
color: #409eff;
|
font-weight: 500;
|
display: inline-flex;
|
align-items: center;
|
margin-right: 8px;
|
}
|
|
.compensate-time-input {
|
width: 90px;
|
margin-left: 8px;
|
}
|
|
/* 响应式设计:小屏幕时换行 */
|
@media (max-width: 768px) {
|
.horizontal-checkbox-group {
|
gap: 12px;
|
}
|
|
.selection-order-display {
|
padding: 8px;
|
flex-direction: column;
|
align-items: flex-start;
|
}
|
|
.order-item {
|
margin-bottom: 8px;
|
}
|
}
|
</style>
|