当前位置: 首页 > 工具软件 > Taro UI > 使用案例 >

react+taroUI评分组件

长孙谦
2023-12-01

子组件:

/**
 * 评分组件
 */
import { View, Textarea, Image } from "@tarojs/components"
import styles from './index.module.less'
import { AtRate } from 'taro-ui';
import { AtFloatLayout } from "taro-ui";
import { useState, useEffect, useRef } from "react";
import ic_payFinish_smilingFace from '@/assets/images/payFinish/ic_payFinish_smilingFace.png';
import Taro, { useDidShow } from "@tarojs/taro";
import { isEmpty } from "@/utils/utils";

// 默认是5星评价、单项建议选项(optionsListA)、200字建议   return:星数、建议选项name(有CodeValue则return出去)、默认200字以内的意见或建议

// optionsList:{
//     name: '态度很好',
//     status: false,
//     CodeValue: 'zzfw013'
// }
interface RateParam {
    startsMax?: number,//最大评分
    startsSize?: number,//评分星星大小
    startsMargin?: number,//星星间隔
    textareaLength?: number,//意见字数
    optionJudgment?: number,//根据多少星展示不同的选项 (默认3星)
    optionsListA: any,//不满意选项 或 建议选项
    optionsListB?: any,//满意选项
    start?: boolean,//建议选项样式
    submit: (e) => any,
    finish: boolean//父组件接口调通的完成
}
const Rate = (props: RateParam) => {
    const { finish, submit, startsMax = 5, startsSize = 25, startsMargin = 30, textareaLength = 200, optionJudgment = 3, optionsListA, optionsListB = [], start = false } = props;
    useDidShow(() => {
        if (!isEmpty(optionsListB)) {
            setOptionsList(optionsListB);
        } else {
            setOptionsList(optionsListA);
        }
    });

    // ================== 评分模块参数 ==================
    const [isOpened, setIsOpened] = useState<boolean>(false);//半屏弹窗
    const [finishScoreFlg, setFinishScoreFlg] = useState<boolean>(false);// 是否完成评分
    const [finalValue, setFinalValue] = useState<number>(0);// 最终评价分数
    const [dialogDesc, setDialogDesc] = useState<string>(''); // 满意程度
    const dialogDescList: Array<string> = ['非常不满意', '不满意', '一般', '满意', '非常满意'];//
    const [optionsList, setOptionsList] = useState<Array<any>>([]);
    const [textarea, setTextarea] = useState<string>(''); // 意见/建议
    const [rateValue, setRateValue] = useState<number>(0);//评分value

    /** 评分弹窗显示 */
    const showPopup = () => {
        setIsOpened(true);
    }

    /** 评分change */
    const handleChange = (value) => {
        setRateValue(value);
        if (!isEmpty(optionsListB)) {
            if (value <= optionJudgment) {
                setOptionsList(optionsListA);
            } else {
                setOptionsList(optionsListB);
            };
        }
        if (startsMax == 5) {//默认星数为5时才适用
            if (value <= 1) {
                setDialogDesc(dialogDescList[0]);
            } else if (value <= 2 && value > 1) {
                setDialogDesc(dialogDescList[1]);
            } else if (value <= 3 && value > 2) {
                setDialogDesc(dialogDescList[2]);
            } else if (value <= 4 && value > 3) {
                setDialogDesc(dialogDescList[3]);
            } else if (value <= 5 && value > 4) {
                setDialogDesc(dialogDescList[4]);
            };
        }
    }

    /** 悬浮弹窗关闭 */
    const handleClose = () => {
        setIsOpened(false)
    }

    /** 点击满意/不满意 选项 */
    const clickOption = (index: number) => {
        optionsList[index].status = !optionsList[index].status;
        setOptionsList([...optionsList]);
    }

    /**
     * 输入意见/建议
     */
    const textareaInput = (e) => {
        setTextarea(e.detail.value)
    };

    /**
     * 提交满意度调查
     */
    const npsSubmit = () => {
        if (rateValue == 0) {
            Taro.showToast({
                title: '请先评分在提交',
                icon: 'none'
            });
            return
        };
        let recommendSelect: any = [];
        let selectNPSCode: any = [];
        optionsList.forEach(element => {
            if (element.status) {
                recommendSelect.push(element.name);
                if (!isEmpty(element.CodeValue)) {
                    selectNPSCode.push(element.CodeValue);
                }
            };
        });
        recommendSelect = recommendSelect.length >= 1 ? recommendSelect.toString() : '';
        selectNPSCode = selectNPSCode.length >= 1 ? selectNPSCode.toString() : '';
        let data;
        if (optionsList[0].CodeValue) {
            data = {
                gradeNPS: rateValue,//顾客回复NPS分数
                ideaNPS: textarea,//顾客NPS意见和建议
                selectNPS: recommendSelect,//顾客NPS选择项
                selectNPSCode,//NPS选项代码 例:zzfw012,zzfw013,zzfw014
            };
        } else {
            data = {
                gradeNPS: rateValue,//顾客回复NPS分数
                ideaNPS: textarea,//顾客NPS意见和建议
                selectNPS: recommendSelect,//顾客NPS选择项
            };
        }
        // console.log('%c 评分组件return的数据===>', 'color:green;', data);
        submit(data);
    }

    // 父组件完成接口提交
    const prevCountRef = useRef(false);
    useEffect(() => {
        if (prevCountRef.current) {
            setFinishScoreFlg(true);
            setFinalValue(rateValue);
            handleClose();
        } else {
            prevCountRef.current = true;
        }
    }, [finish])

    return (
        <View>
            {/* nps入口模块 */}
            <View className={styles.center}>
                <View className={styles.nps_card}>
                    <View className={styles.nps_title}>
                        <Image className={styles.nps_title_img} src={ic_payFinish_smilingFace} mode="widthFix" />
                        <View className={styles.nps_title_Text}>满意度调查</View>
                    </View>
                    {
                        finishScoreFlg ?
                            <View className={styles.center} style={{ flexDirection: 'column' }}>
                                <View className={styles.van_num}>{finalValue}星</View>
                                <View className={styles.van_finish}>
                                    <AtRate value={finalValue} max={startsMax} size={startsSize} margin={startsMargin} />
                                </View>
                                <View className={styles.van_desc}>评价已收到,感谢您的反馈</View>
                            </View>
                            :
                            <View className={`${styles.center} ${styles.van}`} onClick={showPopup}>
                                <AtRate value={0} max={startsMax} size={startsSize} margin={startsMargin} />
                            </View>
                    }
                </View>
            </View>
            {/* nps评分弹窗 */}
            <AtFloatLayout scrollY={true} isOpened={isOpened} title="满意度调查" onClose={() => handleClose()}>
                {/* <!-- 评分组件 --> */}
                <View className={styles.center} style="flex-direction: column;">
                    <AtRate value={rateValue} max={startsMax} size={startsSize} margin={startsMargin} onChange={(e) => handleChange(e)} />
                    <View className={styles.dialog_num}>{rateValue}星</View>
                    <View className={styles.dialog_desc}>{dialogDesc}</View>
                </View>
                {/* <!-- 分割线 --> */}
                <View className={styles.center}>
                    <View className={styles.dialog_line}></View>
                </View>
                {/* <!-- 原因选择 --> */}
                <View className={styles.dialog_options}>
                    <View className={styles.dialog_option_name}>让您感觉满意/不满意的原因(可多选)</View>
                    <View className={styles.dialog_option_box} style={start ? { justifyContent: 'start' } : {}}>
                        {
                            optionsList.map((item, index) => {
                                return <View onClick={() => clickOption(index)} key={index} className={`${styles.center} ${item.status ? styles.option_selected : styles.option_default}`}>
                                    {item.name}
                                </View>
                            })
                        }
                    </View>
                </View>
                {/* <!-- 意见/建议 --> */}
                <View className={`${styles.center} ${styles.textarea_box}`}>
                    <Textarea className={styles.textarea} placeholder="写下您的意见或建议" onInput={(e) => textareaInput(e)} maxlength={textareaLength} />
                </View>
                <View className={`${styles.halfScreenDialog_footer} ${styles.center}`}>
                    <View className={styles.center} onClick={() => npsSubmit()}>提交</View>
                </View>
            </AtFloatLayout>
        </View>
    );
}
export default Rate

