message-rating-star.vue 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. <template>
  2. <div class="message-rating-star">
  3. <p class="rating-head">
  4. {{ props.ratingTemplate.head }}
  5. </p>
  6. <div class="rating-card">
  7. <span class="card-title">请对本次服务进行评价</span>
  8. <div class="card-wrapper">
  9. <div style="max-width: 200px">
  10. <div
  11. v-for="(item, index) in starList"
  12. :key="index"
  13. style="display: inline-block"
  14. @click="setValue(index)"
  15. @mouseenter="setHoverValue(index)"
  16. @mouseleave="setHoverValue(-1)"
  17. >
  18. <Icon
  19. v-if="item === 1"
  20. :src="star"
  21. width="30px"
  22. height="30px"
  23. />
  24. <Icon
  25. v-else
  26. :src="starLine"
  27. width="30px"
  28. height="30px"
  29. />
  30. </div>
  31. </div>
  32. </div>
  33. <div :style="{ marginTop: 10 + 'px', marginBottom: 10 + 'px' }">
  34. {{
  35. hoverValue === -1
  36. ? value === -1
  37. ? "如果满意请给好评哦~"
  38. : desc[value]
  39. : desc[hoverValue]
  40. }}
  41. </div>
  42. <button
  43. class="submit-button"
  44. :disabled="hasReply || hasExpire"
  45. @click="submitRatingStar"
  46. >
  47. 提交评价
  48. </button>
  49. </div>
  50. <p
  51. v-if="hasReply"
  52. class="rating-tail"
  53. :style="{
  54. marginTop: 20 + 'px',
  55. }"
  56. >
  57. {{ props.ratingTemplate.tail }}
  58. </p>
  59. </div>
  60. </template>
  61. <script lang="ts">
  62. import vue from '../../adapter-vue';
  63. import { CUSTOM_MESSAGE_SRC } from '../../constant';
  64. import { ratingTemplateType } from '../../interface';
  65. import star from '../../assets/star.png';
  66. import starLine from '../../assets/starLine.png';
  67. import Icon from '../customer-icon.vue';
  68. const { computed, ref, watchEffect } = vue;
  69. interface Props {
  70. ratingTemplate: ratingTemplateType;
  71. }
  72. export default {
  73. components: {
  74. Icon,
  75. },
  76. props: {
  77. ratingTemplate: {
  78. type: Object as () => ratingTemplateType,
  79. default: () => ({}),
  80. },
  81. },
  82. emits: ['sendMessage'],
  83. setup(props: Props, { emit }) {
  84. const hasReply = ref<boolean>(false);
  85. const sessionId = ref<string>('');
  86. const value = ref<number>(-1);
  87. const hoverValue = ref<number>(-1);
  88. const hasExpire = ref<boolean>(false);
  89. watchEffect(() => {
  90. sessionId.value = props.ratingTemplate.sessionId || '';
  91. if (props.ratingTemplate.selected != undefined) {
  92. for (let i = 0; i < props.ratingTemplate.menu.length; i++) {
  93. if (props.ratingTemplate.menu[i].id == props.ratingTemplate.selected.id) {
  94. hasReply.value = true;
  95. value.value = i;
  96. break;
  97. }
  98. }
  99. }
  100. const timestamp = Math.floor(new Date().getTime() / 1000);
  101. if (timestamp > props.ratingTemplate.expireTime) {
  102. hasExpire.value = true;
  103. }
  104. });
  105. const desc = computed(() => {
  106. return props.ratingTemplate?.menu.map((item) => {
  107. return item.content;
  108. });
  109. });
  110. const starList = computed(() => {
  111. return props.ratingTemplate?.menu.map((item, index) => {
  112. if (hoverValue.value !== -1) {
  113. return index <= hoverValue.value ? 1 : 0;
  114. } else {
  115. return index <= value.value ? 1 : 0;
  116. }
  117. });
  118. });
  119. const setValue = (val: number) => {
  120. if (hasReply.value) {
  121. return;
  122. }
  123. value.value = val;
  124. };
  125. const setHoverValue = (value: number) => {
  126. if (hasReply.value) {
  127. return;
  128. }
  129. hoverValue.value = value;
  130. };
  131. const submitRatingStar = async () => {
  132. if (value.value < 0) {
  133. return;
  134. }
  135. const submitData = {
  136. data: JSON.stringify({
  137. src: CUSTOM_MESSAGE_SRC.MENU_SELECTED,
  138. menuSelected: {
  139. id: props.ratingTemplate.menu[value.value].id,
  140. content: props.ratingTemplate.menu[value.value].content,
  141. sessionId: sessionId.value,
  142. },
  143. customerServicePlugin: 0,
  144. }),
  145. };
  146. hasReply.value = true;
  147. emit('sendMessage', submitData);
  148. };
  149. return {
  150. props,
  151. hasReply,
  152. sessionId,
  153. value,
  154. hoverValue,
  155. hasExpire,
  156. desc,
  157. starList,
  158. setValue,
  159. setHoverValue,
  160. submitRatingStar,
  161. star,
  162. starLine,
  163. };
  164. },
  165. };
  166. </script>
  167. <style lang="scss" scoped>
  168. .rating-head {
  169. font-size: 14px;
  170. font-weight: 400;
  171. color: #999;
  172. }
  173. .rating-tail {
  174. font-size: 14px;
  175. font-weight: 400;
  176. color: #999;
  177. }
  178. .card-title {
  179. font-size: 14px;
  180. font-weight: 500;
  181. }
  182. .rating-card {
  183. min-width: 270px;
  184. width: 50%;
  185. background: #fbfbfb;
  186. border-radius: 20px;
  187. border: 0;
  188. margin-top: 10px;
  189. padding-top: 20px;
  190. padding-bottom: 20px;
  191. button:disabled {
  192. background: #d8d8d8;
  193. }
  194. }
  195. .message-rating-star {
  196. text-align: center;
  197. display: flex;
  198. flex-flow: column wrap;
  199. justify-content: center;
  200. padding-bottom: 30px;
  201. align-items: center;
  202. }
  203. .card-wrapper {
  204. display: flex;
  205. flex-wrap: wrap;
  206. justify-content: center;
  207. padding-top: 10px;
  208. }
  209. .submit-button {
  210. width: 50%;
  211. height: 50px;
  212. background-color: #0365f9;
  213. font-size: 18px;
  214. font-weight: 400;
  215. color: white;
  216. border: 0;
  217. border-radius: 8px;
  218. cursor: pointer;
  219. }
  220. </style>