54def6aa创建于 2025年8月14日历史提交
<template>
    <div class="rendering-area">
        <div class="form-group" :style="common_store.layout_style + layout_style">
            <form-title :value="props.value" :style="title_style"></form-title>
            <div class="content w flex-1 flex-col gap-10">
                <template v-if="form.type == 'checkbox'">
                    <el-checkbox-group v-model="form.form_value" :class="['adaptive-height', { 'vertical-group' : form.arrangement == 'vertical' }]" @change="data_check">
                        <el-checkbox v-for="item in form.option_list" :key="item.value" :value="item.value"><div :style="option_style(item)">{{ item.name }}</div></el-checkbox>
                    </el-checkbox-group>
                    <el-popover v-if="form.is_add_option == '1'" :visible="popover_visible" placement="top-start" trigger='click' effect="light" popper-class="custom-popover" :width="200">
                        <div class="flex-col gap-20">
                            <el-form ref="ruleFormRef" :model="popover_form" :rules="rules" label-width="85" status-icon>
                                <el-form-item label-width="0" prop="popover_option">
                                    <el-input v-model="popover_form.popover_option" placeholder="请填写内容,enter确定" @change="confirm(ruleFormRef)"></el-input>
                                </el-form-item>
                                <div style="text-align: right; margin: 0">
                                    <el-button size="small" text @click="cancle(ruleFormRef)">取消</el-button>
                                    <el-button size="small" type="primary" @click="confirm(ruleFormRef)">确定</el-button>
                                </div>
                            </el-form>
                        </div>
                        <template #reference>
                            <div class="add-option flex-row gap-10 align-c" @click="add_option">
                                <icon name="add-wide" size="14" color="#2a94ff"/>
                                <span class="size-14 cr-primary">添加选项</span>
                            </div>
                        </template>
                    </el-popover>
                </template>
                <template v-else-if="form.type == 'select-multi'">
                    <div class="flex-col gap-10">
                        <el-select v-model="form.form_value" multiple placeholder="" class="multi-select flex-1 border-focus" popper-class="custom-select" :style="frame_style + style_container" @change="data_check" @visible-change="input_value = ''">
                            <template #header>
                                <el-input v-model="input_value" class="search-select-input" placeholder="搜索(多个关键字用空格隔开)" :prefix-icon="Search" size="large" />
                            </template>
                            <el-checkbox v-model="selectAll" :indeterminate="indeterminate" class="pl-20 mb-10 w" @change="handleCheckAllChange">{{ !isEmpty(input_value) ? '搜索结果全选' : '全选' }}</el-checkbox>
                            <el-checkbox-group :model-value="form.form_value" class="select-multi-checkbox flex-col gap-10" @change="data_check">
                                <el-option v-for="item in new_option_list" :key="item.value" :value="item.value" :label="item.name">
                                    <el-checkbox :value="item.value" :label="item.name"><div :style="option_style(item)">{{ item.name }}</div></el-checkbox>
                                </el-option>
                            </el-checkbox-group>
                            <template v-if="form.is_add_option == '1'" #footer>
                                <div v-if="!popover_visible" class="add-option flex-row gap-10 align-c pl-20" @click="add_option">
                                    <icon name="add-wide" size="14" color="#2a94ff"/>
                                    <span class="size-14 cr-primary">添加选项</span>
                                </div>
                                <div v-else class="flex-col gap-10 align-c jc-sb w h">
                                    <el-form ref="ruleFormRef" :model="popover_form" :rules="rules" class="w h" label-width="0" status-icon>
                                        <el-form-item label-width="0" prop="popover_option" class="mb-0">
                                            <el-input v-model="popover_form.popover_option" placeholder="请填写内容,enter确定" type="small" @change="confirm(ruleFormRef)"></el-input>
                                        </el-form-item>
                                    </el-form>
                                    <div style="text-align: left;">
                                        <el-button size="small" text @click="cancle(ruleFormRef)">取消</el-button>
                                        <el-button size="small" type="primary" @click="confirm(ruleFormRef)">确定</el-button>
                                    </div>
                                </div>
                            </template>
                            <!-- 选中之后的效果 -->
                            <template #tag>
                                <template v-if="isEmpty(form.form_value)">
                                    <div class="select-tag" :style="common_styles">{{ form.placeholder }}</div>
                                </template>
                                <template v-else>
                                    <template v-if="form.is_multicolour == '1'">
                                        <div v-for="item in form.option_list.filter((item1: any) => form.form_value.includes(item1.value))" :key="item.value" :style="option_style(item) + 'white-space: nowrap;'">{{ item.name }}</div>
                                    </template>
                                    <template v-else> 
                                        <div class="text-line-1" :style="common_styles">{{ selected_names }}</div>
                                    </template>
                                </template>
                            </template>
                        </el-select>
                    </div>
                </template>
                <form-error v-if="form.common_config.is_error == '1'" v-model="form.common_config.error_text"></form-error>
            </div>
        </div>
    </div>
</template>
<script setup lang="ts">
import { common_styles_computer, get_border_left_right_size, get_format_checks, get_math } from "@/utils";
import { commonStore } from "@/store";
import { isEmpty, cloneDeep } from "lodash";
import { FormInstance, FormRules } from "element-plus/es/components/form";
import { color_change } from "@/utils/common";
import { Search } from '@element-plus/icons-vue'
const common_store = commonStore();
const props = defineProps({
    value: {
        type: Object,
        default: () => ({}),
    },
    isCustom: {
        type: Boolean,
        default: false,
    }
});
const form = computed(() => props.value);

