match.vue 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. <template>
  2. <div class="svgCup" ref="svgCup">
  3. <img
  4. class="cupTitle"
  5. :style="'width:' + fontSize * 4.6 + 'px'"
  6. :src="require('../../../assets/img/2022worldCup.png')"
  7. />
  8. <div class="guessing" :style="'height: ' + height + 'px'">
  9. <svg
  10. class="svg"
  11. :width="width"
  12. :height="height"
  13. xmlns="http://www.w3.org/2000/svg"
  14. version="1.1"
  15. >
  16. <polyline
  17. v-for="(item, i) in line"
  18. :key="i"
  19. :points="item.points"
  20. :id="'line' + item.id"
  21. :style="
  22. 'fill: none; stroke: ' +
  23. item.color +
  24. '; stroke-width: ' +
  25. item.width
  26. "
  27. />
  28. <image
  29. v-for="(item, i) in flag"
  30. :key="i"
  31. :xlink:href="item[6].file"
  32. :x="item[0]"
  33. :y="item[1]"
  34. :id="'image' + item[5]"
  35. :width="item[2] != 4 ? fontSize : fontSize + 35"
  36. :height="item[2] != 4 ? fontSize / 1.4 : (fontSize + 35) / 1.4"
  37. @click="() => selectFlag(i, item[5])"
  38. />
  39. <text
  40. v-for="(item, i) in flag"
  41. :key="i"
  42. :x="item[4].x"
  43. :y="item[4].y"
  44. :id="'text' + item[5]"
  45. :width="fontSize"
  46. v-text="item[4].text || ''"
  47. :fill="item[4].color"
  48. :font-size="item[4].fontSize"
  49. @click="() => selectFlag(i, item[5])"
  50. ></text>
  51. </svg>
  52. </div>
  53. <br />
  54. <div style="padding: 0 10vw" v-if="!isWin">
  55. <van-button
  56. round
  57. type="primary"
  58. block
  59. @click="upData"
  60. color="linear-gradient(to right, #ff6034, #ee0a24)"
  61. >完成预测</van-button
  62. >
  63. </div>
  64. </div>
  65. </template>
  66. <script setup>
  67. import { ref, reactive, inject } from "vue";
  68. import { Toast } from "vant";
  69. import { forecast } from "@/api/worldCup.js";
  70. // import { onMounted, reactive } from "vue";
  71. // import { isIpad, isIpod, isIphone } from "../../utils/isTerminal";
  72. /**
  73. * window.$originData.orginParames.title 页面标题
  74. * window.$originData.orginParames.parameters 固定参数值
  75. * window.$originData.urlParames url参数
  76. */
  77. const fontSize = inject("fontSize"); // 接收父级传参
  78. const availWidth = inject("availWidth");
  79. const maxcol = inject("maxcol");
  80. const team = inject("team");
  81. const user = inject("user");
  82. const width = ref(availWidth - 4);
  83. const flag = reactive([]);
  84. const line = reactive([]);
  85. const rowHeight = fontSize.value / 1.5 + 30;
  86. const height = ref(rowHeight * maxcol.length + 25);
  87. let textSize = 12;
  88. let id = "";
  89. const isWin = ref(team[0][0] ? team[0][0].isWinner : false);
  90. for (let row = 0; row < maxcol.length; row++) {
  91. let text = "?";
  92. let file = undefined;
  93. if (row == 4) {
  94. file = require("../../../assets/img/default_big.png");
  95. } else {
  96. file = require("../../../assets/img/default.png");
  97. }
  98. const len = maxcol[row];
  99. let fSize = fontSize.value;
  100. let y = row * rowHeight + 10; // 行高
  101. row > 4 && (y += 25);
  102. if (row == 4) fSize += 35;
  103. const colWidth = (width.value - 10) / len; // 列宽
  104. for (let col = 0; col < len; col++) {
  105. const teamItem = team[row][col] || {};
  106. let imgUrl = {
  107. file,
  108. isWinner: teamItem.isWinner,
  109. selectId: teamItem.selectId,
  110. pSelectId: teamItem.pSelectId,
  111. isForeast: teamItem.isForeast,
  112. isED: teamItem.isED,
  113. ed: false,
  114. };
  115. const x = colWidth * col + colWidth / 2;
  116. const textY = y + fSize / 1.5 + textSize;
  117. id = [row, col].join("-");
  118. if (teamItem.team) text = teamItem.team;
  119. if (teamItem.teamlogo) {
  120. imgUrl.file = teamItem.teamlogo;
  121. } else if (!imgUrl.file)
  122. imgUrl.file = require("../../../assets/img/china.png");
  123. // 前两位 坐标, 第三位行数, 第四位 列数, 第五位 文本配置;
  124. flag.push([
  125. x - fSize / 2,
  126. y,
  127. row,
  128. col,
  129. {
  130. text: text,
  131. x: colWidth * col + colWidth / 2 - (text.length * textSize) / 2 + 4,
  132. y: textY + 1,
  133. fontSize: textSize,
  134. color: "#ffffff",
  135. },
  136. id,
  137. imgUrl,
  138. ]);
  139. let points = [];
  140. if (row < 3) points = line1(x, textY, col % 2 === 0, colWidth);
  141. if (row > 2 && row < 5) points = line2(x, textY);
  142. if (row > 5) points = line3(x, y - 8, col % 2 === 0, colWidth);
  143. line.push({
  144. points,
  145. width: 1,
  146. color: "#b8dd8a80",
  147. id,
  148. });
  149. }
  150. }
  151. function line1(x, textY, col, colWidth) {
  152. // 线条 上半部分
  153. let points = [[x, textY + 5].join(","), [x, textY + 10].join(",")];
  154. let nextX = x;
  155. if (col) {
  156. nextX += colWidth / 2;
  157. } else {
  158. nextX -= colWidth / 2;
  159. }
  160. points.push([nextX, textY + 10].join(","));
  161. points.push([nextX, textY + 15].join(","));
  162. return points;
  163. }
  164. function line2(x, textY) {
  165. // 线条 中间部分
  166. return [[x, textY + 5].join(","), [x, textY + 15].join(",")];
  167. }
  168. function line3(x, textY, col, colWidth) {
  169. // 线条 下半部分
  170. let points = [[x, textY + 5].join(","), [x, textY].join(",")];
  171. let nextX = x;
  172. if (col) {
  173. nextX += colWidth / 2;
  174. } else {
  175. nextX -= colWidth / 2;
  176. }
  177. points.push([nextX, textY].join(","));
  178. points.push([nextX, textY - 5].join(","));
  179. return points;
  180. }
  181. function selectFlag(index) {
  182. const select = flag[index];
  183. if (select[2] == 4 || select[4].text === '?' || select[6].isED || select[6].isForeast) return;
  184. const linkSelect = flag[select[3] % 2 === 0 ? index + 1 : index - 1] || undefined;
  185. const startRow = select[2]; // 行数
  186. const startCol = select[3]; // 点击列数
  187. const isDown = startRow < 4 ? 1 : -1; // 递增系数
  188. let Row = startRow + isDown;
  189. let Col = startCol % 2 === 0 ? startCol / 2 : (startCol - 1) / 2;
  190. let coordinate = [];
  191. for (let i = Row; isDown > 0 ? i <= 4 : i >= 4; i += isDown) {
  192. let indexNum = Col;
  193. for (let o = 0; o < i; o++) {
  194. indexNum += maxcol[o];
  195. }
  196. const startText = flag[indexNum][4].text || "";
  197. coordinate.push({
  198. x: Col,
  199. y: i,
  200. indexNum,
  201. });
  202. Col = Col % 2 === 0 ? Col / 2 : (Col - 1) / 2;
  203. if (startText === "?") break;
  204. }
  205. let len = coordinate.length;
  206. if (len < 2) {
  207. // 只有下一行
  208. flag[coordinate[0].indexNum][4].text = select[4].text;
  209. flag[coordinate[0].indexNum][6].file = select[6].file;
  210. return;
  211. }
  212. // 多行已经选择
  213. if(flag[coordinate[len - 1].indexNum][4].text == '?') len--;
  214. for (let i = 0; i < len; i++) {
  215. if (
  216. !linkSelect ||
  217. flag[coordinate[i].indexNum][4].text !== linkSelect[4].text
  218. )
  219. continue;
  220. flag[coordinate[i].indexNum][4].text = select[4].text;
  221. flag[coordinate[i].indexNum][6].file = select[6].file;
  222. }
  223. }
  224. function upData() {
  225. const objFlag = [];
  226. for (let i = 0; i < flag.length; i++) {
  227. const v = flag[i];
  228. if (!v[6].pSelectId || !v[4].text || v[4].text == "?") continue;
  229. let raceId = v[6].pSelectId != -1 ? v[6].pSelectId : 15;
  230. objFlag.push({
  231. raceId,
  232. winner: v[4].text,
  233. });
  234. }
  235. if (objFlag.length < 15) return Toast("请选择完整的冠军之路。");
  236. forecast({
  237. phone: user.phone,
  238. preRaceItems: objFlag,
  239. }).then(() => {
  240. Toast("预测成功!");
  241. });
  242. }
  243. </script>
  244. <style lang="scss" scoped>
  245. .svgCup {
  246. padding-top: 25px;
  247. padding-bottom: 55px;
  248. .cupTitle {
  249. display: block;
  250. margin: 0 auto;
  251. }
  252. .guessing {
  253. margin: 0 5px;
  254. min-height: 100px;
  255. border-radius: 12px;
  256. background-color: rgba($color: #b8dd8a, $alpha: 0.5);
  257. color: #fff;
  258. padding: 0;
  259. position: relative;
  260. .svg {
  261. position: absolute;
  262. z-index: 0;
  263. }
  264. .row {
  265. display: flex;
  266. .col {
  267. flex: 1;
  268. font-size: 10px;
  269. text-align: center;
  270. padding: 5px 0;
  271. }
  272. }
  273. }
  274. }
  275. </style>