ResultView.vue 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. <script setup lang="ts">
  2. import {
  3. ref,
  4. reactive,
  5. toRefs,
  6. onMounted,
  7. watch,
  8. computed,
  9. onBeforeUnmount,
  10. } from "vue";
  11. import NavBarPage from "../components/NavBarPage.vue";
  12. import randarPage from "./result/randarPage.vue";
  13. import { useRoute } from "vue-router";
  14. import { fetchTaskScore } from "./utils/api";
  15. import { Toast } from "vant";
  16. const route = useRoute();
  17. const score = ref(0);
  18. const data = ref(null);
  19. const scoresList = ref(null);
  20. const defectsList = ref(null);
  21. const taskId = computed(() => route.query.conversationId); // 会话ID "2c64eb8b69be432ca0bb9ae55bc78def"
  22. const randarlist = ref([0, 0, 0, 0, 0,0]);
  23. const loading = ref(false);
  24. const nameMapping = {
  25. settle_reason: "提前结清原因(10分)",
  26. speech_retention: "话术挽留客户(20分)",
  27. strategic_retention: "策略挽留客户(30分)",
  28. other_retentions: "其他挽留客户(10分)",
  29. call_ratio:"通话比例(10分)",
  30. persistence:"坚持力度(20分)",
  31. penalty_points: "扣分项",
  32. defects: "评分详解"
  33. };
  34. const handleResult = async () => {
  35. let res;
  36. let shouldContinue = true; // 控制是否继续调用接口的标志
  37. loading.value = true;
  38. while (shouldContinue) {
  39. res = await fetchTaskScore(taskId.value);
  40. if (res.code !== 200) {
  41. // 当返回错误时,停止调用接口
  42. loading.value = false
  43. shouldContinue = false;
  44. } else if (res.body && Object.keys(res.body).length !== 0) {
  45. // 当res.body有值时,停止调用接口
  46. data.value = res.body;
  47. shouldContinue = false;
  48. } else {
  49. await new Promise((resolve) => setTimeout(resolve, 3000));
  50. }
  51. }
  52. if (res && res.code === 200 && res.body) {
  53. loading.value = false;
  54. const scores = extractScores(res.body);
  55. score.value = scores.reduce((sum, score) => sum + score, 0);
  56. scoresList.value = Object.keys(res.body).reduce((acc, key) => {
  57. if (key !== "defects") {
  58. acc[key] = {
  59. ...res.body[key],
  60. name: nameMapping[key], // 添加 name 字段
  61. };
  62. }
  63. return acc;
  64. }, {});
  65. defectsList.value = res.body.defects;
  66. console.log(defectsList.value, '000000000');
  67. const obj = extractScores(scoresList.value);
  68. randarlist.value = Object.values(obj);
  69. }
  70. };
  71. // 处理“分”字
  72. const extractScores = (data) => {
  73. return Object.values(data).map((item) => {
  74. // 确保 score 是一个字符串,并且去除可能的 "分" 字
  75. let scoreStr = String(item.score).replace("分", "");
  76. // 将 score 转换为整数,如果转换失败则返回 0
  77. const score = parseInt(scoreStr, 10);
  78. return isNaN(score) ? 0 : score;
  79. });
  80. };
  81. onMounted(() => {
  82. handleResult();
  83. window.addEventListener("popstate", function (event) {
  84. // 执行一些操作,例如关闭当前页面或跳转到其他页面
  85. window.location.href = "/#/home";
  86. });
  87. });
  88. onBeforeUnmount(() => {
  89. window.removeEventListener("popstate", function (event) {
  90. // 执行一些操作,例如关闭当前页面或跳转到其他页面
  91. window.location.href = "/#/home";
  92. });
  93. });
  94. </script>
  95. <template>
  96. <div class="result" style="overflow: hidden">
  97. <NavBarPage title="考试" type="home" />
  98. <div style="height: 46px"></div>
  99. <div class="score">
  100. <span>最终得分</span>
  101. <p class="score-num">
  102. <span style="margin-right: 0.2rem;">{{ score }}</span>分
  103. </p>
  104. </div>
  105. <div style="height: 9.06rem; visibility: hidden"></div>
  106. <div class="content">
  107. <div style="width: 100vw; height: 19.06rem">
  108. <randarPage :randarList="randarlist" />
  109. </div>
  110. <div class="loading" v-show="loading">
  111. <van-loading color="#0094ff" size="26px" vertical>加载中...</van-loading>
  112. </div>
  113. <div class="standard">
  114. <div class="standard-title">
  115. <img src="../assets/robot.jpg" alt="" />
  116. <span>评分标准</span>
  117. </div>
  118. <div class="standard-content" v-for="(item, key) in scoresList" :key="key">
  119. <div class="standard-subtitle">
  120. <span class="pro">{{ item.name == "扣分项" ? item.name : `${item.name}` }}:</span>
  121. <span>{{ item.score }}</span>
  122. </div>
  123. <p>
  124. <span>得分原因:</span>
  125. <span>{{ item.reason }}</span>
  126. </p>
  127. </div>
  128. <div class="standard-content" style="margin-top: 1.5rem;">
  129. <div class="standard-title">
  130. <img src="../assets/robot.jpg" alt="" />
  131. <span>评分详解</span>
  132. </div>
  133. <div class="standard-content" v-for="(item, index) in defectsList" :key="index">
  134. <div class="standard-subtitle">
  135. <span class="pro">轮次{{item.rounds}}:</span>
  136. </div>
  137. <p>
  138. <span>原句:</span>
  139. <span>{{ item.original_sentence }}</span>
  140. </p>
  141. <p>
  142. <span>不足:</span>
  143. <span>{{ item.defect }}</span>
  144. </p>
  145. <p>
  146. <span>建议:</span>
  147. <span>{{ item.example }}</span>
  148. </p>
  149. </div>
  150. </div>
  151. </div>
  152. </div>
  153. </div>
  154. </template>
  155. <style scoped lang="less">
  156. html,
  157. body {
  158. margin: 0;
  159. padding: 0;
  160. height: 100vh;
  161. overflow: hidden;
  162. /* 禁止页面整体滚动 */
  163. }
  164. .result {
  165. width: 100%;
  166. height: 100%;
  167. /* height: 100vh; */
  168. overflow: hidden;
  169. }
  170. .score {
  171. position: fixed;
  172. z-index: 999;
  173. width: 100%;
  174. height: 9.06rem;
  175. background-color: rgba(243, 249, 255, 1);
  176. display: flex;
  177. flex-direction: column;
  178. align-items: center;
  179. justify-content: center;
  180. span {
  181. display: flex;
  182. width: 5.06rem;
  183. height: 2.88rem;
  184. font-weight: bold;
  185. line-height: 2.88rem;
  186. color: rgba(64, 149, 229, 1);
  187. font-size: 1rem;
  188. text-align: center;
  189. font-family: Times New Roman-regular;
  190. }
  191. .score-num {
  192. display: flex;
  193. align-items: last baseline;
  194. color: rgba(64, 149, 229, 1);
  195. font-size: 1rem;
  196. span {
  197. display: block;
  198. width: 5.06rem;
  199. height: 3.31rem;
  200. line-height: 4.25rem;
  201. font-size: 3rem;
  202. text-align: center;
  203. font-family: Times New Roman-regular;
  204. }
  205. }
  206. }
  207. .content {
  208. width: 100%;
  209. height: 100%;
  210. overflow: scroll;
  211. }
  212. .standard-title {
  213. display: flex;
  214. align-items: center;
  215. padding: 0 0.94rem;
  216. margin-bottom: 0.63rem;
  217. img {
  218. width: 1.5rem;
  219. height: 1.5rem;
  220. }
  221. span {
  222. display: inline-block;
  223. width: 4rem;
  224. height: 1.44rem;
  225. line-height: 1.44rem;
  226. margin-left: 0.33rem;
  227. color: rgba(64, 149, 229, 1);
  228. font-size: 1rem;
  229. text-align: center;
  230. font-family: Times New Roman-regular;
  231. }
  232. }
  233. .standard-subtitle {
  234. padding: 0.56rem 1rem;
  235. height: 1.06rem;
  236. font-size: 0.88rem;
  237. font-family: Times New Roman-regular;
  238. span {
  239. color: rgba(64, 149, 229, 1);
  240. font-weight: 600;
  241. }
  242. .pro {
  243. display: inline-block;
  244. height: 1.06rem;
  245. line-height: 1.06rem;
  246. padding: 0 0.3rem;
  247. font-weight: normal;
  248. color: rgba(102, 102, 102, 1);
  249. border-left: 0.3rem solid rgba(64, 149, 229, 1);
  250. }
  251. }
  252. .standard-content p {
  253. padding: 0 1.63rem;
  254. margin-bottom: 0.31rem;
  255. line-height: 1.25rem;
  256. color: rgba(102, 102, 102, 1);
  257. font-size: 0.88rem;
  258. text-align: left;
  259. font-family: SourceHanSansSC-bold;
  260. }
  261. .standard-content p span:nth-child(1) {
  262. font-weight: 600;
  263. }
  264. .loading {
  265. position: fixed;
  266. top: 0;
  267. left: 0;
  268. width: 100%;
  269. height: 100%;
  270. background-color: rgba(0, 0, 0, 0.5);
  271. display: flex;
  272. justify-content: center;
  273. align-items: center;
  274. z-index: 9999;
  275. }
  276. </style>