1个文件已删除
27个文件已添加
20个文件已修改
| | |
| | | "pinia": "^3.0.3", |
| | | "spark-md5": "^3.0.2", |
| | | "vue": "^3.5.18", |
| | | "vue-clipboard3": "^2.0.0", |
| | | "vue-router": "^4.5.1" |
| | | }, |
| | | "devDependencies": { |
| | |
| | | } |
| | | ] |
| | | }, |
| | | "node_modules/clipboard": { |
| | | "version": "2.0.11", |
| | | "resolved": "https://registry.npmmirror.com/clipboard/-/clipboard-2.0.11.tgz", |
| | | "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==", |
| | | "dependencies": { |
| | | "good-listener": "^1.2.2", |
| | | "select": "^1.1.2", |
| | | "tiny-emitter": "^2.0.0" |
| | | } |
| | | }, |
| | | "node_modules/combined-stream": { |
| | | "version": "1.0.8", |
| | | "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", |
| | |
| | | "engines": { |
| | | "node": ">=0.4.0" |
| | | } |
| | | }, |
| | | "node_modules/delegate": { |
| | | "version": "3.2.0", |
| | | "resolved": "https://registry.npmmirror.com/delegate/-/delegate-3.2.0.tgz", |
| | | "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==" |
| | | }, |
| | | "node_modules/dunder-proto": { |
| | | "version": "1.0.1", |
| | |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/good-listener": { |
| | | "version": "1.2.2", |
| | | "resolved": "https://registry.npmmirror.com/good-listener/-/good-listener-1.2.2.tgz", |
| | | "integrity": "sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==", |
| | | "dependencies": { |
| | | "delegate": "^3.1.2" |
| | | } |
| | | }, |
| | | "node_modules/gopd": { |
| | |
| | | "license": "ISC", |
| | | "optional": true |
| | | }, |
| | | "node_modules/select": { |
| | | "version": "1.1.2", |
| | | "resolved": "https://registry.npmmirror.com/select/-/select-1.1.2.tgz", |
| | | "integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==" |
| | | }, |
| | | "node_modules/semver": { |
| | | "version": "6.3.1", |
| | | "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", |
| | |
| | | "engines": { |
| | | "node": ">=16" |
| | | } |
| | | }, |
| | | "node_modules/tiny-emitter": { |
| | | "version": "2.1.0", |
| | | "resolved": "https://registry.npmmirror.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz", |
| | | "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" |
| | | }, |
| | | "node_modules/tinyglobby": { |
| | | "version": "0.2.14", |
| | |
| | | "typescript": { |
| | | "optional": true |
| | | } |
| | | } |
| | | }, |
| | | "node_modules/vue-clipboard3": { |
| | | "version": "2.0.0", |
| | | "resolved": "https://registry.npmmirror.com/vue-clipboard3/-/vue-clipboard3-2.0.0.tgz", |
| | | "integrity": "sha512-Q9S7dzWGax7LN5iiSPcu/K1GGm2gcBBlYwmMsUc5/16N6w90cbKow3FnPmPs95sungns4yvd9/+JhbAznECS2A==", |
| | | "dependencies": { |
| | | "clipboard": "^2.0.6" |
| | | } |
| | | }, |
| | | "node_modules/vue-router": { |
| | |
| | | "integrity": "sha512-EV/laoX7Wq2J9TQlyIXRxTJqIw4sxfXS4OYgudGxBYRuTv0q7AM6yMEpU/Vo1I94thg9U6EZ2NfZx9GJq83u7w==", |
| | | "dev": true |
| | | }, |
| | | "clipboard": { |
| | | "version": "2.0.11", |
| | | "resolved": "https://registry.npmmirror.com/clipboard/-/clipboard-2.0.11.tgz", |
| | | "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==", |
| | | "requires": { |
| | | "good-listener": "^1.2.2", |
| | | "select": "^1.1.2", |
| | | "tiny-emitter": "^2.0.0" |
| | | } |
| | | }, |
| | | "combined-stream": { |
| | | "version": "1.0.8", |
| | | "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", |
| | |
| | | "version": "1.0.0", |
| | | "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", |
| | | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" |
| | | }, |
| | | "delegate": { |
| | | "version": "3.2.0", |
| | | "resolved": "https://registry.npmmirror.com/delegate/-/delegate-3.2.0.tgz", |
| | | "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==" |
| | | }, |
| | | "dunder-proto": { |
| | | "version": "1.0.1", |
| | |
| | | "requires": { |
| | | "@sec-ant/readable-stream": "^0.4.1", |
| | | "is-stream": "^4.0.1" |
| | | } |
| | | }, |
| | | "good-listener": { |
| | | "version": "1.2.2", |
| | | "resolved": "https://registry.npmmirror.com/good-listener/-/good-listener-1.2.2.tgz", |
| | | "integrity": "sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==", |
| | | "requires": { |
| | | "delegate": "^3.1.2" |
| | | } |
| | | }, |
| | | "gopd": { |
| | |
| | | "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", |
| | | "optional": true |
| | | }, |
| | | "select": { |
| | | "version": "1.1.2", |
| | | "resolved": "https://registry.npmmirror.com/select/-/select-1.1.2.tgz", |
| | | "integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==" |
| | | }, |
| | | "semver": { |
| | | "version": "6.3.1", |
| | | "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", |
| | |
| | | "requires": { |
| | | "copy-anything": "^3.0.2" |
| | | } |
| | | }, |
| | | "tiny-emitter": { |
| | | "version": "2.1.0", |
| | | "resolved": "https://registry.npmmirror.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz", |
| | | "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" |
| | | }, |
| | | "tinyglobby": { |
| | | "version": "0.2.14", |
| | |
| | | "@vue/shared": "3.5.18" |
| | | } |
| | | }, |
| | | "vue-clipboard3": { |
| | | "version": "2.0.0", |
| | | "resolved": "https://registry.npmmirror.com/vue-clipboard3/-/vue-clipboard3-2.0.0.tgz", |
| | | "integrity": "sha512-Q9S7dzWGax7LN5iiSPcu/K1GGm2gcBBlYwmMsUc5/16N6w90cbKow3FnPmPs95sungns4yvd9/+JhbAznECS2A==", |
| | | "requires": { |
| | | "clipboard": "^2.0.6" |
| | | } |
| | | }, |
| | | "vue-router": { |
| | | "version": "4.5.1", |
| | | "resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.5.1.tgz", |
| | |
| | | "pinia": "^3.0.3", |
| | | "spark-md5": "^3.0.2", |
| | | "vue": "^3.5.18", |
| | | "vue-clipboard3": "^2.0.0", |
| | | "vue-router": "^4.5.1" |
| | | }, |
| | | "devDependencies": { |
| | |
| | | License: none (public domain) |
| | | */ |
| | | |
| | | html, body, div, span, applet, object, iframe, |
| | | h1, h2, h3, h4, h5, h6, p, blockquote, pre, |
| | | a, abbr, acronym, address, big, cite, code, |
| | | del, dfn, em, img, ins, kbd, q, s, samp, |
| | | small, strike, strong, sub, sup, tt, var, |
| | | b, u, i, center, |
| | | dl, dt, dd, ol, ul, li, |
| | | fieldset, form, label, legend, |
| | | table, caption, tbody, tfoot, thead, tr, th, td, |
| | | article, aside, canvas, details, embed, |
| | | figure, figcaption, footer, header, hgroup, |
| | | menu, nav, output, ruby, section, summary, |
| | | time, mark, audio, video { |
| | | margin: 0; |
| | | padding: 0; |
| | | border: 0; |
| | | font-size: 100%; |
| | | font: inherit; |
| | | vertical-align: baseline; |
| | | |
| | | html, |
| | | body, |
| | | div, |
| | | span, |
| | | applet, |
| | | object, |
| | | iframe, |
| | | h1, |
| | | h2, |
| | | h3, |
| | | h4, |
| | | h5, |
| | | h6, |
| | | p, |
| | | blockquote, |
| | | pre, |
| | | a, |
| | | abbr, |
| | | acronym, |
| | | address, |
| | | big, |
| | | cite, |
| | | code, |
| | | del, |
| | | dfn, |
| | | em, |
| | | img, |
| | | ins, |
| | | kbd, |
| | | q, |
| | | s, |
| | | samp, |
| | | small, |
| | | strike, |
| | | strong, |
| | | sub, |
| | | sup, |
| | | tt, |
| | | var, |
| | | b, |
| | | u, |
| | | i, |
| | | center, |
| | | dl, |
| | | dt, |
| | | dd, |
| | | ol, |
| | | ul, |
| | | li, |
| | | fieldset, |
| | | form, |
| | | label, |
| | | legend, |
| | | table, |
| | | caption, |
| | | tbody, |
| | | tfoot, |
| | | thead, |
| | | tr, |
| | | th, |
| | | td, |
| | | article, |
| | | aside, |
| | | canvas, |
| | | details, |
| | | embed, |
| | | figure, |
| | | figcaption, |
| | | footer, |
| | | header, |
| | | hgroup, |
| | | menu, |
| | | nav, |
| | | output, |
| | | ruby, |
| | | section, |
| | | summary, |
| | | time, |
| | | mark, |
| | | audio, |
| | | video { |
| | | margin: 0; |
| | | padding: 0; |
| | | border: 0; |
| | | font-size: 100%; |
| | | font: inherit; |
| | | vertical-align: baseline; |
| | | } |
| | | /* HTML5 display-role reset for older browsers */ |
| | | article, aside, details, figcaption, figure, |
| | | footer, header, hgroup, menu, nav, section { |
| | | display: block; |
| | | article, |
| | | aside, |
| | | details, |
| | | figcaption, |
| | | figure, |
| | | footer, |
| | | header, |
| | | hgroup, |
| | | menu, |
| | | nav, |
| | | section { |
| | | display: block; |
| | | } |
| | | body { |
| | | line-height: 1; |
| | | font-size: 14px; |
| | | line-height: 1; |
| | | font-size: 14px; |
| | | } |
| | | ol, ul { |
| | | list-style: none; |
| | | ol, |
| | | ul { |
| | | list-style: none; |
| | | } |
| | | blockquote, q { |
| | | quotes: none; |
| | | blockquote, |
| | | q { |
| | | quotes: none; |
| | | } |
| | | blockquote:before, blockquote:after, |
| | | q:before, q:after { |
| | | content: ''; |
| | | content: none; |
| | | blockquote:before, |
| | | blockquote:after, |
| | | q:before, |
| | | q:after { |
| | | content: ''; |
| | | content: none; |
| | | } |
| | | table { |
| | | border-collapse: collapse; |
| | | border-spacing: 0; |
| | | } |
| | | border-collapse: collapse; |
| | | border-spacing: 0; |
| | | } |
New file |
| | |
| | | <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1755764010884" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7634" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M580.205386 310.17543C577.496936 310.092291 576.262736 306.37798 573.580048 307.257377 573.585904 308.22928 573.590587 309.203526 573.59527 310.17543L580.205386 310.17543 580.205386 310.17543ZM657.335891 309.950603C620.414092 303.49974 586.829553 311.777314 556.109201 332.861768 528.873652 351.553933 506.245862 375.465104 482.403779 397.969943 453.357912 425.390505 423.285106 451.412932 387.851607 470.399011 355.473164 487.748077 321.502205 499.77392 284.133096 499.172043 279.79583 499.101785 278.890671 500.77744 279.498404 504.416808 279.992552 507.371162 280.274756 510.389918 281.069844 513.265816 286.38721 532.509507 298.574647 546.57752 314.402625 558.145515 320.29962 562.459362 326.251652 564.132676 333.211886 562.520252 341.734194 560.542487 350.440342 559.084632 358.708548 556.32583 399.432481 542.739085 431.48071 517.028136 458.226795 484.096997 486.517388 449.265377 515.366532 414.896289 548.303525 384.312941 582.077762 352.950899 617.321563 323.70948 664.584182 314.737522 665.46475 313.759763 665.474118 312.787859 664.56896 311.819469 662.161452 311.185975 659.783215 310.376836 657.335891 309.950603L657.335891 309.950603ZM761.314359 234.146805C744.82361 234.329476 731.125623 248.228868 731.360986 264.541627 731.597524 280.983192 745.549612 294.701084 761.827239 294.500849 778.284025 294.298271 791.911759 280.405904 791.723233 264.027572 791.527677 247.445492 777.809783 233.965305 761.314359 234.146805L761.314359 234.146805ZM512 0C229.231081 0 0 229.22991 0 512 0 794.768916 229.231081 1024 512 1024 794.768916 1024 1024 794.768916 1024 512 1024 229.231081 794.768916 0 512 0L512 0ZM453.397725 830.388599C445.68924 853.581967 429.74885 867.448573 406.048454 872.682803 398.503905 872.63245 390.959357 872.579755 383.417151 872.529408 360.844396 866.301024 344.659274 853.008193 338.015201 830.015065 331.017495 805.794755 337.720117 785.192742 355.767079 767.915104 359.020029 764.802669 361.357281 764.596579 365.087986 767.587232 391.534302 788.770051 419.481801 807.701094 450.22323 822.176604 454.503118 824.191836 454.688132 826.505667 453.397725 830.388599L453.397725 830.388599ZM822.448265 268.575613C820.650831 269.792248 822.666069 272.811005 821.094625 274.1342 814.626202 305.161344 797.209218 319.368701 758.139863 325.517455 760.587189 333.102988 763.447863 340.590158 765.423288 348.302155 778.817993 400.635067 771.239485 451.135414 751.131621 500.268069 734.028459 542.061096 708.461534 578.369308 676.907456 610.440956 656.386238 631.299413 642.929471 655.974056 634.379061 683.694387 625.959799 710.98497 620.9785 739.12802 613.415216 766.622358 610.289903 777.981918 606.786366 789.334453 599.64346 798.881355 585.05905 818.370956 563.733377 821.321796 541.70161 820.555981 503.900414 819.239813 470.101587 804.811141 438.020571 786.168156 380.617368 752.808441 332.734134 708.20978 289.594494 658.256272 260.649331 624.737307 235.78265 588.550876 218.529604 547.470969 211.226274 530.079749 206.863247 511.922715 203.241443 493.522121 202.918255 493.040853 202.606778 492.820712 202.310523 492.852328 201.952207 490.10992 203.033011 487.2188 201.509581 484.593489L201.509581 483.089965C202.715678 479.580573 202.715678 476.072353 201.509581 472.564133L201.509581 471.06061C202.917085 468.955208 202.023636 466.552381 202.291788 464.30061 202.585702 464.334567 202.892496 464.112084 203.210998 463.624961 203.606785 462.461019 204.188757 461.32635 204.37377 460.127278 207.716884 438.43275 219.102207 423.54506 240.238184 416.148054 259.717241 409.331848 279.967965 406.067188 300.041873 401.918448 326.748144 396.398504 353.488376 391.17013 378.651311 379.939374 400.265043 370.291767 415.909179 353.231931 433.159883 338.025738 474.861575 301.262021 521.378286 273.059251 576.003955 259.926842 600.232459 254.102446 624.749019 251.617651 649.744508 254.206662 667.245799 256.019321 683.975421 260.481881 700.822139 266.97607 702.652368 234.179592 718.561137 213.123242 750.256906 204.86089 752.001652 202.85268 755.679662 205.831623 757.253441 203.388983 761.779234 203.336289 766.303853 203.292963 770.829647 203.442847 795.110844 202.33511 823.773805 230.489872 822.448271 255.574353 822.448265 259.909277 822.448265 264.24186 822.448265 268.575613L822.448265 268.575613Z" fill="#1C9E3A" p-id="7635"></path></svg> |
| | |
| | | export const requestCtx = 'http://182.92.203.7:5001' // 请求地址 |
| | | export const requestCtx = 'https://yxjy.pumcp.com/' // 请求地址 |
| | | // export const appId = 1051; |
| | | |
| | | // export const requestCtx = 'http://172.31.31.145' // 请求地址 |
| | |
| | | export const appId = 1 |
| | | |
| | | export const requestTimeOut = 300000 // 请求超时时间 |
| | | export const tokenKey = 'jilin-token' |
| | | export const userInfoKey = 'jilin-userInfo' // 用户信息key |
| | | export const appRefCode = 'jilinWebsite' |
| | | export const tokenKey = 'xiehe-token' |
| | | export const userInfoKey = 'xiehe-userInfo' // 用户信息key |
| | | export const appRefCode = 'PUMC' |
| | | export const goodsStore = `defaultGoodsStore${appId}` // 默认商品库(书城) |
| | | export const publicStore = `defaultPublicStore${appId}` // 默认资源开放仓储 |
| | | export const publicRepository = `defaultPublicRepository${appId}` // 默认资源开放库 |
| | | |
| | | export const reg_tel = |
| | | /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/ // 电话号正则 |
| | | export const reg_telphone = /^0\d{2}-\d{8}$|^0\d{3}-\d{7}$/ //座机号正则 |
| | | |
| | | // refcode |
| | | const refCode = { |
| | |
| | | newVideosStore: 'jilin_videosLibrary\\jilin_newVideosStore', |
| | | newModelsStore: 'jilin_modelsLibrary\\jilin_newModelsStore', |
| | | // 首页推荐资源 |
| | | recommendImgStore:'jilin_imgLibrary\\jilin_recommendedImage', |
| | | recommendAudioStore:'jilin_audiosLibrary\\jilin_recommendedAudio', |
| | | recommendVideoStore:'jilin_videosLibrary\\jilin_recommendedVideo', |
| | | recommendModelStore:'jilin_modelsLibrary\\jilin_recommendedModel', |
| | | recommendImgStore: 'jilin_imgLibrary\\jilin_recommendedImage', |
| | | recommendAudioStore: 'jilin_audiosLibrary\\jilin_recommendedAudio', |
| | | recommendVideoStore: 'jilin_videosLibrary\\jilin_recommendedVideo', |
| | | recommendModelStore: 'jilin_modelsLibrary\\jilin_recommendedModel', |
| | | } |
| | | |
| | | const wxLogin = { |
| | | appid: 'wx2b9d4a6308fd03d6', |
| | | scope: 'snsapi_login', |
| | | logInRedirectURL: encodeURIComponent(requestCtx + '/website'), |
| | | authenRedirectURL:encodeURIComponent(requestCtx + '/website/#/userInfo') |
| | | authenRedirectURL: encodeURIComponent(requestCtx + '/website/#/userInfo'), |
| | | } |
| | | |
| | | const config = { |
| | |
| | | reg_tel, |
| | | appId, |
| | | refCode, |
| | | wxLogin |
| | | wxLogin, |
| | | reg_telphone, |
| | | } |
| | | export default config |
| | |
| | | }) |
| | | }, |
| | | |
| | | // 获取班级详情 |
| | | getCourseClass(data) { |
| | | return request({ |
| | | url: '/edu/api/ApiGetCourseClass', |
| | | method: 'post', |
| | | data, |
| | | }) |
| | | }, |
| | | |
| | | // 获取topic信息 |
| | | getClassTopic(data) { |
| | | return request({ |
| | | url: '/edu/api/ApiGetClassTopic', |
| | | method: 'post', |
| | | data, |
| | | }) |
| | | }, |
| | | |
| | | //创建课程订单 |
| | | createCourseOrder(data) { |
| | | return request({ |
| | |
| | | import request from "@/plugin/axios/index.ts"; |
| | | import request from '@/plugin/axios/index.ts' |
| | | const identityApi = { |
| | | // 获取图形验证码 |
| | | getImgCode() { |
| | | return request({ |
| | | url: "/identity/NewCaptcha", |
| | | method: "post", |
| | | }); |
| | | url: '/identity/NewCaptcha', |
| | | method: 'post', |
| | | }) |
| | | }, |
| | | |
| | | // 验证图形验证码 |
| | | verificationImgCode(data) { |
| | | return request({ |
| | | url: "/identity/ValidCaptcha", |
| | | method: "post", |
| | | url: '/identity/ValidCaptcha', |
| | | method: 'post', |
| | | data, |
| | | }); |
| | | }) |
| | | }, |
| | | |
| | | // 获取短信验证码 |
| | | getPhoneCode(data) { |
| | | return request({ |
| | | url: "/identity/NewSms", |
| | | method: "post", |
| | | url: '/identity/NewSms', |
| | | method: 'post', |
| | | data, |
| | | }); |
| | | }) |
| | | }, |
| | | // 验证短信验证码 |
| | | verificationPhoneCode(data) { |
| | | return request({ |
| | | url: "/identity/api/ApiValidMobilePhone", |
| | | method: "post", |
| | | url: '/identity/api/ApiValidMobilePhone', |
| | | method: 'post', |
| | | data, |
| | | }); |
| | | }) |
| | | }, |
| | | |
| | | // 通过手机号注册用户 |
| | | registerAppUserWithPhone(data) { |
| | | return request({ |
| | | url: "/identity/api/RegisterAppUserWithPhone", |
| | | method: "post", |
| | | url: '/identity/api/RegisterAppUserWithPhone', |
| | | method: 'post', |
| | | data, |
| | | }); |
| | | }) |
| | | }, |
| | | |
| | | // 账号密码登录 |
| | | loginByPassword(data) { |
| | | return request({ |
| | | url: "/identity/api/LoginByPassword", |
| | | method: "post", |
| | | url: '/identity/api/LoginByPassword', |
| | | method: 'post', |
| | | data, |
| | | }); |
| | | }) |
| | | }, |
| | | |
| | | // 短信验证码登录 |
| | | loginByMobilePhone(data) { |
| | | return request({ |
| | | url: "/identity/api/LoginByMobilePhone", |
| | | method: "post", |
| | | url: '/identity/api/LoginByMobilePhone', |
| | | method: 'post', |
| | | data, |
| | | }); |
| | | }) |
| | | }, |
| | | |
| | | // 设置用户key |
| | | setUserKey(data) { |
| | | return request({ |
| | | url: "/identity/api/ApiAppUserSetKey", |
| | | method: "post", |
| | | url: '/identity/api/ApiAppUserSetKey', |
| | | method: 'post', |
| | | data, |
| | | }); |
| | | }) |
| | | }, |
| | | |
| | | // 获取用户key |
| | | getUserKey(data) { |
| | | return request({ |
| | | url: "/identity/api/ApiGetAppUserKey", |
| | | method: "post", |
| | | url: '/identity/api/ApiGetAppUserKey', |
| | | method: 'post', |
| | | data, |
| | | }); |
| | | }) |
| | | }, |
| | | |
| | | // 删除用户key |
| | | delUserKey(data) { |
| | | return request({ |
| | | url: "/identity/api/ApiDelAppUserKey", |
| | | method: "post", |
| | | url: '/identity/api/ApiDelAppUserKey', |
| | | method: 'post', |
| | | data, |
| | | }); |
| | | }) |
| | | }, |
| | | |
| | | // 获取去当前用户信息 |
| | | getCurrentAppUser() { |
| | | return request({ |
| | | url: "/identity/api/GetCurrentAppUser", |
| | | method: "post", |
| | | }); |
| | | url: '/identity/api/GetCurrentAppUser', |
| | | method: 'post', |
| | | }) |
| | | }, |
| | | |
| | | // 添加用户信息 |
| | | setAppUserInfo(data) { |
| | | return request({ |
| | | url: "/identity/api/SetAppUserInfoRequest", |
| | | method: "post", |
| | | url: '/identity/api/SetAppUserInfoRequest', |
| | | method: 'post', |
| | | data, |
| | | }); |
| | | }) |
| | | }, |
| | | |
| | | // 用户更换绑定手机号,如没有绑定手机则自动创建 |
| | | userSetPhoneNumber(data) { |
| | | return request({ |
| | | url: "/identity/api/ApiUserSetPhoneNumber", |
| | | method: "post", |
| | | url: '/identity/api/ApiUserSetPhoneNumber', |
| | | method: 'post', |
| | | data, |
| | | }); |
| | | }) |
| | | }, |
| | | |
| | | // 检测用户是否绑定微信 |
| | | checkBuildingWeChat(data) { |
| | | return request({ |
| | | url: "/identity/api/ApiCheckBuildingWeChat", |
| | | method: "post", |
| | | url: '/identity/api/ApiCheckBuildingWeChat', |
| | | method: 'post', |
| | | data, |
| | | }); |
| | | }) |
| | | }, |
| | | |
| | | |
| | | // 通过手机号重置密码 |
| | | changePasswordByMobilePhone(data) { |
| | | return request({ |
| | | url: "/identity/api/ChangePasswordByMobilePhone", |
| | | method: "post", |
| | | url: '/identity/api/ChangePasswordByMobilePhone', |
| | | method: 'post', |
| | | data, |
| | | }); |
| | | }) |
| | | }, |
| | | |
| | | // 微信开放平台扫码登录 |
| | | loginByWeChatOpenCode(data) { |
| | | return request({ |
| | | url: "/identity/api/LoginByWeChatOpenCode", |
| | | method: "post", |
| | | url: '/identity/api/LoginByWeChatOpenCode', |
| | | method: 'post', |
| | | data, |
| | | }); |
| | | }) |
| | | }, |
| | | |
| | | // 用户绑定微信号 |
| | | bindingWeChat(data) { |
| | | return request({ |
| | | url: "/identity/api/ApiBindingWeChat", |
| | | method: "post", |
| | | url: '/identity/api/ApiBindingWeChat', |
| | | method: 'post', |
| | | data, |
| | | }); |
| | | }) |
| | | }, |
| | | |
| | | // 设置登录的用户名和密码,用户名和密码至少6位 |
| | | setLoginNameAndPassword(data) { |
| | | return request({ |
| | | url: "/identity/api/ApiUserSetLoginNameAndPassword", |
| | | method: "post", |
| | | url: '/identity/api/ApiUserSetLoginNameAndPassword', |
| | | method: 'post', |
| | | data, |
| | | }); |
| | | }) |
| | | }, |
| | | |
| | | // 获取邮箱验证码 |
| | | getEmailCode(data) { |
| | | return request({ |
| | | url: "/identity/api/SendVerifyEMail", |
| | | method: "post", |
| | | url: '/identity/api/SendVerifyEMail', |
| | | method: 'post', |
| | | data, |
| | | }); |
| | | }) |
| | | }, |
| | | // 用户绑定邮箱 |
| | | bindingEmail(data) { |
| | | return request({ |
| | | url: "/identity/api/ApiBindEMail", |
| | | method: "post", |
| | | url: '/identity/api/ApiBindEMail', |
| | | method: 'post', |
| | | data, |
| | | }); |
| | | }) |
| | | }, |
| | | }; |
| | | // 通过refcode加入班级/组 |
| | | joinGroupByRefCode(data) { |
| | | return request({ |
| | | url: '/identity/api/ApiJoinGroupByRefCode', |
| | | method: 'post', |
| | | data, |
| | | }) |
| | | }, |
| | | |
| | | export default identityApi; |
| | | // 获取加入组的列表信息 |
| | | joinedGroupByList(data) { |
| | | return request({ |
| | | url: '/identity/api/ApiGetJoinedGroupByList', |
| | | method: 'post', |
| | | data, |
| | | }) |
| | | }, |
| | | |
| | | // 获取组或班级成员 |
| | | getGroupUserList(data) { |
| | | return request({ |
| | | url: '/identity/api/ApiGetGroupUserList', |
| | | method: 'post', |
| | | data, |
| | | }) |
| | | }, |
| | | |
| | | // 更新组成员或班级成员状态 |
| | | updateAppUserGroupLink(data) { |
| | | return request({ |
| | | url: '/identity/api/ApiUpdateAppUserGroupLink', |
| | | method: 'post', |
| | | data, |
| | | }) |
| | | }, |
| | | |
| | | // 删除组成员或班级成员状态 |
| | | removeAppUserFromGroup(data) { |
| | | return request({ |
| | | url: '/identity/api/ApiRemoveAppUserFromGroup', |
| | | method: 'post', |
| | | data, |
| | | }) |
| | | }, |
| | | } |
| | | |
| | | export default identityApi |
| | |
| | | @import './base.css'; |
| | | |
| | | :root { |
| | | --el-color-primary: #019e58 !important; |
| | | --el-color-primary-light-3: #019e58 !important; |
| | | --el-color-primary-light-5: #019e58 !important; |
| | | --el-color-primary-light-7: #019e58 !important; |
| | | --el-color-primary-dark-2: #019e58 !important; |
| | | --el-color-primary-dark-3: #019e58 !important; |
| | | } |
| | | |
| | | /* 居中布局 */ |
| | | .contentBox { |
| | | width: 1200px; |
| | |
| | | } |
| | | |
| | | .avatar-uploader .el-upload:hover { |
| | | border-color: #409eff; |
| | | border-color: #019e58; |
| | | } |
| | | |
| | | .avatarCover { |
| | |
| | | .el-input-group__prepend { |
| | | vertical-align: initial !important; |
| | | } |
| | | .el-checkbox__inner { |
| | | border: 1px solid #000 !important; |
| | | width: 20px !important; |
| | | height: 20px !important; |
| | | } |
| | | |
| | | .el-checkbox__inner::after { |
| | | left: 7px !important; |
| | | top: 4px !important; |
| | | } |
| | | |
| | | /* 个人中心页面公共样式 */ |
| | | .personalPage-title { |
| | |
| | | border-radius: 4px 4px 0px 0px; |
| | | } |
| | | .personalPage-content { |
| | | padding: 20px 40px; |
| | | padding: 20px 20px; |
| | | } |
| | | |
| | | /* 两边对齐 */ |
| | |
| | | cursor: pointer; |
| | | transition: all 0.2s; |
| | | } |
| | | |
| | | .no { |
| | | color: #ee1818; |
| | | } |
| | | |
| | | .yes { |
| | | color: #1fbc1f; |
| | | } |
| | | .wait, |
| | | .main { |
| | | color: #ff6d00; |
| | | } |
| | | .grey { |
| | | color: #949494; |
| | | } |
| | |
| | | path: '/myBook', |
| | | name: 'myBook', |
| | | meta: { |
| | | name: '图书', |
| | | name: '书架', |
| | | }, |
| | | component: () => import('@/views/personalCenter/myBook.vue'), |
| | | }, |
| | |
| | | }, |
| | | component: () => import('@/views/personalCenter/activeCode.vue'), |
| | | }, |
| | | { |
| | | path: '/courseDetail', |
| | | name: 'courseDetail', |
| | | meta: { |
| | | name: '课程详情', |
| | | }, |
| | | component: () => import('@/views/courseManage/index.vue'), |
| | | }, |
| | | ], |
| | | }, |
| | | // 班级 |
| | | { |
| | | path: '/classManage', |
| | | name: 'classManage', |
| | | redirect: '/classHome', |
| | | meta: { |
| | | name: '班级管理', |
| | | }, |
| | | component: () => import('../views/classManage/index.vue'), |
| | | children: [ |
| | | { |
| | | path: '/classHome', |
| | | name: 'classHome', |
| | | meta: { |
| | | name: '班级首页', |
| | | }, |
| | | component: () => import('@/views/classManage/classHome.vue'), |
| | | }, |
| | | { |
| | | path: '/studentManage', |
| | | name: 'studentManage', |
| | | meta: { |
| | | name: '学生管理', |
| | | }, |
| | | component: () => import('@/views/classManage/studentManage.vue'), |
| | | }, |
| | | { |
| | | path: '/teachingPlan', |
| | | name: 'teachingPlan', |
| | | meta: { |
| | | name: '教学计划', |
| | | }, |
| | | component: () => import('@/views/classManage/teachingPlan.vue'), |
| | | }, |
| | | { |
| | | path: '/prepareLessons', |
| | | name: 'prepareLessons', |
| | | meta: { |
| | | name: '备课', |
| | | }, |
| | | component: () => import('@/views/classManage/prepareLessons.vue'), |
| | | }, |
| | | { |
| | | path: '/jobManage', |
| | | name: 'jobManage', |
| | | meta: { |
| | | name: '作业管理-教师', |
| | | }, |
| | | component: () => import('@/views/classManage/jobManage.vue'), |
| | | }, |
| | | { |
| | | path: '/studentJob', |
| | | name: 'studentJob', |
| | | meta: { |
| | | name: '作业管理-学生', |
| | | }, |
| | | component: () => import('@/views/classManage/studentJob.vue'), |
| | | }, |
| | | { |
| | | path: '/jobDetail', |
| | | name: 'jobDetail', |
| | | meta: { |
| | | name: '作业管理详情', |
| | | }, |
| | | component: () => import('@/views/classManage/jobDetail.vue'), |
| | | }, |
| | | { |
| | | path: '/testManage', |
| | | name: 'testManage', |
| | | meta: { |
| | | name: '测试管理', |
| | | }, |
| | | component: () => import('@/views/classManage/testManage.vue'), |
| | | }, |
| | | { |
| | | path: '/jobAnalysis', |
| | | name: 'jobAnalysis', |
| | | meta: { |
| | | name: '作业分析', |
| | | }, |
| | | component: () => import('@/views/classManage/jobAnalysis.vue'), |
| | | }, |
| | | { |
| | | path: '/teachInteraction', |
| | | name: 'teachInteraction', |
| | | meta: { |
| | | name: '教学互动', |
| | | }, |
| | | component: () => import('@/views/classManage/teachInteraction.vue'), |
| | | }, |
| | | { |
| | | path: '/interactionDetail', |
| | | name: 'interactionDetail', |
| | | meta: { |
| | | name: '教学互动-详情', |
| | | }, |
| | | component: () => import('@/views/classManage/interactionDetail.vue'), |
| | | }, |
| | | { |
| | | path: '/talkingPoint', |
| | | name: 'talkingPoint', |
| | | meta: { |
| | | name: '话题', |
| | | }, |
| | | component: () => import('@/views/classManage/talkingPoint.vue'), |
| | | }, |
| | | { |
| | | path: '/talkDetail', |
| | | name: 'talkDetail', |
| | | meta: { |
| | | name: '话题', |
| | | }, |
| | | component: () => import('@/views/classManage/talkDetail.vue'), |
| | | }, |
| | | { |
| | | path: '/info', |
| | | name: 'info', |
| | | meta: { |
| | | name: '班级通知列表', |
| | | }, |
| | | component: () => import('@/views/classManage/infoList.vue'), |
| | | }, |
| | | ], |
| | | }, |
| | | ], |
New file |
| | |
| | | import { createPinia } from "pinia"; |
| | | |
| | | // 创建pinia实例 |
| | | const pinia = createPinia() |
| | | |
| | | export default pinia |
| | | |
| | | export * from './modules/breadcrumb' |
| | | export * from './modules/user' |
New file |
| | |
| | | // 面包屑数据 |
| | | import { defineStore } from 'pinia' |
| | | import tool from '@/assets/js/toolClass.js' |
| | | export const useBreadcrumbStore = defineStore('breadcrumb', () => { |
| | | const crumbList = localStorage.getItem('crumbs') |
| | | ? JSON.parse(localStorage.getItem('crumbs')) |
| | | : { |
| | | home: {}, // 首页 |
| | | bookService: {}, // 图书服务 |
| | | digitalCourse: {}, // 数字课程 |
| | | digitalBook: {}, // 数字教材 |
| | | seminar: {}, // 数字教材 |
| | | shoppingCart: {}, // 购物车 |
| | | personalCenter: {}, //个人中心 |
| | | retrievalPage: {}, //全局检索 |
| | | digitalCourses: {}, //数字课程 |
| | | digitalTextbooks: {} //数字教材 |
| | | } |
| | | // 面包屑 |
| | | const changeCrumbs = (data: any) => { |
| | | switch (data.type) { |
| | | case 'home': |
| | | data.data.unshift({ |
| | | name: '首页', |
| | | // isCrumbs: true, |
| | | path: '/home' |
| | | }) |
| | | break |
| | | case 'bookService': |
| | | data.data.unshift({ |
| | | name: '图书服务', |
| | | // isCrumbs: true, |
| | | path: '/bookService' |
| | | }) |
| | | break |
| | | case 'personalCenter': |
| | | data.data.unshift({ |
| | | name: '个人中心', |
| | | // isCrumbs: true, |
| | | path: '/personalCenter' |
| | | }) |
| | | break |
| | | case 'retrievalPage': |
| | | data.data.unshift({ |
| | | name: '全局检索', |
| | | // isCrumbs: true, |
| | | path: '/retrievalPage' |
| | | }) |
| | | break |
| | | case 'digitalCourses': |
| | | data.data.unshift({ |
| | | name: '数字课程', |
| | | // isCrumbs: true, |
| | | path: '/digitalCourses' |
| | | }) |
| | | break |
| | | case 'digitalTextbooks': |
| | | data.data.unshift({ |
| | | name: '数字教材', |
| | | // isCrumbs: true, |
| | | path: '/digitalTextbooks' |
| | | }) |
| | | break |
| | | case 'shoppingCart': |
| | | data.data.unshift({ |
| | | name: '购物车', |
| | | path: '/shoppingCart' |
| | | }) |
| | | } |
| | | if (!crumbList[data.type].keys) { |
| | | crumbList[data.type].keys = [] |
| | | } |
| | | crumbList[data.type].keys.push(data.cid) |
| | | crumbList[data.type][data.cid] = data.data |
| | | if (crumbList[data.type].keys.length > 20) { |
| | | const key = crumbList[data.type].keys[0] |
| | | delete crumbList[data.type][key] |
| | | crumbList[data.type].keys.splice(0, 1) |
| | | } |
| | | localStorage.setItem('crumbs', JSON.stringify(crumbList)) |
| | | } |
| | | |
| | | const setCrumbs = (data: any) => { |
| | | // 存储面包屑 |
| | | if (!data.cid) { |
| | | data.cid = tool.uuid(8) |
| | | } |
| | | changeCrumbs(data) |
| | | if (data.callback) data.callback(data.cid) |
| | | } |
| | | |
| | | return { |
| | | crumbList, |
| | | setCrumbs |
| | | } |
| | | }) |
New file |
| | |
| | | // 用户信息 |
| | | import { defineStore } from 'pinia' |
| | | import config from '@/assets/js/config' |
| | | import { ref } from 'vue' |
| | | interface userInfo { |
| | | userName: string |
| | | userType: string |
| | | roleId?: any |
| | | role?: any |
| | | userId?: number |
| | | name?: string |
| | | } |
| | | |
| | | export const useUserStore = defineStore('user', () => { |
| | | const token = localStorage.getItem(config.tokenKey) |
| | | ? ref<string>(localStorage.getItem(config.tokenKey) as string) |
| | | : ref<string>() |
| | | const userInfo = localStorage.getItem(config.userInfoKey) |
| | | ? ref<userInfo>(JSON.parse(localStorage.getItem(config.userInfoKey) as string)) |
| | | : ref<userInfo>() |
| | | const setToken = (value: string) => { |
| | | token.value = value |
| | | localStorage.setItem(config.tokenKey, value) |
| | | } |
| | | const setUserInfo = (value: userInfo) => { |
| | | userInfo.value = value |
| | | localStorage.setItem(config.userInfoKey, JSON.stringify(value)) |
| | | } |
| | | // 退出登录 |
| | | const delteUserInfo = () => { |
| | | ;((token.vlaue = ''), (userInfo.value = { userName: '', userType: '' })) |
| | | localStorage.removeItem(config.tokenKey) |
| | | localStorage.removeItem(config.userInfoKey) |
| | | localStorage.removeItem('xiehe-isUserInfo') |
| | | } |
| | | // 购物车数量 |
| | | let cartNum = ref<number>(1) |
| | | // 更新右侧弹出框购物车的数量 |
| | | const updateRightPop = () => { |
| | | cartNum.value += 1 |
| | | } |
| | | |
| | | // 购物车商品id |
| | | const shoppingIds = ref<number[]>([]) |
| | | const updateShoppingIds = (ids: number[]) => { |
| | | shoppingIds.value = ids |
| | | } |
| | | |
| | | // 已购买的商品id |
| | | const buyIds = ref<number[]>([]) |
| | | const updateBuyIds = (ids: number[]) => { |
| | | buyIds.value = ids |
| | | } |
| | | |
| | | return { |
| | | token, |
| | | setToken, |
| | | userInfo, |
| | | setUserInfo, |
| | | delteUserInfo, |
| | | cartNum, |
| | | updateRightPop, |
| | | shoppingIds, |
| | | updateShoppingIds, |
| | | buyIds, |
| | | updateBuyIds, |
| | | } |
| | | }) |
| | | |
| | | export const applyBookStore = defineStore('applyBook', () => { |
| | | //样书申请 |
| | | let electronicBookList = localStorage.getItem('electronicBookList') |
| | | ? ref(JSON.parse(localStorage.getItem('electronicBookList'))) |
| | | : ref([]) |
| | | let paperBookList = localStorage.getItem('paperBookList') |
| | | ? ref(JSON.parse(localStorage.getItem('paperBookList'))) |
| | | : ref([]) |
| | | //已申请图书 |
| | | let alreadyPaperBook = localStorage.getItem('alreadyPaperBook') |
| | | ? ref(JSON.parse(localStorage.getItem('alreadyPaperBook'))) |
| | | : ref([]) |
| | | let alreadyElectronicBook = localStorage.getItem('alreadyElectronicBook') |
| | | ? ref(JSON.parse(localStorage.getItem('alreadyElectronicBook'))) |
| | | : ref([]) |
| | | // 添加电子样书列表 |
| | | const appplyElectronicBook = (value: data) => { |
| | | electronicBookList.value.push(value) |
| | | localStorage.setItem('electronicBookList', JSON.stringify(electronicBookList.value)) |
| | | } |
| | | |
| | | //添加纸质样式列表 |
| | | const appplyPaperBook = (value: data) => { |
| | | paperBookList.value.push(value) |
| | | localStorage.setItem('paperBookList', JSON.stringify(paperBookList.value)) |
| | | } |
| | | |
| | | //删除电子样书列表 |
| | | const removeElectronicBook = (value: int) => { |
| | | electronicBookList.value.splice(value, 1) |
| | | localStorage.setItem('electronicBookList', JSON.stringify(electronicBookList.value)) |
| | | } |
| | | |
| | | //删除纸质样式 |
| | | const removePaperBook = (value: int) => { |
| | | paperBookList.value.splice(value, 1) |
| | | localStorage.setItem('paperBookList', JSON.stringify(paperBookList.value)) |
| | | } |
| | | const emptyBookList = (value: data) => { |
| | | if (value && value.type == 'eBook') { |
| | | electronicBookList.value = [] |
| | | localStorage.setItem('electronicBookList', JSON.stringify(electronicBookList.value)) |
| | | } else if (value && value.type == 'paperBook') { |
| | | paperBookList.value = [] |
| | | localStorage.setItem('paperBookList', JSON.stringify(paperBookList.value)) |
| | | } else { |
| | | paperBookList.value = [] |
| | | electronicBookList.value = [] |
| | | alreadyPaperBook.value = [] |
| | | alreadyElectronicBook.value = [] |
| | | localStorage.removeItem('electronicBookList') |
| | | localStorage.removeItem('paperBookList') |
| | | } |
| | | } |
| | | |
| | | //已申请图书 |
| | | const alreadyPaperBookList = (value: data) => { |
| | | alreadyPaperBook.value = value.list |
| | | localStorage.setItem('alreadyPaperBook', JSON.stringify(alreadyPaperBook.value)) |
| | | } |
| | | |
| | | const alreadyElectronicBookList = (value: data) => { |
| | | alreadyElectronicBook.value = value.list |
| | | localStorage.setItem('alreadyElectronicBook', JSON.stringify(alreadyElectronicBook.value)) |
| | | } |
| | | |
| | | return { |
| | | electronicBookList, |
| | | paperBookList, |
| | | alreadyPaperBook, |
| | | alreadyElectronicBook, |
| | | appplyElectronicBook, |
| | | appplyPaperBook, |
| | | removeElectronicBook, |
| | | removePaperBook, |
| | | emptyBookList, |
| | | alreadyPaperBookList, |
| | | alreadyElectronicBookList, |
| | | } |
| | | }) |
New file |
| | |
| | | <template> |
| | | <div class="classManagePage-box"> |
| | | <div class="classManagePage-nav" v-if="classInfo"> |
| | | <el-breadcrumb :separator-icon="ArrowRight"> |
| | | <el-breadcrumb-item>我的班级</el-breadcrumb-item> |
| | | <el-breadcrumb-item>{{ classInfo?.name }}</el-breadcrumb-item> |
| | | <el-breadcrumb-item>班级首页</el-breadcrumb-item> |
| | | </el-breadcrumb> |
| | | </div> |
| | | <div class="classManagePage-content"> |
| | | <div class="content-left fl"> |
| | | <div class="classOverview mainBorder"> |
| | | <div class=""> |
| | | <div class="title mainbg">班级概览</div> |
| | | </div> |
| | | <div class="bodyBox" v-if="currentClass?.name && !classLoading"> |
| | | <div class="classInfo"> |
| | | <div class="name">{{ currentClass?.name }}</div> |
| | | <!-- <div class="time">报名时间:2024.7.30--2024-8.03</div> --> |
| | | <div class="time">开课时间: {{ currentClass?.classTime }}</div> |
| | | </div> |
| | | <div class="line"></div> |
| | | <div class="classInfoBox"> |
| | | <div class="iconBox"> |
| | | <img :src="currentClass?.bookIcon ? currentClass?.bookIcon : defaultImg" /> |
| | | </div> |
| | | <div class="infoBox"> |
| | | <div class="main">{{ currentClass?.bookName }}</div> |
| | | <div class="job">作者:{{ classInfo?.author ?? '-' }}</div> |
| | | <div class="job">ISBN:{{ classInfo?.isbn ?? '-' }}</div> |
| | | </div> |
| | | </div> |
| | | <div class="line"></div> |
| | | <div class="classInfo"> |
| | | <div class="name">班级人数</div> |
| | | <div class="con"> |
| | | <span class="main">{{ currentClass?.memberCount }}</span |
| | | >/{{ currentClass?.maxUserCount }} |
| | | </div> |
| | | </div> |
| | | <div class="line"></div> |
| | | <div class="classInfo"> |
| | | <div class="name">作业次数</div> |
| | | <div class="con"> |
| | | <span class="main">{{ homeworkCount }}</span> |
| | | </div> |
| | | </div> |
| | | <!-- <div class="line"></div> |
| | | <div class="classInfo"> |
| | | <div class="name">教学进度</div> |
| | | <div class="con"><span class="main">0</span>/0</div> |
| | | </div> --> |
| | | </div> |
| | | <div |
| | | class="bodyBox" |
| | | style="display: flex; justify-content: center; align-items: center" |
| | | v-if="classLoading" |
| | | > |
| | | <div v-loading="classLoading"></div> |
| | | </div> |
| | | <div v-if="!currentClass && !classLoading"> |
| | | <el-empty style="padding: 0" :image-size="100" /> |
| | | </div> |
| | | </div> |
| | | <div class="classNotice"> |
| | | <div class="titleBox"> |
| | | <div class="border mainbg"></div> |
| | | <div class="title"> |
| | | <span>班级通知</span> |
| | | <el-icon |
| | | style="cursor: pointer" |
| | | color="#FF6D00" |
| | | v-if="noticeList.length > 0 && userInfo.role == 'Teacher'" |
| | | @click="toInfo" |
| | | > |
| | | <ArrowRightBold /> |
| | | </el-icon> |
| | | </div> |
| | | </div> |
| | | <div class="noticeList" v-if="noticeList.length > 0 && !noticeLoading"> |
| | | <div class="noticeItem" v-for="(item, index) in noticeList" :key="index"> |
| | | <div class="noticeContent"> |
| | | <span class="title">{{ item.name }}:</span> |
| | | <div class="contentText">{{ item.content }}</div> |
| | | </div> |
| | | <span class="time">{{ item.createDate }}</span> |
| | | </div> |
| | | </div> |
| | | <div v-if="noticeLoading" v-loading="noticeLoading"></div> |
| | | <div v-if="noticeList.length == 0 && !noticeLoading" class="notBox"> |
| | | <el-empty :image-size="100" /> |
| | | </div> |
| | | </div> |
| | | <div class="classTalk"> |
| | | <div class="titleBox"> |
| | | <div class="border mainbg"></div> |
| | | <div class="title"> |
| | | <span>班组话题</span> |
| | | <el-icon |
| | | style="cursor: pointer" |
| | | color="#FF6D00" |
| | | v-if="messageList.length > 0" |
| | | @click="toTalk" |
| | | > |
| | | <ArrowRightBold /> |
| | | </el-icon> |
| | | </div> |
| | | </div> |
| | | <div class="noticeList" v-if="messageList.length > 0 && !messageLoading"> |
| | | <div class="noticeItem" v-for="(item, index) in messageList" :key="index"> |
| | | <div class="noticeContent"> |
| | | <span class="title">{{ item.name }}</span> |
| | | <div class="content" v-if="item.publicText"> |
| | | <span>{{ item.publicText.publishRole }}:</span> |
| | | <span>{{ item.publicText.publisher }}</span> |
| | | </div> |
| | | <span>最近回复:{{ item.updateDate }}</span> |
| | | </div> |
| | | <span class="time">{{ item.createDate }}</span> |
| | | </div> |
| | | </div> |
| | | <div v-if="messageLoading" v-loading="messageLoading"></div> |
| | | <div v-if="messageList.length == 0 && !messageLoading" class="notBox"> |
| | | <el-empty :image-size="100" /> |
| | | </div> |
| | | </div> |
| | | <div class="classTask"> |
| | | <div class="titleBox" style="margin-bottom: 5px"> |
| | | <div class="border mainbg"></div> |
| | | <div class="title"> |
| | | <span>班级作业概览</span> |
| | | <!-- <el-icon |
| | | style="cursor: pointer" |
| | | color="#FF6D00" |
| | | v-if="tableData.length > 0" |
| | | @click="toWorkList" |
| | | > |
| | | <ArrowRightBold /> |
| | | </el-icon> --> |
| | | </div> |
| | | </div> |
| | | <div class="tableWall"> |
| | | <el-table :data="tableData" border style="width: 100%; font-size: 14px" size="small"> |
| | | <el-table-column prop="name" label="名称" /> |
| | | <el-table-column prop="beginDate" label="开始时间" /> |
| | | <el-table-column prop="endDate" label="截止时间" /> |
| | | <el-table-column prop="submitCount" label="完成情况(提交人数)" width="180" /> |
| | | </el-table> |
| | | </div> |
| | | </div> |
| | | <!-- <div class="classTask"> |
| | | <div class="titleBox" style="margin-bottom: 5px"> |
| | | <div class="border mainbg"></div> |
| | | <div class="title"> |
| | | <span>教学互动</span> |
| | | <el-icon |
| | | style="cursor: pointer" |
| | | color="#FF6D00" |
| | | v-if="tableData.length > 0" |
| | | @click="toTeaching" |
| | | > |
| | | <ArrowRightBold /> |
| | | </el-icon> |
| | | </div> |
| | | </div> |
| | | <div class="tableWall"> |
| | | <el-table :data="[]" border style="width: 100%; font-size: 14px" size="small"> |
| | | <el-table-column prop="index" label="序号" /> |
| | | <el-table-column prop="name" label="标题" /> |
| | | <el-table-column prop="beginDate" label="互动学生数(已互动/全部学生)" /> |
| | | <el-table-column prop="endDate" label="最后提交时间" /> |
| | | </el-table> |
| | | </div> |
| | | </div> --> |
| | | </div> |
| | | <div class="content-right fr"> |
| | | <div class="assistant"> |
| | | <div class="titleBox"> |
| | | <div class="border mainbg"></div> |
| | | <div class="title">助教列表</div> |
| | | <div class="options"> |
| | | <!-- <div class="optionsItem">移除</div> --> |
| | | <div class="copyIdBtn" @click="copy(currentClass)">复制邀请码</div> |
| | | </div> |
| | | </div> |
| | | <div class="avatarList" style="max-height: 147px; overflow-y: auto"> |
| | | <div class="avatarItem" v-for="(item, index) in teacherList" :key="index"> |
| | | <el-avatar v-if="item.appUser?.icon" :size="35" :src="item.appUser?.icon" /> |
| | | <el-avatar v-else :size="35" :icon="UserFilled" /> |
| | | <el-tooltip :content="item.appUser?.name" placement="top" effect="light"> |
| | | <span class="userName">{{ item.appUser?.name }}</span> |
| | | </el-tooltip> |
| | | </div> |
| | | <div class="nullBox" v-if="!Sloading && teacherList.length == 0"> |
| | | <el-empty :image-size="100" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="student"> |
| | | <div class="titleBox"> |
| | | <div class="border mainbg"></div> |
| | | <div class="title">学生列表</div> |
| | | <div class="options"> |
| | | <div class="copyIdBtn" @click="copy(currentClass)">复制邀请码</div> |
| | | </div> |
| | | </div> |
| | | <div class="avatarList" style="max-height: 570px; overflow-y: auto"> |
| | | <div class="avatarItem02" v-for="(item, index) in studentList" :key="index"> |
| | | <el-avatar v-if="item.appUser?.icon" :size="35" :src="item.appUser?.icon" /> |
| | | <el-avatar v-else :size="35" :icon="UserFilled" /> |
| | | <el-tooltip :content="item.appUser?.name" placement="top" effect="light"> |
| | | <span class="userName">{{ item.appUser?.name }}</span> |
| | | </el-tooltip> |
| | | </div> |
| | | <div class="nullBox" v-if="!Sloading && studentList.length == 0"> |
| | | <el-empty :image-size="100" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { useRoute, useRouter } from 'vue-router' |
| | | import { getPublicImage } from '@/assets/js/middleGround/tool.js' |
| | | import useClipboard from 'vue-clipboard3' |
| | | import { inject, onMounted, ref } from 'vue' |
| | | import moment from 'moment' |
| | | import { ElMessage } from 'element-plus' |
| | | import { ArrowRight, UserFilled } from '@element-plus/icons-vue' |
| | | import defaultImg from '@/assets/images/default-book-img.png' |
| | | |
| | | const { toClipboard } = useClipboard() |
| | | const route: any = useRoute() |
| | | const router: any = useRouter() |
| | | const classInfo = JSON.parse(route.query.classInfo) |
| | | const MG: any = inject('MG') |
| | | const config: any = inject('config') |
| | | const userInfo: any = ref() |
| | | |
| | | const currentClass = ref() |
| | | const classLoading = ref(true) |
| | | const messageTopicInfo = ref() |
| | | const talkTopicInfo = ref() |
| | | const noticeList: any = ref([]) |
| | | const noticeLoading = ref(true) |
| | | const messageList: any = ref([]) |
| | | const messageLoading = ref(true) |
| | | const tableData: any = ref([]) |
| | | const homeworkCount = ref(0) |
| | | const studentList: any = ref([]) |
| | | const teacherList: any = ref([]) |
| | | const Sloading = ref(false) |
| | | |
| | | onMounted(() => { |
| | | const userCache: any = localStorage.getItem('jesk-userInfo') |
| | | if (userCache) { |
| | | userInfo.value = JSON.parse(userCache) |
| | | } |
| | | getData() |
| | | getStudentList() |
| | | getTaskList() |
| | | }) |
| | | |
| | | // 复制 |
| | | const copy = async (val: any) => { |
| | | try { |
| | | await toClipboard(val.refCode) |
| | | ElMessage({ |
| | | message: '复制成功', |
| | | type: 'success' |
| | | }) |
| | | } catch (e) { |
| | | console.error(e) |
| | | } |
| | | } |
| | | |
| | | // 获取班级 |
| | | const getData = () => { |
| | | MG.edu |
| | | .getCourseClass({ |
| | | ClassIdOrRefCode: String(classInfo.id) |
| | | }) |
| | | .then((res: any) => { |
| | | if (res) { |
| | | res.bookName = res.linkProductDto.product.name |
| | | res.bookIcon = getPublicImage(res.linkProductDto.product.icon, 100) |
| | | res.classTime = |
| | | moment(res.beginDate).format('YYYY.MM.DD') + |
| | | '--' + |
| | | moment(res.endDate).format('YYYY.MM.DD') |
| | | } |
| | | currentClass.value = res |
| | | classLoading.value = false |
| | | getTopicInfo() |
| | | }) |
| | | } |
| | | |
| | | // 获取topic |
| | | const getTopicInfo = () => { |
| | | const pramas = { |
| | | classId: classInfo.id, |
| | | refCodes: [config.refCodes.message, config.refCodes.talk] |
| | | } |
| | | MG.edu.getClassTopic(pramas).then((res: any) => { |
| | | const list = res |
| | | messageTopicInfo.value = list.find((item: any) => item.refCode == config.refCodes.message) |
| | | if (messageTopicInfo.value.id) { |
| | | sessionStorage.messageId = messageTopicInfo.value.id |
| | | noticeLoading.value = true |
| | | getNotice() |
| | | } |
| | | talkTopicInfo.value = list.find((item: any) => item.refCode == config.refCodes.talk) |
| | | if (talkTopicInfo.value.id) { |
| | | sessionStorage.talkId = talkTopicInfo.value.id |
| | | messageLoading.value = true |
| | | getMessage() |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 获取班级通知 |
| | | const getNotice = () => { |
| | | const data = { |
| | | start: 0, |
| | | size: 3, |
| | | appRefCode: config.appRefCode, |
| | | topicIdOrRefCode: String(messageTopicInfo.value.id), |
| | | sort: { |
| | | type: 'Desc', |
| | | field: 'CreateDate', |
| | | subSorts: [] |
| | | } |
| | | } |
| | | MG.ugc.getTopicMessageList(data).then((res: any) => { |
| | | noticeLoading.value = false |
| | | const list = res.datas |
| | | noticeList.value = list.map((item: any) => { |
| | | return { |
| | | ...item, |
| | | createDate: moment(item.createDate).format('YYYY-MM-DD') |
| | | } |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | // 获取班级话题 |
| | | const getMessage = () => { |
| | | const data = { |
| | | start: 0, |
| | | size: 3, |
| | | appRefCode: config.appRefCode, |
| | | topicIdOrRefCode: String(talkTopicInfo.value.id), |
| | | sort: { |
| | | type: 'Desc', |
| | | field: 'CreateDate', |
| | | subSorts: [] |
| | | } |
| | | } |
| | | MG.ugc.getTopicMessageList(data).then((res: any) => { |
| | | messageLoading.value = false |
| | | const list = res.datas |
| | | messageList.value = list.map((item: any, i: number) => { |
| | | const str = item.content.indexOf('publisher') |
| | | if (str > -1) { |
| | | item.publicText = JSON.parse(item.content) |
| | | if (item.publicText && item.publicText.publishRole) { |
| | | item.publicText.publishRole = item.publicText.publishRole == 'Teacher' ? '助教' : '学生' |
| | | } |
| | | } |
| | | return { |
| | | ...item, |
| | | index: i + 1, |
| | | createDate: moment(item.createDate).format('YYYY-MM-DD HH:mm:ss'), |
| | | updateDate: moment(item.updateDate).format('YYYY-MM-DD HH:mm:ss') |
| | | } |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | // 获取教师/学生列表 |
| | | const getStudentList = () => { |
| | | Sloading.value = true |
| | | const data = { |
| | | start: 0, |
| | | size: 999, |
| | | groupId: classInfo.id, |
| | | filterList: [ |
| | | { |
| | | value: 'Normal', |
| | | field: 'State', |
| | | subFilters: [] |
| | | } |
| | | ] |
| | | } |
| | | MG.identity.getGroupUserList(data).then((res: any) => { |
| | | const { datas } = res |
| | | Sloading.value = false |
| | | let list: any = [] |
| | | if (datas.length > 0) { |
| | | list = datas.map((item: any, index: number) => { |
| | | if (item.linkType == 'Creator') { |
| | | const userInfo = item.appUser?.infoList?.find((citem: any) => citem.type == 'teacherInfo') |
| | | item.appUser.name = userInfo.name |
| | | item.appUser.icon = userInfo.icon |
| | | if (userInfo?.data) { |
| | | const iconData = JSON.parse(userInfo.data) |
| | | item.appUser.icon = getPublicImage(iconData?.relevantCertificates[0]?.md5, 100) ?? '' |
| | | } |
| | | } |
| | | if (item.linkType == 'RefCode' || item.linkType == 'Teacher') { |
| | | let userInfo = null |
| | | const wechatData = item.appUser?.infoList?.find((citem: any) => citem.type == 'WeChat') |
| | | const defaultData = item.appUser?.infoList?.find((citem: any) => citem.type == 'Default') |
| | | userInfo = defaultData |
| | | if (wechatData?.name) { |
| | | userInfo = wechatData |
| | | } |
| | | item.appUser.name = userInfo.name |
| | | item.appUser.icon = userInfo.icon |
| | | } |
| | | return { |
| | | ...item, |
| | | index: index + 1, |
| | | createDate: moment(item.createDate).format('YYYY-MM-DD') |
| | | } |
| | | }) |
| | | } |
| | | teacherList.value = list.filter((item: any) => item.linkType != 'RefCode') |
| | | studentList.value = list.filter((item: any) => item.linkType == 'RefCode') |
| | | }) |
| | | } |
| | | |
| | | // 前往话题 |
| | | const toTalk = () => { |
| | | classInfo.index = 5 |
| | | if (userInfo.value?.role != 'Teacher') { |
| | | classInfo.index = 3 |
| | | } |
| | | router.push({ |
| | | path: '/talkingPoint', |
| | | query: { |
| | | classInfo: JSON.stringify(classInfo) |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 前往通知 |
| | | const toInfo = () => { |
| | | classInfo.index = 0 |
| | | router.push({ |
| | | path: '/info', |
| | | query: { |
| | | classInfo: JSON.stringify(classInfo) |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 教学互动 |
| | | const toTeaching = () => {} |
| | | |
| | | // 班级作业概览 |
| | | const getTaskList = () => { |
| | | const data = { |
| | | start: 0, |
| | | size: 3, |
| | | sort: { |
| | | type: 'Desc', |
| | | field: 'CreateDate', |
| | | subSorts: [] |
| | | }, |
| | | filterList: [ |
| | | // { |
| | | // value: 'Normal', |
| | | // field: 'State', |
| | | // subFilters: [] |
| | | // }, |
| | | { |
| | | value: config.taskType.homeWork, |
| | | field: 'Type', |
| | | subFilters: [] |
| | | } |
| | | ], |
| | | groupId: classInfo?.id |
| | | } |
| | | MG.edu |
| | | .getTaskList(data) |
| | | .then((res: any) => { |
| | | let list: any = [] |
| | | if (res.datas.length > 0) { |
| | | list = res.datas |
| | | ?.map((item: any) => { |
| | | return { |
| | | ...item, |
| | | beginDate: moment(item.beginDate).format('YYYY-MM-DD'), |
| | | endDate: moment(item.endDate).format('YYYY-MM-DD') |
| | | } |
| | | }) |
| | | .slice(0, 3) |
| | | } |
| | | tableData.value = list |
| | | homeworkCount.value = res.totalSize |
| | | }) |
| | | .catch((e: any) => { |
| | | console.log(e) |
| | | }) |
| | | } |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .nullBox { |
| | | width: 100%; |
| | | display: flex; |
| | | justify-content: center; |
| | | } |
| | | .classManagePage-box { |
| | | padding: 20px; |
| | | .classManagePage-nav { |
| | | padding-bottom: 20px; |
| | | border-bottom: 1px solid #e6e8ed; |
| | | } |
| | | .classManagePage-content { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | .content-left { |
| | | width: 70%; |
| | | min-width: 950px; |
| | | .classOverview { |
| | | height: 190px; |
| | | margin-top: 30px; |
| | | border-radius: 10px; |
| | | .title { |
| | | width: 80px; |
| | | text-align: center; |
| | | padding: 7px; |
| | | border-radius: 8px 0 8px 0; |
| | | } |
| | | .bodyBox { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | margin-top: 20px; |
| | | padding: 0 20px; |
| | | .classInfoBox { |
| | | padding: 0 20px; |
| | | display: flex; |
| | | .iconBox { |
| | | width: 90px; |
| | | height: 120px; |
| | | img { |
| | | width: 100%; |
| | | height: 100%; |
| | | object-fit: contain; |
| | | } |
| | | } |
| | | .infoBox { |
| | | flex: 1; |
| | | padding-left: 10px; |
| | | .main { |
| | | font-size: 16px; |
| | | line-height: 20px; |
| | | } |
| | | .job { |
| | | // padding:10px; |
| | | margin-top: 20px; |
| | | } |
| | | } |
| | | } |
| | | .line { |
| | | width: 1px; |
| | | height: 130px; |
| | | background: linear-gradient( |
| | | 180deg, |
| | | rgba(255, 255, 255, 0) 0%, |
| | | #b7b7b7 51%, |
| | | rgba(255, 255, 255, 0) 100% |
| | | ); |
| | | } |
| | | .classInfo { |
| | | padding: 0 20px; |
| | | font-size: 16px; |
| | | min-width: 120px; |
| | | .name { |
| | | font-weight: bold; |
| | | margin-bottom: 20px; |
| | | text-align: center; |
| | | } |
| | | .con { |
| | | margin-top: 40px; |
| | | font-size: 22px; |
| | | text-align: center; |
| | | } |
| | | .time { |
| | | line-height: 30px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .classNotice { |
| | | height: 200px; |
| | | margin-top: 20px; |
| | | border-radius: 20px; |
| | | background: linear-gradient(180deg, #fffcf1 0%, #ffffff 100%); |
| | | border: 1px solid rgba(249, 200, 35, 0.2); |
| | | } |
| | | .classTalk { |
| | | height: 200px; |
| | | margin-top: 20px; |
| | | border-radius: 20px; |
| | | background: linear-gradient(180deg, #edf0ff 0%, #ffffff 100%); |
| | | border: 1px solid rgba(154, 171, 251, 0.2); |
| | | } |
| | | .classTask { |
| | | min-height: 200px; |
| | | margin-top: 20px; |
| | | border-radius: 20px; |
| | | border: 1px solid #e8ebf5; |
| | | .tableWall { |
| | | width: 100%; |
| | | padding: 10px 5px; |
| | | box-sizing: border-box; |
| | | } |
| | | } |
| | | .titleBox { |
| | | display: flex; |
| | | align-items: center; |
| | | margin: 20px 0; |
| | | font-size: 16px; |
| | | .title { |
| | | width: 100%; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding-right: 10px; |
| | | } |
| | | .border { |
| | | width: 4px; |
| | | height: 23px; |
| | | border-radius: 0px 10px 10px 0px; |
| | | margin-right: 10px; |
| | | } |
| | | } |
| | | } |
| | | .content-right { |
| | | width: 28%; |
| | | margin-left: 20px; |
| | | min-width: 270px; |
| | | |
| | | .assistant { |
| | | min-height: 160px; |
| | | margin-top: 30px; |
| | | border-radius: 10px; |
| | | border: 1px solid #e8ebf5; |
| | | overflow: hidden; |
| | | } |
| | | .student { |
| | | height: 640px; |
| | | margin-top: 20px; |
| | | border-radius: 10px; |
| | | border: 1px solid #e8ebf5; |
| | | overflow: hidden; |
| | | } |
| | | .titleBox { |
| | | display: flex; |
| | | align-items: center; |
| | | margin: 10px 0; |
| | | .border { |
| | | width: 4px; |
| | | height: 23px; |
| | | border-radius: 0px 10px 10px 0px; |
| | | margin-right: 10px; |
| | | } |
| | | } |
| | | } |
| | | .notBox { |
| | | width: 100%; |
| | | height: 100px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | } |
| | | .options { |
| | | flex: 1; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: flex-end; |
| | | padding-right: 10px; |
| | | .optionsItem { |
| | | color: #999; |
| | | margin-right: 10px; |
| | | cursor: pointer; |
| | | } |
| | | .copyIdBtn { |
| | | background-color: #fff; |
| | | color: #3b93fe; |
| | | padding: 0 6px; |
| | | border-radius: 50px; |
| | | overflow: hidden; |
| | | cursor: pointer; |
| | | } |
| | | } |
| | | .avatarList { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | width: 100%; |
| | | padding: 0 20px; |
| | | box-sizing: border-box; |
| | | .avatarItem, |
| | | .avatarItem02 { |
| | | width: 68px; |
| | | max-height: 88px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | padding: 6px 4px; |
| | | position: relative; |
| | | margin-left: 1px; |
| | | |
| | | .userName { |
| | | width: 100%; |
| | | margin: 3px 0; |
| | | white-space: nowrap; |
| | | text-overflow: ellipsis; |
| | | overflow: hidden; |
| | | text-align: center; |
| | | min-height: 30px; |
| | | line-height: 30px; |
| | | font-size: 12px; |
| | | } |
| | | } |
| | | // .avatarItem:hover { |
| | | // background-image: url('@/assets/images/class/avabg.png'); |
| | | // background-size: 100% 100%; |
| | | // background-position: center; |
| | | // background-repeat: no-repeat; |
| | | // cursor: pointer; |
| | | // } |
| | | .avatarItem:hover, |
| | | .avatarItem02:hover { |
| | | background: #eee; |
| | | } |
| | | } |
| | | .noticeList { |
| | | width: 100%; |
| | | height: calc(100% - 63px); |
| | | padding: 5px 25px; |
| | | overflow: auto; |
| | | .noticeItem { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | font-family: PingFang SC; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | line-height: 32px; |
| | | .noticeContent { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | color: #000000; |
| | | max-width: 800px; |
| | | white-space: nowrap; |
| | | text-overflow: ellipsis; |
| | | overflow: hidden; |
| | | .title { |
| | | margin-right: 30px; |
| | | } |
| | | .content { |
| | | margin-right: 30px; |
| | | } |
| | | } |
| | | .time { |
| | | color: #b7b7b7; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="pageHeader"> |
| | | <div class="headerBox"> |
| | | <div class="logoBox"> |
| | | <el-image :src="logo" class="logo" @click="goHome" style="cursor: pointer" /> |
| | | <div class="titleName"><img :src="titleName" /></div> |
| | | </div> |
| | | <div class="inputBox f1"> |
| | | <div class="signIn"> |
| | | <p v-if="!userStore.userInfo?.name" class="signInBox"> |
| | | <span @click="loginBtn">注册</span> |
| | | <span>|</span> |
| | | <span @click="signupBtn">登录</span> |
| | | </p> |
| | | <!-- 用户名 --> |
| | | <el-dropdown trigger="click" v-else> |
| | | <p class="el-dropdown-link signInBox"> |
| | | <span>{{ userStore.userInfo?.name }}</span> |
| | | <el-icon class="el-icon--right"> |
| | | <CaretBottom /> |
| | | </el-icon> |
| | | </p> |
| | | <template #dropdown> |
| | | <el-dropdown-menu> |
| | | <el-dropdown-item @click="router.push('/personalCenter')" |
| | | >个人中心</el-dropdown-item |
| | | > |
| | | <el-dropdown-item @click="logOut">退出登录</el-dropdown-item> |
| | | </el-dropdown-menu> |
| | | </template> |
| | | </el-dropdown> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <login ref="loginRef"></login> |
| | | <!-- 导航栏 --> |
| | | |
| | | <!-- 温馨提示弹窗 --> |
| | | <el-dialog v-model="tipsDialogState" width="420" align-center class="tipsDialog"> |
| | | <template #title>温馨提示</template> |
| | | <el-icon color="#e6a23c" size="24"> |
| | | <WarningFilled /> |
| | | </el-icon> |
| | | <p> |
| | | 如果您已使用【京师智教扫一扫】或【云上书房】 微信注册过,请使用微信扫码登录;如果您已在【 |
| | | 京师智教】PC端注册过,请使用手机号登录!继续注册将创建全新账户! |
| | | </p> |
| | | <template #footer> |
| | | <el-button @click="goPhoneSignup">手机号登录</el-button> |
| | | <el-button @click="goWechatSignUp">微信登录</el-button> |
| | | <el-button type="primary" @click="goLogin">继续注册</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import login from '@/layout/components/login.vue' |
| | | import { onMounted, ref, watchEffect, inject, watch } from 'vue' |
| | | import { ElMessage, ElMessageBox, type FormInstance } from 'element-plus' |
| | | import logo from '@/assets/images/header/logo.png' |
| | | import titleName from '@/assets/images/header/titleName.png' |
| | | import { useRouter } from 'vue-router' |
| | | import { useUserStore, applyBookStore } from '@/store' |
| | | const loginRef = ref() |
| | | const router = useRouter() |
| | | const userStore = useUserStore() |
| | | const applyBook = applyBookStore() |
| | | const MG = inject('MG') |
| | | const config = inject('config') |
| | | const tipsDialogState = ref<boolean>(false) // 温馨提示弹窗状态 |
| | | const wechatTipsState = ref<boolean>(false) |
| | | const localData = ref(localStorage.getItem('jsek-token')) |
| | | onMounted(() => { |
| | | // 判断是否微信扫码登录 |
| | | var url = window.location.href |
| | | if (url.indexOf('WeChatScanningCodeLogin') > -1) { |
| | | var querys = url.substring(url.indexOf('?') + 1).split('&') |
| | | var result = {} |
| | | for (var i = 0; i < querys.length; i++) { |
| | | var temp = querys[i].split('=') |
| | | if (temp.length < 2) { |
| | | result[temp[0]] = '' |
| | | } else { |
| | | result[temp[0]] = temp[1] |
| | | } |
| | | } |
| | | if (result && result.code) { |
| | | MG.identity |
| | | .loginByWeChatOpenCode({ |
| | | code: result.code, |
| | | appRefCode: config.appRefCode, |
| | | platform: 'PCWeb' |
| | | }) |
| | | .then((res) => { |
| | | if (res && res.status == 'Ok') { |
| | | userStore.setToken(res.token) |
| | | loginRef.value.getUserInfo() |
| | | MG.app.creatUserBehavior({ |
| | | refCode:"sign" |
| | | }).then(res => { |
| | | if(res){ |
| | | console.log("今日已积分") |
| | | } |
| | | }); |
| | | } |
| | | }) |
| | | } |
| | | } |
| | | }) |
| | | watchEffect(() => { |
| | | localData.value = localStorage.getItem('jsek-token') || '0' |
| | | }) |
| | | |
| | | // 注册按钮 |
| | | const loginBtn = () => { |
| | | tipsDialogState.value = true |
| | | } |
| | | // 登录按钮 |
| | | const signupBtn = () => { |
| | | loginRef.value.logIn() |
| | | } |
| | | |
| | | // 继续注册 |
| | | const goLogin = () => { |
| | | tipsDialogState.value = false |
| | | loginRef.value.signUp() |
| | | } |
| | | // 去微信登录 |
| | | const goWechatSignUp = () => { |
| | | tipsDialogState.value = false |
| | | // loginRef.value.logIn() |
| | | loginRef.value.setWechatTipsState() |
| | | } |
| | | // 去手机号登录 |
| | | const goPhoneSignup = () => { |
| | | tipsDialogState.value = false |
| | | loginRef.value.logIn() |
| | | loginRef.value.changeSignUp('authSignUp') |
| | | } |
| | | // 退出登录 |
| | | const logOut = () => { |
| | | router.push('/home') |
| | | userStore.delteUserInfo() |
| | | applyBook.emptyBookList() |
| | | sessionStorage.removeItem('cartNumber') |
| | | localStorage.removeItem('alreadyElectronicBook') |
| | | localStorage.removeItem('alreadyPaperBook') |
| | | ElMessage.success('退出成功') |
| | | } |
| | | |
| | | // logo首页定向 |
| | | const goHome = () => { |
| | | router.push('/home') |
| | | } |
| | | |
| | | </script> |
| | | |
| | | <style lang="less"> |
| | | .tipsDialog { |
| | | .el-dialog__header { |
| | | font-size: 18px; |
| | | } |
| | | |
| | | .el-dialog__body { |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | p { |
| | | margin-left: 10px; |
| | | line-height: 24px; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | | <style lang="less" scoped> |
| | | .pageHeader { |
| | | width: 100%; |
| | | background: #fff; |
| | | // border-bottom:1px solid #C0C0C0; |
| | | } |
| | | |
| | | .headerBox { |
| | | width: 1200px; |
| | | margin: 0 auto; |
| | | height: 60px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | .logoBox { |
| | | display: flex; |
| | | align-items: center; |
| | | .titleName { |
| | | font-size: 24px; |
| | | padding: 0 10px; |
| | | margin-left: 15px; |
| | | border-left: 1px solid #C0C0C0; |
| | | color:#181818; |
| | | font-family: Microsoft YaHei, Microsoft YaHei; |
| | | font-weight: 400; |
| | | } |
| | | /deep/.el-image__inner { |
| | | height: 48px; |
| | | border: 0; |
| | | padding: 0; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** 验证码图片 */ |
| | | .imgCode { |
| | | height: 40px; |
| | | margin-top: 5px; |
| | | } |
| | | |
| | | /** 看不清换一张 */ |
| | | .linkHight { |
| | | height: 20px; |
| | | |
| | | /deep/ .el-link__inner { |
| | | height: 100%; |
| | | } |
| | | } |
| | | |
| | | /** header登录注册文字 */ |
| | | .signIn { |
| | | height: 40px; |
| | | width: 95px; |
| | | min-width: 90px; |
| | | text-align: right; |
| | | margin-left: 80px; |
| | | font-weight: 400; |
| | | justify-content: space-around; |
| | | color: #000; |
| | | font-size: 14px; |
| | | |
| | | span:first-child, |
| | | span:last-child { |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .signInBox { |
| | | height: 100%; |
| | | width: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | span { |
| | | padding: 5px; |
| | | } |
| | | |
| | | .el-dropdown { |
| | | width: 100%; |
| | | height: 100%; |
| | | |
| | | span { |
| | | height: 40px; |
| | | line-height: 40px; |
| | | padding: 0; |
| | | display: block; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .selectPhone { |
| | | background: #fff; |
| | | } |
| | | |
| | | .el-select { |
| | | width: 100px; |
| | | height: 40px; |
| | | color: red; |
| | | |
| | | /deep/ .select-trigger { |
| | | height: 100%; |
| | | |
| | | .el-input--suffix { |
| | | height: 100%; |
| | | background-color: #fff; |
| | | } |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="questionDom"> |
| | | <div class="list-item" v-for="(pitem, pindex) in questionList" :key="pindex"> |
| | | <div class="list-item-title"> |
| | | {{ pitem.name }} |
| | | <span v-if="isPreview">(共 {{ pitem.data.length }} 题)</span> |
| | | </div> |
| | | <div class="list-item-box" v-for="(item, index) in pitem.data" :key="index"> |
| | | <div class="list-item-box-title-box"> |
| | | <el-checkbox |
| | | v-if="noCheckbox" |
| | | v-model="item.isCheck" |
| | | @change="checkItems($event, item)" |
| | | size="large" |
| | | > |
| | | <template #default> |
| | | <i class="el-icon-check"></i> |
| | | <span |
| | | class="custom-checkbox" |
| | | v-html="index + 1 + '、' + item.questionStem?.stemTxt" |
| | | ></span> |
| | | </template> |
| | | </el-checkbox> |
| | | <div class="list-item-box-title" v-else> |
| | | <span>{{ index + 1 }}</span |
| | | >、 |
| | | <span class="questionT" v-html="item.questionStem?.stemTxt"></span> |
| | | <span v-if="item.score > 0 && isPreview">({{ item.score }} 分)</span> |
| | | <el-icon v-if="isDelete" @click="deleteItem(item)" class="deletIcon"> |
| | | <Delete /> |
| | | </el-icon> |
| | | </div> |
| | | </div> |
| | | <div> |
| | | <div class="shortAnswer" v-if="item.questionType == 'shortAnswer' && !isJudge"> |
| | | <div class="anSwer" v-if="!isPreview"> |
| | | <div class="anSwerText" v-if="item.questionAnswer" style="margin: 15px 0"> |
| | | <span style="min-width: 40px">答案:</span |
| | | ><span v-html="item.questionAnswer"></span> |
| | | </div> |
| | | <div :class="isPreview ? 'questionAnalysisCon' : ''" v-if="item.questionAnalysisCon"> |
| | | 分析:<span v-html="item.questionAnalysisCon"></span> |
| | | </div> |
| | | </div> |
| | | <div v-else> |
| | | <!-- <el-input type="textarea" disabled :placeholder="item.userAnswer"></el-input> --> |
| | | <div v-html="item.userAnswer"></div> |
| | | </div> |
| | | </div> |
| | | <div class="discuss" v-else-if="item.questionType == 'discuss' && !isJudge"> |
| | | <div class="anSwer" v-if="!isPreview"> |
| | | <div class="anSwerText" v-if="item.questionAnswer" style="margin: 15px 0"> |
| | | <span style="min-width: 40px">答案:</span |
| | | ><span v-html="item.questionAnswer"></span> |
| | | </div> |
| | | <div :class="isPreview ? 'questionAnalysisCon' : ''" v-if="item.questionAnalysisCon"> |
| | | 分析:<span v-html="item.questionAnalysisCon"></span> |
| | | </div> |
| | | </div> |
| | | <div v-else> |
| | | <!-- <el-input type="textarea" disabled :placeholder="item.userAnswer"></el-input> --> |
| | | <div v-html="item.userAnswer"></div> |
| | | </div> |
| | | </div> |
| | | <div v-if="isJudge"> |
| | | <div class="shortAnswer anSwerText" v-if="item.answer" style="margin: 15px 0"> |
| | | <span v-html="item.answer"></span> |
| | | </div> |
| | | <div class="scoreData"> |
| | | <span>得分:</span> |
| | | <el-input-number v-model="item.score" style="width: 100px" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="completion" v-if="item.questionType == 'completion'"> |
| | | <div class="anSwer" v-if="!isPreview"> |
| | | <div class="anSwerText" v-if="item.questionAnswer" style="margin: 15px 0"> |
| | | <span style="min-width: 40px">答案:</span><span v-html="item.questionAnswer"></span> |
| | | </div> |
| | | <div :class="isPreview ? 'questionAnalysisCon' : ''" v-if="item.questionAnalysisCon"> |
| | | 分析:<span v-html="item.questionAnalysisCon"></span> |
| | | </div> |
| | | </div> |
| | | <div v-else> |
| | | <el-input |
| | | style="width: 200px" |
| | | v-model="item.userAnswer" |
| | | disabled |
| | | placeholder="请填写答案" |
| | | ></el-input> |
| | | </div> |
| | | </div> |
| | | <div class="classification" v-if="item.questionType == 'classification'"> |
| | | <div class="class-item-box"> |
| | | <span |
| | | class="class-item-box-span" |
| | | v-for="citem in item.questionOption" |
| | | :key="citem.index" |
| | | > |
| | | {{ citem.txt }} |
| | | </span> |
| | | </div> |
| | | <div class="anSwer" v-if="!isPreview"> |
| | | <div class="anSwerText" v-if="item.questionAnswer" style="margin: 15px 0"> |
| | | <span>答案:</span> |
| | | <div class="class-anSwer-box"> |
| | | <div |
| | | class="class-anSwer-box-item" |
| | | v-for="aitem in item.questionAnswer" |
| | | :key="aitem.key" |
| | | > |
| | | <span>{{ aitem.name }}:</span> |
| | | <div |
| | | class="class-anSwer-box-item-box" |
| | | v-for="citem in aitem.option" |
| | | :key="citem.key" |
| | | > |
| | | <span>{{ citem.txt }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div :class="isPreview ? 'questionAnalysisCon' : ''" v-if="item.questionAnalysisCon"> |
| | | 分析:<span v-html="item.questionAnalysisCon"></span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="judge" v-if="item.questionType == 'judge'"> |
| | | <el-radio-group v-model="item.customAnswer"> |
| | | <el-radio |
| | | v-for="ritem in item.questionOption" |
| | | :key="ritem.index" |
| | | :value="ritem.value" |
| | | :label="ritem.value" |
| | | size="large" |
| | | :disabled="!isPreview" |
| | | > |
| | | {{ ritem.value + '. ' + ritem.txt }} |
| | | </el-radio> |
| | | </el-radio-group> |
| | | <div class="anSwer" v-if="!isPreview"> |
| | | <div v-if="item.questionAnswer" style="margin: 15px 0"> |
| | | 答案:<span v-html="item.questionAnswer"></span> |
| | | </div> |
| | | <div :class="isPreview ? 'questionAnalysisCon' : ''" v-if="item.questionAnalysisCon"> |
| | | 分析:<span v-html="item.questionAnalysisCon"></span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="singleChoice" v-if="item.questionType == 'singleChoice'"> |
| | | <el-radio-group v-if="!isInteraction" v-model="item.customAnswer"> |
| | | <el-radio |
| | | v-for="ritem in item.questionOption" |
| | | :key="ritem.index" |
| | | :value="ritem.value" |
| | | :label="ritem.value" |
| | | size="large" |
| | | :disabled="!isPreview" |
| | | > |
| | | {{ ritem.value + '. ' + ritem.txt }} |
| | | </el-radio> |
| | | </el-radio-group> |
| | | <el-radio-group v-else v-model="item.userAnswer"> |
| | | <el-radio |
| | | v-for="ritem in item.questionOption" |
| | | :key="ritem.index" |
| | | :value="ritem.value" |
| | | :label="ritem.value" |
| | | size="large" |
| | | :disabled="isInteraction" |
| | | > |
| | | {{ ritem.value + '. ' + ritem.txt }} |
| | | </el-radio> |
| | | </el-radio-group> |
| | | <div class="anSwer" v-if="!isPreview"> |
| | | <div v-if="item.questionAnswer" style="margin: 15px 0"> |
| | | 答案:<span v-html="item.questionAnswer"></span> |
| | | </div> |
| | | <div :class="isPreview ? 'questionAnalysisCon' : ''" v-if="item.questionAnalysisCon"> |
| | | 分析:<span v-html="item.questionAnalysisCon"></span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="multipleChoice" v-if="item.questionType == 'multipleChoice'"> |
| | | <el-checkbox-group v-if="!isInteraction" v-model="item.customAnswer"> |
| | | <el-checkbox |
| | | v-for="mitem in item.questionOption" |
| | | :key="mitem.index" |
| | | :value="mitem.value" |
| | | :label="mitem.value" |
| | | size="large" |
| | | :disabled="!isPreview" |
| | | > |
| | | {{ mitem.value + '. ' + mitem.txt }} |
| | | </el-checkbox> |
| | | </el-checkbox-group> |
| | | <el-checkbox-group v-else v-model="item.userAnswer"> |
| | | <el-checkbox |
| | | v-for="mitem in item.questionOption" |
| | | :key="mitem.index" |
| | | :value="mitem.value" |
| | | :label="mitem.value" |
| | | size="large" |
| | | :disabled="isInteraction" |
| | | > |
| | | {{ mitem.value + '. ' + mitem.txt }} |
| | | </el-checkbox> |
| | | </el-checkbox-group> |
| | | <div class="anSwer" v-if="!isPreview"> |
| | | <div v-if="item.questionAnswer" style="margin: 15px 0"> |
| | | 答案:<span v-html="item.questionAnswer"></span> |
| | | </div> |
| | | <div :class="isPreview ? 'questionAnalysisCon' : ''" v-if="item.questionAnalysisCon"> |
| | | 分析:<span v-html="item.questionAnalysisCon"></span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="jugdeBtn" v-if="isJudge"> |
| | | <el-button type="primary" @click="submitScore">提交分数</el-button> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { defineProps, onMounted } from 'vue' |
| | | |
| | | const props = defineProps<{ |
| | | questionList?: any |
| | | noCheckbox?: boolean |
| | | isDelete?: boolean |
| | | isPreview?: boolean |
| | | isJudge?: boolean |
| | | isInteraction?: boolean |
| | | }>() |
| | | |
| | | const emit = defineEmits(['selectQuestion', 'deleteItem', 'judgeUpdate']) |
| | | |
| | | onMounted(() => {}) |
| | | |
| | | const checkItems = (e: Event, item: any) => { |
| | | emit('selectQuestion', item) |
| | | } |
| | | |
| | | const deleteItem = (item: any) => { |
| | | emit('deleteItem', item) |
| | | } |
| | | |
| | | const submitScore = () => { |
| | | const list = [...props.questionList] |
| | | let data: any = [] |
| | | list.forEach((item) => { |
| | | data.push(...item.data) |
| | | }) |
| | | emit('judgeUpdate', JSON.stringify(data)) |
| | | } |
| | | </script> |
| | | <style lang="less" scoped> |
| | | .questionDom { |
| | | width: 100%; |
| | | height: 100%; |
| | | overflow: auto; |
| | | padding: 10px; |
| | | box-sizing: border-box; |
| | | font-family: PingFang SC; |
| | | .questionT { |
| | | // display: flex; |
| | | flex-wrap: wrap; |
| | | align-items: baseline; |
| | | } |
| | | .jugdeBtn { |
| | | position: absolute; |
| | | bottom: -40px; |
| | | width: 100%; |
| | | display: flex; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .list-item { |
| | | width: 100%; |
| | | margin-bottom: 20px; |
| | | .list-item-title { |
| | | padding: 4px 0; |
| | | padding-left: 10px; |
| | | border-left: 4px solid #ff6c00; |
| | | color: #000; |
| | | margin: 15px 0; |
| | | } |
| | | } |
| | | |
| | | .list-item-box { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | ::v-deep(.list-item-box-title-box) { |
| | | margin-bottom: 10px; |
| | | .el-checkbox { |
| | | display: flex; |
| | | align-items: flex-start; |
| | | } |
| | | .el-checkbox__label { |
| | | line-height: 22px; |
| | | color: #000; |
| | | } |
| | | .el-checkbox__input { |
| | | margin-top: 3px; |
| | | } |
| | | .el-checkbox__input.is-checked + .el-checkbox__label { |
| | | color: #ff6c00; |
| | | } |
| | | } |
| | | |
| | | .list-item-box-title { |
| | | font-weight: 400; |
| | | font-size: 13px; |
| | | color: #000000; |
| | | display: flex; |
| | | width: 100%; |
| | | align-items: baseline; |
| | | justify-content: flex-start; |
| | | line-height: 25px; |
| | | .deletIcon { |
| | | color: red; |
| | | margin-left: 10px; |
| | | font-size: 15px; |
| | | cursor: pointer; |
| | | } |
| | | } |
| | | |
| | | .anSwer { |
| | | font-family: PingFang SC; |
| | | font-weight: 400; |
| | | font-size: 13px; |
| | | color: #000000; |
| | | line-height: 22px; |
| | | padding-left: 20px; |
| | | box-sizing: border-box; |
| | | .anSwerText { |
| | | display: flex; |
| | | justify-content: flex-start; |
| | | |
| | | .class-anSwer-box { |
| | | margin-left: 10px; |
| | | .class-anSwer-box-item { |
| | | display: flex; |
| | | justify-content: flex-start; |
| | | align-items: center; |
| | | .class-anSwer-box-item-box span { |
| | | margin-left: 10px; |
| | | margin-right: 20px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .questionAnalysisCon { |
| | | min-height: 40px; |
| | | padding: 10px; |
| | | background-color: #ff6a00a8; |
| | | } |
| | | } |
| | | .shortAnswer { |
| | | padding: 20px; |
| | | line-height: 22px; |
| | | border: 1px solid #eee; |
| | | border-radius: 5px; |
| | | margin: 10px 0; |
| | | } |
| | | ::v-deep(.judge), |
| | | ::v-deep(.singleChoice) { |
| | | width: 100%; |
| | | margin-bottom: 20px; |
| | | .el-radio-group { |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: center; |
| | | align-items: flex-start; |
| | | padding-left: 20px; |
| | | box-sizing: border-box; |
| | | } |
| | | } |
| | | ::v-deep(.multipleChoice) { |
| | | width: 100%; |
| | | margin-bottom: 20px; |
| | | .el-checkbox-group { |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: center; |
| | | align-items: flex-start; |
| | | padding-left: 20px; |
| | | box-sizing: border-box; |
| | | } |
| | | } |
| | | .class-item-box { |
| | | width: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: flex-start; |
| | | flex-wrap: wrap; |
| | | .class-item-box-span { |
| | | margin-left: 50px; |
| | | } |
| | | } |
| | | .scoreData { |
| | | display: flex; |
| | | justify-content: flex-start; |
| | | align-items: center; |
| | | span { |
| | | white-space: nowrap; |
| | | } |
| | | } |
| | | ::v-deep(.custom-checkbox) { |
| | | display: inline-flex; |
| | | justify-content: flex-start; |
| | | p { |
| | | white-space: pre-line !important; |
| | | } |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | export const menu: any = [ |
| | | { |
| | | label: '班级首页', |
| | | key: '1', |
| | | path: 'classHome', |
| | | icon: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16.002" viewBox="0 0 16 16.002"> |
| | | <path class="a" |
| | | d="M62.384,58.423a1.166,1.166,0,0,1,1.469,0l6.818,5.5a1.22,1.22,0,0,1,.193,1.692,1.178,1.178,0,0,1-.644.423l-.063.014v6.164a1.937,1.937,0,0,1-1.748,1.941l-.081.006-.084,0H57.994A1.932,1.932,0,0,1,56.083,72.3V66.052l-.042-.008a1.2,1.2,0,0,1-.919-1.108l0-.068a1.216,1.216,0,0,1,.449-.945Zm.8.853a.1.1,0,0,0-.124,0l-6.811,5.509a.1.1,0,0,0-.038.08.1.1,0,0,0,.1.1h.321a.547.547,0,0,1,.541.552v6.75a.838.838,0,0,0,.828.8h10.28a.839.839,0,0,0,.786-.846V65.521a.547.547,0,0,1,.541-.553h.321a.1.1,0,0,0,.078-.038.106.106,0,0,0-.016-.144ZM65.535,68.9a.545.545,0,0,1-.064.769,3.18,3.18,0,0,1-4.343,0,.546.546,0,0,1,.705-.833,2.092,2.092,0,0,0,2.931,0,.545.545,0,0,1,.769.063Z" |
| | | transform="translate(-55.12 -58.163)" /> |
| | | </svg>` |
| | | |
| | | }, |
| | | { |
| | | label: '班级管理', |
| | | key: '2', |
| | | path: 'studentManage', |
| | | icon: `<svg xmlns="http://www.w3.org/2000/svg" width="16.2" height="17.885" viewBox="0 0 16.2 17.885"> |
| | | <g transform="translate(-106.5 -63.9)"> |
| | | <path class="a" |
| | | d="M414.049,453.35a2.947,2.947,0,1,0-3.4,0,5.05,5.05,0,0,0-3.329,4.291.424.424,0,0,0,.42.464.413.413,0,0,0,.416-.369,4.21,4.21,0,0,1,8.388,0,.413.413,0,0,0,.416.369.423.423,0,0,0,.42-.464A5.05,5.05,0,0,0,414.049,453.35Zm-1.7-.3a2.106,2.106,0,1,1,2.106-2.106A2.109,2.109,0,0,1,412.348,453.052Z" |
| | | transform="translate(-294.781 -376.422)" /> |
| | | <path class="a" |
| | | d="M121.759,64H107.443a.842.842,0,0,0-.843.843v16a.842.842,0,0,0,.843.843h2.947a.42.42,0,0,0,0-.841h-2.526a.421.421,0,0,1-.42-.42V65.263a.421.421,0,0,1,.42-.42h13.473a.421.421,0,0,1,.42.42v5.052a.42.42,0,0,0,.841,0V64.843a.839.839,0,0,0-.839-.843Z" /> |
| | | <path class="a" |
| | | d="M256.42,235.541h9.262a.42.42,0,1,0,0-.841H256.42a.42.42,0,1,0,0,.841Zm0,2.526h3.369a.42.42,0,1,0,0-.841H256.42a.42.42,0,1,0,0,.841Z" |
| | | transform="translate(-146.451 -167.331)" /> |
| | | </g> |
| | | </svg>` |
| | | }, |
| | | { |
| | | label: '教学计划', |
| | | key: '3', |
| | | path: 'teachingPlan', |
| | | icon: `<svg xmlns="http://www.w3.org/2000/svg" width="16.2" height="16.2" viewBox="0 0 16.2 16.2"> |
| | | <path class="a" |
| | | d="M79.6,67.2a.4.4,0,0,0,.4-.4v-2a.8.8,0,0,0-.8-.8H64.8a.8.8,0,0,0-.8.8V79.2a.8.8,0,0,0,.8.8H79.2a.8.8,0,0,0,.8-.8V70a.4.4,0,1,0-.8,0v8.8a.4.4,0,0,1-.4.4H65.2a.4.4,0,0,1-.4-.4V65.2a.4.4,0,0,1,.4-.4H78.8a.4.4,0,0,1,.4.4v1.6A.4.4,0,0,0,79.6,67.2ZM76,72.8H68a.4.4,0,1,0,0,.8h8a.4.4,0,1,0,0-.8Zm0-3.2H73.959a2,2,0,0,0-3.918,0H68a.4.4,0,1,0,0,.8h2.8V70a1.2,1.2,0,1,1,2.4,0v.4H76a.4.4,0,1,0,0-.8Zm0,6H68a.4.4,0,1,0,0,.8h8a.4.4,0,0,0,0-.8Z" |
| | | transform="translate(-63.9 -63.9)" /> |
| | | </svg>` |
| | | }, |
| | | // { |
| | | // label: '备课', |
| | | // key: '4', |
| | | // path: 'prepareLessons', |
| | | // icon: beike |
| | | // }, |
| | | { |
| | | label: '作业管理', |
| | | key: '5', |
| | | path: 'jobManage', |
| | | icon: `<svg xmlns="http://www.w3.org/2000/svg" width="16.326" height="16.2" viewBox="0 0 16.326 16.2"> |
| | | <g transform="translate(-63.9 -63.9)"> |
| | | <path class="a" |
| | | d="M485.31,298.51a2,2,0,0,0-2.829,0l-4.525,4.527a2,2,0,0,0-.254,2.518l-.311.311a.4.4,0,0,0,.566.566l.311-.311a2,2,0,0,0,2.518-.254l4.525-4.525A2.007,2.007,0,0,0,485.31,298.51Zm-5.091,6.789a1.2,1.2,0,0,1-1.7-1.7l2.263-2.263,1.7,1.7Zm4.525-4.525-1.7,1.7-1.7-1.7,1.7-1.7a1.2,1.2,0,1,1,1.7,1.7Z" |
| | | transform="translate(-405.895 -229.748)" /> |
| | | <path class="a" |
| | | d="M76,78.8a.4.4,0,0,1-.4.4H65.2a.4.4,0,0,1-.4-.4V65.2a.4.4,0,0,1,.4-.4H75.6a.4.4,0,0,1,.4.4V68l.8-.8V64.8A.8.8,0,0,0,76,64H64.8a.8.8,0,0,0-.8.8V79.2a.8.8,0,0,0,.8.8H76a.8.8,0,0,0,.8-.8V76l-.8.8Z" /> |
| | | <path class="a" |
| | | d="M204.8,266a.4.4,0,0,0-.4-.4h-5.6a.4.4,0,1,0,0,.8h5.6A.4.4,0,0,0,204.8,266Zm-6,2a.4.4,0,1,0,0,.8H202a.4.4,0,0,0,0-.8Z" |
| | | transform="translate(-132 -198)" /> |
| | | </g> |
| | | </svg>` |
| | | }, |
| | | // { |
| | | // label: '测试管理', |
| | | // key: '6', |
| | | // path: 'testManage', |
| | | // icon: ceshi |
| | | // }, |
| | | { |
| | | label: '作业分析', |
| | | key: '7', |
| | | path: 'jobAnalysis', |
| | | icon: `<svg xmlns="http://www.w3.org/2000/svg" width="16.2" height="16.2" viewBox="0 0 16.2 16.2"> |
| | | <path class="a" |
| | | d="M69.2,67.2a.4.4,0,0,0,.4-.4V64.4a.4.4,0,1,0-.8,0v2.4A.4.4,0,0,0,69.2,67.2Zm2.8,0a.4.4,0,0,0,.4-.4V64.4a.4.4,0,1,0-.8,0v2.4A.4.4,0,0,0,72,67.2Zm2.8,0a.4.4,0,0,0,.4-.4V64.4a.4.4,0,0,0-.8,0v2.4A.4.4,0,0,0,74.8,67.2Zm4.4-2H76.8a.4.4,0,1,0,0,.8h2a.4.4,0,0,1,.4.4v2.4H64.8V66.4a.4.4,0,0,1,.4-.4h2a.4.4,0,0,0,0-.8H64.8a.8.8,0,0,0-.8.8V79.2a.8.8,0,0,0,.8.8H79.2a.8.8,0,0,0,.8-.8V66A.8.8,0,0,0,79.2,65.2Zm0,13.6a.4.4,0,0,1-.4.4H65.2a.4.4,0,0,1-.4-.4V69.6H79.2Zm-11.466-2a.4.4,0,0,0,.282-.118l2.941-2.941,2.12,1.766a.4.4,0,0,0,.543-.029l2.934-3.034a.4.4,0,1,0-.575-.557L73.3,74.655l-2.114-1.762a.4.4,0,0,0-.539.025l-3.2,3.2a.4.4,0,0,0,0,.566A.4.4,0,0,0,67.734,76.8Z" |
| | | transform="translate(-63.9 -63.9)" /> |
| | | </svg>` |
| | | }, |
| | | { |
| | | label: '教学互动', |
| | | key: '9', |
| | | path: 'teachInteraction', |
| | | icon: `<svg xmlns="http://www.w3.org/2000/svg" width="16.2" height="16.2" viewBox="0 0 1024 1024"> |
| | | <path |
| | | d="M447.766594 480.256747H252.078775C126.599562 480.256747 24.274252 377.931437 24.274252 252.452225S125.852662 24.647702 252.078775 24.647702 479.883297 126.973012 479.883297 252.452225V448.140044c0 17.925602-14.191101 32.116703-32.116703 32.116703zM252.078775 88.134209c-90.374909 0-164.318016 73.943107-164.318016 164.318016s73.943107 164.318016 164.318016 164.318016h164.318016v-164.318016c0-90.374909-73.943107-164.318016-164.318016-164.318016zM251.331875 999.352298C125.852662 999.352298 23.527352 897.026988 23.527352 771.547775s102.32531-227.804522 227.804523-227.804522H447.766594c17.178702 0 32.116703 14.191101 32.116703 32.116703v196.434719c-0.7469 124.732312-103.07221 227.057622-228.551422 227.057623z m0-392.122539c-90.374909 0-164.318016 73.943107-164.318017 164.318016s73.943107 164.318016 164.318017 164.318016 164.318016-73.943107 164.318016-164.318016v-164.318016h-164.318016zM773.415026 999.352298c-125.479212 0-227.804522-102.32531-227.804523-227.804523V575.113056c0-17.178702 14.191101-32.116703 32.116703-32.116703h196.43472c125.479212 0 227.804522 102.32531 227.804522 227.804522 0 36.598104-8.962801 72.449307-25.394603 104.56601-8.215901 15.684902-26.888403 21.660102-42.573304 13.444202-15.684902-8.215901-21.660102-26.888403-13.444201-42.573304 11.950401-23.153902 18.672502-49.295405 18.672502-75.436908 0-90.374909-73.943107-164.318016-164.318016-164.318016h-164.318016v164.318016c0 90.374909 73.943107 164.318016 164.318016 164.318016 17.178702 0 34.357403-2.9876 50.042305-8.2159 16.431802-5.228301 34.357403 3.7345 39.585703 20.166301 5.228301 16.431802-3.7345 34.357403-20.166302 39.585704-23.900802 8.962801-47.054705 12.697301-70.955506 12.697302zM773.415026 480.256747H577.727206c-17.178702 0-32.116703-14.191101-32.116703-32.116703V252.452225c0-125.479212 102.32531-227.804522 227.804523-227.804523s227.804522 102.32531 227.804522 227.804523-102.32531 227.804522-227.804522 227.804522z m-164.318017-63.486506h164.318017c90.374909 0 164.318016-73.943107 164.318016-164.318016s-73.943107-164.318016-164.318016-164.318016-164.318016 73.943107-164.318017 164.318016v164.318016z" /> |
| | | </svg>` |
| | | }, |
| | | { |
| | | label: '话题', |
| | | key: '8', |
| | | path: 'talkingPoint', |
| | | icon: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="15.97" viewBox="0 0 16 15.97"> |
| | | <g transform="translate(-58.026 -58.026)"> |
| | | <path class="a" |
| | | d="M66.026,74a8.075,8.075,0,0,1-3.049-.6,7.7,7.7,0,0,1-1.3-.694,15.665,15.665,0,0,0-2.294.513.505.505,0,0,1-.453-.121.483.483,0,0,1-.121-.453,11.77,11.77,0,0,0,.513-2.294,6.444,6.444,0,0,1-.694-1.268,8,8,0,1,1,15.4-3.049,7.988,7.988,0,0,1-8,7.97Zm-4.317-2.2a.767.767,0,0,1,.362.091,6.09,6.09,0,0,0,1.238.664A7.093,7.093,0,1,0,66.026,58.9,7.125,7.125,0,0,0,58.932,66a7.109,7.109,0,0,0,1.208,3.955c.121.181.242.332-.242,2.2a8.636,8.636,0,0,1,1.811-.362Z" /> |
| | | <path class="a" d="M332.766,395.146h-6.34a.453.453,0,0,1,0-.906h6.34a.453.453,0,0,1,0,.906Z" |
| | | transform="translate(-263.207 -330.267)" /> |
| | | <path class="a" |
| | | d="M375.27,315.381h-.091a.426.426,0,0,1-.362-.513l1.087-6.249a.444.444,0,0,1,.875.151l-1.057,6.219A.433.433,0,0,1,375.27,315.381Zm2.657,0h-.091a.426.426,0,0,1-.362-.513l1.087-6.249a.444.444,0,0,1,.875.151l-1.087,6.249A.423.423,0,0,1,377.927,315.381Z" |
| | | transform="translate(-311.176 -245.793)" /> |
| | | <path class="a" d="M290.1,569.226h-6.34a.453.453,0,1,1,0-.906h6.34a.453.453,0,0,1,0,.906Z" |
| | | transform="translate(-221.296 -501.268)" /> |
| | | </g> |
| | | </svg>` |
| | | } |
| | | ] |
New file |
| | |
| | | <template> |
| | | <div class="layoutBox"> |
| | | <Header class="header"></Header> |
| | | <div class="layoutContentBox clear"> |
| | | <div class="classContentBox clear"> |
| | | <div class="leftList fl"> |
| | | <!-- <div class="main title" @click="goBack()"> --> |
| | | <div class="main title"> |
| | | <!-- <el-icon><ArrowLeft /></el-icon> --> |
| | | <span>我的班级</span> |
| | | </div> |
| | | <div class="classInfo-box"> |
| | | <div class="iconBox"><img :src="classIcon" /></div> |
| | | <div class="infoBox"> |
| | | <div class="main">{{ classInfo?.name }}</div> |
| | | <div class="job" v-if="userData && userData.role == 'Teacher'"> |
| | | <span class="mainbg">助教</span> |
| | | </div> |
| | | <div class="job" v-else><span class="mainbg">学生</span></div> |
| | | </div> |
| | | </div> |
| | | <div class="line"></div> |
| | | <ul class="menu"> |
| | | <li |
| | | v-for="(item, index) in listMenu" |
| | | :key="index" |
| | | @click="goRouter(item, index)" |
| | | :class="activeIndex == index ? 'activeItem mainbg hover' : 'menuItem hover'" |
| | | > |
| | | <span |
| | | :style="{ |
| | | fill: activeIndex == index ? '#fff' : '#000' |
| | | }" |
| | | v-html="item.icon" |
| | | > |
| | | </span> |
| | | <span>{{ item.label }}</span> |
| | | </li> |
| | | </ul> |
| | | </div> |
| | | <div class="rightContent"> |
| | | <div> |
| | | <!-- 让主体做子路由的显示 --> |
| | | <router-view /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { ref, watch, provide, onMounted, inject } from 'vue' |
| | | import { useRoute, useRouter, onBeforeRouteUpdate } from 'vue-router' |
| | | import Header from './components/headerPage.vue' |
| | | import { menu } from './config' |
| | | import { getPublicImage } from '@/assets/js/middleGround/tool.js' |
| | | import defaultImg from '@/assets/images/default-book-img.png' |
| | | |
| | | const router: any = useRouter() |
| | | const route: any = useRoute() |
| | | const MG: any = inject('MG') |
| | | const config: any = inject('config') |
| | | const routerVal = router.currentRoute.value |
| | | const path = ref(routerVal.path) |
| | | const label = ref('') |
| | | const classInfo: any = ref() |
| | | const classIcon: any = ref() |
| | | const listMenu = ref([]) |
| | | const activeIndex = ref(0) |
| | | const userData = ref() |
| | | |
| | | watch(router.currentRoute, (val) => { |
| | | path.value = val.path |
| | | if (val.query.classInfo) { |
| | | const data: any = val.query.classInfo |
| | | const routerInfo: any = JSON.parse(data) |
| | | activeIndex.value = routerInfo.index |
| | | } |
| | | }) |
| | | |
| | | watch(classInfo, (val) => { |
| | | if (val) { |
| | | activeIndex.value = val.index |
| | | } |
| | | if (!val.index) { |
| | | activeIndex.value = 0 |
| | | } |
| | | }) |
| | | |
| | | onBeforeRouteUpdate(async (to, from) => { |
| | | path.value = to.path |
| | | }) |
| | | |
| | | onMounted(() => { |
| | | classInfo.value = JSON.parse(route.query.classInfo) |
| | | classIcon.value = classInfo.value.icon ? getPublicImage(classInfo.value.icon, 200) : defaultImg |
| | | menu.forEach((item) => { |
| | | if ('/' + item.path === path.value) { |
| | | label.value = item.label |
| | | } |
| | | }) |
| | | const userCache: any = localStorage.getItem('jesk-userInfo') |
| | | const userInfo = JSON.parse(userCache) |
| | | userData.value = userInfo |
| | | if (!userInfo) { |
| | | router.push({ |
| | | path: '/' |
| | | }) |
| | | return false |
| | | } |
| | | if (userInfo.role != 'Teacher') { |
| | | const data: any = menu.filter( |
| | | (item: any) => item.path != 'studentManage' && item.path != 'jobAnalysis' |
| | | ) |
| | | listMenu.value = data |
| | | } else { |
| | | const data: any = menu |
| | | // if (!classInfo.bookRefCode) { |
| | | // // 融媒体图书,无数字阅读,无法跳转 |
| | | // const list: any = menu.filter((item: any) => item.path != 'teachingPlan') |
| | | // listMenu.value = list; |
| | | // return false |
| | | // } |
| | | listMenu.value = data |
| | | } |
| | | }) |
| | | |
| | | const goRouter = (item: any, index: number) => { |
| | | activeIndex.value = index |
| | | if (!localStorage.getItem('jsek-token') || localStorage.getItem('jsek-token') == null) { |
| | | router.push({ |
| | | path: '/home', |
| | | query: { |
| | | showLogin: '1' |
| | | } |
| | | }) |
| | | } else { |
| | | label.value = item.label |
| | | classInfo.value.index = index |
| | | if (item.key == 5) { |
| | | router.push({ |
| | | path: userData.value.role != 'Teacher' ? '/studentJob' : '/jobManage', |
| | | query: { |
| | | classInfo: JSON.stringify(classInfo.value) |
| | | } |
| | | }) |
| | | } else { |
| | | router.push({ |
| | | path: item.path, |
| | | query: { |
| | | classInfo: JSON.stringify(classInfo.value) |
| | | } |
| | | }) |
| | | } |
| | | } |
| | | } |
| | | |
| | | const goBack = () => { |
| | | router.go(-1) |
| | | } |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .layoutBox { |
| | | width: 100%; |
| | | height: 100vh; |
| | | display: flex; |
| | | flex-direction: column; |
| | | background-color: #fff; |
| | | .layoutContentBox { |
| | | flex: 1; |
| | | height: auto; |
| | | } |
| | | .classContentBox { |
| | | padding: 10px 40px; |
| | | display: flex; |
| | | height: 100%; |
| | | .leftList { |
| | | padding: 20px; |
| | | width: 280px; |
| | | min-width: 230px; |
| | | box-shadow: 0px 0px 20px 1px #ccc; |
| | | border-radius: 3px; |
| | | background-color: #fff; |
| | | .title { |
| | | font-size: 16px; |
| | | display: flex; |
| | | align-items: center; |
| | | cursor: pointer; |
| | | span { |
| | | margin-left: 10px; |
| | | } |
| | | } |
| | | .classInfo-box { |
| | | padding: 20px 10px; |
| | | margin-bottom: 10px; |
| | | display: flex; |
| | | .iconBox { |
| | | width: 90px; |
| | | height: 120px; |
| | | img { |
| | | width: 100%; |
| | | height: 100%; |
| | | object-fit: contain; |
| | | } |
| | | } |
| | | .infoBox { |
| | | flex: 1; |
| | | padding-left: 10px; |
| | | .main { |
| | | font-size: 16px; |
| | | line-height: 20px; |
| | | } |
| | | .job { |
| | | // padding:10px; |
| | | margin-top: 20px; |
| | | span { |
| | | padding: 5px 15px; |
| | | border-radius: 20px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .line { |
| | | width: 100%; |
| | | height: 1px; |
| | | background: linear-gradient(63deg, #ffffff 0%, #e0f2ff 51%, #ffffff 100%); |
| | | } |
| | | .menu { |
| | | margin-top: 20px; |
| | | li { |
| | | height: 36px; |
| | | padding: 0 40px; |
| | | margin: 5px 0; |
| | | font-size: 16px; |
| | | display: flex; |
| | | align-items: center; |
| | | position: relative; |
| | | |
| | | img { |
| | | width: 18px; |
| | | height: 18px; |
| | | } |
| | | |
| | | span { |
| | | margin-left: 10px; |
| | | font-size: 15px; |
| | | } |
| | | } |
| | | |
| | | .activeItem { |
| | | background-size: 100% 100%; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .rightContent { |
| | | flex: 1; |
| | | overflow: auto; |
| | | min-width: 800px; |
| | | margin-left: 15px; |
| | | box-shadow: 0px 0px 20px 1px #ccc; |
| | | border-radius: 3px; |
| | | background-color: #fff; |
| | | } |
| | | } |
| | | |
| | | .header { |
| | | flex-shrink: 0; |
| | | width: 100%; |
| | | } |
| | | } |
| | | |
| | | @media screen and (min-width: 1200px) { |
| | | .layoutContentBox { |
| | | flex: 1; |
| | | overflow: auto; |
| | | // display: flex; |
| | | // flex-direction: column; |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="classManagePage-box"> |
| | | <div class="classManagePage-nav"> |
| | | <el-breadcrumb :separator-icon="ArrowRight"> |
| | | <el-breadcrumb-item>我的班级</el-breadcrumb-item> |
| | | <el-breadcrumb-item>{{ classInfo?.name }}</el-breadcrumb-item> |
| | | <el-breadcrumb-item>班级通知审核</el-breadcrumb-item> |
| | | </el-breadcrumb> |
| | | </div> |
| | | <div class="classManagePage-content"> |
| | | <div class="backBtn"> |
| | | <el-button @click="goBack()" type="primary" link> |
| | | <el-icon style="margin-right: 5px"><ArrowLeftBold /></el-icon> 返回 |
| | | </el-button> |
| | | </div> |
| | | <div class="contentBox"> |
| | | <div class="titleOptions"> |
| | | <span>班级通知审核列表</span> |
| | | </div> |
| | | <div class="content-tab-box"> |
| | | <div class="content-list-box"> |
| | | <el-table |
| | | :header-cell-style="{ background: '#eee' }" |
| | | :data="dataList" |
| | | max-height="600px" |
| | | style="width: 100%" |
| | | v-loading="pages.loading" |
| | | > |
| | | <el-table-column prop="id" label="序号" width="70" /> |
| | | <el-table-column prop="name" label="通知" width="500" /> |
| | | <el-table-column prop="state" label="状态" #default="scope"> |
| | | <span style="color: #ff6d00" v-if="scope.row.state == 'WaitAudit'">待审核</span> |
| | | <span style="color: #67c23a" v-if="scope.row.state == 'Normal'">已通过</span> |
| | | <span style="color: red" v-if="scope.row.state == 'Reject'">已拒绝</span> |
| | | </el-table-column> |
| | | <el-table-column prop="createDate" label="创建时间" /> |
| | | <el-table-column label="操作" #default="scope"> |
| | | <el-button |
| | | link |
| | | v-if="scope.row.state != 'Normal'" |
| | | type="success" |
| | | size="small" |
| | | @click="successMessage(scope.row)" |
| | | > |
| | | 发布 |
| | | </el-button> |
| | | <el-button link type="danger" size="small" @click="removeMessage(scope.row)"> |
| | | 删除 |
| | | </el-button> |
| | | </el-table-column> |
| | | </el-table> |
| | | <div class="pageBox"> |
| | | <el-pagination |
| | | style="float: right" |
| | | v-model:current-page="pages.currentPage" |
| | | :page-size="pages.pageSize" |
| | | :size="'small'" |
| | | :disabled="pages.count <= 1" |
| | | layout="total, prev, pager, next" |
| | | :total="pages.count" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { useRoute, useRouter } from 'vue-router' |
| | | import { inject, onMounted, reactive, ref } from 'vue' |
| | | import { Search, UserFilled, ArrowRight } from '@element-plus/icons-vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import moment from 'moment' |
| | | |
| | | const route: any = useRoute() |
| | | const router = useRouter() |
| | | const classInfo = JSON.parse(route.query.classInfo) |
| | | const MG: any = inject('MG') |
| | | const config: any = inject('config') |
| | | const tool: any = inject('toolClass') |
| | | |
| | | let pages = reactive({ |
| | | currentPage: 1, |
| | | page: 1, |
| | | pageSize: 15, |
| | | count: 0, |
| | | loading: true |
| | | }) |
| | | |
| | | const dataList: any = ref([]) |
| | | |
| | | // 获取班级通知 |
| | | const getNotice = () => { |
| | | const data = { |
| | | start: (pages.page - 1) * pages.pageSize, |
| | | size: pages.pageSize, |
| | | appRefCode: config.appRefCode, |
| | | topicIdOrRefCode: String(sessionStorage.messageId), |
| | | sort: { |
| | | type: 'Desc', |
| | | field: 'CreateDate', |
| | | subSorts: [] |
| | | } |
| | | } |
| | | MG.ugc |
| | | .getTopicMessageList(data) |
| | | .then((res: any) => { |
| | | pages.loading = false |
| | | pages.count = res.totalSize |
| | | const list = res.datas |
| | | dataList.value = list.map((item: any) => { |
| | | return { |
| | | ...item, |
| | | createDate: moment(item.createDate).format('YYYY-MM-DD') |
| | | } |
| | | }) |
| | | }) |
| | | .catch((err: any) => { |
| | | pages.loading = false |
| | | console.log(err) |
| | | }) |
| | | } |
| | | |
| | | // 通过 |
| | | const successMessage = (item: any) => { |
| | | const data = { |
| | | id: item.id, |
| | | name: item.name, |
| | | description: item.description, |
| | | icon: item.icon, |
| | | type: item.type, |
| | | state: 'Normal', |
| | | content: JSON.stringify(item.publicText), |
| | | newDataRequests: [], |
| | | updateDataRequests: [] |
| | | } |
| | | MG.ugc |
| | | .updateTopicMessage(data) |
| | | .then((res: any) => { |
| | | if (res) { |
| | | ElMessage({ |
| | | type: 'success', |
| | | message: '已发布' |
| | | }) |
| | | getNotice() |
| | | } |
| | | }) |
| | | .catch((err: any) => { |
| | | console.log(err, '审核话题') |
| | | }) |
| | | } |
| | | |
| | | // 删除 |
| | | const removeMessage = (item: any) => { |
| | | const data = { |
| | | messageIds: [item.id] |
| | | } |
| | | MG.ugc |
| | | .delTopicMessage(data) |
| | | .then((res: any) => { |
| | | if (res) { |
| | | ElMessage.success('已删除') |
| | | getNotice() |
| | | } |
| | | }) |
| | | .catch((err: any) => { |
| | | ElMessage.error('删除失败,请稍后再试') |
| | | console.log(err) |
| | | }) |
| | | } |
| | | |
| | | // 分页 |
| | | const handleSizeChange = (val: number) => { |
| | | pages.pageSize = val |
| | | getNotice() |
| | | } |
| | | |
| | | const handleCurrentChange = (val: number) => { |
| | | pages.page = val |
| | | pages.currentPage = val |
| | | getNotice() |
| | | } |
| | | |
| | | const goBack = () => { |
| | | router.go(-1) |
| | | } |
| | | |
| | | onMounted(() => { |
| | | getNotice() |
| | | }) |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .classManagePage-box { |
| | | background: #fff; |
| | | |
| | | .classManagePage-nav { |
| | | width: 100%; |
| | | padding: 0 20px; |
| | | height: 40px; |
| | | border-bottom: 1px solid #e6e8ed; |
| | | position: sticky; |
| | | top: 0; |
| | | z-index: 999; |
| | | display: flex; |
| | | align-items: center; |
| | | background: #fff; |
| | | } |
| | | .classManagePage-content { |
| | | width: 100%; |
| | | position: relative; |
| | | .backBtn { |
| | | width: 100%; |
| | | height: 45px; |
| | | margin-bottom: 10px; |
| | | padding: 0 20px; |
| | | display: flex; |
| | | align-items: center; |
| | | position: sticky; |
| | | top: 40px; |
| | | z-index: 99; |
| | | background: #fff; |
| | | box-shadow: 0px 0px 20px 1px #eeeeee83; |
| | | } |
| | | .contentBox { |
| | | width: 100%; |
| | | padding: 0 20px; |
| | | box-sizing: border-box; |
| | | .titleOptions { |
| | | width: 160px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 20px; |
| | | span { |
| | | height: 30px; |
| | | font-family: PingFang SC; |
| | | font-weight: bold; |
| | | font-size: 16px; |
| | | color: #333; |
| | | line-height: 30px; |
| | | text-align: left; |
| | | border-left: 6px solid #ff6c00; |
| | | padding-left: 10px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="classManagePage-box"> |
| | | <div class="classManagePage-nav"> |
| | | <el-breadcrumb :separator-icon="ArrowRight"> |
| | | <el-breadcrumb-item>我的班级</el-breadcrumb-item> |
| | | <el-breadcrumb-item>{{ classInfo?.name }}</el-breadcrumb-item> |
| | | <el-breadcrumb-item>互动学生列表</el-breadcrumb-item> |
| | | </el-breadcrumb> |
| | | </div> |
| | | <div class="classManagePage-content"> |
| | | <div class="backBtn"> |
| | | <el-button @click="goBack()" type="primary" link> |
| | | <el-icon style="margin-right: 5px"><ArrowLeftBold /></el-icon> 返回 |
| | | </el-button> |
| | | </div> |
| | | <div class="contentBox"> |
| | | <div class="titleOptions"> |
| | | <span>互动学生列表</span> |
| | | </div> |
| | | <div class="content-tab-box"> |
| | | <div class="content-list-box"> |
| | | <el-table |
| | | :header-cell-style="{ background: '#eee' }" |
| | | :data="dataList" |
| | | max-height="600px" |
| | | style="width: 100%" |
| | | v-loading="pages.loading" |
| | | > |
| | | <el-table-column prop="index" label="序号" width="70" /> |
| | | <el-table-column prop="userName" label="姓名" width="500" /> |
| | | <el-table-column label="状态"> |
| | | <el-button link type="success">已完成</el-button> |
| | | </el-table-column> |
| | | <el-table-column prop="questionTime" label="答题时间" /> |
| | | <el-table-column label="操作" #default="scoped"> |
| | | <el-button link type="primary" @click="getQuestions(scoped.row)"> |
| | | 答题详情 |
| | | </el-button> |
| | | </el-table-column> |
| | | </el-table> |
| | | <div class="pageBox"> |
| | | <el-pagination |
| | | style="float: right" |
| | | v-model:current-page="pages.currentPage" |
| | | :page-size="pages.pageSize" |
| | | :size="'small'" |
| | | :disabled="pages.count <= 1" |
| | | layout="total, prev, pager, next" |
| | | :total="pages.count" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <!-- 浏览答题 --> |
| | | <el-dialog |
| | | class="customDialog" |
| | | title="浏览答题" |
| | | v-model="visible" |
| | | destroy-on-close |
| | | width="1000" |
| | | align-center |
| | | > |
| | | <div class="pubContent" v-if="dialogList.length > 0 && !dialogLLoading"> |
| | | <div v-for="(item, index) in dialogList" :key="index"> |
| | | <span class="userName">答题人:{{ item.userName ?? '-' }}</span> |
| | | <question-dom |
| | | v-if="item.questionTypeList.length > 0" |
| | | :questionList="item.questionTypeList" |
| | | :noCheckbox="false" |
| | | :is-preview="true" |
| | | :is-interaction="true" |
| | | /> |
| | | </div> |
| | | </div> |
| | | <div class="pubContent" v-if="dialogLLoading" v-loading="dialogLLoading"></div> |
| | | <div class="pubContent noData" v-if="dialogList.length == 0 && !dialogLLoading"> |
| | | <el-empty></el-empty> |
| | | </div> |
| | | <template #footer> |
| | | <div class="selectedFooter" style="padding: 0"> |
| | | <el-button type="primary" @click="visible = false"> 关闭 </el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | <script setup lang="ts"> |
| | | import { useRoute, useRouter } from 'vue-router' |
| | | import { inject, onMounted, reactive, ref } from 'vue' |
| | | import { Search, UserFilled, ArrowRight } from '@element-plus/icons-vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import moment from 'moment' |
| | | import questionDom from './components/questionDom.vue' |
| | | |
| | | const route: any = useRoute() |
| | | const router = useRouter() |
| | | const classInfo = JSON.parse(route.query.classInfo) |
| | | const MG: any = inject('MG') |
| | | const config: any = inject('config') |
| | | const tool: any = inject('toolClass') |
| | | |
| | | const dataList = ref([]) |
| | | let pages = reactive({ |
| | | currentPage: 1, |
| | | page: 1, |
| | | pageSize: 15, |
| | | count: 0, |
| | | loading: false |
| | | }) |
| | | |
| | | const visible = ref(false) |
| | | const dialogList: any = ref([]) |
| | | const dialogLLoading = ref(false) |
| | | const defaultCmsPath = ref('') |
| | | |
| | | const handleDelete = (item: any) => { |
| | | const data = { |
| | | messageIds: [item.id] |
| | | } |
| | | MG.ugc.delTopicMessage(data).then((res: any) => { |
| | | ElMessage.success('删除成功') |
| | | getMessage() |
| | | }) |
| | | } |
| | | |
| | | // 获取当前话题 |
| | | const getMessage = () => { |
| | | pages.loading = true |
| | | const data = { |
| | | start: (pages.page - 1) * pages.pageSize, |
| | | size: pages.pageSize, |
| | | appRefCode: config.appRefCode, |
| | | topicIdOrRefCode: String(classInfo.teachInteractionId), |
| | | sort: { |
| | | type: 'Desc', |
| | | field: 'CreateDate' |
| | | }, |
| | | searchList: [ |
| | | { |
| | | keywords: classInfo.questionName, |
| | | field: 'Name', |
| | | compareType: 'Contains' |
| | | } |
| | | ] |
| | | } |
| | | MG.ugc.getTopicMessageList(data).then((res: any) => { |
| | | pages.loading = false |
| | | pages.count = res.totalSize |
| | | dataList.value = res.datas.map((item: any, i: number) => { |
| | | item.question = [] |
| | | item.bookId = null |
| | | item.path = '' |
| | | item.index = i + 1 |
| | | try { |
| | | const obj = JSON.parse(item.content) |
| | | if (obj.bookId) { |
| | | item.question = obj.content |
| | | item.bookId = obj.bookId |
| | | item.path = obj.path |
| | | item.userName = obj.userName ?? '-' |
| | | } |
| | | } catch (error) { |
| | | console.log(item) |
| | | } |
| | | return { |
| | | ...item, |
| | | questionTime: moment(item.updateDate).format('YYYY-MM-DD HH:mm:ss') |
| | | } |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | // 分页 |
| | | const handleSizeChange = (val: number) => { |
| | | pages.pageSize = val |
| | | getMessage() |
| | | } |
| | | |
| | | const handleCurrentChange = (val: number) => { |
| | | pages.page = val |
| | | pages.currentPage = val |
| | | getMessage() |
| | | } |
| | | |
| | | onMounted(() => { |
| | | defaultCmsPath.value = classInfo.bookRefCode ? 'jsek_digitalTextbooks' : 'defaultGoodsStore3' |
| | | getMessage() |
| | | }) |
| | | |
| | | // 获取题目列表 |
| | | const getQuestions = (item: any) => { |
| | | visible.value = true |
| | | dialogLLoading.value = true |
| | | MG.store |
| | | .getProductDetail({ |
| | | path: defaultCmsPath.value, |
| | | queryType: '*', |
| | | productId: classInfo.bookId, |
| | | storeInfo: defaultCmsPath.value, |
| | | cmsPath: item.path, |
| | | itemFields: { |
| | | Embedded_QuestionBank_AnalysisCon: [], |
| | | Embedded_QuestionBank_Answer: [], |
| | | Embedded_QuestionBank_Difficulty: [], |
| | | Embedded_QuestionBank_KnowledgePoint: [], |
| | | Embedded_QuestionBank_Option: [], |
| | | Embedded_QuestionBank_OptionStyle: [], |
| | | Embedded_QuestionBank_QuestionType: [], |
| | | Embedded_QuestionBank_Score: [], |
| | | Embedded_QuestionBank_Stem: [], |
| | | Embedded_QuestionBank_StemStyle: [] |
| | | } |
| | | }) |
| | | .then((res: any) => { |
| | | try { |
| | | let list = [] |
| | | list = res.datas.cmsDatas[0]?.datas.map((item: any) => { |
| | | try { |
| | | if (item.Embedded_QuestionBank_Stem) { |
| | | item.questionStem = JSON.parse(item.Embedded_QuestionBank_Stem) |
| | | } |
| | | if ( |
| | | item.Embedded_QuestionBank_Option && |
| | | item.Embedded_QuestionBank_Option.indexOf('[') > -1 |
| | | ) { |
| | | item.questionOption = JSON.parse(item.Embedded_QuestionBank_Option) |
| | | } |
| | | if ( |
| | | item.Embedded_QuestionBank_Answer && |
| | | item.Embedded_QuestionBank_Answer.indexOf('[') > -1 |
| | | ) { |
| | | item.Embedded_QuestionBank_Answer = JSON.parse(item.Embedded_QuestionBank_Answer) |
| | | } |
| | | return { |
| | | ...item, |
| | | questionType: item.Embedded_QuestionBank_QuestionType, |
| | | questionAnalysisCon: item.Embedded_QuestionBank_AnalysisCon, |
| | | questionAnswer: item.Embedded_QuestionBank_Answer, |
| | | customAnswer: null |
| | | } |
| | | } catch (error) { |
| | | console.log(item) |
| | | } |
| | | }) |
| | | dialogList.value = chageData([item], list) |
| | | dialogLLoading.value = false |
| | | } catch (error) { |
| | | dialogList.value = [] |
| | | dialogLLoading.value = false |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 处理数据结构 |
| | | const chageData = (arr: any, zrr: any) => { |
| | | let newData = [] |
| | | // 题库题目类型 |
| | | const questionTypeList = [ |
| | | { name: '单选题', value: 'singleChoice', data: [] }, |
| | | { name: '多选题', value: 'multipleChoice', data: [] }, |
| | | { name: '判断题', value: 'judge', data: [] }, |
| | | { name: '简答题', value: 'shortAnswer', data: [] }, |
| | | { name: '论述题', value: 'discuss', data: [] }, |
| | | { name: '填空题', value: 'completion', data: [] }, |
| | | { name: '连线题', value: 'matching', data: [] }, |
| | | { name: '分类题', value: 'classification', data: [] } |
| | | ] |
| | | for (let i = 0; i < arr.length; i++) { |
| | | const item = arr[i] |
| | | item.questionTypeList = JSON.parse(JSON.stringify(questionTypeList)) |
| | | for (let j = 0; j < zrr.length; j++) { |
| | | const ele = zrr[j] |
| | | const qusObj = item.question.find((citem: any) => citem.cmsItemId == ele.id) |
| | | if (qusObj?.cmsItemId) { |
| | | ele.userAnswer = qusObj.answer |
| | | const index = findIndexByValue(questionTypeList, ele.questionType) |
| | | if (index > -1) { |
| | | item.questionTypeList[index].data.push(ele) |
| | | } |
| | | } |
| | | } |
| | | item.questionTypeList = item.questionTypeList.filter((item: any) => item.data.length > 0) |
| | | newData.push(item) |
| | | } |
| | | return newData.filter((item) => item.questionTypeList.length > 0) |
| | | } |
| | | |
| | | const findIndexByValue = (res: any, type: string) => { |
| | | for (let i = 0; i < res.length; i++) { |
| | | if (res[i].value == type) { |
| | | return i |
| | | } |
| | | } |
| | | return -1 // 如果未找到,则返回 -1 |
| | | } |
| | | |
| | | // 作业搜索 |
| | | const searchData = () => {} |
| | | |
| | | const goBack = () => { |
| | | router.go(-1) |
| | | } |
| | | </script> |
| | | <style lang="less" scoped> |
| | | .classManagePage-box { |
| | | background: #fff; |
| | | |
| | | .classManagePage-nav { |
| | | width: 100%; |
| | | padding: 0 20px; |
| | | height: 40px; |
| | | border-bottom: 1px solid #e6e8ed; |
| | | position: sticky; |
| | | top: 0; |
| | | z-index: 999; |
| | | display: flex; |
| | | align-items: center; |
| | | background: #fff; |
| | | } |
| | | .classManagePage-content { |
| | | width: 100%; |
| | | position: relative; |
| | | .backBtn { |
| | | width: 100%; |
| | | height: 45px; |
| | | margin-bottom: 10px; |
| | | padding: 0 20px; |
| | | display: flex; |
| | | align-items: center; |
| | | position: sticky; |
| | | top: 40px; |
| | | z-index: 99; |
| | | background: #fff; |
| | | box-shadow: 0px 0px 20px 1px #eeeeee83; |
| | | } |
| | | .contentBox { |
| | | width: 100%; |
| | | padding: 0 20px; |
| | | box-sizing: border-box; |
| | | .titleOptions { |
| | | width: 160px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 20px; |
| | | span { |
| | | height: 30px; |
| | | font-family: PingFang SC; |
| | | font-weight: bold; |
| | | font-size: 16px; |
| | | color: #333; |
| | | line-height: 30px; |
| | | text-align: left; |
| | | border-left: 6px solid #ff6c00; |
| | | padding-left: 10px; |
| | | } |
| | | } |
| | | } |
| | | .pubContent { |
| | | padding: 10px; |
| | | box-sizing: border-box; |
| | | min-height: 750px; |
| | | .userName { |
| | | color: #ff6d00; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="classManagePage-box"> |
| | | <el-breadcrumb :separator-icon="ArrowRight"> |
| | | <el-breadcrumb-item>我的班级</el-breadcrumb-item> |
| | | <el-breadcrumb-item>{{ classInfo?.name }}</el-breadcrumb-item> |
| | | <el-breadcrumb-item>作业分析</el-breadcrumb-item> |
| | | </el-breadcrumb> |
| | | <div class="classManagePage-content" v-loading="pageLoading"> |
| | | <div class="staticBox"> |
| | | <div class="pub_staticItem"> |
| | | <img src="@/assets/images/class/zuoyecishu@2x.png" alt="" /> |
| | | <div class="staticText"> |
| | | <el-statistic title="作业次数" :value="outputValue" /> |
| | | </div> |
| | | </div> |
| | | <!-- <div class="pub_staticItem"> |
| | | <img src="@/assets/images/class/jinxing@2x.png" alt="" /> |
| | | <div class="staticText"> |
| | | <el-statistic title="进行中" :value="8" /> |
| | | </div> |
| | | </div> |
| | | <div class="pub_staticItem"> |
| | | <img src="@/assets/images/class/jieshu@2x.png" alt="" /> |
| | | <div class="staticText"> |
| | | <el-statistic title="已结束" :value="8" /> |
| | | </div> |
| | | </div> --> |
| | | </div> |
| | | <div class="chartsBox"> |
| | | <div id="chartsContent" v-show="charstData.length > 0"></div> |
| | | </div> |
| | | <div v-if="charstData.length == 0 && !pageLoading"> |
| | | <el-empty /> |
| | | </div> |
| | | <div class="listContent" v-if="tabHeader.length > 0"> |
| | | <div class="tableTitle">班级成绩详情</div> |
| | | <div class="tableContent"> |
| | | <el-table |
| | | v-loading="pages.loading" |
| | | :data="tableData" |
| | | border |
| | | style="width: 100%" |
| | | :cell-style="{ textAlign: 'center' }" |
| | | :header-cell-style="{ textAlign: 'center' }" |
| | | size="small" |
| | | > |
| | | <el-table-column prop="index" label="序号" width="70" /> |
| | | <el-table-column label="姓名" #default="scope"> |
| | | <span>{{ scope.row.appUser?.userInfo?.name }}</span> |
| | | </el-table-column> |
| | | <el-table-column label="学号" #default="scope"> |
| | | <span>{{ scope.row.appUser?.appUserId }}</span> |
| | | </el-table-column> |
| | | <el-table-column label="班级作业得分" v-if="tabHeader.length > 0"> |
| | | <el-table-column v-for="(item, index) in tabHeader" :key="index" :label="item"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.results[index]?.result >= 0"> |
| | | {{ scope.row.results[index]?.result }} |
| | | </span> |
| | | <span v-else> -- </span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table-column> |
| | | </el-table> |
| | | <el-pagination |
| | | style="float: right" |
| | | v-model:current-page="pages.page" |
| | | :page-size="pages.pageSize" |
| | | layout="total, prev, pager, next" |
| | | :total="pages.count" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import * as echarts from 'echarts' |
| | | import { ArrowRight } from '@element-plus/icons-vue' |
| | | import { useRoute } from 'vue-router' |
| | | import { useTransition } from '@vueuse/core' |
| | | import { inject, onMounted, onUnmounted, reactive, ref } from 'vue' |
| | | const route: any = useRoute() |
| | | const MG: any = inject('MG') |
| | | const classInfo: any = JSON.parse(route.query.classInfo) |
| | | var chartDom = null |
| | | var myChart: any = {} |
| | | var option = null |
| | | |
| | | const nameList: any = ref([]) |
| | | const charstData: any = ref([]) |
| | | const count = ref(0) |
| | | const pageLoading = ref(true) |
| | | const outputValue = useTransition(count, { |
| | | duration: 1000 |
| | | }) |
| | | const tabHeader: any = ref([]) |
| | | const tableData: any = ref([]) |
| | | |
| | | let pages = reactive({ |
| | | page: 1, |
| | | pageSize: 5, |
| | | count: 0, |
| | | loading: false |
| | | }) |
| | | |
| | | // 图表初始化 |
| | | const initCharts = () => { |
| | | option = { |
| | | legend: { |
| | | bottom: 0 |
| | | }, |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | showContent: true |
| | | }, |
| | | toolbox: { |
| | | feature: { |
| | | saveAsImage: {}, |
| | | magicType: { |
| | | type: ['bar'] |
| | | }, |
| | | restore: {} |
| | | } |
| | | }, |
| | | title: { |
| | | text: '班级成绩概览', |
| | | textStyle: { |
| | | fontFamily: 'PingFang SC', |
| | | color: '#000000', |
| | | fontWeight: 'bold', |
| | | fontSize: '16px' |
| | | } |
| | | }, |
| | | dataset: { |
| | | source: charstData.value |
| | | }, |
| | | xAxis: { type: 'category' }, |
| | | yAxis: { gridIndex: 0 }, |
| | | grid: { |
| | | left: '3%', |
| | | right: '4%', |
| | | containLabel: true |
| | | }, |
| | | series: [ |
| | | { |
| | | type: 'line', |
| | | smooth: true, |
| | | seriesLayoutBy: 'row', |
| | | emphasis: { focus: 'series' } |
| | | }, |
| | | { |
| | | type: 'line', |
| | | smooth: true, |
| | | seriesLayoutBy: 'row', |
| | | emphasis: { focus: 'series' } |
| | | }, |
| | | { |
| | | type: 'line', |
| | | smooth: true, |
| | | seriesLayoutBy: 'row', |
| | | emphasis: { focus: 'series' } |
| | | } |
| | | ] |
| | | } |
| | | option && myChart.setOption(option) |
| | | } |
| | | |
| | | onMounted(() => { |
| | | getData() |
| | | getUserTaskList() |
| | | }) |
| | | |
| | | // 获取统计数据 |
| | | const getData = () => { |
| | | const data = { |
| | | classId: classInfo?.id |
| | | } |
| | | MG.edu |
| | | .getTaskStatistics(data) |
| | | .then((res: any) => { |
| | | count.value = res.length |
| | | if (res.length > 0) { |
| | | let dataX = res.map((item: any) => item.task.name) |
| | | dataX.unshift('homeWork') |
| | | nameList.value = dataX |
| | | let avg = ['班级平均分'] |
| | | let max = ['最高分'] |
| | | let min = ['最低分'] |
| | | res.forEach((item: any) => { |
| | | avg.push(item.avgScore) |
| | | max.push(item.maxScore) |
| | | min.push(item.minScore) |
| | | }) |
| | | charstData.value = [dataX, avg, max, min] |
| | | } else { |
| | | charstData.value = [] |
| | | nameList.value = [] |
| | | } |
| | | setTimeout(() => { |
| | | pageLoading.value = false |
| | | chartDom = document.getElementById('chartsContent') |
| | | myChart = echarts.init(chartDom) |
| | | initCharts() |
| | | }, 1000) |
| | | }) |
| | | .catch((err: any) => { |
| | | pageLoading.value = false |
| | | console.log(err) |
| | | }) |
| | | } |
| | | |
| | | // 获取班级作业成绩详情 |
| | | const getUserTaskList = () => { |
| | | pages.loading = true |
| | | const data = { |
| | | start: (pages.page - 1) * pages.pageSize, |
| | | size: pages.pageSize, |
| | | classId: classInfo?.id |
| | | } |
| | | MG.edu |
| | | .getUserTaskList(data) |
| | | .then((res: any) => { |
| | | let headerList: any = [] |
| | | pages.count = res.totalSize |
| | | if (res.datas.length > 0) { |
| | | res.datas.forEach((item: any, index: number) => { |
| | | item.index = index + 1 |
| | | const hitem = item.results.map((citem: any) => citem.name) |
| | | headerList.push(...hitem) |
| | | }) |
| | | tableData.value = res.datas |
| | | tabHeader.value = Array.from(new Set(headerList)) |
| | | } else { |
| | | tableData.value = [] |
| | | tabHeader.value = [] |
| | | } |
| | | pages.loading = false |
| | | }) |
| | | .catch((err: any) => { |
| | | pages.loading = false |
| | | console.log(err) |
| | | }) |
| | | } |
| | | |
| | | const handleSizeChange = (val: number) => { |
| | | pages.pageSize = val |
| | | getUserTaskList() |
| | | } |
| | | |
| | | const handleCurrentChange = (val: number) => { |
| | | pages.page = val |
| | | getUserTaskList() |
| | | } |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .classManagePage-box { |
| | | width: 100%; |
| | | padding: 20px; |
| | | .classManagePage-nav { |
| | | padding-bottom: 20px; |
| | | border-bottom: 1px solid #e6e8ed; |
| | | } |
| | | .classManagePage-content { |
| | | width: 100%; |
| | | padding: 30px 0; |
| | | |
| | | .staticBox { |
| | | width: 100%; |
| | | height: 60px; |
| | | display: flex; |
| | | justify-content: flex-start; |
| | | align-items: center; |
| | | margin-bottom: 40px; |
| | | |
| | | .pub_staticItem { |
| | | display: flex; |
| | | |
| | | img { |
| | | width: 60px; |
| | | height: 60px; |
| | | background: #ebf4ff; |
| | | border-radius: 8px 8px 8px 8px; |
| | | margin-right: 15px; |
| | | } |
| | | .staticText { |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: space-between; |
| | | |
| | | span:nth-child(1) { |
| | | font-family: PingFang SC; |
| | | font-weight: bold; |
| | | font-size: 14px; |
| | | color: #a5a7ab; |
| | | } |
| | | |
| | | span:nth-child(2) { |
| | | font-family: DIN; |
| | | font-weight: 500; |
| | | font-size: 20px; |
| | | color: #000000; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .chartsBox { |
| | | margin-bottom: 40px; |
| | | #chartsContent { |
| | | height: 600px; |
| | | } |
| | | } |
| | | |
| | | .listContent { |
| | | width: 100%; |
| | | .tableTitle { |
| | | font-family: PingFang SC; |
| | | font-weight: bold; |
| | | font-size: 16px; |
| | | color: #000000; |
| | | margin-bottom: 22px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="classManagePage-box"> |
| | | <div class="classManagePage-nav"> |
| | | <el-breadcrumb :separator-icon="ArrowRight"> |
| | | <el-breadcrumb-item>我的班级</el-breadcrumb-item> |
| | | <el-breadcrumb-item>{{ classInfo?.name }}</el-breadcrumb-item> |
| | | <el-breadcrumb-item>作业管理详情</el-breadcrumb-item> |
| | | </el-breadcrumb> |
| | | </div> |
| | | <div class="classManagePage-content"> |
| | | <div class="backBtn"> |
| | | <el-button @click="goBack()" type="primary" link> |
| | | <el-icon style="margin-right: 5px"><ArrowLeftBold /></el-icon> 返回 |
| | | </el-button> |
| | | </div> |
| | | <div class="contentBox"> |
| | | <div class="content-tab-box"> |
| | | <div class="content-header"> |
| | | <div class="selectState"> |
| | | <span>状态:</span> |
| | | <el-select placeholder="全部" v-model="workState" @change="selectChangeState"> |
| | | <el-option |
| | | v-for="item in options" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" |
| | | /> |
| | | </el-select> |
| | | </div> |
| | | <div class="searchBox" v-if="workState != 'WaitSubmit'"> |
| | | <!-- <el-input |
| | | v-model="searchKey" |
| | | clearable |
| | | @clear="searchData" |
| | | placeholder="请输入关键字" |
| | | > |
| | | <template #append> |
| | | <el-button type="primary" @click="searchData" class="searchBtn" :icon="Search" /> |
| | | </template> |
| | | </el-input> --> |
| | | </div> |
| | | </div> |
| | | <div class="content-list-box"> |
| | | <el-table |
| | | :data="tableData" |
| | | border |
| | | max-height="600px" |
| | | style="width: 100%" |
| | | :header-cell-class-name="'headerCellClassName'" |
| | | v-loading="tableLoading" |
| | | v-if="workState != 'WaitSubmit'" |
| | | > |
| | | <el-table-column label="序号" prop="id" width="60"> </el-table-column> |
| | | <el-table-column label="姓名" #default="scope" width="150"> |
| | | <span>{{ scope.row.appUser?.userInfo?.name }}</span> |
| | | </el-table-column> |
| | | <el-table-column label="状态" prop="state" #default="scope"> |
| | | <span v-if="scope.row.state == 'WaitCheck'" style="color: #409eff">未批改</span> |
| | | <span v-if="scope.row.state == 'Normal'" style="color: #67c23a">已批改</span> |
| | | <span v-if="scope.row.state == 'WaitSubmit'" style="color: red">未提交</span> |
| | | </el-table-column> |
| | | <el-table-column label="得分" #default="scope"> |
| | | <span v-if="scope.row.result > 0">{{ scope.row.result }}</span> |
| | | <span v-else>{{ scope.row.totalScore }}</span> |
| | | </el-table-column> |
| | | <el-table-column label="单选题" v-if="singleChoiceLength > 0"> |
| | | <el-table-column |
| | | v-for="(item, index) in singleChoiceLength" |
| | | :key="index" |
| | | :label="item" |
| | | > |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.singleChoiceArr[index]?.score == 0" style="color: red"> |
| | | {{ scope.row.singleChoiceArr[index]?.answer }} |
| | | </span> |
| | | <span v-else style="color: #67c23a"> |
| | | {{ scope.row.singleChoiceArr[index]?.answer }} |
| | | </span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table-column> |
| | | <el-table-column label="多选题" v-if="multipleChoiceLength > 0"> |
| | | <el-table-column |
| | | v-for="(item, index) in multipleChoiceLength" |
| | | :key="index" |
| | | :label="item" |
| | | > |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.judgeArr[index]?.score == 0" style="color: red"> |
| | | {{ scope.row.multipleChoiceArr[index]?.answer.join(',') }} |
| | | </span> |
| | | <span v-else style="color: #67c23a"> |
| | | {{ scope.row.multipleChoiceArr[index]?.answer.join(',') }} |
| | | </span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table-column> |
| | | <el-table-column label="判断题" v-if="judgeLength > 0"> |
| | | <el-table-column v-for="(item, index) in judgeLength" :key="index" :label="item"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.judgeArr[index]?.score == 0" style="color: red"> |
| | | {{ scope.row.judgeArr[index]?.answer }} |
| | | </span> |
| | | <span v-else style="color: #67c23a"> |
| | | {{ scope.row.judgeArr[index]?.answer }} |
| | | </span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table-column> |
| | | <el-table-column label="填空题(分)" v-if="completionLength > 0"> |
| | | <el-table-column |
| | | v-for="(item, index) in completionLength" |
| | | :key="index" |
| | | :label="item" |
| | | > |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.completionArr[index]?.score == 0" style="color: red"> |
| | | {{ scope.row.completionArr[index]?.score }} |
| | | </span> |
| | | <span v-else style="color: #67c23a"> |
| | | {{ scope.row.completionArr[index]?.score }} |
| | | </span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table-column> |
| | | <el-table-column label="主观题(分)" v-if="otherLength > 0"> |
| | | <el-table-column v-for="(item, index) in otherLength" :key="index" :label="item"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.otherArr[index]?.score == 0" style="color: red"> |
| | | {{ scope.row.otherArr[index]?.score }} |
| | | </span> |
| | | <span v-else style="color: #67c23a"> |
| | | {{ scope.row.otherArr[index]?.score }} |
| | | </span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="150" #default="scope"> |
| | | <el-button |
| | | link |
| | | v-if="scope.row.state != 'Normal'" |
| | | style="color: #409eff" |
| | | @click="openDialog(scope.row)" |
| | | > |
| | | 判断主观题 |
| | | </el-button> |
| | | <el-button link v-if="scope.row.state == 'Normal'"> -- </el-button> |
| | | </el-table-column> |
| | | </el-table> |
| | | <el-table |
| | | :data="dataList" |
| | | border |
| | | v-else |
| | | max-height="600px" |
| | | style="width: 100%" |
| | | :header-cell-class-name="'headerCellClassName'" |
| | | v-loading="pages.loading" |
| | | > |
| | | <el-table-column prop="index" label="序号" width="70" /> |
| | | <el-table-column prop="appUserId" label="学号" width="150" /> |
| | | <el-table-column label="姓名" width="400"> |
| | | <template #default="scope"> |
| | | <div class="userBox"> |
| | | <el-avatar |
| | | style="margin-right: 10px" |
| | | v-if="scope.row.appUser.icon" |
| | | :size="35" |
| | | :src="scope.row.appUser.icon" |
| | | /> |
| | | <el-avatar |
| | | style="margin-right: 10px" |
| | | :size="35" |
| | | v-if="!scope.row.appUser.icon" |
| | | :icon="UserFilled" |
| | | /> |
| | | <span v-if="scope.row.appUser.name">{{ scope.row.appUser.name }}</span> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="createDate" label="加入班级时间" /> |
| | | <el-table-column label="操作" width="220" #default="scope"> |
| | | <el-button link style="color: red" @click="remindWork(scope.row)"> |
| | | 催交作业 |
| | | </el-button> |
| | | </el-table-column> |
| | | </el-table> |
| | | <div class="pageBox"> |
| | | <el-pagination |
| | | v-model:current-page="pages.currentPage" |
| | | :page-size="pages.pageSize" |
| | | :size="'small'" |
| | | :disabled="pages.count <= 1" |
| | | layout="total, prev, pager, next" |
| | | :total="pages.count" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <!-- 主观题判断 --> |
| | | <el-dialog |
| | | class="customDialog" |
| | | title="判断主观题" |
| | | v-model="otherVisible" |
| | | destroy-on-close |
| | | width="800" |
| | | :before-close="close" |
| | | > |
| | | <div class="pubContent"> |
| | | <questionDom |
| | | :question-list="otherQuestions" |
| | | :is-judge="true" |
| | | @judge-update="judgeUpdate" |
| | | /> |
| | | </div> |
| | | </el-dialog> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | <script setup lang="ts"> |
| | | import { useRoute, useRouter } from 'vue-router' |
| | | import { inject, onMounted, reactive, ref } from 'vue' |
| | | import { Search, UserFilled, ArrowRight } from '@element-plus/icons-vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import questionDom from './components/questionDom.vue' |
| | | import moment from 'moment' |
| | | |
| | | const route: any = useRoute() |
| | | const router = useRouter() |
| | | const classInfo = JSON.parse(route.query.classInfo) |
| | | const MG: any = inject('MG') |
| | | const config: any = inject('config') |
| | | const tool: any = inject('toolClass') |
| | | |
| | | // 作业详情 |
| | | const workState = ref('all') |
| | | const searchKey = ref('') |
| | | const cmsDatas: any = ref([]) |
| | | const tableData: any = ref([]) |
| | | const tableLoading = ref(true) |
| | | const singleChoiceLength = ref(0) |
| | | const multipleChoiceLength = ref(0) |
| | | const judgeLength = ref(0) |
| | | const completionLength = ref(0) |
| | | const otherLength = ref(0) |
| | | const otherVisible = ref(false) |
| | | const otherQuestions: any = ref([]) // 主观题 |
| | | const cacheDate: any = ref([]) |
| | | const currentWorkId = ref(null) // 当前作业id |
| | | const dataList: any = ref([]) // 未提交列表 |
| | | const options = ref([ |
| | | { |
| | | label: '全部', |
| | | value: 'all' |
| | | }, |
| | | { |
| | | label: '未批改', |
| | | value: 'WaitCheck' |
| | | }, |
| | | { |
| | | label: '已批改', |
| | | value: 'Normal' |
| | | }, |
| | | { |
| | | label: '未提交', |
| | | value: 'WaitSubmit' |
| | | } |
| | | ]) |
| | | |
| | | let pages = reactive({ |
| | | currentPage: 1, |
| | | page: 1, |
| | | pageSize: 15, |
| | | count: 0, |
| | | loading: true |
| | | }) |
| | | |
| | | const questionKey = [ |
| | | 'Name', |
| | | 'Embedded_QuestionBank_AnalysisCon', |
| | | 'Embedded_QuestionBank_Answer', |
| | | 'Embedded_QuestionBank_Difficulty', |
| | | 'Embedded_QuestionBank_KnowledgePoint', |
| | | 'Embedded_QuestionBank_Option', |
| | | 'Embedded_QuestionBank_OptionStyle', |
| | | 'Embedded_QuestionBank_QuestionType', |
| | | 'Embedded_QuestionBank_Score', |
| | | 'Embedded_QuestionBank_Stem', |
| | | 'Embedded_QuestionBank_StemStyle' |
| | | ] |
| | | |
| | | // 分页 |
| | | const handleSizeChange = (val: number) => { |
| | | pages.pageSize = val |
| | | if (workState.value != 'WaitSubmit') { |
| | | getTaskDetail() |
| | | } else { |
| | | getUnSubmitList() |
| | | } |
| | | } |
| | | |
| | | const handleCurrentChange = (val: number) => { |
| | | pages.page = val |
| | | pages.currentPage = val |
| | | if (workState.value != 'WaitSubmit') { |
| | | getTaskDetail() |
| | | } else { |
| | | getUnSubmitList() |
| | | } |
| | | } |
| | | |
| | | onMounted(() => { |
| | | getTaskCmsList() |
| | | }) |
| | | |
| | | // 状态改变 |
| | | const selectChangeState = (item: any) => { |
| | | workState.value = item |
| | | if (item == 'WaitSubmit') { |
| | | // const data = [{ field: 'State', value: 'Normal', subFilters: [] }] |
| | | getUnSubmitList() |
| | | } else { |
| | | const data = item != 'all' ? [{ field: 'State', value: item, subFilters: [] }] : [] |
| | | getTaskDetail(data) |
| | | } |
| | | } |
| | | |
| | | const openDialog = (item: any) => { |
| | | otherVisible.value = true |
| | | currentWorkId.value = item.id |
| | | } |
| | | |
| | | // 获取详情 |
| | | const getTaskDetail = (filter?: any, search?: any) => { |
| | | const filterList = filter ?? [] |
| | | const searchList = search ?? [] |
| | | tableLoading.value = true |
| | | const data = { |
| | | start: (pages.page - 1) * pages.pageSize, |
| | | size: pages.pageSize, |
| | | taskId: classInfo?.taskWorkId, |
| | | classId: classInfo?.id, |
| | | filterList, |
| | | searchList |
| | | } |
| | | MG.edu |
| | | .getTaskSubmitList(data) |
| | | .then((res: any) => { |
| | | pages.loading = false |
| | | pages.count = res.totalSize |
| | | cacheDate.value = [] |
| | | // 题库题目类型 |
| | | const questionTypeList = [ |
| | | { name: '简答题', totalScore: 0, value: 'shortAnswer', data: [] }, |
| | | { name: '论述题', totalScore: 0, value: 'discuss', data: [] }, |
| | | { name: '连线题', totalScore: 0, value: 'matching', data: [] }, |
| | | { name: '分类题', totalScore: 0, value: 'classification', data: [] } |
| | | ] |
| | | try { |
| | | let list: any = [] |
| | | res.datas.forEach((item: any) => { |
| | | const parentData = { |
| | | feedBack: item.feedBack, |
| | | id: item.id, |
| | | result: item.result, |
| | | type: item.type, |
| | | state: item.state, |
| | | submit: item.submit, |
| | | updateTaskSubmitCmsItemRequests: [] |
| | | } |
| | | item.singleChoiceName = '单选题' |
| | | item.singleChoiceArr = [] |
| | | item.multipleChoiceName = '多选题' |
| | | item.multipleChoiceArr = [] |
| | | item.judgeName = '判断题' |
| | | item.judgeArr = [] |
| | | item.completionName = '填空题' |
| | | item.completionArr = [] |
| | | item.otherName = '主观题' |
| | | item.otherArr = [] |
| | | item.totalScore = 0 |
| | | const submitData = deduplicateArray(item.submitAndCmsItemLinks, 'cmsItemId') |
| | | submitData.forEach((citem: any) => { |
| | | const obj = cmsDatas.value.find((i: any) => i.id == citem.cmsItemId) |
| | | item.totalScore += citem.score |
| | | if (citem.answer != '') { |
| | | if (obj.questionType == 'singleChoice') { |
| | | citem.answer = JSON.parse(citem.answer) ?? '-' |
| | | item.singleChoiceArr.push(citem) |
| | | } else if (obj.questionType == 'multipleChoice') { |
| | | citem.answer = JSON.parse(citem.answer) ?? '-' |
| | | item.multipleChoiceArr.push(citem) |
| | | } else if (obj.questionType == 'judge') { |
| | | citem.answer = JSON.parse(citem.answer) ?? '-' |
| | | item.judgeArr.push(citem) |
| | | } else if (obj.questionType == 'completion') { |
| | | citem.answer = JSON.parse(citem.answer) ?? '-' |
| | | item.completionArr.push(citem) |
| | | } else { |
| | | obj.score = citem.score |
| | | obj.answer = citem.answer |
| | | obj.updateId = citem.id |
| | | obj.parentId = item.id |
| | | item.otherArr.push(citem) |
| | | list.push(obj) |
| | | } |
| | | } |
| | | }) |
| | | cacheDate.value.push(parentData) |
| | | }) |
| | | list.forEach((item: any) => { |
| | | const index = findIndexByValue(questionTypeList, item.questionType) |
| | | if (index > -1) { |
| | | questionTypeList[index].data.push(item) |
| | | if (item.score) { |
| | | questionTypeList[index].totalScore += item.score |
| | | } |
| | | } |
| | | }) |
| | | otherQuestions.value = questionTypeList.filter((item) => item.data.length > 0) |
| | | const lenghtArr = [...res.datas] |
| | | singleChoiceLength.value = lenghtArr.reduce( |
| | | (max: any, obj: any) => Math.max(max, obj.singleChoiceArr.length), |
| | | 0 |
| | | ) |
| | | multipleChoiceLength.value = lenghtArr.reduce( |
| | | (max: any, obj: any) => Math.max(max, obj.multipleChoiceArr.length), |
| | | 0 |
| | | ) |
| | | judgeLength.value = lenghtArr.reduce( |
| | | (max: any, obj: any) => Math.max(max, obj.judgeArr.length), |
| | | 0 |
| | | ) |
| | | completionLength.value = lenghtArr.reduce( |
| | | (max: any, obj: any) => Math.max(max, obj.completionArr.length), |
| | | 0 |
| | | ) |
| | | otherLength.value = lenghtArr.reduce( |
| | | (max: any, obj: any) => Math.max(max, obj.otherArr.length), |
| | | 0 |
| | | ) |
| | | tableLoading.value = false |
| | | tableData.value = res.datas |
| | | } catch (err) { |
| | | tableLoading.value = false |
| | | console.log(err) |
| | | } |
| | | }) |
| | | .catch((err: any) => { |
| | | console.log(err) |
| | | }) |
| | | } |
| | | |
| | | // 获取任务下的资源列表 |
| | | const getTaskCmsList = () => { |
| | | tableLoading.value = true |
| | | const data = { |
| | | start: 0, |
| | | size: 999, |
| | | searchList: [], |
| | | taskId: classInfo?.taskWorkId, // taskData?.id |
| | | path: String(classInfo?.taskCmsId), //taskData?.rootCmsItemId |
| | | type: '*', |
| | | keys: questionKey |
| | | } |
| | | MG.edu |
| | | .getTaskCmsItem(data) |
| | | .then((res: any) => { |
| | | for (let i = 0; i < res.datas.length; i++) { |
| | | let item = res.datas[i] |
| | | item.index = i + 1 |
| | | // 处理字段 |
| | | if (questionKey != null) { |
| | | for (let fieldKey of questionKey) { |
| | | if (item.datas[fieldKey]) { |
| | | const values = JSON.parse(item.datas[fieldKey]) |
| | | if (values.length > 0) { |
| | | // 用字段名处理返回的字段值 |
| | | if (values[0].Value) { |
| | | item[fieldKey] = values[0].Value |
| | | } else if (values[0].Data) { |
| | | item[fieldKey] = values[0].Data.Value |
| | | } else if (!values[0].Value && values[0].FileList?.length > 0) { |
| | | item[fieldKey] = values[0].FileList |
| | | } else { |
| | | item[fieldKey] = '-' |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | cmsDatas.value = changeQuestionData(res.datas) |
| | | tableLoading.value = false |
| | | }) |
| | | .catch((e: any) => { |
| | | ElMessage({ |
| | | message: '列表获取失败', |
| | | type: 'error' |
| | | }) |
| | | tableLoading.value = false |
| | | console.log(e) |
| | | }) |
| | | } |
| | | |
| | | // 处理题目数据结构 |
| | | const changeQuestionData = (res: any) => { |
| | | try { |
| | | let list = [] |
| | | list = res?.map((item: any) => { |
| | | try { |
| | | if (item.Embedded_QuestionBank_Stem) { |
| | | item.questionStem = JSON.parse(item.Embedded_QuestionBank_Stem) |
| | | } |
| | | if ( |
| | | item.Embedded_QuestionBank_Option && |
| | | item.Embedded_QuestionBank_Option.indexOf('[') > -1 |
| | | ) { |
| | | item.questionOption = JSON.parse(item.Embedded_QuestionBank_Option) |
| | | } |
| | | if ( |
| | | item.Embedded_QuestionBank_Answer && |
| | | item.Embedded_QuestionBank_Answer.indexOf('[') > -1 |
| | | ) { |
| | | item.Embedded_QuestionBank_Answer = JSON.parse(item.Embedded_QuestionBank_Answer) |
| | | } |
| | | return { |
| | | ...item, |
| | | questionType: item.Embedded_QuestionBank_QuestionType, |
| | | questionAnalysisCon: item.Embedded_QuestionBank_AnalysisCon, |
| | | questionAnswer: item.Embedded_QuestionBank_Answer, |
| | | customAnswer: null |
| | | } |
| | | } catch (error) { |
| | | console.log(item) |
| | | } |
| | | }) |
| | | getTaskDetail() |
| | | return list |
| | | } catch (error) { |
| | | console.log(error) |
| | | return [] |
| | | } |
| | | } |
| | | |
| | | const findIndexByValue = (res: any, type: string) => { |
| | | for (let i = 0; i < res.length; i++) { |
| | | if (res[i].value == type) { |
| | | return i |
| | | } |
| | | } |
| | | return -1 // 如果未找到,则返回 -1 |
| | | } |
| | | |
| | | // 获取未提交任务列表 |
| | | const getUnSubmitList = (filter?: any, search?: any) => { |
| | | const filterList = filter ?? [] |
| | | const searchList = search ?? [] |
| | | const data = { |
| | | start: (pages.page - 1) * pages.pageSize, |
| | | size: pages.pageSize, |
| | | taskId: classInfo?.taskWorkId, |
| | | classId: classInfo?.id, |
| | | filterList, |
| | | searchList |
| | | } |
| | | MG.edu |
| | | .getUnSubmitList(data) |
| | | .then((res: any) => { |
| | | const { datas, totalSize } = res |
| | | pages.loading = false |
| | | pages.count = totalSize |
| | | if (datas.length > 0) { |
| | | dataList.value = datas.map((item: any, index: number) => { |
| | | const userInfo = item.appUser?.infoList[0] ?? null |
| | | item.appUser.name = userInfo.name |
| | | item.appUser.icon = userInfo.icon |
| | | return { |
| | | ...item, |
| | | index: index + 1, |
| | | createDate: moment(item.createDate).format('YYYY-MM-DD'), |
| | | appUserId: item.appUser.id |
| | | } |
| | | }) |
| | | pages.count = totalSize |
| | | } |
| | | }) |
| | | .catch((err: any) => { |
| | | console.log(err) |
| | | }) |
| | | } |
| | | |
| | | // 关闭 |
| | | const close = () => { |
| | | otherVisible.value = false |
| | | } |
| | | |
| | | // 主观题提交 |
| | | const judgeUpdate = (item: any) => { |
| | | const listData = [...cacheDate.value] |
| | | let judgeScore = 0 |
| | | if (item) { |
| | | const requestData = { |
| | | classId: classInfo?.id, |
| | | requests: [] |
| | | } |
| | | const data = JSON.parse(item) |
| | | listData.forEach((citem: any) => { |
| | | const strData = data.find((i: any) => i.parentId == citem.id) |
| | | if (strData) { |
| | | citem.updateTaskSubmitCmsItemRequests = data.map((uitem: any) => { |
| | | judgeScore += uitem.score |
| | | return { |
| | | linkId: uitem.updateId, |
| | | score: uitem.score, |
| | | answer: uitem.answer, |
| | | state: 'Normal', |
| | | comments: 'judge' |
| | | } |
| | | }) |
| | | } |
| | | }) |
| | | let dataobj = null |
| | | dataobj = listData.find((litem) => litem.id == currentWorkId.value) |
| | | dataobj.state = 'Normal' |
| | | dataobj.result = dataobj.result + judgeScore |
| | | requestData.requests = [dataobj] |
| | | MG.edu |
| | | .updateTaskSubmit(requestData) |
| | | .then((res: any) => { |
| | | if (res) { |
| | | otherVisible.value = false |
| | | getTaskDetail() |
| | | } |
| | | }) |
| | | .catch((err: any) => { |
| | | console.log(err) |
| | | }) |
| | | } |
| | | } |
| | | |
| | | //数组去重 |
| | | const deduplicateArray = (arr: any, idKey: string) => { |
| | | const seen: any = {} |
| | | const deduplicatedArray = arr.filter((item: any) => { |
| | | const id = item[idKey] |
| | | if (!seen[id]) { |
| | | seen[id] = true |
| | | return true |
| | | } |
| | | return false |
| | | }) |
| | | |
| | | return deduplicatedArray |
| | | } |
| | | |
| | | // 催交作业 |
| | | const remindWork = (item: any) => { |
| | | const content = classInfo?.name + '班' + item.appUser.name + '同学,请及时提交作业' |
| | | const data = { |
| | | description: '', |
| | | icon: '', |
| | | state: 'Normal', |
| | | topicIdOrRefCode: String(sessionStorage.messageId), |
| | | name: '未交作业人员', |
| | | content, |
| | | type: 'Normal', |
| | | cmsTypeRefCode: '', |
| | | newDataListRequest: [] |
| | | } |
| | | MG.ugc |
| | | .newTopicMessage(data) |
| | | .then((res: any) => { |
| | | if (res) { |
| | | ElMessage({ |
| | | type: 'success', |
| | | message: '已催交' |
| | | }) |
| | | } |
| | | }) |
| | | .catch((err: any) => { |
| | | console.log(err) |
| | | }) |
| | | } |
| | | |
| | | // 作业搜索 |
| | | const searchData = () => { |
| | | const data = [ |
| | | { |
| | | compareType: 'Contains', |
| | | keywords: searchKey.value, |
| | | field: 'Name' |
| | | } |
| | | ] |
| | | pages.page = 1 |
| | | if (workState.value != 'WaitSubmit') { |
| | | getTaskDetail(undefined, searchKey.value ? data : []) |
| | | } else { |
| | | getUnSubmitList(undefined, searchKey.value ? data : []) |
| | | } |
| | | } |
| | | |
| | | const goBack = () => { |
| | | router.go(-1) |
| | | } |
| | | </script> |
| | | <style lang="less" scoped> |
| | | .classManagePage-box { |
| | | background: #fff; |
| | | |
| | | .classManagePage-nav { |
| | | width: 100%; |
| | | padding: 0 20px; |
| | | height: 40px; |
| | | border-bottom: 1px solid #e6e8ed; |
| | | position: sticky; |
| | | top: 0; |
| | | z-index: 999; |
| | | display: flex; |
| | | align-items: center; |
| | | background: #fff; |
| | | } |
| | | .classManagePage-content { |
| | | width: 100%; |
| | | position: relative; |
| | | .backBtn { |
| | | width: 100%; |
| | | height: 45px; |
| | | margin-bottom: 10px; |
| | | padding: 0 20px; |
| | | display: flex; |
| | | align-items: center; |
| | | position: sticky; |
| | | top: 40px; |
| | | z-index: 99; |
| | | background: #fff; |
| | | box-shadow: 0px 0px 20px 1px #eeeeee83; |
| | | } |
| | | .contentBox { |
| | | width: 100%; |
| | | padding: 0 20px; |
| | | box-sizing: border-box; |
| | | .content-title-box { |
| | | padding: 0 10px; |
| | | display: flex; |
| | | justify-content: flex-start; |
| | | align-items: center; |
| | | border-left: 4px solid #ff6d00; |
| | | span { |
| | | margin-right: 15px; |
| | | } |
| | | } |
| | | .content-user-box { |
| | | width: 100%; |
| | | padding: 10px 10px; |
| | | box-sizing: border-box; |
| | | display: flex; |
| | | overflow-x: auto; |
| | | .user-info-box { |
| | | width: auto; |
| | | display: flex; |
| | | align-items: center; |
| | | padding: 10px 15px; |
| | | .user-info-data-box { |
| | | flex: 1; |
| | | height: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: flex-start; |
| | | justify-content: space-between; |
| | | margin-left: 10px; |
| | | .user-name { |
| | | padding: 6px 0; |
| | | } |
| | | .user-num { |
| | | padding: 6px 0; |
| | | color: #666; |
| | | font-size: 12px; |
| | | white-space: nowrap; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .content-user-box::-webkit-scrollbar { |
| | | height: 3px; |
| | | } |
| | | .content-user-box::-webkit-scrollbar-thumb { |
| | | background-color: #ff6d00; |
| | | cursor: pointer; |
| | | } |
| | | .content-user-box::-webkit-scrollbar-track-piece { |
| | | background: #eee; |
| | | } |
| | | .content-tab-box { |
| | | .content-header { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | padding: 10px 0; |
| | | .searchBox { |
| | | width: 300px; |
| | | float: left; |
| | | padding: 10px 0; |
| | | .searchBtn { |
| | | background-color: var(--el-color-primary); |
| | | color: #fff; |
| | | border-top-left-radius: 0; |
| | | border-bottom-left-radius: 0; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .content-list-box { |
| | | .headerCellClassName { |
| | | .cell { |
| | | text-align: center; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | ::v-deep(.customDialog) { |
| | | border-radius: 5px; |
| | | margin: 10px auto; |
| | | padding-bottom: 20px; |
| | | .pubContent { |
| | | position: relative; |
| | | height: 80vh; |
| | | } |
| | | } |
| | | .pageBox { |
| | | padding: 10px 0; |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="classManagePage-box"> |
| | | <div class="classManagePage-nav"> |
| | | <el-breadcrumb :separator-icon="ArrowRight"> |
| | | <el-breadcrumb-item>我的班级</el-breadcrumb-item> |
| | | <el-breadcrumb-item>{{ classInfo?.name }}</el-breadcrumb-item> |
| | | <el-breadcrumb-item>作业管理</el-breadcrumb-item> |
| | | </el-breadcrumb> |
| | | </div> |
| | | <div class="classManagePage-content"> |
| | | <div class="cartClass"> |
| | | <!-- <el-tabs v-model="jobState" @tab-click="tabCart"> |
| | | <el-tab-pane label="全部" name="all"></el-tab-pane> |
| | | <el-tab-pane label="进行中" name="payment"></el-tab-pane> |
| | | <el-tab-pane label="已过期" name="complete"></el-tab-pane> |
| | | </el-tabs> --> |
| | | <div class="titleOptions"> |
| | | <span>作业管理</span> |
| | | </div> |
| | | </div> |
| | | <div class="headerBox"> |
| | | <div class="searchBox"> |
| | | <el-input |
| | | v-model="searchKey" |
| | | clearable |
| | | @clear="searchTask" |
| | | @keydown.enter="searchTask" |
| | | placeholder="请输入关键字" |
| | | > |
| | | <template #append> |
| | | <el-button type="primary" @click="searchTask" class="searchBtn" :icon="Search" /> |
| | | </template> |
| | | </el-input> |
| | | </div> |
| | | <el-button |
| | | style="float: right" |
| | | v-if="userInfo?.role == 'Teacher'" |
| | | @click="openWork()" |
| | | type="primary" |
| | | round |
| | | > |
| | | <el-icon size="large" style="margin-right: 3px"><Document /></el-icon> |
| | | 新建作业 |
| | | </el-button> |
| | | </div> |
| | | <div class="listBox"> |
| | | <el-table |
| | | :data="tableData" |
| | | :header-cell-style="{ background: '#eee' }" |
| | | max-height="600px" |
| | | style="width: 100%" |
| | | v-loading="pages.loading" |
| | | > |
| | | <el-table-column label="序号" prop="id" width="70"> </el-table-column> |
| | | <el-table-column label="名称" prop="name"> </el-table-column> |
| | | <el-table-column label="作业开始日期" prop="beginDate"> </el-table-column> |
| | | <el-table-column label="作业结束日期" prop="endDate"> </el-table-column> |
| | | <el-table-column label="作业完成情况(人数)" prop="submitCount"></el-table-column> |
| | | <el-table-column label="操作" width="200" #default="scope"> |
| | | <el-button |
| | | link |
| | | style="color: #409eff" |
| | | v-if="scope.row.state == 'Normal'" |
| | | @click="detail(scope.row)" |
| | | >详情</el-button |
| | | > |
| | | <!-- v-if="scope.row.state != 'Normal'" --> |
| | | <el-button |
| | | link |
| | | type="primary" |
| | | v-if="scope.row.state != 'Normal'" |
| | | @click="edit(scope.row)" |
| | | >编辑</el-button |
| | | > |
| | | <el-button |
| | | link |
| | | style="color: #67c23a" |
| | | v-if="scope.row.state == 'Waiting'" |
| | | @click="releaseWork(scope.row)" |
| | | >发布</el-button |
| | | > |
| | | <el-button link type="danger" @click="removeTaskItem(scope.row)">移除</el-button> |
| | | </el-table-column> |
| | | </el-table> |
| | | <div class="pageBox"> |
| | | <el-pagination |
| | | v-model:current-page="pages.currentPage" |
| | | :page-size="pages.pageSize" |
| | | :size="'small'" |
| | | :disabled="pages.count <= 1" |
| | | layout="total, prev, pager, next" |
| | | :total="pages.count" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" |
| | | /> |
| | | </div> |
| | | </div> |
| | | <!-- 新建作业 --> |
| | | <el-dialog |
| | | class="customDialog" |
| | | destroy-on-close |
| | | v-model="visible" |
| | | :title="visibleEdit ? '更新作业' : '新建作业'" |
| | | width="1650" |
| | | :before-close="close" |
| | | align-center |
| | | > |
| | | <div class="stepBox"> |
| | | <el-steps |
| | | style="max-width: 600px; margin: auto" |
| | | :active="stepActive" |
| | | finish-status="success" |
| | | align-center |
| | | > |
| | | <el-step :title="visibleEdit ? '更新作业' : '新建作业'" /> |
| | | <el-step title="添加题目" /> |
| | | <el-step title="设置分数" /> |
| | | <el-step title="完成" /> |
| | | </el-steps> |
| | | </div> |
| | | <div class="newTaskBox" v-if="stepActive == 0"> |
| | | <el-row class="row-center"> |
| | | <el-col :span="2" class="labelItem"> |
| | | <div class="grid-content ep-bg-purple" /> |
| | | 名称 |
| | | </el-col> |
| | | <el-col :span="20"> |
| | | <div class="grid-content ep-bg-purple-light" /> |
| | | <el-input |
| | | v-model="taskItem.homeworkName" |
| | | placeholder="请填写名称" |
| | | size="large" |
| | | clearable |
| | | style="width: 600px" |
| | | /> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row class="row-center"> |
| | | <el-col :span="2" class="labelItem"> |
| | | <div class="grid-content ep-bg-purple" /> |
| | | 开始日期 |
| | | </el-col> |
| | | <el-col :span="20"> |
| | | <div class="grid-content ep-bg-purple-light" /> |
| | | <!-- <el-input v-model="taskItem.beginDate" placeholder="请选择开始日期" size="large" clearable /> --> |
| | | <el-date-picker |
| | | v-model="taskItem.homeworkStartingDate" |
| | | type="date" |
| | | placeholder="请选择开始日期" |
| | | size="large" |
| | | style="width: 600px" |
| | | /> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row class="row-center"> |
| | | <el-col :span="2" class="labelItem"> |
| | | <div class="grid-content ep-bg-purple" /> |
| | | 结束日期 |
| | | </el-col> |
| | | <el-col :span="20"> |
| | | <div class="grid-content ep-bg-purple-light" /> |
| | | <el-date-picker |
| | | v-model="taskItem.homeworkSubmissionDate" |
| | | type="date" |
| | | placeholder="请选择结束日期" |
| | | size="large" |
| | | style="width: 600px" |
| | | /> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="2" class="labelItem"> |
| | | <div class="grid-content ep-bg-purple" /> |
| | | 描述 |
| | | </el-col> |
| | | <el-col :span="20"> |
| | | <div class="grid-content ep-bg-purple-light" /> |
| | | <el-input |
| | | v-model="taskItem.explain" |
| | | placeholder="请填写说明" |
| | | type="textarea" |
| | | :rows="12" |
| | | size="large" |
| | | clearable |
| | | style="width: 600px" |
| | | /> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | <div class="workBox" v-if="stepActive == 1"> |
| | | <div class="workLeft"> |
| | | <el-tabs |
| | | v-model="activeTabs" |
| | | style="margin: auto" |
| | | class="demo-tabs" |
| | | @tab-change="handleClick" |
| | | > |
| | | <el-tab-pane label="系统" name="1"></el-tab-pane> |
| | | <!-- <el-tab-pane label="教材" name="2"></el-tab-pane> --> |
| | | </el-tabs> |
| | | <div class="workList" v-if="workLeftList.length > 0 && !leftLoading"> |
| | | <!-- <div class="searchBox" v-if="activeTabs == '1'"> |
| | | <el-input v-model="sysWorkKey" clearable @clear="searchWork" placeholder="请输入关键字"> |
| | | <template #append> |
| | | <el-button type="primary" class="searchBtn" @click="searchWork" :icon="Search" /> |
| | | </template> |
| | | </el-input> |
| | | </div> --> |
| | | <div class="work-list-item" v-for="(item, index) in workLeftList" :key="index"> |
| | | <el-tooltip :content="item.name" placement="bottom-end" effect="light"> |
| | | <p |
| | | :class=" |
| | | index == sysIndex ? 'work-list-item-text leftBg' : 'work-list-item-text' |
| | | " |
| | | @click="clickRightItem(item, index)" |
| | | > |
| | | {{ item.name }} |
| | | </p> |
| | | </el-tooltip> |
| | | </div> |
| | | </div> |
| | | <div |
| | | class="workList" |
| | | v-if="workLeftList.length == 0 && !leftLoading" |
| | | style="display: flex; align-items: center; justify-content: center" |
| | | > |
| | | <el-empty image-size="100px" /> |
| | | </div> |
| | | <div |
| | | class="workList" |
| | | v-if="leftLoading" |
| | | style=" |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | background-color: none; |
| | | " |
| | | v-loading="leftLoading" |
| | | ></div> |
| | | </div> |
| | | <div class="workRight"> |
| | | <div class="right-list-title"> |
| | | <span>题目列表</span> |
| | | <!-- <el-button type="primary" round size="small" icon="Plus">新建</el-button> --> |
| | | </div> |
| | | <div class="right-list-components"> |
| | | <questionDom |
| | | v-if="workRightList.length > 0 && !rightLoading" |
| | | :questionList="workRightList" |
| | | @selectQuestion="selectQuestion" |
| | | :noCheckbox="true" |
| | | /> |
| | | <div v-if="rightLoading" v-loading="rightLoading"></div> |
| | | <el-empty v-if="workRightList.length == 0 && !rightLoading" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="workBox" v-if="stepActive == 2"> |
| | | <div class="workLeft" style="width: 230px"> |
| | | <div class="scoreTitle"> |
| | | <span>题目类型</span> |
| | | </div> |
| | | <div class="workList" v-if="scoreLeftList.length > 0"> |
| | | <div class="work-list-item" v-for="(item, index) in scoreLeftList" :key="index"> |
| | | <p |
| | | :class=" |
| | | index == scoreIndex ? 'work-list-item-text leftBg' : 'work-list-item-text' |
| | | " |
| | | @click="scoreItem(item, index)" |
| | | > |
| | | {{ item.name }} ({{ item.data.length }}) |
| | | </p> |
| | | </div> |
| | | </div> |
| | | <div |
| | | class="workList" |
| | | v-if="scoreLeftList.length == 0" |
| | | style="display: flex; align-items: center; justify-content: center" |
| | | > |
| | | <el-empty image-size="100px" /> |
| | | </div> |
| | | </div> |
| | | <div class="workRight"> |
| | | <div class="right-list-title"> |
| | | <span>题目列表</span> |
| | | </div> |
| | | <div class="right-score-components"> |
| | | <div class="scoreBtn"> |
| | | <!-- <el-button size="small">上移</el-button> |
| | | <el-button size="small">下移</el-button> --> |
| | | <div class="setScore" v-if="scoreLeftList.length > 0"> |
| | | <span>批量设置分数:</span> |
| | | <el-input-number |
| | | v-model="scoreValue" |
| | | :min="0" |
| | | :max="100" |
| | | controls-position="right" |
| | | @change="changeScore" |
| | | /> |
| | | <el-button v-if="scoreValue > 0" style="margin-left: 10px" @click="setScoreArr" |
| | | >确认</el-button |
| | | > |
| | | </div> |
| | | </div> |
| | | <el-table |
| | | :data="scoreDataList" |
| | | max-height="500px" |
| | | :header-cell-style="{ background: '#eee' }" |
| | | style="width: 100%" |
| | | v-loading="selectedLoading" |
| | | > |
| | | <el-table-column prop="index" label="序号" width="100" /> |
| | | <el-table-column prop="name" label="题目"> |
| | | <template #default="scope"> |
| | | <span>{{ scope.row.questionStem.stemTxt }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="分数" width="120"> |
| | | <template #default="scope"> |
| | | <span style="color: #ff6c00">{{ scope.row.score }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="设置" width="260"> |
| | | <template #default="scope"> |
| | | <el-button |
| | | link |
| | | v-if="!scope.row.isInput" |
| | | type="primary" |
| | | size="small" |
| | | @click="openSetScore(scope.row)" |
| | | >设置分数</el-button |
| | | > |
| | | <el-input-number |
| | | v-if="scope.row.isInput" |
| | | v-model="scoreItemValue" |
| | | :min="0" |
| | | :max="100" |
| | | :controls="false" |
| | | size="small" |
| | | @blur="setScore(scope.row)" |
| | | /> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="workBox" style="height: 720px" v-if="stepActive == 3"> |
| | | <div class="finishBg"> |
| | | <img src="@/assets//images/class/finish.png" alt="" /> |
| | | <span>作业已创建完成</span> |
| | | </div> |
| | | </div> |
| | | <template #footer v-if="stepActive == 0"> |
| | | <div style="width: 100%; display: flex; justify-content: flex-end"> |
| | | <el-button @click="nextStep" v-if="visibleEdit"> 跳过 </el-button> |
| | | <el-button type="primary" :loading="newLoading" @click="newTask"> 确认 </el-button> |
| | | </div> |
| | | </template> |
| | | <template #footer v-if="stepActive != 3 && stepActive != 0"> |
| | | <div class="leftFooter" :style="{ width: stepActive == 2 ? '230px' : '' }"></div> |
| | | <div class="dialog-footer"> |
| | | <div class="check-list-box" v-if="stepActive == 1"> |
| | | <el-checkbox v-model="checkAll" @change="handleCheckAllChange"> 全选 </el-checkbox> |
| | | </div> |
| | | <div class="btnGroup" v-if="stepActive == 1"> |
| | | <el-button plain :disabled="checkData.length == 0" @click="addCmsitem"> |
| | | 加入作业 |
| | | </el-button> |
| | | <el-button plain @click="selectedData"> 查看已选 </el-button> |
| | | <el-button type="primary" @click="nextStep"> 下一步 </el-button> |
| | | </div> |
| | | <div class="btnGroup" v-if="stepActive == 2"> |
| | | <el-button type="primary" plain @click="preStep"> 上一步 </el-button> |
| | | <el-button plain @click="lookWork"> 预览作业 </el-button> |
| | | <el-button type="primary" @click="nextStep"> 下一步 </el-button> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | <template #footer v-if="stepActive == 3"> |
| | | <div style="width: 100%; display: flex; justify-content: flex-end"> |
| | | <el-button type="primary" @click="close"> 完 成 </el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- 查看已选 --> |
| | | <el-dialog |
| | | class="customDialog" |
| | | align-center |
| | | v-model="visibleView" |
| | | destroy-on-close |
| | | width="900" |
| | | > |
| | | <template #header> |
| | | <div class="viewTitle">已选题目</div> |
| | | </template> |
| | | <div class="viewContent"> |
| | | <div class="workBox"> |
| | | <div class="workLeft" style="width: 200px"> |
| | | <div class="workList" style="height: 100%" v-if="selectedTypeList.length > 0"> |
| | | <div class="work-list-item" v-for="(item, index) in selectedTypeList" :key="index"> |
| | | <p |
| | | :class=" |
| | | index == selectedIndex ? 'work-list-item-text leftBg' : 'work-list-item-text' |
| | | " |
| | | @click="selectedItems(item, index)" |
| | | > |
| | | {{ item.name }}<span style="margin-left: 5px">({{ item.data.length }})</span> |
| | | </p> |
| | | </div> |
| | | </div> |
| | | <div |
| | | class="workList" |
| | | v-if="selectedTypeList.length == 0" |
| | | style="display: flex; align-items: center; justify-content: center" |
| | | > |
| | | <el-empty image-size="100px" /> |
| | | </div> |
| | | </div> |
| | | <div class="workRight"> |
| | | <div class="right-list-components"> |
| | | <questionDom |
| | | v-if="selectedDataList.length > 0 && !selectedLoading" |
| | | :questionList="selectedDataList" |
| | | @selectQuestion="selectQuestion" |
| | | @delete-item="deleteCmsItem" |
| | | :noCheckbox="false" |
| | | :isDelete="true" |
| | | /> |
| | | <div v-if="selectedLoading" v-loading="selectedLoading"></div> |
| | | <el-empty v-if="selectedDataList.length == 0 && !selectedLoading" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <template #footer> |
| | | <div class="selectedFooter"> |
| | | <el-button type="primary" @click="visibleView = false"> 确认 </el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- 预览作业 --> |
| | | <el-dialog |
| | | class="customDialog" |
| | | align-center |
| | | v-model="visibleLook" |
| | | destroy-on-close |
| | | width="900" |
| | | > |
| | | <template #header> |
| | | <div class="viewTitle">预览作业</div> |
| | | </template> |
| | | <div class="viewContent"> |
| | | <div class="workBox"> |
| | | <div class="workLeft" style="width: 200px"> |
| | | <div class="workList" style="height: 100%" v-if="lookLeftList.length > 0"> |
| | | <div class="work-list-item" v-for="(item, index) in lookLeftList" :key="index"> |
| | | <p |
| | | :class=" |
| | | index == lookIndex ? 'work-list-item-text leftBg' : 'work-list-item-text' |
| | | " |
| | | @click="lookItems(item, index)" |
| | | > |
| | | {{ item.name }}<span style="margin-left: 5px">({{ item.data.length }})</span> |
| | | </p> |
| | | </div> |
| | | </div> |
| | | <div |
| | | class="workList" |
| | | v-if="lookLeftList.length == 0" |
| | | style="display: flex; align-items: center; justify-content: center" |
| | | > |
| | | <el-empty image-size="100px" /> |
| | | </div> |
| | | </div> |
| | | <div class="workRight"> |
| | | <div class="right-list-components"> |
| | | <questionDom |
| | | v-if="lookDataList.length > 0 && !selectedLoading" |
| | | :questionList="lookDataList" |
| | | @selectQuestion="selectQuestion" |
| | | @delete-item="deleteCmsItem" |
| | | :is-preview="visibleLook" |
| | | /> |
| | | <div v-if="selectedLoading" v-loading="selectedLoading"></div> |
| | | <el-empty v-if="lookDataList.length == 0 && !selectedLoading" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <template #footer> |
| | | <div class="selectedFooter"> |
| | | <el-button type="primary" @click="visibleLook = false"> 确认 </el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- 发布作业 --> |
| | | <el-dialog |
| | | class="customDialog" |
| | | title="发布作业" |
| | | v-model="visiblePub" |
| | | destroy-on-close |
| | | width="500" |
| | | align-center |
| | | :before-close="close" |
| | | > |
| | | <div class="pubContent"> |
| | | <span>发布日期:</span> |
| | | <el-date-picker |
| | | v-model="pubValue" |
| | | type="daterange" |
| | | range-separator="--" |
| | | start-placeholder="开始日期" |
| | | end-placeholder="结束日期" |
| | | @change="selectPubDate" |
| | | /> |
| | | </div> |
| | | <template #footer> |
| | | <div class="selectedFooter" style="padding: 0"> |
| | | <el-button type="primary" @click="submitWork"> 确认 </el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { reactive, ref, onMounted, inject, watch } from 'vue' |
| | | import { Search, ArrowRight } from '@element-plus/icons-vue' |
| | | import { useRoute, useRouter } from 'vue-router' |
| | | import questionDom from './components/questionDom.vue' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import moment from 'moment' |
| | | |
| | | const route: any = useRoute() |
| | | const router = useRouter() |
| | | const MG: any = inject('MG') |
| | | const config: any = inject('config') |
| | | const tool: any = inject('toolClass') |
| | | const classInfo = JSON.parse(route.query.classInfo) |
| | | const jobState = ref('all') |
| | | const searchKey = ref('') |
| | | const dataList = ref([]) |
| | | const userInfo = ref() |
| | | const defaultCmsPath = ref('') |
| | | |
| | | // 获取task参数 |
| | | const filterData = ref([ |
| | | { |
| | | value: config.taskType.homeWork, |
| | | field: 'Type', |
| | | subFilters: [] |
| | | } |
| | | ]) |
| | | // task |
| | | const taskData = reactive({ |
| | | id: '', |
| | | description: '', |
| | | rootCmsItemId: '', |
| | | name: '', |
| | | type: '', |
| | | state: '', |
| | | groupId: '', |
| | | beginDate: '', |
| | | endDate: '' |
| | | }) |
| | | // question Key |
| | | const questionKey = [ |
| | | 'Name', |
| | | 'Embedded_QuestionBank_AnalysisCon', |
| | | 'Embedded_QuestionBank_Answer', |
| | | 'Embedded_QuestionBank_Difficulty', |
| | | 'Embedded_QuestionBank_KnowledgePoint', |
| | | 'Embedded_QuestionBank_Option', |
| | | 'Embedded_QuestionBank_OptionStyle', |
| | | 'Embedded_QuestionBank_QuestionType', |
| | | 'Embedded_QuestionBank_Score', |
| | | 'Embedded_QuestionBank_Stem', |
| | | 'Embedded_QuestionBank_StemStyle' |
| | | ] |
| | | // dialognew |
| | | const visible = ref(false) |
| | | const stepActive = ref(0) |
| | | const activeTabs = ref('1') |
| | | // 新建作业 |
| | | const newLoading = ref(false) |
| | | const taskItem = reactive({ |
| | | homeworkName: '', |
| | | homeworkStartingDate: '', |
| | | homeworkSubmissionDate: '', |
| | | explain: '' |
| | | }) |
| | | let pages = reactive({ |
| | | currentPage: 1, |
| | | page: 1, |
| | | pageSize: 15, |
| | | count: 0, |
| | | loading: false |
| | | }) |
| | | // dialogedit |
| | | const visibleEdit = ref(false) |
| | | // dialogView |
| | | const visibleView = ref(false) |
| | | // dialogLook |
| | | const visibleLook = ref(false) |
| | | // left |
| | | const workLeftList: any = ref([]) |
| | | const leftLoading = ref(false) |
| | | const sysIndex = ref(0) |
| | | // 分数 |
| | | const scoreValue = ref(0) // 批量 |
| | | const scoreItemValue = ref('') // 单一 |
| | | const scoreLeftList: any = ref([]) |
| | | const scoreDataList: any = ref([]) |
| | | const scoreIndex = ref(0) |
| | | const scoreData: any = ref([]) // 自存储题目分数 |
| | | const isSet = ref(false) |
| | | // right |
| | | const workRightList: any = ref([]) |
| | | const rightLoading = ref(false) |
| | | const checkAll = ref(false) |
| | | const selectCache: any = ref([]) |
| | | const checkData: any = ref([]) |
| | | // 作业列表 |
| | | const tableData: any = ref([]) |
| | | // 已选作业资源 |
| | | const selectedTypeList: any = ref([]) |
| | | const selectedDataList: any = ref([]) |
| | | const selectedLoading = ref(false) |
| | | const selectedIndex = ref(0) |
| | | //预览作业 |
| | | const lookLeftList: any = ref([]) |
| | | const lookDataList: any = ref([]) |
| | | const lookIndex = ref(0) |
| | | // 发布作业 |
| | | const visiblePub = ref(false) |
| | | const pubValue = ref(null) |
| | | |
| | | onMounted(() => { |
| | | const userCache: any = localStorage.getItem('jesk-userInfo') |
| | | if (userCache) { |
| | | userInfo.value = JSON.parse(userCache) |
| | | } |
| | | defaultCmsPath.value = classInfo.bookRefCode ? 'jsek_digitalTextbooks' : 'defaultGoodsStore3' |
| | | getTaskList() |
| | | }) |
| | | |
| | | // 发布 |
| | | const selectPubDate = (item: any) => { |
| | | if (item.length > 0) { |
| | | taskItem.homeworkStartingDate = moment(item[0]).format('YYYY-MM-DDTHH:mm:ss') |
| | | taskItem.homeworkSubmissionDate = moment(item[1]).format('YYYY-MM-DDTHH:mm:ss') |
| | | } |
| | | } |
| | | |
| | | // 分页 |
| | | const handleSizeChange = (val: number) => { |
| | | pages.pageSize = val |
| | | getTaskList() |
| | | } |
| | | |
| | | const handleCurrentChange = (val: number) => { |
| | | pages.page = val |
| | | pages.currentPage = val |
| | | getTaskList() |
| | | } |
| | | |
| | | // 新建任务{Waiting:未开始,Normal:进行中,Ended:已结束} |
| | | const newTask = () => { |
| | | newLoading.value = true |
| | | if (!taskItem.homeworkName) { |
| | | ElMessage({ |
| | | type: 'warning', |
| | | message: '请填写作业名称 ' |
| | | }) |
| | | newLoading.value = false |
| | | return false |
| | | } |
| | | if (!taskItem.homeworkStartingDate) { |
| | | ElMessage({ |
| | | type: 'warning', |
| | | message: '请填写作业开始时间 ' |
| | | }) |
| | | newLoading.value = false |
| | | return false |
| | | } |
| | | if (!taskItem.homeworkSubmissionDate) { |
| | | ElMessage({ |
| | | type: 'warning', |
| | | message: '请填写作业结束时间' |
| | | }) |
| | | newLoading.value = false |
| | | return false |
| | | } |
| | | if (!visibleEdit.value) { |
| | | const data = { |
| | | name: taskItem.homeworkName, |
| | | description: taskItem.explain, |
| | | icon: '', |
| | | type: config.taskType.homeWork, |
| | | state: 'Waiting', |
| | | groupId: classInfo?.id, |
| | | order: 0, |
| | | beginDate: taskItem.homeworkStartingDate, |
| | | endDate: taskItem.homeworkSubmissionDate, |
| | | duration: 0, |
| | | config: JSON.stringify({ scoreData: [] }) |
| | | } |
| | | MG.edu |
| | | .newTask(data) |
| | | .then((res: any) => { |
| | | taskData.id = res |
| | | }) |
| | | .catch((e: any) => { |
| | | newLoading.value = false |
| | | console.log(e) |
| | | }) |
| | | } else { |
| | | updateTask() |
| | | } |
| | | setTimeout(() => { |
| | | newLoading.value = false |
| | | stepActive.value++ |
| | | getTaskList() |
| | | }, 600) |
| | | } |
| | | |
| | | // 更新任务 |
| | | const updateTask = () => { |
| | | const data = { |
| | | id: taskData.id, |
| | | name: taskItem.homeworkName, |
| | | description: taskItem.explain, |
| | | icon: '', |
| | | type: taskData.type, |
| | | state: taskData.state, |
| | | order: 0, |
| | | beginDate: moment(taskItem.homeworkStartingDate).format('YYYY-MM-DDTHH:mm:ss'), |
| | | endDate: moment(taskItem.homeworkSubmissionDate).format('YYYY-MM-DDTHH:mm:ss'), |
| | | duration: 0, |
| | | config: JSON.stringify({ scoreData: scoreData.value }) |
| | | } |
| | | MG.edu |
| | | .updateTask(data) |
| | | .then((res: any) => { |
| | | if (res) { |
| | | if (stepActive.value == 2) { |
| | | getTaskCmsList() |
| | | } |
| | | getTaskList() |
| | | } |
| | | }) |
| | | .catch((err: any) => { |
| | | console.log(err, 'updateTask') |
| | | }) |
| | | } |
| | | |
| | | // 获取任务列表 |
| | | const getTaskList = (filter?: any[], search?: any[]) => { |
| | | const filterList = filter ?? filterData.value |
| | | const searchList = search ?? [] |
| | | pages.loading = true |
| | | const data = { |
| | | start: (pages.page - 1) * pages.pageSize, |
| | | size: pages.pageSize, |
| | | sort: { |
| | | type: 'Desc', |
| | | field: 'CreateDate' |
| | | }, |
| | | filterList, |
| | | searchList, |
| | | groupId: classInfo?.id |
| | | } |
| | | MG.edu |
| | | .getTaskList(data) |
| | | .then((res: any) => { |
| | | pages.count = res.totalSize |
| | | if (res.datas.length > 0) { |
| | | tableData.value = res.datas?.map((item: any) => { |
| | | // const currTime = Number(sessionStorage.currentDate); |
| | | // const taskTime = moment(item.endDate).valueOf() |
| | | // if(taskTime < currTime){ |
| | | // console.log(taskTime,item.name,'7878') |
| | | // } |
| | | return { |
| | | ...item, |
| | | beginDate: moment(item.beginDate).format('YYYY-MM-DD'), |
| | | endDate: moment(item.endDate).format('YYYY-MM-DD') |
| | | } |
| | | }) |
| | | if (taskData.id) { |
| | | scoreData.value = [] |
| | | const obj = res.datas.find((item: any) => item.id == taskData.id) |
| | | taskData.id = obj.id |
| | | taskData.rootCmsItemId = obj.rootCmsItemId |
| | | if (obj.config) { |
| | | scoreData.value = JSON.parse(obj.config).scoreData |
| | | } |
| | | taskData.name = obj.name |
| | | taskData.groupId = classInfo?.id |
| | | taskData.state = obj.state |
| | | taskData.type = obj.type |
| | | taskData.beginDate = moment(obj.beginDate).format('YYYY-MM-DDTHH:mm:ss') |
| | | taskData.endDate = moment(obj.endDate).format('YYYY-MM-DDTHH:mm:ss') |
| | | } |
| | | } else { |
| | | tableData.value = [] |
| | | } |
| | | pages.loading = false |
| | | }) |
| | | .catch((e: any) => { |
| | | pages.loading = false |
| | | console.log(e) |
| | | }) |
| | | } |
| | | |
| | | // 搜索任务 |
| | | const searchTask = () => { |
| | | const data = [ |
| | | { |
| | | compareType: 'Contains', |
| | | keywords: searchKey.value, |
| | | field: 'Name' |
| | | } |
| | | ] |
| | | pages.page = 1 |
| | | pages.currentPage = 1 |
| | | getTaskList(undefined, data) |
| | | } |
| | | |
| | | // 删除资源 |
| | | const removeTaskItem = (item: any) => { |
| | | const data = { |
| | | ids: [item.id] |
| | | } |
| | | MG.edu |
| | | .delTask(data) |
| | | .then((res: any) => { |
| | | if (res) { |
| | | ElMessage({ |
| | | message: '删除成功', |
| | | type: 'success' |
| | | }) |
| | | getTaskList() |
| | | } |
| | | }) |
| | | .catch((e: any) => { |
| | | ElMessage({ |
| | | message: '删除失败', |
| | | type: 'error' |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | // 为任务添加资源 |
| | | const addCmsitem = () => { |
| | | const data = { |
| | | taskId: taskData.id, |
| | | requests: checkData.value?.map((item: any) => { |
| | | return { |
| | | path: String(taskData.rootCmsItemId), |
| | | cmsItemId: item.id |
| | | } |
| | | }) |
| | | } |
| | | MG.edu |
| | | .addTaskCmsItemList(data) |
| | | .then((res: any) => { |
| | | if (res) { |
| | | ElMessage({ |
| | | message: '已加入', |
| | | type: 'success' |
| | | }) |
| | | selectCache.value = [] |
| | | checkData.value = [] |
| | | checkAll.value = false |
| | | workRightList.value?.forEach((citem: any) => { |
| | | citem.data.forEach((titem: any) => (titem.isCheck = false)) |
| | | }) |
| | | } |
| | | }) |
| | | .catch((e: any) => { |
| | | ElMessage({ |
| | | message: '加入失败', |
| | | type: 'error' |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | // 获取任务下的资源列表 |
| | | const getTaskCmsList = () => { |
| | | selectedLoading.value = true |
| | | const data = { |
| | | start: 0, |
| | | size: 999, |
| | | searchList: [], |
| | | taskId: taskData?.id, // taskData?.id |
| | | path: String(taskData?.rootCmsItemId), //taskData?.rootCmsItemId |
| | | type: '*', |
| | | keys: questionKey |
| | | } |
| | | MG.edu |
| | | .getTaskCmsItem(data) |
| | | .then((res: any) => { |
| | | selectedLoading.value = false |
| | | for (let i = 0; i < res.datas.length; i++) { |
| | | let item = res.datas[i] |
| | | item.index = i + 1 |
| | | const scoreItem = scoreData.value.find((i: any) => i.id == item.id) |
| | | item.score = scoreItem?.score ?? 0 |
| | | item.isInput = false |
| | | // 处理字段 |
| | | if (questionKey != null) { |
| | | for (let fieldKey of questionKey) { |
| | | if (item.datas[fieldKey]) { |
| | | const values = JSON.parse(item.datas[fieldKey]) |
| | | if (values.length > 0) { |
| | | // 用字段名处理返回的字段值 |
| | | if (values[0].Value) { |
| | | item[fieldKey] = values[0].Value |
| | | } else if (values[0].Data) { |
| | | item[fieldKey] = values[0].Data.Value |
| | | } else if (!values[0].Value && values[0].FileList?.length > 0) { |
| | | item[fieldKey] = values[0].FileList |
| | | } else { |
| | | item[fieldKey] = '-' |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | if (stepActive.value == 2) { |
| | | scoreDataList.value = [] |
| | | scoreLeftList.value = changeQuestionData(res.datas) |
| | | if (scoreLeftList.value.length > 0) { |
| | | scoreDataList.value = scoreLeftList.value[scoreIndex.value].data |
| | | } |
| | | scoreValue.value = 0 |
| | | } else { |
| | | selectedDataList.value = [] |
| | | selectedTypeList.value = changeQuestionData(res.datas) |
| | | if (selectedTypeList.value.length > 0) { |
| | | selectedDataList.value = [selectedTypeList.value[0]] |
| | | } |
| | | } |
| | | }) |
| | | .catch((e: any) => { |
| | | ElMessage({ |
| | | message: '列表获取失败', |
| | | type: 'error' |
| | | }) |
| | | console.log(e) |
| | | }) |
| | | } |
| | | |
| | | // 删除已选的题目 |
| | | const deleteCmsItem = (item: any) => { |
| | | ElMessageBox.confirm('是否确认删除?', '提示', { |
| | | confirmButtonText: '是', |
| | | cancelButtonText: '否', |
| | | type: 'warning' |
| | | }).then(() => { |
| | | const data = { |
| | | taskId: taskData.id, |
| | | requests: [ |
| | | { |
| | | cmsItemId: item.id, |
| | | path: String(taskData.rootCmsItemId) |
| | | } |
| | | ] |
| | | } |
| | | MG.edu |
| | | .removeTaskCmsItemList(data) |
| | | .then((res: any) => { |
| | | if (res) { |
| | | ElMessage({ |
| | | type: 'success', |
| | | message: '已删除' |
| | | }) |
| | | selectedIndex.value = 0 |
| | | getTaskCmsList() |
| | | } |
| | | }) |
| | | .catch((err: any) => { |
| | | ElMessage({ |
| | | type: 'error', |
| | | message: '删除失败,请稍后再试' |
| | | }) |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | // 题目分数列表切换 |
| | | const scoreItem = (item: any, index: number) => { |
| | | scoreIndex.value = index |
| | | scoreDataList.value = item.data |
| | | } |
| | | |
| | | // 打开设置文本框 |
| | | const openSetScore = (item: any) => { |
| | | scoreItemValue.value = '' |
| | | item.isInput = true |
| | | } |
| | | |
| | | // 预览作业 |
| | | const lookWork = () => { |
| | | visibleLook.value = true |
| | | lookIndex.value = 0 |
| | | lookLeftList.value = [...scoreLeftList.value] |
| | | lookDataList.value = [lookLeftList.value[0]] |
| | | } |
| | | |
| | | // 批量设置分数 |
| | | const changeScore = () => { |
| | | isSet.value = true |
| | | } |
| | | |
| | | // 批量设置分数确认 |
| | | const setScoreArr = () => { |
| | | let data = [...scoreData.value] |
| | | let idsData = scoreDataList.value.map((item: any) => { |
| | | return { id: item.id, score: scoreValue.value } |
| | | }) |
| | | if (data.length == 0) { |
| | | data = [...idsData] |
| | | } else { |
| | | data = updateArr(data, idsData) |
| | | } |
| | | scoreData.value = data |
| | | updateTask() |
| | | isSet.value = false |
| | | } |
| | | |
| | | // 题目分数设置 |
| | | const setScore = (item: any) => { |
| | | item.score = Number(scoreItemValue.value) |
| | | const data = [...scoreData.value.filter((citem: any) => citem.id != item.id)] |
| | | data.push({ id: item.id, score: item.score }) |
| | | scoreData.value = [...data] |
| | | item.isInput = false |
| | | updateTask() |
| | | } |
| | | |
| | | // lookItems |
| | | const lookItems = (item: any, index: number) => { |
| | | lookIndex.value = index |
| | | lookDataList.value = [item] |
| | | } |
| | | |
| | | // 已选题目切换 |
| | | const selectedItems = (item: any, index: number) => { |
| | | selectedIndex.value = index |
| | | selectedDataList.value = [item] |
| | | } |
| | | |
| | | // 表格tab事件{Waiting:未开始,Normal:进行中,Ended:已结束} |
| | | const tabCart = (event: Event | any) => { |
| | | let queryFilter: any = [] |
| | | jobState.value = event.props.name |
| | | pages.page = 1 |
| | | dataList.value = [] |
| | | if (jobState.value == 'all') { |
| | | queryFilter = [...filterData.value] |
| | | } |
| | | if (jobState.value == 'payment') { |
| | | queryFilter = [...filterData.value, { field: 'State', value: 'Normal', subFilters: [] }] |
| | | } |
| | | if (jobState.value == 'complete') { |
| | | queryFilter = [...filterData.value, { field: 'State', value: 'Ended', subFilters: [] }] |
| | | } |
| | | getTaskList(queryFilter) |
| | | } |
| | | |
| | | // 题目tab事件 |
| | | const handleClick = (val: any) => { |
| | | activeTabs.value = val |
| | | workLeftList.value = [] |
| | | if (val == '1') { |
| | | getBookQuestionList() |
| | | } else { |
| | | workLeftList.value = [] |
| | | } |
| | | } |
| | | |
| | | // 下一步 |
| | | const nextStep = () => { |
| | | if (stepActive.value++ > 2) stepActive.value = 0 |
| | | if (stepActive.value == 2) getTaskCmsList() |
| | | } |
| | | |
| | | // 上一步 |
| | | const preStep = () => { |
| | | if (stepActive.value-- == 0) stepActive.value = 0 |
| | | } |
| | | |
| | | // 选择题目 |
| | | const selectQuestion = (item: any) => { |
| | | selectCache.value.push(item) |
| | | const list = selectCache.value.filter((citem: any) => citem.isCheck == true) |
| | | let dataT: any = [] |
| | | workRightList.value?.forEach((citem: any) => { |
| | | const itemArr = citem.data |
| | | dataT.push(...itemArr) |
| | | }) |
| | | checkData.value = [...new Set(list)] |
| | | if (dataT?.length > 0) { |
| | | checkAll.value = dataT.length == checkData.value.length |
| | | } |
| | | } |
| | | |
| | | // 全选 |
| | | const handleCheckAllChange = (val: boolean) => { |
| | | const data = workRightList.value |
| | | data.forEach((ele: any) => { |
| | | ele.data.forEach((item: any) => { |
| | | item.isCheck = val |
| | | }) |
| | | }) |
| | | let list: any = [] |
| | | data.forEach((citem: any) => { |
| | | const itemArr = citem.data.filter((titem: any) => titem.isCheck == true) |
| | | list.push(...itemArr) |
| | | }) |
| | | checkData.value = list |
| | | } |
| | | |
| | | // 查看已选 |
| | | const selectedData = () => { |
| | | visibleView.value = true |
| | | getTaskCmsList() |
| | | } |
| | | |
| | | // 新建作业打开 |
| | | const openWork = () => { |
| | | visible.value = true |
| | | checkAll.value = false |
| | | activeTabs.value = '1' |
| | | stepActive.value = 0 |
| | | selectCache.value = [] |
| | | workRightList.value = [] |
| | | checkData.value = [] |
| | | getBookQuestionList() |
| | | } |
| | | |
| | | // 关闭新建作业 |
| | | const close = () => { |
| | | taskItem.homeworkName = '' |
| | | taskItem.homeworkStartingDate = '' |
| | | taskItem.homeworkSubmissionDate = '' |
| | | taskItem.explain = '' |
| | | visible.value = false |
| | | visibleEdit.value = false |
| | | visiblePub.value = false |
| | | getTaskList() |
| | | } |
| | | |
| | | // 发布作业 |
| | | const releaseWork = (item: any) => { |
| | | visiblePub.value = true |
| | | taskData.id = item.id |
| | | taskData.rootCmsItemId = item.rootCmsItemId |
| | | if (item.config) { |
| | | scoreData.value = JSON.parse(item.config).scoreData |
| | | } |
| | | taskData.groupId = classInfo?.id |
| | | taskData.state = 'Normal' |
| | | taskData.type = item.type |
| | | taskItem.homeworkName = item.name |
| | | taskItem.explain = item.description |
| | | } |
| | | |
| | | // 请确认发布 |
| | | const submitWork = () => { |
| | | visiblePub.value = false |
| | | updateTask() |
| | | submitNewMessage() |
| | | } |
| | | |
| | | // 发布作业通知 |
| | | const submitNewMessage = () => { |
| | | const date = moment(taskItem.homeworkStartingDate).format('YYYY-MM-DD') |
| | | const content = date + ',发布作业,' + taskItem.homeworkName |
| | | const data = { |
| | | description: '', |
| | | icon: '', |
| | | state: 'Normal', |
| | | topicIdOrRefCode: String(sessionStorage.messageId), |
| | | name: '老师发布作业', |
| | | content, |
| | | type: 'Normal', |
| | | cmsTypeRefCode: '', |
| | | newDataListRequest: [] |
| | | } |
| | | MG.ugc |
| | | .newTopicMessage(data) |
| | | .then((res: any) => { |
| | | if (res) { |
| | | ElMessage({ |
| | | type: 'success', |
| | | message: '已发布' |
| | | }) |
| | | } |
| | | }) |
| | | .catch((err: any) => { |
| | | console.log(err) |
| | | }) |
| | | } |
| | | |
| | | // 编辑 |
| | | const edit = (item: any) => { |
| | | scoreData.value = [] |
| | | visibleEdit.value = true |
| | | taskData.id = item.id |
| | | taskData.rootCmsItemId = item.rootCmsItemId |
| | | if (item.config) { |
| | | scoreData.value = JSON.parse(item.config).scoreData |
| | | } |
| | | taskData.groupId = classInfo?.id |
| | | taskData.state = item.state |
| | | taskData.type = item.type |
| | | taskItem.homeworkName = item.name |
| | | taskItem.homeworkStartingDate = item.beginDate |
| | | taskItem.homeworkSubmissionDate = item.endDate |
| | | taskItem.explain = item.description |
| | | openWork() |
| | | } |
| | | |
| | | // 详情 |
| | | const detail = (item: any) => { |
| | | const obj = classInfo |
| | | obj.taskCmsId = item.rootCmsItemId |
| | | obj.taskWorkId = item.id |
| | | router.push({ |
| | | path: '/jobDetail', |
| | | query: { |
| | | classInfo: JSON.stringify(obj) |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 作业选中left |
| | | const clickRightItem = (item: any, index: number) => { |
| | | workRightList.value = [] |
| | | checkAll.value = false |
| | | sysIndex.value = index |
| | | getBookQuestionContentList(item.productLinkPath, item) |
| | | } |
| | | |
| | | // 搜索题干 |
| | | const searchWork = () => { |
| | | workLeftList.value = [] |
| | | getBookQuestionList() |
| | | } |
| | | |
| | | // 获取系统题干列表 |
| | | const getBookQuestionList = () => { |
| | | leftLoading.value = true |
| | | let query = { |
| | | path: defaultCmsPath.value, |
| | | queryType: '*', |
| | | productId: String(classInfo?.bookId), |
| | | storeInfo: defaultCmsPath.value, |
| | | cmsPath: classInfo?.rootCmsItemId |
| | | } |
| | | MG.store |
| | | .getProductDetail(query) |
| | | .then(async (res: any) => { |
| | | const { cmsDatas } = res.datas |
| | | leftLoading.value = false |
| | | const listQusetion = cmsDatas[0]?.datas |
| | | const obj = listQusetion?.find((item: any) => item.type == 'questionBankFolder') |
| | | if (obj && obj.productLinkPath) { |
| | | let query = { |
| | | path: defaultCmsPath.value, |
| | | queryType: '*', |
| | | productId: String(classInfo?.bookId), |
| | | storeInfo: defaultCmsPath.value, |
| | | cmsPath: obj.productLinkPath |
| | | } |
| | | MG.store |
| | | .getProductDetail(query) |
| | | .then(async (cres: any) => { |
| | | const { cmsDatas } = cres.datas |
| | | const list: any = cmsDatas[0]?.datas |
| | | workLeftList.value = list |
| | | if (list?.length > 0) { |
| | | const cmsPath = list[0].productLinkPath |
| | | getBookQuestionContentList(cmsPath, list[0]) |
| | | } |
| | | }) |
| | | .catch((err: any) => { |
| | | leftLoading.value = false |
| | | workLeftList.value = [] |
| | | console.log(err) |
| | | }) |
| | | } |
| | | }) |
| | | .catch((err: any) => { |
| | | leftLoading.value = false |
| | | workLeftList.value = [] |
| | | console.log(err) |
| | | }) |
| | | } |
| | | |
| | | // 递归获取 |
| | | const getDataCms = async (res: any) => { |
| | | for (const item of res) { |
| | | const data = await MG.store.getProductDetail({ |
| | | path: defaultCmsPath.value, |
| | | queryType: '*', |
| | | productId: String(classInfo?.bookId), |
| | | storeInfo: defaultCmsPath.value, |
| | | cmsPath: item.productLinkPath, |
| | | itemFields: { |
| | | Embedded_QuestionBank_AnalysisCon: [], |
| | | Embedded_QuestionBank_Answer: [], |
| | | Embedded_QuestionBank_Difficulty: [], |
| | | Embedded_QuestionBank_KnowledgePoint: [], |
| | | Embedded_QuestionBank_Option: [], |
| | | Embedded_QuestionBank_OptionStyle: [], |
| | | Embedded_QuestionBank_QuestionType: [], |
| | | Embedded_QuestionBank_Score: [], |
| | | Embedded_QuestionBank_Stem: [], |
| | | Embedded_QuestionBank_StemStyle: [] |
| | | } |
| | | }) |
| | | if (item.type == 'questionBankFolder' && item.childrenFolderCount == 0) { |
| | | return data.datas.cmsDatas |
| | | } else { |
| | | const { cmsDatas } = data.datas |
| | | if (cmsDatas?.length > 0) { |
| | | const list: any = await getDataCms(cmsDatas[0].datas) |
| | | return list |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 获取系统题目列表 |
| | | const getBookQuestionContentList = (cmsPath: string, item: any) => { |
| | | rightLoading.value = true |
| | | workRightList.value = [] |
| | | if (item.type == 'questionBankFolder' && item.childrenFolderCount == 0) { |
| | | let query = { |
| | | path: defaultCmsPath.value, |
| | | queryType: '*', |
| | | productId: String(classInfo?.bookId), |
| | | storeInfo: defaultCmsPath.value, |
| | | cmsPath, |
| | | itemFields: { |
| | | Embedded_QuestionBank_AnalysisCon: [], |
| | | Embedded_QuestionBank_Answer: [], |
| | | Embedded_QuestionBank_Difficulty: [], |
| | | Embedded_QuestionBank_KnowledgePoint: [], |
| | | Embedded_QuestionBank_Option: [], |
| | | Embedded_QuestionBank_OptionStyle: [], |
| | | Embedded_QuestionBank_QuestionType: [], |
| | | Embedded_QuestionBank_Score: [], |
| | | Embedded_QuestionBank_Stem: [], |
| | | Embedded_QuestionBank_StemStyle: [] |
| | | } |
| | | } |
| | | MG.store |
| | | .getProductDetail(query) |
| | | .then(async (cres: any) => { |
| | | rightLoading.value = false |
| | | const { cmsDatas } = cres.datas |
| | | const list: any = cmsDatas[0]?.datas |
| | | workRightList.value = changeQuestionData(list) |
| | | if (workRightList.value?.length > 0) { |
| | | const ids = workRightList.value.map((item: any) => item.id) |
| | | checkAll.value = getInclude3(checkData.value, ids) |
| | | } |
| | | }) |
| | | .catch((err: any) => { |
| | | rightLoading.value = false |
| | | workRightList.value = [] |
| | | console.log(err) |
| | | }) |
| | | } else { |
| | | let query = { |
| | | path: defaultCmsPath.value, |
| | | queryType: '*', |
| | | productId: String(classInfo?.bookId), |
| | | storeInfo: defaultCmsPath.value, |
| | | cmsPath: item.productLinkPath |
| | | } |
| | | MG.store |
| | | .getProductDetail(query) |
| | | .then(async (res: any) => { |
| | | const { cmsDatas } = res.datas |
| | | const cmsList = await getDataCms(cmsDatas[0]?.datas) |
| | | const list = cmsList[0]?.datas |
| | | workRightList.value = changeQuestionData(list) |
| | | rightLoading.value = false |
| | | if (workRightList.value?.length > 0) { |
| | | const ids = workRightList.value.map((item: any) => item.id) |
| | | checkAll.value = getInclude3(checkData.value, ids) |
| | | } |
| | | }) |
| | | .catch((err: any) => { |
| | | rightLoading.value = false |
| | | workRightList.value = [] |
| | | console.log(err) |
| | | }) |
| | | } |
| | | } |
| | | |
| | | // // 获取教材题目章节 |
| | | // const getChapter = async () => { |
| | | // const url = config.questionUrl + classInfo?.bookRefCode + '/information.json' |
| | | // const { data } = await axios.get(url) |
| | | // let dataList: any = [] |
| | | // if (data?.data?.length > 0) { |
| | | // dataList = data.data.map((item: any) => { |
| | | // return { |
| | | // ...item, |
| | | // name: item.label |
| | | // } |
| | | // }) |
| | | // } |
| | | // workLeftList.value = dataList?.filter((item: any) => item.page != '') |
| | | // } |
| | | |
| | | // // 获取章节题目列表 |
| | | // const getChapterQeustion = async (item: any) => { |
| | | // // 题库题目类型 |
| | | // const questionTypeList = [ |
| | | // { name: '单选题', totalScore: 0, value: 'singleChoice', data: [] }, |
| | | // { name: '多选题', totalScore: 0, value: 'multipleChoice', data: [] }, |
| | | // { name: '判断题', totalScore: 0, value: 'judge', data: [] }, |
| | | // { name: '简答题', totalScore: 0, value: 'shortAnswer', data: [] }, |
| | | // { name: '论述题', totalScore: 0, value: 'discuss', data: [] }, |
| | | // { name: '填空题', totalScore: 0, value: 'completion', data: [] }, |
| | | // { name: '连线题', totalScore: 0, value: 'matching', data: [] }, |
| | | // { name: '分类题', totalScore: 0, value: 'classification', data: [] } |
| | | // ] |
| | | // try { |
| | | // let list: any = [] |
| | | // const { data } = await axios.get( |
| | | // config.questionUrl + classInfo?.bookRefCode + '/question-' + item.chapter + '.json' |
| | | // ) |
| | | // list = data.data.map((item: any) => { |
| | | // if (item.type == 'material') { |
| | | // item.questionType = 'shortAnswer' |
| | | // } |
| | | // return { |
| | | // ...item, |
| | | // analysisCon: item.Embedded_QuestionBank_AnalysisCon, |
| | | // questionAnswer: item.answer, |
| | | // questionStem: item.stem, |
| | | // questionOption: item.option, |
| | | // customAnswer: null |
| | | // } |
| | | // }) |
| | | // console.log(list, 'list') |
| | | // list.forEach((item: any) => { |
| | | // const index = findIndexByValue(questionTypeList, item.questionType) |
| | | // if (index > -1) { |
| | | // questionTypeList[index].data.push(item) |
| | | // if (item.score) { |
| | | // questionTypeList[index].totalScore += item.score |
| | | // } |
| | | // } |
| | | // }) |
| | | // console.log(questionTypeList) |
| | | // } catch (error) { |
| | | // console.log(error) |
| | | // } |
| | | // } |
| | | |
| | | // 数组中是否包含另一个数组 |
| | | const getInclude3 = (arr1: any[], arr2: any[]) => { |
| | | let temp = [] |
| | | temp = arr1.filter((item) => arr2.indexOf(item.id) > -1) |
| | | return temp.length ? true : false |
| | | } |
| | | |
| | | // 处理题目数据结构 |
| | | const changeQuestionData = (res: any) => { |
| | | // 题库题目类型 |
| | | const questionTypeList = [ |
| | | { name: '单选题', totalScore: 0, value: 'singleChoice', data: [] }, |
| | | { name: '多选题', totalScore: 0, value: 'multipleChoice', data: [] }, |
| | | { name: '判断题', totalScore: 0, value: 'judge', data: [] }, |
| | | { name: '简答题', totalScore: 0, value: 'shortAnswer', data: [] }, |
| | | { name: '论述题', totalScore: 0, value: 'discuss', data: [] }, |
| | | { name: '填空题', totalScore: 0, value: 'completion', data: [] }, |
| | | { name: '连线题', totalScore: 0, value: 'matching', data: [] }, |
| | | { name: '分类题', totalScore: 0, value: 'classification', data: [] } |
| | | ] |
| | | try { |
| | | let list = [] |
| | | list = res?.map((item: any) => { |
| | | try { |
| | | if (item.Embedded_QuestionBank_Stem) { |
| | | item.questionStem = JSON.parse(item.Embedded_QuestionBank_Stem) |
| | | } |
| | | if ( |
| | | item.Embedded_QuestionBank_Option && |
| | | item.Embedded_QuestionBank_Option.indexOf('[') > -1 |
| | | ) { |
| | | item.questionOption = JSON.parse(item.Embedded_QuestionBank_Option) |
| | | } |
| | | if ( |
| | | item.Embedded_QuestionBank_Answer && |
| | | item.Embedded_QuestionBank_Answer.indexOf('[') > -1 |
| | | ) { |
| | | item.Embedded_QuestionBank_Answer = JSON.parse(item.Embedded_QuestionBank_Answer) |
| | | } |
| | | const checkObj = checkData.value.find((citem: any) => citem.id == item.id) |
| | | item.isCheck = checkObj ? true : false |
| | | return { |
| | | ...item, |
| | | questionType: item.Embedded_QuestionBank_QuestionType, |
| | | questionAnalysisCon: item.Embedded_QuestionBank_AnalysisCon, |
| | | questionAnswer: item.Embedded_QuestionBank_Answer, |
| | | customAnswer: null |
| | | } |
| | | } catch (error) { |
| | | console.log(item) |
| | | } |
| | | }) |
| | | list.forEach((item: any) => { |
| | | const index = findIndexByValue(questionTypeList, item.questionType) |
| | | if (index > -1) { |
| | | questionTypeList[index].data.push(item) |
| | | if (item.score) { |
| | | questionTypeList[index].totalScore += item.score |
| | | } |
| | | } |
| | | }) |
| | | return questionTypeList.filter((item) => item.data.length > 0) |
| | | } catch (error) { |
| | | console.log(error) |
| | | return [] |
| | | } |
| | | } |
| | | |
| | | const findIndexByValue = (res: any, type: string) => { |
| | | for (let i = 0; i < res.length; i++) { |
| | | if (res[i].value == type) { |
| | | return i |
| | | } |
| | | } |
| | | return -1 // 如果未找到,则返回 -1 |
| | | } |
| | | |
| | | // 合并更新数组 |
| | | const updateArr = (arr: any, brr: any) => { |
| | | // 使用 Map 来存储合并后的结果 |
| | | const mergedMap = new Map() |
| | | |
| | | // 将第一个数组的对象加入到 Map 中 |
| | | arr.forEach((item: any) => { |
| | | mergedMap.set(item.id, { ...item }) |
| | | }) |
| | | |
| | | // 遍历第二个数组,更新 Map 中相同 id 的对象的 score |
| | | brr.forEach((item: any) => { |
| | | if (mergedMap.has(item.id)) { |
| | | mergedMap.get(item.id).score = item.score |
| | | } else { |
| | | mergedMap.set(item.id, { ...item }) |
| | | } |
| | | }) |
| | | |
| | | // 将 Map 转换为数组 |
| | | const mergedArray = Array.from(mergedMap.values()) |
| | | return mergedArray |
| | | } |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .classManagePage-box { |
| | | padding: 20px; |
| | | .classManagePage-nav { |
| | | padding-bottom: 20px; |
| | | border-bottom: 1px solid #e6e8ed; |
| | | } |
| | | .classManagePage-content { |
| | | .cartClass { |
| | | .titleOptions { |
| | | width: 160px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | span { |
| | | height: 30px; |
| | | font-weight: bold; |
| | | font-size: 16px; |
| | | color: #333; |
| | | line-height: 30px; |
| | | text-align: left; |
| | | border-left: 6px solid #ff6c00; |
| | | padding-left: 10px; |
| | | } |
| | | } |
| | | margin-top: 20px; |
| | | ::v-deep .el-tabs__nav-wrap::after { |
| | | background-color: #ff6d00; |
| | | height: 1px; |
| | | } |
| | | |
| | | ::v-deep .el-tabs__item { |
| | | width: 100px; |
| | | padding: 0; |
| | | color: #545c63; |
| | | } |
| | | |
| | | ::v-deep .is-active { |
| | | background-color: #ff6d00; |
| | | color: #fff; |
| | | border-radius: 3px 3px 0 0; |
| | | } |
| | | } |
| | | .headerBox { |
| | | padding: 20px 0; |
| | | overflow: hidden; |
| | | .searchBox { |
| | | width: 300px; |
| | | float: left; |
| | | .searchBtn { |
| | | background-color: var(--el-color-primary); |
| | | color: #fff; |
| | | border-top-left-radius: 0; |
| | | border-bottom-left-radius: 0; |
| | | } |
| | | } |
| | | } |
| | | ::v-deep(.customDialog) { |
| | | border-radius: 5px; |
| | | .stepBox { |
| | | padding: 15px 0; |
| | | } |
| | | padding-bottom: 20px; |
| | | .el-dialog__body { |
| | | padding: 0 20px; |
| | | } |
| | | .el-dialog__footer { |
| | | width: calc(100% - 40px); |
| | | margin: auto; |
| | | display: flex; |
| | | padding: 0; |
| | | .leftFooter { |
| | | height: 55px; |
| | | width: 286px; |
| | | border: 1px solid #f4f4f4; |
| | | background: #e0f2ff; |
| | | margin-right: 20px; |
| | | } |
| | | .dialog-footer { |
| | | flex: 1; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: flex-start; |
| | | border: 1px solid #f4f4f4; |
| | | border-top: 0; |
| | | padding: 0 10px; |
| | | .check-list-box { |
| | | width: 220px; |
| | | display: flex; |
| | | justify-content: flex-start; |
| | | } |
| | | .btnGroup { |
| | | flex: 1; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: flex-end; |
| | | } |
| | | } |
| | | .selectedFooter { |
| | | width: 100%; |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | padding: 10px 0; |
| | | } |
| | | } |
| | | .viewTitle { |
| | | width: 100%; |
| | | text-align: center; |
| | | font-size: 16px; |
| | | } |
| | | } |
| | | .workTitle { |
| | | margin: 20px 0; |
| | | font-size: 16px; |
| | | color: #333; |
| | | } |
| | | .viewContent { |
| | | width: 100%; |
| | | .right-list-components { |
| | | height: calc(100% - 5px) !important; |
| | | } |
| | | } |
| | | .workBox { |
| | | width: 100%; |
| | | display: flex; |
| | | .workLeft { |
| | | width: 286px; |
| | | height: 700px; |
| | | border-radius: 10px 10px 0px 0px; |
| | | border: 1px solid #f4f4f4; |
| | | border-bottom: 0; |
| | | .scoreTitle { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: flex-start; |
| | | line-height: 39px; |
| | | padding-left: 10px; |
| | | box-sizing: border-box; |
| | | } |
| | | ::v-deep(.demo-tabs) { |
| | | .el-tabs__header { |
| | | margin: 0; |
| | | } |
| | | .el-tabs__nav { |
| | | width: 100%; |
| | | justify-content: center; |
| | | padding: 8px 0; |
| | | .el-tabs__item { |
| | | flex: 1; |
| | | height: 0px; |
| | | padding: 12px 0; |
| | | } |
| | | .el-tabs__item { |
| | | border-right: 1px solid #eee; |
| | | } |
| | | .el-tabs__item:last-child { |
| | | border: 0; |
| | | } |
| | | .el-tabs__active-bar { |
| | | display: none; |
| | | // width: 60px !important; |
| | | // left: 40px !important; |
| | | } |
| | | } |
| | | .el-tabs__nav-wrap::after { |
| | | height: 0px !important; |
| | | background: none; |
| | | } |
| | | } |
| | | .workList { |
| | | width: 100%; |
| | | height: calc(100% - 39px); |
| | | background: #e0f2ff; |
| | | overflow: auto; |
| | | padding: 10px 18px; |
| | | .searchBox { |
| | | position: sticky; |
| | | top: -10px; |
| | | z-index: 9999999; |
| | | } |
| | | .work-list-item { |
| | | background: #ffffff; |
| | | border-radius: 5px 5px 5px 5px; |
| | | margin: 10px 0; |
| | | .work-list-item-text { |
| | | font-family: PingFang SC; |
| | | font-weight: 400; |
| | | font-size: 13px; |
| | | color: #000000; |
| | | line-height: 22px; |
| | | max-width: 248px; |
| | | white-space: nowrap; |
| | | text-overflow: ellipsis; |
| | | overflow: hidden; |
| | | padding: 6px 10px; |
| | | } |
| | | .work-list-item-text:hover { |
| | | cursor: pointer; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .workRight { |
| | | flex: 1; |
| | | height: 700px; |
| | | margin-left: 20px; |
| | | border-radius: 10px 10px 0px 0px; |
| | | border: 1px solid #f4f4f4; |
| | | .right-list-title { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | width: 100%; |
| | | height: 39px; |
| | | border-bottom: 1px solid #f4f4f4; |
| | | line-height: 39px; |
| | | padding: 0 10px; |
| | | } |
| | | .right-list-components { |
| | | width: 100%; |
| | | height: calc(100% - 40px); |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | .right-score-components { |
| | | padding: 10px; |
| | | .scoreBtn { |
| | | margin-bottom: 20px; |
| | | display: flex; |
| | | justify-content: flex-start; |
| | | align-items: center; |
| | | // .setScore { |
| | | // margin-left: 20px; |
| | | // } |
| | | } |
| | | } |
| | | } |
| | | .finishBg { |
| | | width: 100%; |
| | | height: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: center; |
| | | align-items: center; |
| | | img { |
| | | width: 300px; |
| | | margin-bottom: 20px; |
| | | } |
| | | span { |
| | | font-family: PingFang SC; |
| | | font-weight: 500; |
| | | font-size: 18px; |
| | | color: #999999; |
| | | } |
| | | } |
| | | } |
| | | .newTaskBox { |
| | | width: 750px; |
| | | height: 700px; |
| | | font-family: PingFang SC; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #333333; |
| | | margin: auto; |
| | | padding-top: 60px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | box-sizing: border-box; |
| | | |
| | | .el-row { |
| | | margin-bottom: 20px; |
| | | display: flex; |
| | | align-items: flex-start; |
| | | .labelItem { |
| | | text-align: right; |
| | | margin-right: 10px; |
| | | padding-top: 2px; |
| | | } |
| | | .selectBox { |
| | | border: 1px solid #ddd; |
| | | border-radius: 5px; |
| | | padding: 20px 30px; |
| | | } |
| | | .selectMarBot { |
| | | margin-bottom: 10px; |
| | | } |
| | | .btngroup { |
| | | position: absolute; |
| | | top: 20px; |
| | | right: 27px; |
| | | } |
| | | .el-upload-list__item-name { |
| | | line-height: 22px; |
| | | } |
| | | } |
| | | |
| | | .row-center { |
| | | align-items: center; |
| | | } |
| | | } |
| | | .leftBg { |
| | | background-color: rgba(255, 173, 65, 0.1); |
| | | border-radius: 5px 5px 5px 5px; |
| | | color: #ff6c00 !important; |
| | | } |
| | | .pageBox { |
| | | padding: 10px 0; |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | } |
| | | .pubContent { |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | padding: 20px 0; |
| | | } |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="classManagePage-box"> |
| | | <div class="classManagePage-nav">我的班级>{{ classInfo.name }}>备课</div> |
| | | <div class="classManagePage-content"></div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { useRoute } from 'vue-router' |
| | | const route = useRoute() |
| | | const classInfo = JSON.parse(route.query.classInfo) |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .classManagePage-box { |
| | | padding: 20px; |
| | | .classManagePage-nav { |
| | | padding-bottom: 20px; |
| | | border-bottom: 1px solid #e6e8ed; |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="classManagePage-box"> |
| | | <div class="classManagePage-nav"> |
| | | <el-breadcrumb :separator-icon="ArrowRight"> |
| | | <el-breadcrumb-item>我的班级</el-breadcrumb-item> |
| | | <el-breadcrumb-item>{{ classInfo?.name }}</el-breadcrumb-item> |
| | | <el-breadcrumb-item>作业管理</el-breadcrumb-item> |
| | | </el-breadcrumb> |
| | | </div> |
| | | <div class="classManagePage-content"> |
| | | <div class="cartClass"> |
| | | <!-- <el-tabs v-model="jobState" @tab-click="tabCart"> |
| | | <el-tab-pane label="全部" name="all"></el-tab-pane> |
| | | <el-tab-pane label="进行中" name="payment"></el-tab-pane> |
| | | <el-tab-pane label="已过期" name="complete"></el-tab-pane> |
| | | </el-tabs> --> |
| | | <div class="titleOptions"> |
| | | <span>作业管理</span> |
| | | </div> |
| | | </div> |
| | | <div class="headerBox"> |
| | | <div class="searchBox"> |
| | | <el-input |
| | | v-model="searchKey" |
| | | clearable |
| | | @clear="searchTask" |
| | | @keydown.enter="searchTask" |
| | | placeholder="请输入关键字" |
| | | > |
| | | <template #append> |
| | | <el-button type="primary" @click="searchTask" class="searchBtn" :icon="Search" /> |
| | | </template> |
| | | </el-input> |
| | | </div> |
| | | </div> |
| | | <div class="listBox"> |
| | | <el-table |
| | | :data="tableData" |
| | | :header-cell-style="{ background: '#eee' }" |
| | | max-height="600px" |
| | | style="width: 100%" |
| | | v-loading="pages.loading" |
| | | > |
| | | <el-table-column label="序号" prop="id" width="70"> </el-table-column> |
| | | <el-table-column label="名称" prop="name"> </el-table-column> |
| | | <el-table-column label="作业完成情况" #default="scope"> |
| | | <span v-if="scope.row.submitState == 'WaitCheck'" style="color: #ff6d00">待批改</span> |
| | | <span v-if="scope.row.submitState == 'Normal'" style="color: #67c23a">已批改</span> |
| | | <span v-if="!scope.row.submitState" style="color: red">未提交</span> |
| | | </el-table-column> |
| | | <!-- <el-table-column label="状态" prop="state" #default="scope"> |
| | | <span v-if="scope.row.state == 'Waiting'" style="color: red">未开始</span> |
| | | <span v-if="scope.row.state == 'Normal'" style="color: #67c23a">进行中</span> |
| | | <span v-if="scope.row.state == 'Ended'" style="color: #999">已结束</span> |
| | | </el-table-column> --> |
| | | <el-table-column label="作业开始日期" prop="beginDate"> </el-table-column> |
| | | <el-table-column label="作业结束日期" prop="endDate"> </el-table-column> |
| | | <el-table-column label="主观题得分" prop="judgeScore"> </el-table-column> |
| | | <el-table-column label="客观题得分" prop="otherScore"> </el-table-column> |
| | | <el-table-column label="总分" prop="totalScore"> </el-table-column> |
| | | <el-table-column label="操作" width="200" #default="scope"> |
| | | <el-button link style="color: #409eff" @click="preview(scope.row)">预览</el-button> |
| | | <el-button link v-if="!scope.row.submitState" type="primary" @click="answer(scope.row)"> |
| | | 答题 |
| | | </el-button> |
| | | </el-table-column> |
| | | </el-table> |
| | | <div class="pageBox"> |
| | | <el-pagination |
| | | v-model:current-page="pages.currentPage" |
| | | :page-size="pages.pageSize" |
| | | :size="'small'" |
| | | :disabled="pages.count <= 1" |
| | | layout="total, prev, pager, next" |
| | | :total="pages.count" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { reactive, ref, onMounted, inject, watch } from 'vue' |
| | | import { Search, ArrowRight } from '@element-plus/icons-vue' |
| | | import { useRoute, useRouter } from 'vue-router' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import moment from 'moment' |
| | | |
| | | const route: any = useRoute() |
| | | const router = useRouter() |
| | | const MG: any = inject('MG') |
| | | const config: any = inject('config') |
| | | const tool: any = inject('toolClass') |
| | | const classInfo = JSON.parse(route.query.classInfo) |
| | | const jobState = ref('all') |
| | | const searchKey = ref('') |
| | | const dataList = ref([]) |
| | | const userInfo = ref() |
| | | |
| | | // 获取task参数 |
| | | const filterData = ref([ |
| | | { |
| | | value: config.taskType.homeWork, |
| | | field: 'Type', |
| | | subFilters: [] |
| | | } |
| | | ]) |
| | | // task |
| | | const taskData = reactive({ |
| | | id: '', |
| | | description: '', |
| | | rootCmsItemId: '', |
| | | name: '', |
| | | type: '', |
| | | state: '', |
| | | groupId: '', |
| | | beginDate: '', |
| | | endDate: '' |
| | | }) |
| | | |
| | | const visiblePub = ref(false) |
| | | const questionData: any = ref([]) |
| | | |
| | | const scoreData: any = ref([]) |
| | | // question Key |
| | | const questionKey = [ |
| | | 'Name', |
| | | 'Embedded_QuestionBank_AnalysisCon', |
| | | 'Embedded_QuestionBank_Answer', |
| | | 'Embedded_QuestionBank_Difficulty', |
| | | 'Embedded_QuestionBank_KnowledgePoint', |
| | | 'Embedded_QuestionBank_Option', |
| | | 'Embedded_QuestionBank_OptionStyle', |
| | | 'Embedded_QuestionBank_QuestionType', |
| | | 'Embedded_QuestionBank_Score', |
| | | 'Embedded_QuestionBank_Stem', |
| | | 'Embedded_QuestionBank_StemStyle' |
| | | ] |
| | | |
| | | let pages = reactive({ |
| | | currentPage: 1, |
| | | page: 1, |
| | | pageSize: 15, |
| | | count: 0, |
| | | loading: false |
| | | }) |
| | | // 作业列表 |
| | | const tableData: any = ref([]) |
| | | |
| | | onMounted(() => { |
| | | const userCache: any = localStorage.getItem('jesk-userInfo') |
| | | if (userCache) { |
| | | userInfo.value = JSON.parse(userCache) |
| | | } |
| | | getTaskList() |
| | | }) |
| | | |
| | | // 分页 |
| | | const handleSizeChange = (val: number) => { |
| | | pages.pageSize = val |
| | | getTaskList() |
| | | } |
| | | |
| | | const handleCurrentChange = (val: number) => { |
| | | pages.page = val |
| | | pages.currentPage = val |
| | | getTaskList() |
| | | } |
| | | |
| | | // 获取任务列表 |
| | | const getTaskList = (filter?: any[], search?: any[]) => { |
| | | const filterList = filter ?? filterData.value |
| | | const searchList = search ?? [] |
| | | pages.loading = true |
| | | const data = { |
| | | start: (pages.page - 1) * pages.pageSize, |
| | | size: pages.pageSize, |
| | | sort: { |
| | | type: 'Desc', |
| | | field: 'CreateDate' |
| | | }, |
| | | filterList, |
| | | searchList, |
| | | groupId: classInfo?.id |
| | | } |
| | | MG.edu |
| | | .getTaskList(data) |
| | | .then((res: any) => { |
| | | pages.count = res.totalSize |
| | | if (res.datas.length > 0) { |
| | | tableData.value = res.datas?.map((item: any) => { |
| | | item.judgeScore = 0 |
| | | item.otherScore = 0 |
| | | if (item.submit?.id) { |
| | | item.submit?.submitAndCmsItemLinks?.forEach((citem: any) => { |
| | | if (citem.comments == 'judge') { |
| | | item.judgeScore += citem.score |
| | | } |
| | | if (citem.comments != 'judge') { |
| | | item.otherScore += citem.score |
| | | } |
| | | }) |
| | | } |
| | | return { |
| | | ...item, |
| | | totalScore: item.judgeScore + item.otherScore, |
| | | beginDate: moment(item.beginDate).format('YYYY-MM-DD'), |
| | | endDate: moment(item.endDate).format('YYYY-MM-DD') |
| | | } |
| | | }) |
| | | } else { |
| | | tableData.value = [] |
| | | } |
| | | pages.loading = false |
| | | }) |
| | | .catch((e: any) => { |
| | | pages.loading = false |
| | | console.log(e) |
| | | }) |
| | | } |
| | | |
| | | // 搜索任务 |
| | | const searchTask = () => { |
| | | const data = [ |
| | | { |
| | | compareType: 'Contains', |
| | | keywords: searchKey.value, |
| | | field: 'Name' |
| | | } |
| | | ] |
| | | pages.page = 1 |
| | | pages.currentPage = 1 |
| | | getTaskList(undefined, data) |
| | | } |
| | | |
| | | // 表格tab事件{Waiting:未开始,Normal:进行中,Ended:已结束} |
| | | const tabCart = (event: Event | any) => { |
| | | let queryFilter: any = [] |
| | | jobState.value = event.props.name |
| | | pages.page = 1 |
| | | dataList.value = [] |
| | | if (jobState.value == 'all') { |
| | | queryFilter = [...filterData.value] |
| | | } |
| | | if (jobState.value == 'payment') { |
| | | queryFilter = [...filterData.value, { field: 'State', value: 'Normal', subFilters: [] }] |
| | | } |
| | | if (jobState.value == 'complete') { |
| | | queryFilter = [...filterData.value, { field: 'State', value: 'Ended', subFilters: [] }] |
| | | } |
| | | getTaskList(queryFilter) |
| | | } |
| | | |
| | | // 答题 |
| | | const answer = (item: any) => { |
| | | router.push({ |
| | | path: '/bookService/details/answer', |
| | | query: { |
| | | answerTitle: item.name, |
| | | taskId: item.id, |
| | | groupId: classInfo?.id, |
| | | answerType: 'task' |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 预览 |
| | | const preview = (item: any) => { |
| | | router.push({ |
| | | path: '/bookService/details/answer', |
| | | query: { |
| | | answerTitle: item.name, |
| | | taskId: item.id, |
| | | groupId: classInfo?.id, |
| | | answerType: 'task', |
| | | isPreview: 'true' |
| | | } |
| | | }) |
| | | } |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .classManagePage-box { |
| | | padding: 20px; |
| | | .classManagePage-nav { |
| | | padding-bottom: 20px; |
| | | border-bottom: 1px solid #e6e8ed; |
| | | } |
| | | .classManagePage-content { |
| | | .cartClass { |
| | | .titleOptions { |
| | | width: 160px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | span { |
| | | height: 30px; |
| | | font-weight: bold; |
| | | font-size: 16px; |
| | | color: #333; |
| | | line-height: 30px; |
| | | text-align: left; |
| | | border-left: 6px solid #ff6c00; |
| | | padding-left: 10px; |
| | | } |
| | | } |
| | | margin-top: 20px; |
| | | ::v-deep .el-tabs__nav-wrap::after { |
| | | background-color: #ff6d00; |
| | | height: 1px; |
| | | } |
| | | |
| | | ::v-deep .el-tabs__item { |
| | | width: 100px; |
| | | padding: 0; |
| | | color: #545c63; |
| | | } |
| | | |
| | | ::v-deep .is-active { |
| | | background-color: #ff6d00; |
| | | color: #fff; |
| | | border-radius: 3px 3px 0 0; |
| | | } |
| | | } |
| | | .headerBox { |
| | | padding: 20px 0; |
| | | overflow: hidden; |
| | | .searchBox { |
| | | width: 300px; |
| | | float: left; |
| | | .searchBtn { |
| | | background-color: var(--el-color-primary); |
| | | color: #fff; |
| | | border-top-left-radius: 0; |
| | | border-bottom-left-radius: 0; |
| | | } |
| | | } |
| | | } |
| | | ::v-deep(.customDialog) { |
| | | border-radius: 5px; |
| | | margin: 10px auto; |
| | | padding-bottom: 20px; |
| | | .pubContent { |
| | | height: 800px; |
| | | } |
| | | } |
| | | .pageBox { |
| | | padding: 10px 0; |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | } |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="classManagePage-box"> |
| | | <div class="classManagePage-nav"> |
| | | <el-breadcrumb :separator-icon="ArrowRight"> |
| | | <el-breadcrumb-item>我的班级</el-breadcrumb-item> |
| | | <el-breadcrumb-item>{{ classInfo?.name }}</el-breadcrumb-item> |
| | | <el-breadcrumb-item>班级管理</el-breadcrumb-item> |
| | | </el-breadcrumb> |
| | | </div> |
| | | <div class="classManagePage-content"> |
| | | <div class="headerBox"> |
| | | <div class="btnBox"> |
| | | <!-- 批量通过按钮 --> |
| | | <el-button |
| | | v-if="multipleSelection.length > 0" |
| | | type="success" |
| | | size="small" |
| | | @click="updateStateNormalDatas" |
| | | >批量通过</el-button |
| | | > |
| | | <!-- 批量移除按钮 --> |
| | | <el-button |
| | | v-if="multipleSelection.length > 0" |
| | | type="danger" |
| | | size="small" |
| | | @click="removeStudentDatas" |
| | | >批量移除</el-button |
| | | > |
| | | <!-- 批量拒绝 --> |
| | | <el-button |
| | | v-if="multipleSelection.length > 0" |
| | | type="warning" |
| | | size="small" |
| | | @click="updateStateRejectDatas" |
| | | >批量拒绝</el-button |
| | | > |
| | | </div> |
| | | <!-- <div class="searchBox"> |
| | | <el-input v-model="searchKey" clearable @clear="searchData()" placeholder="请输入关键字"> |
| | | <template #append> |
| | | <el-button type="primary" @click="searchData()" class="searchBtn" :icon="Search" /> |
| | | </template> |
| | | </el-input> |
| | | </div> --> |
| | | </div> |
| | | <div class="listBox"> |
| | | <el-table |
| | | :header-cell-style="{ background: '#eee' }" |
| | | :data="dataList" |
| | | max-height="600px" |
| | | style="width: 100%" |
| | | v-loading="pages.loading" |
| | | @selection-change="handleSelectionChange" |
| | | > |
| | | <el-table-column type="selection" :selectable="selectable" width="55" /> |
| | | <el-table-column prop="index" label="序号" width="70" /> |
| | | <el-table-column label="姓名" width="400"> |
| | | <template #default="scope"> |
| | | <div class="userBox"> |
| | | <el-avatar |
| | | style="margin-right: 10px" |
| | | v-if="scope.row.appUser.icon" |
| | | :size="35" |
| | | :src="scope.row.appUser.icon" |
| | | /> |
| | | <el-avatar |
| | | style="margin-right: 10px" |
| | | :size="35" |
| | | v-if="!scope.row.appUser.icon" |
| | | :icon="UserFilled" |
| | | /> |
| | | <span v-if="scope.row.appUser.name">{{ scope.row.appUser.name }}</span> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="createDate" label="加入班级时间" /> |
| | | <el-table-column label="状态"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.state == 'WaitValid'" style="color: #ef9f29"> 审核中 </span> |
| | | <span v-if="scope.row.state == 'Normal'" style="color: #1dbd11"> 已通过 </span> |
| | | <span v-if="scope.row.state == 'Reject'" style="color: #fc425d"> 未通过 </span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="班级成员身份"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.linkType == 'RefCode'"> 学生 </span> |
| | | <span v-if="scope.row.linkType == 'Teacher'"> 助教 </span> |
| | | <span v-if="scope.row.linkType == 'Creator'"> 创建人 </span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="200"> |
| | | <template #default="scope"> |
| | | <el-button |
| | | link |
| | | v-if="scope.row.linkType != 'Creator' && scope.row.state == 'Normal'" |
| | | type="danger" |
| | | size="small" |
| | | @click="removeStudent(scope.row)" |
| | | > |
| | | 移除 |
| | | </el-button> |
| | | <el-button link v-if="scope.row.linkType == 'Creator'" type="info" size="small"> |
| | | --- |
| | | </el-button> |
| | | <el-button |
| | | link |
| | | v-if="scope.row.state != 'Normal'" |
| | | type="success" |
| | | size="small" |
| | | @click="selectIdentity(scope.row)" |
| | | > |
| | | 通过 |
| | | </el-button> |
| | | <el-button |
| | | link |
| | | v-if="scope.row.state != 'Normal' && scope.row.state != 'Reject'" |
| | | type="warning" |
| | | size="small" |
| | | @click="updateStateReject(scope.row)" |
| | | > |
| | | 拒绝 |
| | | </el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <el-pagination |
| | | style="float: right" |
| | | v-model:current-page="pages.page" |
| | | :page-size="pages.pageSize" |
| | | layout="total, prev, pager, next" |
| | | :total="pages.count" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" |
| | | /> |
| | | <el-dialog v-model="visible" title="选择当前成员身份" width="500" align-center> |
| | | <el-radio-group v-model="currentLinkType"> |
| | | <el-radio label="RefCode" size="large" border>学生</el-radio> |
| | | <el-radio label="Teacher" size="large" border>助教</el-radio> |
| | | </el-radio-group> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button @click="cancleLinkType"> 取消 </el-button> |
| | | <el-button type="primary" @click="updateStateNormal"> 确认 </el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <el-dialog v-model="visibleReject" title="拒绝原因" width="500" align-center> |
| | | <div class="reasonStr"> |
| | | <span style="width: 100px">拒绝原因:</span> |
| | | <el-input type="textarea" :rows="2" maxlength="100" v-model="reasonStr"></el-input> |
| | | </div> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button @click="cancleReject"> 取消 </el-button> |
| | | <el-button type="primary" @click="updateStateReject"> 确认 </el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { reactive, ref, onMounted, inject, watch } from 'vue' |
| | | import type { TableInstance } from 'element-plus' |
| | | import { useRoute } from 'vue-router' |
| | | import { Search, ArrowRight, UserFilled } from '@element-plus/icons-vue' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import { getPublicImage } from '@/assets/js/middleGround/tool.js' |
| | | import moment from 'moment' |
| | | |
| | | const route: any = useRoute() |
| | | const MG: any = inject('MG') |
| | | const classInfo = JSON.parse(route.query.classInfo) |
| | | |
| | | const searchKey = ref('') |
| | | const reasonStr = ref('') |
| | | const dataList = ref([]) |
| | | const visible = ref(false) |
| | | const currentIdentity = ref() |
| | | const currentLinkType = ref('RefCode') |
| | | const visibleReject = ref(false) |
| | | const rejectData: any = ref() |
| | | let pages = reactive({ |
| | | page: 1, |
| | | pageSize: 10, |
| | | count: 0, |
| | | loading: false |
| | | }) |
| | | |
| | | const multipleSelection = ref<any[]>([]) |
| | | |
| | | const selectable = (row: any) => ![1].includes(row.index) |
| | | |
| | | onMounted(() => { |
| | | getStudentList() |
| | | }) |
| | | |
| | | const handleSelectionChange = (val: any) => { |
| | | multipleSelection.value = val |
| | | } |
| | | |
| | | const handleSizeChange = (val: number) => { |
| | | pages.pageSize = val |
| | | getStudentList() |
| | | } |
| | | |
| | | const handleCurrentChange = (val: number) => { |
| | | pages.page = val |
| | | getStudentList() |
| | | } |
| | | |
| | | const searchData = () => { |
| | | pages.page = 1 |
| | | pages.pageSize = 10 |
| | | getStudentList() |
| | | } |
| | | |
| | | // 获取学生列表 |
| | | const getStudentList = () => { |
| | | pages.loading = true |
| | | const data = { |
| | | start: (pages.page - 1) * pages.pageSize, |
| | | size: pages.pageSize, |
| | | groupId: classInfo.id |
| | | } |
| | | MG.identity.getGroupUserList(data).then((res: any) => { |
| | | const { datas } = res |
| | | pages.loading = false |
| | | if (datas.length > 0) { |
| | | dataList.value = datas.map((item: any, index: number) => { |
| | | if (item.linkType == 'Creator') { |
| | | const userInfo = item.appUser?.infoList?.find((citem: any) => citem.type == 'teacherInfo') |
| | | item.appUser.name = userInfo.name |
| | | item.appUser.icon = userInfo.icon |
| | | if (userInfo?.data) { |
| | | const iconData = JSON.parse(userInfo.data) |
| | | item.appUser.icon = getPublicImage(iconData?.relevantCertificates[0]?.md5, 100) ?? '' |
| | | } |
| | | } |
| | | if (item.linkType == 'RefCode' || item.linkType == 'Teacher') { |
| | | let userInfo = null |
| | | const wechatData = item.appUser?.infoList?.find((citem: any) => citem.type == 'WeChat') |
| | | const defaultData = item.appUser?.infoList?.find((citem: any) => citem.type == 'Default') |
| | | userInfo = defaultData |
| | | if (wechatData?.name) { |
| | | userInfo = wechatData |
| | | } |
| | | item.appUser.name = userInfo.name |
| | | item.appUser.icon = userInfo.icon |
| | | } |
| | | return { |
| | | ...item, |
| | | index: index + 1, |
| | | createDate: moment(item.createDate).format('YYYY-MM-DD') |
| | | } |
| | | }) |
| | | pages.count = dataList.value.length |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 移除学生 |
| | | const removeStudent = (item: any) => { |
| | | ElMessageBox.confirm('是否移除选中成员?') |
| | | .then(() => { |
| | | const data = { |
| | | groupId: classInfo.id, |
| | | appUserIds: [item.appUser.id] |
| | | } |
| | | MG.identity.removeAppUserFromGroup(data).then((res: any) => { |
| | | if (res) { |
| | | ElMessage({ |
| | | message: '已移除', |
| | | type: 'success' |
| | | }) |
| | | getStudentList() |
| | | } |
| | | }) |
| | | }) |
| | | .catch(() => { |
| | | // catch error |
| | | }) |
| | | } |
| | | |
| | | // 批量移除学生 |
| | | const removeStudentDatas = () => { |
| | | ElMessageBox.confirm('是否批量移除选中成员?') |
| | | .then(() => { |
| | | const data = { |
| | | groupId: classInfo.id, |
| | | appUserIds: multipleSelection.value.map((item) => item.appUser.id) |
| | | } |
| | | MG.identity.removeAppUserFromGroup(data).then((res: any) => { |
| | | if (res) { |
| | | ElMessage({ |
| | | message: '已移除', |
| | | type: 'success' |
| | | }) |
| | | getStudentList() |
| | | } |
| | | }) |
| | | }) |
| | | .catch(() => { |
| | | // catch error |
| | | }) |
| | | } |
| | | |
| | | const selectIdentity = (item: any) => { |
| | | visible.value = true |
| | | currentIdentity.value = item |
| | | } |
| | | |
| | | const cancleLinkType = () => { |
| | | visible.value = false |
| | | currentIdentity.value = null |
| | | currentLinkType.value = 'RefCode' |
| | | } |
| | | |
| | | // 更新状态 |
| | | const updateStateNormal = () => { |
| | | const data = { |
| | | groupId: classInfo.id, |
| | | requests: [ |
| | | { |
| | | linkId: currentIdentity.value.linkId, |
| | | linkType: currentLinkType.value, |
| | | state: 'Normal', |
| | | groupState: 'Normal' |
| | | } |
| | | ] |
| | | } |
| | | MG.identity.updateAppUserGroupLink(data).then((res: any) => { |
| | | if (res) { |
| | | visible.value = false |
| | | ElMessage({ |
| | | message: '已通过', |
| | | type: 'success' |
| | | }) |
| | | getStudentList() |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 批量通过 |
| | | const updateStateNormalDatas = () => { |
| | | const data = { |
| | | groupId: classInfo.id, |
| | | requests: multipleSelection.value.map((item) => { |
| | | return { |
| | | linkId: item.linkId, |
| | | linkType: item.linkType, |
| | | state: 'Normal', |
| | | groupState: 'Normal' |
| | | } |
| | | }) |
| | | } |
| | | MG.identity.updateAppUserGroupLink(data).then((res: any) => { |
| | | if (res) { |
| | | ElMessage({ |
| | | message: '已通过', |
| | | type: 'success' |
| | | }) |
| | | getStudentList() |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 批量拒绝 |
| | | const updateStateRejectDatas = () => { |
| | | const data = { |
| | | groupId: classInfo.id, |
| | | requests:multipleSelection.value.map((item) => { |
| | | return { |
| | | linkId: item.linkId, |
| | | linkType: item.linkType, |
| | | state: 'Reject', |
| | | groupState: 'Reject' |
| | | } |
| | | }) |
| | | } |
| | | MG.identity.updateAppUserGroupLink(data).then((res:any) => { |
| | | if (res) { |
| | | ElMessage({ |
| | | message: '已拒绝', |
| | | type: 'success' |
| | | }) |
| | | getStudentList() |
| | | } |
| | | }) |
| | | } |
| | | |
| | | const rejectInfo = (item: any) => { |
| | | visibleReject.value = true |
| | | rejectData.value = item |
| | | } |
| | | |
| | | const cancleReject = () => { |
| | | visibleReject.value = false |
| | | reasonStr.value = '' |
| | | } |
| | | |
| | | // 更新状态 拒绝 |
| | | const updateStateReject = (item:any) => { |
| | | const data = { |
| | | groupId: classInfo.id, |
| | | requests: [ |
| | | { |
| | | linkId: item.linkId, |
| | | linkType: item.linkType, |
| | | state: 'Reject', |
| | | groupState: 'Reject' |
| | | } |
| | | ] |
| | | } |
| | | MG.identity.updateAppUserGroupLink(data).then((res: any) => { |
| | | if (res) { |
| | | ElMessage({ |
| | | message: '已拒绝', |
| | | type: 'warning' |
| | | }) |
| | | cancleReject() |
| | | getStudentList() |
| | | } |
| | | }) |
| | | } |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .classManagePage-box { |
| | | padding: 20px; |
| | | .classManagePage-nav { |
| | | padding-bottom: 20px; |
| | | border-bottom: 1px solid #e6e8ed; |
| | | } |
| | | .classManagePage-content { |
| | | .headerBox { |
| | | height: 50px; |
| | | line-height: 50px; |
| | | overflow: hidden; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | .btnBox { |
| | | flex: 1; |
| | | } |
| | | .searchBox { |
| | | width: 300px; |
| | | float: right; |
| | | .searchBtn { |
| | | background-color: var(--el-color-primary); |
| | | color: #fff; |
| | | border-top-left-radius: 0; |
| | | border-bottom-left-radius: 0; |
| | | } |
| | | } |
| | | } |
| | | .listBox { |
| | | .el-radio.is-bordered.el-radio--large { |
| | | padding: 0px 100px 0 11px; |
| | | } |
| | | .userBox { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | } |
| | | } |
| | | .reasonStr { |
| | | display: flex; |
| | | justify-content: flex-start; |
| | | align-items: center; |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="classManagePage-box"> |
| | | <div class="classManagePage-nav"> |
| | | <el-breadcrumb :separator-icon="ArrowRight"> |
| | | <el-breadcrumb-item>我的班级</el-breadcrumb-item> |
| | | <el-breadcrumb-item>{{ classInfo?.name }}</el-breadcrumb-item> |
| | | <el-breadcrumb-item>话题详情</el-breadcrumb-item> |
| | | </el-breadcrumb> |
| | | </div> |
| | | <div class="classManagePage-content"> |
| | | <div class="backBtn"> |
| | | <el-button @click="goBack()" type="primary" link> |
| | | <el-icon style="margin-right: 5px"><ArrowLeftBold /></el-icon> 返回 |
| | | </el-button> |
| | | </div> |
| | | <div class="talkBox"> |
| | | <div class="leftBox"> |
| | | <div class="MessageCount">{{ dataList.length }} 条回复</div> |
| | | <div class="inputBox"> |
| | | <el-input v-model="textarea" :rows="8" type="textarea" placeholder="请输入" /> |
| | | <el-button |
| | | class="submit" |
| | | :type="textarea.length > 0 ? 'primary' : 'info'" |
| | | :disabled="textarea.length == 0" |
| | | round |
| | | @click="submitText('1')" |
| | | > |
| | | 回 复 |
| | | </el-button> |
| | | </div> |
| | | <div v-if="dataList.length > 0 && !childLoading"> |
| | | <div class="MessageBox" v-for="(item, index) in dataList" :key="index"> |
| | | <div class="MessageHeader"> |
| | | <div class="userBox"> |
| | | <el-avatar |
| | | :src=" |
| | | item.publicText?.icon ?? |
| | | 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png' |
| | | " |
| | | /> |
| | | <el-text class="userName mx-1">{{ item.publicText?.publisher }}</el-text> |
| | | <el-text class="mx-1">{{ item.createDate }}</el-text> |
| | | </div> |
| | | <div class="options"> |
| | | <!-- <el-button type="primary" link @click="openSubmit()"> 回复 </el-button> --> |
| | | <!-- <el-button |
| | | type="success" |
| | | link |
| | | @click="pubTalk(item)" |
| | | v-if="userInfo.role == 'Teacher' && item.state == 'WaitAudit'" |
| | | > |
| | | 发布 |
| | | </el-button> --> |
| | | <el-button |
| | | type="danger" |
| | | v-if="userInfo.role == 'Teacher'" |
| | | link |
| | | @click="removeMessageItem(item)" |
| | | > |
| | | 删除 |
| | | </el-button> |
| | | </div> |
| | | <!-- <el-dialog v-model="dialogVisible" title="回复话题" width="800"> |
| | | <div class="talkWall"> |
| | | <div class="talKBox"> |
| | | <el-input |
| | | style="flex: 1" |
| | | v-model="talkContent" |
| | | :autosize="{ minRows: 10, maxRows: 15 }" |
| | | type="textarea" |
| | | placeholder="请输入内容" |
| | | /> |
| | | </div> |
| | | </div> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button @click="dialogVisible = false"> 取消 </el-button> |
| | | <el-button type="primary" @click="submitText('2')"> 回复 </el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> --> |
| | | </div> |
| | | <div class="MessageContent" v-html="item.publicText?.content"></div> |
| | | </div> |
| | | </div> |
| | | <div v-if="childLoading" v-loading="childLoading" style="height: 100px"></div> |
| | | </div> |
| | | <div class="rightBox" v-if="ownData && !isLoading"> |
| | | <div class="talkHeader"> |
| | | <div class="talkUser"> |
| | | <el-avatar |
| | | src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png" |
| | | /> |
| | | <el-text class="userName mx-1">{{ ownData?.publicText?.publisher }}</el-text> |
| | | </div> |
| | | <el-text class="mx-1">{{ ownData?.updateDate }}</el-text> |
| | | </div> |
| | | <div class="talkContent"> |
| | | <div class="contentTilte">{{ ownData?.name }}</div> |
| | | <div |
| | | v-if="ownData?.publicText" |
| | | class="contentText" |
| | | v-html="ownData?.publicText?.content" |
| | | ></div> |
| | | <div v-else class="contentText" v-html="ownData?.content"></div> |
| | | </div> |
| | | </div> |
| | | <div class="rightBox" v-if="isLoading" v-loading="isLoading"></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { useRoute, useRouter } from 'vue-router' |
| | | import { ArrowRight } from '@element-plus/icons-vue' |
| | | import { inject, onMounted, ref } from 'vue' |
| | | import moment from 'moment' |
| | | import { ElMessage } from 'element-plus' |
| | | import { getPublicImage } from '@/assets/js/middleGround/tool.js' |
| | | |
| | | const route: any = useRoute() |
| | | const router = useRouter() |
| | | const classInfo = JSON.parse(route.query.classInfo) |
| | | const userInfo = ref() |
| | | const textarea = ref('') |
| | | const talkContent = ref('') |
| | | const dialogVisible = ref(false) |
| | | const MG: any = inject('MG') |
| | | const config: any = inject('config') |
| | | const talkTopicInfo = ref() |
| | | const dataList: any = ref([]) |
| | | const ownData = ref() |
| | | const isLoading = ref(false) |
| | | const childLoading = ref(false) |
| | | |
| | | onMounted(() => { |
| | | const userCache: any = localStorage.getItem('jesk-userInfo') |
| | | if (userCache) { |
| | | userInfo.value = JSON.parse(userCache) |
| | | } |
| | | getTopicInfo() |
| | | }) |
| | | |
| | | const openSubmit = () => { |
| | | talkContent.value = '' |
| | | dialogVisible.value = true |
| | | } |
| | | |
| | | const submitText = (val: string) => { |
| | | const userCache: any = localStorage.getItem('jesk-userInfo') |
| | | const userInfo = JSON.parse(userCache) |
| | | if (userInfo?.data) { |
| | | const iconData = JSON.parse(userInfo.data) |
| | | userInfo.icon = iconData?.relevantCertificates[0]?.md5 ?? '' |
| | | } |
| | | const textObj = { |
| | | content: val == '1' ? textarea.value : talkContent.value, |
| | | publisher: userInfo?.name ?? '', |
| | | publishRole: userInfo?.role ?? '', |
| | | icon: userInfo.icon ?? '', |
| | | type: userInfo.type ?? '' |
| | | } |
| | | const data = { |
| | | description: '', |
| | | icon: '', |
| | | state: 'Normal', |
| | | parentId: ownData?.value.id, |
| | | topicIdOrRefCode: String(talkTopicInfo.value.id), |
| | | name: userInfo?.name, |
| | | content: JSON.stringify(textObj), |
| | | type: 'Normal', |
| | | cmsTypeRefCode: '', |
| | | newDataListRequest: [] |
| | | } |
| | | MG.ugc.newTopicMessage(data).then((res: any) => { |
| | | if (res) { |
| | | ElMessage({ |
| | | message: '已回复', |
| | | type: 'success' |
| | | }) |
| | | dialogVisible.value = false |
| | | textarea.value = '' |
| | | getMessageChildren() |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 获取话题topic |
| | | const getTopicInfo = () => { |
| | | const pramas = { |
| | | classId: classInfo.id, |
| | | refCodes: [config.refCodes.talk] |
| | | } |
| | | MG.edu.getClassTopic(pramas).then((res: any) => { |
| | | const list = res |
| | | talkTopicInfo.value = list.find((item: any) => item.refCode == config.refCodes.talk) |
| | | if (talkTopicInfo.value.id) { |
| | | getMessage() |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 获取当前话题 |
| | | const getMessage = () => { |
| | | isLoading.value = true |
| | | const data = { |
| | | start: 0, |
| | | size: 1, |
| | | searchList: [ |
| | | { |
| | | keywords: classInfo.MessageName, |
| | | field: 'Name', |
| | | compareType: 'Contains' |
| | | } |
| | | ], |
| | | appRefCode: config.appRefCode, |
| | | topicIdOrRefCode: String(talkTopicInfo.value.id) |
| | | } |
| | | MG.ugc.getTopicMessageList(data).then((res: any) => { |
| | | const list = res.datas |
| | | isLoading.value = false |
| | | list.map((item: any) => { |
| | | const str = item.content.indexOf('publisher') |
| | | if (str > -1) { |
| | | item.publicText = JSON.parse(item.content) |
| | | if (item.publicText && item.publicText.publishRole) { |
| | | item.publicText.publishRole = item.publicText.publishRole == 'Teacher' ? '助教' : '学生' |
| | | } |
| | | } |
| | | item.createDate = moment(item.createDate).format('YYYY-MM-DD HH:mm:ss') |
| | | item.updateDate = moment(item.updateDate).format('YYYY-MM-DD HH:mm:ss') |
| | | return { |
| | | ...item |
| | | } |
| | | }) |
| | | ownData.value = list[0] |
| | | getMessageChildren() |
| | | }) |
| | | } |
| | | |
| | | // 获取当前话题的回复消息 |
| | | const getMessageChildren = () => { |
| | | childLoading.value = true |
| | | const data = { |
| | | start: 0, |
| | | size: 999, |
| | | parentId: ownData?.value.id, |
| | | topicIdOrRefCode: String(talkTopicInfo.value.id) |
| | | } |
| | | MG.ugc.getTopicMessageSubList(data).then((res: any) => { |
| | | const list = res.datas |
| | | childLoading.value = false |
| | | dataList.value = list.map((item: any) => { |
| | | const str = item.content.indexOf('publisher') |
| | | if (str > -1) { |
| | | item.publicText = JSON.parse(item.content) |
| | | if (item.publicText && item.publicText.publishRole) { |
| | | item.publicText.publishRole = item.publicText.publishRole == 'Teacher' ? '助教' : '学生' |
| | | } |
| | | if (item.publicText?.icon && item.publicText?.type == 'teacherInfo') { |
| | | item.publicText.icon = getPublicImage(item.publicText?.icon, 60) |
| | | } |
| | | } |
| | | item.createDate = moment(item.createDate).format('YYYY-MM-DD HH:mm:ss') |
| | | item.updateDate = moment(item.updateDate).format('YYYY-MM-DD HH:mm:ss') |
| | | return { |
| | | ...item |
| | | } |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | // 删除回复话题 |
| | | const removeMessageItem = (item: any) => { |
| | | const data = { |
| | | messageIds: [item.id] |
| | | } |
| | | MG.ugc.delTopicMessage(data).then((res: any) => { |
| | | if (res) { |
| | | ElMessage({ |
| | | message: '已删除', |
| | | type: 'success' |
| | | }) |
| | | } |
| | | getMessage() |
| | | }) |
| | | } |
| | | |
| | | // 审核话题 |
| | | const pubTalk = (item: any) => { |
| | | const data = { |
| | | id: item.id, |
| | | name: item.name, |
| | | description: item.description, |
| | | icon: item.icon, |
| | | type: item.type, |
| | | state: 'Normal', |
| | | content: JSON.stringify(item.publicText), |
| | | newDataRequests: [], |
| | | updateDataRequests: [] |
| | | } |
| | | MG.ugc |
| | | .updateTopicMessage(data) |
| | | .then((res: any) => { |
| | | if (res) { |
| | | ElMessage({ |
| | | type: 'success', |
| | | message: '已发布' |
| | | }) |
| | | getMessage() |
| | | } |
| | | }) |
| | | .catch((err: any) => { |
| | | console.log(err, '审核话题') |
| | | }) |
| | | } |
| | | |
| | | const goBack = () => { |
| | | router.go(-1) |
| | | } |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .classManagePage-box { |
| | | // padding: 20px 0; |
| | | background: #fff; |
| | | |
| | | .classManagePage-nav { |
| | | width: 100%; |
| | | padding: 0 20px; |
| | | height: 40px; |
| | | border-bottom: 1px solid #e6e8ed; |
| | | position: sticky; |
| | | top: 0; |
| | | z-index: 999; |
| | | display: flex; |
| | | align-items: center; |
| | | background: #fff; |
| | | } |
| | | .classManagePage-content { |
| | | width: 100%; |
| | | position: relative; |
| | | .backBtn { |
| | | width: 100%; |
| | | height: 45px; |
| | | margin-bottom: 10px; |
| | | padding: 0 20px; |
| | | display: flex; |
| | | align-items: center; |
| | | position: sticky; |
| | | top: 40px; |
| | | z-index: 99; |
| | | background: #fff; |
| | | box-shadow: 0px 0px 20px 1px #eee; |
| | | } |
| | | .talkBox { |
| | | width: 100%; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: flex-start; |
| | | padding: 0 20px; |
| | | .leftBox { |
| | | flex: 1; |
| | | min-width: 500px; |
| | | min-height: 700px; |
| | | background: #ffffff; |
| | | box-shadow: 0px 0px 10px 1px rgba(0, 0, 0, 0.08); |
| | | border-radius: 5px 5px 5px 5px; |
| | | border: 1px solid #e7eaec; |
| | | margin-right: 20px; |
| | | .MessageCount { |
| | | padding: 0 30px; |
| | | width: 100%; |
| | | height: 60px; |
| | | border-bottom: 1px solid #e7eaec; |
| | | line-height: 60px; |
| | | } |
| | | :deep(.inputBox) { |
| | | padding: 20px 30px; |
| | | position: relative; |
| | | |
| | | .el-textarea__inner { |
| | | padding: 15px; |
| | | padding-bottom: 45px; |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | .submit { |
| | | position: absolute; |
| | | bottom: 30px; |
| | | right: 40px; |
| | | } |
| | | } |
| | | .MessageBox { |
| | | width: 100%; |
| | | padding: 0 30px; |
| | | .MessageHeader { |
| | | width: 100%; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | .userBox { |
| | | display: flex; |
| | | align-items: center; |
| | | .userName { |
| | | margin: 0 20px; |
| | | } |
| | | } |
| | | } |
| | | .MessageContent { |
| | | padding: 0 60px; |
| | | padding-bottom: 20px; |
| | | margin-bottom: 10px; |
| | | font-family: PingFang SC; |
| | | font-weight: 400; |
| | | font-size: 13px; |
| | | color: #333333; |
| | | line-height: 25px; |
| | | border-bottom: 1px solid #e7eaec; |
| | | } |
| | | } |
| | | } |
| | | .rightBox { |
| | | width: 650px; |
| | | min-width: 500px; |
| | | height: 650px; |
| | | background: #ffffff; |
| | | box-shadow: 0px 0px 10px 1px rgba(0, 0, 0, 0.08); |
| | | border-radius: 5px 5px 5px 5px; |
| | | border: 1px solid #e7eaec; |
| | | position: sticky; |
| | | top: 95px; |
| | | z-index: 99; |
| | | background: #fff; |
| | | .talkHeader { |
| | | width: 100%; |
| | | padding: 0 30px; |
| | | height: 60px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | border-bottom: 1px solid #e7eaec; |
| | | |
| | | .talkUser { |
| | | display: flex; |
| | | align-items: center; |
| | | .userName { |
| | | margin-left: 20px; |
| | | } |
| | | } |
| | | } |
| | | .talkContent { |
| | | width: 100%; |
| | | height: calc(100% - 60px); |
| | | overflow: auto; |
| | | |
| | | padding: 20px 30px; |
| | | .contentTilte { |
| | | font-family: PingFang SC; |
| | | font-weight: bold; |
| | | font-size: 16px; |
| | | color: #333333; |
| | | margin-bottom: 20px; |
| | | } |
| | | .contentText { |
| | | font-family: PingFang SC; |
| | | font-weight: 400; |
| | | font-size: 13px; |
| | | color: #333333; |
| | | line-height: 30px; |
| | | text-align: left; |
| | | word-break: break-all; |
| | | word-wrap: break-word; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="classManagePage-box"> |
| | | <div class="classManagePage-nav"> |
| | | <el-breadcrumb :separator-icon="ArrowRight"> |
| | | <el-breadcrumb-item>我的班级</el-breadcrumb-item> |
| | | <el-breadcrumb-item>{{ classInfo?.name }}</el-breadcrumb-item> |
| | | <el-breadcrumb-item>话题</el-breadcrumb-item> |
| | | </el-breadcrumb> |
| | | </div> |
| | | <div class="classManagePage-content"> |
| | | <div class="headerBox"> |
| | | <div class="searchBox"> |
| | | <el-input |
| | | v-model="searchKey" |
| | | @clear="searchData()" |
| | | @keydown.enter="searchData()" |
| | | clearable |
| | | placeholder="搜索话题名称" |
| | | > |
| | | <template #append> |
| | | <el-button type="primary" class="searchBtn" @click="searchData()" :icon="Search" /> |
| | | </template> |
| | | </el-input> |
| | | </div> |
| | | <el-button @click="openTalk()" v-if="userInfo?.role == 'Teacher'" type="primary" round> |
| | | 新建 <el-icon><Plus /></el-icon> |
| | | </el-button> |
| | | </div> |
| | | <div class="listBox"> |
| | | <el-table |
| | | :header-cell-style="{ background: '#eee' }" |
| | | :data="dataList" |
| | | border |
| | | v-loading="isLoading" |
| | | style="width: 100%" |
| | | > |
| | | <el-table-column prop="index" label="序号" width="70" /> |
| | | <el-table-column label="话题名称" width="500"> |
| | | <template #default="scope"> |
| | | <span style="color: #ff6c00" v-if="scope.row.name">{{ scope.row.name }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="createDate" label="发起日期" /> |
| | | <el-table-column label="发起人"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.publicText">{{ scope.row.publicText.publisher }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="发起人角色"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.publicText?.publishRole == 'Teacher'">助教</span> |
| | | <span v-else>学生</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="updateDate" label="发起人最后回复日期" /> |
| | | <el-table-column label="操作" width="180px"> |
| | | <template #default="scope"> |
| | | <el-button |
| | | link |
| | | type="primary" |
| | | v-if="scope.row.state == 'Normal'" |
| | | @click="toDetail(scope.row)" |
| | | >详情</el-button |
| | | > |
| | | <el-button |
| | | link |
| | | type="success" |
| | | v-if="scope.row.state != 'Normal'" |
| | | @click="pubTalk(scope.row)" |
| | | >发布</el-button |
| | | > |
| | | <el-button |
| | | link |
| | | type="danger" |
| | | v-if="userInfo.role == 'Teacher'" |
| | | @click="delMessageItem(scope.row)" |
| | | >删除</el-button |
| | | > |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <el-pagination |
| | | style="float: right" |
| | | v-model:current-page="pages.page" |
| | | :page-size="pages.pageSize" |
| | | layout="total, prev, pager, next" |
| | | :total="pages.count" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" |
| | | /> |
| | | </div> |
| | | <el-dialog v-model="dialogVisible" title="新建话题" width="800"> |
| | | <div class="talkWall"> |
| | | <div class="talKBox"> |
| | | <span>话题标题:</span> |
| | | <el-input v-model="talkTitle" style="width: 440px" placeholder="请输入标题" /> |
| | | </div> |
| | | <div class="talKBox"> |
| | | <span>话题内容:</span> |
| | | <el-input |
| | | style="flex: 1" |
| | | v-model="talkContent" |
| | | :autosize="{ minRows: 10, maxRows: 15 }" |
| | | type="textarea" |
| | | placeholder="请输入内容" |
| | | /> |
| | | </div> |
| | | </div> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button @click="dialogVisible = false"> 取消 </el-button> |
| | | <el-button type="primary" @click="createMessage()"> 确认 </el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { reactive, ref, onMounted, inject, watch } from 'vue' |
| | | import { useRoute, useRouter } from 'vue-router' |
| | | import { Search, ArrowRight } from '@element-plus/icons-vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import moment from 'moment' |
| | | const route: any = useRoute() |
| | | const router = useRouter() |
| | | const MG: any = inject('MG') |
| | | const config: any = inject('config') |
| | | const classInfo = JSON.parse(route.query.classInfo) |
| | | const userInfo = ref() |
| | | |
| | | const searchKey = ref('') |
| | | const talkTitle = ref('') |
| | | const talkContent = ref('') |
| | | const dialogVisible = ref(false) |
| | | const talkTopicInfo = ref() |
| | | const dataList = ref([]) |
| | | const isLoading = ref(false) |
| | | let pages = reactive({ |
| | | page: 1, |
| | | pageSize: 10, |
| | | count: 0, |
| | | loading: false |
| | | }) |
| | | |
| | | onMounted(() => { |
| | | const userCache: any = localStorage.getItem('jesk-userInfo') |
| | | if (userCache) { |
| | | userInfo.value = JSON.parse(userCache) |
| | | } |
| | | getTopicInfo() |
| | | }) |
| | | |
| | | const handleSizeChange = (val: number) => { |
| | | pages.pageSize = val |
| | | getMessage() |
| | | } |
| | | |
| | | const handleCurrentChange = (val: number) => { |
| | | pages.page = val |
| | | getMessage() |
| | | } |
| | | |
| | | const searchData = () => { |
| | | pages.page = 1 |
| | | pages.pageSize = 10 |
| | | getMessage() |
| | | } |
| | | |
| | | // 获取话题topic |
| | | const getTopicInfo = () => { |
| | | const pramas = { |
| | | classId: classInfo.id, |
| | | refCodes: [config.refCodes.talk] |
| | | } |
| | | MG.edu.getClassTopic(pramas).then((res: any) => { |
| | | const list = res |
| | | talkTopicInfo.value = list.find((item: any) => item.refCode == config.refCodes.talk) |
| | | if (talkTopicInfo.value.id) { |
| | | getMessage() |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 新建话题 |
| | | const createMessage = () => { |
| | | if (talkTitle.value == '') { |
| | | ElMessage({ |
| | | message: '请填写标题', |
| | | type: 'warning' |
| | | }) |
| | | return false |
| | | } |
| | | if (talkContent.value == '') { |
| | | ElMessage({ |
| | | message: '请填写内容', |
| | | type: 'warning' |
| | | }) |
| | | return false |
| | | } |
| | | newTalkMessage() |
| | | } |
| | | |
| | | // 话题详情 |
| | | const toDetail = (item: any) => { |
| | | const obj = classInfo |
| | | obj.MessageName = item.name |
| | | router.push({ |
| | | path: '/talkDetail', |
| | | query: { |
| | | classInfo: JSON.stringify(obj) |
| | | } |
| | | }) |
| | | } |
| | | |
| | | const newTalkMessage = () => { |
| | | const userCache: any = localStorage.getItem('jesk-userInfo') |
| | | const userInfo = JSON.parse(userCache) |
| | | const textObj = { |
| | | content: talkContent.value, |
| | | publisher: userInfo?.name ?? '', |
| | | publishRole: userInfo?.role ?? '', |
| | | icon: userInfo.icon ?? '' |
| | | } |
| | | const data = { |
| | | description: '', |
| | | icon: '', |
| | | state: 'Normal', |
| | | topicIdOrRefCode: String(talkTopicInfo.value.id), |
| | | name: talkTitle.value, |
| | | content: JSON.stringify(textObj), |
| | | type: 'Normal', |
| | | cmsTypeRefCode: '', |
| | | newDataListRequest: [] |
| | | } |
| | | MG.ugc.newTopicMessage(data).then((res: any) => { |
| | | if (res) { |
| | | dialogVisible.value = false |
| | | getMessage() |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 获取班级话题 |
| | | const getMessage = () => { |
| | | isLoading.value = true |
| | | const data = { |
| | | start: (pages.page - 1) * pages.pageSize, |
| | | size: pages.pageSize, |
| | | appRefCode: config.appRefCode, |
| | | topicIdOrRefCode: String(talkTopicInfo.value.id), |
| | | searchList: searchKey.value |
| | | ? [ |
| | | { |
| | | keywords: searchKey.value, |
| | | field: 'Name', |
| | | compareType: 'Contains' |
| | | } |
| | | ] |
| | | : [] |
| | | } |
| | | MG.ugc.getTopicMessageList(data).then((res: any) => { |
| | | const list = res.datas |
| | | pages.count = res.totalSize |
| | | isLoading.value = false |
| | | dataList.value = list.map((item: any, i: number) => { |
| | | const str = item.content.indexOf('publisher') |
| | | if (str > -1) { |
| | | item.publicText = JSON.parse(item.content) |
| | | } |
| | | return { |
| | | ...item, |
| | | index: i + 1, |
| | | createDate: moment(item.createDate).format('YYYY-MM-DD HH:mm:ss'), |
| | | updateDate: moment(item.updateDate).format('YYYY-MM-DD HH:mm:ss') |
| | | } |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | // 删除话题 |
| | | const delMessageItem = (item: any) => { |
| | | const data = { |
| | | messageIds: [item.id] |
| | | } |
| | | MG.ugc |
| | | .delTopicMessage(data) |
| | | .then((res: any) => { |
| | | if (res) { |
| | | ElMessage.success('已删除') |
| | | getTopicInfo() |
| | | } |
| | | }) |
| | | .catch((err: any) => { |
| | | ElMessage.error('删除失败,请稍后再试') |
| | | console.log(err) |
| | | }) |
| | | } |
| | | |
| | | // 审核话题 |
| | | const pubTalk = (item: any) => { |
| | | const data = { |
| | | id: item.id, |
| | | name: item.name, |
| | | description: item.description, |
| | | icon: item.icon, |
| | | type: item.type, |
| | | state: 'Normal', |
| | | content: JSON.stringify(item.publicText), |
| | | newDataRequests: [], |
| | | updateDataRequests: [] |
| | | } |
| | | MG.ugc |
| | | .updateTopicMessage(data) |
| | | .then((res: any) => { |
| | | if (res) { |
| | | ElMessage({ |
| | | type: 'success', |
| | | message: '已发布' |
| | | }) |
| | | getMessage() |
| | | } |
| | | }) |
| | | .catch((err: any) => { |
| | | console.log(err, '审核话题') |
| | | }) |
| | | } |
| | | |
| | | const openTalk = () => { |
| | | dialogVisible.value = true |
| | | } |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .classManagePage-box { |
| | | padding: 20px; |
| | | .classManagePage-nav { |
| | | padding-bottom: 20px; |
| | | border-bottom: 1px solid #e6e8ed; |
| | | } |
| | | .classManagePage-content { |
| | | .headerBox { |
| | | padding: 20px 0; |
| | | overflow: hidden; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | .searchBox { |
| | | width: 300px; |
| | | float: left; |
| | | .searchBtn { |
| | | background-color: var(--el-color-primary); |
| | | color: #fff; |
| | | border-top-left-radius: 0; |
| | | border-bottom-left-radius: 0; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .headerCellClass { |
| | | background-color: red !important; |
| | | } |
| | | |
| | | .talkWall { |
| | | width: 100%; |
| | | height: auto; |
| | | .talKBox { |
| | | display: flex; |
| | | align-items: baseline; |
| | | margin-bottom: 20px; |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="classManagePage-box"> |
| | | <div class="classManagePage-nav"> |
| | | <el-breadcrumb :separator-icon="ArrowRight"> |
| | | <el-breadcrumb-item>我的班级</el-breadcrumb-item> |
| | | <el-breadcrumb-item>{{ classInfo?.name }}</el-breadcrumb-item> |
| | | <el-breadcrumb-item>教学互动</el-breadcrumb-item> |
| | | </el-breadcrumb> |
| | | </div> |
| | | <div class="classManagePage-content"> |
| | | <div class="teachPlaneBox"> |
| | | <div class="titleBox"> |
| | | <div class="titleOptions"> |
| | | <span>教学互动</span> |
| | | </div> |
| | | <div class="searchBox"> |
| | | <el-input |
| | | v-model="searchKey" |
| | | clearable |
| | | @clear="searchData()" |
| | | placeholder="请输入关键字" |
| | | @keydown.enter="searchData()" |
| | | > |
| | | <template #append> |
| | | <el-button type="primary" @click="searchData()" class="searchBtn" :icon="Search" /> |
| | | </template> |
| | | </el-input> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="listBox"> |
| | | <el-table |
| | | :header-cell-style="{ background: '#eee' }" |
| | | :data="cmsDataList" |
| | | max-height="700px" |
| | | style="width: 100%" |
| | | v-loading="cmsLoading" |
| | | > |
| | | <el-table-column prop="id" label="序号" width="100" /> |
| | | <el-table-column prop="name" label="标题" width="500" /> |
| | | <el-table-column prop="address" label="已互动学生数" #default="scoped"> |
| | | <div> |
| | | <span style="color: #ff6d00">{{ scoped.row.subList.length }}</span> |
| | | </div> |
| | | </el-table-column> |
| | | <el-table-column prop="address" label="最后提交时间" #default="scoped"> |
| | | <span v-if="scoped.row.updateDate"> {{ scoped.row.updateDate }} </span> |
| | | <span v-else> - </span> |
| | | </el-table-column> |
| | | <el-table-column prop="address" label="操作" #default="scoped"> |
| | | <el-button link type="success" @click="toDetail(scoped.row)">查看详情</el-button> |
| | | <el-button link style="color: #409eff" @click="getQuestions(scoped.row)" |
| | | >浏览答题</el-button |
| | | > |
| | | </el-table-column> |
| | | </el-table> |
| | | <!-- 浏览答题 --> |
| | | <el-dialog |
| | | class="customDialog" |
| | | title="浏览答题" |
| | | v-model="visible" |
| | | destroy-on-close |
| | | width="1000" |
| | | align-center |
| | | :before-close="close" |
| | | > |
| | | <div class="pubContent" v-if="dialogList.length > 0 && !dialogLLoading"> |
| | | <div v-for="(item, index) in dialogList" :key="index"> |
| | | <span class="userName">答题人:{{ item.userName ?? '-' }}</span> |
| | | <question-dom |
| | | v-if="item.questionTypeList.length > 0" |
| | | :questionList="item.questionTypeList" |
| | | :noCheckbox="false" |
| | | :is-preview="true" |
| | | :is-interaction="true" |
| | | /> |
| | | </div> |
| | | </div> |
| | | <div class="pubContent" v-if="dialogLLoading" v-loading="dialogLLoading"></div> |
| | | <div class="pubContent noData" v-if="dialogList.length == 0 && !dialogLLoading"> |
| | | <el-empty></el-empty> |
| | | </div> |
| | | <template #footer> |
| | | <div class="selectedFooter" style="padding: 0"> |
| | | <el-button type="primary" @click="visible = false"> 关闭 </el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { Search, ArrowRight } from '@element-plus/icons-vue' |
| | | import moment from 'moment' |
| | | import { ref, onMounted, inject } from 'vue' |
| | | import { useRoute, useRouter } from 'vue-router' |
| | | import questionDom from './components/questionDom.vue' |
| | | |
| | | const route: any = useRoute() |
| | | const router: any = useRouter() |
| | | const MG: any = inject('MG') |
| | | const config: any = inject('config') |
| | | const classInfo = JSON.parse(route.query.classInfo) |
| | | const userInfo = ref() |
| | | |
| | | const teachInteractionInfo: any = ref([]) |
| | | const searchKey = ref('') |
| | | const dataList: any = ref([]) |
| | | const currentClass = ref() |
| | | const cmsDataList: any = ref([]) |
| | | const cmsLoading = ref(true) |
| | | |
| | | const visible = ref(false) |
| | | const dialogList: any = ref([]) |
| | | const dialogLLoading = ref(true) |
| | | const defaultCmsPath = ref('') |
| | | |
| | | onMounted(() => { |
| | | const userCache: any = localStorage.getItem('jesk-userInfo') |
| | | if (userCache) { |
| | | userInfo.value = JSON.parse(userCache) |
| | | } |
| | | defaultCmsPath.value = classInfo.bookRefCode ? 'jsek_digitalTextbooks' : config.goodsStore |
| | | getData() |
| | | }) |
| | | |
| | | const searchData = () => { |
| | | const data = [...cmsDataList.value] |
| | | if (!searchKey.value) { |
| | | getCmsList() |
| | | } else { |
| | | const list = data.filter((item) => item.name.indexOf(searchKey.value) > -1) |
| | | cmsDataList.value = list |
| | | } |
| | | } |
| | | |
| | | const close = () => { |
| | | visible.value = false |
| | | } |
| | | |
| | | // 获取教学互动 |
| | | const getCmsList = () => { |
| | | cmsLoading.value = true |
| | | cmsDataList.value = [] |
| | | try { |
| | | MG.store |
| | | .getProductDetail({ |
| | | path: defaultCmsPath.value, |
| | | queryType: '*', |
| | | productId: classInfo.bookId, |
| | | storeInfo: defaultCmsPath.value, |
| | | cmsPath: classInfo.rootCmsItemId |
| | | }) |
| | | .then((res: any) => { |
| | | try { |
| | | const data = res.datas?.cmsDatas[0]?.datas.find( |
| | | (item: any) => item.refCode == 'questionBank' |
| | | ) |
| | | MG.store |
| | | .getProductDetail({ |
| | | path: defaultCmsPath.value, |
| | | queryType: '*', |
| | | storeInfo: defaultCmsPath.value, |
| | | productId: classInfo.bookId, |
| | | cmsPath: data.productLinkPath |
| | | }) |
| | | .then((res: any) => { |
| | | try { |
| | | const dataTeach = res.datas.cmsDatas[0]?.datas.find( |
| | | (item: any) => item.refCode == 'jsek_interaction' |
| | | ) |
| | | MG.store |
| | | .getProductDetail({ |
| | | path: defaultCmsPath.value, |
| | | queryType: '*', |
| | | productId: classInfo.bookId, |
| | | storeInfo: defaultCmsPath.value, |
| | | cmsPath: dataTeach.productLinkPath |
| | | }) |
| | | .then((res: any) => { |
| | | let datas = res.datas.cmsDatas[0] ? res.datas.cmsDatas[0].datas : [] |
| | | if (datas?.length > 0) { |
| | | datas.forEach((item: any) => { |
| | | MG.store |
| | | .getProductDetail({ |
| | | path: defaultCmsPath.value, |
| | | queryType: '*', |
| | | productId: classInfo.bookId, |
| | | storeInfo: defaultCmsPath.value, |
| | | cmsPath: item.productLinkPath, |
| | | cmsSort: { |
| | | ProductLinkOrder: 'Desc' |
| | | } |
| | | }) |
| | | .then(async (cmsRes: any) => { |
| | | cmsLoading.value = false |
| | | if ( |
| | | cmsRes.datas.cmsDatas[0].datas && |
| | | cmsRes.datas.cmsDatas[0].datas.length > 0 |
| | | ) { |
| | | cmsRes.datas.cmsDatas[0].datas.forEach((item: any) => { |
| | | item.subList = [] |
| | | if (dataList.value.length > 0) { |
| | | dataList.value.forEach((mitem: any) => { |
| | | if (mitem.name == item.name) { |
| | | item.updateDate = moment(dataList.value[0].updateDate).format( |
| | | 'YYYY-MM-DD HH:mm:ss' |
| | | ) |
| | | item.subList.push(mitem) |
| | | } |
| | | }) |
| | | } |
| | | cmsDataList.value.push(item) |
| | | }) |
| | | } |
| | | }) |
| | | }) |
| | | } |
| | | }) |
| | | } catch (error) { |
| | | cmsLoading.value = false |
| | | cmsDataList.value = [] |
| | | } |
| | | }) |
| | | } catch (error) { |
| | | cmsLoading.value = false |
| | | cmsDataList.value = [] |
| | | } |
| | | }) |
| | | } catch (error) { |
| | | cmsLoading.value = false |
| | | cmsDataList.value = [] |
| | | } |
| | | } |
| | | |
| | | // 获取Messsagetopic |
| | | const getTopicInfo = () => { |
| | | const pramas = { |
| | | classId: classInfo.id, |
| | | refCodes: [config.refCodes.teachInteraction] |
| | | } |
| | | MG.edu.getClassTopic(pramas).then((res: any) => { |
| | | const list = res |
| | | teachInteractionInfo.value = list.find( |
| | | (item: any) => item.refCode == config.refCodes.teachInteraction |
| | | ) |
| | | if (teachInteractionInfo.value.id) { |
| | | getMessage() |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 获取当前MessageList |
| | | const getMessage = () => { |
| | | const data = { |
| | | start: 0, |
| | | size: 999, |
| | | appRefCode: config.appRefCode, |
| | | topicIdOrRefCode: String(teachInteractionInfo.value.id), |
| | | sort: { |
| | | type: 'Desc', |
| | | field: 'CreateDate' |
| | | }, |
| | | searchList: searchKey.value |
| | | ? [ |
| | | { |
| | | keywords: searchKey.value, |
| | | field: 'Name', |
| | | compareType: 'Contains' |
| | | } |
| | | ] |
| | | : [] |
| | | } |
| | | MG.ugc.getTopicMessageList(data).then((res: any) => { |
| | | dataList.value = res.datas.map((item: any) => { |
| | | item.question = [] |
| | | item.bookId = null |
| | | item.path = '' |
| | | try { |
| | | const obj = JSON.parse(item.content) |
| | | if (obj.bookId) { |
| | | item.question = obj.content.map((citem: any) => { |
| | | return { |
| | | ...citem, |
| | | updateDate: moment(item.updateDate).format('YYYY-MM-DD HH:mm:ss'), |
| | | userId: item.appUserCreator.userId |
| | | } |
| | | }) |
| | | item.bookId = obj.bookId |
| | | item.path = obj.path |
| | | item.userName = obj.userName |
| | | } |
| | | } catch (error) { |
| | | console.log(item) |
| | | } |
| | | return { |
| | | ...item |
| | | } |
| | | }) |
| | | console.log(dataList.value, 'datal') |
| | | getCmsList() |
| | | }) |
| | | } |
| | | |
| | | // 获取班级 |
| | | const getData = () => { |
| | | MG.edu |
| | | .getCourseClass({ |
| | | ClassIdOrRefCode: String(classInfo.id) |
| | | }) |
| | | .then((res: any) => { |
| | | if (res) { |
| | | currentClass.value = res |
| | | } |
| | | getTopicInfo() |
| | | }) |
| | | } |
| | | |
| | | // 获取题目列表 |
| | | const getQuestions = (pitem: any) => { |
| | | visible.value = true |
| | | dialogLLoading.value = true |
| | | MG.store |
| | | .getProductDetail({ |
| | | path: '*', |
| | | queryType: '*', |
| | | productId: classInfo.bookId, |
| | | cmsPath: pitem.productLinkPath, |
| | | itemFields: { |
| | | Embedded_QuestionBank_AnalysisCon: [], |
| | | Embedded_QuestionBank_Answer: [], |
| | | Embedded_QuestionBank_Difficulty: [], |
| | | Embedded_QuestionBank_KnowledgePoint: [], |
| | | Embedded_QuestionBank_Option: [], |
| | | Embedded_QuestionBank_OptionStyle: [], |
| | | Embedded_QuestionBank_QuestionType: [], |
| | | Embedded_QuestionBank_Score: [], |
| | | Embedded_QuestionBank_Stem: [], |
| | | Embedded_QuestionBank_StemStyle: [] |
| | | } |
| | | }) |
| | | .then((res: any) => { |
| | | try { |
| | | let list = [] |
| | | list = res.datas.cmsDatas[0]?.datas.map((item: any) => { |
| | | try { |
| | | if (item.Embedded_QuestionBank_Stem) { |
| | | item.questionStem = JSON.parse(item.Embedded_QuestionBank_Stem) |
| | | } |
| | | if ( |
| | | item.Embedded_QuestionBank_Option && |
| | | item.Embedded_QuestionBank_Option.indexOf('[') > -1 |
| | | ) { |
| | | item.questionOption = JSON.parse(item.Embedded_QuestionBank_Option) |
| | | } |
| | | if ( |
| | | item.Embedded_QuestionBank_Answer && |
| | | item.Embedded_QuestionBank_Answer.indexOf('[') > -1 |
| | | ) { |
| | | item.Embedded_QuestionBank_Answer = JSON.parse(item.Embedded_QuestionBank_Answer) |
| | | } |
| | | return { |
| | | ...item, |
| | | questionType: item.Embedded_QuestionBank_QuestionType, |
| | | questionAnalysisCon: item.Embedded_QuestionBank_AnalysisCon, |
| | | questionAnswer: item.Embedded_QuestionBank_Answer, |
| | | customAnswer: null, |
| | | updateDate: pitem.updateDate |
| | | } |
| | | } catch (error) { |
| | | console.log(item) |
| | | } |
| | | }) |
| | | dialogList.value = chageData(pitem.subList, list) |
| | | dialogLLoading.value = false |
| | | } catch (error) { |
| | | dialogList.value = [] |
| | | dialogLLoading.value = false |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 处理数据结构 |
| | | const chageData = (arr: any, zrr: any) => { |
| | | // 题库题目类型 |
| | | const questionTypeList = [ |
| | | { name: '单选题', value: 'singleChoice', data: [] }, |
| | | { name: '多选题', value: 'multipleChoice', data: [] }, |
| | | { name: '判断题', value: 'judge', data: [] }, |
| | | { name: '简答题', value: 'shortAnswer', data: [] }, |
| | | { name: '论述题', value: 'discuss', data: [] }, |
| | | { name: '填空题', value: 'completion', data: [] }, |
| | | { name: '连线题', value: 'matching', data: [] }, |
| | | { name: '分类题', value: 'classification', data: [] } |
| | | ] |
| | | for (let i = 0; i < arr.length; i++) { |
| | | const item = arr[i] |
| | | item.questionTypeList = JSON.parse(JSON.stringify(questionTypeList)) |
| | | item.other = [] |
| | | for (let j = 0; j < item.question.length; j++) { |
| | | const ele = item.question[j] |
| | | const data = zrr.find((sitem: any) => sitem.id == ele.cmsItemId) |
| | | const index = findIndexById(zrr, ele.cmsItemId) |
| | | if (index > -1) { |
| | | item.other[index] = { ...data, userAnswer: ele.answer } |
| | | } |
| | | } |
| | | if (item.other.length > 0) { |
| | | item.other.forEach((aitem: any) => { |
| | | const index = findIndexByValue(item.questionTypeList, aitem.questionType) |
| | | if (index > -1) { |
| | | item.questionTypeList[index].data.push(aitem) |
| | | } |
| | | }) |
| | | } |
| | | item.questionTypeList = item.questionTypeList.filter((xitem: any) => xitem.data.length > 0) |
| | | } |
| | | return arr |
| | | } |
| | | |
| | | const findIndexByValue = (res: any, type: string) => { |
| | | for (let i = 0; i < res.length; i++) { |
| | | if (res[i].value == type) { |
| | | return i |
| | | } |
| | | } |
| | | return -1 // 如果未找到,则返回 -1 |
| | | } |
| | | |
| | | const findIndexById = (res: any, id: string) => { |
| | | for (let i = 0; i < res.length; i++) { |
| | | if (res[i].id == id) { |
| | | return i |
| | | } |
| | | } |
| | | return -1 // 如果未找到,则返回 -1 |
| | | } |
| | | |
| | | // 去详情 |
| | | const toDetail = (item: any) => { |
| | | const obj = classInfo |
| | | obj.questionName = item.name |
| | | obj.teachInteractionId = teachInteractionInfo.value.id |
| | | router.push({ |
| | | path: '/interactionDetail', |
| | | query: { |
| | | classInfo: JSON.stringify(obj) |
| | | } |
| | | }) |
| | | } |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .classManagePage-box { |
| | | padding: 20px; |
| | | .classManagePage-nav { |
| | | padding-bottom: 20px; |
| | | border-bottom: 1px solid #e6e8ed; |
| | | margin-bottom: 20px; |
| | | } |
| | | .classManagePage-content { |
| | | width: 100%; |
| | | .teachPlaneBox { |
| | | width: 100%; |
| | | .titleBox { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 20px; |
| | | .titleOptions { |
| | | width: 160px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | span { |
| | | height: 30px; |
| | | font-family: PingFang SC; |
| | | font-weight: bold; |
| | | font-size: 16px; |
| | | color: #333; |
| | | line-height: 30px; |
| | | text-align: left; |
| | | border-left: 6px solid #ff6c00; |
| | | padding-left: 10px; |
| | | } |
| | | } |
| | | .searchBox { |
| | | width: 300px; |
| | | float: left; |
| | | .searchBtn { |
| | | background-color: var(--el-color-primary); |
| | | color: #fff; |
| | | border-top-left-radius: 0; |
| | | border-bottom-left-radius: 0; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .pubContent { |
| | | height: 80vh; |
| | | padding: 10px; |
| | | box-sizing: border-box; |
| | | overflow-y: auto; |
| | | .userName { |
| | | color: #ff6d00; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="classManagePage-box"> |
| | | <div class="classManagePage-nav"> |
| | | <el-breadcrumb :separator-icon="ArrowRight"> |
| | | <el-breadcrumb-item>我的班级</el-breadcrumb-item> |
| | | <el-breadcrumb-item>{{ classInfo?.name }}</el-breadcrumb-item> |
| | | <el-breadcrumb-item>教学计划</el-breadcrumb-item> |
| | | </el-breadcrumb> |
| | | </div> |
| | | <div class="classManagePage-content"> |
| | | <div class="teachPlaneBox"> |
| | | <div class="titleBox"> |
| | | <div class="titleOptions"> |
| | | <span>教学计划</span> |
| | | <el-button v-if="userInfo?.role == 'Teacher'" @click="openPlan()" type="primary" round |
| | | >新建 <el-icon style="margin-left: 3px"><Plus /></el-icon |
| | | ></el-button> |
| | | </div> |
| | | <div class="searchBox"> |
| | | <el-input |
| | | v-model="searchKey" |
| | | clearable |
| | | @clear="searchData()" |
| | | placeholder="请输入关键字" |
| | | @keydown.enter="searchData()" |
| | | > |
| | | <template #append> |
| | | <el-button type="primary" @click="searchData()" class="searchBtn" :icon="Search" /> |
| | | </template> |
| | | </el-input> |
| | | </div> |
| | | </div> |
| | | <div class="listBox"> |
| | | <el-table |
| | | :header-cell-style="{ background: '#eee' }" |
| | | :data="tableData" |
| | | max-height="600px" |
| | | style="width: 100%" |
| | | v-loading="pages.loading" |
| | | > |
| | | <el-table-column label="序号" width="70"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.datas.index">{{ scope.row.datas.index }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="名称" prop="name"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.datas.Name">{{ scope.row.datas.Name }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="学习章节" width="300"> |
| | | <template #default="scope"> |
| | | <div v-if="scope.row.datas.selectChapter?.length > 0"> |
| | | <div |
| | | @click="toRead(item)" |
| | | class="linkTitle" |
| | | v-for="(item, index) in scope.row.datas.selectChapter" |
| | | :key="index" |
| | | > |
| | | {{ item.parentName }} |
| | | </div> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="上传资源"> |
| | | <template #default="scope"> |
| | | <div v-if="scope.row.datas.uploadResources?.length > 0"> |
| | | <span |
| | | @click="downloadRes(item)" |
| | | class="linkTitle" |
| | | v-for="(item, index) in scope.row.datas.uploadResources" |
| | | :key="index" |
| | | > |
| | | {{ item.FileName + '.' + item.Extension }} |
| | | </span> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="参考资料" width="300"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.datas.referenceMaterial">{{ |
| | | scope.row.datas.referenceMaterial |
| | | }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="说明" width="300"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.datas.explain">{{ scope.row.datas.explain }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column v-if="userInfo?.role == 'Teacher'" label="操作" width="150"> |
| | | <template #default="scope"> |
| | | <!-- <el-button |
| | | v-if="scope.row" |
| | | @click="editOpen(scope.row)" |
| | | link |
| | | type="primary" |
| | | size="small" |
| | | > |
| | | 编辑 |
| | | </el-button> --> |
| | | <el-button |
| | | v-if="scope.row" |
| | | @click="removeTaskItem(scope.row)" |
| | | link |
| | | type="danger" |
| | | size="small" |
| | | > |
| | | 移除 |
| | | </el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <el-pagination |
| | | style="float: right" |
| | | v-model:current-page="pages.page" |
| | | :page-size="pages.pageSize" |
| | | layout="total, prev, pager, next" |
| | | :total="pages.count" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" |
| | | /> |
| | | </div> |
| | | </div> |
| | | <el-dialog v-model="visible" destroy-on-close title="新建教学计划" width="1000"> |
| | | <div class="formBox"> |
| | | <el-row> |
| | | <el-col :span="2" class="labelItem"> |
| | | <div class="grid-content ep-bg-purple" /> |
| | | 名称<span style="color: red">*</span> |
| | | </el-col> |
| | | <el-col :span="20"> |
| | | <div class="grid-content ep-bg-purple-light" /> |
| | | <el-input v-model="taskItem.title" placeholder="请填写名称" size="large" clearable /> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="2" class="labelItem"> |
| | | <div class="grid-content ep-bg-purple" /> |
| | | 选择章节<span style="color: red">*</span> |
| | | </el-col> |
| | | <el-col :span="20" style="position: relative" v-if="classInfo?.bookRefCode"> |
| | | <div class="grid-content ep-bg-purple-light" /> |
| | | <div |
| | | :class="dynamicList.length > 1 ? 'selectBox selectMarBot' : 'selectBox'" |
| | | v-for="(item, index) in dynamicList" |
| | | :key="index" |
| | | > |
| | | <el-cascader |
| | | size="large" |
| | | style="width: 620px; margin-right: 10px" |
| | | :options="chapterList" |
| | | clearable |
| | | @change="parentSelect($event, item)" |
| | | > |
| | | <template #default="{ node, data }"> |
| | | <span>{{ data.label }}</span> |
| | | <span v-if="!node.isLeaf"> ({{ data.children.length }}) </span> |
| | | </template> |
| | | </el-cascader> |
| | | </div> |
| | | <div class="btngroup"> |
| | | <el-button type="primary" @click="addGroup" style="height: 40px" :icon="Plus" /> |
| | | <el-button |
| | | type="warning" |
| | | :disabled="dynamicList.length == 1" |
| | | @click="reduceGroup" |
| | | style="height: 40px" |
| | | :icon="Minus" |
| | | /> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="20" style="position: relative" v-else> |
| | | <div class="grid-content ep-bg-purple-light" /> |
| | | <div |
| | | :class="dynamicList.length > 1 ? 'selectBox selectMarBot' : 'selectBox'" |
| | | v-for="(item, index) in dynamicList" |
| | | :key="index" |
| | | > |
| | | <div class="inputBox"> |
| | | <el-input |
| | | type="text" |
| | | placeholder="请输入章" |
| | | style="width: 300px; margin-right: 15px" |
| | | v-model="item.parentVal" |
| | | ></el-input> |
| | | <el-input |
| | | type="text" |
| | | placeholder="请输入节" |
| | | style="width: 300px" |
| | | v-model="item.childVal" |
| | | ></el-input> |
| | | </div> |
| | | <div class="btngroup"> |
| | | <el-button type="primary" @click="addGroup" style="height: 40px" :icon="Plus" /> |
| | | <el-button |
| | | type="warning" |
| | | :disabled="dynamicList.length == 1" |
| | | @click="reduceGroup" |
| | | style="height: 40px" |
| | | :icon="Minus" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="2" class="labelItem"> |
| | | <div class="grid-content ep-bg-purple" /> |
| | | 上传资源<span style="color: red">*</span> |
| | | </el-col> |
| | | <el-col :span="20"> |
| | | <div class="grid-content ep-bg-purple-light" /> |
| | | <!-- <el-upload |
| | | class="upload" |
| | | :http-request="fileUpload" |
| | | :show-file-list="false" |
| | | :action="'#'" |
| | | > |
| | | <el-button type="primary" size="large" |
| | | ><el-icon size="large" style="margin-right: 5px"><DocumentAdd /></el-icon |
| | | >上传</el-button |
| | | > |
| | | </el-upload> --> |
| | | <el-upload class="upload" drag action="#" multiple :http-request="fileUpload"> |
| | | <el-icon class="el-icon--upload"><upload-filled /></el-icon> |
| | | <div class="el-upload__text">拖拽或点击文件上传</div> |
| | | </el-upload> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="2" class="labelItem"> |
| | | <div class="grid-content ep-bg-purple" /> |
| | | 参考资料 |
| | | </el-col> |
| | | <el-col :span="20"> |
| | | <div class="grid-content ep-bg-purple-light" /> |
| | | <el-input |
| | | placeholder="请填写参考资料" |
| | | type="textarea" |
| | | :rows="8" |
| | | size="large" |
| | | clearable |
| | | v-model="taskItem.referenceMaterial" |
| | | /> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="2" class="labelItem"> |
| | | <div class="grid-content ep-bg-purple" /> |
| | | 说明 |
| | | </el-col> |
| | | <el-col :span="20"> |
| | | <div class="grid-content ep-bg-purple-light" /> |
| | | <el-input |
| | | v-model="taskItem.explain" |
| | | placeholder="请填写说明" |
| | | type="textarea" |
| | | :rows="8" |
| | | size="large" |
| | | clearable |
| | | /> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" :loading="newLoading" @click="newTaskCmsItems"> |
| | | 确认 |
| | | </el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { Search, ArrowRight, Plus, Minus } from '@element-plus/icons-vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import { reactive, ref, onMounted, inject, watch } from 'vue' |
| | | import { useRoute } from 'vue-router' |
| | | import axios from 'axios' |
| | | |
| | | const route: any = useRoute() |
| | | const MG: any = inject('MG') |
| | | const config: any = inject('config') |
| | | const tool: any = inject('toolClass') |
| | | const classInfo = JSON.parse(route.query.classInfo) |
| | | const userInfo = ref() |
| | | const searchKey = ref('') |
| | | const visible = ref(false) |
| | | const dynamicList: any = ref([]) |
| | | const tableData: any = ref([]) |
| | | const classItem = ref([]) |
| | | const fileList: any = ref([]) |
| | | const chapterList: any = ref([]) |
| | | const childrenList: any = ref([]) |
| | | const taskData: any = ref() |
| | | // 新建教学计划防抖 |
| | | const newLoading = ref(false) |
| | | const teachPlanvalue = ref('') |
| | | const taskItem = reactive({ |
| | | title: '', |
| | | selectChapter: '', |
| | | referenceMaterial: '', |
| | | explain: '', |
| | | uploadResources: '' |
| | | }) |
| | | let pages = reactive({ |
| | | page: 1, |
| | | pageSize: 13, |
| | | count: 0, |
| | | loading: false |
| | | }) |
| | | |
| | | onMounted(() => { |
| | | const list = [{ key: 1, parentVal: '', childVal: '' }] |
| | | dynamicList.value = list |
| | | const userCache: any = localStorage.getItem('jesk-userInfo') |
| | | if (userCache) { |
| | | userInfo.value = JSON.parse(userCache) |
| | | } |
| | | pages.loading = true |
| | | getTaskList() |
| | | }) |
| | | |
| | | const searchData = () => { |
| | | pages.page = 1 |
| | | getTaskCmsList() |
| | | } |
| | | |
| | | const openPlan = () => { |
| | | visible.value = true |
| | | taskItem.title = '' |
| | | taskItem.selectChapter = '' |
| | | taskItem.referenceMaterial = '' |
| | | taskItem.explain = '' |
| | | taskItem.uploadResources = '' |
| | | dynamicList.value = [{ key: 1, parentVal: '', childVal: '' }] |
| | | fileList.value = [] |
| | | } |
| | | |
| | | const reduceGroup = () => { |
| | | dynamicList.value.pop() |
| | | } |
| | | |
| | | const addGroup = () => { |
| | | const source = dynamicList.value[dynamicList.value.length - 1] |
| | | const obj = { key: source.key++, parentVal: '', childVal: '' } |
| | | dynamicList.value.push(obj) |
| | | } |
| | | |
| | | const handleSizeChange = (val: number) => { |
| | | pages.pageSize = val |
| | | getTaskCmsList() |
| | | } |
| | | |
| | | const handleCurrentChange = (val: number) => { |
| | | pages.page = val |
| | | getTaskCmsList() |
| | | } |
| | | |
| | | // 新建任务 |
| | | const newTask = () => { |
| | | const data = { |
| | | name: classInfo?.name + '教学计划', |
| | | description: '', |
| | | icon: '', |
| | | type: config.taskType.teachingPlan, |
| | | state: 'Normal', |
| | | groupId: classInfo?.id, |
| | | order: 0, |
| | | beginDate: '2024-09-09T03:38:07.167Z', |
| | | endDate: '2024-09-09T03:38:07.167Z', |
| | | duration: 0 |
| | | } |
| | | MG.edu |
| | | .newTask(data) |
| | | .then((res: any) => {}) |
| | | .catch((e: any) => { |
| | | console.log(e) |
| | | }) |
| | | } |
| | | |
| | | // 获取任务列表 |
| | | const getTaskList = () => { |
| | | const data = { |
| | | start: 0, |
| | | size: 10, |
| | | filterList: [ |
| | | { |
| | | value: config.taskType.teachingPlan, |
| | | field: 'Type', |
| | | subFilters: [] |
| | | } |
| | | ], |
| | | searchList: [], |
| | | groupId: classInfo?.id |
| | | } |
| | | MG.edu |
| | | .getTaskList(data) |
| | | .then((res: any) => { |
| | | if (res.datas.length == 0 && userInfo.value.role == 'Teacher') { |
| | | newTask() |
| | | } |
| | | if (res.datas.length > 0) { |
| | | taskData.value = res.datas[0] |
| | | classInfo.taskId = taskData.value?.id |
| | | classInfo.rootTaskCmsId = taskData.value?.rootCmsItemId |
| | | } |
| | | getTypeByCode() |
| | | if (classInfo.bookRefCode) { |
| | | getCatalogueList() |
| | | } |
| | | }) |
| | | .catch((e: any) => { |
| | | console.log(e) |
| | | }) |
| | | } |
| | | |
| | | // 前往阅读器 |
| | | const toRead = (item: any) => { |
| | | // config.textReaderUrl |
| | | // 'http://192.168.3.132:8005/#/home' |
| | | if (classInfo.bookRefCode) { |
| | | const url = |
| | | config.textReaderUrl + |
| | | '?bookId=' + |
| | | classInfo?.bookRefCode + |
| | | '&token=' + |
| | | localStorage.getItem('jsek-token') + |
| | | '&chapter=' + |
| | | item.parentVal + |
| | | '&startPage=' + |
| | | item.childVal |
| | | window.open(url, '_blank') |
| | | } else { |
| | | ElMessage.warning('当前章节无法跳转') |
| | | } |
| | | } |
| | | |
| | | // 下载上传资源 |
| | | const downloadRes = (item: any) => { |
| | | const url = config.requestCtx + '/file/api/ApiDownload?md5=' + item.Md5 |
| | | window.open(url, '_blank') |
| | | } |
| | | |
| | | // 选择器 |
| | | const parentSelect = (val: any, item: any) => { |
| | | if (val?.length) { |
| | | const str = val[2] |
| | | const obj = findObj(chapterList.value, str) |
| | | item.parentVal = obj.chapter |
| | | item.childVal = obj.start |
| | | } |
| | | } |
| | | |
| | | // 文件上传 |
| | | const fileUpload = (file: any) => { |
| | | return new Promise((resolve, reject) => { |
| | | // const isJPG = file.file.type === 'image/jpeg' || file.file.type === 'image/png' |
| | | // const isLt2M = (0.3 * file.file.size) / 1024 / 1024 < 0.3 |
| | | // if (!isJPG) { |
| | | // ElMessage.error('上传文件只能是 jpg/png 格式!') |
| | | // return reject() |
| | | // } |
| | | // if (!isLt2M) { |
| | | // ElMessage.error('上传文件大小不能超过 300KB!') |
| | | // return reject() |
| | | // } |
| | | const FileName = file.file.name.split('.')[0] |
| | | const Extension = file.file.name.split('.')[1] |
| | | const FileType = file.file.type |
| | | let size = 1024 |
| | | tool |
| | | .getFileMd5(file.file, size * 1024) |
| | | .then((e: string) => { |
| | | if (!fileList.value.find((item: any) => item.md5 == e)) { |
| | | const imgData = new FormData() |
| | | imgData.append('Md5', e) |
| | | imgData.append('FileName', FileName) |
| | | imgData.append('Extension', Extension) |
| | | imgData.append('FileType', FileType) |
| | | imgData.append('MetaData', null) |
| | | imgData.append('file', file.file) |
| | | MG.file.upload(imgData).then(() => { |
| | | fileList.value.push({ |
| | | md5: e, |
| | | linkType: 'LinkFile', |
| | | linkProtectType: 'Public', |
| | | fileName: FileName, |
| | | extension: Extension, |
| | | url: config.requestCtx + `/file/api/ApiDownload?md5=` + e |
| | | }) |
| | | }) |
| | | } else { |
| | | ElMessage.warning('当前文件已上传,请勿重复操作!') |
| | | } |
| | | }) |
| | | .catch((e: any) => { |
| | | console.error(e) |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | // 获取章节目录 |
| | | const getCatalogueList = () => { |
| | | const url = config.requestCtx + '/books/resource/' + classInfo?.bookRefCode + '/information.json' |
| | | axios |
| | | .get(url) |
| | | .then((res) => { |
| | | if (res.data?.data.length > 0) { |
| | | const datas = res.data.data |
| | | const list = datas?.filter((item: any) => item.children?.length > 0) |
| | | chapterList.value = changeCascaderData(list) |
| | | } |
| | | }) |
| | | .catch((e) => { |
| | | console.log(e) |
| | | }) |
| | | } |
| | | |
| | | // 递归更数组 |
| | | const changeCascaderData = (data: any) => { |
| | | for (const item of data) { |
| | | item.value = item.start |
| | | if (item.children?.length > 0) { |
| | | changeCascaderData(item.children) |
| | | } |
| | | } |
| | | return data |
| | | } |
| | | |
| | | // 递归查找 |
| | | const findObj = (arr: any, val: any) => { |
| | | for (let i = 0; i < arr.length; i++) { |
| | | const obj = arr[i] |
| | | if (obj.start === val) { |
| | | return obj // 找到目标对象,直接返回 |
| | | } |
| | | if (obj.children && obj.children.length > 0) { |
| | | // 如果当前对象有子对象,递归查找子对象 |
| | | const found: any = findObj(obj.children, val) |
| | | if (found) { |
| | | return found // 在子对象中找到目标对象,返回 |
| | | } |
| | | } |
| | | } |
| | | return null |
| | | } |
| | | |
| | | // 获取类型字段 |
| | | const getTypeByCode = () => { |
| | | MG.resource |
| | | .getCmsTypeByRefCode({ |
| | | refCodes: [config.refCodes.teachingPlan] |
| | | }) |
| | | .then((res: any) => { |
| | | const data = res[0]?.cmsTypeLinks[0]?.children |
| | | if (data?.length) { |
| | | classItem.value = data |
| | | } |
| | | getTaskCmsList() |
| | | }) |
| | | .catch((err: any) => { |
| | | console.log(err) |
| | | }) |
| | | } |
| | | |
| | | // 获取任务下的资源列表 |
| | | const getTaskCmsList = () => { |
| | | const data = { |
| | | start: (pages.page - 1) * pages.pageSize, |
| | | size: pages.pageSize, |
| | | searchList: searchKey.value |
| | | ? [ |
| | | { |
| | | keywords: searchKey.value, |
| | | field: 'Name', |
| | | compareType: 'Contains' |
| | | } |
| | | ] |
| | | : [], |
| | | taskId: classInfo?.taskId, |
| | | path: String(classInfo?.rootTaskCmsId), |
| | | type: '*', |
| | | keys: ['referenceMaterial', 'Name', 'selectChapter', 'uploadResources', 'explain'] |
| | | } |
| | | MG.edu |
| | | .getTaskCmsItem(data) |
| | | .then((res: any) => { |
| | | pages.loading = false |
| | | pages.count = res.totalSize |
| | | for (let i = 0; i < res.datas.length; i++) { |
| | | const item = res.datas[i] |
| | | // 处理字段 |
| | | if (taskItem != null) { |
| | | for (let fieldKey in taskItem) { |
| | | if (item.datas[fieldKey]) { |
| | | const values = JSON.parse(item.datas[fieldKey]) |
| | | if (values.length > 0) { |
| | | // 用字段名处理返回的字段值 |
| | | if (values[0].Value) { |
| | | item.datas[fieldKey] = values[0].Value |
| | | } else if (values[0].Data) { |
| | | item.datas[fieldKey] = values[0].Data.Value |
| | | } else if (!values[0].Value && values[0].FileList?.length > 0) { |
| | | item.datas[fieldKey] = values[0].FileList |
| | | } else { |
| | | item.datas[fieldKey] = '-' |
| | | } |
| | | if (fieldKey == 'selectChapter' && values[0].Value) { |
| | | const data = JSON.parse(values[0].Value) |
| | | item.datas['selectChapter'] = data.map((citem: any) => { |
| | | if (classInfo.bookRefCode) { |
| | | const dataS = findObj(chapterList.value, citem.childVal) |
| | | return { |
| | | ...citem, |
| | | parentName: |
| | | chapterList.value.find((sitem: any) => sitem.chapter == citem.parentVal) |
| | | ?.label + |
| | | '---' + |
| | | dataS?.label |
| | | } |
| | | } else { |
| | | return { |
| | | ...citem, |
| | | parentName: citem.parentVal + '---' + citem.childVal |
| | | } |
| | | } |
| | | }) |
| | | } |
| | | if (fieldKey == 'selectChapter' && !values[0].Value) { |
| | | item.datas['selectChapter'] = [] |
| | | } |
| | | } |
| | | const index = i |
| | | item.datas['index'] = index + 1 |
| | | } |
| | | } |
| | | } |
| | | } |
| | | tableData.value = res.datas |
| | | }) |
| | | .catch((e: any) => { |
| | | ElMessage({ |
| | | message: '列表获取失败', |
| | | type: 'error' |
| | | }) |
| | | console.log(e) |
| | | }) |
| | | } |
| | | |
| | | // 删除资源 |
| | | const removeTaskItem = (item: any) => { |
| | | const data = { |
| | | taskId: classInfo?.taskId, |
| | | requests: [ |
| | | { |
| | | cmsItemId: item.id, |
| | | path: String(classInfo?.rootTaskCmsId) |
| | | } |
| | | ] |
| | | } |
| | | MG.edu |
| | | .removeTaskCmsItemList(data) |
| | | .then((res: any) => { |
| | | if (res) { |
| | | ElMessage({ |
| | | message: '删除成功', |
| | | type: 'success' |
| | | }) |
| | | getTaskCmsList() |
| | | } |
| | | }) |
| | | .catch((e: any) => { |
| | | ElMessage({ |
| | | message: '删除失败', |
| | | type: 'error' |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | // 为任务新建资源 |
| | | const newTaskCmsItems = () => { |
| | | newLoading.value = true |
| | | taskItem.selectChapter = JSON.stringify(dynamicList.value) |
| | | if (!taskItem.title) { |
| | | ElMessage({ |
| | | message: '请填写教学名称', |
| | | type: 'warning' |
| | | }) |
| | | newLoading.value = false |
| | | return false |
| | | } |
| | | if (dynamicList.value[0]?.parentVal == '') { |
| | | ElMessage({ |
| | | message: '请选择教学章节', |
| | | type: 'warning' |
| | | }) |
| | | newLoading.value = false |
| | | return false |
| | | } |
| | | if (fileList.value.length == 0) { |
| | | ElMessage({ |
| | | message: '请上传教学文件', |
| | | type: 'warning' |
| | | }) |
| | | newLoading.value = false |
| | | return false |
| | | } |
| | | const data = { |
| | | groupId: classInfo?.id, |
| | | taskId: classInfo?.taskId, |
| | | accessPath: String(classInfo?.rootTaskCmsId), |
| | | newGroupCmsItemRequests: [ |
| | | { |
| | | name: taskItem.title, |
| | | description: '', |
| | | icon: '', |
| | | type: config.refCodes.teachingPlan, |
| | | state: 'Normal', |
| | | order: 0, |
| | | newDataListRequest: tool.worksDataBytool(classItem.value, taskItem, fileList.value), |
| | | newCmsItemAndFileLinkListRequest: [], |
| | | newChildrenListRequest: [] |
| | | } |
| | | ] |
| | | } |
| | | MG.edu.newTaskCmsItem(data).then((res: any) => { |
| | | newLoading.value = false |
| | | if (res) { |
| | | ElMessage({ |
| | | message: '新建成功', |
| | | type: 'success' |
| | | }) |
| | | visible.value = false |
| | | getTaskCmsList() |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // // 编辑资源 |
| | | // const editOpen = (item: any) => { |
| | | // visible.value = true |
| | | // taskItem.title = item?.datas?.Name |
| | | // taskItem.explain = item?.datas?.explain |
| | | // taskItem.referenceMaterial = item?.datas?.referenceMaterial |
| | | // if (item?.datas?.selectChapter > 0) { |
| | | // dynamicList.value = item?.datas?.selectChapter |
| | | // chapterList.value?.forEach((item: any) => { |
| | | // if (dynamicList.value.find((citem: any) => citem.parentVal == item.chapter)) { |
| | | // childrenList.value.push(...item.children) |
| | | // } |
| | | // }) |
| | | // } |
| | | // } |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .classManagePage-box { |
| | | padding: 20px; |
| | | .classManagePage-nav { |
| | | padding-bottom: 20px; |
| | | border-bottom: 1px solid #e6e8ed; |
| | | margin-bottom: 30px; |
| | | } |
| | | .classManagePage-content { |
| | | width: 100%; |
| | | .teachPlaneBox { |
| | | width: 100%; |
| | | .titleBox { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 10px; |
| | | .titleOptions { |
| | | width: 160px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | span { |
| | | font-family: PingFang SC; |
| | | font-weight: bold; |
| | | font-size: 16px; |
| | | color: #333; |
| | | line-height: 0px; |
| | | text-align: left; |
| | | } |
| | | } |
| | | .searchBox { |
| | | width: 300px; |
| | | float: left; |
| | | .searchBtn { |
| | | background-color: var(--el-color-primary); |
| | | color: #fff; |
| | | border-top-left-radius: 0; |
| | | border-bottom-left-radius: 0; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .linkTitle { |
| | | color: #ff6c00; |
| | | cursor: pointer; |
| | | } |
| | | .linkTitle:hover { |
| | | text-decoration: underline; |
| | | } |
| | | } |
| | | .formBox { |
| | | width: 100%; |
| | | font-family: PingFang SC; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #333333; |
| | | |
| | | .el-row { |
| | | margin-bottom: 20px; |
| | | display: flex; |
| | | align-items: flex-start; |
| | | .labelItem { |
| | | text-align: right; |
| | | margin-right: 15px; |
| | | padding-top: 2px; |
| | | } |
| | | .selectBox { |
| | | border: 1px solid #ddd; |
| | | border-radius: 5px; |
| | | padding: 20px 30px; |
| | | ::v-deep(.inputBox) { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: flex-start; |
| | | .el-input__wrapper { |
| | | padding: 5px 11px; |
| | | } |
| | | } |
| | | } |
| | | .selectMarBot { |
| | | margin-bottom: 10px; |
| | | } |
| | | .btngroup { |
| | | position: absolute; |
| | | top: 20px; |
| | | right: 27px; |
| | | } |
| | | .el-upload-list__item-name { |
| | | line-height: 22px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="classManagePage-box"> |
| | | <div class="classManagePage-nav">我的班级>{{ classInfo.name }}>作业管理</div> |
| | | <div class="classManagePage-content"></div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { useRoute } from 'vue-router' |
| | | const route = useRoute() |
| | | const classInfo = JSON.parse(route.query.classInfo) |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .classManagePage-box { |
| | | padding: 20px; |
| | | .classManagePage-nav { |
| | | padding-bottom: 20px; |
| | | border-bottom: 1px solid #e6e8ed; |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="classPage"> |
| | | <div class="headerBox"> |
| | | <div class="searchBox"> |
| | | <el-input v-model="searchKey" @clear="searchData()" clearable placeholder="请输入关键字"> |
| | | <template #append> |
| | | <el-button type="primary" class="searchBtn" :icon="Search" @click="searchData()" /> |
| | | </template> |
| | | </el-input> |
| | | </div> |
| | | <el-button type="primary" class="applyStartClasses" @click="applyClass">申请开班</el-button> |
| | | </div> |
| | | <div class="classListBox" v-loading="pages.loading"> |
| | | <div class="classItem" v-for="(item, index) in classList" :key="index"> |
| | | <div class="itemHeader"> |
| | | <div class="title">{{ item.name }}</div> |
| | | <div class="classId">(ID:{{ item.id }})</div> |
| | | <div class="copyIdBtn" v-if="item.applyState == 'Normal'" @click="copy(item.refCode)"> |
| | | 复制邀请码 |
| | | </div> |
| | | <div |
| | | class="copyIdBtn" |
| | | style="background: transparent; padding: 0" |
| | | v-if="item.applyState == 'Reject'" |
| | | > |
| | | <el-icon @click="delClass(item)" style="color: red; font-size: 14px" |
| | | ><Delete |
| | | /></el-icon> |
| | | </div> |
| | | </div> |
| | | <div class="itemInfo" @click="groupDetail(item)"> |
| | | <div class="infoBox"> |
| | | <p> |
| | | 状态:<span v-if="item.applyState == 'WaitAudit'" style="color: #ef9f29"> |
| | | 审核中 </span |
| | | ><span v-if="item.applyState == 'Normal'" style="color: #1dbd11"> 进行中 </span |
| | | ><span v-if="item.applyState == 'Reject'" style="color: red"> 未通过 </span> |
| | | </p> |
| | | <p v-if="item.applyState == 'Reject'"> |
| | | 拒绝原因:<span style="color: red">{{ item.reason != '' ? item.reason : '-' }}</span> |
| | | </p> |
| | | <p>班级人数:{{ item.memberCount }} / {{ item.maxUserCount }}</p> |
| | | <p> |
| | | 有效期:{{ moment(item.beginDate).format('YYYY-MM-DD') }} - |
| | | {{ moment(item.endDate).format('YYYY-MM-DD') }} |
| | | </p> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="pagination-box" v-if="classList.length > 0"> |
| | | <el-pagination |
| | | v-model:current-page="pages.page" |
| | | v-model:page-size="pages.pageSize" |
| | | :background="false" |
| | | layout="total, prev, pager, next" |
| | | :total="pages.count" |
| | | @current-change="pageChange" |
| | | @size-change="handleSizeChange" |
| | | /> |
| | | </div> |
| | | <div class="nullBox" v-if="!pages.loading && classList.length == 0"> |
| | | <el-empty /> |
| | | </div> |
| | | <!-- 申请开班弹框 --> |
| | | <el-dialog v-model="applyClassDialog" width="450" align-center> |
| | | <template #title>申请开班</template> |
| | | <el-form :model="formData" label-position="left" ref="dialogFormRef" label-width="100px"> |
| | | <el-form-item |
| | | label="班级名称" |
| | | prop="name" |
| | | :rules="[{ required: true, message: '请输入班级名称' }]" |
| | | > |
| | | <el-input v-model="formData.name" placeholder="请输入班级名称" /> |
| | | </el-form-item> |
| | | <el-form-item |
| | | label="班级人数" |
| | | prop="num" |
| | | :rules="[{ required: true, message: '请输入班级人数' }]" |
| | | > |
| | | <el-input-number v-model="formData.num" :min="1" :step="1" :precision="0" /> |
| | | </el-form-item> |
| | | <el-form-item |
| | | label="班级有效期" |
| | | prop="date" |
| | | :rules="[{ required: true, message: '请选择班级有效期' }]" |
| | | > |
| | | <el-date-picker |
| | | v-model="formData.date" |
| | | type="daterange" |
| | | range-separator="-" |
| | | start-placeholder="开始时间" |
| | | end-placeholder="结束时间" |
| | | /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button @click="applyClassDialog = false">取消</el-button> |
| | | <el-button type="primary" @click="submit" :loading="submitLoading">提交</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { defineProps, reactive, ref, onMounted, inject, watch } from 'vue' |
| | | import { Search } from '@element-plus/icons-vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import { getPublicImage } from '@/assets/js/middleGround/tool.js' |
| | | import moment from 'moment' |
| | | import { useRouter } from 'vue-router' |
| | | import useClipboard from 'vue-clipboard3' |
| | | |
| | | const { toClipboard } = useClipboard() |
| | | const uRouter = useRouter() |
| | | const MG: any = inject('MG') |
| | | const props = defineProps<{ |
| | | courseId: number |
| | | bookInfo: any |
| | | }>() |
| | | |
| | | const emit = defineEmits(['refreshParent']) |
| | | |
| | | // 申请开班防抖loading |
| | | const submitLoading = ref(false) |
| | | |
| | | const classList: any = ref([]) |
| | | |
| | | onMounted(() => { |
| | | getData() |
| | | }) |
| | | |
| | | const searchKey = ref('') |
| | | const pages = reactive({ |
| | | page: 1, |
| | | pageSize: 6, |
| | | count: 0, |
| | | loading: true |
| | | }) |
| | | |
| | | const searchData = () => { |
| | | pages.page = 1 |
| | | pages.pageSize = 10 |
| | | getData() |
| | | } |
| | | |
| | | // 获取班级 |
| | | const getData = () => { |
| | | pages.loading = true |
| | | MG.edu |
| | | .getCourseClassList({ |
| | | courseId: props.courseId, |
| | | start: (pages.page - 1) * pages.pageSize, |
| | | size: pages.pageSize, |
| | | sort: { |
| | | type: 'Desc', |
| | | field: 'CreateDate' |
| | | }, |
| | | filterList: [], |
| | | searchList: searchKey.value |
| | | ? [ |
| | | { |
| | | keywords: searchKey.value, |
| | | field: 'Name', |
| | | compareType: 'Contains' |
| | | } |
| | | ] |
| | | : [] |
| | | }) |
| | | .then((res: any) => { |
| | | pages.loading = false |
| | | pages.count = res.totalSize; |
| | | classList.value = res.datas.map((item: any) => { |
| | | return { |
| | | ...item, |
| | | name: item.name, |
| | | id: item.id, |
| | | icon: item.icon ? getPublicImage(item.icon, 80) : '', |
| | | introduction: item.description, |
| | | reason: item.applyReturnMsg ? JSON.parse(item.applyReturnMsg).reason : '' |
| | | } |
| | | }) |
| | | refreshParent() |
| | | }) |
| | | } |
| | | |
| | | // 加入班级 |
| | | const applyClass = () => { |
| | | formData.value = { |
| | | name: '', |
| | | num: '', |
| | | date: '' |
| | | } |
| | | applyClassDialog.value = true |
| | | } |
| | | |
| | | // 刷新父组件数据 |
| | | const refreshParent = () => { |
| | | emit('refreshParent', 'del') |
| | | } |
| | | |
| | | const applyClassDialog = ref(false) |
| | | const formData = ref({ |
| | | name: '', |
| | | num: '', |
| | | date: '' |
| | | }) |
| | | |
| | | const submit = () => { |
| | | submitLoading.value = true |
| | | MG.edu |
| | | .newCourseClass({ |
| | | courseId: props.courseId, |
| | | name: formData.value.name, |
| | | description: '', |
| | | icon: '', |
| | | type: 'class', |
| | | beginDate: moment(formData.value.date[0]).format('YYYY-MM-DD'), |
| | | endDate: moment(formData.value.date[1]).format('YYYY-MM-DD'), |
| | | config: '', |
| | | price: 0, |
| | | maxUserCount: formData.value.num |
| | | }) |
| | | .then((res: any) => { |
| | | if (res) { |
| | | setTimeout(() => { |
| | | submitLoading.value = false |
| | | ElMessage.success('开班已申请,等待管理员审核。') |
| | | applyClassDialog.value = false |
| | | getData() |
| | | }, 1000) |
| | | } |
| | | }) |
| | | .catch((err: any) => { |
| | | ElMessage.error('开班申请出错,请稍后再试') |
| | | setTimeout(() => { |
| | | submitLoading.value = false |
| | | }, 1000) |
| | | }) |
| | | } |
| | | |
| | | // 复制 |
| | | const copy = async (text: string) => { |
| | | try { |
| | | await toClipboard(text) |
| | | ElMessage({ |
| | | message: '复制成功', |
| | | type: 'success' |
| | | }) |
| | | } catch (e) { |
| | | console.error(e) |
| | | } |
| | | } |
| | | |
| | | // 删除班级 |
| | | const delClass = (item: any) => { |
| | | const data = { |
| | | ids: [item.id] |
| | | } |
| | | MG.edu |
| | | .delCourseClass(data) |
| | | .then((res: any) => { |
| | | if (res) { |
| | | ElMessage({ |
| | | message: '已删除', |
| | | type: 'success' |
| | | }) |
| | | getData() |
| | | } |
| | | }) |
| | | .catch((err: any) => { |
| | | ElMessage({ |
| | | message: '删除失败', |
| | | type: 'error' |
| | | }) |
| | | console.log(err) |
| | | }) |
| | | } |
| | | |
| | | // 获取审核通过的课程 |
| | | const coursePages = reactive({ |
| | | page: 1, |
| | | pageSize: 10, |
| | | count: 0, |
| | | loading: false |
| | | }) |
| | | const courseListData = ref([]) |
| | | |
| | | // const getCourse = () => { |
| | | // coursePages.loading = true |
| | | // const searchData = [ |
| | | // { |
| | | // keywords: 'jsek_digitalTextbooks', |
| | | // field: 'ProductType' |
| | | // } |
| | | // ] |
| | | // const data = { |
| | | // Size: coursePages.pageSize, |
| | | // Start: coursePages.pageSize * coursePages.page - coursePages.pageSize, |
| | | // sort: { |
| | | // type: 'Desc', |
| | | // field: 'CreateDate' |
| | | // }, |
| | | // searchList: searchData |
| | | // } |
| | | // MG.store |
| | | // .getPurchasedProductList(data) |
| | | // .then((res: any) => { |
| | | // coursePages.count = res.totalSize |
| | | // courseListData.value = res.datas.map((item: any) => { |
| | | // return { |
| | | // ...item, |
| | | // img: item.product.icon ? getPublicImage(item.product.icon, 80) : '' |
| | | // } |
| | | // }) |
| | | // coursePages.loading = false |
| | | // }) |
| | | // .catch(() => { |
| | | // coursePages.loading = false |
| | | // }) |
| | | // } |
| | | |
| | | const pageChange = (val: number) => { |
| | | pages.page = val |
| | | getData() |
| | | } |
| | | const handleSizeChange = (val: number) => { |
| | | pages.pageSize = val |
| | | getData() |
| | | } |
| | | |
| | | const groupDetail = (item: any) => { |
| | | if (item.applyState == 'WaitAudit') { |
| | | ElMessage({ |
| | | message: '正在审核中....', |
| | | type: 'warning' |
| | | }) |
| | | return false |
| | | } |
| | | if (item.applyState == 'Reject') { |
| | | ElMessage({ |
| | | message: '审核未通过', |
| | | type: 'warning' |
| | | }) |
| | | return false |
| | | } |
| | | const bookData = item.linkProductDto.product |
| | | let classinfo: any = { |
| | | id: item.id, |
| | | name: item.name, |
| | | courseId: props.courseId, |
| | | icon: bookData.icon, |
| | | rootCmsItemId: bookData.rootCmsItemId, |
| | | bookId: bookData.id, |
| | | author: bookData.author, |
| | | isbn: bookData.isbn, |
| | | bookRefCode: bookData.refCode |
| | | } |
| | | let page = uRouter.resolve({ |
| | | path: '/classManage', |
| | | query: { |
| | | classInfo: JSON.stringify(classinfo) |
| | | } |
| | | }) |
| | | window.open(page.href, '_blank') |
| | | } |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .classPage { |
| | | .headerBox { |
| | | margin-bottom: 10px; |
| | | overflow: hidden; |
| | | .searchBox { |
| | | width: 300px; |
| | | float: left; |
| | | .searchBtn { |
| | | background-color: var(--el-color-primary); |
| | | color: #fff; |
| | | border-top-left-radius: 0; |
| | | border-bottom-left-radius: 0; |
| | | } |
| | | } |
| | | .applyStartClasses { |
| | | float: right; |
| | | } |
| | | } |
| | | .classListBox { |
| | | overflow: hidden; |
| | | min-height: 200px; |
| | | .classItem { |
| | | float: left; |
| | | width: 49%; |
| | | margin-bottom: 16px; |
| | | margin-right: 1%; |
| | | border-radius: 8px; |
| | | border: 1px solid #efefef; |
| | | overflow: hidden; |
| | | |
| | | &:nth-child(2n) { |
| | | margin-left: 1%; |
| | | margin-right: 0; |
| | | } |
| | | .itemHeader { |
| | | height: 40px; |
| | | line-height: 40px; |
| | | padding: 0 20px; |
| | | background-color: #f8f8f8; |
| | | div { |
| | | display: inline-block; |
| | | } |
| | | .classId { |
| | | margin-left: 6px; |
| | | font-size: 12px; |
| | | color: #999; |
| | | } |
| | | .copyIdBtn { |
| | | float: right; |
| | | height: 20px; |
| | | line-height: 20px; |
| | | margin-top: 10px; |
| | | font-size: 12px; |
| | | background-color: #fff; |
| | | color: #3b93fe; |
| | | padding: 0 6px; |
| | | border-radius: 50px; |
| | | overflow: hidden; |
| | | cursor: pointer; |
| | | } |
| | | } |
| | | .itemInfo { |
| | | height: 128px; |
| | | padding: 20px; |
| | | flex: 1; |
| | | display: flex; |
| | | cursor: pointer; |
| | | .infoBox { |
| | | flex: 1; |
| | | font-size: 12px; |
| | | p { |
| | | margin-bottom: 10px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .courseList { |
| | | overflow: hidden; |
| | | margin-bottom: 20px; |
| | | |
| | | .courseItem { |
| | | float: left; |
| | | width: 100px; |
| | | margin: 10px; |
| | | position: relative; |
| | | |
| | | .checkBox { |
| | | position: absolute; |
| | | right: 0; |
| | | top: 0; |
| | | height: 14px; |
| | | |
| | | ::v-deep { |
| | | .el-checkbox__inner { |
| | | border-color: #888; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .imgBox { |
| | | width: 100px; |
| | | height: 110px; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | p { |
| | | line-height: 1.2; |
| | | display: -webkit-box; |
| | | -webkit-line-clamp: 2; |
| | | -webkit-box-orient: vertical; |
| | | overflow: hidden; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .pagination-box { |
| | | padding: 10px 0; |
| | | display: flex; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .nullBox { |
| | | text-align: center; |
| | | margin-top: 30px; |
| | | font-size: 20px; |
| | | color: #ccc; |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="courseManage" v-loading="loading"> |
| | | <div class="backBox"> |
| | | <span @click="router.back()">< 返回</span> |
| | | </div> |
| | | <div class="courseName"> |
| | | <div class="title" :title="detailData.name">{{ detailData.name }}</div> |
| | | <span class="courseId">ID:{{ detailData.id }}</span> |
| | | </div> |
| | | <div class="courseInfoBox"> |
| | | <div class="desc" :title="detailData.description"> |
| | | {{ detailData.description }} |
| | | </div> |
| | | <div class="textBookImg autoImgBox"> |
| | | <img |
| | | v-if="detailData?.linkProduct?.icon != 'default'" |
| | | :src=" |
| | | detailData.linkProduct?.icon ? getPublicImage(detailData.linkProduct.icon, 80) : defaultImg |
| | | " |
| | | /> |
| | | </div> |
| | | <div class="textBookInfo"> |
| | | <p class="title">{{ bookDetail?.name }}</p> |
| | | <p v-if="bookDetail?.author">作者: {{ bookDetail?.author }}</p> |
| | | <p>ISBN:{{ bookDetail?.isbn }}</p> |
| | | </div> |
| | | <div class="statisticsInfoBox"> |
| | | <p class="title">班级数量<span>(进行中/全部)</span></p> |
| | | <!-- <p class="num">0 / 0</p> --> |
| | | <p class="num">{{ numClass }}</p> |
| | | </div> |
| | | <!-- <div class="statisticsInfoBox"> |
| | | <p class="title">学习人数<span>(学习中/全部)</span></p> |
| | | <p class="num">0 / 0</p> |
| | | </div> --> |
| | | <!-- <div class="statisticsInfoBox"> |
| | | <p class="title" style="margin-bottom: 40px">教学大纲</p> |
| | | <p class="num">25</p> |
| | | </div> --> |
| | | </div> |
| | | <el-tabs style="margin-top: 20px"> |
| | | <el-tab-pane label="我的班级"> |
| | | <classManage |
| | | v-if="detailData.id" |
| | | :courseId="detailData.id" |
| | | :bookInfo="bookDetail" |
| | | @refreshParent="refreshParent" |
| | | /> |
| | | </el-tab-pane> |
| | | <!-- <el-tab-pane label="教学计划">教学计划</el-tab-pane> --> |
| | | </el-tabs> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { reactive, ref, onMounted, inject, watch } from 'vue' |
| | | import { useRouter, useRoute } from 'vue-router' |
| | | import { Search } from '@element-plus/icons-vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import { getPublicImage } from '@/assets/js/middleGround/tool.js' |
| | | import classManage from './components/class.vue' |
| | | import defaultImg from '@/assets/images/default-book-img.png' |
| | | |
| | | const MG: any = inject('MG') |
| | | const router = useRouter() |
| | | const route = useRoute() |
| | | const query = route.query |
| | | const bookDetail = ref() |
| | | const numClass = ref(0) |
| | | |
| | | onMounted(() => { |
| | | getData() |
| | | }) |
| | | |
| | | const loading = ref(true) |
| | | |
| | | const detailData: any = ref({}) |
| | | |
| | | // 获取班级 |
| | | const getDataClass = () => { |
| | | MG.edu |
| | | .getCourseClassList({ |
| | | courseId: detailData.value.id, |
| | | start: 0, |
| | | size: 999, |
| | | sort: { |
| | | type: 'Desc', |
| | | field: 'CreateDate' |
| | | }, |
| | | filterList: [], |
| | | searchList: [] |
| | | }) |
| | | .then((res: any) => { |
| | | numClass.value = res.datas.length |
| | | }) |
| | | } |
| | | |
| | | // 获取课程信息 |
| | | const getData = () => { |
| | | MG.edu |
| | | .getCourseById({ |
| | | courseId: query.courseId |
| | | }) |
| | | .then((res: any) => { |
| | | detailData.value = res |
| | | loading.value = false |
| | | const shopId = res.linkProduct?.id |
| | | getBookDetail(shopId) |
| | | getDataClass() |
| | | }) |
| | | } |
| | | |
| | | // 获取教材详情 |
| | | const getBookDetail = (shopId: number) => { |
| | | let query = { |
| | | path: '*', |
| | | queryType: '*', |
| | | productId: String(shopId), |
| | | coverSize: { |
| | | height: 300, |
| | | width: 210 |
| | | }, |
| | | fields: { |
| | | seriesName: [], |
| | | author: [], |
| | | isbn: [], |
| | | publicationDate: [] |
| | | } |
| | | } |
| | | MG.store.getProductDetail(query).then(async (res: any) => { |
| | | bookDetail.value = res.datas |
| | | }) |
| | | } |
| | | |
| | | const refreshParent = (str: string) => { |
| | | if (str == 'del') getData() |
| | | } |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .courseManage { |
| | | padding: 0 20px; |
| | | .backBox { |
| | | border-bottom: 1px solid #efefef; |
| | | padding: 15px 0; |
| | | margin-bottom: 20px; |
| | | color: var(--el-color-primary); |
| | | span { |
| | | cursor: pointer; |
| | | } |
| | | } |
| | | .courseName { |
| | | margin-bottom: 20px; |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | display: flex; |
| | | justify-content: flex-start; |
| | | align-items: center; |
| | | .title { |
| | | max-width: 300px; |
| | | white-space: nowrap; |
| | | text-overflow: ellipsis; |
| | | overflow: hidden; |
| | | word-wrap: break-word; |
| | | } |
| | | .courseId { |
| | | margin-left: 40px; |
| | | font-size: 12px; |
| | | font-weight: normal; |
| | | } |
| | | } |
| | | .courseInfoBox { |
| | | font-size: 14px; |
| | | border: 1px solid #7ac1ec; |
| | | border-radius: 10px; |
| | | padding: 20px 10px; |
| | | display: flex; |
| | | background: #ebf7ff; |
| | | .desc { |
| | | width: 18%; |
| | | border-right: 1px solid #ccc; |
| | | padding-right: 20px; |
| | | margin-right: 20px; |
| | | font-size: 12px; |
| | | line-height: 30px; |
| | | display: -webkit-box; |
| | | -webkit-box-orient: vertical; |
| | | -webkit-line-clamp: 4; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | .textBookImg { |
| | | width: 100px; |
| | | height: 120px; |
| | | margin-right: 10px; |
| | | } |
| | | .textBookInfo { |
| | | flex: 1.5; |
| | | overflow: hidden; |
| | | line-height: 18px; |
| | | p { |
| | | margin-bottom: 10px; |
| | | } |
| | | } |
| | | .statisticsInfoBox { |
| | | flex: 1; |
| | | overflow: hidden; |
| | | text-align: center; |
| | | p { |
| | | margin-bottom: 20px; |
| | | } |
| | | .num { |
| | | font-size: 16px; |
| | | } |
| | | } |
| | | .title { |
| | | font-weight: bold; |
| | | font-size: 14px; |
| | | span { |
| | | display: inline-block; |
| | | font-weight: normal; |
| | | font-size: 12px; |
| | | margin-top: 6px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div>激活码</div> |
| | | </template> |
| | | <!-- <page> --> |
| | | <div class="personalPage-box"> |
| | | <div class="personalPage-title">激活商品</div> |
| | | <div class="personalPage-content"> |
| | | <div class="activation flex"> |
| | | <el-input class="inputBox" v-model="activateCode" placeholder="请输入激活码"> |
| | | <template #append> |
| | | <el-button |
| | | style="background-color: #019e58; color: #fff" |
| | | @click="userActiveCodeGet" |
| | | :loading="loading" |
| | | >激活</el-button |
| | | > |
| | | </template> |
| | | </el-input> |
| | | <!-- <el-button class="buttonBox" type="primary" @click="userActiveCodeGet" :loading="loading" |
| | | >激活商品</el-button |
| | | > --> |
| | | </div> |
| | | <div class="tipTitle">已激活商品</div> |
| | | <div class="myCarTopPage"> |
| | | <div class="cartContent"> |
| | | <div class="list-box" v-loading="pages.loading"> |
| | | <ul class="listTable" v-if="dataList.length > 0 && !pages.loading"> |
| | | <li v-for="item in dataList" :key="item.index"> |
| | | <div class="stateBox flex"> |
| | | <span class="flex1" |
| | | >使用激活码:<span>{{ item.code }}</span></span |
| | | > |
| | | <span class="createDate flex1" |
| | | >激活日期:{{ item.createDate ? item.createDate : "-" }}</span |
| | | > |
| | | </div> |
| | | <div class="listItemBox flex"> |
| | | <div style="width: 100%" v-if="item.typeList.length > 0"> |
| | | <div |
| | | v-for="pItem in item.typeList" |
| | | :key="pItem.id" |
| | | class="listItem" |
| | | @click=" |
| | | goBookDetails(pItem.id, pItem.name, pItem.defaultSaleMethodId) |
| | | " |
| | | > |
| | | <div class="cover"> |
| | | <img |
| | | :src=" |
| | | pItem.icon ? getPublicImage(pItem.icon, '', '') : bookCover |
| | | " |
| | | alt="" |
| | | /> |
| | | <!-- <div class="type" v-if="pItem.type">{{ pItem.type }}</div> --> |
| | | </div> |
| | | <div class="info"> |
| | | <div style="margin-bottom: 10px" v-if="pItem.type"> |
| | | {{ pItem.type }} |
| | | </div> |
| | | <span :title="pItem.name">{{ pItem.name }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div v-else class="noProduct"> |
| | | <el-empty :image-size="80" description="无激活商品" /> |
| | | </div> |
| | | </div> |
| | | </li> |
| | | </ul> |
| | | <div v-if="dataList.length == 0 && !pages.loading"> |
| | | <el-empty :image-size="200" /> |
| | | </div> |
| | | </div> |
| | | <div class="pagination-box" v-if="dataList.length > 0 && !pages.loading"> |
| | | <el-pagination |
| | | v-model:current-page="pages.page" |
| | | v-model:page-size="pages.pageSize" |
| | | layout="total, prev, pager, next" |
| | | :total="pages.count" |
| | | @current-change="handleCurrentChange" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <!-- </page> --> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { reactive, ref, onMounted, inject, watch } from "vue"; |
| | | import moment from "moment"; |
| | | import { getPublicImage } from "@/assets/js/middleGround/tool.js"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { useBreadcrumbStore, useUserStore } from "@/store"; |
| | | import { useRouter } from "vue-router"; |
| | | import bookCover from "@/assets/images/personalCenter/book-cover.png"; |
| | | const router = useRouter(); |
| | | const crumbStore = useBreadcrumbStore(); |
| | | const userStore = useUserStore(); |
| | | const MG = inject("MG"); |
| | | const activateCode = ref(""); |
| | | const loading = ref(false); |
| | | let dataList = ref([]); |
| | | let pages = reactive({ |
| | | page: 1, |
| | | pageSize: 5, |
| | | count: 0, |
| | | loading: false, |
| | | }); |
| | | |
| | | // 使用激活码 |
| | | const userActiveCodeGet = () => { |
| | | loading.value = true; |
| | | let lock = true; |
| | | if (activateCode.value == "") { |
| | | ElMessage({ |
| | | type: "error", |
| | | message: "请输入激活码!", |
| | | }); |
| | | loading.value = false; |
| | | } else { |
| | | if (lock) { |
| | | lock = false; |
| | | MG.store |
| | | .userActiveCode({ |
| | | code: activateCode.value, |
| | | }) |
| | | .then((res) => { |
| | | ElMessage({ |
| | | type: res == "激活成功" ? "success" : "error", |
| | | message: res, |
| | | }); |
| | | activateCode.value = ""; |
| | | loading.value = false; |
| | | getDataList(); |
| | | lock = true; |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | function getDataList() { |
| | | pages.loading = true; |
| | | MG.store |
| | | .userActiveCodeList({ |
| | | start: (pages.page - 1) * pages.pageSize, |
| | | size: pages.pageSize, |
| | | sort: { |
| | | type: "Desc", |
| | | field: "CreateDate", |
| | | }, |
| | | }) |
| | | .then((res) => { |
| | | let list: any[] = []; |
| | | res.datas.forEach((item) => { |
| | | item.createDate = moment(item.createDate).format("YYYY-MM-DD HH:mm:ss"); |
| | | item.typeList = []; |
| | | item.saleMethodList.forEach(async (i) => { |
| | | const obj = { |
| | | icon: item.productList[0]?.icon, |
| | | id: item.productList[0]?.id, |
| | | name: item.productList[0]?.name, |
| | | type: |
| | | i.type == "defaultSaleMethod" |
| | | ? "电子书" |
| | | : i.name.includes("-") |
| | | ? i.name.split("-")[0] |
| | | : i.name, |
| | | defaultSaleMethodId: item.productList[0]?.defaultSaleMethodId, |
| | | }; |
| | | |
| | | let parentData = await MG.store.getProductBySaleMethod({ saleMethodId: i.id }); |
| | | if (parentData.storeLinks[0].storeRefCode == "jsek_digitalCourses") { |
| | | obj.type = "数字课程"; |
| | | } |
| | | if (parentData.storeLinks[0].storeRefCode == "jsek_digitalTextbooks") { |
| | | obj.type = "数字教材"; |
| | | } |
| | | item.typeList.push(obj); |
| | | }); |
| | | list.push(item); |
| | | }); |
| | | setTimeout(() => { |
| | | dataList.value = list; |
| | | pages.count = res.totalSize; |
| | | pages.loading = false; |
| | | }, 500); |
| | | }) |
| | | .catch(() => { |
| | | pages.loading = false; |
| | | }); |
| | | } |
| | | |
| | | onMounted(() => { |
| | | getDataList(); |
| | | }); |
| | | |
| | | // watch( |
| | | // () => userStore.token, |
| | | // () => { |
| | | // getDataList() |
| | | // } |
| | | // ) |
| | | |
| | | const handleCurrentChange = (val: number) => { |
| | | pages.page = val; |
| | | getDataList(); |
| | | }; |
| | | // 跳转书本详情 |
| | | const goBookDetails = async (id: number, name: string, defaultSaleMethodId: number) => { |
| | | let parentData = await MG.store.getProductBySaleMethod({ |
| | | saleMethodId: defaultSaleMethodId, |
| | | }); |
| | | console.log(parentData, 123); |
| | | if (parentData.storeLinks[0].storeRefCode == "jsek_digitalCourses") { |
| | | let crumbs = [ |
| | | { |
| | | name, |
| | | isCrumbs: true, |
| | | type: "digitalCourses", |
| | | path: "digitalCoursesDetails", |
| | | }, |
| | | ]; |
| | | // 在全局数据中设置面包屑 |
| | | crumbStore.setCrumbs({ |
| | | type: "digitalCourses", |
| | | data: crumbs, |
| | | callback: (key: any) => { |
| | | router.push({ |
| | | name: "digitalCoursesDetails", |
| | | query: { |
| | | crumbsKey: key, |
| | | bookId: parentData.id, |
| | | bookName: parentData.name, |
| | | type: "digitalCourses", |
| | | }, |
| | | }); |
| | | }, |
| | | }); |
| | | } else if (parentData.storeLinks[0].storeRefCode == "jsek_digitalTextbooks") { |
| | | let crumbs = [ |
| | | { |
| | | name, |
| | | isCrumbs: true, |
| | | type: "digitalTextbooks", |
| | | path: "digitalTextbooksDetails", |
| | | }, |
| | | ]; |
| | | // 在全局数据中设置面包屑 |
| | | crumbStore.setCrumbs({ |
| | | type: "digitalTextbooks", |
| | | data: crumbs, |
| | | callback: (key: any) => { |
| | | router.push({ |
| | | name: "digitalTextbooksDetails", |
| | | query: { |
| | | crumbsKey: key, |
| | | bookId: parentData.id, |
| | | bookName: parentData.name, |
| | | type: "digitalTextbooks", |
| | | }, |
| | | }); |
| | | }, |
| | | }); |
| | | } else { |
| | | let crumbs = [ |
| | | { |
| | | name, |
| | | isCrumbs: true, |
| | | type: "bookService", |
| | | path: "/bookService/details", |
| | | }, |
| | | ]; |
| | | // 在全局数据中设置面包屑 |
| | | crumbStore.setCrumbs({ |
| | | type: "bookService", |
| | | data: crumbs, |
| | | callback: (key: any) => { |
| | | router.push({ |
| | | name: "bookDetails", |
| | | query: { |
| | | crumbsKey: key, |
| | | bookId: id, |
| | | bookName: name, |
| | | type: "bookService", |
| | | }, |
| | | }); |
| | | }, |
| | | }); |
| | | } |
| | | }; |
| | | </script> |
| | | <style lang="less" scoped> |
| | | ::v-deep(.activation) { |
| | | margin-bottom: 30px; |
| | | .el-input__wrapper.is-focus { |
| | | border-color: none !important; |
| | | } |
| | | } |
| | | |
| | | .inputBox { |
| | | width: 300px; |
| | | margin-right: 10px; |
| | | } |
| | | |
| | | .tipTitle { |
| | | font-family: Microsoft YaHei UI, Microsoft YaHei UI; |
| | | font-weight: 400; |
| | | font-size: 16px; |
| | | color: #000000; |
| | | padding: 5px 20px; |
| | | box-sizing: border-box; |
| | | border-left: 3px solid #019e58; |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .stateBox { |
| | | height: 47px; |
| | | line-height: 47px; |
| | | padding: 0 20px; |
| | | border: 1px solid #edecec; |
| | | background: #f3f3f3; |
| | | } |
| | | |
| | | .listItemBox { |
| | | margin-top: 20px; |
| | | } |
| | | |
| | | .listItem { |
| | | width: 130px; |
| | | cursor: pointer; |
| | | box-sizing: border-box; |
| | | float: left; |
| | | position: relative; |
| | | margin-right: 5%; |
| | | |
| | | .cover { |
| | | width: 100%; |
| | | height: 180px; |
| | | box-shadow: 0px 0px 20px 1px #ccc; |
| | | position: relative; |
| | | |
| | | img { |
| | | width: 100%; |
| | | height: 100%; |
| | | object-fit: contain; |
| | | } |
| | | .type { |
| | | width: 50px; |
| | | height: 26px; |
| | | text-align: center; |
| | | font-size: 12px; |
| | | line-height: 24px; |
| | | position: absolute; |
| | | top: 0; |
| | | right: 0; |
| | | background-color: #019e58; |
| | | color: #fff; |
| | | border-radius: 0px 0px 0px 5px; |
| | | } |
| | | } |
| | | |
| | | .info { |
| | | height: 90px; |
| | | padding: 15px 0; |
| | | width: 100%; |
| | | |
| | | span { |
| | | font-weight: bold; |
| | | height: 45px; |
| | | line-height: 22px; |
| | | display: -webkit-box; |
| | | margin-bottom: 5px; |
| | | -webkit-box-orient: vertical; |
| | | -webkit-line-clamp: 2; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .list-box { |
| | | min-height: 450px; |
| | | } |
| | | |
| | | .createDate { |
| | | text-align: right; |
| | | } |
| | | .noProduct { |
| | | padding: 30px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .pagination-box { |
| | | display: flex; |
| | | justify-content: center; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div class="myBook"> |
| | | <div class="myBook_header"> |
| | | <div class="myBook_header_title">我的班级</div> |
| | | <div class="coursePage"> |
| | | <div class="personalPage-title">我的班级</div> |
| | | <div class="tabs"> |
| | | <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick"> |
| | | <el-tab-pane |
| | | :label="'当前班级(' + calssList.length + ')'" |
| | | name="1" |
| | | ></el-tab-pane> |
| | | <!-- <el-tab-pane label="历史班级(5)" name="2"></el-tab-pane> --> |
| | | </el-tabs> |
| | | </div> |
| | | <div class="headerBox"> |
| | | <div class="searchBox"> |
| | | <el-input |
| | | v-model="searchKey" |
| | | clearable |
| | | @clear="searchList()" |
| | | placeholder="请输入关键字" |
| | | > |
| | | <template #append> |
| | | <el-button |
| | | type="primary" |
| | | class="searchBtn" |
| | | @click="searchList()" |
| | | :icon="Search" |
| | | /> |
| | | </template> |
| | | </el-input> |
| | | </div> |
| | | <el-button type="primary" class="applyStartClasses" @click="openJoin()" |
| | | >加入班级</el-button |
| | | > |
| | | <el-dialog v-model="dialogVisible" title="加入班级" width="500"> |
| | | <div class="codeContent"> |
| | | <span>邀请码:</span> |
| | | <el-input style="width: 330px" v-model="codeText" placeholder="请输入邀请码" /> |
| | | <el-button type="primary" @click="getClassDetail">确认</el-button> |
| | | </div> |
| | | <div class="classInfo" v-if="classDetail?.name"> |
| | | <div class="itemCon"> |
| | | <span>班级名称:</span> |
| | | <span>{{ classDetail.name }}</span> |
| | | </div> |
| | | <div class="itemCon"> |
| | | <span>班级人数:</span> |
| | | <span>{{ classDetail.memberCount }} / {{ classDetail.maxUserCount }}</span> |
| | | </div> |
| | | <div class="itemCon"> |
| | | <span>开课时间:</span> |
| | | <span |
| | | >{{ moment(classDetail.beginDate).format("YYYY-MM-DD") }} - |
| | | {{ moment(classDetail.endDate).format("YYYY-MM-DD") }}</span |
| | | > |
| | | </div> |
| | | </div> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button @click="dialogVisible = false"> 取消 </el-button> |
| | | <el-button type="primary" @click="joinClass()"> 确认 </el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | <div class="courseListBox" v-if="calssList.length > 0 && !isLoading"> |
| | | <div class="courseItem" v-for="(item, index) in calssList" :key="index"> |
| | | <div class="itemHeader"> |
| | | <div class="title">{{ item.name }}</div> |
| | | <div class="courseId">(ID:{{ item.id }})</div> |
| | | <!-- <div class="copyIdBtn" @click="copy(item.refCode)">复制邀请码</div> --> |
| | | </div> |
| | | <div class="itemInfo" @click="goClassManage(item)"> |
| | | <div class="infoBox"> |
| | | <p> |
| | | 状态:<span v-if="item.userState == 'WaitValid'" style="color: #ef9f29"> |
| | | 审核中 </span |
| | | ><span v-if="item.userState == 'Normal'" style="color: #1dbd11"> |
| | | 进行中 </span |
| | | ><span v-if="item.userState == 'Reject'" style="color: red"> 未通过 </span> |
| | | </p> |
| | | <p>班级人数:{{ item.memberCount }} / {{ item.maxUserCount }}</p> |
| | | <p>有效期:{{ item.classTime }}</p> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <el-empty description="暂无数据" v-if="calssList.length == 0 && !isLoading" /> |
| | | <div style="min-height: 200px" v-if="isLoading" v-loading="isLoading"></div> |
| | | <div class="pageBox"> |
| | | <el-pagination |
| | | v-model:current-page="pages.currentPage" |
| | | :page-size="pages.pageSize" |
| | | :size="'small'" |
| | | :disabled="pages.count <= 1" |
| | | layout="total, prev, pager, next" |
| | | :total="pages.count" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { reactive, ref, onMounted, inject, watch } from "vue"; |
| | | import { Search } from "@element-plus/icons-vue"; |
| | | import { useRouter } from "vue-router"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { getPublicImage } from "@/assets/js/middleGround/tool.js"; |
| | | import moment from "moment"; |
| | | import useClipboard from "vue-clipboard3"; |
| | | |
| | | const { toClipboard } = useClipboard(); |
| | | const MG: any = inject("MG"); |
| | | const config: any = inject("config"); |
| | | const router = useRouter(); |
| | | const activeName = ref("1"); |
| | | |
| | | interface ClassItem { |
| | | id: string; |
| | | name: string; |
| | | memberCount: number; |
| | | maxUserCount: number; |
| | | userState: string; |
| | | beginDate: string; |
| | | endDate: string; |
| | | classTime: string; |
| | | linkProductDto: { |
| | | product: { |
| | | name: string; |
| | | icon: string; |
| | | }; |
| | | }; |
| | | } |
| | | |
| | | const calssList = ref<ClassItem[]>([]); |
| | | const searchKey = ref(""); |
| | | const codeText = ref(""); |
| | | const dialogVisible = ref(false); |
| | | const classDetail = ref(); |
| | | const isLoading = ref(true); |
| | | |
| | | let pages = reactive({ |
| | | currentPage: 1, |
| | | page: 1, |
| | | pageSize: 6, |
| | | count: 0, |
| | | loading: false, |
| | | }); |
| | | |
| | | onMounted(() => { |
| | | getCurrentClassList(); |
| | | }); |
| | | |
| | | // 分页 |
| | | const handleSizeChange = (val: number) => { |
| | | pages.pageSize = val; |
| | | getCurrentClassList(); |
| | | }; |
| | | |
| | | const handleCurrentChange = (val: number) => { |
| | | pages.page = val; |
| | | pages.currentPage = val; |
| | | getCurrentClassList(); |
| | | }; |
| | | |
| | | const handleClick = (val: any) => { |
| | | activeName.value = val; |
| | | }; |
| | | |
| | | const openJoin = () => { |
| | | dialogVisible.value = true; |
| | | classDetail.value = null; |
| | | codeText.value = ""; |
| | | }; |
| | | |
| | | // 搜索 |
| | | const searchList = () => { |
| | | pages.page = 1; |
| | | pages.currentPage = 1; |
| | | getCurrentClassList(); |
| | | }; |
| | | |
| | | // 复制 |
| | | const copy = async (text: string) => { |
| | | try { |
| | | await toClipboard(text); |
| | | ElMessage({ |
| | | message: "复制成功", |
| | | type: "success", |
| | | }); |
| | | } catch (e) { |
| | | console.error(e); |
| | | } |
| | | }; |
| | | |
| | | // 加入班级 |
| | | const joinClass = () => { |
| | | if (!codeText.value) { |
| | | ElMessage({ |
| | | message: "无效的邀请码", |
| | | type: "error", |
| | | }); |
| | | return false; |
| | | } |
| | | const data = { refCode: codeText.value }; |
| | | MG.identity.joinGroupByRefCode(data).then((res: any) => { |
| | | if (res == "组不存在") { |
| | | ElMessage({ |
| | | message: "无效的班级", |
| | | type: "error", |
| | | }); |
| | | } |
| | | if (res == "组成员数量已最大,不能加入") { |
| | | ElMessage({ |
| | | message: "班级成员数量已最大,不能加入", |
| | | type: "error", |
| | | }); |
| | | } |
| | | if (res == "已经申请过加入此组") { |
| | | ElMessage({ |
| | | message: "已经申请过加入此班级", |
| | | type: "error", |
| | | }); |
| | | } |
| | | dialogVisible.value = false; |
| | | getCurrentClassList(); |
| | | }); |
| | | }; |
| | | |
| | | // 获取当前班级列表 |
| | | const getCurrentClassList = () => { |
| | | isLoading.value = true; |
| | | const data = { |
| | | start: (pages.page - 1) * pages.pageSize, |
| | | size: pages.pageSize, |
| | | sort: { |
| | | type: "Desc", |
| | | field: "CreateDate", |
| | | subSorts: [], |
| | | }, |
| | | filterList: [], |
| | | searchList: searchKey.value |
| | | ? [ |
| | | { |
| | | keywords: searchKey.value, |
| | | field: "Name", |
| | | compareType: "Contains", |
| | | }, |
| | | ] |
| | | : [], |
| | | }; |
| | | MG.identity.joinedGroupByList(data).then((res: any) => { |
| | | isLoading.value = false; |
| | | pages.count = res.totalSize; |
| | | if (res.datas) { |
| | | calssList.value = res.datas.map((item: any) => { |
| | | return { |
| | | ...item, |
| | | classTime: |
| | | moment(item.beginDate).format("YYYY.MM.DD") + |
| | | "--" + |
| | | moment(item.endDate).format("YYYY.MM.DD"), |
| | | bookName: item.linkProductDto.product.name, |
| | | bookIcon: getPublicImage(item.linkProductDto.product.icon, 100), |
| | | }; |
| | | }); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | // 跳转班级管理 |
| | | const goClassManage = async (item: any) => { |
| | | if (item.userState == "WaitValid") { |
| | | ElMessage({ |
| | | message: "正在审核中....", |
| | | type: "warning", |
| | | }); |
| | | return false; |
| | | } |
| | | if (item.userState == "Reject") { |
| | | ElMessage({ |
| | | message: "审核未通过", |
| | | type: "warning", |
| | | }); |
| | | return false; |
| | | } |
| | | const bookInfo = await getBookDetail(item.linkProductDto?.product); |
| | | let info = { |
| | | id: item.id, |
| | | name: item.name, |
| | | icon: bookInfo.icon, |
| | | rootCmsItemId: bookInfo.rootCmsItemId, |
| | | bookId: bookInfo.id, |
| | | author: bookInfo.author, |
| | | isbn: bookInfo.isbn, |
| | | bookRefCode: bookInfo.refCode, |
| | | }; |
| | | let page = router.resolve({ |
| | | path: "/classManage", |
| | | query: { |
| | | classInfo: JSON.stringify(info), |
| | | }, |
| | | }); |
| | | window.open(page.href, "_blank"); |
| | | // router.push({ |
| | | // path: '/classManage', |
| | | // query: { |
| | | // classInfo: JSON.stringify(info) |
| | | // } |
| | | // }) |
| | | }; |
| | | |
| | | // 获取教材详情 |
| | | const getBookDetail = async (item: any) => { |
| | | const path = item.refCode ? "jsek_digitalTextbooks" : config.goodsStore; |
| | | let query = { |
| | | path, |
| | | queryType: "*", |
| | | productId: String(item.id), |
| | | storeInfo: path, |
| | | coverSize: { |
| | | height: 300, |
| | | width: 210, |
| | | }, |
| | | fields: { |
| | | author: [], |
| | | isbn: [], |
| | | }, |
| | | }; |
| | | const res = await MG.store.getProductDetail(query); |
| | | return res.datas ?? null; |
| | | }; |
| | | |
| | | // 通过code查询班级 |
| | | const getClassDetail = () => { |
| | | if (codeText.value == "") { |
| | | ElMessage({ |
| | | message: "请输入邀请码", |
| | | type: "warning", |
| | | }); |
| | | return false; |
| | | } |
| | | const data = { |
| | | classIdOrRefCode: codeText.value, |
| | | }; |
| | | MG.edu |
| | | .getCourseClass(data) |
| | | .then((res: any) => { |
| | | classDetail.value = res; |
| | | }) |
| | | .catch((err: any) => { |
| | | console.log(err); |
| | | }); |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .coursePage { |
| | | .tabs { |
| | | padding: 0 20px; |
| | | } |
| | | .headerBox { |
| | | padding: 5px 20px; |
| | | margin-bottom: 10px; |
| | | overflow: hidden; |
| | | .searchBox { |
| | | width: 300px; |
| | | float: left; |
| | | .searchBtn { |
| | | background-color: var(--el-color-primary); |
| | | color: #fff; |
| | | border-top-left-radius: 0; |
| | | border-bottom-left-radius: 0; |
| | | } |
| | | } |
| | | .applyStartClasses { |
| | | float: right; |
| | | } |
| | | } |
| | | .courseListBox { |
| | | overflow: hidden; |
| | | .courseItem { |
| | | float: left; |
| | | width: 46%; |
| | | margin: 0 2% 20px; |
| | | border-radius: 8px; |
| | | border: 1px solid #efefef; |
| | | overflow: hidden; |
| | | .itemHeader { |
| | | height: 40px; |
| | | line-height: 40px; |
| | | padding: 0 20px; |
| | | // color: #fff; |
| | | background-color: #f8f8f8; |
| | | .title { |
| | | font-weight: 600; |
| | | } |
| | | div { |
| | | display: inline-block; |
| | | } |
| | | .courseId { |
| | | margin-left: 6px; |
| | | font-size: 12px; |
| | | color: #999; |
| | | } |
| | | .copyIdBtn { |
| | | float: right; |
| | | height: 20px; |
| | | line-height: 20px; |
| | | margin-top: 10px; |
| | | font-size: 12px; |
| | | background-color: #fff; |
| | | color: #3b93fe; |
| | | padding: 0 6px; |
| | | border-radius: 50px; |
| | | overflow: hidden; |
| | | cursor: pointer; |
| | | } |
| | | } |
| | | .itemInfo { |
| | | padding: 20px; |
| | | flex: 1; |
| | | display: flex; |
| | | cursor: pointer; |
| | | .imgBox { |
| | | width: 90px; |
| | | height: 120px; |
| | | margin-right: 20px; |
| | | } |
| | | .infoBox { |
| | | flex: 1; |
| | | font-size: 12px; |
| | | p { |
| | | margin-bottom: 10px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .codeContent { |
| | | width: 100%; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding-bottom: 30px; |
| | | } |
| | | .classInfo { |
| | | padding: 30px 0; |
| | | border-top: 2px dashed #ccc; |
| | | |
| | | .itemCon { |
| | | margin-bottom: 20px; |
| | | } |
| | | } |
| | | .pageBox { |
| | | padding: 10px 0; |
| | | display: flex; |
| | | justify-content: center; |
| | | } |
| | | } |
| | | </style> |
| | |
| | | </svg>`, |
| | | }, |
| | | { |
| | | label: '我的图书', |
| | | label: '我的书架', |
| | | key: '3', |
| | | path: 'myBook', |
| | | icon: `<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> |
| | |
| | | <template> |
| | | <div class="myBook"> |
| | | <div class="myBook_header"> |
| | | <div class="myBook_header_title">我的课程</div> |
| | | <div class="coursePage"> |
| | | <div class="personalPage-title">我的课程</div> |
| | | <div class="headerBox"> |
| | | <div class="searchBox"> |
| | | <el-input |
| | | v-model="searchKey" |
| | | clearable |
| | | @clear="getData" |
| | | placeholder="请输入关键字" |
| | | > |
| | | <template #append> |
| | | <el-button type="primary" class="searchBtn" :icon="Search" @click="getData" /> |
| | | </template> |
| | | </el-input> |
| | | </div> |
| | | <el-button type="primary" class="applyStartClasses" @click="applyCourse" |
| | | >申请开课</el-button |
| | | > |
| | | </div> |
| | | <div class="courseListBox" v-loading="pages.loading"> |
| | | <div |
| | | class="courseItem" |
| | | v-for="(item, index) in courseList" |
| | | :key="index" |
| | | @click="gotoDetail(item)" |
| | | > |
| | | <div class="itemHeader"> |
| | | <div class="title" :title="item.name">{{ item.name }}</div> |
| | | </div> |
| | | <div class="reasonBox"> |
| | | <el-tooltip placement="right-end" effect="light" class="box-item"> |
| | | <template #content> |
| | | <div style="width: 300px" v-html="item.reason"></div> |
| | | </template> |
| | | <span v-if="item.applyState == 'Reject'" style="color: red"> |
| | | 拒绝原因:{{ item.reason != "" ? item.reason : "-" }} |
| | | </span> |
| | | </el-tooltip> |
| | | <el-button |
| | | v-if="item.applyState == 'Reject'" |
| | | type="primary" |
| | | size="small" |
| | | style="margin-left: 20px" |
| | | @click="reapplyCourse(item)" |
| | | >重新申请</el-button |
| | | > |
| | | </div> |
| | | |
| | | <div class="itemInfo"> |
| | | <div class="imgBox autoImgBox"> |
| | | <div |
| | | class="stateIcon" |
| | | v-if="item.applyState == 'Normal'" |
| | | style="background-color: #1dbd11" |
| | | > |
| | | 使用中 |
| | | </div> |
| | | <div |
| | | class="stateIcon" |
| | | v-if="item.applyState == 'WaitAudit'" |
| | | style="background-color: #ef9f29" |
| | | > |
| | | 审核中 |
| | | </div> |
| | | <div |
| | | class="stateIcon" |
| | | v-if="item.applyState == 'Reject'" |
| | | style="background-color: red" |
| | | > |
| | | 未通过 |
| | | </div> |
| | | <img :src="item.icon" /> |
| | | </div> |
| | | <div class="infoBox"> |
| | | <p class="id">ID:{{ item.id }}</p> |
| | | <div class="introduction" :title="item.introduction"> |
| | | {{ item.introduction }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="pagination-box" v-if="courseList.length > 0"> |
| | | <el-pagination |
| | | v-model:current-page="pages.page" |
| | | v-model:page-size="pages.pageSize" |
| | | :background="false" |
| | | layout="total, prev, pager, next" |
| | | :total="pages.count" |
| | | @current-change="pageChange" |
| | | /> |
| | | </div> |
| | | <div class="nullBox" v-if="!pages.loading && courseList.length == 0"> |
| | | <el-empty /> |
| | | </div> |
| | | <!-- 申请开课弹框 --> |
| | | <el-dialog v-model="applyCourseDialog" width="750" align-center> |
| | | <template #title>{{ editData ? "重新申请" : "申请开课" }}</template> |
| | | <el-form |
| | | :model="formData" |
| | | label-position="left" |
| | | ref="dialogFormRef" |
| | | label-width="80px" |
| | | > |
| | | <el-form-item |
| | | label="课程名称" |
| | | prop="name" |
| | | :rules="[{ required: true, message: '请输入课程名称' }]" |
| | | > |
| | | <el-input v-model="formData.name" placeholder="请输入课程名称" /> |
| | | </el-form-item> |
| | | <el-form-item |
| | | v-if="!editData" |
| | | label="关联教材" |
| | | prop="bookName" |
| | | :rules="[{ required: true, message: '请选择教材' }]" |
| | | > |
| | | <div style="display: flex"> |
| | | <el-input v-model="formData.bookName" disabled="true" style="width: 300px" /> |
| | | <el-button style="margin-left: 10px" @click="selectBook">选择教材</el-button> |
| | | </div> |
| | | </el-form-item> |
| | | <el-form-item label="课程介绍"> |
| | | <el-input |
| | | v-model="formData.desc" |
| | | type="textarea" |
| | | autocomplete="off" |
| | | maxlength="300" |
| | | show-word-limit |
| | | rows="7" |
| | | placeholder="请输入课程介绍" |
| | | /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button @click="applyCourseDialog = false">取消</el-button> |
| | | <el-button type="primary" @click="submit" :loading="submitLoading" |
| | | >提交</el-button |
| | | > |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- 选择教材弹框 --> |
| | | <el-dialog v-model="selectTextBookDialog" width="1000" align-center> |
| | | <template #title>选择教材</template> |
| | | <div class="textBookList" v-loading="textBookPages.loading"> |
| | | <div class="headerBox" style="padding: 10px"> |
| | | <div class="searchBox" style="float: right"> |
| | | <el-input |
| | | v-model="selectName" |
| | | @clear="getTextBook" |
| | | clearable |
| | | placeholder="请输入关键字" |
| | | > |
| | | <template #append> |
| | | <el-button |
| | | type="primary" |
| | | class="searchBtn" |
| | | :icon="Search" |
| | | @click="getTextBook" |
| | | /> |
| | | </template> |
| | | </el-input> |
| | | </div> |
| | | </div> |
| | | <div style="min-height: 370px" v-if="textBookListData.length > 0"> |
| | | <div |
| | | v-for="(item, index) in textBookListData" |
| | | :key="index" |
| | | class="textBookItem" |
| | | > |
| | | <el-checkbox |
| | | class="checkBox" |
| | | v-model="item.check" |
| | | @change="selectChange(item)" |
| | | /> |
| | | <div class="imgBox autoImgBox"> |
| | | <img :src="item.img" /> |
| | | </div> |
| | | <p>{{ item.product.name }}</p> |
| | | </div> |
| | | </div> |
| | | <div |
| | | class="nullBox" |
| | | v-if="!textBookPages.loading && textBookListData.length == 0" |
| | | > |
| | | <el-empty /> |
| | | </div> |
| | | </div> |
| | | <div class="pagination-box" v-if="textBookListData.length > 0"> |
| | | <el-pagination |
| | | v-model:current-page="textBookPages.page" |
| | | v-model:page-size="textBookPages.pageSize" |
| | | :background="false" |
| | | layout="total, prev, pager, next" |
| | | :total="textBookPages.count" |
| | | @current-change="handleCurrentChange" |
| | | /> |
| | | </div> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button @click="selectTextBookDialog = false">取消</el-button> |
| | | <el-button type="primary" @click="selectTextBookSubmit">确定</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { reactive, ref, onMounted, inject, watch } from "vue"; |
| | | import { Search } from "@element-plus/icons-vue"; |
| | | import { useRouter, useRoute } from "vue-router"; |
| | | import { ElMessage } from "element-plus"; |
| | | // eslint-disable-next-line |
| | | import { getPublicImage } from "@/assets/js/middleGround/tool.js"; |
| | | // eslint-disable-next-line |
| | | import defaultImg from "@/assets/images/default-book-img.png"; |
| | | |
| | | const router: any = useRouter(); |
| | | const route: any = useRoute(); |
| | | const MG: any = inject("MG"); |
| | | const selectName = ref(""); |
| | | |
| | | // 申请开课防抖loading |
| | | const submitLoading = ref(false); |
| | | |
| | | const courseList: any = ref([]); |
| | | |
| | | onMounted(() => { |
| | | getData(); |
| | | }); |
| | | |
| | | const searchKey = ref(""); |
| | | const pages = reactive({ |
| | | page: 1, |
| | | pageSize: 6, |
| | | count: 0, |
| | | loading: true, |
| | | }); |
| | | |
| | | // 获取课程 |
| | | const getData = () => { |
| | | pages.loading = true; |
| | | MG.edu |
| | | .getAppCourseList({ |
| | | size: pages.pageSize, |
| | | start: pages.pageSize * pages.page - pages.pageSize, |
| | | sort: { |
| | | type: "Desc", |
| | | field: "CreateDate", |
| | | }, |
| | | filterList: [], |
| | | searchList: searchKey.value |
| | | ? [ |
| | | { |
| | | keywords: searchKey.value, |
| | | field: "Name", |
| | | compareType: "Contains", |
| | | }, |
| | | ] |
| | | : [], |
| | | }) |
| | | .then((res: any) => { |
| | | pages.loading = false; |
| | | pages.count = res.totalSize; |
| | | courseList.value = res.datas.map((item: any) => { |
| | | return { |
| | | ...item, |
| | | name: item.name, |
| | | id: item.id, |
| | | icon: item.icon != "default" ? getPublicImage(item.icon, 80) : defaultImg, |
| | | introduction: item.description, |
| | | reason: item.applyReturnMsg ? JSON.parse(item.applyReturnMsg).reason : "", |
| | | }; |
| | | }); |
| | | }); |
| | | }; |
| | | |
| | | // 申请开课 |
| | | const applyCourse = () => { |
| | | editData.value = null; |
| | | formData.value = { |
| | | name: "", |
| | | bookName: "", |
| | | bookId: "", |
| | | selectData: "", |
| | | desc: "", |
| | | }; |
| | | applyCourseDialog.value = true; |
| | | }; |
| | | |
| | | const editData: any = ref(null); |
| | | const reapplyCourse = (data: any) => { |
| | | editData.value = data; |
| | | formData.value = { |
| | | name: data.name, |
| | | bookName: data.linkProduct.name, |
| | | bookId: data.linkProduct.id, |
| | | selectData: "", |
| | | desc: data.description, |
| | | }; |
| | | applyCourseDialog.value = true; |
| | | }; |
| | | |
| | | // 申请教材弹框 |
| | | const applyCourseDialog = ref(false); |
| | | const selectTextBookDialog = ref(false); |
| | | const formData = ref({ |
| | | name: "", |
| | | bookName: "", |
| | | bookId: "", |
| | | selectData: "", |
| | | desc: "", |
| | | }); |
| | | |
| | | const selectChange = (select: any) => { |
| | | for (let i = 0; i < textBookListData.value.length; i++) { |
| | | const item: any = textBookListData.value[i]; |
| | | if (item.id == select.id) { |
| | | item.check = true; |
| | | } else { |
| | | item.check = false; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const selectTextBookSubmit = () => { |
| | | const selectData: any = textBookListData.value.filter((item: any) => item.check)[0]; |
| | | if (!selectData?.product?.id) { |
| | | ElMessage.warning("请选择开课教材!"); |
| | | return false; |
| | | } |
| | | formData.value.bookId = selectData.product.id; |
| | | formData.value.bookName = selectData.product.name; |
| | | formData.value.selectData = selectData; |
| | | selectTextBookDialog.value = false; |
| | | }; |
| | | |
| | | const submit = () => { |
| | | submitLoading.value = true; |
| | | if (editData.value) { |
| | | MG.edu |
| | | .updateCourse({ |
| | | courseId: editData.value.id, |
| | | name: formData.value.name, |
| | | description: formData.value.desc, |
| | | }) |
| | | .then((res: any) => { |
| | | MG.edu |
| | | .updateCourseApply({ |
| | | courseId: editData.value.id, |
| | | applyData: JSON.stringify({ |
| | | textBookId: formData.value.bookId, |
| | | textBookName: formData.value.bookName, |
| | | }), |
| | | }) |
| | | .then((ares: any) => { |
| | | ElMessage.success("课程已重新申请,等待管理员审核。"); |
| | | applyCourseDialog.value = false; |
| | | getData(); |
| | | }); |
| | | }); |
| | | } else { |
| | | if (formData.value.name == "") { |
| | | ElMessage({ |
| | | type: "warning", |
| | | message: "请填写课程名称", |
| | | }); |
| | | submitLoading.value = false; |
| | | return false; |
| | | } |
| | | if (!formData.value.bookId) { |
| | | ElMessage({ |
| | | type: "warning", |
| | | message: "请选择关联教材", |
| | | }); |
| | | submitLoading.value = false; |
| | | return false; |
| | | } |
| | | MG.edu |
| | | .applyNewCourse({ |
| | | name: formData.value.name, |
| | | description: formData.value.desc, |
| | | content: "", |
| | | icon: formData.value.selectData.product.icon ?? "default", |
| | | type: "course", |
| | | config: "", |
| | | applyData: JSON.stringify({ |
| | | textBookId: formData.value.bookId, |
| | | textBookName: formData.value.bookName, |
| | | }), |
| | | linkProductId: formData.value.bookId, |
| | | maxClassCount: 999, |
| | | payPrice: 0, |
| | | }) |
| | | .then((res: any) => { |
| | | if (res) { |
| | | ElMessage.success("课程已申请,等待管理员审核。"); |
| | | applyCourseDialog.value = false; |
| | | getData(); |
| | | } |
| | | }); |
| | | } |
| | | formData.value.selectData = ""; |
| | | setTimeout(() => { |
| | | submitLoading.value = false; |
| | | }, 1000); |
| | | }; |
| | | |
| | | // 获取已购买的教材列表 |
| | | const textBookPages = reactive({ |
| | | page: 1, |
| | | pageSize: 12, |
| | | count: 0, |
| | | loading: false, |
| | | }); |
| | | const textBookListData = ref([]); |
| | | |
| | | const getTextBook = () => { |
| | | textBookPages.loading = true; |
| | | const searchData = [ |
| | | { |
| | | keywords: "jsek_digitalTextbooks", |
| | | field: "ProductType", |
| | | }, |
| | | { |
| | | keywords: "jsek_mediaBook", |
| | | field: "ProductType", |
| | | }, |
| | | { |
| | | keywords: selectName.value, |
| | | field: "ProductName", |
| | | }, |
| | | ]; |
| | | const data = { |
| | | Size: textBookPages.pageSize, |
| | | Start: textBookPages.pageSize * textBookPages.page - textBookPages.pageSize, |
| | | sort: { |
| | | type: "Desc", |
| | | field: "CreateDate", |
| | | }, |
| | | searchList: searchData, |
| | | }; |
| | | MG.store |
| | | .getPurchasedProductList(data) |
| | | .then((res: any) => { |
| | | textBookPages.count = res.totalSize; |
| | | textBookListData.value = res.datas.map((item: any) => { |
| | | return { |
| | | ...item, |
| | | img: item.product.icon ? getPublicImage(item.product.icon, 80) : defaultImg, |
| | | }; |
| | | }); |
| | | textBookPages.loading = false; |
| | | }) |
| | | .catch(() => { |
| | | textBookPages.loading = false; |
| | | }); |
| | | }; |
| | | |
| | | // 选择教材 |
| | | const selectBook = () => { |
| | | selectTextBookDialog.value = true; |
| | | textBookListData.value = []; |
| | | getTextBook(); |
| | | }; |
| | | |
| | | const pageChange = (val: any) => { |
| | | pages.page = val; |
| | | getData(); |
| | | }; |
| | | const handleCurrentChange = (val: any) => { |
| | | textBookPages.page = val; |
| | | getTextBook(); |
| | | }; |
| | | |
| | | const gotoDetail = (data: any) => { |
| | | if (data.applyState == "Normal") { |
| | | router.push({ |
| | | name: "courseDetail", |
| | | query: { |
| | | courseId: data.id, |
| | | }, |
| | | }); |
| | | } |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .coursePage { |
| | | .headerBox { |
| | | padding: 20px; |
| | | margin-bottom: 10px; |
| | | overflow: hidden; |
| | | |
| | | .searchBox { |
| | | width: 300px; |
| | | float: left; |
| | | |
| | | .searchBtn { |
| | | background-color: var(--el-color-primary); |
| | | color: #fff; |
| | | border-top-left-radius: 0; |
| | | border-bottom-left-radius: 0; |
| | | } |
| | | } |
| | | |
| | | .applyStartClasses { |
| | | float: right; |
| | | } |
| | | } |
| | | |
| | | .courseListBox { |
| | | overflow: hidden; |
| | | min-height: 200px; |
| | | |
| | | .courseItem { |
| | | float: left; |
| | | width: 46%; |
| | | height: 210px; |
| | | margin: 0 2% 20px; |
| | | border-radius: 8px; |
| | | border: 1px solid #efefef; |
| | | overflow: hidden; |
| | | cursor: pointer; |
| | | |
| | | .itemHeader { |
| | | height: 40px; |
| | | line-height: 40px; |
| | | padding: 0 20px; |
| | | background-color: #f8f8f8; |
| | | .title { |
| | | font-weight: 600; |
| | | } |
| | | |
| | | div { |
| | | width: 100%; |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | word-break: break-all; |
| | | } |
| | | } |
| | | |
| | | .reasonBox { |
| | | display: flex; |
| | | padding: 5px 20px; |
| | | cursor: default; |
| | | span { |
| | | font-size: 12px; |
| | | line-height: 24px; |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | } |
| | | |
| | | .itemInfo { |
| | | padding: 10px 20px; |
| | | flex: 1; |
| | | display: flex; |
| | | .imgBox { |
| | | width: 90px; |
| | | height: 120px; |
| | | margin-right: 20px; |
| | | } |
| | | .infoBox { |
| | | flex: 1; |
| | | font-size: 14px; |
| | | p { |
| | | margin-bottom: 10px; |
| | | } |
| | | .introduction { |
| | | height: 88px; |
| | | line-height: 22px; |
| | | display: -webkit-box; |
| | | -webkit-box-orient: vertical; |
| | | -webkit-line-clamp: 4; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | word-break: break-all; |
| | | } |
| | | } |
| | | .stateIcon { |
| | | position: absolute; |
| | | right: -6px; |
| | | top: -4px; |
| | | padding: 5px 8px; |
| | | color: #fff; |
| | | border-top-left-radius: 30px; |
| | | border-bottom-right-radius: 30px; |
| | | border-top-right-radius: 30px; |
| | | z-index: 99; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .textBookList { |
| | | overflow: hidden; |
| | | margin-bottom: 20px; |
| | | .textBookItem { |
| | | float: left; |
| | | width: 140px; |
| | | height: 200px; |
| | | margin: 10px; |
| | | position: relative; |
| | | border: 1px solid #eee; |
| | | padding: 20px; |
| | | box-sizing: border-box; |
| | | .checkBox { |
| | | position: absolute; |
| | | right: 0; |
| | | top: 0; |
| | | height: 14px; |
| | | ::v-deep { |
| | | .el-checkbox__inner { |
| | | border-color: #888; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .imgBox { |
| | | width: 100px; |
| | | height: 110px; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | p { |
| | | line-height: 1.2; |
| | | display: -webkit-box; |
| | | -webkit-line-clamp: 2; |
| | | -webkit-box-orient: vertical; |
| | | overflow: hidden; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .pagination-box { |
| | | display: flex; |
| | | justify-content: center; |
| | | padding: 10px 0; |
| | | } |
| | | |
| | | .nullBox { |
| | | text-align: center; |
| | | margin-top: 30px; |
| | | font-size: 20px; |
| | | color: #ccc; |
| | | } |
| | | </style> |
| | |
| | | <!-- 基本信息 --> |
| | | <template> |
| | | <div>我的申请</div> |
| | | <div class="personalPage-box"> |
| | | <div class="personalPage-title">我的申请</div> |
| | | <div class="personalPage-content"> |
| | | <div class="tipsText"> |
| | | <div> |
| | | 如您在教材试用申请过程中遇到问题,请于工作时间联系我们。<span class="phone"> |
| | | QQ号:3565269931 / 咨询电话010-65778403(工作时间:9:00~17:00) |
| | | </span> |
| | | </div> |
| | | </div> |
| | | <div class="stageBtm" v-for="(item, index) in listData" :key="index"> |
| | | <div class="infor"> |
| | | <div class="infoBox"> |
| | | <div> |
| | | 审核状态: |
| | | <span |
| | | :class="{ |
| | | reviewstatus: true, |
| | | reviewstatusRed: item.state == 'Reject', |
| | | reviewstatusWait: item.state == 'WaitAudit', |
| | | }" |
| | | >{{ |
| | | item.state == "WaitAudit" |
| | | ? "审核中" |
| | | : item.state == "Normal" |
| | | ? "通过" |
| | | : "拒绝" |
| | | }}</span |
| | | > |
| | | </div> |
| | | <div |
| | | style="color: orangered" |
| | | v-if="item.state == 'Normal' && item.feedBack && !item.isExpiry" |
| | | > |
| | | 试用期限:<span>{{ item.updateDate }}</span> -- |
| | | <span>{{ item.feedBack.endDate }}</span> |
| | | </div> |
| | | <div style="color: orangered" v-if="item.isExpiry"> |
| | | 阅读期限:<span>已过期</span> |
| | | </div> |
| | | <div class="time">申请时间:{{ item.updateDate }}</div> |
| | | </div> |
| | | <div |
| | | class="reasonForFailure" |
| | | style="margin: 10px 0" |
| | | v-if="item.state == 'Reject'" |
| | | > |
| | | <div class="centerVertically">未通过原因:</div> |
| | | <div |
| | | style="flex: 1" |
| | | class="ellipsis-3" |
| | | :title="item.feedBack.reason ? item.feedBack.reason : ' - '" |
| | | > |
| | | {{ item.feedBack.reason ? item.feedBack.reason : " - " }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="contentInfoBox"> |
| | | <div class="listImg"> |
| | | <img @click.stop="toDetail(item.content)" :src="item.content.icon" alt="" /> |
| | | <div class="name" :title="item.content.title"> |
| | | {{ item.content.title }} |
| | | </div> |
| | | <el-button |
| | | size="mini" |
| | | v-if="item.state == 'Normal' && !item.isExpiry" |
| | | @click="read(item.content)" |
| | | >开始阅读</el-button |
| | | > |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div |
| | | style="min-height: 100px" |
| | | v-if="listData && listData.length > 0" |
| | | v-loading="loading" |
| | | ></div> |
| | | </div> |
| | | <div v-if="listData && listData.length == 0 && !loading"> |
| | | <el-empty :image-size="200" description="暂无内容"></el-empty> |
| | | </div> |
| | | <div class="pageBox" v-if="listData && listData.length > 0"> |
| | | <!-- 分页 --> |
| | | <el-pagination |
| | | background |
| | | :current-page="paginationData.page - 0" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" |
| | | :page-size="paginationData.limit" |
| | | layout="total, prev, pager, next, slot" |
| | | :total="paginationData.totalCount" |
| | | > |
| | | <div style="display: inline-block"> |
| | | <span class="el-pagination__jump" |
| | | >前往 |
| | | <div class="el-input el-pagination__editor is-in-pagination"> |
| | | <input |
| | | type="number" |
| | | autocomplete="off" |
| | | min="1" |
| | | :max="paginationData.totalPage" |
| | | v-model="inputPage" |
| | | class="el-input__inner" |
| | | @keyup.enter="jumpFun($event)" |
| | | /> |
| | | </div> |
| | | 页 |
| | | </span> |
| | | <el-button type="primary" class="toBtn" @click="jumpFun">确定</el-button> |
| | | </div> |
| | | </el-pagination> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | <script setup lang="ts"> |
| | | import { reactive, ref, onMounted, inject } from "vue"; |
| | | import { getPublicImage } from "@/assets/js/middleGround/tool"; |
| | | const MG: any = inject("MG"); |
| | | const config: any = inject("config"); |
| | | const crumbStore = inject("crumbStore"); |
| | | const router = inject("router"); |
| | | let listData = ref([]); |
| | | let loading = ref(false); |
| | | let paginationData = reactive({ |
| | | page: 1, |
| | | limit: 10, |
| | | totalCount: 0, |
| | | totalPage: 0, |
| | | }); |
| | | let inputPage = ref(1); |
| | | |
| | | const getTextBookList = () => { |
| | | loading.value = true; |
| | | let { page, limit } = paginationData; |
| | | const data = { |
| | | start: limit * page - limit, |
| | | size: limit, |
| | | topicIdOrRefCode: "applyDigitalBook", |
| | | appRefCode: config.appRefCode, |
| | | sort: { |
| | | type: "Desc", |
| | | field: "CreateDate", |
| | | }, |
| | | }; |
| | | MG.ugc.getTopicMessageList(data).then((res) => { |
| | | loading.value = false; |
| | | res.datas.forEach((item) => { |
| | | item.icon = item.icon ? item.icon : getPublicImage(null); |
| | | item.updateDate = item.updateDate.split("T")[0]; |
| | | if (item.feedBack) { |
| | | item.feedBack = JSON.parse(item.feedBack); |
| | | if (item.feedBack.endDate) { |
| | | let times = new Date(item.feedBack.endDate + " 23:59:59").getTime(); |
| | | if (times < sessionStorage.currentDate) { |
| | | item.isExpiry = true; |
| | | } |
| | | } |
| | | } |
| | | if (item.content) { |
| | | item.content = JSON.parse(item.content)[0] ?? {}; |
| | | if (!item.content?.icon) { |
| | | item.content.icon = require("@/assets/images/default-book-img.png"); |
| | | } |
| | | } |
| | | }); |
| | | paginationData.totalCount = res.totalSize; |
| | | paginationData.totalPage = Math.ceil(res.totalSize / limit); |
| | | listData.value = res.datas; |
| | | }); |
| | | }; |
| | | onMounted(() => { |
| | | getTextBookList(); |
| | | }); |
| | | |
| | | const toDetail = (item: any) => { |
| | | const thisCrumbs = [{ name: "书籍详情", pathName: "digitalTextbooks-textbooksDetail" }]; |
| | | MG.store.dispatch("setCrumbs", { |
| | | type: "textbooks", |
| | | data: thisCrumbs, |
| | | callback: (key: string) => { |
| | | MG.router.push({ |
| | | name: "digitalTextbooks-textbooksDetail", |
| | | query: { |
| | | id: item.id, |
| | | rootCmsItemId: item.rootCmsItemId, |
| | | crumbsKey: key, |
| | | }, |
| | | }); |
| | | }, |
| | | }); |
| | | }; |
| | | const read = (pItem: any) => { |
| | | let token = MG.tool.getCookie(config.tokenKey); |
| | | window.open(config.textReaderUrl + "?bookId=" + pItem.refCode + "&token=" + token); |
| | | }; |
| | | const handleSizeChange = (val: number) => { |
| | | paginationData.limit = val; |
| | | getTextBookList(); |
| | | }; |
| | | const handleCurrentChange = (val: number) => { |
| | | paginationData.page = val; |
| | | getTextBookList(); |
| | | }; |
| | | const jumpFun = (event: any) => { |
| | | event.target.blur(); |
| | | if (inputPage.value <= 0) { |
| | | inputPage.value = 1; |
| | | } |
| | | if (inputPage.value > paginationData.totalPage) { |
| | | inputPage.value = paginationData.totalPage; |
| | | } |
| | | paginationData.page = inputPage.value; |
| | | getTextBookList(); |
| | | }; |
| | | </script> |
| | | <style scoped lang="less"> |
| | | .myCarTopPage { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 10px 15px; |
| | | box-sizing: border-box; |
| | | background-color: #fff; |
| | | border-bottom: 1px solid #dcdcdc; |
| | | } |
| | | .tipsText { |
| | | padding: 10px 15px; |
| | | line-height: 20px; |
| | | box-sizing: border-box; |
| | | border: 1px solid #ccc; |
| | | .phone { |
| | | color: #019e58; |
| | | } |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .pageBox { |
| | | background-color: #fff; |
| | | margin-top: 50px; |
| | | } |
| | | .stageBtm { |
| | | border: 1px solid #dcdcdc; |
| | | .infor { |
| | | border-bottom: 1px solid #dcdcdc; |
| | | padding: 0 15px; |
| | | .infoBox { |
| | | line-height: 45px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | .time { |
| | | color: #999; |
| | | } |
| | | } |
| | | .reasonForFailure { |
| | | display: flex; |
| | | margin: 10px 0; |
| | | line-height: 1.5; |
| | | .centerVertically { |
| | | width: 80px; |
| | | } |
| | | /* 双行省略 */ |
| | | .ellipsis-3 { |
| | | text-overflow: -o-ellipsis-lastline; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | display: -webkit-box; |
| | | -webkit-line-clamp: 3; |
| | | line-clamp: 3; |
| | | -webkit-box-orient: vertical; |
| | | } |
| | | } |
| | | } |
| | | .contentInfoBox { |
| | | padding: 15px; |
| | | box-sizing: border-box; |
| | | .listImg { |
| | | display: inline-block; |
| | | margin-right: 60px; |
| | | width: 120px; |
| | | img { |
| | | width: 120px; |
| | | cursor: pointer; |
| | | } |
| | | .name { |
| | | line-height: 27px; |
| | | font-size: 15px; |
| | | color: #333; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .reviewstatus { |
| | | color: #0bc266; |
| | | } |
| | | .reviewstatusWait { |
| | | color: #ffbe00; |
| | | } |
| | | .reviewstatusRed { |
| | | color: red; |
| | | } |
| | | |
| | | .timer { |
| | | color: rgb(240, 67, 67); |
| | | } |
| | | </style> |
| | | <style> |
| | | .el-pagination { |
| | | text-align: center; |
| | | margin-top: 15px; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div class="myBook"> |
| | | <div class="myBook_header"> |
| | | <div class="myBook_header_title">我的订单</div> |
| | | <div class="personalPage-box"> |
| | | <div class="personalPage-title">我的书架</div> |
| | | <div class="personalPage-content"> |
| | | <div class="pageBox cartPage" v-loading="isLoading"> |
| | | <div class="myCarTopPage" v-if="collectList.length > 0"> |
| | | <div |
| | | class="bookone" |
| | | v-for="(item, index) in collectList" |
| | | :key="index" |
| | | @click="goDetail(item)" |
| | | > |
| | | <div class="imgBox"> |
| | | <img :src="item.product.icon" alt /> |
| | | </div> |
| | | <div class="details"> |
| | | <div class="text-flow" v-if="item.product.name"> |
| | | {{ item.product.name || "-" }} |
| | | </div> |
| | | <div class="text-flow" :title="item.tourism_ISBN"> |
| | | ISBN:{{ item.tourism_ISBN.length != 0 ? item.tourism_ISBN : "-" }} |
| | | </div> |
| | | <div class="text-flow"> |
| | | 作者:{{ item.tourism_author.length != 0 ? item.tourism_author : "-" }} |
| | | </div> |
| | | <!-- <div class="text-flow" v-if="item.ExpiryDate"> |
| | | 截止日期:<span style="color: #dd0000">{{ item.ExpiryDate }}</span> |
| | | </div> --> |
| | | </div> |
| | | </div> |
| | | <div class="pageCon"> |
| | | <!-- 分页 --> |
| | | <el-pagination |
| | | background |
| | | :current-page="paginationData.page - 0" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" |
| | | :page-size="paginationData.limit" |
| | | layout="total, prev, pager, next, slot" |
| | | :total="paginationData.totalCount" |
| | | > |
| | | <div style="display: inline-block"> |
| | | <span class="el-pagination__jump" |
| | | >前往 |
| | | <div class="el-input el-pagination__editor is-in-pagination"> |
| | | <input |
| | | type="number" |
| | | autocomplete="off" |
| | | min="1" |
| | | :max="paginationData.totalPage" |
| | | v-model="inputPage" |
| | | class="el-input__inner" |
| | | @keyup.enter="jumpFun($event)" |
| | | /> |
| | | </div> |
| | | 页 |
| | | </span> |
| | | <el-button type="primary" class="toBtn" @click="jumpFun">确定</el-button> |
| | | </div> |
| | | </el-pagination> |
| | | </div> |
| | | </div> |
| | | <div class="myCarTopPage" v-else> |
| | | <el-empty description="您还未购买任何图书" :image-size="200" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | import { reactive, ref, onMounted, inject, watch } from "vue"; |
| | | import { useRouter } from "vue-router"; |
| | | import { useUserStore, useBreadcrumbStore } from "@/store"; |
| | | import tool from "@/assets/js/toolClass"; |
| | | const MG: any = inject("MG"); |
| | | const config: any = inject("config"); |
| | | const router = useRouter(); |
| | | const crumbStore = useBreadcrumbStore(); |
| | | let collectList = ref([]); |
| | | let currentCollect = ref("book"); |
| | | let isLoading = ref(false); |
| | | let pages = reactive({ |
| | | page: 1, |
| | | pageSize: 10, |
| | | count: 0, |
| | | loading: false, |
| | | }); |
| | | let linkType = ref("PurchasedProduct"); |
| | | let paginationData = reactive({ |
| | | page: 1, |
| | | limit: 10, |
| | | totalCount: 0, |
| | | totalPage: 0, |
| | | }); |
| | | let inputPage = ref(1); |
| | | const loading = ref(false); |
| | | const listData = ref([]); |
| | | const keyQueryRequests = [ |
| | | { |
| | | key: "author", |
| | | }, |
| | | { |
| | | key: "isbn", |
| | | }, |
| | | ]; |
| | | |
| | | const getData = () => { |
| | | loading.value = true; |
| | | const searchData = [ |
| | | { |
| | | keywords: "digitalTextbooks", |
| | | field: "ProductType", |
| | | }, |
| | | ]; |
| | | const data = { |
| | | Size: paginationData.limit, |
| | | Start: (paginationData.page - 1) * paginationData.limit, |
| | | sort: { |
| | | type: "Desc", |
| | | field: "CreateDate", |
| | | }, |
| | | searchList: searchData, |
| | | keyQueryRequests: keyQueryRequests, |
| | | }; |
| | | MG.store.getPurchasedProductList(data).then(async (response) => { |
| | | listData.value = handResultsChange(response.datas); |
| | | listData.value.forEach((item) => { |
| | | item.product.icon = tool.getPublicImage(item.product.icon); |
| | | }); |
| | | // console.log(that.collectList); |
| | | // //当前页面 |
| | | paginationData.totalCount = response.totalSize; |
| | | paginationData.totalPage = |
| | | response.totalSize % paginationData.limit === 0 |
| | | ? response.totalSize / paginationData.limit |
| | | : Math.floor(response.totalSize / paginationData.limit) + 1; |
| | | loading.value = false; |
| | | }); |
| | | }; |
| | | onMounted(() => { |
| | | getData(); |
| | | }); |
| | | // 处理查询结果 |
| | | const handResultsChange = (data) => { |
| | | let fieldsData = []; |
| | | for (let i = 0; i < data.length; i++) { |
| | | const item = data[i]; |
| | | for (const val in keyQueryRequests) { |
| | | fieldsData.push(keyQueryRequests[val].key); |
| | | } |
| | | for (let i = 0; i < fieldsData.length; i++) { |
| | | const field = fieldsData[i]; |
| | | item[field] = JSON.parse(item.datas[field]); |
| | | const datas = item[field]; |
| | | if (datas.length > 0) { |
| | | if (datas[0].Value) { |
| | | item[field] = datas[0].Value; |
| | | } else if (datas[0].Data) { |
| | | item[field] = datas[0].Data.Value; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return data; |
| | | }; |
| | | |
| | | //到图书详情 |
| | | const goDetail = (item) => { |
| | | let crumbs = [ |
| | | { |
| | | name: "教材详情", |
| | | }, |
| | | ]; |
| | | crumbStore.dispatch("setCrumbs", { |
| | | type: "textbooks", |
| | | data: crumbs, |
| | | callback: (key) => { |
| | | router.push({ |
| | | name: "digitalTextbooks-textbooksDetail", |
| | | query: { |
| | | id: item.product.id, |
| | | rootCmsItemId: item.product.rootCmsItemId, |
| | | crumbsKey: key, |
| | | }, |
| | | }); |
| | | }, |
| | | }); |
| | | }; |
| | | |
| | | //分页 |
| | | const handleSizeChange = (val) => { |
| | | paginationData.limit = val; |
| | | getData(); |
| | | }; |
| | | const handleCurrentChange = (val) => { |
| | | paginationData.page = val; |
| | | inputPage.value = val; |
| | | getData(); |
| | | }; |
| | | const jumpFun = (event) => { |
| | | event.target.blur(); |
| | | var that = this; |
| | | if (inputPage.value <= 0) { |
| | | inputPage.value = 1; |
| | | } |
| | | if (inputPage.value > paginationData.totalPage) { |
| | | inputPage.value = paginationData.totalPage; |
| | | } |
| | | paginationData.page = inputPage.value; |
| | | getData(); |
| | | }; |
| | | </script> |
| | | <style scoped> |
| | | .pageCon { |
| | | width: 100%; |
| | | float: left; |
| | | margin-top: 20px; |
| | | display: flex; |
| | | justify-content: center; |
| | | } |
| | | .myCarTopPage { |
| | | box-sizing: border-box; |
| | | overflow: hidden; |
| | | padding-bottom: 20px; |
| | | } |
| | | .details div:first-child { |
| | | font-size: 16px; |
| | | color: #2b68cd; |
| | | margin-bottom: 11px; |
| | | } |
| | | |
| | | .details div:nth-child(2) { |
| | | font-size: 14px; |
| | | color: #666; |
| | | margin: 15px 0; |
| | | } |
| | | |
| | | .details div:nth-child(3) { |
| | | margin-bottom: 11px; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | .details div:last-child { |
| | | font-size: 14px; |
| | | color: #666666; |
| | | } |
| | | .resonBox { |
| | | display: flex; |
| | | line-height: 24px; |
| | | } |
| | | .resonTxt { |
| | | flex: 1; |
| | | overflow: hidden; |
| | | line-height: 24px; |
| | | text-overflow: ellipsis; |
| | | display: -webkit-box; |
| | | -webkit-line-clamp: 3; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .bookoneTitle { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding-bottom: 10px; |
| | | border-bottom: 1px solid #ddd; |
| | | } |
| | | .bookone { |
| | | display: flex; |
| | | width: 478px; |
| | | min-height: 173px; |
| | | float: left; |
| | | cursor: pointer; |
| | | box-sizing: border-box; |
| | | margin: 20px 0px 0 20px; |
| | | padding: 10px 30px; |
| | | border: 1px solid #ddd; |
| | | } |
| | | .bookone:hover { |
| | | -moz-box-shadow: 4px 3px 6px rgba(0, 0, 0, 0.3); |
| | | -webkit-box-shadow: 4px 3px 6px rgba(0, 0, 0, 0.3); |
| | | box-shadow: 4px 3px 6px rgba(0, 0, 0, 0.3); |
| | | } |
| | | |
| | | .bookone .imgBox { |
| | | position: relative; |
| | | width: 120px; |
| | | height: 160px; |
| | | background: #fff; |
| | | } |
| | | .newBookli .imgBox { |
| | | position: relative; |
| | | width: 105px; |
| | | height: 140px; |
| | | } |
| | | |
| | | .imgBox img { |
| | | width: auto; |
| | | height: auto; |
| | | max-width: 100%; |
| | | max-height: 100%; |
| | | position: absolute; |
| | | top: 0; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | margin: auto; |
| | | } |
| | | |
| | | .details { |
| | | flex: 1; |
| | | margin-left: 10px; |
| | | margin-top: 10px; |
| | | overflow: hidden; |
| | | } |
| | | .pageBox { |
| | | width: 100%; |
| | | } |
| | | .noDataTxt { |
| | | margin: 50px auto; |
| | | text-align: center; |
| | | font-size: 22px; |
| | | color: #999; |
| | | } |
| | | .el-pagination button { |
| | | margin-left: 10px; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div>购物车</div> |
| | | <div class="personalPage-box"> |
| | | <div class="personalPage-title">我的购物车</div> |
| | | <div class="personalPage-content"> |
| | | <div class="deleteBox"> |
| | | <el-dialog |
| | | v-model="dialogVisible" |
| | | width="30%" |
| | | draggable |
| | | align-center |
| | | :modal="false" |
| | | > |
| | | <span> |
| | | <el-icon style="color: orange"> <Warning /> </el-icon |
| | | >确认要删除选中的商品吗?</span |
| | | > |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="dialogVisible = false">取消</el-button> |
| | | <el-button type="primary" @click="handleDelete"> 确定 </el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <el-dialog v-model="showHide" width="30%" draggable align-center :modal="false"> |
| | | <span |
| | | ><el-icon style="color: orange"> <Warning /> </el-icon |
| | | >确认要删除选中的商品吗?</span |
| | | > |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="showHide = false">取消</el-button> |
| | | <el-button type="primary" @click="confirmEvent"> 确定 </el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | |
| | | <div class="breadcrumbsBox"> |
| | | <p> |
| | | 位置: <span>购物车({{ total }})</span> |
| | | </p> |
| | | </div> |
| | | <div class="selectproduct"> |
| | | <el-table |
| | | ref="multipleTableRef" |
| | | :data="shoppingCartData" |
| | | style="width: 100%" |
| | | @selection-change="handleSelectionChange" |
| | | :cell-style="cellStyle" |
| | | v-loading="loading" |
| | | > |
| | | <template v-slot:empty> |
| | | <el-empty class="noData" image-size="100" description="暂无数据" /> |
| | | </template> |
| | | |
| | | <el-table-column type="selection" width="30" /> |
| | | |
| | | <el-table-column label="全选" width="200"> |
| | | <template #default="scope"> |
| | | <div style="position: relative; width: 110px"> |
| | | <el-image |
| | | :src="scope.row.imgUrl ? scope.row.imgUrl : defaultImg" |
| | | class="bookImg" |
| | | > |
| | | </el-image> |
| | | <div |
| | | class="labelBox" |
| | | :style="{ |
| | | background: scope.row.type == 'product' ? '#019e58 ' : '#5f92fd', |
| | | }" |
| | | > |
| | | <p>{{ scope.row.typeTxt }}</p> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | |
| | | <el-table-column |
| | | property="name" |
| | | label="商品信息" |
| | | width="300" |
| | | :cell-style="{ margin: '30px' }" |
| | | /> |
| | | <el-table-column property="productType" label="商品类型" width="300" /> |
| | | <el-table-column label="价格"> |
| | | <template #default="scope">¥{{ scope.row.unitprice.toFixed(2) }}</template> |
| | | </el-table-column> |
| | | <el-table-column label="操作"> |
| | | <template #default="scope"> |
| | | <span @click="dialog(scope.$index, scope.row)" class="deleteBtn">删除</span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </div> |
| | | <div class="settlement"> |
| | | <div class="box"> |
| | | <div class="gaugeOutfit"> |
| | | <div class="leftBox"> |
| | | <el-checkbox |
| | | v-if="shoppingCartData.length" |
| | | class="checkbox" |
| | | v-model="selectAll" |
| | | label="全选" |
| | | name="type" |
| | | @change="toggleAllSelection" |
| | | /> |
| | | <el-checkbox |
| | | v-else |
| | | class="checkbox" |
| | | v-model="select" |
| | | disabled |
| | | label="全选" |
| | | name="type" |
| | | @change="toggleAllSelection" |
| | | /> |
| | | <el-button class="buttonBox" @click="batchDelete">批量删除</el-button> |
| | | </div> |
| | | |
| | | <div class="rightBox"> |
| | | <p> |
| | | 已选择 <span>{{ selectedItemCount }}</span> 件商品 |
| | | </p> |
| | | <p> |
| | | 总价:<span v-if="sumUnitprice">¥{{ sumUnitprice.toFixed(2) }}</span> |
| | | <span v-else>¥0.00</span> |
| | | </p> |
| | | <el-button class="button" type="warning" @click="goPaymentPage" |
| | | >结算</el-button |
| | | > |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { onMounted, ref, inject, watch } from "vue"; |
| | | import { ElTable, ElMessage } from "element-plus"; |
| | | import { reactive } from "vue"; |
| | | import { useRouter } from "vue-router"; |
| | | import { InfoFilled } from "@element-plus/icons-vue"; |
| | | import { useUserStore, useBreadcrumbStore } from "@/store"; |
| | | import { getPublicImage } from "@/assets/js/middleGround/tool.js"; |
| | | import defaultImg from "@/assets/images/default-book-img.png"; |
| | | const dialogVisible = ref(false); |
| | | const crumbStore = useBreadcrumbStore(); |
| | | const router = useRouter(); |
| | | const userStore = useUserStore(); |
| | | const MG = inject("MG"); |
| | | const total = ref(); |
| | | const multipleTableRef = ref(); |
| | | const loading = ref(true); |
| | | const selectAll = ref(false); |
| | | const multipleSelection = ref([]); |
| | | const orderNumber = ref(); |
| | | const select = ref(false); |
| | | const showHide = ref(false); |
| | | const selectedItemCount = ref(0); // 新增一个变量用于存储已选商品数量 |
| | | const sumUnitprice = ref(); |
| | | |
| | | watch(multipleSelection, (newSelection) => { |
| | | // 当 multipleSelection.value 发生变化时触发的回调函数 |
| | | let sum = 0; |
| | | newSelection.forEach((item) => { |
| | | sum += item.unitprice; |
| | | }); |
| | | |
| | | sumUnitprice.value = sum; |
| | | |
| | | selectedItemCount.value = newSelection.length; |
| | | }); |
| | | |
| | | onMounted(() => { |
| | | shoppingCartGet(); |
| | | // totalPrice() |
| | | }); |
| | | const batchDelete = (evt) => { |
| | | let target = evt.target; |
| | | if (target.nodeName == "SPAN") { |
| | | target = evt.target.parentNode; |
| | | } |
| | | target.blur(); |
| | | if (multipleSelection.value.length === 0) { |
| | | // 如果没有选择任何商品,可以在此处给出提示或者直接返回 |
| | | ElMessage({ |
| | | message: "未选择商品", |
| | | type: "warning", |
| | | }); |
| | | } else { |
| | | showHide.value = true; |
| | | // showHide.value = false |
| | | } |
| | | }; |
| | | |
| | | const handleSelectionChange = (val) => { |
| | | // console.log(val); |
| | | |
| | | multipleSelection.value = val; |
| | | // 判断是否全部选择 |
| | | if (!delShoppingSelec.value) { |
| | | if (val.length === shoppingCartData.length) { |
| | | selectAll.value = true; |
| | | } else { |
| | | selectAll.value = false; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | // 切换所有行选中状态的方法 |
| | | const toggleAllSelection = () => { |
| | | if (shoppingCartData.length === 0) { |
| | | selectAll.value = false; |
| | | |
| | | ElMessage({ |
| | | message: "没有可选择的商品", |
| | | type: "warning", |
| | | }); |
| | | } else { |
| | | multipleTableRef.value.toggleAllSelection(); |
| | | } |
| | | }; |
| | | const selectedRow = ref(); |
| | | const dialog = (index, row) => { |
| | | dialogVisible.value = true; |
| | | |
| | | // 将当前行数据存储起来,以备删除时使用 |
| | | selectedRow.value = row; |
| | | }; |
| | | |
| | | const handleDelete = () => { |
| | | const row = selectedRow.value; |
| | | dialogVisible.value = false; |
| | | MG.store |
| | | .delShoppingCart({ |
| | | ids: [row.id], |
| | | }) |
| | | .then((res) => { |
| | | shoppingCartGet(); |
| | | ElMessage({ |
| | | message: "删除成功", |
| | | type: "success", |
| | | }); |
| | | //更新购物车数量 |
| | | userStore.updateRightPop(); |
| | | }) |
| | | .catch((error) => { |
| | | ElMessage.error("删除失败"); |
| | | }); |
| | | }; |
| | | |
| | | //表单的样式 |
| | | const cellStyle = ({ row, column, rowIndex, columnIndex }) => { |
| | | if (columnIndex === 4) { |
| | | return { color: "#FF6C00" }; |
| | | } |
| | | }; |
| | | |
| | | const shoppingCartData = reactive([]); |
| | | |
| | | const shoppingCartGet = () => { |
| | | let query = { |
| | | start: 0, |
| | | size: 999, |
| | | filterList: [], |
| | | searchList: [], |
| | | }; |
| | | MG.store.getShoppingCartProductList(query).then((res) => { |
| | | const newData = res.datas.map((item) => { |
| | | console.log(item.saleMethod.type, "item.saleMethod.type"); |
| | | if (item.productMonWithLinkDto.links[0].storeRefCode == "jsek_digitalTextbooks") { |
| | | item.typeTxt = "数字教材"; |
| | | item.productType = "数字教材"; |
| | | } else if ( |
| | | item.productMonWithLinkDto.links[0].storeRefCode == "jsek_digitalCourses" |
| | | ) { |
| | | item.typeTxt = "数字课程"; |
| | | item.productType = "数字课程"; |
| | | } else { |
| | | item.typeTxt = "电子书"; |
| | | item.productType = "图书服务-电子书"; |
| | | } |
| | | |
| | | // console.log(item.saleMethod.id); |
| | | console.log(item.saleMethod.type, "item.saleMethod.type"); |
| | | return { |
| | | saleMethodId: item.saleMethod.id, |
| | | id: item.id, |
| | | name: |
| | | item.linkCmsItems.length && item.linkCmsItems[0].name |
| | | ? item.productMonWithLinkDto.product.name + ":" + item.linkCmsItems[0].name |
| | | : item.productMonWithLinkDto.product.name, |
| | | type: item.saleMethod.type == "createProductItemSaleMethod" ? "item" : "product", |
| | | typeTxt: item.typeTxt, |
| | | productType: item.productType, |
| | | imgUrl: getPublicImage(item.productMonWithLinkDto.product.icon, "", "160"), |
| | | unitprice: item.saleMethod.price, |
| | | expire: |
| | | new Date(item.saleMethod.endDate).getTime() < new Date().getTime() || |
| | | new Date().getTime() < new Date(item.saleMethod.beginDate).getTime() |
| | | ? true |
| | | : false, |
| | | }; |
| | | }); |
| | | |
| | | // 重新赋值 shoppingCartData.value |
| | | shoppingCartData.splice(0, shoppingCartData.length, ...newData); |
| | | loading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | //跳转面包屑 |
| | | const goPaymentPage = async () => { |
| | | try { |
| | | // console.log(multipleSelection.value, 346588998) |
| | | let expire = multipleSelection.value.filter((item) => item.expire == true); |
| | | if (expire.length > 0) { |
| | | ElMessage({ |
| | | message: "您选择的商品有不在有效期内的,请重新选择可购买商品!", |
| | | type: "warning", |
| | | }); |
| | | } else { |
| | | const selectedIds = multipleSelection.value.map((item) => item.id); |
| | | const saleMethodId = multipleSelection.value.map((item) => item.saleMethodId); |
| | | |
| | | console.log(saleMethodId, 789); |
| | | |
| | | let queryCreateOrder = { linkIds: selectedIds }; |
| | | const createOrderResult = await MG.store.shoppingCartCreateOrder(queryCreateOrder); |
| | | orderNumber.value = createOrderResult.orderNumber; |
| | | |
| | | if (selectedIds.length) { |
| | | let crumbs = { |
| | | name: "订单支付", // 面包屑名称 |
| | | pathName: "paymentPage", // 面包屑跳转路由,可传递 pathName 或 path |
| | | isCrumbs: true, // 面包屑点击跳转时是否创建新的面包屑记录 |
| | | type: "shoppingCart", // 如果需要创建新的面包屑记录,创建的type |
| | | }; |
| | | // 在全局数据中设置面包屑 |
| | | crumbStore.setCrumbs({ |
| | | type: "shoppingCart", |
| | | data: [crumbs], |
| | | callback: (key) => { |
| | | router.push({ |
| | | name: "paymentPage", |
| | | query: { |
| | | crumbsKey: key, |
| | | orderNumber: orderNumber.value, |
| | | // type: route.query.type, |
| | | type: "shoppingCart", |
| | | onNorderSaleMethod: saleMethodId, |
| | | }, |
| | | }); |
| | | }, |
| | | }); |
| | | } else { |
| | | ElMessage({ |
| | | message: "请选择商品", |
| | | type: "warning", |
| | | }); |
| | | } |
| | | } |
| | | } catch (error) { |
| | | console.error(error); |
| | | // 错误处理逻辑 |
| | | } |
| | | }; |
| | | |
| | | const delShoppingSelec = ref(); |
| | | |
| | | const confirmEvent = () => { |
| | | showHide.value = false; |
| | | if (multipleSelection.value.length === 0) { |
| | | // 如果没有选择任何商品,可以在此处给出提示或者直接返回 |
| | | return; |
| | | } else { |
| | | const selectedIds = multipleSelection.value.map((item) => item.id); |
| | | MG.store |
| | | .delShoppingCart({ ids: selectedIds }) |
| | | .then((res) => { |
| | | delShoppingSelec.value = res; |
| | | ElMessage({ |
| | | message: "批量删除成功", |
| | | type: "success", |
| | | }); |
| | | selectAll.value = false; |
| | | // 删除成功后,刷新购物车列表 |
| | | shoppingCartGet(); |
| | | //更新购物车数量 |
| | | userStore.updateRightPop(); |
| | | }) |
| | | .catch((error) => { |
| | | console.error("批量删除失败", error); |
| | | ElMessage.error("批量删除失败"); |
| | | }); |
| | | } |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .deleteBtn { |
| | | cursor: pointer; |
| | | color: #019e58; |
| | | } |
| | | |
| | | page { |
| | | position: relative; |
| | | min-height: calc(100vh - 430px); |
| | | } |
| | | |
| | | .bookImg { |
| | | box-shadow: 0px 3px 6px 1px rgba(0, 0, 0, 0.16); |
| | | |
| | | /deep/ .el-image__inner { |
| | | object-fit: contain !important; |
| | | } |
| | | } |
| | | |
| | | .settlement { |
| | | width: 100%; |
| | | box-shadow: 0px -2px 10px 1px rgba(0, 0, 0, 0.08); |
| | | |
| | | position: sticky; |
| | | |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | background-color: #fff; |
| | | z-index: 2; |
| | | |
| | | .box { |
| | | position: relative; |
| | | |
| | | .gaugeOutfit { |
| | | padding-left: 12px; |
| | | box-shadow: 0px -2px 5px 1px rgba(0, 0, 0, 0.02); |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | position: sticky; |
| | | top: 0; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | z-index: 2; |
| | | background-color: #fff; |
| | | height: 60px; |
| | | |
| | | .leftBox { |
| | | display: flex; |
| | | flex-direction: row; |
| | | |
| | | .checkbox { |
| | | margin-right: 20px; |
| | | } |
| | | |
| | | /deep/ .el-checkbox__input.is-checked + .el-checkbox__label { |
| | | color: #000 !important; |
| | | } |
| | | } |
| | | |
| | | .rightBox { |
| | | display: flex; |
| | | flex-direction: row; |
| | | align-items: center; |
| | | |
| | | p { |
| | | margin: 0 10px; |
| | | font-size: 14px; |
| | | |
| | | span { |
| | | color: #019e58; |
| | | font-size: 18px; |
| | | } |
| | | } |
| | | |
| | | .button { |
| | | margin-left: 50px; |
| | | background-color: #019e58; |
| | | width: 150px; |
| | | height: 50px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .selected { |
| | | display: flex; |
| | | justify-content: center; |
| | | height: 200px; |
| | | min-width: 1370px; |
| | | width: 1370px; |
| | | margin: 0 auto; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .selectproduct { |
| | | margin-top: 30px; |
| | | } |
| | | |
| | | ::v-deep { |
| | | .el-checkbox__label { |
| | | margin-left: 6px; |
| | | color: #000; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | .el-table td.el-table__cell div { |
| | | margin-right: 20px; |
| | | } |
| | | |
| | | .el-table th { |
| | | background-color: #f3f3f3; |
| | | color: #000; |
| | | } |
| | | |
| | | .el-table td { |
| | | color: #333333; |
| | | } |
| | | |
| | | .el-table--enable-row-transition .el-table__body td.el-table__cell { |
| | | height: 180px; |
| | | } |
| | | |
| | | .el-checkbox__inner { |
| | | width: 16px; |
| | | height: 16px; |
| | | } |
| | | |
| | | .el-image__inner { |
| | | box-shadow: 0px 0px 20px 1px #ccc; |
| | | object-fit: contain !important; |
| | | width: 110px; |
| | | height: 140px; |
| | | } |
| | | |
| | | .el-icon { |
| | | margin-right: 10px; |
| | | font-size: 20px; |
| | | position: relative; |
| | | top: 3px; |
| | | left: 0px; |
| | | } |
| | | |
| | | .deleteBox { |
| | | .el-dialog.is-align-center { |
| | | width: 350px; |
| | | } |
| | | |
| | | .el-dialog__body { |
| | | display: flex; |
| | | justify-content: center; |
| | | font-size: 16px; |
| | | } |
| | | } |
| | | |
| | | .el-table__inner-wrapper::before { |
| | | height: 0px; |
| | | } |
| | | } |
| | | |
| | | .labelBox { |
| | | // width: 50px; |
| | | padding: 0 4px; |
| | | height: 25px; |
| | | color: #fff; |
| | | position: absolute; |
| | | top: 0; |
| | | right: 0; |
| | | margin: 0 !important; |
| | | border-radius: 0px 0px 0px 5px; |
| | | |
| | | p { |
| | | display: flex; |
| | | justify-content: center; |
| | | } |
| | | } |
| | | |
| | | .breadcrumbsBox { |
| | | height: 60px; |
| | | border-bottom: 1px solid #f5f5f5; |
| | | |
| | | p { |
| | | line-height: 60px; |
| | | font-size: 14px; |
| | | color: #545c63; |
| | | } |
| | | } |
| | | |
| | | .noData { |
| | | font-size: 26px; |
| | | font-weight: bold; |
| | | display: flex; |
| | | justify-content: center; |
| | | margin: 0 auto; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div>我的收藏</div> |
| | | <!-- <page> --> |
| | | <div class="personalPage-box"> |
| | | <div class="personalPage-title">我的收藏</div> |
| | | <div class="personalPage-content"> |
| | | <div class="cartClass"> |
| | | <el-tabs v-model="currentCollect" type="capsule" @tab-click="tabCart"> |
| | | <el-tab-pane label="数字教材" name="textBooks"></el-tab-pane> |
| | | </el-tabs> |
| | | </div> |
| | | <div class="myCarTopPage"> |
| | | <div class="list-box" v-loading="pages.loading"> |
| | | <div |
| | | :class=" |
| | | currentCollect == 'book' || currentCollect == 'textBooks' |
| | | ? 'bookCartContent cartContent' |
| | | : currentCollect == 'course' |
| | | ? 'courseCartContent cartContent' |
| | | : 'cartContent' |
| | | " |
| | | > |
| | | <div |
| | | class="collectList flex jc-sb clear" |
| | | v-if="collectList.length > 0 && !pages.loading" |
| | | > |
| | | <div |
| | | v-for="(item, index) in collectList" |
| | | :key="index" |
| | | class="collectList-item fl" |
| | | > |
| | | <div class="cover" @click="goBookDetails(item.id, item.name)"> |
| | | <img :src="item.icon" alt="" /> |
| | | </div> |
| | | <div class="info" @click="goBookDetails(item.id, item.name)"> |
| | | <span>{{ item.name }}</span> |
| | | </div> |
| | | <div class="currentBtn hover" @click="setCoolect(item)"> |
| | | <img |
| | | src="@/assets/images/personalCenter/collect-click.png" |
| | | alt="star" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div v-if="collectList.length == 0 && !pages.loading"> |
| | | <el-empty :image-size="200" description="暂无数据" /> |
| | | </div> |
| | | </div> |
| | | <div class="pagination-box"> |
| | | <el-pagination |
| | | v-model:current-page="pages.page" |
| | | v-model:page-size="pages.pageSize" |
| | | :disabled="disabled" |
| | | :background="background" |
| | | layout="total, prev, pager, next" |
| | | :total="pages.count" |
| | | @current-change="handleCurrentChange" |
| | | v-if="collectList.length > 0 && !pages.loading" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <!-- </page> --> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { reactive, ref, onMounted, inject, watch } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import { useBreadcrumbStore, useUserStore } from '@/store' |
| | | import { useRouter } from "vue-router"; |
| | | const crumbStore = useBreadcrumbStore() |
| | | const userStore = useUserStore() |
| | | const router = useRouter(); |
| | | const MG: any = inject("MG"); |
| | | const config: any = inject("config"); |
| | | let currentCollect = ref("book"); |
| | | let collectList = ref([]); |
| | | const background = ref(false); |
| | | const disabled = ref(false); |
| | | let pages = reactive({ |
| | | page: 1, |
| | | pageSize: 10, |
| | | count: 0, |
| | | loading: false, |
| | | }); |
| | | let linkType = ref("FavoriteTextBooks"); |
| | | |
| | | const tabCart = (event: Event) => { |
| | | pages.page = 1; |
| | | pages.loading = true; |
| | | collectList.value = []; |
| | | currentCollect.value = event.props.name; |
| | | if (currentCollect.value == "textBooks") { |
| | | linkType.value = "FavoriteTextBooks"; |
| | | } |
| | | getDataList(); |
| | | }; |
| | | |
| | | function getDataList() { |
| | | pages.loading = true; |
| | | MG.store |
| | | .getProductList({ |
| | | handelEBooK: true, |
| | | queryType: "AppUserProductLink", |
| | | linkType: linkType.value, |
| | | paging: { |
| | | start: pages.pageSize * pages.page - pages.pageSize, |
| | | size: pages.pageSize, |
| | | }, |
| | | }) |
| | | .then((res) => { |
| | | collectList.value = res.datas; |
| | | pages.count = res.total; |
| | | pages.loading = false; |
| | | }) |
| | | .catch(() => { |
| | | pages.loading = false; |
| | | }); |
| | | } |
| | | onMounted(() => { |
| | | getDataList(); |
| | | }); |
| | | |
| | | // watch( |
| | | // () => userStore.token, |
| | | // () => { |
| | | // getDataList() |
| | | // } |
| | | // ) |
| | | |
| | | const handleCurrentChange = (val: number) => { |
| | | pages.page = val; |
| | | getDataList(); |
| | | }; |
| | | |
| | | const setCoolect = (item) => { |
| | | ElMessageBox.confirm("确定要取消收藏吗?", { |
| | | confirmButtonText: "确定", |
| | | cancelButtonText: "取消", |
| | | autofocus: false, |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | MG.store |
| | | .delProductLink({ |
| | | productIds: [item.id], |
| | | linkType: linkType.value, |
| | | }) |
| | | .then(() => { |
| | | ElMessage({ |
| | | message: "收藏已取消!", |
| | | type: "success", |
| | | }); |
| | | pages.page = 1; |
| | | getDataList(); |
| | | }); |
| | | }) |
| | | .catch(() => {}); |
| | | }; |
| | | // 跳转书本详情 |
| | | const goBookDetails = (id: number, name: string) => { |
| | | let crumbs = [ |
| | | { |
| | | name, |
| | | isCrumbs: true, |
| | | type: |
| | | currentCollect.value == "book" |
| | | ? "bookService" |
| | | : currentCollect.value == "textBooks" |
| | | ? "digitalTextbooks" |
| | | : "digitalCourses", |
| | | path: |
| | | currentCollect.value == "book" |
| | | ? "/bookService/details" |
| | | : "/digitalCoursesDetails", |
| | | }, |
| | | ]; |
| | | // 在全局数据中设置面包屑 |
| | | crumbStore.setCrumbs({ |
| | | type: |
| | | currentCollect.value == "book" |
| | | ? "bookService" |
| | | : currentCollect.value == "textBooks" |
| | | ? "digitalTextbooks" |
| | | : "digitalCourses", |
| | | data: crumbs, |
| | | callback: (key: any) => { |
| | | router.push({ |
| | | name: |
| | | currentCollect.value == "book" |
| | | ? "bookDetails" |
| | | : currentCollect.value == "textBooks" |
| | | ? "digitalTextbooksDetails" |
| | | : "digitalCoursesDetails", |
| | | query: { |
| | | crumbsKey: key, |
| | | bookId: id, |
| | | bookName: name, |
| | | type: |
| | | currentCollect.value == "book" |
| | | ? "bookService" |
| | | : currentCollect.value == "textBooks" |
| | | ? "digitalTextbooks" |
| | | : "digitalCourses", |
| | | }, |
| | | }); |
| | | }, |
| | | }); |
| | | }; |
| | | </script> |
| | | <style lang="less" scoped> |
| | | .cartClass { |
| | | ::v-deep .el-tabs__nav-wrap::after { |
| | | background-color: #019e58; |
| | | height: 1px; |
| | | } |
| | | |
| | | ::v-deep .el-tabs__item { |
| | | width: 100px; |
| | | padding: 0; |
| | | color: #545c63; |
| | | } |
| | | |
| | | ::v-deep .is-active { |
| | | background-color: #019e58; |
| | | color: #fff; |
| | | border-radius: 3px 3px 0 0; |
| | | } |
| | | } |
| | | |
| | | .collectList { |
| | | // overflow: hidden; |
| | | justify-content: flex-start; |
| | | flex-wrap: wrap; |
| | | } |
| | | |
| | | .bookCartContent { |
| | | .collectList-item { |
| | | width: 130px; |
| | | cursor: pointer; |
| | | box-sizing: border-box; |
| | | float: left; |
| | | position: relative; |
| | | margin-right: 38px; |
| | | |
| | | .cover { |
| | | width: 100%; |
| | | height: 180px; |
| | | box-shadow: 0px 0px 20px 1px #ccc; |
| | | |
| | | img { |
| | | width: 100%; |
| | | height: 100%; |
| | | object-fit: contain; |
| | | } |
| | | } |
| | | |
| | | .info { |
| | | height: 90px; |
| | | padding: 15px 0; |
| | | width: 100%; |
| | | |
| | | span { |
| | | font-weight: bold; |
| | | height: 45px; |
| | | line-height: 22px; |
| | | display: -webkit-box; |
| | | margin-bottom: 5px; |
| | | -webkit-box-orient: vertical; |
| | | -webkit-line-clamp: 2; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .collectList-item:nth-child(5), |
| | | :nth-child(10) { |
| | | margin-right: 0; |
| | | } |
| | | } |
| | | |
| | | .courseCartContent { |
| | | .collectList-item { |
| | | width: 28%; |
| | | cursor: pointer; |
| | | box-sizing: border-box; |
| | | float: left; |
| | | margin-right: 5%; |
| | | box-shadow: 0px 0px 20px 1px #ccc; |
| | | position: relative; |
| | | |
| | | .cover { |
| | | width: 100%; |
| | | height: 130px; |
| | | |
| | | img { |
| | | width: 100%; |
| | | height: 100%; |
| | | object-fit: contain; |
| | | } |
| | | } |
| | | |
| | | .info { |
| | | height: 70px; |
| | | padding: 15px; |
| | | width: 100%; |
| | | |
| | | span { |
| | | font-weight: bold; |
| | | height: 45px; |
| | | line-height: 22px; |
| | | display: -webkit-box; |
| | | margin-bottom: 5px; |
| | | -webkit-box-orient: vertical; |
| | | -webkit-line-clamp: 2; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .currentBtn { |
| | | width: 20px; |
| | | height: 20px; |
| | | padding: 2px; |
| | | background-color: #fff; |
| | | position: absolute; |
| | | top: 10px; |
| | | right: 10px; |
| | | |
| | | img { |
| | | width: 16px; |
| | | height: 16px; |
| | | } |
| | | } |
| | | |
| | | .cartContent { |
| | | min-height: 495px; |
| | | } |
| | | |
| | | .pagination-box { |
| | | display: flex; |
| | | justify-content: center; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div>我的消息</div> |
| | | <!-- <page> --> |
| | | <div class="personalPage-box"> |
| | | <div class="personalPage-title">我的消息</div> |
| | | <div class="personalPage-content"> |
| | | <div class="list-box" v-loading="pages.loading"> |
| | | <ul class="listTable" v-if="dataList.length > 0 && !pages.loading"> |
| | | <li v-for="(item, index) in dataList" :key="index" class="body flex"> |
| | | <div class="icon"> |
| | | <img src="@/assets/images/personalCenter/notification.svg" alt="star" /> |
| | | </div> |
| | | <div class="flex1 ai-c"> |
| | | <p class="title hover" :title="item.name" @click="viewDetail(item)"> |
| | | {{ item.name }} |
| | | </p> |
| | | <p class="content" :title="item.description">{{ item.description }}</p> |
| | | </div> |
| | | <span class="createDate">{{ item.createDate }}</span> |
| | | </li> |
| | | </ul> |
| | | <div v-if="dataList.length == 0 && !pages.loading"> |
| | | <el-empty :image-size="200" description="暂无数据" /> |
| | | </div> |
| | | </div> |
| | | <div class="pagination-box" v-if="dataList.length > 0 && !pages.loading"> |
| | | <el-pagination |
| | | v-model:current-page="pages.page" |
| | | v-model:page-size="pages.pageSize" |
| | | layout="total, prev, pager, next" |
| | | :total="pages.count" |
| | | @current-change="handleCurrentChange" |
| | | /> |
| | | </div> |
| | | </div> |
| | | <el-dialog align-center v-model="detailDialog" title="消息" class="messageDialog"> |
| | | <div> |
| | | <div class="title">{{ dataInfo.name }}</div> |
| | | <div class="content" v-html="dataInfo.content"></div> |
| | | </div> |
| | | </el-dialog> |
| | | </div> |
| | | <!-- </page> --> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { reactive, ref, onMounted, inject, watch } from "vue"; |
| | | import moment from "moment"; |
| | | import { useUserStore } from "@/store"; |
| | | const userStore = useUserStore(); |
| | | const MG: any = inject("MG"); |
| | | const config: any = inject("config"); |
| | | let dataList = ref([]); |
| | | let pages = reactive({ |
| | | page: 1, |
| | | pageSize: 10, |
| | | count: 0, |
| | | loading: false, |
| | | }); |
| | | const detailDialog = ref(false); |
| | | let dataInfo = reactive({ |
| | | name: "", |
| | | content: "", |
| | | }); |
| | | |
| | | function getDataList() { |
| | | pages.loading = true; |
| | | MG.app |
| | | .getAppMessageList({ |
| | | appRefCode: config.appRefCode, |
| | | start: (pages.page - 1) * pages.pageSize, |
| | | size: pages.pageSize, |
| | | sort: { |
| | | type: "Desc", |
| | | field: "CreateDate", |
| | | }, |
| | | }) |
| | | .then((res) => { |
| | | pages.count = res.totalSize; |
| | | res.datas.forEach((item) => { |
| | | item.createDate = moment(item.createDate).format("YYYY-MM-DD HH:mm:ss"); |
| | | }); |
| | | dataList.value = res.datas; |
| | | pages.loading = false; |
| | | }) |
| | | .catch(() => { |
| | | pages.loading = false; |
| | | }); |
| | | } |
| | | onMounted(() => { |
| | | getDataList(); |
| | | }); |
| | | |
| | | watch( |
| | | () => userStore?.token, |
| | | () => { |
| | | getDataList(); |
| | | } |
| | | ); |
| | | |
| | | const handleCurrentChange = (val: number) => { |
| | | pages.page = val; |
| | | getDataList(); |
| | | }; |
| | | |
| | | function viewDetail(data) { |
| | | MG.app |
| | | .getMessage({ |
| | | messageId: data.id, |
| | | }) |
| | | .then((res) => { |
| | | if (res) { |
| | | dataInfo.name = res.name; |
| | | dataInfo.content = res.content; |
| | | detailDialog.value = true; |
| | | } |
| | | }); |
| | | } |
| | | </script> |
| | | <style lang="less" scoped> |
| | | .listTable { |
| | | .body { |
| | | padding: 15px 0; |
| | | border-bottom: 1px solid #ededed; |
| | | |
| | | .icon { |
| | | width: 36px; |
| | | |
| | | img { |
| | | margin-top: 2px; |
| | | width: 22px; |
| | | height: 22px; |
| | | } |
| | | } |
| | | |
| | | .title { |
| | | font-weight: bold; |
| | | line-height: 24px; |
| | | height: 24px; |
| | | display: -webkit-box; |
| | | -webkit-box-orient: vertical; |
| | | -webkit-line-clamp: 1; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | |
| | | .content { |
| | | height: 45px; |
| | | line-height: 24px; |
| | | display: -webkit-box; |
| | | margin: 5px 0; |
| | | -webkit-box-orient: vertical; |
| | | -webkit-line-clamp: 2; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | |
| | | .createDate { |
| | | line-height: 24px; |
| | | padding-left: 20px; |
| | | color: #949494; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .list-box { |
| | | min-height: 570px; |
| | | } |
| | | |
| | | .pagination-box { |
| | | display: flex; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .messageDialog { |
| | | width: 600px; |
| | | |
| | | .title { |
| | | line-height: 22px; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | .content { |
| | | margin-top: 10px; |
| | | line-height: 22px; |
| | | } |
| | | } |
| | | </style> |
| | | <style lang="less"> |
| | | .messageDialog { |
| | | .el-dialog__header { |
| | | padding: 15px; |
| | | margin-right: 0; |
| | | border-bottom: 1px solid #f4f4f4; |
| | | } |
| | | |
| | | .el-dialog__title { |
| | | font-weight: bold; |
| | | font-size: 16px; |
| | | } |
| | | |
| | | .el-dialog__headerbtn { |
| | | top: 6px; |
| | | right: 6px; |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div>我的订单</div> |
| | | <!-- <page> --> |
| | | <div class="personalPage-box"> |
| | | <div class="personalPage-title">我的订单</div> |
| | | <div class="personalPage-content"> |
| | | <div class="cartClass"> |
| | | <el-tabs v-model="order" type="capsule" @tab-click="tabCart"> |
| | | <el-tab-pane label="全部" name="all"></el-tab-pane> |
| | | <el-tab-pane label="待支付" name="payment"></el-tab-pane> |
| | | <el-tab-pane label="已完成" name="complete"></el-tab-pane> |
| | | <el-tab-pane label="已取消" name="cancellation"></el-tab-pane> |
| | | </el-tabs> |
| | | </div> |
| | | <div class="myCarTopPage"> |
| | | <div class="cartContent" v-loading="pages.loading"> |
| | | <div class="list-box"> |
| | | <ul class="listTable" v-if="dataList.length > 0 && !pages.loading"> |
| | | <li class="head flex"> |
| | | <span class="index">序号</span> |
| | | <span class="clear flex1">商品信息</span> |
| | | <span class="state">商品类型</span> |
| | | <span class="price">价格</span> |
| | | </li> |
| | | <li v-for="item in dataList" :key="item.index"> |
| | | <div class="body flex ai-c"> |
| | | <div class="index">{{ item.index }}</div> |
| | | <div class="list"> |
| | | <div |
| | | v-for="pItem in item.productList" |
| | | :key="pItem.id" |
| | | class="listItem flex ai-c" |
| | | > |
| | | <div |
| | | class="clear hover" |
| | | @click=" |
| | | goBookDetails( |
| | | pItem.orderSaleMethod.product.id, |
| | | pItem.orderSaleMethod.product.name, |
| | | pItem.orderSaleMethod.product.cmsTypeRefCode, |
| | | item.remarks, |
| | | pItem.orderSaleMethod.id |
| | | ) |
| | | " |
| | | > |
| | | <div class="cover fl"> |
| | | <img |
| | | :src=" |
| | | pItem.orderSaleMethod.product.icon |
| | | ? getPublicImage( |
| | | pItem.orderSaleMethod.product.icon, |
| | | '', |
| | | '' |
| | | ) |
| | | : bookCover |
| | | " |
| | | alt="" |
| | | /> |
| | | </div> |
| | | <div class="title flex ai-c"> |
| | | {{ |
| | | pItem.orderSaleMethod.type === "defaultSaleMethod" || |
| | | pItem.orderSaleMethod.cmsItemList.length == 0 |
| | | ? pItem.orderSaleMethod.product.name |
| | | : pItem.orderSaleMethod.product.name + |
| | | ":" + |
| | | pItem.orderSaleMethod.cmsItemList[0].name |
| | | }} |
| | | </div> |
| | | </div> |
| | | <span class="state">{{ |
| | | pItem.orderSaleMethod.product.cmsTypeRefCode == |
| | | "jsek_digitalTextbooks" |
| | | ? "数字教材" |
| | | : pItem.orderSaleMethod.product.cmsTypeRefCode == |
| | | "jsek_digitalCourses" |
| | | ? "数字课程" |
| | | : pItem.orderSaleMethod.type == "defaultSaleMethod" |
| | | ? "图书服务-电子书" |
| | | : pItem.orderSaleMethod.type == "createProductSaleMethod" && |
| | | pItem.orderSaleMethod.cmsItemList == 0 |
| | | ? "图书服务-组卷" |
| | | : pItem.orderSaleMethod.cmsItemList[0].type == |
| | | "questionBankFolder" |
| | | ? "图书服务-云测试" |
| | | : "图书服务-云学习" |
| | | }}</span> |
| | | <div class="price"> |
| | | <span>¥{{ pItem.payPrice.toFixed(2) }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="count"> |
| | | <span>订单号: {{ item.orderNumber }}</span> |
| | | <span v-if="item.createDate"> |
| | | 创建时间: |
| | | <span>{{ item.createDate.slice(0, 10) }}</span> |
| | | <span style="margin-left: 5px">{{ |
| | | item.createDate.slice(11, 19) |
| | | }}</span> |
| | | </span> |
| | | <span class="right"> |
| | | <span |
| | | >总计:<span class="main" |
| | | >¥{{ item.totalPrice.toFixed(2) }}</span |
| | | ></span |
| | | > |
| | | <span class="status yes" v-if="item.state == 'Success'">已完成</span> |
| | | <span class="status cancel" v-if="item.state == 'Cancel'" |
| | | >已取消</span |
| | | > |
| | | <span class="status cancel" v-if="item.state == 'ReFoundFinished'" |
| | | >已退款</span |
| | | > |
| | | <span class="status" v-if="item.state == 'WaitPay'"> |
| | | <span class="main hover" @click="toPay(item.orderNumber)" |
| | | >立即支付</span |
| | | > |
| | | <span class="grey hover" @click="cancleOrder(item.orderNumber)" |
| | | >取消订单</span |
| | | > |
| | | </span> |
| | | </span> |
| | | </div> |
| | | </li> |
| | | </ul> |
| | | <div v-if="dataList.length == 0 && !pages.loading"> |
| | | <el-empty :image-size="200" description="暂无数据" /> |
| | | </div> |
| | | </div> |
| | | <div class="pagination-box" v-if="dataList.length > 0 && !pages.loading"> |
| | | <el-pagination |
| | | v-model:current-page="pages.page" |
| | | v-model:page-size="pages.pageSize" |
| | | layout="total, prev, pager, next" |
| | | :total="pages.count" |
| | | @current-change="handleCurrentChange" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <!-- </page> --> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { reactive, ref, onMounted, inject, watch } from "vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { getPublicImage } from "@/assets/js/middleGround/tool.js"; |
| | | import { useRouter } from "vue-router"; |
| | | import { useBreadcrumbStore, useUserStore } from "@/store"; |
| | | import bookCover from "@/assets/images/personalCenter/book-cover.png"; |
| | | const router = useRouter(); |
| | | const crumbStore = useBreadcrumbStore(); |
| | | const userStore = useUserStore(); |
| | | const MG: any = inject("MG"); |
| | | let order = ref("all"); |
| | | let dataList = ref([]); |
| | | let queryFilter = reactive([]); |
| | | let pages = reactive({ |
| | | page: 1, |
| | | pageSize: 5, |
| | | count: 0, |
| | | loading: false, |
| | | }); |
| | | |
| | | const tabCart = (event: Event) => { |
| | | order.value = event.props.name; |
| | | pages.page = 1; |
| | | dataList.value = []; |
| | | if (order.value == "all") { |
| | | queryFilter.value = []; |
| | | } |
| | | if (order.value == "payment") { |
| | | queryFilter.value = [{ field: "State", value: "WaitPay" }]; |
| | | } |
| | | if (order.value == "complete") { |
| | | queryFilter.value = [{ field: "State", value: "Success" }]; |
| | | } |
| | | if (order.value == "cancellation") { |
| | | queryFilter.value = [{ field: "State", value: "Cancel" }]; |
| | | } |
| | | getDataList(); |
| | | }; |
| | | function getDataList() { |
| | | pages.loading = true; |
| | | const data = { |
| | | start: pages.pageSize * pages.page - pages.pageSize, |
| | | size: pages.pageSize, |
| | | filterList: queryFilter.value, |
| | | sort: { |
| | | type: "Desc", |
| | | field: "CreateDate", |
| | | }, |
| | | }; |
| | | MG.store |
| | | .getUserOrderList(data) |
| | | .then((res) => { |
| | | res.datas.forEach((item, index) => { |
| | | item.index = |
| | | pages.page == 1 ? index + 1 : pages.pageSize * (pages.page - 1) + (index + 1); |
| | | item.productList = item.saleMethodLinks; |
| | | item.time = item.createDate.slice(0, 10) + +item.createDate.slice(11, 20); |
| | | }); |
| | | pages.count = res.totalSize; |
| | | dataList.value = [...res.datas]; |
| | | console.log("订单列表", res.datas); |
| | | pages.loading = false; |
| | | }) |
| | | .catch(() => { |
| | | pages.loading = false; |
| | | }); |
| | | } |
| | | |
| | | onMounted(() => { |
| | | getDataList(); |
| | | }); |
| | | |
| | | // watch( |
| | | // () => userStore.token, |
| | | // () => { |
| | | // getDataList() |
| | | // } |
| | | // ) |
| | | |
| | | const handleCurrentChange = (val: number) => { |
| | | pages.page = val; |
| | | getDataList(); |
| | | }; |
| | | // 跳转书本详情 |
| | | const goBookDetails = async ( |
| | | id: number, |
| | | name: string, |
| | | refCode: string, |
| | | remarks: string, |
| | | orderSaleMethodId: string |
| | | ) => { |
| | | let parentData = null; |
| | | let bookId = id; |
| | | if (refCode == "digitalCourses") { |
| | | let crumbs = [ |
| | | { |
| | | name, |
| | | isCrumbs: true, |
| | | type: "digitalCourses", |
| | | path: "digitalCoursesDetails", |
| | | }, |
| | | ]; |
| | | // 在全局数据中设置面包屑 |
| | | crumbStore.setCrumbs({ |
| | | type: "digitalCourses", |
| | | data: crumbs, |
| | | callback: (key: any) => { |
| | | router.push({ |
| | | name: "digitalCoursesDetails", |
| | | query: { |
| | | crumbsKey: key, |
| | | bookId: bookId, |
| | | bookName: name, |
| | | type: "digitalCourses", |
| | | }, |
| | | }); |
| | | }, |
| | | }); |
| | | } else if (refCode == "digitalTextbooks") { |
| | | let crumbs = [ |
| | | { |
| | | name, |
| | | isCrumbs: true, |
| | | type: "digitalTextbooks", |
| | | path: "digitalTextbooksDetails", |
| | | }, |
| | | ]; |
| | | // 在全局数据中设置面包屑 |
| | | crumbStore.setCrumbs({ |
| | | type: "digitalTextbooks", |
| | | data: crumbs, |
| | | callback: (key: any) => { |
| | | router.push({ |
| | | name: "digitalTextbooksDetails", |
| | | query: { |
| | | crumbsKey: key, |
| | | bookId: bookId, |
| | | bookName: name, |
| | | type: "digitalTextbooks", |
| | | }, |
| | | }); |
| | | }, |
| | | }); |
| | | } else { |
| | | parentData = await MG.store.getProductBySaleMethod({ |
| | | saleMethodId: orderSaleMethodId, |
| | | }); |
| | | if (parentData.parentProduct.length > 0) { |
| | | bookId = parentData.parentProduct[parentData.parentProduct.length - 1].id; |
| | | } |
| | | console.log(bookId, "bookId"); |
| | | let crumbs = [ |
| | | { |
| | | name, |
| | | isCrumbs: true, |
| | | type: "bookService", |
| | | path: "/bookService/details", |
| | | }, |
| | | ]; |
| | | // 在全局数据中设置面包屑 |
| | | crumbStore.setCrumbs({ |
| | | type: "bookService", |
| | | data: crumbs, |
| | | callback: (key: any) => { |
| | | router.push({ |
| | | name: "bookDetails", |
| | | query: { |
| | | crumbsKey: key, |
| | | bookId: bookId, |
| | | bookName: name, |
| | | type: "bookService", |
| | | }, |
| | | }); |
| | | }, |
| | | }); |
| | | } |
| | | }; |
| | | //立即支付 |
| | | const toPay = (orderNo) => { |
| | | let crumbs: any[] = [ |
| | | { |
| | | name: "我的订单", // 面包屑名称 |
| | | pathName: "myOrder", // 面包屑跳转路由,可传递 pathName 或 path |
| | | isCrumbs: true, // 面包屑点击跳转时是否创建新的面包屑记录 |
| | | type: "personalCenter", // 如果需要创建新的面包屑记录,创建的type |
| | | query: { |
| | | type: "personalCenter", |
| | | }, |
| | | }, |
| | | ]; |
| | | crumbs.push({ |
| | | name: "订单详情", |
| | | }); |
| | | // 在全局数据中设置面包屑 |
| | | crumbStore.setCrumbs({ |
| | | type: "personalCenter", |
| | | data: crumbs, |
| | | callback: (key: any) => { |
| | | router.push({ |
| | | path: "/paymentPage", //要跳转的页面 |
| | | query: { |
| | | crumbsKey: key, |
| | | orderNum: orderNo, |
| | | type: "personalCenter", |
| | | }, |
| | | }); |
| | | }, |
| | | }); |
| | | }; |
| | | |
| | | //取消订单 |
| | | const cancleOrder = (orderNum) => { |
| | | MG.store.cancelOrder({ orderNum: orderNum }).then(() => { |
| | | ElMessage({ |
| | | message: "订单已取消", |
| | | type: "success", |
| | | }); |
| | | getDataList(); |
| | | }); |
| | | }; |
| | | </script> |
| | | <style lang="less" scoped> |
| | | .cartClass { |
| | | ::v-deep .el-tabs__nav-wrap::after { |
| | | background-color: #019e58; |
| | | height: 1px; |
| | | } |
| | | |
| | | ::v-deep .el-tabs__item { |
| | | width: 100px; |
| | | padding: 0; |
| | | color: #545c63; |
| | | } |
| | | |
| | | ::v-deep .is-active { |
| | | background-color: #019e58; |
| | | color: #fff; |
| | | border-radius: 3px 3px 0 0; |
| | | } |
| | | } |
| | | |
| | | .listTable { |
| | | .head { |
| | | font-weight: bold; |
| | | padding: 12px 10px; |
| | | background-color: #f3f3f3; |
| | | |
| | | .flex1 { |
| | | padding: 0 50px; |
| | | } |
| | | } |
| | | |
| | | .body { |
| | | padding: 15px 10px; |
| | | } |
| | | |
| | | li { |
| | | line-height: 23px; |
| | | border-bottom: 1px solid #f4f4f4; |
| | | |
| | | .index { |
| | | // padding: 0 20px; |
| | | text-align: center; |
| | | width: 80px; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .list { |
| | | .listItem { |
| | | padding-bottom: 10px; |
| | | |
| | | .clear { |
| | | width: 400px; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | } |
| | | |
| | | :last-child { |
| | | padding-bottom: 0px; |
| | | } |
| | | } |
| | | |
| | | .cover { |
| | | box-shadow: 0px 0px 20px 1px #ccc; |
| | | margin-right: 20px; |
| | | width: 130px; |
| | | height: 180px; |
| | | |
| | | img { |
| | | width: 100%; |
| | | height: 100%; |
| | | object-fit: contain; |
| | | } |
| | | } |
| | | |
| | | .title { |
| | | height: 180px; |
| | | line-height: 180px; |
| | | } |
| | | |
| | | .state { |
| | | padding: 0 20px; |
| | | width: 230px; |
| | | } |
| | | |
| | | .price { |
| | | text-align: right; |
| | | padding: 0 20px; |
| | | // width: 100px; |
| | | color: #019e58; |
| | | } |
| | | |
| | | .count { |
| | | // text-align: right; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | padding: 10px; |
| | | background: rgba(205, 207, 219, 0.14); |
| | | |
| | | .right { |
| | | float: right; |
| | | } |
| | | |
| | | .cancel { |
| | | color: #949494; |
| | | } |
| | | |
| | | .status { |
| | | margin-left: 40px; |
| | | |
| | | span { |
| | | padding: 0 10px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .list-box { |
| | | min-height: 495px; |
| | | } |
| | | |
| | | .pagination-box { |
| | | display: flex; |
| | | justify-content: center; |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div> |
| | | <el-dialog |
| | | align-center |
| | | destroy-on-close |
| | | :close-on-click-modal="false" |
| | | v-model="teacherDialog" |
| | | title="教师认证申请" |
| | | class="myDialog" |
| | | @close="closeDialog(teacherFormRef)" |
| | | > |
| | | <div v-loading="loading" class="box"> |
| | | <div class="body-box"> |
| | | <div class="tipsBox"> |
| | | <p class="main">温馨提示</p> |
| | | <p>仅限学校本课程任课教师申请;请上传有效在职教师工作证将有助于审核。</p> |
| | | </div> |
| | | <el-form |
| | | ref="teacherFormRef" |
| | | :model="teacherInfo" |
| | | :rules="teacherRules" |
| | | label-width="140px" |
| | | class="teacherInfo" |
| | | status-icon |
| | | > |
| | | <el-form-item label="当前状态:"> |
| | | <span class="wait" v-if="teacherInfo.state == 'WaitAudit'">等待审核</span> |
| | | <span class="yes" v-else-if="teacherInfo.state == 'Normal'">已认证</span> |
| | | <span class="no" v-else-if="teacherInfo.state == 'Reject'" |
| | | ><span>已驳回</span |
| | | ><span @click="lookReason()" class="wait hover" style="margin-left: 20px" |
| | | >查看原因</span |
| | | ></span |
| | | > |
| | | <span class="wait" v-else>待认证</span> |
| | | </el-form-item> |
| | | <el-form-item label="学校:" prop="schoolName"> |
| | | <span v-if="!editState">{{ teacherInfo.schoolName || "-" }}</span> |
| | | <el-input |
| | | v-else |
| | | v-model="teacherInfo.schoolName" |
| | | autocomplete="off" |
| | | placeholder="请输入学校" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="真实姓名:" prop="fullName"> |
| | | <span v-if="!editState">{{ teacherInfo.fullName || "-" }}</span> |
| | | <el-input |
| | | v-else |
| | | v-model="teacherInfo.fullName" |
| | | autocomplete="off" |
| | | placeholder="请输入真实姓名" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="职称:"> |
| | | <span v-if="!editState">{{ teacherInfo.positionalTitle || "-" }}</span> |
| | | <el-select |
| | | v-else |
| | | v-model="teacherInfo.positionalTitle" |
| | | placeholder="请选择职称" |
| | | > |
| | | <el-option |
| | | v-for="item in teachPosts" |
| | | :key="item.value" |
| | | :label="item.name" |
| | | :value="item.name" |
| | | ></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="任教课程:" prop="courseName"> |
| | | <span v-if="!editState">{{ teacherInfo.courseName || "-" }}</span> |
| | | <el-input |
| | | v-else |
| | | v-model="teacherInfo.courseName" |
| | | autocomplete="off" |
| | | placeholder="请输入任教课程" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="手机号:" prop="phone"> |
| | | <span v-if="!editState">{{ teacherInfo.phone || "-" }}</span> |
| | | <el-input |
| | | v-else |
| | | v-model="teacherInfo.phone" |
| | | autocomplete="off" |
| | | placeholder="请输入手机号" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="座机:" prop="telphone"> |
| | | <span v-if="!editState">{{ teacherInfo.telphone || "-" }}</span> |
| | | <el-input |
| | | v-else |
| | | v-model="teacherInfo.telphone" |
| | | autocomplete="off" |
| | | placeholder="请输入座机" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="邮箱:" prop="email"> |
| | | <span v-if="!editState">{{ teacherInfo.email || "-" }}</span> |
| | | <el-input |
| | | v-else |
| | | v-model="teacherInfo.email" |
| | | autocomplete="off" |
| | | placeholder="请输入邮箱" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="详细地址:" prop="detailedAddress"> |
| | | <span v-if="!editState">{{ teacherInfo.detailedAddress || "-" }}</span> |
| | | <el-input |
| | | v-else |
| | | v-model="teacherInfo.detailedAddress" |
| | | autocomplete="off" |
| | | placeholder="请输入详细地址" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="在职教师工作证:" prop="relevantCertificates"> |
| | | <div class="uploadBox"> |
| | | <div class="fileList"> |
| | | <div class="fileImgBox" v-for="(file, index) in fileList" :key="file"> |
| | | <el-image |
| | | v-if="file.md5" |
| | | style="width: 100%; height: 100%" |
| | | :src="config?.requestCtx + `/file/GetPreViewImage?md5=` + file.md5" |
| | | :zoom-rate="1.2" |
| | | :max-scale="7" |
| | | :min-scale="0.2" |
| | | :hide-on-click-modal="true" |
| | | :preview-src-list="showFileList" |
| | | :initial-index="index" |
| | | fit="contain" |
| | | /> |
| | | <el-icon |
| | | v-if="editState" |
| | | @click="handleRemove(file)" |
| | | color="#F56C6C" |
| | | style=" |
| | | position: absolute; |
| | | top: -10px; |
| | | right: -10px; |
| | | font-size: 20px; |
| | | background: #fff; |
| | | border-radius: 50%; |
| | | cursor: pointer; |
| | | " |
| | | ><CircleCloseFilled |
| | | /></el-icon> |
| | | </div> |
| | | <el-upload |
| | | v-if="editState" |
| | | class="upload" |
| | | :http-request="fileUpload" |
| | | :show-file-list="false" |
| | | list-type="picture-card" |
| | | :action="'#'" |
| | | > |
| | | <el-icon> |
| | | <Plus /> |
| | | </el-icon> |
| | | </el-upload> |
| | | </div> |
| | | </div> |
| | | <div class="grey" style="font-size: 12px">教务处盖章文件、校工卡皆可</div> |
| | | </el-form-item> |
| | | </el-form> |
| | | <div class="agree-msg"> |
| | | <!-- <input |
| | | :disabled="!editState ? true : false" |
| | | type="checkbox" |
| | | class="checkbox" |
| | | v-model="teacherInfo.agree" |
| | | /> --> |
| | | <el-checkbox |
| | | v-model="teacherInfo.agree" |
| | | :disabled="!editState ? true : false" |
| | | ></el-checkbox> |
| | | <span class="agree" |
| | | >同意<span class="main hover" @click="dialogVisibleTecher = true" |
| | | >《教师认证服务条款》</span |
| | | ></span |
| | | > |
| | | </div> |
| | | </div> |
| | | <div class="footer-box"> |
| | | <span class="myDialog-footer" v-if="!loading && editState"> |
| | | <el-button @click="closeDialog(teacherFormRef)"> 取消</el-button> |
| | | <el-button |
| | | type="primary" |
| | | @click="submitBtn(teacherFormRef)" |
| | | :loading="subLoading" |
| | | > |
| | | 提交</el-button |
| | | > |
| | | </span> |
| | | </div> |
| | | </div> |
| | | </el-dialog> |
| | | <!-- 教师认证服务条款 --> |
| | | <el-dialog |
| | | title="《教师认证服务条款》" |
| | | v-model="dialogVisibleTecher" |
| | | :close-on-click-modal="false" |
| | | width="40%" |
| | | > |
| | | <div class="protocolBox" v-html="protocolTxt"></div> |
| | | <template #footer> |
| | | <span class="myDialog-footer" v-if="editState"> |
| | | <el-button type="primary" class="btn" @click="dialogVisibleTecher = false" |
| | | >确 定</el-button |
| | | > |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- 查看原因 --> |
| | | <el-dialog |
| | | align-center |
| | | :close-on-click-modal="false" |
| | | v-model="dialogReason" |
| | | title="驳回原因" |
| | | > |
| | | <div class="reason" v-if="reasonTxt"> |
| | | {{ reasonTxt }} |
| | | </div> |
| | | <div v-else>无</div> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { reactive, ref, watch, defineEmits, inject, onMounted } from "vue"; |
| | | import type { FormInstance, FormRules } from "element-plus"; |
| | | import { ElMessage } from "element-plus"; |
| | | import tool from "@/assets/js/toolClass.js"; |
| | | import { getTopicMsgCmsItemFile } from "@/assets/js/middleGround/tool.js"; |
| | | import { useUserStore } from "@/store"; |
| | | const userStore = useUserStore(); |
| | | const MG: any = inject("MG"); |
| | | const config: any = inject("config"); |
| | | // 证件验证 |
| | | const valiCertificate = (rule: any, value: any, callback: any) => { |
| | | if (fileList.value.length == 0) { |
| | | callback(new Error("请上传相关证件")); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }; |
| | | |
| | | // const validateTelphone = (rule: any, value: any, callback: any) => { |
| | | // if (value !== "" && !config.reg_telphone.test(value)) { |
| | | // callback(new Error("请输入正确格式的座机号")); |
| | | // } |
| | | // callback(); |
| | | // }; |
| | | |
| | | const validatePhone = (rule: any, value: any, callback: any) => { |
| | | if (value === "") { |
| | | callback(new Error("请输入联系电话")); |
| | | } else { |
| | | if (!config.reg_tel.test(value)) { |
| | | callback(new Error("请输入正确格式的电话")); |
| | | } |
| | | callback(); |
| | | } |
| | | }; |
| | | const validateEmail = (rule: any, value: any, callback: any) => { |
| | | let myreg = /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/; |
| | | if (value === "") { |
| | | callback(new Error("请输入电子邮箱")); |
| | | } else { |
| | | if (!myreg.test(value)) { |
| | | callback(new Error("请输入正确格式的电子邮箱")); |
| | | } |
| | | callback(); |
| | | } |
| | | }; |
| | | |
| | | const props = defineProps({ |
| | | isShow: Boolean, |
| | | }); |
| | | |
| | | let teacherDialog = ref(false); //弹窗 |
| | | let loading = ref(false); |
| | | let subLoading = ref(false); |
| | | const teachPosts = ref([]); |
| | | const teacherInfo = reactive({ |
| | | schoolName: "", //学校名称 |
| | | fullName: "", //姓名 |
| | | positionalTitle: "", //职称 |
| | | courseName: "", //任课教程 |
| | | phone: "", //联系电话 |
| | | telphone: "", //座机 |
| | | email: "", //联系邮箱 |
| | | detailedAddress: "", //通讯地址 |
| | | relevantCertificates: [], //相关证件 |
| | | state: "", //审核状态默认待审核 |
| | | agree: false, |
| | | }); |
| | | const topicMessageList = ref([]); |
| | | const topicId = ref(); |
| | | const worksInfo = ref([]); |
| | | const userId = ref(); |
| | | const teacherFormRef = ref<FormInstance>(); |
| | | |
| | | interface TeacherInfo { |
| | | schoolName: string; |
| | | fullName: string; |
| | | courseName: string; |
| | | telphone: string; |
| | | phone: string; |
| | | email: string; |
| | | detailedAddress: string; |
| | | relevantCertificates: string[]; |
| | | } |
| | | const teacherRules = reactive<FormRules<TeacherInfo>>({ |
| | | schoolName: [{ required: true, message: "学校名称不能为空", trigger: "blur" }], |
| | | fullName: [{ required: true, message: "真实姓名不能为空", trigger: "blur" }], |
| | | courseName: [{ required: true, message: "任教课程不能为空", trigger: "blur" }], |
| | | // telphone: [{ validator: validateTelphone, trigger: "blur" }], |
| | | phone: [{ required: true, validator: validatePhone, trigger: "blur" }], |
| | | email: [{ required: true, validator: validateEmail, trigger: "blur" }], |
| | | detailedAddress: [{ required: true, message: "详细地址不能为空", trigger: "blur" }], |
| | | relevantCertificates: [ |
| | | { required: true, validator: valiCertificate, trigger: "change" }, |
| | | ], |
| | | }); |
| | | const fileList = ref([]); |
| | | const editState = ref<boolean>(true); |
| | | watch(props, (newValue) => { |
| | | // 统监听props的值变化,动态修改isShow的值 |
| | | teacherDialog.value = newValue.isShow; |
| | | if (teacherDialog.value) { |
| | | getpositionalTitle(); |
| | | getAgreement(); |
| | | if (localStorage.getItem(config.tokenKey)) { |
| | | getUserRole(); |
| | | } |
| | | } |
| | | }); |
| | | |
| | | // 获取职称 |
| | | function getpositionalTitle() { |
| | | const data = { |
| | | refCodes: ["positionalTitle"], |
| | | }; |
| | | MG.store.getProductTypeField(data).then((res) => { |
| | | try { |
| | | const list = res[0]; |
| | | const options = JSON.parse(list.config).option; |
| | | teachPosts.value = options; |
| | | } catch (error) { |
| | | teachPosts.value = []; |
| | | } |
| | | }); |
| | | } |
| | | |
| | | // 获取登录用户身份 |
| | | function getUserRole() { |
| | | loading.value = true; |
| | | MG.identity.getCurrentAppUser().then((res) => { |
| | | if (res) { |
| | | getType(); |
| | | userId.value = res.userId; |
| | | let userInfo = res.infoList.find((item: any) => item.type == "userInfo"); |
| | | let userTypeObj = res.infoList.find((item: any) => item.type == "userType"); |
| | | const userData = { |
| | | userName: userInfo && userInfo.data ? JSON.parse(userInfo.data).name : "", |
| | | school: userInfo && userInfo.data ? JSON.parse(userInfo.data).school : "", |
| | | address: userInfo && userInfo.data ? JSON.parse(userInfo.data).address : "", |
| | | userType: |
| | | userTypeObj && userTypeObj.data ? JSON.parse(userTypeObj.data).userType : "", |
| | | }; |
| | | let teacherRole = res.roleLinks.find((item) => item.role.refCode == "teacher"); |
| | | let teacherInfos = res.infoList.find((item) => item.type == "teacherInfo"); |
| | | let wechatInfo = res.infoList.find((item) => item.type == "WeChat"); |
| | | let studentInfo = res.infoList.find((item) => item.type == "Default"); |
| | | let phoneInfo = res.secretList.find((item) => item.type == "MobilePhone"); |
| | | let emailInfo = res.secretList.find((item) => item.type == "EMail"); |
| | | if (teacherRole && teacherInfos) { |
| | | userStore.setUserInfo({ |
| | | ...userData, |
| | | ...teacherInfos, |
| | | phoneNumber: phoneInfo?.credential, |
| | | Email: emailInfo ? emailInfo.credential : JSON.parse(teacherInfos.data).email, |
| | | icon: wechatInfo?.icon, |
| | | role: "Teacher", |
| | | roleId: teacherRole.role.id, |
| | | userId: res.userId, |
| | | }); |
| | | } else if (wechatInfo) { |
| | | userStore.setUserInfo({ |
| | | ...userData, |
| | | ...wechatInfo, |
| | | phoneNumber: phoneInfo?.credential, |
| | | Email: emailInfo?.credential, |
| | | role: "Student", |
| | | userId: res.userId, |
| | | }); |
| | | } else if (studentInfo) { |
| | | if (!studentInfo?.fullName) { |
| | | teacherInfo.fullName = userStore.userInfo!.userName; |
| | | } |
| | | userStore.setUserInfo({ |
| | | ...userData, |
| | | ...studentInfo, |
| | | icon: wechatInfo?.icon, |
| | | phoneNumber: phoneInfo?.credential, |
| | | Email: emailInfo?.credential, |
| | | role: "Student", |
| | | userId: res.userId, |
| | | }); |
| | | } else if (phoneInfo) { |
| | | userStore.setUserInfo({ |
| | | ...userData, |
| | | ...phoneInfo, |
| | | name: phoneInfo?.credential, |
| | | icon: phoneInfo?.icon, |
| | | phoneNumber: phoneInfo?.credential, |
| | | role: "Student", |
| | | userId: res.userId, |
| | | }); |
| | | } |
| | | |
| | | teacherInfo.phone = userStore.userInfo!.phoneNumber; |
| | | teacherInfo.schoolName = userStore.userInfo!.school; |
| | | teacherInfo.detailedAddress = userStore.userInfo!.address; |
| | | } |
| | | }); |
| | | } |
| | | |
| | | function getType() { |
| | | const data = { |
| | | refCodes: ["teacherCertification"], |
| | | }; |
| | | MG.resource.getCmsTypeByRefCode(data).then((res) => { |
| | | worksInfo.value = res[0].cmsTypeLinks[0].children; |
| | | newGetTeacherInfo(); |
| | | }); |
| | | } |
| | | |
| | | // 文件上传 |
| | | function fileUpload(file) { |
| | | console.log(file, 2); |
| | | return new Promise((resolve, reject) => { |
| | | const isJPG = file.file.type === "image/jpeg" || file.file.type === "image/png"; |
| | | const isLt2M = (0.5 * file.file.size) / 1024 / 1024 < 0.5; |
| | | if (!isJPG) { |
| | | ElMessage.error("上传文件只能是 jpg/png 格式!"); |
| | | return reject(); |
| | | } |
| | | if (!isLt2M) { |
| | | ElMessage.error("上传文件大小不能超过 500KB!"); |
| | | return reject(); |
| | | } |
| | | const FileName = file.file.name.split(".")[0]; |
| | | const Extension = file.file.name.split(".")[1]; |
| | | const FileType = file.file.type; |
| | | let size = 1024; |
| | | tool |
| | | .getFileMd5(file.file, size * 1024) |
| | | .then((e) => { |
| | | console.log(e, 2); |
| | | if (!fileList.value.find((item) => item.md5 == e)) { |
| | | const imgData = new FormData(); |
| | | imgData.append("Md5", e); |
| | | imgData.append("FileName", FileName); |
| | | imgData.append("Extension", Extension); |
| | | imgData.append("FileType", FileType); |
| | | imgData.append("MetaData", null); |
| | | imgData.append("file", file.file); |
| | | MG.file.upload(imgData).then(() => { |
| | | fileList.value.push({ |
| | | md5: e, |
| | | linkType: "LinkFile", |
| | | linkProtectType: "Public", |
| | | url: config.requestCtx + `/file/GetPreViewImage?md5=` + e, |
| | | }); |
| | | }); |
| | | } else { |
| | | ElMessage.error("当前文件已上传,请勿重复操作!"); |
| | | } |
| | | }) |
| | | .catch((e) => { |
| | | console.error(e); |
| | | }); |
| | | }); |
| | | } |
| | | |
| | | // 证件删除 |
| | | function handleRemove(file) { |
| | | for (let i = 0; i < fileList.value.length; i++) { |
| | | if (fileList.value[i].md5 == file.md5) { |
| | | fileList.value.splice(i, 1); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 监听文件列表变化,同步修改展示列表 |
| | | const showFileList = ref([]); |
| | | watch( |
| | | fileList, |
| | | (newValue) => { |
| | | showFileList.value = newValue.map( |
| | | (item) => config.requestCtx + `/file/GetPreViewImage?md5=` + item.md5 |
| | | ); |
| | | }, |
| | | { immediate: true, deep: true } |
| | | ); |
| | | |
| | | // 关闭弹框,回调父层方法 |
| | | const emit = defineEmits(["dialogChange"]); |
| | | const closeDialog = (formEl: FormInstance | undefined) => { |
| | | if (!formEl) return; |
| | | formEl.resetFields(); |
| | | teacherDialog.value = false; |
| | | emit("dialogChange", teacherDialog.value); |
| | | }; |
| | | |
| | | // 教师协议 |
| | | const dialogVisibleTecher = ref(false); |
| | | const protocolTxt = ref(""); |
| | | const getAgreement = () => { |
| | | let query = { |
| | | path: "protocol", |
| | | fields: { |
| | | content: [], |
| | | }, |
| | | }; |
| | | MG.resource.getItem(query).then((res) => { |
| | | try { |
| | | const data = res.datas.find( |
| | | (e) => e.refCode == "teacherCertificationAgreement" |
| | | ); |
| | | protocolTxt.value = data ? data.content : "暂无协议"; |
| | | } catch (error) { |
| | | protocolTxt.value = "暂无协议"; |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | //教师信息 |
| | | function newGetTeacherInfo() { |
| | | const data = { |
| | | start: 0, |
| | | size: 10, |
| | | topicIdOrRefCode: "teacherRoleApproval", |
| | | appRefCode: config.appRefCode, |
| | | sort: { |
| | | type: "Desc", |
| | | field: "CreateDate", |
| | | }, |
| | | }; |
| | | MG.ugc.getTopicMessageList(data).then((res) => { |
| | | try { |
| | | fileList.value = []; |
| | | const resData = res.datas.find((i) => i.appUserCreator.userId === userId.value); |
| | | if (resData) { |
| | | if (resData.state == "WaitAudit") { |
| | | editState.value = false; |
| | | } else { |
| | | editState.value = true; |
| | | } |
| | | let info = getTopicMsgCmsItemFile(worksInfo.value, resData.cmsItemDataList); |
| | | teacherInfo.fullName = info.fullName; |
| | | teacherInfo.schoolName = info.schoolName; |
| | | teacherInfo.positionalTitle = info.positionalTitle; |
| | | teacherInfo.courseName = info.courseName; |
| | | teacherInfo.phone = info.phone; |
| | | teacherInfo.telphone = info.telphone ? info.telphone : ""; |
| | | teacherInfo.email = info.email; |
| | | teacherInfo.detailedAddress = info.detailedAddress ? info.detailedAddress : ""; |
| | | teacherInfo.relevantCertificates = info.relevantCertificates; |
| | | teacherInfo.agree = true; |
| | | teacherInfo.state = resData.state; |
| | | topicId.value = resData.id; |
| | | topicMessageList.value = resData.cmsItemDataList; |
| | | if (resData.feedBack != null) { |
| | | reasonTxt.value = JSON.parse(resData.feedBack).reason; |
| | | } |
| | | if (teacherInfo.relevantCertificates.length > 0) { |
| | | if (typeof teacherInfo.relevantCertificates == "object") { |
| | | teacherInfo.relevantCertificates.forEach((ele) => { |
| | | let imgObj = { |
| | | md5: ele.file.md5, |
| | | linkType: "LinkFile", |
| | | linkProtectType: "Public", |
| | | url: config.requestCtx + `/file/GetPreViewImage?md5=` + ele.file.md5, |
| | | }; |
| | | fileList.value.push(imgObj); |
| | | }); |
| | | } else { |
| | | let imgObj = { |
| | | md5: teacherInfo.relevantCertificates, |
| | | linkType: "LinkFile", |
| | | linkProtectType: "Public", |
| | | url: |
| | | config.requestCtx + |
| | | `/file/GetPreViewImage?md5=` + |
| | | teacherInfo.relevantCertificates, |
| | | }; |
| | | fileList.value.push(imgObj); |
| | | } |
| | | } |
| | | loading.value = false; |
| | | } else { |
| | | loading.value = false; |
| | | } |
| | | } catch (error) { |
| | | loading.value = false; |
| | | } |
| | | }); |
| | | } |
| | | |
| | | //教师认证提交 |
| | | const submitBtn = async (formEl: FormInstance | undefined) => { |
| | | if (!formEl) return; |
| | | await formEl.validate((valid, fields) => { |
| | | if (valid) { |
| | | if (teacherInfo.agree) { |
| | | subLoading.value = true; |
| | | if (topicMessageList.value.length > 0) { |
| | | let dataRequests = tool.UpdateworksDataBytool( |
| | | worksInfo.value, |
| | | topicMessageList.value, |
| | | teacherInfo, |
| | | fileList.value |
| | | ); |
| | | const data = { |
| | | description: "", |
| | | icon: "", |
| | | id: topicId.value, |
| | | topicIdOrRefCode: "teacherRoleApproval", |
| | | name: teacherInfo.fullName + "", |
| | | content: "", |
| | | state: "WaitAudit", |
| | | type: "teacherRegister", |
| | | newDataRequests: dataRequests.newData, |
| | | updateDataRequests: dataRequests.updateData, |
| | | delDataRequest: { |
| | | ids: [], |
| | | }, |
| | | }; |
| | | let basicInfo = JSON.parse(JSON.stringify(teacherInfo)); |
| | | delete basicInfo.worksInfo; |
| | | delete basicInfo.state; |
| | | const userInfo = { |
| | | requests: [ |
| | | { |
| | | data: JSON.stringify(basicInfo), |
| | | name: teacherInfo.fullName + "", |
| | | type: "newTeacherInfo", |
| | | }, |
| | | ], |
| | | }; |
| | | MG.identity.setAppUserInfo(userInfo).then((res) => { |
| | | if (res) { |
| | | MG.ugc.updateTopicMessage(data).then(() => { |
| | | if (res !== false) { |
| | | ElMessage({ |
| | | message: "提交成功!请等待审核...", |
| | | type: "success", |
| | | }); |
| | | teacherDialog.value = false; |
| | | subLoading.value = false; |
| | | newGetTeacherInfo(); |
| | | } else { |
| | | subLoading.value = false; |
| | | } |
| | | }); |
| | | } else { |
| | | subLoading.value = true; |
| | | } |
| | | }); |
| | | } else { |
| | | const data = { |
| | | topicIdOrRefCode: "teacherRoleApproval", |
| | | name: teacherInfo.fullName + "", |
| | | content: "", |
| | | state: "WaitAudit", |
| | | type: "teacherRegister", |
| | | cmsTypeRefCode: "teacherCertification", |
| | | newDataListRequest: tool.worksDataBytool( |
| | | worksInfo.value, |
| | | teacherInfo, |
| | | fileList.value |
| | | ), |
| | | }; |
| | | |
| | | let basicInfo = JSON.parse(JSON.stringify(teacherInfo)); |
| | | delete basicInfo.worksInfo; |
| | | delete basicInfo.state; |
| | | const userInfo = { |
| | | requests: [ |
| | | { |
| | | data: JSON.stringify(basicInfo), |
| | | name: teacherInfo.fullName + "", |
| | | type: "teacherInfo", |
| | | }, |
| | | ], |
| | | }; |
| | | MG.identity.setAppUserInfo(userInfo).then((res) => { |
| | | MG.ugc.newTopicMessage(data).then(() => { |
| | | if (res !== false) { |
| | | ElMessage({ |
| | | message: "提交成功!请等待审核...", |
| | | type: "success", |
| | | }); |
| | | teacherDialog.value = false; |
| | | newGetTeacherInfo(); |
| | | subLoading.value = false; |
| | | } else { |
| | | subLoading.value = false; |
| | | } |
| | | }); |
| | | }); |
| | | } |
| | | } else { |
| | | ElMessage({ |
| | | message: "请同意《教师认证服务条款》!", |
| | | type: "warning", |
| | | }); |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | //原因查看 |
| | | const dialogReason = ref(false); |
| | | const reasonTxt = ref(""); |
| | | const lookReason = () => { |
| | | dialogReason.value = true; |
| | | }; |
| | | defineExpose({ getUserRole }); |
| | | </script> |
| | | <style lang="less"> |
| | | .myDialog { |
| | | width: 628px; |
| | | .el-dialog__body { |
| | | padding: 0; |
| | | } |
| | | .body-box { |
| | | padding: 10px 20px 40px; |
| | | height: 80vh; |
| | | overflow-y: auto; |
| | | } |
| | | |
| | | .el-dialog__header { |
| | | padding: 15px; |
| | | margin-right: 0; |
| | | border-bottom: 1px solid #f4f4f4; |
| | | } |
| | | .el-dialog__title { |
| | | font-weight: bold; |
| | | font-size: 16px; |
| | | } |
| | | |
| | | .el-dialog__headerbtn { |
| | | top: 6px; |
| | | right: 6px; |
| | | } |
| | | |
| | | .footer-box { |
| | | padding: 15px; |
| | | border-top: 1px solid #f4f4f4; |
| | | text-align: right; |
| | | height: 63px; |
| | | } |
| | | |
| | | .myDialog-footer { |
| | | .el-button { |
| | | padding: 0 20px; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | | <style lang="less" scoped> |
| | | .tipsBox { |
| | | line-height: 24px; |
| | | padding: 5px; |
| | | border: 1px solid #019e58; |
| | | background: rgba(116, 252, 188, 0.1); |
| | | color: #019e58; |
| | | text-align: center; |
| | | width: 86%; |
| | | margin: 0 auto 20px auto; |
| | | |
| | | .main { |
| | | font-weight: bold; |
| | | text-align: center; |
| | | } |
| | | } |
| | | |
| | | .teacherInfo { |
| | | .el-select { |
| | | width: 90%; |
| | | height: 38px; |
| | | |
| | | /deep/.el-input__wrapper { |
| | | height: 38px; |
| | | } |
| | | } |
| | | |
| | | .el-input { |
| | | width: 90%; |
| | | height: 38px; |
| | | } |
| | | } |
| | | |
| | | .uploadBox { |
| | | padding: 10px 0 0 10px; |
| | | border: 1px solid #e9e9eb; |
| | | border-radius: 3px; |
| | | width: 330px; |
| | | } |
| | | |
| | | .fileList .upload { |
| | | display: inline-block; |
| | | vertical-align: middle; |
| | | margin-right: 10px; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .fileImgBox { |
| | | display: inline-block; |
| | | position: relative; |
| | | width: 146px; |
| | | height: 146px; |
| | | border-radius: 6px; |
| | | background: #ddd; |
| | | margin-right: 10px; |
| | | margin-bottom: 10px; |
| | | vertical-align: middle; |
| | | border: 1px solid #c0ccda; |
| | | } |
| | | |
| | | .fileList .fileImgBox:hover { |
| | | border-color: #019E58; |
| | | } |
| | | |
| | | .agree-msg { |
| | | margin-left: 140px; |
| | | display: flex; |
| | | justify-content: flex-start; |
| | | align-items: center; |
| | | |
| | | .agree { |
| | | margin-left: 5px; |
| | | } |
| | | |
| | | .term { |
| | | color: #019E58; |
| | | } |
| | | } |
| | | .reason { |
| | | word-wrap: break-word; |
| | | } |
| | | .protocolBox { |
| | | height: 500px; |
| | | overflow-y: auto; |
| | | } |
| | | </style> |
| | |
| | | <div class="info-box flex"> |
| | | <span class="label">用户名:</span> |
| | | <span class="text">{{ userStore?.userInfo.name }}</span> |
| | | <span class="change-info hover" @click="changeUserInfo('password')">修改密码</span> |
| | | <span class="change-info hover" @click="changeUserInfo('password')" |
| | | >修改密码</span |
| | | > |
| | | </div> |
| | | <div class="info-box flex"> |
| | | <span class="label">微信认证:</span> |
| | |
| | | }}</span> |
| | | <span class="text no" v-else>未绑定</span> |
| | | <span class="change-info hover" @click="changeUserInfo('phone')">{{ |
| | | userStore?.userInfo?.phoneNumber ? '更换手机号' : '绑定' |
| | | userStore?.userInfo?.phoneNumber ? "更换手机号" : "绑定" |
| | | }}</span> |
| | | </div> |
| | | <div class="info-box flex"> |
| | | <span class="label">邮箱:</span> |
| | | <span class="text">{{ |
| | | userStore?.userInfo?.Email ? userStore.userInfo?.Email : '--' |
| | | userStore?.userInfo?.Email ? userStore.userInfo?.Email : "--" |
| | | }}</span> |
| | | <span class="change-info hover" @click="changeUserInfo('email')">{{ |
| | | userStore?.userInfo?.Email ? '更换邮箱' : '绑定邮箱' |
| | | userStore?.userInfo?.Email ? "更换邮箱" : "绑定邮箱" |
| | | }}</span> |
| | | </div> |
| | | </div> |
| | |
| | | <div class="item-title flex jc-sb"> |
| | | <span>教师认证</span> |
| | | <div> |
| | | <span class="change-info hover" v-if="teacherState == ''" @click="showTeacherDialog()" |
| | | <span |
| | | class="change-info hover" |
| | | v-if="teacherState == ''" |
| | | @click="showTeacherDialog()" |
| | | >认证</span |
| | | > |
| | | <span |
| | |
| | | destroy-on-close |
| | | v-model="userInfoDialog" |
| | | :title=" |
| | | changeType == 'email' ? '更换邮箱' : changeType == 'password' ? '修改密码' : '更换手机号' |
| | | changeType == 'email' |
| | | ? '更换邮箱' |
| | | : changeType == 'password' |
| | | ? '修改密码' |
| | | : '更换手机号' |
| | | " |
| | | width="500" |
| | | class="myDialogs" |
| | |
| | | > |
| | | {{ |
| | | countDown > 0 |
| | | ? '验证码(' + countDown + 's)' |
| | | : changeType == 'email' |
| | | ? '获取邮箱验证码' |
| | | : '获取短信验证码' |
| | | ? "验证码(" + countDown + "s)" |
| | | : changeType == "email" |
| | | ? "获取邮箱验证码" |
| | | : "获取短信验证码" |
| | | }} |
| | | </el-button> |
| | | </div> |
| | |
| | | placeholder="请输入8-16位新密码,且不能为纯数字" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="确认密码:" prop="confirmPassword" v-if="changeType == 'password'"> |
| | | <el-form-item |
| | | label="确认密码:" |
| | | prop="confirmPassword" |
| | | v-if="changeType == 'password'" |
| | | > |
| | | <el-input |
| | | type="password" |
| | | v-model="userInfoForm.confirmPassword" |
| | |
| | | <template #footer> |
| | | <span class="myDialogs-footer"> |
| | | <el-button @click="closeUserInfoDialog(userFormRef)">取消</el-button> |
| | | <el-button type="primary" @click="confirmInfo(userFormRef)" :loading="subLoading"> |
| | | <el-button |
| | | type="primary" |
| | | @click="confirmInfo(userFormRef)" |
| | | :loading="subLoading" |
| | | > |
| | | 确定 |
| | | </el-button> |
| | | </span> |
| | |
| | | <li v-for="item in integralRecord.recordList" :key="item.key" class="body"> |
| | | <span class="label">{{ item.type }}</span> |
| | | <span class="value" :class="item.value > 0 ? 'yes' : 'no'">{{ |
| | | item.value > 0 ? '+' + item.value : item.value |
| | | item.value > 0 ? "+" + item.value : item.value |
| | | }}</span> |
| | | <span>{{ item.createDate ? item.createDate : '-' }}</span> |
| | | <span>{{ item.createDate ? item.createDate : "-" }}</span> |
| | | </li> |
| | | <li class="total" v-if="integralRecord.recordList.length > 0"> |
| | | <span class="label">总计</span> |
| | |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { reactive, ref, inject, onMounted, watch } from 'vue' |
| | | import type { FormInstance, FormRules } from 'element-plus' |
| | | import { reactive, ref, inject, onMounted, watch } from "vue"; |
| | | import type { FormInstance, FormRules } from "element-plus"; |
| | | // import verify from '@/components/sliderImg/component/verify.vue' |
| | | // import '@/components/sliderImg/sliderImg.js' |
| | | // import '@/components/sliderImg/sliderImg.css' |
| | | import { ElMessage } from 'element-plus' |
| | | import tool from '@/assets/js/toolClass.js' |
| | | // import { useUserStore } from '@/store' |
| | | import { ElMessage } from "element-plus"; |
| | | import tool from "@/assets/js/toolClass.js"; |
| | | import { useUserStore } from "@/store"; |
| | | // import wxlogin from 'vue-wxlogin' |
| | | // import teacherCertification from '@/views/components/teacherCertification.vue' |
| | | import teacherCertification from "./teacherCertification.vue"; |
| | | // import login from '@/layout/components/login.vue' |
| | | // const userStore = useUserStore() |
| | | import { useRoute } from 'vue-router' |
| | | import moment from 'moment' |
| | | const route = useRoute() |
| | | const MG: any = inject('MG') |
| | | const config: any = inject('config') |
| | | const userStore = useUserStore(); |
| | | import { useRoute } from "vue-router"; |
| | | import moment from "moment"; |
| | | const route = useRoute(); |
| | | const MG: any = inject("MG"); |
| | | const config: any = inject("config"); |
| | | |
| | | const validatePhone = (rule: any, value: any, callback: any) => { |
| | | if (value === '') { |
| | | callback(new Error('请输入联系电话')) |
| | | if (value === "") { |
| | | callback(new Error("请输入联系电话")); |
| | | } else { |
| | | if (!config.reg_tel.test(value)) { |
| | | callback(new Error('请输入正确格式的电话')) |
| | | callback(new Error("请输入正确格式的电话")); |
| | | } |
| | | callback() |
| | | callback(); |
| | | } |
| | | } |
| | | }; |
| | | const validateEmail = (rule: any, value: any, callback: any) => { |
| | | let myreg = /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/ |
| | | if (value === '') { |
| | | callback(new Error('请输入电子邮箱')) |
| | | let myreg = /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/; |
| | | if (value === "") { |
| | | callback(new Error("请输入电子邮箱")); |
| | | } else { |
| | | if (!myreg.test(value)) { |
| | | callback(new Error('请输入正确格式的电子邮箱')) |
| | | callback(new Error("请输入正确格式的电子邮箱")); |
| | | } |
| | | callback() |
| | | callback(); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const validatePassword = (rule: any, value: any, callback: any) => { |
| | | let myreg = /^(?!^\d+$)(?!^[a-zA-Z]+$)(?!^\W+$)[a-zA-Z\d\W]{8,16}$/ |
| | | if (value === '') { |
| | | callback(new Error('请输入密码')) |
| | | let myreg = /^(?!^\d+$)(?!^[a-zA-Z]+$)(?!^\W+$)[a-zA-Z\d\W]{8,16}$/; |
| | | if (value === "") { |
| | | callback(new Error("请输入密码")); |
| | | } else { |
| | | if (!myreg.test(value)) { |
| | | callback(new Error('请输入正确格式的密码,8-16位,且不能为纯数字')) |
| | | callback(new Error("请输入正确格式的密码,8-16位,且不能为纯数字")); |
| | | } |
| | | callback() |
| | | callback(); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | // onMounted(() => { |
| | | // getWechatAuthenticationState() |
| | | // getIntegral() |
| | | // if (localStorage.getItem(config.tokenKey)) { |
| | | // getUserRole() |
| | | // } |
| | | // }) |
| | | onMounted(() => { |
| | | getWechatAuthenticationState(); |
| | | getIntegral(); |
| | | if (localStorage.getItem(config.tokenKey)) { |
| | | getUserRole(); |
| | | } |
| | | }); |
| | | |
| | | // watch(route, () => { |
| | | // bindWeChat() |
| | | // }) |
| | | let subLoading = ref(false) |
| | | let subLoading = ref(false); |
| | | //用户信息 |
| | | let weChatState = ref(false) |
| | | let weChatState = ref(false); |
| | | const userInfo = reactive({ |
| | | userType: '', |
| | | userType: "", |
| | | integral: 0, |
| | | }) |
| | | }); |
| | | //基础信息 |
| | | const userInfoDialog = ref(false) |
| | | let changeType = ref('password') |
| | | const imgCode = ref<string>() // 图形验证码url |
| | | let countDown = ref(0) |
| | | // function changeUserInfo(type) { |
| | | // changeType.value = type |
| | | // if (type == 'password') { |
| | | // if (userStore.userInfo?.phoneNumber) { |
| | | // getImgCapcha() |
| | | // userInfoDialog.value = true |
| | | // } else { |
| | | // ElMessage({ |
| | | // message: '修改密码需短信验证,请绑定手机号后再修改密码!', |
| | | // type: 'warning' |
| | | // }) |
| | | // } |
| | | // } else { |
| | | // getImgCapcha() |
| | | // userInfoDialog.value = true |
| | | // } |
| | | // } |
| | | // const getImgCapcha = () => { |
| | | // MG.identity.getImgCode().then((res) => { |
| | | // imgCode.value = 'data:image/png;base64,' + res |
| | | // }) |
| | | // } |
| | | const userInfoDialog = ref(false); |
| | | let changeType = ref("password"); |
| | | const imgCode = ref<string>(); // 图形验证码url |
| | | let countDown = ref(0); |
| | | |
| | | const userFormRef = ref<FormInstance>() |
| | | const changeUserInfo = (type) => { |
| | | changeType.value = type; |
| | | if (type == "password") { |
| | | if (userStore.userInfo?.phoneNumber) { |
| | | getImgCapcha(); |
| | | userInfoDialog.value = true; |
| | | } else { |
| | | ElMessage({ |
| | | message: "修改密码需短信验证,请绑定手机号后再修改密码!", |
| | | type: "warning", |
| | | }); |
| | | } |
| | | } else { |
| | | getImgCapcha(); |
| | | userInfoDialog.value = true; |
| | | } |
| | | }; |
| | | const getImgCapcha = () => { |
| | | MG.identity.getImgCode().then((res) => { |
| | | imgCode.value = "data:image/png;base64," + res; |
| | | }); |
| | | }; |
| | | |
| | | const userFormRef = ref<FormInstance>(); |
| | | const userInfoForm = reactive({ |
| | | phone: '', |
| | | email: '', |
| | | captcha: '', |
| | | code: '', |
| | | password: '', |
| | | confirmPassword: '', |
| | | }) |
| | | const formDisabled = ref(false) |
| | | phone: "", |
| | | email: "", |
| | | captcha: "", |
| | | code: "", |
| | | password: "", |
| | | confirmPassword: "", |
| | | }); |
| | | const formDisabled = ref(false); |
| | | const userFormRules = reactive<FormRules<userInfoForm>>({ |
| | | phone: [{ required: true, validator: validatePhone, trigger: 'blur' }], |
| | | email: [{ required: true, validator: validateEmail, trigger: 'blur' }], |
| | | phone: [{ required: true, validator: validatePhone, trigger: "blur" }], |
| | | email: [{ required: true, validator: validateEmail, trigger: "blur" }], |
| | | captcha: [ |
| | | { required: true, message: '图形验证码不能为空', trigger: 'blur' }, |
| | | { min: 4, max: 4, message: '请输入 4 位验证码', trigger: 'blur' }, |
| | | { required: true, message: "图形验证码不能为空", trigger: "blur" }, |
| | | { min: 4, max: 4, message: "请输入 4 位验证码", trigger: "blur" }, |
| | | ], |
| | | code: [{ required: true, message: '验证码不能为空', trigger: 'blur' }], |
| | | password: [{ required: true, validator: validatePassword, trigger: 'blur' }], |
| | | confirmPassword: [{ required: true, message: '确认密码不能为空', trigger: 'blur' }], |
| | | }) |
| | | code: [{ required: true, message: "验证码不能为空", trigger: "blur" }], |
| | | password: [{ required: true, validator: validatePassword, trigger: "blur" }], |
| | | confirmPassword: [{ required: true, message: "确认密码不能为空", trigger: "blur" }], |
| | | }); |
| | | |
| | | const getVerifyCode = async () => { |
| | | sliderImgDialogVisable.value = true |
| | | } |
| | | sliderImgDialogVisable.value = true; |
| | | }; |
| | | |
| | | // 验证码倒计时 |
| | | function getSecond(time: number) { |
| | | let timer: ReturnType<typeof setInterval> | null = null |
| | | let timer: ReturnType<typeof setInterval> | null = null; |
| | | if (!timer) { |
| | | countDown.value = time |
| | | countDown.value = time; |
| | | timer = setInterval(() => { |
| | | countDown.value-- |
| | | countDown.value--; |
| | | if (countDown.value == 0) { |
| | | if (timer) clearInterval(timer) |
| | | timer = null |
| | | if (timer) clearInterval(timer); |
| | | timer = null; |
| | | } |
| | | }, 1000) |
| | | }, 1000); |
| | | } |
| | | } |
| | | |
| | | const closeUserInfoDialog = (formEl: FormInstance | undefined) => { |
| | | if (!formEl) return |
| | | formEl.resetFields() |
| | | countDown.value = 0 |
| | | userInfoDialog.value = false |
| | | } |
| | | if (!formEl) return; |
| | | formEl.resetFields(); |
| | | countDown.value = 0; |
| | | userInfoDialog.value = false; |
| | | }; |
| | | const confirmInfo = async (formEl: FormInstance | undefined) => { |
| | | if (!formEl) return |
| | | if (!formEl) return; |
| | | await formEl.validate((valid, fields) => { |
| | | if (valid) { |
| | | subLoading.value = true |
| | | if (changeType.value == 'password') { |
| | | subLoading.value = true; |
| | | if (changeType.value == "password") { |
| | | if (userInfoForm.password != userInfoForm.confirmPassword) { |
| | | ElMessage({ |
| | | message: '两次密码输入不一致', |
| | | type: 'warning', |
| | | }) |
| | | return false |
| | | message: "两次密码输入不一致", |
| | | type: "warning", |
| | | }); |
| | | return false; |
| | | } |
| | | let query = { |
| | | phoneNumber: userInfoForm.phone, |
| | | phoneCaptcha: userInfoForm.code, |
| | | password: userInfoForm.password, |
| | | } |
| | | }; |
| | | MG.identity.changePasswordByMobilePhone(query).then((res) => { |
| | | if (res) { |
| | | ElMessage({ |
| | | message: '密码重置成功!', |
| | | type: 'success', |
| | | }) |
| | | userInfoDialog.value = false |
| | | message: "密码重置成功!", |
| | | type: "success", |
| | | }); |
| | | userInfoDialog.value = false; |
| | | } else { |
| | | ElMessage({ |
| | | message: '密码重置失败,请填写正确的验证码。', |
| | | type: 'error', |
| | | }) |
| | | message: "密码重置失败,请填写正确的验证码。", |
| | | type: "error", |
| | | }); |
| | | } |
| | | subLoading.value = false |
| | | }) |
| | | } else if (changeType.value == 'phone') { |
| | | subLoading.value = false; |
| | | }); |
| | | } else if (changeType.value == "phone") { |
| | | let query = { |
| | | phoneNumber: userInfoForm.phone, |
| | | phoneCaptcha: userInfoForm.code, |
| | | } |
| | | }; |
| | | MG.identity.userSetPhoneNumber(query).then((res) => { |
| | | if (res == '验证码过期或错误') { |
| | | if (res == "验证码过期或错误") { |
| | | ElMessage({ |
| | | message: res + ',请稍后重试', |
| | | type: 'error', |
| | | }) |
| | | } else if (res == '此手机号码已被其它账号绑定') { |
| | | message: res + ",请稍后重试", |
| | | type: "error", |
| | | }); |
| | | } else if (res == "此手机号码已被其它账号绑定") { |
| | | ElMessage({ |
| | | message: res + ',请更换其他手机号。', |
| | | type: 'error', |
| | | }) |
| | | message: res + ",请更换其他手机号。", |
| | | type: "error", |
| | | }); |
| | | } else { |
| | | ElMessage({ |
| | | message: res, |
| | | type: 'success', |
| | | }) |
| | | type: "success", |
| | | }); |
| | | userStore.setUserInfo({ |
| | | ...userStore.userInfo, |
| | | phoneNumber: userInfoForm.phone, |
| | | }) |
| | | userInfoDialog.value = false |
| | | }); |
| | | userInfoDialog.value = false; |
| | | } |
| | | subLoading.value = false |
| | | }) |
| | | } else if (changeType.value == 'email') { |
| | | subLoading.value = false; |
| | | }); |
| | | } else if (changeType.value == "email") { |
| | | let query = { |
| | | eMail: userInfoForm.email, |
| | | captcha: userInfoForm.code, |
| | | } |
| | | }; |
| | | |
| | | MG.identity.bindingEmail(query).then((res) => { |
| | | if (res == '验证码过期') { |
| | | if (res == "验证码过期") { |
| | | ElMessage({ |
| | | message: res + ',请稍后重试', |
| | | type: 'error', |
| | | }) |
| | | } else if (res == '此邮箱已被其它账号绑定') { |
| | | message: res + ",请稍后重试", |
| | | type: "error", |
| | | }); |
| | | } else if (res == "此邮箱已被其它账号绑定") { |
| | | ElMessage({ |
| | | message: res + ',请更换其他邮箱。', |
| | | type: 'error', |
| | | }) |
| | | } else if (res == '验证码无效') { |
| | | message: res + ",请更换其他邮箱。", |
| | | type: "error", |
| | | }); |
| | | } else if (res == "验证码无效") { |
| | | ElMessage({ |
| | | message: res, |
| | | type: 'error', |
| | | }) |
| | | type: "error", |
| | | }); |
| | | } else { |
| | | ElMessage({ |
| | | message: res, |
| | | type: 'success', |
| | | }) |
| | | type: "success", |
| | | }); |
| | | userStore.setUserInfo({ |
| | | ...userStore.userInfo, |
| | | Email: userInfoForm.email, |
| | | }) |
| | | userInfoDialog.value = false |
| | | }); |
| | | userInfoDialog.value = false; |
| | | } |
| | | subLoading.value = false |
| | | }) |
| | | subLoading.value = false; |
| | | }); |
| | | } |
| | | } else { |
| | | subLoading.value = false |
| | | subLoading.value = false; |
| | | } |
| | | }) |
| | | } |
| | | }); |
| | | }; |
| | | // 滑动验证 |
| | | const sliderImgDialogVisable = ref<boolean>(false) |
| | | const sliderImgDialogVisable = ref<boolean>(false); |
| | | const loginImgVerify = (code: string) => { |
| | | userInfoForm.captcha = code |
| | | sliderImgDialogVisable.value = false |
| | | if (changeType.value == 'phone' || changeType.value == 'password') { |
| | | userInfoForm.captcha = code; |
| | | sliderImgDialogVisable.value = false; |
| | | if (changeType.value == "phone" || changeType.value == "password") { |
| | | MG.identity |
| | | .getPhoneCode({ |
| | | phoneNumber: userInfoForm.phone, |
| | |
| | | appRefCode: config.appRefCode, |
| | | }) |
| | | .then((res: any) => { |
| | | if (res == '验证码发送成功') { |
| | | if (res == "验证码发送成功") { |
| | | ElMessage({ |
| | | message: res, |
| | | type: 'success', |
| | | }) |
| | | type: "success", |
| | | }); |
| | | // 开启短信验证倒计时 |
| | | getSecond(60) |
| | | getSecond(60); |
| | | } else { |
| | | ElMessage({ |
| | | message: res, |
| | | type: 'error', |
| | | }) |
| | | type: "error", |
| | | }); |
| | | } |
| | | }) |
| | | } else if (changeType.value == 'email') { |
| | | }); |
| | | } else if (changeType.value == "email") { |
| | | MG.identity |
| | | .getEmailCode({ |
| | | sendEmail: userInfoForm.email, |
| | |
| | | .then((res) => { |
| | | if (res == true) { |
| | | ElMessage({ |
| | | message: '邮件已发送', |
| | | type: 'success', |
| | | }) |
| | | message: "邮件已发送", |
| | | type: "success", |
| | | }); |
| | | } else { |
| | | ElMessage({ |
| | | message: '邮件发送失败', |
| | | type: 'error', |
| | | }) |
| | | message: "邮件发送失败", |
| | | type: "error", |
| | | }); |
| | | } |
| | | }) |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | | //微信认证 |
| | | let wxLogin = reactive({ |
| | | appid: 'wx5cfe8b007a3c6f8c', |
| | | scope: 'snsapi_login', |
| | | redirectURL: encodeURIComponent(config.requestCtx + '/home/#/personalCenter'), |
| | | }) |
| | | appid: "wx5cfe8b007a3c6f8c", |
| | | scope: "snsapi_login", |
| | | redirectURL: encodeURIComponent(config.requestCtx + "/home/#/personalCenter"), |
| | | }); |
| | | const getWechatAuthenticationState = () => { |
| | | MG.identity.checkBuildingWeChat({}).then((res: any) => { |
| | | if (res) { |
| | | weChatState.value = true |
| | | weChatState.value = true; |
| | | } else { |
| | | weChatState.value = false |
| | | weChatState.value = false; |
| | | } |
| | | }) |
| | | } |
| | | const weChartDialog = ref(false) |
| | | }); |
| | | }; |
| | | const weChartDialog = ref(false); |
| | | function goBindWeChat() { |
| | | window.location.href = `https://open.weixin.qq.com/connect/qrconnect?appid=${wxLogin.appid}&scope=${wxLogin.scope}&redirect_uri=${wxLogin.redirectURL}&state=WeChatScanningCodeBind` |
| | | window.location.href = `https://open.weixin.qq.com/connect/qrconnect?appid=${wxLogin.appid}&scope=${wxLogin.scope}&redirect_uri=${wxLogin.redirectURL}&state=WeChatScanningCodeBind`; |
| | | } |
| | | |
| | | //绑定微信 |
| | | const bindWeChat = () => { |
| | | var url = window.location.href |
| | | if (url.indexOf('WeChatScanningCodeBind') > -1) { |
| | | var querys = url.substring(url.indexOf('?') + 1).split('&') |
| | | var result = {} |
| | | var url = window.location.href; |
| | | if (url.indexOf("WeChatScanningCodeBind") > -1) { |
| | | var querys = url.substring(url.indexOf("?") + 1).split("&"); |
| | | var result = {}; |
| | | for (var i = 0; i < querys.length; i++) { |
| | | var temp = querys[i].split('=') |
| | | var temp = querys[i].split("="); |
| | | if (temp.length < 2) { |
| | | result[temp[0]] = '' |
| | | result[temp[0]] = ""; |
| | | } else { |
| | | result[temp[0]] = temp[1] |
| | | result[temp[0]] = temp[1]; |
| | | } |
| | | } |
| | | if (result && result.code) { |
| | |
| | | .then((res) => { |
| | | if (res) { |
| | | ElMessage({ |
| | | message: '绑定成功!', |
| | | type: 'success', |
| | | }) |
| | | getWechatAuthenticationState() |
| | | weChartDialog.value = false |
| | | message: "绑定成功!", |
| | | type: "success", |
| | | }); |
| | | getWechatAuthenticationState(); |
| | | weChartDialog.value = false; |
| | | } else { |
| | | ElMessage({ |
| | | message: '绑定失败,该微信已被绑定!', |
| | | type: 'error', |
| | | }) |
| | | message: "绑定失败,该微信已被绑定!", |
| | | type: "error", |
| | | }); |
| | | } |
| | | }) |
| | | }); |
| | | } |
| | | } |
| | | } |
| | | }; |
| | | |
| | | //用户类型 |
| | | const loginRef = ref() |
| | | const loginRef = ref(); |
| | | // const userTypeDialog = ref(false) |
| | | const userTypeActive = ref('') |
| | | const teacherType = ref('') |
| | | const userTypeActive = ref(""); |
| | | const teacherType = ref(""); |
| | | const teacherList = ref([ |
| | | { |
| | | value: 'vocSchoolTeachers', |
| | | label: '中职教师', |
| | | value: "vocSchoolTeachers", |
| | | label: "中职教师", |
| | | }, |
| | | { |
| | | value: 'vocCollegeTeachers', |
| | | label: '高职教师', |
| | | value: "vocCollegeTeachers", |
| | | label: "高职教师", |
| | | }, |
| | | { |
| | | value: 'ordUniversityTeachers', |
| | | label: '本科教师', |
| | | value: "ordUniversityTeachers", |
| | | label: "本科教师", |
| | | }, |
| | | { |
| | | value: 'primarySchoolTeachers', |
| | | label: '中小学教师', |
| | | value: "primarySchoolTeachers", |
| | | label: "中小学教师", |
| | | }, |
| | | { |
| | | value: 'kindergarteTeachers', |
| | | label: '幼儿园教师', |
| | | value: "kindergarteTeachers", |
| | | label: "幼儿园教师", |
| | | }, |
| | | ]) |
| | | ]); |
| | | const userTypeList = ref([ |
| | | { |
| | | value: 'Teacher', |
| | | label: '教师', |
| | | value: "Teacher", |
| | | label: "教师", |
| | | checked: false, |
| | | }, |
| | | { |
| | | value: 'Student', |
| | | label: '学生', |
| | | value: "Student", |
| | | label: "学生", |
| | | checked: false, |
| | | }, |
| | | { |
| | | value: 'otherReaders', |
| | | label: '其他读者', |
| | | value: "otherReaders", |
| | | label: "其他读者", |
| | | checked: false, |
| | | }, |
| | | ]) |
| | | ]); |
| | | |
| | | // 修改用户类型调用注册时用户信息填写弹窗 |
| | | const updateUserInfo = () => { |
| | | loginRef.value.updateUserInfo() |
| | | loginRef.value.signUp() |
| | | } |
| | | loginRef.value.updateUserInfo(); |
| | | loginRef.value.signUp(); |
| | | }; |
| | | |
| | | //教师认证 |
| | | let teacherDialog = ref(false) //弹窗 |
| | | let loading = ref(false) |
| | | const teacherState = ref(null) |
| | | const reasonTxt = ref('') |
| | | const userId = ref() |
| | | let teacherDialog = ref(false); //弹窗 |
| | | let loading = ref(false); |
| | | const teacherState = ref(null); |
| | | const reasonTxt = ref(""); |
| | | const userId = ref(); |
| | | |
| | | const dialogReason = ref(false) |
| | | const dialogReason = ref(false); |
| | | //教师认证弹窗 |
| | | function showTeacherDialog() { |
| | | teacherDialog.value = true |
| | | teacherDialog.value = true; |
| | | } |
| | | |
| | | const dialogChange = (val: any) => { |
| | | getTeacherInfo() |
| | | getTeacherInfo(); |
| | | if (val == false) { |
| | | teacherDialog.value = false |
| | | teacherDialog.value = false; |
| | | } else { |
| | | teacherDialog.value = true |
| | | teacherDialog.value = true; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | // 修改密码弹窗打开 |
| | | const openChangePassword = () => { |
| | | if (changeType.value == 'password' && userStore.userInfo?.phoneNumber) { |
| | | userInfoForm.phone = userStore.userInfo?.phoneNumber |
| | | if (changeType.value == "password" && userStore.userInfo?.phoneNumber) { |
| | | userInfoForm.phone = userStore.userInfo?.phoneNumber; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | // 获取登录用户身份 |
| | | function getUserRole() { |
| | | loading.value = true |
| | | loading.value = true; |
| | | MG.identity.getCurrentAppUser().then((res: any) => { |
| | | if (res) { |
| | | if (res.lastLoginTime) { |
| | | localStorage.setItem('lastLoginTime', res.lastLoginTime) |
| | | localStorage.setItem("lastLoginTime", res.lastLoginTime); |
| | | } |
| | | //获取用户类型 |
| | | let userTypeData = res.infoList.find((item: any) => item.type == 'userType') |
| | | let userTypeData = res.infoList.find((item: any) => item.type == "userType"); |
| | | if (userTypeData) { |
| | | userTypeActive.value = JSON.parse(userTypeData.data).userType |
| | | if (userTypeActive.value !== 'Student' && userTypeActive.value !== 'otherReaders') { |
| | | const index = userTypeList.value.findIndex((item) => item.value === 'Teacher') |
| | | userTypeActive.value = JSON.parse(userTypeData.data).userType; |
| | | if ( |
| | | userTypeActive.value !== "Student" && |
| | | userTypeActive.value !== "otherReaders" |
| | | ) { |
| | | const index = userTypeList.value.findIndex((item) => item.value === "Teacher"); |
| | | if (index !== -1) { |
| | | userTypeList.value[index].checked = true |
| | | teacherType.value = JSON.parse(userTypeData.data).userType |
| | | userTypeList.value[index].checked = true; |
| | | teacherType.value = JSON.parse(userTypeData.data).userType; |
| | | } |
| | | userInfo.userType = |
| | | teacherList.value.find((item) => item.value === userTypeActive.value)?.label ?? '' |
| | | teacherList.value.find((item) => item.value === userTypeActive.value) |
| | | ?.label ?? ""; |
| | | } else { |
| | | const index = userTypeList.value.findIndex((item) => item.value === userTypeActive.value) |
| | | const index = userTypeList.value.findIndex( |
| | | (item) => item.value === userTypeActive.value |
| | | ); |
| | | if (index !== -1) { |
| | | userTypeList.value[index].checked = true |
| | | userTypeList.value[index].checked = true; |
| | | } |
| | | userInfo.userType = |
| | | userTypeList.value.find((item) => item.value === userTypeActive.value)?.label ?? '' |
| | | userTypeList.value.find((item) => item.value === userTypeActive.value) |
| | | ?.label ?? ""; |
| | | } |
| | | } else { |
| | | userInfo.userType = '-' |
| | | userInfo.userType = "-"; |
| | | } |
| | | getTeacherInfo() |
| | | userId.value = res.userId |
| | | let customUser = res.infoList.find((item: any) => item.type == 'userInfo') |
| | | let teacherRole = res.roleLinks.find((item: any) => item.role.refCode == 'teacher') |
| | | let teacherInfos = res.infoList.find((item: any) => item.type == 'teacherInfo') |
| | | let wechatInfo = res.infoList.find((item: any) => item.type == 'WeChat') |
| | | let studentInfo = res.infoList.find((item: any) => item.type == 'Default') |
| | | let phoneInfo = res.secretList.find((item: any) => item.type == 'MobilePhone') |
| | | let emailInfo = res.secretList.find((item: any) => item.type == 'EMail') |
| | | getTeacherInfo(); |
| | | userId.value = res.userId; |
| | | let customUser = res.infoList.find((item: any) => item.type == "userInfo"); |
| | | let teacherRole = res.roleLinks.find((item: any) => item.role.refCode == "teacher"); |
| | | let teacherInfos = res.infoList.find((item: any) => item.type == "teacherInfo"); |
| | | let wechatInfo = res.infoList.find((item: any) => item.type == "WeChat"); |
| | | let studentInfo = res.infoList.find((item: any) => item.type == "Default"); |
| | | let phoneInfo = res.secretList.find((item: any) => item.type == "MobilePhone"); |
| | | let emailInfo = res.secretList.find((item: any) => item.type == "EMail"); |
| | | const userData = { |
| | | userName: customUser && customUser.data ? JSON.parse(customUser.data).name : '', |
| | | school: customUser && customUser.data ? JSON.parse(customUser.data).school : '', |
| | | cityCode: customUser && customUser.data ? JSON.parse(customUser.data).cityCode : '', |
| | | address: customUser && customUser.data ? JSON.parse(customUser.data).address : '', |
| | | userType: userTypeData && userTypeData.data ? JSON.parse(userTypeData.data).userType : '', |
| | | } |
| | | userName: customUser && customUser.data ? JSON.parse(customUser.data).name : "", |
| | | school: customUser && customUser.data ? JSON.parse(customUser.data).school : "", |
| | | cityCode: |
| | | customUser && customUser.data ? JSON.parse(customUser.data).cityCode : "", |
| | | address: customUser && customUser.data ? JSON.parse(customUser.data).address : "", |
| | | userType: |
| | | userTypeData && userTypeData.data ? JSON.parse(userTypeData.data).userType : "", |
| | | }; |
| | | if (teacherRole && teacherInfos) { |
| | | if (JSON.parse(teacherInfos.data).email && !emailInfo) { |
| | | userInfoForm.email = JSON.parse(teacherInfos.data).email |
| | | formDisabled.value = true |
| | | userInfoForm.email = JSON.parse(teacherInfos.data).email; |
| | | formDisabled.value = true; |
| | | } |
| | | userStore.setUserInfo({ |
| | | ...userData, |
| | |
| | | phoneNumber: phoneInfo?.credential, |
| | | Email: emailInfo ? emailInfo.credential : JSON.parse(teacherInfos.data).email, |
| | | icon: wechatInfo?.icon, |
| | | role: 'Teacher', |
| | | role: "Teacher", |
| | | roleId: teacherRole.role.id, |
| | | userId: res.userId, |
| | | }) |
| | | }); |
| | | } else if (wechatInfo) { |
| | | userStore.setUserInfo({ |
| | | ...userData, |
| | | ...wechatInfo, |
| | | phoneNumber: phoneInfo?.credential, |
| | | Email: emailInfo?.credential, |
| | | role: 'Student', |
| | | role: "Student", |
| | | userId: res.userId, |
| | | }) |
| | | }); |
| | | } else if (studentInfo) { |
| | | userStore.setUserInfo({ |
| | | ...userData, |
| | |
| | | icon: wechatInfo?.icon, |
| | | phoneNumber: phoneInfo?.credential, |
| | | Email: emailInfo?.credential, |
| | | role: 'Student', |
| | | role: "Student", |
| | | userId: res.userId, |
| | | }) |
| | | }); |
| | | } |
| | | } |
| | | }) |
| | | }); |
| | | } |
| | | |
| | | //教师信息 |
| | |
| | | const data = { |
| | | start: 0, |
| | | size: 10, |
| | | topicIdOrRefCode: 'teacherRoleApproval', |
| | | topicIdOrRefCode: "teacherRoleApproval", |
| | | appRefCode: config.appRefCode, |
| | | sort: { |
| | | type: 'Desc', |
| | | field: 'CreateDate', |
| | | type: "Desc", |
| | | field: "CreateDate", |
| | | }, |
| | | } |
| | | }; |
| | | MG.ugc.getTopicMessageList(data).then((res) => { |
| | | try { |
| | | const resData = res.datas.find((i) => i.appUserCreator.userId == userId.value) |
| | | const resData = res.datas.find((i) => i.appUserCreator.userId == userId.value); |
| | | if (resData) { |
| | | teacherState.value = resData.state |
| | | teacherState.value = resData.state; |
| | | if (resData.feedBack != null) { |
| | | reasonTxt.value = JSON.parse(resData.feedBack).reason |
| | | reasonTxt.value = JSON.parse(resData.feedBack).reason; |
| | | } |
| | | } else { |
| | | teacherState.value = '' |
| | | teacherState.value = ""; |
| | | } |
| | | loading.value = false |
| | | loading.value = false; |
| | | } catch (error) { |
| | | loading.value = false |
| | | loading.value = false; |
| | | } |
| | | }) |
| | | }); |
| | | } |
| | | |
| | | //原因查看 |
| | | const lookReason = () => { |
| | | dialogReason.value = true |
| | | } |
| | | dialogReason.value = true; |
| | | }; |
| | | |
| | | //积分 |
| | | function getIntegral() { |
| | | MG.store |
| | | .getUserWallet({ |
| | | type: 'integral', |
| | | type: "integral", |
| | | }) |
| | | .then((res) => { |
| | | userInfo.integral = res.balance |
| | | }) |
| | | userInfo.integral = res.balance; |
| | | }); |
| | | } |
| | | |
| | | const integralRecord = reactive({ |
| | | recordDialog: false, |
| | | recordList: [], |
| | | }) |
| | | }); |
| | | |
| | | // 积分记录弹窗 |
| | | function recordDialog() { |
| | | integralRecord.recordDialog = true |
| | | getRecordList() |
| | | integralRecord.recordDialog = true; |
| | | getRecordList(); |
| | | } |
| | | |
| | | //获取积分记录 |
| | |
| | | Size: 999, |
| | | Start: 0, |
| | | sort: { |
| | | type: 'Desc', |
| | | field: 'CreateDate', |
| | | type: "Desc", |
| | | field: "CreateDate", |
| | | }, |
| | | type: 'integral', |
| | | type: "integral", |
| | | }) |
| | | .then((res) => { |
| | | console.log(res, '积分记录') |
| | | console.log(res, "积分记录"); |
| | | if (res.datas.length > 0) { |
| | | res.datas.forEach((element) => { |
| | | element.createDate = moment(element.createDate).format('YYYY-MM-DD HH:mm:ss') |
| | | if (element.refType == 'sign') { |
| | | element.type = '每日登录' |
| | | element.createDate = moment(element.createDate).format("YYYY-MM-DD HH:mm:ss"); |
| | | if (element.refType == "sign") { |
| | | element.type = "每日登录"; |
| | | } |
| | | if (element.refType == 'Reward') { |
| | | element.type = '上传资源奖励' |
| | | if (element.refType == "Reward") { |
| | | element.type = "上传资源奖励"; |
| | | } |
| | | if (element.refType == 'OrderCoinBonus') { |
| | | element.type = '订单支付奖励' |
| | | if (element.refType == "OrderCoinBonus") { |
| | | element.type = "订单支付奖励"; |
| | | } |
| | | if (element.refType == 'Order' && element.value < 0) { |
| | | element.type = '订单支付抵扣' |
| | | if (element.refType == "Order" && element.value < 0) { |
| | | element.type = "订单支付抵扣"; |
| | | } |
| | | if (element.refType == 'Order' && element.value > 0) { |
| | | element.type = '订单取消退回' |
| | | if (element.refType == "Order" && element.value > 0) { |
| | | element.type = "订单取消退回"; |
| | | } |
| | | if (element.refType == 'AdminRecharge') { |
| | | element.type = '管理员充值' |
| | | if (element.refType == "AdminRecharge") { |
| | | element.type = "管理员充值"; |
| | | } |
| | | }) |
| | | integralRecord.recordList = res.datas |
| | | }); |
| | | integralRecord.recordList = res.datas; |
| | | } |
| | | }) |
| | | }); |
| | | } |
| | | </script> |
| | | <style lang="less" scoped> |
| | |
| | | line-height: 20px; |
| | | padding: 0 10px; |
| | | border-left: 3px solid #019e58; |
| | | font-family: |
| | | Microsoft YaHei UI, |
| | | Microsoft YaHei UI; |
| | | font-family: Microsoft YaHei UI, Microsoft YaHei UI; |
| | | font-weight: 400; |
| | | font-size: 16px; |
| | | } |
| | |
| | | |
| | | .info-box { |
| | | padding: 10px 0; |
| | | font-family: |
| | | Microsoft YaHei UI, |
| | | Microsoft YaHei UI; |
| | | font-family: Microsoft YaHei UI, Microsoft YaHei UI; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #333333; |