评分模块子组件:vue3+antd+js

96 阅读1分钟
    <div class="wrap">
        <!-- 评分项 -->
        <div class="paramesItem">
            <div class="params" v-for="(item, index) in paramesItem" :key="item.id">
                <div class="top-info">
                    <span class="parameName item">{{ item.paramsName }}</span>
                    <!-- 评分时会把单项的得分和对应级别背景色呈现在单项评分的上方,无分值时呈现:? -->
                    <!-- 分数背景颜色区间:0 白色 1 绿色 2 黄色 3 红色-->
                    <div class="score item" :style="{background: item.color||''}"><span class="text">{{ item.score || '?' }}</span></div>
                </div>
                <div class="edit">
                    <!-- 输入框 -->
                    <input
                        v-model="item.value" 
                        :placeholder="item.placeholder" 
                        clearable
                        class="input"
                        v-if="item.type=='input'"
                        @blur="getinput(item.id,item.value)"
                        :type="item.leixing"
                        @change="change(item.id, item.value)"
                    />
                    <!-- 下拉框 -->
                    <select v-model="item.value"  v-if="item.type=='select'" @change="change(item.id, item.value)">
                        <option :value="option.name" v-for="option in item.selections">{{ option.name }}</option>
                    </select>
                </div>
            </div>
        </div>
        <!-- 评分分数总分计算结果呈现区 -->
        <div class="content">
            <div class="chart num">
                <div class="total-area" :style="{background:totalColor}"><span class="total-score">{{ totalScore || '?' }}</span></div>
                <div class="icon">
                    <div v-for="(item, index) in color" :style="{background: item, border: item==totalColor?'1px white solid':'none'}" :key="index" class="color"></div>
                </div>
            </div>
            <!-- 护理建议 -->
            <div class="notice num">
                <p class="info">注意:</p>
                <div class="tips">
                    <p class="tip-info" v-for="item in advice" :key="item.id">{{item.id}}、&ensp;{{item.content}}</p>
                </div>
            </div>
        </div>
        <!-- 重置和计算 -->
        <!-- 全部评分项填充完毕,【计算】按钮置为可选状态,点击【计算】显示计算结果和对应的护理建议 -->
        <div class="footer">
            <div class="reset icon" @click="reset()"><span>重置</span></div>
            <div class="comput icon" @click="comput()" :disabled="isComputed" :style="{background:isComputed?'gray':''}"><span>计算</span></div>
        </div>
    </div>
</template>
<script setup>
import {ref, computed, onMounted, watch, defineProps, defineEmits} from "vue";

// 设置信息
const props = defineProps({
    paramesItem: {
        type: Array,
        required: true,
        default: () => []
    },
    totalArr: {
        type: Array,
        required: true,
        default: () => []
    },
});
const emit = defineEmit(['reset','change','input']); //定义一个变量来接收父组件传来的方法
const color = ref(['#d9d9d9', 'green', 'yellow', 'red']);
watch(props,(value,newvalue) => {
    props.paramesItem = newvalue.paramesItem
});
// 计算
const totalScore = ref(0);
const comput = () => {
    totalScore.value && (totalScore.value = 0);    // 计算之前,先清空之前的总和
    props.paramesItem.forEach((item) => {
        totalScore.value += Number(item.score);
    });
    // 计算后,恢复至false
    isComputed.value = false
};

const totalColor = computed(() => {
    const n = totalScore.value;
    const arr = props.totalArr
    for (let i = 0; i <arr.length; i++){
        if(n<=arr[i].area[1] && (n>=arr[i].area[0])){
            advice.value = arr[i].advice;
            return arr[i].color
        }
    }
})

const isComputed = ref(false)

// 建议
const advice = ref([
    {id:1, content:'点击重置按钮清除上一次的评分结果'},
    {id:2, content:'点击重置按钮清除上一次的评分结果'},
    {id:3, content:'点击重置按钮清除上一次的评分结果'},
    {id:4, content:'点击重置按钮清除上一次的评分结果'},
    {id:5, content:'点击重置按钮清除上一次的评分结果'},
])


//重置
const reset = () => {
    emit("reset");
    totalScore.value = 0 // 还原计算值
};
// 输入事件
const getinput=(id, value) => {
    emit("input", {id, value});
}

