new-major-detail.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. <template>
  2. <div id="professDetail" style="padding:24px 5%">
  3. <el-row :gutter="20">
  4. <el-col :span="6" >
  5. <el-tabs type="border-card" @tab-click="tabClick" :value="type" stretch >
  6. <el-tab-pane label="本科" name="本科" ></el-tab-pane>
  7. <el-tab-pane label="专科" name="专科" ></el-tab-pane>
  8. <el-tree
  9. ref="tree"
  10. :data="majorList"
  11. node-key="code"
  12. :default-checked-keys="[code]"
  13. :default-expanded-keys="[code]"
  14. :props="defaultProps"
  15. :current-node-key="code"
  16. @node-click="handleNodeClick"
  17. :isLeaf="isLeaf"
  18. >
  19. <p class="custom-tree-node text-ellipsis" :title="node.label" slot-scope="{node, data}">
  20. <span >{{node.label }}</span>
  21. <span>{{data.children ? data.children.length : ''}}</span>
  22. </p>
  23. </el-tree>
  24. </el-tabs>
  25. </el-col>
  26. <el-col :span="18">
  27. <div >
  28. <el-card style="color: #5E5E5E;" ref="navBar">
  29. <el-breadcrumb separator-class="el-icon-arrow-right">
  30. <el-breadcrumb-item :to="{ path: '/index' }">首页</el-breadcrumb-item>
  31. <el-breadcrumb-item :to="{ path: '/career/plan/ProfessLib'}">专业库</el-breadcrumb-item>
  32. <el-breadcrumb-item>专业详情</el-breadcrumb-item>
  33. </el-breadcrumb>
  34. </el-card>
  35. <div class="mt20 header-content pd20">
  36. <p class="f28 f-333 mb20">{{ majorDetail.name || '' }}</p>
  37. <p class="f14 f-666">{{ `国标代码${majorDetail.code}(不可用于填报)` }}</p>
  38. </div>
  39. <div class="tabs-wrap">
  40. <span class="tabs-item" @click="tabActive = 0" :class="{'bg-primary':tabActive == 0}">专业概况</span>
  41. <span class="tabs-item" @click="tabActive = 1" :class="{'bg-primary':tabActive == 1}">就业前景</span>
  42. <span class="tabs-item" @click="tabActive = 2" :class="{'bg-primary':tabActive == 2}">开设院校</span>
  43. </div>
  44. <p class="line"></p>
  45. <div
  46. v-show="loading"
  47. class="loading-div"
  48. v-loading="loading"
  49. :style="{height:windowHeight + 'px'}"
  50. >
  51. </div>
  52. <div class="content-wrap mt20">
  53. <!-- 专业概况 -->
  54. <div v-if="tabActive == 0">
  55. <div class="info-wrap mb10" >
  56. <div class="info-item">
  57. <el-image :src="require('@/assets/images/career/school_icon.png')" />
  58. <div>
  59. <p class="f18">{{ majorDetail.eduLevel == 'ben' ? '本科' : '专科' }}</p>
  60. <p class="f14 f-999">学历层次</p>
  61. </div>
  62. </div>
  63. <div class="info-item">
  64. <el-image :src="require('@/assets/images/career/level_icon.png')" />
  65. <div>
  66. <p class="f18">{{ majorDetail.learnYearZh }}</p>
  67. <p class="f14 f-999">修业年限</p>
  68. </div>
  69. </div>
  70. <div class="info-item" v-if="majorDetail.degree">
  71. <el-image :src="require('@/assets/images/career/pre_icon.png')" />
  72. <div>
  73. <p class="f18">{{ majorDetail.degree }}</p>
  74. <p class="f14 f-999">授予学位</p>
  75. </div>
  76. </div>
  77. <div class="info-item">
  78. <el-image :src="require('@/assets/images/career/year_icon.png')" />
  79. <div>
  80. <p class="f18">{{ `${majorDetail.maleRatio}:${majorDetail.femaleRatio }`}}</p>
  81. <p class="f14 f-999">男女比例</p>
  82. </div>
  83. </div>
  84. </div>
  85. <div class="desc-item" v-for="(item,index) in contentProps">
  86. <p class="format-tit">{{getDetailContent(index,'title')}}</p>
  87. <div class="f-666 f14" v-html="getDetailContent(index,item)"></div>
  88. </div>
  89. </div>
  90. <!-- 就业岗位-->
  91. <div v-if="tabActive == 1 && !!prospects">
  92. <div class="desc-item" >
  93. <p class="format-tit">就业方向</p>
  94. <div class="f-666 f14" v-html="prospects.jobDirection"></div>
  95. </div>
  96. <div class="desc-item" >
  97. <p class="format-tit">平均薪酬(毕业年限) <span class="f-333 f14 ml20">{{`平均薪资:${reverseSalary[0].value}`}}</span></p>
  98. <div class="f-666 f14" >
  99. <el-row :gutter="10">
  100. <el-col :span="12">
  101. <mx-chart :options="chartSalary" height="240px"></mx-chart>
  102. </el-col>
  103. <el-col style="height: 100%" :span="12">
  104. <el-row :gutter="40" type="flex" style="flex-wrap: wrap">
  105. <el-col :span="12" class="f16" v-for="(item,index) in reverseSalary">
  106. <el-row class="format-job-wrap">
  107. <el-col :span="3" class="f18 text-center f-666">{{index + 1}}</el-col>
  108. <el-col :span="15" class="f-333">{{item.name}}</el-col>
  109. <el-col :span="6" class="f-666 text-right f14">{{item.value}}</el-col>
  110. </el-row>
  111. </el-col>
  112. </el-row>
  113. </el-col>
  114. </el-row>
  115. </div>
  116. </div>
  117. <el-row :gutter="10" type="flex">
  118. <el-col :span="8">
  119. <div class="desc-item" >
  120. <p class="format-tit">主要职业分布</p>
  121. <div class="f-666 f14" >
  122. <mx-chart :options="occupation" height="200px"></mx-chart>
  123. <el-collapse accordion>
  124. <el-collapse-item v-for="desc in prospects.vocationalDistribution">
  125. <template slot="title">
  126. <div style="display: flex;justify-content: space-between;width: 100%;">
  127. <span style="color: #42b983">{{ desc.name }}</span>
  128. <span class="f-red">{{ desc.value }}%</span>
  129. </div>
  130. </template>
  131. <div>{{ desc.expands }}</div>
  132. </el-collapse-item>
  133. </el-collapse>
  134. </div>
  135. </div>
  136. </el-col>
  137. <el-col :span="8">
  138. <div class="desc-item" >
  139. <p class="format-tit">主要行业分布</p>
  140. <div class="f-666 f14">
  141. <mx-chart :options="industry" height="200px"></mx-chart>
  142. <el-row >
  143. <el-col :span="24" class="f16" v-for="(item,index) in prospects.industryDistribution">
  144. <el-row class="format-job-wrap">
  145. <el-col :span="3" class="f18 text-center f-666">{{index + 1}}</el-col>
  146. <el-col :title="item.name" :span="18" class="f-333 text-ellipsis">{{item.name}}</el-col>
  147. <el-col :span="3" class="f-red text-right f14">{{item.value}}%</el-col>
  148. </el-row>
  149. </el-col>
  150. </el-row>
  151. </div>
  152. </div>
  153. </el-col>
  154. <el-col :span="8">
  155. <div class="desc-item" >
  156. <p class="format-tit">主要就业地区分布</p>
  157. <div class="f-666 f14">
  158. <mx-chart :options="jobAddress" height="200px"></mx-chart>
  159. <el-row >
  160. <el-col :span="24" class="f16" v-for="(item,index) in prospects.jobRegionDistribution">
  161. <el-row class="format-job-wrap">
  162. <el-col :span="3" class="f18 text-center f-666">{{index + 1}}</el-col>
  163. <el-col :span="18" class="f-333 text-ellipsis">{{item.name}}</el-col>
  164. <el-col :span="3" class="f-red text-right f14">{{item.value}}%</el-col>
  165. </el-row>
  166. </el-col>
  167. </el-row>
  168. </div>
  169. </div>
  170. </el-col>
  171. </el-row>
  172. <el-row :gutter="10" class="f-12 f-666">
  173. <p><i class="el-icon mr5 f-16 el-icon-warning" style="color: #42b983"> </i>数据说明</p>
  174. <p v-for="(desc,index) in prospects.description">
  175. {{index+ 1}}、 {{desc}}
  176. </p>
  177. </el-row>
  178. </div>
  179. <div v-if="tabActive == 2 ">
  180. 暂无
  181. </div>
  182. <div v-if="tabActive == 1 && !prospects">
  183. {{ desc }}
  184. </div>
  185. </div>
  186. </div>
  187. </el-col>
  188. </el-row>
  189. </div>
  190. </template>
  191. <script>
  192. import MxChart from '@/components/MxChart/index'
  193. import { allMajor, careerProspects, majorOverview } from '@/api/webApi/professlib'
  194. import MxMajorTreeTranslateMixin from '@/components/Cache/modules/mx-major-tree-translate-mixin'
  195. export default {
  196. name: 'ProfessLibDetails',
  197. components: {
  198. MxChart
  199. },
  200. mixins:[MxMajorTreeTranslateMixin],
  201. data() {
  202. return {
  203. desc: '',
  204. loading: false,
  205. code: '',
  206. tabActive: 0,
  207. defaultProps: {
  208. children: 'children',
  209. label: 'name'
  210. },
  211. type: '本科',
  212. majorDetail: {}, // 概况
  213. prospects: {}, // 前景
  214. contentPropsByBen: ['introduction', 'eduObjective', 'eduRequirement', 'subjectRequirement', 'loreAndAbility', 'studyDirection', 'mainCourse', 'famousScholar'], // 本科概况列
  215. contentTotalByBen: ['专业介绍', '培养目标', '培养要求', '学科要求', '知识能力', '考研方向', '主要课程', '社会名人'], // 本
  216. contentPropsByZhuan: ['eduObjective', 'internshipDesc', 'jobDirection', 'loreAndAbility', 'zhuanToBenOrient', 'mainCourse'], // 本科概况列
  217. contentTotalByZhuan: ['培养目标', '实习实训', '职业资格证书举例', '知识能力', '专升本方向', '主要课程'], // 专
  218. windowHeight: document.documentElement.clientHeight
  219. }
  220. },
  221. computed: {
  222. majorList() {
  223. if(this.type == '本科') return this.masterMajorList
  224. if(this.type == '专科') return this.specialtyMajorList
  225. },
  226. // 平均薪资趋势
  227. reverseSalary() {
  228. if (!this.prospects.averageSalary) return null
  229. const averageSalary = this.deepClone(this.prospects.averageSalary)
  230. return averageSalary.reverse().splice(0 ,10)
  231. },
  232. // 主要职业分布
  233. occupation() {
  234. if (!this.prospects.vocationalDistribution) return null
  235. const pieData = this.prospects.vocationalDistribution
  236. const options = {
  237. toolbox: {
  238. show: true,
  239. },
  240. series: [
  241. {
  242. type: 'pie',
  243. radius: [40, 60],
  244. label:{
  245. formatter: '{b}'
  246. },
  247. labelLine: {
  248. length2: 6,
  249. length: 5
  250. },
  251. data: pieData
  252. }
  253. ]
  254. }
  255. return options
  256. },
  257. // 主要行业分布
  258. industry() {
  259. if (!this.prospects.industryDistribution) return null
  260. const pieData = this.prospects.industryDistribution
  261. const options = {
  262. toolbox: {
  263. show: true,
  264. },
  265. series: [
  266. {
  267. type: 'pie',
  268. radius: [40, 60],
  269. label:{
  270. formatter: '{b}'
  271. },
  272. labelLine: {
  273. length2: 6,
  274. length: 5
  275. },
  276. data: pieData
  277. }
  278. ]
  279. }
  280. return options
  281. },
  282. // 主要就业地区分布
  283. jobAddress() {
  284. if(!this.prospects.jobRegionDistribution) return
  285. const pieData = this.prospects.jobRegionDistribution
  286. const options = {
  287. toolbox: {
  288. show: true,
  289. },
  290. series: [
  291. {
  292. type: 'pie',
  293. radius: [40, 60],
  294. label:{
  295. formatter: '{b}'
  296. },
  297. labelLine: {
  298. length2: 6,
  299. length: 5
  300. },
  301. data: pieData
  302. }
  303. ]
  304. }
  305. return options
  306. },
  307. chartSalary() {
  308. if (!this.prospects.averageSalary) return null
  309. const col = this.prospects.averageSalary.map(item => item.name + '年')
  310. const row = this.prospects.averageSalary.map(item => item.value)
  311. const options = {
  312. grid:{
  313. left: '2%',
  314. right: '2%',
  315. bottom: '3%',
  316. top: '14%',
  317. containLabel: true
  318. },
  319. tooltip: {
  320. trigger: 'axis'
  321. },
  322. xAxis: {
  323. data: col,
  324. axisLine: {
  325. lineStyle: {
  326. type: 'dashed'
  327. }
  328. },
  329. axisTick: {
  330. alignWithLabel: true
  331. },
  332. },
  333. yAxis: {
  334. type: 'value',
  335. },
  336. series: [
  337. {
  338. type: 'line',
  339. color: '#47C6A2',
  340. stack: 'Total',
  341. label: {
  342. show: true,
  343. position: 'top',
  344. },
  345. smooth: false,
  346. data: row
  347. },
  348. ]
  349. }
  350. return options
  351. },
  352. contentProps() {
  353. if(this.majorDetail.eduLevel == 'ben') return this.contentPropsByBen
  354. if(this.majorDetail.eduLevel == 'zhuan') return this.contentPropsByZhuan
  355. },
  356. contentTotal() {
  357. if(this.majorDetail.eduLevel == 'ben') return this.contentTotalByBen
  358. if(this.majorDetail.eduLevel == 'zhuan') return this.contentTotalByZhuan
  359. },
  360. getDetailContent() {
  361. return function(id, type) {
  362. if(type==='title'){
  363. return this.contentTotal[id]
  364. }
  365. const flag = this.contentProps.some(item=>{
  366. return item===type
  367. })
  368. if(flag){
  369. return this.majorDetail[type]
  370. }
  371. }
  372. }
  373. },
  374. watch: {
  375. tabActive: {
  376. handler(newVal) {
  377. // 2 院校 1 前景 0 概览
  378. if (newVal == 0) this.getOverView()
  379. if (newVal == 1) this.getCareerProspects()
  380. }
  381. },
  382. },
  383. created() {
  384. console.log(this.$route.query.code)
  385. this.code = this.$route.query.code
  386. this.type = this.$route.query.type || '本科'
  387. if (this.$route.query.code) {
  388. this.getOverView()
  389. }
  390. },
  391. mounted() {
  392. this.$refs.tree.setCurrentKey(this.code)
  393. },
  394. methods: {
  395. handleNodeClick(data,node) {
  396. if(!node.isLeaf || this.code == node.data.code) return
  397. // console.log('跳转')
  398. // 跳转
  399. this.code= node.data.code
  400. this.tabActive = 0
  401. this.getOverView()
  402. // this.$router.replace({path:'/career/plan/MajorDetail',query:{type:this.type,code:node.data.code}})
  403. },
  404. isLeaf(data,node) {
  405. return node.childCount == 0
  406. },
  407. tabClick(type) {
  408. this.type =type.name
  409. },
  410. getCareerProspects() {
  411. this.loading = true
  412. careerProspects({
  413. code: this.code
  414. }).then(res => {
  415. this.prospects = res.data
  416. this.desc = res.msg
  417. console.log(res)
  418. }).finally(_ => {
  419. this.loading = false
  420. })
  421. },
  422. getOverView() {
  423. this.loading = true
  424. majorOverview({
  425. code: this.code
  426. }).then(res => {
  427. console.log(res)
  428. this.majorDetail = res.data
  429. }).finally(_ => {
  430. this.loading = false
  431. })
  432. }
  433. }
  434. }
  435. </script>
  436. <style lang="scss" scoped>
  437. #professDetail {
  438. .header-content {
  439. top: 0;
  440. left: 0;
  441. width: 100%;
  442. height: 100%;
  443. background: rgba(66, 185, 131, 0.1);
  444. }
  445. .custom-tree-node{
  446. display: flex;
  447. justify-content: space-between;
  448. align-items: center;
  449. width: 100%;
  450. overflow: hidden;
  451. }
  452. .tabs-wrap {
  453. margin-top: 20px;
  454. height: 40px;
  455. .tabs-item {
  456. cursor: pointer;
  457. padding: 0 33px;
  458. border-radius: 4px 4px 0 0;
  459. display: inline-block;
  460. line-height: 40px;
  461. &:hover {
  462. color: #47C6A2;
  463. }
  464. &.bg-primary {
  465. background: #47C6A2;
  466. color: white;
  467. }
  468. }
  469. }
  470. .bg-primary {
  471. background: #47C6A2 !important;
  472. color: white;
  473. }
  474. .format-tit{
  475. border-left: 4px solid #47C6A2;
  476. padding-left: 10px;
  477. margin-bottom: 20px;
  478. font-size: 20px;
  479. }
  480. .desc-item{
  481. margin-bottom: 40px;
  482. }
  483. .format-job-wrap {
  484. display: flex;
  485. height: 44px;
  486. line-height: 44px;
  487. border-bottom: 1px solid #f2f2f2;
  488. }
  489. .line {
  490. background: #47C6A2;
  491. height: 1px;
  492. }
  493. .el-tabs--border-card ::v-deep .el-tabs__content{
  494. height: calc(100vh - 176px) ;
  495. overflow: hidden;
  496. overflow-y: auto;
  497. }
  498. ::v-deep .el-tree-node.is-current > .el-tree-node__content {
  499. background: rgba(22, 119, 255, 0.1);
  500. color: #47C6A2;
  501. ::v-deep .is-leaf {
  502. color: rgba(0, 0, 0, 0);
  503. }
  504. }
  505. .info-wrap{
  506. display: flex;
  507. align-items: center;
  508. .info-item {
  509. display: flex;
  510. margin-right: 50px;
  511. .el-image {
  512. width: 50px;
  513. }
  514. div{
  515. display: flex;
  516. flex-direction: column;
  517. justify-content: space-between;
  518. }
  519. }
  520. }
  521. }
  522. </style>