index.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  1. <template>
  2. <div class="m-right-block fr mh576">
  3. <div class="right-block-bd ng-scope" ui-view="myStudyContent" style="position: relative;">
  4. <div class="panel-tit clear">
  5. <p class="fl">推荐课程</p>
  6. <ul class="fr tips-intro" style="color:royalblue" @mouseover="showTip=true" @mouseleave="showTip=false">
  7. <li class="fs15 tit" style="margin-right: 20px;">
  8. <i class="p-ico questiong-ico" style="margin-right: 0px;" /> 温馨提醒
  9. </li>
  10. </ul>
  11. <div class="fr tip-card" v-show="showTip">
  12. <div class="p20">
  13. <h3>温馨提醒:</h3>
  14. <h2 style="margin: 8px; 0 16px 0px;">一、福建省内可报</h2>
  15. <h4 style="margin: 8px;">1.施工现场专业人员</h4>
  16. <h4 style="margin: 8px;">2.20周岁以上,且男性小于60周岁,女性小于55周岁。</h4>
  17. <h2 style="margin:8px 0 16px 0px;">二、宁德内可报:</h2>
  18. <h4 style="margin: 8px;">1.安全生产管理人员</h4>
  19. <h4 style="margin: 8px;">2.建筑施工特种作业人员</h4>
  20. <h4 style="margin: 8px;">3.企业安全生产培训</h4>
  21. </div>
  22. </div>
  23. </div>
  24. <el-row class="pt-line mt20">
  25. <el-col :span="4" :xs="12">
  26. <el-button :class="{type_active : type==''}" class="type_item" type="text" @click="type=''">所有</el-button>
  27. </el-col>
  28. <el-col :span="item.span" :xs="12" v-for="item in typeList" :key="item.id" v-if="item.isOpen && !item.link">
  29. <el-button :class="{type_active:item.name==type }" class="type_item" type="text"
  30. @click="type=item.name">{{item.name}}</el-button>
  31. </el-col>
  32. </el-row>
  33. <ul class="pt-line mt20" v-if="ndList.length>1">
  34. <li style="float: left;font-size: 16px;margin: 4px;padding: 4px;">
  35. <span>课程年度:</span>
  36. </li>
  37. <li style="float: left;">
  38. <span :class="{type_active:nd==''}" class="nav-btn-years" @click="nd=''">所有</span>
  39. </li>
  40. <li v-for="item in ndList" style="float: left;">
  41. <span :class="{type_active:item==nd }" class="nav-btn-years" @click="nd=item">{{item}} </span>
  42. </li>
  43. <li style="float: left;">
  44. <input type="text" style="line-height: 1;padding: 10px" v-model="filterName"
  45. class="ui-ipt ng-pristine ng-valid filterName" placeholder="输入名字查找">
  46. </li>
  47. </ul>
  48. <ul class="m-course-list clear mt10 classlist">
  49. <li v-for="(item,index) in list.slice(page*size-size, page*size)" :key="item.course_id"
  50. class="pt-sola mt20 pb10">
  51. <div>
  52. <span v-if="item.isFinish==1" class="p-ico2 ico-passed"></span>
  53. <div class="img">
  54. <img :src="item.tb">
  55. <div class="year-label">
  56. <span v-if="item.is_pay==0 && item.buyImg =='' && item.payNo == ''">
  57. 还未购买
  58. </span>
  59. <span v-else-if="item.is_pay == 2 && item.is_import ==9">
  60. 预购买中
  61. </span>
  62. <span v-else-if="item.is_pay==0" style="background-color: orange;">
  63. 等待审核
  64. </span>
  65. <span v-else-if="item.is_pay==2" style="background-color: #78335F;">申请驳回</span>
  66. <span v-else-if="!item.is_pass"
  67. style="background-color: blue;padding: 2px;border-radius: 2px;">在学习中</span>
  68. <span v-else style="background-color: green;padding: 2px;border-radius: 2px;">已经完成</span>
  69. </div>
  70. <div class="hover-block">
  71. <div class="mask-bg"></div>
  72. <el-button @click="gotoPlay(item)" v-if="item.is_pay==1"
  73. class="ui-btn btn-blue">进入学习</el-button>
  74. <el-button @click="goPay(item)" v-else-if="item.is_pay==2 || !!item.buyImg"
  75. class="ui-btn btn-w">补充材料</el-button>
  76. <el-button @click="goPay(item)" v-else-if="item.payErr" class="ui-btn btn-gr">申请购买</el-button>
  77. <el-button @click="goPay(item)" v-else class="ui-btn btn-o">购买课程</el-button>
  78. </div>
  79. </div>
  80. <div class="tit"><a>{{item.displayName || item.name}}</a>
  81. </div>
  82. <div class="info">
  83. <p class="w1"><span class="p-ico c1"></span> {{item.type}} </p>
  84. <p class="w2"><span class="p-ico c2"></span>{{item.nd||'2020'}}</p>
  85. <p class="w1">
  86. <span class="p-ico c5"></span> ¥{{item.fee/100}}元
  87. </p>
  88. <p class="w2">
  89. <span class="p-ico c3"></span> {{item.xs/10}}学时
  90. </p>
  91. </div>
  92. </div>
  93. </li>
  94. </ul>
  95. <div v-if="list.length==0" class="tc mt20 red">
  96. <span style="color: red;padding:40px;font-size: 26px;">已经最后一页了</span>
  97. </div>
  98. <el-pagination class="m-pages" @current-change="(page)=>{this.page=page}" :current-page="page" :page-size="size"
  99. layout="total, prev, pager, next" :total="list.length">
  100. </el-pagination>
  101. </div>
  102. <el-dialog title="申请开通课程" :visible.sync="buyCourseDialog" width="550px" top="100px" align="left">
  103. <template v-if="!showPay">
  104. <el-form label-width="100px" :inline="false" :model="buyForm" :rules="rules"
  105. ref="refBuyCourse">
  106. <el-form-item label="账户余额" prop="balance" >
  107. <p style="margin-left: 20px;font-size: 16px;">
  108. <span v-if="userInfo.balance>=buyForm.fee" style="color: green;"> ¥{{userInfo.balance/100}}元</span>
  109. <span v-else style="color: red;"> ¥{{userInfo.balance/100}}元</span>
  110. </p>
  111. </el-form-item>
  112. <el-form-item label="报考岗位" prop="courseName">
  113. <el-input type="text" placeholder="报考岗位" v-model="buyForm.courseName+'-'+buyForm.nd"
  114. style="width: 360px;" />
  115. </el-form-item>
  116. <el-form-item label="证书编号" prop="rzCode">
  117. <el-input v-model="buyForm.rzCode" type="text" style="width: 360px;">
  118. <template #suffix>
  119. <el-button @click="openShowAllRzcodeDialog" type="text" style="margin-right: 10px;">修改</el-button>
  120. </template>
  121. </el-input>
  122. </el-form-item>
  123. <el-divider></el-divider>
  124. <h3 class="tc" style="margin-bottom: 16px;">发票信息</h3>
  125. <el-form-item label="是否需要开票">
  126. <el-radio-group v-model="buyForm.needInvoice">
  127. <el-radio :label="1">是</el-radio>
  128. <el-radio :label="0">否</el-radio>
  129. </el-radio-group>
  130. </el-form-item>
  131. <template v-if="buyForm.needInvoice">
  132. <el-form-item label="开票类型">
  133. <el-radio-group v-model="buyForm.invoiceType">
  134. <el-radio label="personal">个人</el-radio>
  135. <el-radio label="enterprise">企业</el-radio>
  136. </el-radio-group>
  137. </el-form-item>
  138. <el-form-item label="发票抬头" prop="title">
  139. <el-input v-model="buyForm.title" :placeholder="buyForm.invoiceType === 'enterprise'?'请输入单位名称':'请输入真实名字'" style="width: 360px;"></el-input>
  140. </el-form-item>
  141. <el-form-item label="纳税识别号" prop="taxId">
  142. <el-input v-model="buyForm.taxId" :placeholder="buyForm.invoiceType === 'enterprise'?'纳税识别号':'身份证号'" style="width: 360px;"></el-input>
  143. </el-form-item>
  144. <el-form-item label="手机号码" prop="phone">
  145. <el-input v-model="buyForm.phone" placeholder="请输入手机号码" style="width: 360px;"></el-input>
  146. </el-form-item>
  147. </template>
  148. <el-form-item label="邮箱地址" prop="email">
  149. <el-input v-model="buyForm.email" placeholder="请输入邮箱地址" style="width: 360px;"></el-input>
  150. </el-form-item>
  151. <el-divider></el-divider>
  152. <h2 class="tc"> 本课程费用: <strong style="color: red;"> {{buyForm.fee/100}} 元 </strong> </h2>
  153. <el-form-item label-width="0" style="margin: 30px auto;text-align: center;">
  154. <el-button @click="cancelBuyCourse">取 消</el-button>
  155. <el-button @click="generatePayQrcode" type="primary">提交订单</el-button>
  156. <el-button v-if="userInfo.balance >= buyForm.fee" @click="doAccountPay" type="success">余额付款</el-button>
  157. </el-form-item>
  158. </el-form>
  159. </template>
  160. <template v-if="showPay">
  161. <h2 class="tc"> 本课程费用: <strong style="color: red;"> {{buyForm.fee/100}} 元 </strong> </h2>
  162. <div style="width: 300px; margin: 20px auto;">
  163. <img :src="wxPayUrl" width="300px" @click="showImg(wxPayUrl)">
  164. </div>
  165. <p class="tc">请使用微信扫码支付</p>
  166. <el-row class="tc fc">
  167. <el-button @click="cancelBuyCourse">关 闭</el-button>
  168. </el-row>
  169. </template>
  170. </el-dialog>
  171. <el-dialog append-to-body close-on-click-modal :visible.sync="showImgDialog" style="margin-top: 0px;"
  172. :width="width">
  173. <img :src="imgUrl" @load="onLoad" alt="" />
  174. </el-dialog>
  175. <el-dialog append-to-body close-on-click-modal :visible.sync="showAllRzcodeDialog" width="1024px">
  176. <el-table v-if="buyForm.list.length>0" :data="buyForm.list" border>
  177. <el-table-column label="证书编号" prop="certificateNum" align="center" />
  178. <el-table-column label="岗位名称" prop="positionName" align="center" />
  179. <el-table-column label="证书状态" prop="certificateStatus" align="center" />
  180. <el-table-column label="发证机关" prop="certificateOrgan" align="center" />
  181. <el-table-column label="发证时间" prop="startTime" align="center" />
  182. <el-table-column label="选择" prop="reviewTime" align="center">
  183. <template slot-scope="{row}">
  184. <el-button @click="selectRzcode(row)" type="primary">选择</el-button>
  185. </template>
  186. </el-table-column>
  187. </el-table>
  188. </el-dialog>
  189. </div>
  190. </template>
  191. <script>
  192. import {
  193. httpServer
  194. } from "@/components/httpServer/httpServer.js";
  195. import {
  196. MessageBox
  197. } from "element-ui";
  198. import {
  199. parseTime
  200. } from "@/utils";
  201. import DoUpload from '@/components/upload/index.vue'
  202. import exampleImg from '@/assets/template.png'
  203. import {curDatetime} from '@/utils/date.js'
  204. import {
  205. mapGetters,
  206. mapActions
  207. } from "vuex";
  208. export default {
  209. name: "Index",
  210. data() {
  211. return {
  212. page: 1,
  213. size: 6,
  214. total: 0,
  215. stage: 0,
  216. isCompanyPay: 0,
  217. showTip: false,
  218. width: "",
  219. type: '',
  220. filterName: '',
  221. list: [],
  222. nd: new Date().getFullYear() + '',
  223. ndList: [],
  224. allList: [],
  225. isCommitment: "",
  226. buyCourseDialog: false,
  227. showExample: false,
  228. showImgDialog: false,
  229. showAllRzcodeDialog: false,
  230. showPay: false,
  231. buyForm: {
  232. payType:'wx',
  233. rzCode: '',
  234. email: '',
  235. title: '',
  236. phone: '',
  237. courseName: '',
  238. list: [],
  239. fee: 0,
  240. courseId: '',
  241. needInvoice: 0,
  242. taxId:'',
  243. invoiceType: 'personal'
  244. },
  245. userInvoiceList:[],
  246. imgUrl: '',
  247. qrcodeUrl: "",
  248. wxPayUrl:"",
  249. aliPayUrl:"",
  250. outTradeNo: "",
  251. courseFee: 0,
  252. title: '',
  253. timer: null,
  254. tickCount: 0,
  255. listLoading: false,
  256. media: {},
  257. commitmentDialog: false,
  258. exampleImg: exampleImg,
  259. rules: {
  260. rzCode: [{
  261. required: true,
  262. message: '请输入证书编号'
  263. }],
  264. payNo: [{
  265. required: true,
  266. message: '请输入订单编号后六位'
  267. }],
  268. title: [{
  269. required: true,
  270. message: '抬头必须填写'
  271. }],
  272. email: [{
  273. required: true,
  274. message: '请输入有效邮箱'
  275. },
  276. {
  277. type: 'string',
  278. message: '邮箱格式不正确',
  279. trigger: 'blur',
  280. transform(value) {
  281. value = value.trim();
  282. if (!/^\w+((-\w+)|(\.\w+))*@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/.test(value)) {
  283. return true
  284. } else {}
  285. }
  286. }
  287. ],
  288. company: [{
  289. required: true,
  290. message: '请输入单位名称'
  291. }],
  292. taxId:[
  293. {
  294. required: true,
  295. message: '纳税识别号'
  296. }
  297. ],
  298. phone: [{
  299. required: true,
  300. message: '请输入手机号码'
  301. }, {
  302. pattern: /^1[3-9]\d{9}$/,
  303. message: '手机号码格式不正确',
  304. trigger: 'blur'
  305. }],
  306. courseName: [{
  307. required: true,
  308. message: '请输入报考岗位'
  309. }]
  310. },
  311. errorImg: 'this.src="' + require('../../../assets/images/no-data_hash5abcd2ef62.png') + '"'
  312. };
  313. },
  314. computed: {
  315. ...mapGetters("user", ["typeList", "userInfo"])
  316. },
  317. components: {
  318. DoUpload
  319. },
  320. filters: {
  321. dateFilter(val) {
  322. return parseTime(val, '{y}-{m}-{d}')
  323. }
  324. },
  325. watch: {
  326. type(val) {
  327. this.page = 1
  328. this.nd = new Date().getFullYear() + ''
  329. this.filterData()
  330. },
  331. nd(val) {
  332. this.filterData()
  333. },
  334. filterName() {
  335. this.page = 1
  336. this.filterData()
  337. }
  338. },
  339. beforeMount() {
  340. this.type = this.$route.query.type || ''
  341. this.getData();
  342. this.getUserInvoice()
  343. },
  344. beforeDestroy() {
  345. if (this.timer) window.clearInterval(this.timer);
  346. },
  347. methods: {
  348. showImg(url) {
  349. if (!url) return;
  350. this.imgUrl = url;
  351. this.showImgDialog = true;
  352. },
  353. closeDialog() {
  354. if (this.timer) window.clearInterval(this.timer);
  355. },
  356. getUserInvoice(){
  357. httpServer("weixin.getUserInvoice", {}).then((res) => {
  358. if (res.code != 200) return
  359. this.userInvoiceList = res.data||[]
  360. })
  361. },
  362. onLoad(e) {
  363. const img = e.target;
  364. let width = 0;
  365. if (img.fileSize > 0 || (img.width > 1 && img.height > 1)) {
  366. width = img.width + 40;
  367. }
  368. this.width = width + "px";
  369. },
  370. initTimer() {
  371. if (this.timer) window.clearInterval(this.timer);
  372. this.tickCount = 0;
  373. this.timer = window.setInterval(() => {
  374. this.tickCount++;
  375. this.tickTimer();
  376. }, 3000);
  377. },
  378. tickTimer() {
  379. if (this.tickCount > 100) {
  380. if (this.timer) window.clearInterval(this.timer);
  381. this.$message.warning("支付超时,请重新支付");
  382. this.buyCourseDialog = false;
  383. return;
  384. }
  385. let outTradeNo = this.outTradeNo;
  386. httpServer("weixin.isPayOk", { outTradeNo }).then((res) => {
  387. if (res.code == 200 && !!res.data) {
  388. if (this.timer) window.clearInterval(this.timer);
  389. this.$message.successMsg("支付成功", 2);
  390. this.buyCourseDialog = false;
  391. this.getData();
  392. }
  393. });
  394. },
  395. doAccountPay(){
  396. let param = Object.assign({}, this.buyForm);
  397. httpServer("weixin.doAccountPay", {courseId}).then((res) => {
  398. if (res.code != 200) return;
  399. this.$message.successMsg("支付成功", 2);
  400. this.buyCourseDialog = false;
  401. this.getData();
  402. });
  403. },
  404. generatePayQrcode() {
  405. this.$refs["refBuyCourse"].validate((valid) => {
  406. if(!valid) return;
  407. let payType = this.buyForm.payType;
  408. let apiName = payType === 'wx' ? "weixin.DoWxpay" : "weixin.DoaliPay";
  409. let {
  410. courseId,
  411. courseName,
  412. title,
  413. email,
  414. phone,
  415. taxId,
  416. needInvoice,
  417. invoiceType
  418. } = this.buyForm;
  419. let param = {
  420. courseId,
  421. title,
  422. phone,
  423. email,
  424. taxId,
  425. needInvoice,
  426. invoiceType
  427. };
  428. httpServer(apiName, param).then((res) => {
  429. if (res.code != 200) return;
  430. let { outTradeNo, showUrl } = res.data;
  431. this.outTradeNo = outTradeNo;
  432. if (payType === 'wx') {
  433. this.wxPayUrl = showUrl;
  434. } else {
  435. this.aliPayUrl = showUrl;
  436. }
  437. this.showPay = true
  438. this.initTimer();
  439. });
  440. })
  441. },
  442. getData() {
  443. let param = {
  444. size: 1000,
  445. trainType: 2,
  446. from: 0
  447. }
  448. httpServer("course.getcoursemarket", param).then((res) => {
  449. if (res.code == 200) {
  450. this.allList = res.data.list;
  451. this.filterData()
  452. }
  453. });
  454. },
  455. filterData() {
  456. let nd = this.nd || '';
  457. let filterName = this.filterName || '';
  458. let type = this.type || ''
  459. this.ndList = [];
  460. this.list = [];
  461. for (let i in this.allList) {
  462. let item = this.allList[i];
  463. if (type != '' && item.type != type) continue;
  464. if (this.ndList.indexOf(item.nd) == -1) {
  465. this.ndList.push(item.nd);
  466. }
  467. if (filterName!='' && item.name.indexOf(filterName) == -1) continue;
  468. if (nd != '' && item.nd != nd) continue;
  469. this.list.push(item)
  470. }
  471. },
  472. cancelBuyCourse() {
  473. if (this.timer) window.clearInterval(this.timer);
  474. this.$refs["elForm"] && this.$refs["elForm"].resetFields();
  475. this.buyCourseDialog = false
  476. this.showPay = false;
  477. },
  478. openShowAllRzcodeDialog() {
  479. this.showAllRzcodeDialog = true;
  480. },
  481. selectRzcode(row) {
  482. this.buyForm.rzCode = row.certificateNum;
  483. this.showAllRzcodeDialog = false;
  484. },
  485. gotoDetail(courseId) {
  486. this.$router.push({name:'play', params:{courseId}})
  487. },
  488. goPay(item) {
  489. this.showPay = false;
  490. this.buyForm = Object.assign(this.buyForm, item)
  491. this.buyForm.phone = this.userInfo.phone;
  492. this.buyForm.temp = item;
  493. this.buyForm.courseName = item.name;
  494. this.buyForm.courseId = item.course_id;
  495. this.buyForm.fee = item.fee;
  496. // 检查
  497. httpServer("weixin.docheckpay", {
  498. courseId: item.course_id
  499. }).then((res) => {
  500. if (res.code != 200) return;
  501. Object.assign(this.buyForm, res.data);
  502. if(this.userInvoiceList.length >0){
  503. this.buyForm.email = this.userInvoiceList[0].email
  504. this.buyForm.title = this.userInvoiceList[0].title
  505. }
  506. this.buyCourseDialog = true;
  507. });
  508. },
  509. gotoPlay(item) {
  510. let courseId = item.course_id || item.courseId;
  511. if( curDatetime() < item.startDate){
  512. this.$message.warning("还未到学习时间");
  513. return
  514. }
  515. this.$router.push({name:'play', params:{courseId}})
  516. },
  517. handleCurrentChange(page) {
  518. this.page = page;
  519. this.filterData()
  520. }
  521. },
  522. };
  523. </script>
  524. <style>
  525. @import "../../../assets/css/content.css";
  526. @import "../../../assets/css/course.css";
  527. @import url("./index.css");
  528. .buyForm-title {
  529. width: 90px;
  530. padding: 2px;
  531. text-align: center;
  532. }
  533. .commitment-header {
  534. font-size: 16px;
  535. text-align: left;
  536. }
  537. .commitment {
  538. text-indent: 30px;
  539. margin-top: 20px;
  540. font-size: 16px;
  541. line-height: 200%;
  542. }
  543. .commitment-footer {
  544. margin-top: 30px;
  545. text-indent: 50px;
  546. font-size: 16px;
  547. text-align: left;
  548. }
  549. .commitment-content {
  550. font-size: 16px;
  551. }
  552. .tip-card {
  553. border-radius: 20px;
  554. font-size: 14px;
  555. float: right;
  556. width: 420px;
  557. right: 20px;
  558. position: absolute;
  559. top: 50px;
  560. color: white;
  561. background-color: #7fbae4;
  562. z-index: 1000;
  563. }
  564. .tips-intro {
  565. color: #468cf2;
  566. cursor: pointer;
  567. position: relative;
  568. }
  569. </style>