const change = (id,value) => {
    emit("change", {id, value, totalScore:totalScore.value});
    if(totalScore.value){
        totalScore.value = 0 // 还原计算值
    }
    // 判断是否已计算:1、总分不存在,2、每个输入框都有分数
    if(!totalScore.value && props.paramesItem.every((item) => (item.score!='' || item.score!=''))){
        isComputed.value = true
    } else {
        isComputed.value = false
    }
}

</script>
<style lang="less" scoped>
.wrap {
    margin-left: -8px;
}
.paramesItem {
    margin-top: 10px;
    display: flex;
    flex-wrap: wrap;
    clear: both;
    width: 438px;
	height: 346px;
    overflow-y: auto;
    -ms-overflow-style: none;
    scrollbar-width: none;
    .params {
        margin-bottom: 18px;
        margin-left: 8px;
        width: 138px;
        height: 104px;
        background-color: #3f475e;
        border-radius: 4px;
        padding: 8px;
        .top-info {
            margin-bottom: 8px;
            display: flex;
            flex-wrap: wrap;
            justify-content: space-between;
            .item {
                width: 49%;
            }
            .parameName {
                width: 68px;
                height: 16px;
                font-family: SourceHanSansCN-Regular;
                font-size: 16px;
                font-weight: normal;
                font-stretch: normal;
                letter-spacing: 0px;
                color: #dadada;
            }
            .score {
                width: 22px;
                height: 22px;
                background-color: #eeeeee;
                border-radius: 4px;
                text-align: center;
                line-height: 22px;
                .text {
                    color: #2b2b2b;
                    font-family: SourceHanSansCN-Regular;
                }
            }
        }
        .edit {
            width: 122px;
            height: 60px;
            background-color: #4b5570;
            border-radius: 4px;
            .input {
                background-color: #4b5570;
                border: none;
                outline: 0;
                width: 122px;
                color: #dadada;
            }
            .input::-webkit-input-placeholder{
                color: rgba(255, 255, 255, 0.6);
            }
        }
        select {
            margin-top: 13px;
            background-color: #4b5570;
            border: none;
            color: #dadada;
        }
    }
}
.paramesItem::-webkit-scrollbar {
    display: none;
}
.content {
    display: flex;
    flex-wrap: nowrap;
    justify-content: space-between;
    padding: 0 48px;
    .num {
        width: 49.9%;
    }
    .chart {
        .total-area {
            width: 106px;
            height: 106px;
            background-color: #4a5165;
            border-radius: 50%;
            text-align: center;
            line-height: 106px;
        .total-score {
            width: 24px;
            height: 48px;
            font-family: SourceHanSansCN-Regular;
            font-size: 48px;
            color: #dadada;
        }
    }
        .icon {
            width: 20px;
	        height: 98px;
            margin-left: 117px;
            margin-top: -100px;
            .color {
                width: 20px;
                height: 20px;
                border-radius: 4px;
                margin-bottom: 6px;
            }
        }
    }
    .notice {
        width: 170px;
        height: 140px;
        margin-top: -10px;
        overflow-y: auto;
        .info {
            font-family: SourceHanSansCN-Bold;
            font-size: 18px;
            color: #dadada;
            margin-bottom: 10px;
        }
        .tip-info {
            /* font-family: SourceHanSansCN-Regular; */
            font-size: 16px;
            color: #b8b9bc;
            /* letter-spacing: 2px; */
            margin-bottom: 10px;
            /* text-indent: -16px; */
        }
    }
    .notice::-webkit-scrollbar {
        display: none;
    }
}
.footer {
    display: flex;
    flex-wrap: nowrap;
    justify-content: space-between;
    padding: 0 107px;
    margin-top: 40px;
    .icon {
        width: 49.9%;
        text-align: center;
        line-height: 32px;
        cursor: pointer;
        span {
            width: 28px;
            height: 14px;
            font-family: SourceHanSansCN-Regular;
            font-size: 14px;
            color: #dadada;
        }
    }
    .reset {
        width: 120px;
        height: 32px;
        background-color: #3a4152;
        margin-left: -18px;
    }
    .comput {
        width: 120px;
        height: 32px;
        background-color: #3a4152;
        margin-right: -18px;
    }
}
:deep(input::-webkit-outer-spin-button),
:deep(input::-webkit-inner-spin-button) {
    -webkit-appearance: none !important;
}
:deep(input[type="number"]) {
    -moz-appearance: textfield !important;
}
</style>