子组件:
/**
* 评分组件
*/
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;