const data_check = () => {
    get_format_checks(form.value, true, 'checkbox');
};
const frame_style = computed(() => common_store.frame_style + `${ props.isCustom ? `max-width:100%;width:calc(100% - ${ get_border_left_right_size(form.value.common_config) }px);` : '' }`);
const layout_style = computed(() => common_store.form_layout?.computer?.flex_direction == 'row' && form.value.type == 'checkbox' ? 'align-items:flex-start;' : '');
const title_style = computed(() => common_store.form_layout?.computer?.flex_direction == 'row' && form.value.type == 'checkbox'? 'margin-top:4px;' : '');
// #region 添加选项相关
type popoverForm = {
    popover_option: string;
}
const popover_form = reactive<popoverForm>({
    popover_option: '',
});
const rules = reactive<FormRules<popoverForm>>({
    popover_option: [
        { required: true, message: '请输入选项名称', trigger: ['change', 'blur'] },
    ],
});
const ruleFormRef = ref<FormInstance>();
const popover_visible = ref(false);
// 点击添加选项
const add_option = () => {
    popover_visible.value = true;
};
// 取消添加选项
const cancle = (formEl: FormInstance | undefined) => {
    if (!formEl) return
    formEl.resetFields()
    popover_visible.value = false;
};
// 确认添加选项时的操作
const confirm = async (formEl: FormInstance | undefined) => {
  if (!formEl) return
  await formEl.validate((valid: any, fields: any) => {
    if (valid) {
        const value = 'option' + get_math();
        form.value.option_list.push({
            name: popover_form.popover_option,
            value: value,
            color: color_change(form.value.option_list.length - 1),
        });
        form.value.form_value.push(value);
        popover_visible.value = false;
    }
  })
}
//#endregion
//#region 多选下拉框全选和反选的处理
// 搜索框筛选内容
const new_option_list = computed(() => {
    if (!isEmpty(input_value.value)) {
        const inputValue = input_value.value.split(' ').filter(item => item !== '');
        return form.value.option_list.filter((item: { name: string }) => inputValue.some(keyword => item.name.includes(keyword)));
    } else {
        return form.value.option_list;
    }
});
const selectAll = ref(false);
const input_value = ref('');
const indeterminate = ref(true);
watchEffect(() => {
    if (!isEmpty(input_value.value)) {
        // 判断符合条件的数据中选中多少个
        const count = new_option_list.value.reduce((acc : number, item: { value: string }) => form.value.form_value.includes(item.value) ? acc + 1 : acc, 0);
        const flag = count > 0 && count < new_option_list.value.length;
        selectAll.value = count == new_option_list.value.length;
        indeterminate.value = flag;
    } else {
        const valueSet = new Set(form.value.form_value);
        const flag = valueSet.size > 0 && valueSet.size < form.value.option_list.length;
        selectAll.value = valueSet.size == form.value.option_list.length;
        indeterminate.value = flag;
    }
});
// 全选操作时的处理
const handleCheckAllChange = () => {
    if (!isEmpty(input_value.value)) {
        // 判断有多少个符合筛选条件的数据
        const option_list_value = new_option_list.value.map((item: { value: any }) => item.value);
        form.value.form_value = selectAll.value ? cloneDeep(form.value.form_value).concat(option_list_value) : cloneDeep(form.value.form_value).filter((item: any) => !option_list_value.includes(item))
    } else {
        form.value.form_value = selectAll.value ? form.value.option_list.map((item: { value: any }) => item.value) : []
    }
    get_format_checks(form.value, true, 'checkbox');
}
//#endregion
const selected_names = computed(() => {
    const optionList = form.value?.option_list || [];
    const formValue = form.value?.form_value || [];

    const valueSet = new Set(formValue);
    return optionList
    .filter((item: { value: any; name: string }) => valueSet.has(item.value))
    .map((item: { name: string }) => item.name)
    .join(',');
});
// 没有彩色时的公共样式
const common_styles = computed(() => `${ common_store.color_style };padding-left:0rem;padding-right:0rem;`);
const option_style = (val: any) => {
    if (form.value.is_multicolour == '1') {
        return `background:${ val.color };color:${ val.is_other == '1' ? '#141E31' : '#fff'};border-radius:0.4rem;${ common_store.color_style }`;
    } else {
        return common_styles.value;
    }
}
// 用于样式显示
const style_container = computed(() => common_styles_computer(form.value.common_config));
</script>
<style lang="scss" scoped>
.select-tag {
    color: #a8abb2;
}
.search-input, .search-select-input {
    :deep(.el-input__wrapper) {
        box-shadow: none;
        border-radius: 0;
    }
}
.multi-select {
    :deep(.el-select__wrapper) {
        .el-select__selection {
            flex-wrap: nowrap;
            overflow: hidden;
        }
        .el-select__selection.is-near {
            margin-left: 0;
        }
        .el-select__suffix {
            padding-left: 0.2rem;
        }
    }
}
.add-option {
    cursor: pointer;
}
</style>