PlayList.cshtml 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. @using WeOnlineApp.Configuration
  2. @{
  3. Layout = "~/Views/Shared/Layout/_Layout.Play.cshtml";
  4. ViewBag.PageId = "start";
  5. ViewBag.Title = "演练课程";
  6. }
  7. <link href="~/Content/Libs/jstree/themes/proton/style.min.css" rel="stylesheet" />
  8. @Html.Partial("~/Views/Play/_BoxBaseStyle.cshtml")
  9. <style>
  10. .jstree-proton-responsive .jstree-wholerow {
  11. border-top: 1px solid rgba(0,0,0,.05);
  12. background: var(--mainBgColor);
  13. }
  14. .jstree-proton .jstree-hovered, .jstree-proton .jstree-wholerow-hovered {
  15. color: var(--mainColor);
  16. background: var(--mainBgColor2);
  17. }
  18. .jstree-proton .jstree-clicked, .jstree-proton .jstree-wholerow-clicked {
  19. color: #fff;
  20. background: var(--mainColor);
  21. }
  22. .box .box-body {
  23. padding: 10px;
  24. }
  25. .box.tree-box {
  26. height: calc(100vh - 35px);
  27. }
  28. .box.subject-box {
  29. height: calc(100vh - 335px);
  30. margin-bottom: 20px;
  31. }
  32. .box.subject-box .box-body {
  33. height: calc(100% - 40px);
  34. }
  35. #subject-info {
  36. padding-left: 0;
  37. padding-right: 0;
  38. }
  39. .subject-info-box {
  40. margin: 8px 0;
  41. --mainColor: #afafaf;
  42. border: 1px solid var(--mainColor);
  43. }
  44. .subject-info-box:first-child {
  45. margin-top: 0;
  46. }
  47. .subject-info-box .box-header {
  48. position: relative;
  49. font-size: 16px;
  50. }
  51. .subject-info-box .btn {
  52. min-width: 80px;
  53. }
  54. .subject-info-box .tool-btn {
  55. position: absolute;
  56. top: -3px;
  57. right: 12px;
  58. }
  59. .subject-info-box .tool-td .btn {
  60. border-radius: 30px;
  61. padding: 1px 0;
  62. font-size: 60%;
  63. min-width: 60px;
  64. }
  65. .subject-box table {
  66. margin-bottom: 0;
  67. }
  68. .subject-box table th, .subject-box table td {
  69. width: 20%;
  70. text-align: center;
  71. }
  72. .box.chat-box, .box.question-box {
  73. height: 280px;
  74. }
  75. .no-data {
  76. display: flex;
  77. color: #ff4500;
  78. font-size: 26px;
  79. font-weight: 600;
  80. width: 100%;
  81. height: 150px;
  82. justify-content: center;
  83. align-items: center;
  84. }
  85. .tool-box {
  86. padding: 0 0 5px;
  87. display: flex;
  88. width: 100%;
  89. }
  90. .tool-box span {
  91. text-align: center;
  92. width: 50%;
  93. padding: 5px;
  94. cursor: pointer;
  95. background: #000000;
  96. background: rgba(0,0,0,0.3);
  97. border: 1px solid #ddd;
  98. }
  99. .tool-box span:hover {
  100. background: #000000;
  101. background: rgba(0,0,0,0.4);
  102. }
  103. .direct-chat-msg.right .direct-chat-text {
  104. background: var(--mainColor);
  105. color: #fff;
  106. }
  107. .direct-chat-msg.right .direct-chat-text::after, .direct-chat-msg.right .direct-chat-text::before {
  108. border-left-color: var(--mainColor);
  109. }
  110. .tool-nav {
  111. background: #c7f0f3;
  112. }
  113. .tool-nav .nav-link {
  114. padding: 5px 16px;
  115. font-size: 14px;
  116. color: var(--mainColor);
  117. }
  118. .tool-nav .nav-link.active {
  119. background: var(--mainColor);
  120. color: #fff;
  121. }
  122. </style>
  123. <div style="padding:10px 15px;">
  124. <div class="row">
  125. <div class="col-sm-3 ">
  126. <div class="box tree-box">
  127. <div class="box-header">课程体系</div>
  128. <div id="subject-type-tree" class="box-body">
  129. </div>
  130. </div>
  131. </div>
  132. <div class="col-sm-9">
  133. <div class="row">
  134. <div class="box subject-box">
  135. <div class="box-header">
  136. <span>演练助手</span>
  137. <div class="back-btn">
  138. <button type="button" class="btn btn-outline-light btn-sm mr-3" style="width: 180px;" onclick="window.open('/play/code/', '_blank');">填写邀请码加入演练</button>
  139. </div>
  140. </div>
  141. <div class="box-body">
  142. <div class="box-header" id="subject-type-name" style="background: var(--mainBgColor2);color: var(--mainColor);font-size: 80%;padding: 0;line-height: 30px;
  143. font-weight: 800;"></div>
  144. <div id="subject-info" class="box-body">
  145. <div class=body-content></div>
  146. </div>
  147. </div>
  148. </div>
  149. </div>
  150. <div class="row" style="margin: 0 -15px;">
  151. <div class="col-sm-5">
  152. <div class="box chat-box">
  153. <div class="box-header">聊天室</div>
  154. <div class="box-body" style="padding: 0;height: calc(100% - 50px)">
  155. <div class="card direct-chat" style="z-index: 1000;color: #111;background: transparent; margin: 0;height: 100%">
  156. <div class="card-body" id="chat-info">
  157. <div class="direct-chat-messages body-content" style="height: 100%;overflow: unset;"></div>
  158. </div>
  159. <div class="card-footer" style="padding: 5px 10px;">
  160. <div class="input-group input-group-sm">
  161. <input type="text" id="chat-message" name="chat-message" placeholder="请输入..." class="form-control">
  162. <span class="input-group-append">
  163. <button type="button" onclick="SendChat()" class="btn btn-info">发送</button>
  164. </span>
  165. </div>
  166. </div>
  167. </div>
  168. </div>
  169. </div>
  170. </div>
  171. <div class="col-sm-7">
  172. <div class="box question-box">
  173. <div class="box-header">
  174. <span>
  175. 答疑室
  176. <small id="q-camp-name"></small>
  177. </span>
  178. <div class="back-btn">
  179. <button type="button" class="btn btn-outline-light btn-sm mr-3" style="width: 80px;" onclick="window.Question(this)">我要提问</button>
  180. <button type="button" class="btn btn-outline-success btn-sm" style="width: 80px;" onclick="window.Answer(this)">我要答疑</button>
  181. </div>
  182. </div>
  183. <div id="question-info" class="box-body">
  184. <div class="tool-nav">
  185. <ul class="nav nav-tabs" role="tablist">
  186. <li class="nav-item">
  187. <a class="nav-link active" data-type="1" href="javascript:void(0)" onclick="window.LoadQuestion(this)">答疑广场</a>
  188. </li>
  189. <li class="nav-item">
  190. <a class="nav-link" data-type="2" href="javascript:void(0)" onclick="window.LoadQuestion(this)">我的问题</a>
  191. </li>
  192. <li class="nav-item">
  193. <a class="nav-link" data-type="3" href="javascript:void(0)" onclick="window.LoadQuestion(this)">我的收藏</a>
  194. </li>
  195. </ul>
  196. </div>
  197. <div class=body-content>
  198. @Html.Partial("~/Views/Play/_Question.cshtml")
  199. </div>
  200. </div>
  201. </div>
  202. </div>
  203. </div>
  204. </div>
  205. </div>
  206. </div>
  207. @section scripts
  208. {
  209. <script src="~/Content/Libs/jstree/jstree.min.js"></script>
  210. <script>
  211. var curSubjectCategoryNo = '', curCampNo='', curCampName='';
  212. var isInit = false;
  213. function GetNode(node, callback) {
  214. $.iwbAjax4({
  215. url: abp.appUrl + 'Query/GetChildSubjectCategory',
  216. data: { id: node.id },
  217. success: function(res) {
  218. var data = [];
  219. if (!isInit) {
  220. isInit = true;
  221. for (var i = 0; i < res.length; i++) {
  222. var item = res[i];
  223. if (i == 0) {
  224. curSubjectCategoryNo = item.id;
  225. $('#subject-type-name').html(item.text);
  226. }
  227. item.state = {
  228. opened: true,
  229. selected: true
  230. };
  231. data.push(item);
  232. }
  233. } else {
  234. data = res;
  235. }
  236. if (callback) {
  237. callback.call(this, data);
  238. } else {
  239. $("#plan-tree").html("暂无数据!");
  240. }
  241. }
  242. });
  243. }
  244. $(function() {
  245. abp.signalr.connect('@(IwbConsts.ChatNo)');
  246. OverlayScrollbar($('#subject-info'));
  247. OverlayScrollbar($('#chat-info'));
  248. OverlayScrollbar($('#question-info'));
  249. $('#chat-message').on('keypress',function(event){
  250. if(event.keyCode == "13") {
  251. SendChat();
  252. return false;
  253. }
  254. return true;
  255. });
  256. $('#subject-type-tree')
  257. .jstree({
  258. 'core': {
  259. 'data': GetNode,
  260. 'strings': {
  261. 'Loading ...': '请稍后...'
  262. },
  263. 'force_text': true,
  264. 'check_callback': true,
  265. 'themes': {
  266. 'name': 'proton',
  267. 'responsive': true,
  268. 'variant': 'large'
  269. }
  270. },
  271. 'plugins': ['wholerow'] // 'state',
  272. })
  273. .on('ready.jstree',
  274. function(e, data) {
  275. //console.log('000', e, data);
  276. @*var inst = data.instance,
  277. obj = inst.get_node('@(IwbConsts.SubjectCategoryRootNo)');
  278. inst.open_node(obj);
  279. inst.select_node(obj);*@
  280. GetSubject();
  281. if (window.LoadQuestion) {
  282. window.LoadQuestion();
  283. }
  284. })
  285. //.on('create_node.jstree', function (e, data) {console.log(1);}).on('rename_node.jstree', function (e, data) {console.log(2);}).on('delete_node.jstree', function (e, data){console.log(3);}).on('changed.jstree', function (e, data) {console.log('222');})
  286. .on('activate_node.jstree',
  287. function(e, data) {
  288. //console.log('111',data);
  289. curSubjectCategoryNo = data.node.id;
  290. $('#subject-type-name').html(data.node.text);
  291. GetSubject();
  292. curCampNo = '';
  293. curCampName = '';
  294. $('#q-camp-name').text('');
  295. if (window.LoadQuestion) {
  296. window.LoadQuestion();
  297. }
  298. });
  299. });
  300. function GetSubject() {
  301. if (curSubjectCategoryNo) {
  302. $.iwbAjax4({
  303. url: abp.appUrl + 'Query/QueryCampBySc?no=' + curSubjectCategoryNo,
  304. success: function(res) {
  305. SubjectFormatter(res);
  306. }
  307. });
  308. }
  309. }
  310. function SubjectFormatter(data) {
  311. var str = '';
  312. if (data && data.length) {
  313. data.forEach(function(v) {
  314. str += SubjectInfoFormatter(v);
  315. });
  316. }
  317. if (str) {
  318. $('#subject-info .body-content').html(str);
  319. } else {
  320. $('#subject-info .body-content').html('<div class="no-data">暂无课程</div>');
  321. }
  322. }
  323. function SubjectInfoFormatter(data) {
  324. var str = '';
  325. if (data) {
  326. str += '<div class="subject-info-box">';
  327. str +=
  328. '<div class="box-header">{0}<div class="tool-btn"><span data-id="{1}" onclick="SubjectDetail(\'{1}\')" class="btn btn-outline-info btn-sm mr-3">课程介绍</span><span data-id="{1}" onclick="SubjectStudy(\'{1}\')" class="btn btn-outline-success btn-sm mr-3">预演学习</span><span data-id="{1}" onclick="SubjectCreate(\'{1}\')" class="btn btn-info btn-sm">选择课程</span></div></div>'.format(data.campName,data.id);
  329. str +=
  330. '<table class="table"><thead><tr><th>演练主题</th><th>演练时长</th><th>演练积分</th><th>截止日期</th><th></th></tr></thead>';
  331. str +=
  332. '<tbody><tr><td>{2}</td><td>{3}&nbsp;&nbsp;分钟</td><td>{4}&nbsp;&nbsp;分</td><td>{5}</td><td class="tool-td"><span data-id="{0}" class="btn btn-info btn-sm float-right">聊天</span><span data-id="{0}" class="btn btn-info btn-sm mr-3 float-right" onclick="QueryQuestion(\'{0}\',\'{1}\')">答疑</span></td></tr></tbody>'
  333. .format(data.id,
  334. data.campName,
  335. data.packageName,
  336. data.maxTrainingMinute,
  337. data.subjectPoint,
  338. new Date(data.endDate).format('yyyy-MM-dd'));
  339. str += '</table>';
  340. str += '</div>';
  341. }
  342. return str;
  343. }
  344. function SubjectDetail(id) {
  345. window.location.href = "@Url.Action("Detail","Play")/" + id;
  346. }
  347. function SubjectStudy(id) {
  348. window.location.href = "@Url.Action("Study","Play")/" + id;
  349. }
  350. function SubjectCreate(id) {
  351. window.location.href = "@Url.Action("Create","Play")/" + id;
  352. }
  353. function QueryQuestion(id,name) {
  354. curCampNo = id;
  355. curCampName = name;
  356. $('#q-camp-name').text('(' + curCampName + ')');
  357. if (window.LoadQuestion) {
  358. window.LoadQuestion();
  359. }
  360. }
  361. function GetCanJoinCamp() {
  362. $.iwbAjax4({
  363. url: abp.appUrl + 'Query/QueryCanJoinCamp',
  364. success: function(res) {
  365. CanJoinCampFormatter(res);
  366. }
  367. });
  368. }
  369. function CanUseCampFormatter(data) {
  370. var str = '';
  371. if (data && data.length) {
  372. data.forEach(function(v) {
  373. str += CampFormatter(v, 1);
  374. });
  375. }
  376. if (str) {
  377. $('#use-camp').html(str);
  378. } else {
  379. $('#use-camp').html('<div class="no-data">暂无可用培训营</div>');
  380. }
  381. }
  382. function CanJoinCampFormatter(data) {
  383. var str = '';
  384. if (data && data.length) {
  385. data.forEach(function(v) {
  386. str += CampFormatter(v, 2);
  387. });
  388. }
  389. if (str) {
  390. $('#join-camp').html(str);
  391. } else {
  392. $('#join-camp').html('<div class="no-data">暂无可用培训营</div>');
  393. }
  394. }
  395. function CampFormatter(data, type) {
  396. var str = '';
  397. if (data) {
  398. var style = "danger", icon = "fas fa-lock", per = 100, title = type == 1 ? "创建演练" : "加入演练";
  399. if (type == 1) {
  400. style = "info";
  401. icon = "far fa-star";
  402. } else {
  403. if (data.isPublic) {
  404. style = "success";
  405. icon = "fas fa-unlock";
  406. }
  407. }
  408. str += '<div class="col-md-3">';
  409. str += '<div class="info-box bg-{0}" style="flex-direction: column;padding:0px">'.format(style);
  410. str += '<div class="ribbon-wrapper"><div class="ribbon bg-success">{0}分钟</div></div>'.format(
  411. data.maxTrainingMinute);
  412. str += '<div style="display: flex;flex-direction: row;padding:5px 0 0;">';
  413. str += '<span class="info-box-icon"><i class="{0}"></i></span>'.format(icon);
  414. str += '<div class="info-box-content">';
  415. str += data.name ? '<span class="info-box-text">演练名称:{0}</span>'.format(data.name) : '';
  416. str += '<span class="info-box-text">培训营:{0}</span>'.format(data.campName);
  417. //if (type != 1) {
  418. // var min = 0;
  419. // str += '<span class="info-box-number">已演练 {0} 分钟</span>'.format(min);
  420. //}
  421. str += '<div class="progress"><div class="progress-bar" style="width: {0}%"></div></div>'.format(per);
  422. str += '<span class="progress-description">{0}</span>'.format(data.packageName);
  423. str += '</div>';
  424. str += '</div>';
  425. str +=
  426. '<div class="tool-box" ><span onclick="Detail(\'{1}\',{2})">查看详情</span><span onclick="CreatePlay(\'{1}\',{2})">{0}</span></div>'
  427. .format(title, data.id, type);
  428. str += '</div>';
  429. str += '</div>';
  430. }
  431. return str;
  432. }
  433. </script>
  434. <script>
  435. function SendChat() {
  436. var text = $('#chat-message').val();
  437. if (!text) {
  438. return;
  439. }
  440. $.iwbAjax4({
  441. url: abp.appUrl + "/Camp/Chat",
  442. data: { Id: '', Msg: text},
  443. success: function() {
  444. $('#chat-message').val('').focus();
  445. }
  446. });
  447. }
  448. function FormatChat(data) {
  449. var str = '';
  450. if (data) {
  451. var imagePath = data.imagePath ? data.imagePath : '/Content/Image/user.png';
  452. var isSelf = '', left = 'left', right = 'right';
  453. if (data.userName === '@(AbpSession.UserName)' ) {
  454. isSelf = "right";
  455. left = 'right';
  456. right = 'left';
  457. }
  458. str += '<div class="direct-chat-msg {0}">'.format(isSelf);
  459. str += '<div class="direct-chat-infos clearfix">';
  460. str += '<span class="direct-chat-name float-{0}">{1}</span>'.format(left, data.name);//+"("+data.userName+")");
  461. str += '<span class="direct-chat-timestamp float-{0}">{1}</span>'.format(right, new Date().format('hh:mm:ss'));
  462. str += '</div>';
  463. str += '<img class="direct-chat-img" src="{0}" alt="{1}">'.format(imagePath, data.name);;
  464. str += '<div class="direct-chat-text">{0}</div>'.format(data.word);
  465. str += '</div>';
  466. }
  467. return str;
  468. }
  469. function Scroll2Bottom(that) {
  470. var instance = window.OverlayScrollbars($(that)[0]);
  471. if (instance) {
  472. try {
  473. instance.scroll({ y: "100%" });
  474. } catch (e) {
  475. }
  476. }
  477. }
  478. iwbHub.client.getCampChat = function(msg) {
  479. console.log('getCampChat: ', msg);
  480. if (msg) {
  481. try {
  482. var data = JSON.parse(msg);
  483. var str = FormatChat(data);
  484. if (str) {
  485. $('#chat-info .body-content').append(str);
  486. Scroll2Bottom($('#chat-info'));
  487. }
  488. } catch (e) {
  489. console.log('getCampChat: ', e);
  490. }
  491. }
  492. };
  493. </script>
  494. <script>
  495. function Detail(id, type) {
  496. if (type == 1) {
  497. window.open("/play/detail/" + id, "_blank");
  498. } else {
  499. window.open("/play/detailByPlay/" + id, "_blank");
  500. }
  501. }
  502. function CreatePlay(id, type) {
  503. if (type == 1) {
  504. window.open("/play/create/" + id, "_blank");
  505. } else {
  506. window.open("/play/ready/" + id, "_blank");
  507. }
  508. }
  509. </script>
  510. }