studentList.vue 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131
  1. <template>
  2. <div class="m-container">
  3. <h2>
  4. <div class="squrt"></div>
  5. 学员列表
  6. </h2>
  7. <div class="m-core">
  8. <div
  9. class="newBand"
  10. v-permission="'studentManage/register'"
  11. @click="addStudent"
  12. >
  13. 新增学员
  14. </div>
  15. <div class="newBand" @click="onCreateQRCode">学员激活列表</div>
  16. <!-- 搜索标题 -->
  17. <save-form
  18. :inline="true"
  19. class="searchForm"
  20. @submit="onSearch"
  21. @reset="onReSet"
  22. :model.sync="searchForm"
  23. >
  24. <el-form-item>
  25. <el-input
  26. clearable
  27. placeholder="学生姓名或电话"
  28. @keyup.enter.native="onSearch"
  29. v-model.trim="searchForm.search"
  30. ></el-input>
  31. </el-form-item>
  32. <el-form-item prop="organId">
  33. <el-select
  34. class="multiple"
  35. filterable
  36. v-model.trim="searchForm.organId"
  37. clearable
  38. placeholder="请选择分部"
  39. >
  40. <el-option
  41. v-for="(item, index) in selects.branchs"
  42. :key="index"
  43. :label="item.name"
  44. :value="item.id"
  45. ></el-option>
  46. </el-select>
  47. </el-form-item>
  48. <el-form-item>
  49. <remote-search
  50. :commit="'setTeachers'"
  51. v-model="searchForm.teacherId"
  52. />
  53. <!-- <el-select
  54. placeholder="指导老师"
  55. v-model="searchForm.teacherId"
  56. clearable
  57. filterable
  58. >
  59. <el-option
  60. v-for="(item, index) in selects.teachers"
  61. :label="item.realName"
  62. :value="item.id"
  63. :key="index"
  64. ></el-option>
  65. </el-select> -->
  66. </el-form-item>
  67. <el-form-item prop="isActive">
  68. <el-select
  69. class="multiple"
  70. v-model.trim="searchForm.isActive"
  71. clearable
  72. placeholder="是否激活"
  73. >
  74. <el-option label="是" value="true"></el-option>
  75. <el-option label="否" value="false"></el-option>
  76. </el-select>
  77. </el-form-item>
  78. <el-form-item prop="operatingTag">
  79. <el-select
  80. class="multiple"
  81. v-model.trim="searchForm.operatingTag"
  82. clearable
  83. placeholder="是否运营"
  84. >
  85. <el-option label="是" :value="1"></el-option>
  86. <el-option label="否" :value="0"></el-option>
  87. </el-select>
  88. </el-form-item>
  89. <el-form-item prop="serviceTag">
  90. <el-select
  91. class="multiple"
  92. v-model.trim="searchForm.serviceTag"
  93. clearable
  94. placeholder="是否服务"
  95. >
  96. <el-option label="是" :value="1"></el-option>
  97. <el-option label="否" :value="0"></el-option>
  98. </el-select>
  99. </el-form-item>
  100. <el-form-item prop="carePackage">
  101. <el-select
  102. class="multiple"
  103. v-model.trim="searchForm.carePackage"
  104. clearable
  105. placeholder="关心包"
  106. >
  107. <el-option label="不可用" :value="0"></el-option>
  108. <el-option label="可用" :value="1"></el-option>
  109. <el-option label="已使用" :value="2"></el-option>
  110. </el-select>
  111. </el-form-item>
  112. <el-form-item prop="comeOnPackage">
  113. <el-select
  114. class="multiple"
  115. v-model.trim="searchForm.comeOnPackage"
  116. clearable
  117. placeholder="加油包"
  118. >
  119. <el-option label="不可用" :value="0"></el-option>
  120. <el-option label="可用" :value="1"></el-option>
  121. <el-option label="已使用" :value="2"></el-option>
  122. </el-select>
  123. </el-form-item>
  124. <el-form-item>
  125. <el-button native-type="submit" type="danger">搜索</el-button>
  126. <el-button native-type="reset" type="primary">重置</el-button>
  127. <el-button
  128. type="primary"
  129. v-permission="'export/studentHasCourse'"
  130. @click="downLoadStudent"
  131. >导出名单</el-button
  132. >
  133. </el-form-item>
  134. </save-form>
  135. <!-- 列表 -->
  136. <div class="tableWrap">
  137. <el-table
  138. :data="tableList"
  139. :header-cell-style="{ background: '#EDEEF0', color: '#444' }"
  140. >
  141. <el-table-column align="center" prop="userId" label="学员编号">
  142. <template slot-scope="scope">
  143. <copy-text>{{ scope.row.userId }}</copy-text>
  144. </template>
  145. </el-table-column>
  146. <el-table-column align="center" prop="username" label="学员姓名">
  147. <template slot-scope="scope">
  148. <copy-text>{{ scope.row.username }}</copy-text>
  149. </template>
  150. </el-table-column>
  151. <el-table-column align="center" prop="organName" label="所属分部">
  152. <template slot-scope="scope">
  153. <copy-text>{{ scope.row.organName }}</copy-text>
  154. </template>
  155. </el-table-column>
  156. <el-table-column
  157. align="center"
  158. prop="cooperationOrganName"
  159. label="所属学校"
  160. ></el-table-column>
  161. <el-table-column
  162. align="center"
  163. prop="subjectName"
  164. label="声部"
  165. ></el-table-column>
  166. <el-table-column align="center" prop="teacherName" label="指导老师">
  167. <template slot-scope="scope">
  168. <copy-text>{{ scope.row.teacherName }}</copy-text>
  169. </template>
  170. </el-table-column>
  171. <el-table-column align="center" label="性别">
  172. <template slot-scope="scope">{{
  173. scope.row.gender ? "男" : "女"
  174. }}</template>
  175. </el-table-column>
  176. <el-table-column
  177. align="center"
  178. prop="realName"
  179. label="家长姓名"
  180. ></el-table-column>
  181. <el-table-column
  182. align="center"
  183. width="120px"
  184. prop="parentsPhone"
  185. label="家长联系电话"
  186. ></el-table-column>
  187. <!-- <el-table-column
  188. align="center"
  189. prop="leaveNum"
  190. label="本月请假次数"
  191. ></el-table-column> -->
  192. <el-table-column align="center">
  193. <template slot="header">
  194. <p style="position: relative">
  195. 是否激活
  196. <el-tooltip placement="top" popper-class="mTooltip">
  197. <div slot="content">学员是否设置密码</div>
  198. <i
  199. class="el-icon-question"
  200. style="font-size: 18px; color: #f56c6c"
  201. ></i>
  202. </el-tooltip>
  203. </p>
  204. </template>
  205. <template slot-scope="scope">{{
  206. scope.row.isActive ? "是" : "否"
  207. }}</template>
  208. </el-table-column>
  209. <el-table-column align="center" label="未上课时">
  210. <template slot-scope="scope">{{
  211. scope.row.hasCourse ? "有" : "无"
  212. }}</template>
  213. </el-table-column>
  214. <!-- <el-table-column align="center" label="预约网管课">
  215. <template slot-scope="scope">{{ scope.row.isMake ? '是' : '否' }}</template>
  216. </el-table-column> -->
  217. <el-table-column align="center" label="网管课剩余课时">
  218. <template slot-scope="scope">{{
  219. scope.row.noStartPracticeCourseNum
  220. }}</template>
  221. </el-table-column>
  222. <el-table-column align="center" label="vip课剩余课时">
  223. <template slot-scope="scope">{{
  224. scope.row.noStartVipCourseNum
  225. }}</template>
  226. </el-table-column>
  227. <el-table-column align="center" label="是否运营">
  228. <template slot-scope="scope">{{
  229. scope.row.operatingTag ? "是" : "否"
  230. }}</template>
  231. </el-table-column>
  232. <el-table-column align="center" label="是否服务">
  233. <template slot-scope="scope">{{
  234. scope.row.serviceTag ? "是" : "否"
  235. }}</template>
  236. </el-table-column>
  237. <el-table-column align="center" label="是否是新用户">
  238. <template slot="header">
  239. <p style="position: relative">
  240. 是否是新用户
  241. <el-tooltip placement="top" popper-class="mTooltip">
  242. <div slot="content">
  243. 没有有效的VIP课程或未参与2020年双十一活动的用户为新用户
  244. </div>
  245. <i
  246. class="el-icon-question"
  247. style="font-size: 18px; color: #f56c6c"
  248. ></i>
  249. </el-tooltip>
  250. </p>
  251. </template>
  252. <template slot-scope="scope">
  253. {{ scope.row.isNewUser ? "是" : "否" }}
  254. </template>
  255. </el-table-column>
  256. <el-table-column
  257. align="center"
  258. prop="courseBalance"
  259. label="课程余额(元)"
  260. >
  261. <template slot-scope="scope">
  262. <div>
  263. {{ scope.row.courseBalance | moneyFormat }}
  264. </div>
  265. </template>
  266. </el-table-column>
  267. <el-table-column
  268. align="center"
  269. prop="balance"
  270. label="账户余额(元)"
  271. >
  272. <template slot-scope="scope">
  273. <div>
  274. {{ scope.row.balance | moneyFormat }}
  275. </div>
  276. </template>
  277. </el-table-column>
  278. <el-table-column
  279. align="center"
  280. prop="carePackage"
  281. label="关心包"
  282. >
  283. <template slot-scope="scope">{{ scope.row.carePackage | studentPackage }}</template>
  284. </el-table-column>
  285. <el-table-column align="center" prop="comeOnPackage" label="加油包">
  286. <template slot-scope="scope">{{
  287. scope.row.comeOnPackage | studentPackage
  288. }}</template>
  289. </el-table-column>
  290. <el-table-column
  291. align="center"
  292. fixed="right"
  293. width="250px"
  294. label="操作"
  295. >
  296. <template slot-scope="scope">
  297. <router-link
  298. v-permission="'/studentDetail'"
  299. class="el-button--text"
  300. :to="{
  301. path: `/studentManager/studentDetail`,
  302. query: { ...scope.row },
  303. }"
  304. >查看</router-link
  305. >
  306. <el-button
  307. type="text"
  308. style="padding-left: 10px"
  309. v-permission="'studentManage/studentUpdate'"
  310. @click="resetStudent(scope.row)"
  311. >修改</el-button
  312. >
  313. <!-- api-auth/user/updatePassword2 -->
  314. <el-button
  315. v-permission="'api-auth/user/updatePassword2'"
  316. @click="resetPassWrod(scope.row)"
  317. type="text"
  318. >修改密码</el-button
  319. >
  320. <el-button
  321. v-if="scope.row.isSignedContract"
  322. type="text"
  323. @click="lookContracts(scope.row)"
  324. v-permission="'sysUserContracts/getLatest'"
  325. >下载协议</el-button
  326. >
  327. </template>
  328. </el-table-column>
  329. </el-table>
  330. <pagination
  331. sync
  332. :total.sync="pageInfo.total"
  333. :page.sync="pageInfo.page"
  334. :limit.sync="pageInfo.limit"
  335. :page-sizes="pageInfo.page_size"
  336. @pagination="getList"
  337. />
  338. </div>
  339. </div>
  340. <el-dialog
  341. :title="maskName"
  342. width="700px"
  343. label-position="right"
  344. class="studentInfo"
  345. @close="onMaskClose('studentForm')"
  346. :close-on-click-modal="false"
  347. :visible.sync="studentVisible"
  348. >
  349. <el-form
  350. :model="studentForm"
  351. :inline="true"
  352. label-width="130px"
  353. label-position="right"
  354. ref="studentForm"
  355. :rules="studentRules"
  356. >
  357. <el-alert
  358. title="课程信息"
  359. type="info"
  360. :closable="false"
  361. style="margin-bottom: 15px"
  362. ></el-alert>
  363. <el-form-item label="学生姓名" prop="name">
  364. <el-input v-model.trim="studentForm.name"></el-input>
  365. </el-form-item>
  366. <el-form-item label="学生性别" prop="sex">
  367. <el-select
  368. class="multiple"
  369. filterable
  370. v-model.trim="studentForm.sex"
  371. clearable
  372. placeholder="请选择性别"
  373. >
  374. <el-option :value="1" label="男"></el-option>
  375. <el-option :value="0" label="女"></el-option>
  376. </el-select>
  377. </el-form-item>
  378. <el-form-item label="出生日期" prop="date">
  379. <el-date-picker
  380. v-model.trim="studentForm.date"
  381. style="width: 185px"
  382. value-format="yyyy-MM-dd"
  383. type="date"
  384. :picker-options="{
  385. firstDayOfWeek: 1,
  386. }"
  387. placeholder="选择日期"
  388. ></el-date-picker>
  389. </el-form-item>
  390. <el-form-item label="学生声部" prop="subjectIdList">
  391. <el-select
  392. v-model.trim="studentForm.subjectIdList"
  393. filterable
  394. clearable
  395. placeholder="学员声部"
  396. >
  397. <el-option-group
  398. v-for="group in subjectList"
  399. :key="group.label"
  400. :label="group.label"
  401. >
  402. <el-option
  403. v-for="item in group.options"
  404. :key="item.value"
  405. :label="item.label"
  406. :value="item.value"
  407. ></el-option>
  408. </el-option-group>
  409. </el-select>
  410. </el-form-item>
  411. <el-form-item label="家长姓名" prop="parseName">
  412. <el-input v-model.trim="studentForm.parseName"></el-input>
  413. </el-form-item>
  414. <el-form-item
  415. label="联系电话"
  416. prop="phone"
  417. :rules="[
  418. { required: true, message: '请输入手机号' },
  419. {
  420. pattern: /^1\d{10}$/,
  421. message: '请输入正确的手机号',
  422. trigger: 'blur',
  423. },
  424. ]"
  425. >
  426. <!-- @blur="checkPhone(studentForm.phone)" -->
  427. <el-input :maxlength="11" v-model.trim="studentForm.phone"></el-input>
  428. </el-form-item>
  429. <el-form-item label="所属分部" prop="organId">
  430. <el-select
  431. class="multiple"
  432. v-model.trim="studentForm.organId"
  433. filterable
  434. clearable
  435. placeholder="请选择分部"
  436. @change="changeStudentOrgan"
  437. >
  438. <el-option
  439. v-for="(item, index) in selects.branchs"
  440. :key="index"
  441. :label="item.name"
  442. :value="item.id"
  443. ></el-option>
  444. </el-select>
  445. </el-form-item>
  446. <el-form-item prop="school" label="所属学校">
  447. <el-select v-model.trim="studentForm.school" filterable clearable :disabled='!studentForm.organId' class="multiple">
  448. <el-option
  449. v-for="(item, index) in cooperationList"
  450. :key="index"
  451. :label="item.name"
  452. :value="item.id"
  453. ></el-option>
  454. </el-select>
  455. </el-form-item>
  456. <el-form-item label="指导老师" prop="teacherId">
  457. <el-select
  458. class="multiple"
  459. v-model.trim="studentForm.teacherId"
  460. clearable
  461. filterable
  462. >
  463. <el-option
  464. v-for="(item, index) in maskTeacherList"
  465. :label="item.realName"
  466. :value="item.id"
  467. :key="index"
  468. ></el-option>
  469. </el-select>
  470. </el-form-item>
  471. <el-alert
  472. title="课程信息"
  473. type="info"
  474. :closable="false"
  475. style="margin-bottom: 15px"
  476. ></el-alert>
  477. <el-form-item label="是否运营" prop="operatingTag">
  478. <el-select
  479. class="multiple"
  480. v-model.trim="studentForm.operatingTag"
  481. clearable
  482. >
  483. <el-option :value="1" label="是"></el-option>
  484. <el-option :value="0" label="否"></el-option>
  485. </el-select>
  486. </el-form-item>
  487. <el-form-item label="是否服务" prop="serviceTag">
  488. <el-select
  489. class="multiple"
  490. v-model.trim="studentForm.serviceTag"
  491. clearable
  492. >
  493. <el-option :value="1" label="是"></el-option>
  494. <el-option :value="0" label="否"></el-option>
  495. </el-select>
  496. </el-form-item>
  497. <el-form-item label="是否是新用户" prop="isNewUser">
  498. <template #label>
  499. <p style="position: relative; display: inline-block">
  500. 是否是新用户
  501. <el-tooltip placement="top" popper-class="mTooltip">
  502. <div slot="content">
  503. 没有有效的VIP课程或未参与2020年双十一活动的用户为新用户
  504. </div>
  505. <i
  506. class="el-icon-question"
  507. style="font-size: 18px; color: #f56c6c"
  508. ></i>
  509. </el-tooltip>
  510. </p>
  511. </template>
  512. <el-select
  513. class="multiple"
  514. v-model.trim="studentForm.isNewUser"
  515. clearable
  516. >
  517. <el-option :value="1" label="是"></el-option>
  518. <el-option :value="0" label="否"></el-option>
  519. </el-select>
  520. </el-form-item>
  521. <el-form-item label="关心包" prop="carePackage">
  522. <el-select
  523. class="multiple"
  524. v-model.trim="studentForm.carePackage"
  525. clearable
  526. :disabled="!isNew && studentUpdatePackage.carePackage == 2"
  527. placeholder="请选择关心包"
  528. >
  529. <el-option label="不可用" :value="0"></el-option>
  530. <el-option label="可用" :value="1"></el-option>
  531. <el-option disabled label="已使用" :value="2"></el-option>
  532. </el-select>
  533. </el-form-item>
  534. <el-form-item label="加油包" prop="comeOnPackage">
  535. <el-select
  536. class="multiple"
  537. v-model.trim="studentForm.comeOnPackage"
  538. clearable
  539. :disabled="!isNew && studentUpdatePackage.comeOnPackage == 2"
  540. placeholder="请选择加油包"
  541. >
  542. <el-option label="不可用" :value="0"></el-option>
  543. <el-option label="可用" :value="1"></el-option>
  544. <el-option disabled label="已使用" :value="2"></el-option>
  545. </el-select>
  546. </el-form-item>
  547. </el-form>
  548. <div slot="footer" class="dialog-footer">
  549. <el-button @click="studentVisible = false">取 消</el-button>
  550. <el-button type="primary" v-if="isNew" @click="submitAddStudent"
  551. >确 定</el-button
  552. >
  553. <el-button type="primary" v-if="!isNew" @click="resetStudentSubmie"
  554. >确 定</el-button
  555. >
  556. </div>
  557. </el-dialog>
  558. <!-- 学员激活列表 -->
  559. <qr-code v-model="qrcodeStatus" title="学员激活列表" :codeUrl="qrcodeUrl" />
  560. <el-dialog
  561. title="修改密码"
  562. :visible.sync="passwrodVisiable"
  563. :before-close="closePassWord"
  564. width="400px"
  565. >
  566. <el-form :model="passwrodForm" ref="passwrodForm" :inline="true">
  567. <el-form-item
  568. label="手机号"
  569. prop="phone"
  570. label-width="120px"
  571. :rules="[
  572. { required: true, message: '手机号不能为空', trigger: 'blur' },
  573. {
  574. pattern: /^1\d{10}$/,
  575. message: '请输入正确的手机号',
  576. trigger: 'blur',
  577. },
  578. ]"
  579. >
  580. <copy-text>{{ passwrodForm.phone }}</copy-text>
  581. </el-form-item>
  582. <el-form-item
  583. label="输入密码"
  584. prop="password"
  585. label-width="120px"
  586. :rules="[
  587. { required: true, message: '密码不能为空', trigger: 'blur' },
  588. {
  589. pattern: /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,20}$/,
  590. message: '密码为6-20位数字和字母组合',
  591. trigger: 'blur',
  592. },
  593. ]"
  594. >
  595. <el-input v-model.trim="passwrodForm.password"></el-input>
  596. </el-form-item>
  597. <el-form-item
  598. label="再次输入"
  599. prop="password2"
  600. label-width="120px"
  601. :rules="[
  602. { required: true, message: '密码不能为空', trigger: 'blur' },
  603. {
  604. pattern: /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,20}$/,
  605. message: '密码为6-20位数字和字母组合',
  606. trigger: 'blur',
  607. },
  608. ]"
  609. >
  610. <el-input v-model.trim="passwrodForm.password2"></el-input>
  611. </el-form-item>
  612. </el-form>
  613. <span slot="footer" class="dialog-footer">
  614. <el-button @click="passwrodVisiable = false">取 消</el-button>
  615. <el-button type="primary" @click="submitResetPassWord">确 定</el-button>
  616. </span>
  617. </el-dialog>
  618. <el-dialog title="协议下载" :visible.sync="protocolVisible" width="650px">
  619. <div v-if="protocolVisible">
  620. <!-- <el-alert
  621. title="点击下载"
  622. :closable="false"
  623. type="info">
  624. </el-alert>
  625. <p style="font-size: 14px; color: #14928A; line-height: 1.5; padding: 8px 16px; cursor: pointer;" v-for="item in protocolVersions" :key="item.id" @click="onDownloadProtocol(item)">
  626. 产品与服务协议{{ item.version == 2 ? "(含课程)" : "(含系统)" }}
  627. </p> -->
  628. <el-table
  629. style="width: 100%"
  630. :header-cell-style="{ background: '#EDEEF0', color: '#444' }"
  631. :data="protocolVersions"
  632. >
  633. <el-table-column align="center" prop="studentId" label="协议名称">
  634. <template slot-scope="scope">
  635. 产品与服务协议{{ formatProtocol(scope.row.version) }}
  636. </template>
  637. </el-table-column>
  638. <el-table-column align="center" label="签署时间" prop="createTime">
  639. </el-table-column>
  640. <el-table-column align="center" width="150px" label="操作">
  641. <template slot-scope="scope">
  642. <div>
  643. <el-button type="text" @click="onDownloadProtocol(scope.row)"
  644. >下载</el-button
  645. >
  646. </div>
  647. </template>
  648. </el-table-column>
  649. </el-table>
  650. </div>
  651. <span slot="footer" class="dialog-footer">
  652. <el-button @click="protocolVisible = false">取 消</el-button>
  653. </span>
  654. </el-dialog>
  655. </div>
  656. </template>
  657. <script>
  658. import pagination from "@/components/Pagination/index";
  659. import {
  660. queryStudentList,
  661. getStudentInfoByPhone,
  662. registerStudent,
  663. updateStudent,
  664. studentHasCourse,
  665. getLatest,
  666. } from "@/api/studentManager";
  667. import { queryByOrganId } from "@/api/systemManage";
  668. import qrCode from "@/components/QrCode/index";
  669. import cleanDeep from "clean-deep";
  670. import { vaildStudentUrl } from "@/utils/validate";
  671. import { getEmployeeOrgan, resetPassword2, getTeacher } from "@/api/buildTeam";
  672. import { subjectListTree } from "@/api/specialSetting";
  673. import axios from "axios";
  674. import qs from "qs";
  675. import { packageStatus } from "@/constant/index";
  676. import { getToken } from "@/utils/auth";
  677. import load from "@/utils/loading";
  678. import { permission } from "@/utils/directivePage";
  679. export default {
  680. name: "studentList",
  681. components: { pagination, qrCode },
  682. data() {
  683. return {
  684. studentVisible: false,
  685. searchForm: {
  686. organId: null,
  687. search: null,
  688. studentName: null,
  689. isActive: null,
  690. hasCourse: null,
  691. // isMake: null,
  692. hasPracticeCourse: null,
  693. operatingTag: null,
  694. serviceTag: null,
  695. teacherId: null,
  696. carePackage: null,
  697. comeOnPackage: null,
  698. },
  699. searchList: [],
  700. tableList: [],
  701. organList: [],
  702. teacherList: [],
  703. maskTeacherList: [],
  704. subjectList: [], // 声部列表
  705. pageInfo: {
  706. // 分页规则
  707. limit: 10, // 限制显示条数
  708. page: 1, // 当前页
  709. total: 0, // 总条数
  710. page_size: [10, 20, 40, 50], // 选择限制显示条数
  711. },
  712. studentForm: {
  713. phone: "",
  714. organId: "",
  715. name: "",
  716. sex: "",
  717. parseName: "",
  718. date: "",
  719. serviceTag: null,
  720. operatingTag: null,
  721. teacherId: null,
  722. subjectIdList: null,
  723. isNewUser: null,
  724. carePackage: 0,
  725. comeOnPackage: 0,
  726. school:null
  727. },
  728. studentUpdatePackage: {
  729. carePackage: 0,
  730. comeOnPackage: 0,
  731. },
  732. studentRules: {
  733. name: [{ required: true, message: "请输入学生姓名" }],
  734. sex: [{ required: true, message: "请选择学生性别" }],
  735. date: [{ required: true, message: "请选择出生日期" }],
  736. organId: [{ required: true, message: "请选择分部" }],
  737. subjectIdList: [{ required: true, message: "请选择声部" }],
  738. serviceTag: [{ required: true, message: "请选择是否参与服务" }],
  739. isNewUser: [{ required: true, message: "请选择是否是新用户" }],
  740. operatingTag: [{ required: true, message: "请选择是否参与运营" }],
  741. teacherId: [{ required: true, message: "请选择指导老师" }],
  742. },
  743. isNew: false,
  744. active: null,
  745. maskName: "新增学员",
  746. qrcodeStatus: false,
  747. qrcodeUrl: null,
  748. activeRow: null,
  749. passwrodVisiable: false,
  750. passwrodForm: {
  751. phone: "",
  752. password: "",
  753. password2: "",
  754. },
  755. activatedRow: null,
  756. protocolVisible: false,
  757. protocolVersions: [],
  758. cooperationList: [],
  759. };
  760. },
  761. mounted() {
  762. this.$store.dispatch("setBranchs");
  763. this.$store.dispatch("setTeachers");
  764. this.getList();
  765. },
  766. methods: {
  767. onSearch() {
  768. this.pageInfo.page = 1;
  769. this.getList();
  770. },
  771. onCreateQRCode() {
  772. // 生成报名二维码
  773. this.qrcodeStatus = true;
  774. this.qrcodeUrl = vaildStudentUrl() + `/#/queryStudentPer`;
  775. },
  776. formatProtocol(version) {
  777. let str = '(含课程)'
  778. if(version == 3) {
  779. str = '(含系统)'
  780. } else if(version == 4) {
  781. str = '(含云教练)'
  782. }
  783. return str
  784. },
  785. getList() {
  786. let params = this.searchForm;
  787. params.rows = this.pageInfo.limit;
  788. params.page = this.pageInfo.page;
  789. params.organId ? params.organId : (params.organId = null);
  790. queryStudentList(params).then((res) => {
  791. if (res.code == 200) {
  792. this.tableList = res.data.rows;
  793. this.pageInfo.total = res.data.total;
  794. }
  795. });
  796. },
  797. onReSet() {
  798. this.searchForm = {
  799. organId: null,
  800. search: null,
  801. studentName: null,
  802. isActive: null,
  803. hasCourse: null,
  804. // isMake: null,
  805. hasPracticeCourse: null,
  806. operatingTag: null,
  807. serviceTag: null,
  808. teacherId: null,
  809. };
  810. this.getList();
  811. },
  812. downLoadStudent() {
  813. let url = "/api-web/export/studentHasCourse";
  814. let searchForm = this.searchForm;
  815. let data = {
  816. organId: searchForm.organId ? searchForm.organId : null,
  817. search: searchForm.search ? searchForm.search : null,
  818. isActive: searchForm.isActive ? searchForm.isActive : null,
  819. hasCourse: searchForm.hasCourse == "" ? null : searchForm.hasCourse,
  820. // isMake: searchForm.isMake ? searchForm.isMake : null,
  821. hasPracticeCourse: searchForm.hasPracticeCourse
  822. ? searchForm.hasPracticeCourse
  823. : null,
  824. operatingTag: searchForm.operatingTag ? searchForm.operatingTag : null,
  825. serviceTag: searchForm.serviceTag ? searchForm.serviceTag : null,
  826. teacherId: searchForm.teacherId ? searchForm.teacherId : null,
  827. };
  828. const options = {
  829. method: "POST",
  830. headers: {
  831. Authorization: getToken(),
  832. },
  833. url,
  834. data: qs.stringify(data),
  835. responseType: "blob",
  836. };
  837. this.$confirm("确定导出学员名单?", "提示", {
  838. confirmButtonText: "确定",
  839. cancelButtonText: "取消",
  840. type: "warning",
  841. })
  842. .then(() => {
  843. load.startLoading();
  844. axios(options)
  845. .then((res) => {
  846. let blob = new Blob([res.data], {
  847. // type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8',
  848. type: "application/vnd.ms-excel;charset=utf-8",
  849. // word文档为application/msword,pdf文档为application/pdf,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8
  850. });
  851. let text = new Response(blob).text();
  852. text.then((res) => {
  853. // 判断是否报错
  854. if (res.indexOf("code") != -1) {
  855. let json = JSON.parse(res);
  856. this.$message.error(json.msg);
  857. } else {
  858. let objectUrl = URL.createObjectURL(blob);
  859. let link = document.createElement("a");
  860. let nowTime = new Date();
  861. let ymd =
  862. nowTime.getFullYear() +
  863. (nowTime.getMonth() + 1) +
  864. nowTime.getDate();
  865. let fname = `导出学员名单` + ymd + ".xls"; //下载文件的名字
  866. link.href = objectUrl;
  867. link.setAttribute("download", fname);
  868. document.body.appendChild(link);
  869. link.click();
  870. }
  871. });
  872. load.endLoading();
  873. })
  874. .catch((error) => {
  875. this.$message.error("导出数据失败,请联系管理员");
  876. load.endLoading();
  877. });
  878. })
  879. .catch(() => {});
  880. },
  881. checkPhone(val) {
  882. var regu = /^1\d{10}$/;
  883. var re = new RegExp(regu);
  884. if (re.test(val)) {
  885. getStudentInfoByPhone({ mobile: this.studentForm.phone }).then(
  886. (res) => {
  887. if (res.code == 200) {
  888. if (res.data) {
  889. this.studentForm = {
  890. name: res.data.name,
  891. sex: res.data.gender,
  892. parseName: res.data.parentsName,
  893. // sound: parseInt(res.data.subjectIdList),
  894. phone: val,
  895. date: res.data.birthdate,
  896. };
  897. }
  898. }
  899. }
  900. );
  901. }
  902. },
  903. submitAddStudent() {
  904. const studentForm = this.studentForm;
  905. // 效验 然后组数据提交
  906. this.$refs["studentForm"].validate((item) => {
  907. if (item) {
  908. let obj = {
  909. phone: studentForm.phone,
  910. username: studentForm.name,
  911. gender: studentForm.sex,
  912. realName: studentForm.parseName,
  913. birthdate: studentForm.date,
  914. organId: studentForm.organId,
  915. serviceTag: studentForm.serviceTag,
  916. operatingTag: studentForm.operatingTag,
  917. teacherId: studentForm.teacherId,
  918. isNewUser: studentForm.isNewUser,
  919. subjectIdList: studentForm.subjectIdList,
  920. carePackage: studentForm.carePackage,
  921. comeOnPackage: studentForm.comeOnPackage,
  922. cooperationOrganId:studentForm.school
  923. };
  924. registerStudent(obj).then((res) => {
  925. if (res.code == 200) {
  926. this.$message.success("添加成功");
  927. this.studentVisible = false;
  928. this.getList();
  929. }
  930. });
  931. }
  932. });
  933. },
  934. // 修改学生信息
  935. resetStudentSubmie() {
  936. const studentForm = this.studentForm;
  937. this.$refs["studentForm"].validate((item) => {
  938. if (item) {
  939. let obj = {
  940. phone: studentForm.phone,
  941. username: studentForm.name,
  942. gender: studentForm.sex,
  943. realName: studentForm.parseName,
  944. birthdate: studentForm.date,
  945. organId: studentForm.organId,
  946. id: this.active.userId,
  947. serviceTag: studentForm.serviceTag,
  948. operatingTag: studentForm.operatingTag,
  949. teacherId: studentForm.teacherId,
  950. isNewUser: studentForm.isNewUser,
  951. subjectIdList: studentForm.subjectIdList,
  952. carePackage: studentForm.carePackage,
  953. comeOnPackage: studentForm.comeOnPackage,
  954. cooperationOrganId:studentForm.school
  955. };
  956. updateStudent(obj).then((res) => {
  957. if (res.code == 200) {
  958. this.$message.success("修改成功");
  959. this.studentVisible = false;
  960. this.getList();
  961. }
  962. });
  963. }
  964. });
  965. },
  966. async getSubjectList() {
  967. await subjectListTree({
  968. delFlag: "NO",
  969. tenantId: 1,
  970. rows: 9999,
  971. }).then((res) => {
  972. let result = res.data;
  973. if (res.code == 200) {
  974. let tempArray = [];
  975. result.rows.forEach((item, index) => {
  976. let subject = [];
  977. item.subjects.forEach((s) => {
  978. subject.push({
  979. value: s.id,
  980. label: s.name,
  981. });
  982. });
  983. tempArray[index] = {
  984. label: item.name,
  985. options: subject,
  986. };
  987. });
  988. this.subjectList = tempArray;
  989. }
  990. });
  991. },
  992. async addStudent() {
  993. await this.getSubjectList();
  994. this.isNew = true;
  995. this.studentVisible = true;
  996. this.maskName = "新增学员";
  997. },
  998. async resetStudent(row) {
  999. let organId = row.organId;
  1000. await this.getSubjectList();
  1001. await this.changeStudentOrgan(row.organId);
  1002. this.isNew = false;
  1003. this.active = row;
  1004. this.studentVisible = true;
  1005. this.maskName = "修改学员";
  1006. this.$nextTick(() => {
  1007. this.studentForm = {
  1008. phone: row.parentsPhone || null,
  1009. name: row.username || null,
  1010. sex: row.gender,
  1011. parseName: row.realName || null,
  1012. date: row.birthdate || null,
  1013. organId: row.organId || null,
  1014. serviceTag: row.serviceTag,
  1015. operatingTag: row.operatingTag,
  1016. teacherId: row.teacherId || null,
  1017. isNewUser: row.isNewUser,
  1018. subjectIdList: Number(row.subjectIdList) || null,
  1019. carePackage: row.carePackage,
  1020. comeOnPackage: row.comeOnPackage,
  1021. school:row.cooperationOrganId
  1022. };
  1023. this.studentUpdatePackage = {
  1024. carePackage: row.carePackage,
  1025. comeOnPackage: row.comeOnPackage,
  1026. };
  1027. });
  1028. },
  1029. onMaskClose(formName) {
  1030. this.$refs[formName].resetFields();
  1031. },
  1032. resetPassWrod(row) {
  1033. this.activatedRow = row;
  1034. this.passwrodForm.phone = row.parentsPhone;
  1035. this.passwrodVisiable = true;
  1036. },
  1037. closePassWord() {
  1038. this.activatedRow = null;
  1039. this.passwrodForm = {
  1040. phone: "",
  1041. password: "",
  1042. password2: "",
  1043. };
  1044. this.$refs["passwrodForm"].resetFields();
  1045. this.passwrodVisiable = false;
  1046. },
  1047. submitResetPassWord() {
  1048. if (this.passwrodForm.password !== this.passwrodForm.password2) {
  1049. this.$message.error("两次密码必须相同");
  1050. return;
  1051. }
  1052. this.$refs["passwrodForm"].validate((res) => {
  1053. if (res) {
  1054. // 发请求
  1055. resetPassword2({
  1056. mobile: this.passwrodForm.phone,
  1057. newPassword: this.passwrodForm.password,
  1058. userId: this.activatedRow.userId,
  1059. }).then((res) => {
  1060. if (res.code == 200) {
  1061. // 修改成功
  1062. this.$message.success("修改成功");
  1063. this.closePassWord();
  1064. }
  1065. });
  1066. }
  1067. });
  1068. },
  1069. async changeStudentOrgan(val) {
  1070. this.studentForm.teacherId = null;
  1071. this.studentForm.school=null;
  1072. if (val) {
  1073. await getTeacher({ organId: val }).then((res) => {
  1074. if (res.code == 200) {
  1075. this.maskTeacherList = res.data;
  1076. }
  1077. });
  1078. queryByOrganId({ organId: val }).then((res) => {
  1079. if (res.code == 200) {
  1080. this.cooperationList = res.data;
  1081. }
  1082. });
  1083. } else {
  1084. this.maskTeacherList = [];
  1085. }
  1086. },
  1087. async lookContracts(row) {
  1088. await getLatest({ userId: row.userId }).then((res) => {
  1089. if (res.code == 200) {
  1090. if (res.data) {
  1091. this.protocolVersions = res.data;
  1092. this.protocolVisible = true;
  1093. }
  1094. }
  1095. });
  1096. },
  1097. onDownloadProtocol(item) {
  1098. window.location.href = item.url;
  1099. },
  1100. },
  1101. };
  1102. </script>
  1103. <style lang="scss" scoped>
  1104. .newBand {
  1105. display: inline-block;
  1106. margin-right: 10px;
  1107. }
  1108. .right-code {
  1109. // width: 50%;
  1110. // float: left;
  1111. .title {
  1112. font-size: 18px;
  1113. text-align: center;
  1114. padding-bottom: 8px;
  1115. }
  1116. }
  1117. /deep/.studentInfo {
  1118. .multiple.el-select {
  1119. width: 185px !important;
  1120. }
  1121. }
  1122. </style>