父组件:

import Rate from "@/components/npsRate";
import { useRequest } from "ahooks";
import {submitCouponsNps} from '@/services/subPackages/user/coupon';

const couponsDetails = () => {
     // ================== 评分模块参数 ==================
    const optionsListA: Array<object> = [{
        name: '专业技能差',
        status: false,
        CodeValue: 'zzfw007'
    }, {
        name: '乱收费',
        status: false,
        CodeValue: 'zzfw001'
    }, {
        name: '没有享受到服务',
        status: false,
        CodeValue: 'zzfw010'
    }]; //不满意选项

    const optionsListB: Array<object> = [{
        name: '服务周到',
        status: false,
        CodeValue: 'zzfw012'
    }];//满意选项

    const [ratefinish, setRatefinish] = useState<boolean>(false);

    /**
     * 提交满意度调查
     */
    const submit = (data) => {
        Taro.showLoading({
            title: '评分中',
            mask: true
        });
        Object.keys(data).forEach(element => {
            if (element == 'gradeNPS') {
                data.gradeNPS = data.gradeNPS * 2
            }
        });
        console.log('%c 子传父__提交评价data===>', 'color:#FF770F;', data);
        submitNps(data);
    };

    /** 享权nps提交 */
    const { run: submitNps } = useRequest(submitCouponsNps, {
        manual: true,
        onSuccess: (res) => {
            console.log('提交评价res===>', res);
            Taro.hideLoading();
            Taro.showModal({
                title: '提示',
                content: '提交成功',
                showCancel: false,
                success() {
                    setRatefinish(true);
                }
            })
        }
    })

    return (
        <View>
            <Rate optionsListA={optionsListA} optionsListB={optionsListB} submit={submit} finish={ratefinish} />
        </View >
    )
};

export default couponsDetails;

 类似资料: