new-profess-detail.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. <template>
  2. <div id="professDetail" style="padding:24px 12%">
  3. <el-card style="color: #5E5E5E;" ref="navBar">
  4. <el-breadcrumb separator-class="el-icon-arrow-right">
  5. <el-breadcrumb-item :to="{ path: '/index' }">首页</el-breadcrumb-item>
  6. <el-breadcrumb-item :to="{ path: '/career/plan/ProfessLib'}">专业库</el-breadcrumb-item>
  7. <el-breadcrumb-item>专业详情</el-breadcrumb-item>
  8. </el-breadcrumb>
  9. </el-card>
  10. <div class="mt20 header-content pd20">
  11. <p class="f28 f-333 mb20">{{ majorDetail.name || '' }}</p>
  12. <p class="f14 f-666">{{ `国标代码${majorDetail.code}(不可用于填报)` }}</p>
  13. </div>
  14. <div class="tabs-wrap">
  15. <span class="tabs-item" @click="tabActive = 0" :class="{'bg-primary':tabActive == 0}">专业概况</span>
  16. <span class="tabs-item" @click="tabActive = 1" :class="{'bg-primary':tabActive == 1}">就业前景</span>
  17. <span class="tabs-item" @click="tabActive = 2" :class="{'bg-primary':tabActive == 2}">开设院校</span>
  18. </div>
  19. <p class="line"></p>
  20. <div
  21. v-show="loading"
  22. class="loading-div"
  23. v-loading="loading"
  24. :style="{height:windowHeight + 'px'}"
  25. >
  26. </div>
  27. <div class="content-wrap mt20">
  28. <!-- 专业概况 -->
  29. <div v-if="tabActive == 0">
  30. <div class="info-wrap">
  31. <div class="info-item"></div>
  32. </div>
  33. <div class="desc-item" v-for="(item,index) in contentProps">
  34. <p class="format-tit">{{getDetailContent(index,'title')}}</p>
  35. <div class="f-666 f14" v-html="getDetailContent(index,item)"></div>
  36. </div>
  37. </div>
  38. <!-- 就业岗位-->
  39. <div v-if="tabActive == 1">
  40. <div class="desc-item" >
  41. <p class="format-tit">就业方向</p>
  42. <div class="f-666 f14" v-html="prospects.jobDirection"></div>
  43. </div>
  44. <div class="desc-item" >
  45. <p class="format-tit">平均薪酬(毕业年限) <span class="f-333 f14 ml20">{{`平均薪资:${reverseSalary[0].value}`}}</span></p>
  46. <div class="f-666 f14" >
  47. <el-row :gutter="10">
  48. <el-col :span="12">
  49. <mx-chart :options="chartSalary" height="240px"></mx-chart>
  50. </el-col>
  51. <el-col style="height: 100%" :span="12">
  52. <el-row :gutter="40" type="flex" style="flex-wrap: wrap">
  53. <el-col :span="12" class="f16" v-for="(item,index) in reverseSalary">
  54. <el-row class="format-job-wrap">
  55. <el-col :span="3" class="f18 text-center f-666">{{index + 1}}</el-col>
  56. <el-col :span="15" class="f-333">{{item.name}}</el-col>
  57. <el-col :span="6" class="f-666 text-right f14">{{item.value}}</el-col>
  58. </el-row>
  59. </el-col>
  60. </el-row>
  61. </el-col>
  62. </el-row>
  63. </div>
  64. </div>
  65. <el-row :gutter="10" type="flex">
  66. <el-col :span="8">
  67. <div class="desc-item" >
  68. <p class="format-tit">主要职业分布</p>
  69. <div class="f-666 f14" >
  70. <mx-chart :options="industry" height="200px"></mx-chart>
  71. <el-collapse accordion>
  72. <el-collapse-item v-for="desc in prospects.vocationalDistribution">
  73. <template slot="title">
  74. <div style="display: flex;justify-content: space-between;width: 100%;">
  75. <span style="color: #42b983">{{ desc.name }}</span>
  76. <span class="f-red">{{ desc.value }}%</span>
  77. </div>
  78. </template>
  79. <div>{{ desc.expands }}</div>
  80. </el-collapse-item>
  81. </el-collapse>
  82. </div>
  83. </div>
  84. </el-col>
  85. <el-col :span="8">
  86. <div class="desc-item" >
  87. <p class="format-tit">主要行业分布</p>
  88. <div class="f-666 f14">
  89. <mx-chart :options="industry" height="200px"></mx-chart>
  90. <el-row >
  91. <el-col :span="24" class="f16" v-for="(item,index) in prospects.industryDistribution">
  92. <el-row class="format-job-wrap">
  93. <el-col :span="3" class="f18 text-center f-666">{{index + 1}}</el-col>
  94. <el-col :span="18" class="f-333">{{item.name}}</el-col>
  95. <el-col :span="3" class="f-red text-right f14">{{item.value}}%</el-col>
  96. </el-row>
  97. </el-col>
  98. </el-row>
  99. </div>
  100. </div>
  101. </el-col>
  102. <el-col :span="8">
  103. <div class="desc-item" >
  104. <p class="format-tit">主要就业地区分布</p>
  105. <div class="f-666 f14">
  106. <mx-chart :options="jobAddress" height="200px"></mx-chart>
  107. <el-row >
  108. <el-col :span="24" class="f16" v-for="(item,index) in prospects.jobRegionDistribution">
  109. <el-row class="format-job-wrap">
  110. <el-col :span="3" class="f18 text-center f-666">{{index + 1}}</el-col>
  111. <el-col :span="18" class="f-333">{{item.name}}</el-col>
  112. <el-col :span="3" class="f-red text-right f14">{{item.value}}%</el-col>
  113. </el-row>
  114. </el-col>
  115. </el-row>
  116. </div>
  117. </div>
  118. </el-col>
  119. </el-row>
  120. <el-row :gutter="10" class="f-12 f-666">
  121. <p><i class="el-icon mr5 f-16 el-icon-warning" style="color: #42b983"> </i>数据说明</p>
  122. <p v-for="(desc,index) in prospects.description">
  123. {{index+ 1}}、 {{desc}}
  124. </p>
  125. </el-row>
  126. </div>
  127. </div>
  128. </div>
  129. </template>
  130. <script>
  131. import MxChart from '@/components/MxChart/index'
  132. import { careerProspects, majorOverview } from '@/api/webApi/professlib'
  133. export default {
  134. name: 'ProfessLibDetails',
  135. components: {
  136. MxChart
  137. },
  138. data() {
  139. return {
  140. loading: false,
  141. code: '',
  142. tabActive: 0,
  143. majorDetail: {}, // 概况
  144. prospects: {}, // 前景
  145. contentPropsByBen: ['introduction', 'eduObjective', 'eduRequirement', 'subjectRequirement', 'loreAndAbility', 'studyDirection', 'mainCourse', 'famousScholar'], // 本科概况列
  146. contentTotalByBen: ['专业介绍', '培养目标', '培养要求', '学科要求', '知识能力', '考研方向', '主要课程', '社会名人'], // 本
  147. contentPropsByZhuan: ['eduObjective', 'internshipDesc', 'jobDirection', 'loreAndAbility', 'zhuanToBenOrient', 'mainCourse'], // 本科概况列
  148. contentTotalByZhuan: ['培养目标', '实习实训', '职业资格证书举例', '知识能力', '专升本方向', '主要课程'], // 专
  149. windowHeight: document.documentElement.clientHeight
  150. }
  151. },
  152. computed: {
  153. // 平均薪资趋势
  154. reverseSalary() {
  155. if (!this.prospects.averageSalary) return null
  156. const averageSalary = this.deepClone(this.prospects.averageSalary)
  157. return averageSalary.reverse().splice(0 ,10)
  158. },
  159. // 主要职业分布
  160. // 主要行业分布
  161. industry() {
  162. if (!this.prospects.industryDistribution) return null
  163. const pieData = this.prospects.industryDistribution
  164. const options = {
  165. toolbox: {
  166. show: true,
  167. },
  168. series: [
  169. {
  170. type: 'pie',
  171. radius: [40, 60],
  172. label:{
  173. formatter: '{b}'
  174. },
  175. labelLine: {
  176. length2: 6,
  177. length: 5
  178. },
  179. data: pieData
  180. }
  181. ]
  182. }
  183. return options
  184. },
  185. // 主要就业地区分布
  186. jobAddress() {
  187. if(!this.prospects.jobRegionDistribution.length) return
  188. const pieData = this.prospects.jobRegionDistribution
  189. const options = {
  190. toolbox: {
  191. show: true,
  192. },
  193. series: [
  194. {
  195. type: 'pie',
  196. radius: [40, 60],
  197. label:{
  198. formatter: '{b}'
  199. },
  200. labelLine: {
  201. length2: 6,
  202. length: 5
  203. },
  204. data: pieData
  205. }
  206. ]
  207. }
  208. return options
  209. },
  210. chartSalary() {
  211. if (!this.prospects.averageSalary) return null
  212. const col = this.prospects.averageSalary.map(item => item.name + '年')
  213. const row = this.prospects.averageSalary.map(item => item.value)
  214. const options = {
  215. grid:{
  216. left: '2%',
  217. right: '2%',
  218. bottom: '3%',
  219. top: '14%',
  220. containLabel: true
  221. },
  222. tooltip: {
  223. trigger: 'axis'
  224. },
  225. xAxis: {
  226. data: col,
  227. axisLine: {
  228. lineStyle: {
  229. type: 'dashed'
  230. }
  231. },
  232. axisTick: {
  233. alignWithLabel: true
  234. },
  235. },
  236. yAxis: {
  237. type: 'value',
  238. },
  239. series: [
  240. {
  241. type: 'line',
  242. color: '#47C6A2',
  243. stack: 'Total',
  244. label: {
  245. show: true,
  246. position: 'top',
  247. },
  248. smooth: false,
  249. data: row
  250. },
  251. ]
  252. }
  253. return options
  254. },
  255. contentProps() {
  256. if(this.majorDetail.eduLevel == 'ben') return this.contentPropsByBen
  257. if(this.majorDetail.eduLevel == 'zhuan') return this.contentPropsByZhuan
  258. },
  259. contentTotal() {
  260. if(this.majorDetail.eduLevel == 'ben') return this.contentTotalByBen
  261. if(this.majorDetail.eduLevel == 'zhuan') return this.contentTotalByZhuan
  262. },
  263. getDetailContent() {
  264. return function(id, type) {
  265. if(type==='title'){
  266. return this.contentTotal[id]
  267. }
  268. const flag = this.contentProps.some(item=>{
  269. return item===type
  270. })
  271. if(flag){
  272. return this.majorDetail[type]
  273. }
  274. }
  275. }
  276. },
  277. watch: {
  278. tabActive: {
  279. handler(newVal) {
  280. // 2 院校 1 前景 0 概览
  281. if (newVal == 0) this.getOverView()
  282. if (newVal == 1) this.getCareerProspects()
  283. }
  284. },
  285. '$route': {
  286. immediate: true,
  287. handler(val) {
  288. this.code = val.query.code
  289. if (val.query.code) {
  290. this.getOverView()
  291. }
  292. }
  293. }
  294. },
  295. methods: {
  296. getCareerProspects() {
  297. this.loading = true
  298. careerProspects({
  299. code: this.code
  300. }).then(res => {
  301. this.prospects = res.data
  302. console.log(res)
  303. }).finally(_ => {
  304. this.loading = false
  305. })
  306. },
  307. getOverView() {
  308. this.loading = true
  309. majorOverview({
  310. code: this.code
  311. }).then(res => {
  312. console.log(res)
  313. this.majorDetail = res.data
  314. }).finally(_ => {
  315. this.loading = false
  316. })
  317. }
  318. }
  319. }
  320. </script>
  321. <style lang="scss" scoped>
  322. #professDetail {
  323. .header-content {
  324. top: 0;
  325. left: 0;
  326. width: 100%;
  327. height: 100%;
  328. background: rgba(66, 185, 131, 0.1);
  329. }
  330. .tabs-wrap {
  331. margin-top: 20px;
  332. height: 40px;
  333. .tabs-item {
  334. cursor: pointer;
  335. padding: 0 33px;
  336. border-radius: 4px 4px 0 0;
  337. display: inline-block;
  338. line-height: 40px;
  339. &:hover {
  340. color: #47C6A2;
  341. }
  342. &.bg-primary {
  343. background: #47C6A2;
  344. color: white;
  345. }
  346. }
  347. }
  348. .bg-primary {
  349. background: #47C6A2 !important;
  350. color: white;
  351. }
  352. .format-tit{
  353. border-left: 4px solid #47C6A2;
  354. padding-left: 10px;
  355. margin-bottom: 20px;
  356. font-size: 20px;
  357. }
  358. .desc-item{
  359. margin-bottom: 40px;
  360. }
  361. .format-job-wrap {
  362. display: flex;
  363. height: 44px;
  364. line-height: 44px;
  365. border-bottom: 1px solid #f2f2f2;
  366. }
  367. .line {
  368. background: #47C6A2;
  369. height: 1px;
  370. }
  371. }
  372. </style>