Ready.cshtml 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. @using IwbZero.ToolCommon.StringModel
  2. @using WeOnlineApp.Configuration
  3. @using WeOnlineApp.Models.Play
  4. @using WeOnlineApp.TrainingCamp.Dto
  5. @using WeOnlineApp.TrainingCampPlay.Dto
  6. @model WeOnlineApp.Models.Play.CampPlayModel
  7. @{
  8. Layout = "~/Views/Shared/Layout/_Layout.None.cshtml";
  9. ViewBag.PageId = "start";
  10. ViewBag.Title = "等待演练";
  11. CampPlayModel campPlay = Model;
  12. CampPlayDto play = campPlay.Play;
  13. CampDto camp = campPlay.Camp;
  14. CampPlayUserDto playUser = campPlay.PlayUser;
  15. var imagePath = string.IsNullOrEmpty(AbpSession.AvatarImagePath) ? "/Content/Image/user.png" : AbpSession.AvatarImagePath;
  16. }
  17. <style>
  18. body {
  19. --mc: #3168f5;
  20. width: 100vw;
  21. height: 100vh;
  22. color: var(--mc);
  23. background-image: linear-gradient(45deg,#f2f6fe,#f2f6fe);
  24. }
  25. .menu {
  26. --h: 35px;
  27. position: absolute;
  28. top: 30px;
  29. right: 10px;
  30. width: 80%;
  31. padding-right: 20px;
  32. line-height: var(--h);
  33. display: inline-block;
  34. list-style: none;
  35. display: flex;
  36. justify-content: flex-end;
  37. }
  38. .menu a {
  39. color: var(--mc);
  40. padding: 3px 5px;
  41. margin: 0 10px;
  42. line-height: var(--h);
  43. }
  44. .menu a:hover {
  45. border-bottom: 1px solid var(--mc);
  46. }
  47. .header {
  48. margin: 60px 20px 0;
  49. min-height: 80px;
  50. display: flex;
  51. justify-content: center;
  52. align-items: center;
  53. }
  54. .friend-box {
  55. margin: 50px 100px 10px;
  56. min-height: 100px;
  57. display: flex;
  58. flex-wrap: wrap;
  59. justify-content: flex-start;
  60. align-items: center;
  61. border: 2px solid var(--mc);
  62. font-size: 1rem;
  63. border-radius: .75rem;
  64. }
  65. .self-box {
  66. margin: 20px 0;
  67. width: 100%;
  68. min-height: 100px;
  69. display: flex;
  70. flex-direction: column;
  71. justify-content: center;
  72. align-items: center;
  73. }
  74. .self-box > div {
  75. margin-top: 15px;
  76. }
  77. .code {
  78. color: var(--mc);
  79. font-weight: 600;
  80. font-size: 24px;
  81. }
  82. .img-box {
  83. width: auto;
  84. }
  85. img {
  86. width: 100px;
  87. height: 100px;
  88. border: 1px solid #ddd;
  89. border-radius: .5rem;
  90. }
  91. .name {
  92. }
  93. .role {
  94. font-size: 90%;
  95. font-weight: bold;
  96. color: #f08080;
  97. margin-top: 0 !important;
  98. text-align: center;
  99. }
  100. .self-box .img-box img {
  101. width: 200px;
  102. height: 200px;
  103. border: 2px solid #ddd;
  104. border-radius: 50%;
  105. }
  106. .self-box .name {
  107. font-weight: 600;
  108. font-size: 22px;
  109. }
  110. .friend {
  111. margin: 10px;
  112. display: flex;
  113. flex-direction: column;
  114. justify-content: center;
  115. align-items: center;
  116. }
  117. .friend > div {
  118. margin-top: 8px;
  119. }
  120. .friend .img-box {
  121. position: relative;
  122. }
  123. .role-box .select2-selection {
  124. height: 38px;
  125. }
  126. .select2-results__option {
  127. color: var(--mc) !important;
  128. }
  129. .select2-results__option.select2-results__option--highlighted {
  130. color: #fff !important;
  131. background: var(--mc) !important;
  132. }
  133. .select2-results__option[aria-selected=true] {
  134. color: #eee !important;
  135. background: var(--mc) !important;
  136. }
  137. .select2-selection__arrow b {
  138. margin-top: 4px !important;
  139. }
  140. .btn-box {
  141. width: 100px;
  142. margin: 15px auto 0;
  143. }
  144. .btn-box button {
  145. width: 100%;
  146. }
  147. .msg-box {
  148. text-align: center;
  149. font-size: 24px;
  150. }
  151. .start-btn {
  152. display: none;
  153. }
  154. .load-per {
  155. padding: 0 10px;
  156. font-size: 120%;
  157. font-weight: 600;
  158. }
  159. .loading:after {
  160. overflow: hidden;
  161. display: inline-block;
  162. vertical-align: bottom;
  163. animation: ellipsis 2s infinite;
  164. content: "\2026";
  165. }
  166. @@keyframes ellipsis {
  167. from {
  168. width: 2px;
  169. margin-right: 16px;
  170. }
  171. to {
  172. width: 18px;
  173. margin-right: 0;
  174. }
  175. }
  176. </style>
  177. <div class="header">
  178. <h2>@(play.Name) (@(camp?.Name)) </h2>
  179. </div>
  180. <ul class="menu">
  181. <li>
  182. <a href="@Url.Action("Index","Play")"><i class="fa fa-home"></i>&nbsp;&nbsp;返回主页</a>
  183. </li>
  184. <li>
  185. <a href="javascript:void(0)" onclick="Exit()"><i class="fas fa-backspace"></i>&nbsp;&nbsp;退出演练</a>
  186. </li>
  187. <li>
  188. <a href="javascript:void(0)" onclick="LoginOut()"><i class="fas fa-sign-out-alt"></i>&nbsp;&nbsp;注销账号</a>
  189. </li>
  190. </ul>
  191. <div class="self-box">
  192. <div class="img-box">
  193. <img src="@(imagePath)" alt="@(AbpSession.RealName)" />
  194. </div>
  195. <div class="name">@(AbpSession.RealName)</div>
  196. @if (playUser == null)
  197. {
  198. <div class="btn-box"><button type="button" class="btn btn-success" onclick="Join()">加入演练</button></div>
  199. }
  200. else if (playUser.PlayerType == CampPlayerTypeDefinition.Creator)
  201. {
  202. <div class="btn-box start-btn"> <button type="button" class="btn btn-success" onclick="Start()">开始演练</button></div>
  203. <div class="msg-box"> <span class="loading">正在加载演练数据 <span class="load-per">0%</span></span></div>
  204. <div class="code">
  205. <span>邀请码:@(play.InvitationCode)</span>
  206. </div>
  207. }
  208. else
  209. {
  210. string style1 = "display:none", style2 = "display:none";
  211. if (playUser.PlayerState == CampPlayUserStateDefinition.Ready)
  212. {
  213. style1 = "display:block";
  214. }
  215. else if (playUser.PlayerState == CampPlayUserStateDefinition.New || playUser.PlayerState == CampPlayUserStateDefinition.CancelReady)
  216. {
  217. style2 = "display:block";
  218. }
  219. var roleNames = "<option value=\"\">请选择一个角色开始准备</option>"; ;
  220. if (play.PlayRoleNames.IsNotEmpty())
  221. {
  222. var arr = play.PlayRoleNames.Split(',');
  223. foreach (var role in arr)
  224. {
  225. roleNames += "<option value=\"" + role + "\">" + role + "</option>";
  226. }
  227. }
  228. <div id="noReady" style="@(style2)">
  229. <div class="role-box">
  230. <select id="role" class="form-control" style="width: 250px" autocomplete="off">
  231. @(Html.Raw(roleNames))
  232. </select>
  233. </div>
  234. <div class="btn-box"><button type="button" class="btn btn-success" onclick="Ready()">准备演练</button></div>
  235. </div>
  236. <div id="hasReady" style="@(style1)">
  237. <div class="role">@(playUser.Role)</div>
  238. <div class="btn-box"><button type="button" class="btn btn-danger" onclick="Cancel()">取消准备</button></div>
  239. </div>
  240. }
  241. </div>
  242. @if (play.PlayModel == CampPlayModelDefinition.Team)
  243. {
  244. <div class="friend-box"></div>
  245. }
  246. @section scripts
  247. {
  248. <script>
  249. $(function() {
  250. abp.signalr.connect('@(play.InvitationCode)');
  251. PreLoad();
  252. $('#role').select2();
  253. @if (play.PlayModel == CampPlayModelDefinition.Team)
  254. {
  255. <text>
  256. GetPlayUsers();
  257. </text>
  258. }
  259. });
  260. function PreLoad() {
  261. var loadCount = 0, loadTimeout,num = 0,ok=false;
  262. load();
  263. loading();
  264. function load() {
  265. loadCount++;
  266. console.log("加载数据中... " + loadCount);
  267. if (loadCount > 5) {
  268. $('.msg-box').hide();
  269. $('.start-btn').fadeIn();
  270. return;
  271. }
  272. $.iwbAjax5({
  273. url: abp.appUrl + "Query/LoadCampPre?no=@camp.Id&type=1",
  274. timeout: 1000 * 60 * 5,
  275. success:() => {
  276. clearTimeout(loadTimeout);
  277. ok = true;
  278. },
  279. complete: function() {
  280. console.log("加载中... " + loadCount);
  281. clearTimeout(loadTimeout);
  282. loadTimeout = setTimeout(load, 1000 * 60 * 2);
  283. }
  284. });
  285. }
  286. function loading() {
  287. num++;
  288. if (num > 99&&!ok) {
  289. num = 99;
  290. }
  291. $('.msg-box .load-per').html(num + "%");
  292. var delay = 1;
  293. if (!ok) {
  294. if (num < 20+Math.floor(Math.random() * 10)) {
  295. delay =50+ Math.floor(Math.random() * 10);
  296. } else if (num < 50 + Math.floor(Math.random() * 10)) {
  297. delay = 300+Math.floor(Math.random() * 100);
  298. } else if (num < 60 + Math.floor(Math.random() * 5)) {
  299. delay =400+ Math.floor(Math.random() * 600);
  300. } else if (num < 63 + Math.floor(Math.random() * 5)) {
  301. delay = 20+ Math.floor(Math.random() * 30);
  302. } else if (num < 68 + Math.floor(Math.random() * 10)) {
  303. delay = 100+ Math.floor(Math.random() * 50);
  304. } else if (num < 80 + Math.floor(Math.random() * 10)) {
  305. delay =40+ Math.floor(Math.random() * 50);
  306. } else if (num < 95 + Math.floor(Math.random() * 9)) {
  307. delay = 500 + Math.floor(Math.random() * 400);
  308. }
  309. }
  310. if (num < 100) {
  311. setTimeout(loading, 10 * delay);
  312. } else {
  313. $('.msg-box').hide();
  314. $('.start-btn').fadeIn();
  315. }
  316. }
  317. }
  318. function Exit() {
  319. MsgConfirm("退出后无法再加入演练,您确定退出演练吗?",
  320. "退出演练",
  321. function () {
  322. @if (playUser?.PlayerType == CampPlayerTypeDefinition.Creator)
  323. {
  324. <text>
  325. MsgConfirm("演练还未开始!您是房主,退出后演练后会删除演练,确定退出吗?",
  326. "再次确认",
  327. function() {
  328. $.iwbAjax({
  329. url: abp.appUrl + '/CampPlay/ExitPlay?no=@(play.Id)',
  330. success: function() {
  331. window.location.href = "@Url.Action("Start", "Play")";
  332. }
  333. });
  334. });
  335. </text>
  336. }
  337. else
  338. {
  339. <text>
  340. $.iwbAjax({
  341. url: abp.appUrl + '/CampPlay/ExitPlay?no=@(play.Id)',
  342. success: function() {
  343. window.location.href = "@Url.Action("Start", "Play")";
  344. }
  345. });
  346. </text>
  347. }
  348. });
  349. }
  350. function LoginOut() {
  351. MsgConfirm("您确定注销账号吗?",
  352. "注销账号",
  353. function () {
  354. @if (playUser?.PlayerType == CampPlayerTypeDefinition.Creator)
  355. {
  356. <text>
  357. MsgConfirm("您是房主,注销后演练进程无法继续,注销退出吗?",
  358. "再次确认",
  359. function() {
  360. window.location.href = "/Account/LogOut";
  361. });
  362. </text>
  363. }
  364. else
  365. {
  366. <text>
  367. window.location.href = "/Account/LogOut";
  368. </text>
  369. }
  370. });
  371. }
  372. function GetPlayUsers() {
  373. $.iwbAjax4({
  374. url: abp.appUrl + "CampPlay/GetPlayUsers?no=@(play.Id)",
  375. success: function(res) {
  376. FormatterPlayUsers(res);
  377. }
  378. });
  379. }
  380. function FormatterPlayUsers(data) {
  381. var str = "";
  382. if (data && data.length) {
  383. data.forEach(function(v) {
  384. str += '<div class="friend" id="user-{0}">'.format(v.id);
  385. str += FormatterPlayUser(v);
  386. str += '</div>';
  387. });
  388. }
  389. if (str) {
  390. $('.friend-box').html(str);
  391. }
  392. }
  393. function FormatterPlayUser(data) {
  394. var str = "";
  395. if (data) {
  396. var ribbon = '<div class="ribbon-wrapper"><div class="ribbon bg-danger">未准备</div></div>';
  397. if (data.playerType == @(CampPlayerTypeDefinition.Creator)) {
  398. ribbon = '<div class="ribbon-wrapper"><div class="ribbon bg-warning">房主</div></div>';
  399. } else if (data.playerState == @(CampPlayUserStateDefinition.Ready)) {
  400. ribbon = '<div class="ribbon-wrapper"><div class="ribbon bg-success">已准备</div></div>';
  401. }
  402. var img = data.imagePath ? data.imagePath : "/Content/Image/user.png";
  403. str += '<div class="img-box"><img src="{0}" alt="{1}" />{2}</div>'.format(img, data.playerName, ribbon);
  404. str += '<div class="name">{0}</div>'.format(data.playerName);
  405. str += '<div class="role">{0}</div>'.format(data.role ? data.role : "未准备");
  406. }
  407. return str;
  408. }
  409. </script>
  410. <script>
  411. function Join() {
  412. MsgConfirm("确认加入演练吗?",
  413. "加入演练",
  414. function() {
  415. $.iwbAjax1({
  416. url: abp.appUrl + "/CampPlay/Join",
  417. data: { id: '@(play.Id)' },
  418. success: function() {
  419. window.location.reload();
  420. }
  421. });
  422. });
  423. }
  424. function Cancel() {
  425. MsgConfirm("确认取消准备吗?",
  426. "取消准备",
  427. function() {
  428. $.iwbAjax1({
  429. url: abp.appUrl + "/CampPlay/CancelReady",
  430. data: { id: '@(play.Id)' },
  431. success: function() {
  432. $('#hasReady').hide();
  433. $('#noReady').fadeIn(500);
  434. }
  435. });
  436. });
  437. }
  438. function Ready() {
  439. var role = $('#role').val();
  440. if (role) {
  441. $.iwbAjax4({
  442. url: abp.appUrl + "/CampPlay/Ready",
  443. data: { id: '@(play.Id)', role: role },
  444. success: function() {
  445. $('#noReady').hide();
  446. $('#hasReady').fadeIn(500);
  447. }
  448. });
  449. } else {
  450. abp.message.warn('请选择一个角色!');
  451. }
  452. }
  453. function Start() {
  454. var msg = "确认开始演练吗?";
  455. MsgConfirm(msg,
  456. "开始演练",
  457. function() {
  458. $.iwbAjax4({
  459. url: abp.appUrl + "/CampPlay/Start",
  460. data: { id: '@(play.Id)' },
  461. success: function() {
  462. abp.message.success("演练启动完成。");
  463. },
  464. error: function() {
  465. }
  466. });
  467. });
  468. }
  469. </script>
  470. <script id="hub-s">
  471. iwbHub.client.getReloadPage = function (msg) {
  472. console.log('getReloadPage: ', msg);
  473. if (msg) {
  474. try {
  475. var data = JSON.parse(msg);
  476. if (data.no=='@(play.Id)') {
  477. window.location.reload();
  478. }
  479. } catch (e) {
  480. console.log('getReloadPage: ', e);
  481. }
  482. }
  483. };
  484. iwbHub.client.getUserChange = function (msg) {
  485. console.log('getUserChange: ', msg);
  486. if (msg) {
  487. try {
  488. var data = JSON.parse(msg);
  489. if (data) {
  490. var str = FormatterPlayUser(data);
  491. var $user = $('#user-' + data.id);
  492. if ($user.length > 0) {
  493. $user.html(str);
  494. } else {
  495. str = '<div class="friend" id="user-{0}">{1}</div>'.format(data.id, str);
  496. $('.friend-box').append(str);
  497. }
  498. }
  499. } catch (e) {
  500. console.log('getUserChange: ', e);
  501. }
  502. }
  503. };
  504. iwbHub.client.getUserExit = function (msg) {
  505. console.log('getUserExit: ', msg);
  506. if (msg) {
  507. try {
  508. var data = JSON.parse(msg);
  509. if (data) {
  510. var $user = $('#user-' + data.id);
  511. if ($user.length > 0) {
  512. $user.remove();
  513. }
  514. }
  515. } catch (e) {
  516. console.log('getUserExit: ', e);
  517. }
  518. }
  519. };
  520. @if (play.PlayModel == CampPlayModelDefinition.Team&& playUser?.PlayerType != CampPlayerTypeDefinition.Creator)
  521. {
  522. <text>
  523. iwbHub.client.getCreatorExit = function (msg) {
  524. console.log('getCreatorExit: ', msg);
  525. if (msg) {
  526. try {
  527. var data = JSON.parse(msg);
  528. if (data) {
  529. abp.message.warn('房主已退出演练,演练已结束!',"演练结束").done(function() {
  530. window.location.href = "@Url.Action("Start", "Play")";
  531. });
  532. }
  533. } catch (e) {
  534. console.log('getCreatorExit: ', e);
  535. }
  536. }
  537. };
  538. </text>
  539. }
  540. </script>
  541. }