CaseDesignS.vue 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952
  1. <template>
  2. <div class="cd_body">
  3. <div class="pb_content_body" style="
  4. background: #fff;
  5. padding: 0px 25px;
  6. box-sizing: border-box;
  7. border-radius: 5px;
  8. width: 95%;
  9. ">
  10. <div class="pb_head">
  11. <span>项目数据看板</span>
  12. <div style="display: flex;align-items: center;">
  13. <el-button type="primary" size="small" @click="exportExcel" style="margin-right: 10px;">导出Excel</el-button>
  14. <el-switch v-model="mode" active-text="详情模式" inactive-text="简易模式">
  15. </el-switch>
  16. </div>
  17. </div>
  18. <div class="student_head">
  19. <div class="head_left">
  20. <span>筛选:</span>
  21. <el-select v-model="choose" @change="isLoadng = true, getData" style="margin-right: 10px;">
  22. <el-option label="默认排序" value=""> </el-option>
  23. <el-option label="学校名称" value="school"> </el-option>
  24. <el-option label="任务数量" value="task"> </el-option>
  25. <!-- <el-option label="评价" value="eval"> </el-option> -->
  26. <el-option label="工具" value="tool"> </el-option>
  27. <el-option label="字数" value="font"> </el-option>
  28. </el-select>
  29. <el-select v-model="ttype" @change="isLoading = true, getData">
  30. <el-option label="全部" value=""></el-option>
  31. <el-option v-for="item in courseTypeId" :key="item.id" :label="item.name" :value="item.id">
  32. </el-option>
  33. </el-select>
  34. <el-input v-model="search" class="student_input" placeholder="请输入教师名称或学校名称" @input="getData"></el-input>
  35. </div>
  36. </div>
  37. </div>
  38. <div class="cd_table">
  39. <el-table ref="table" :data="tableData" border :fit="true" v-loading="isLoading" style="width: 100%"
  40. :header-cell-style="{ background: '#f1f1f1', fontSize: '17px' }" :row-class-name="tableRowClassName"
  41. class="table">
  42. <el-table-column label="序号" prop="number" min-width="5" align="center">
  43. </el-table-column>
  44. <el-table-column label="项目" min-width="15" align="center">
  45. <template slot-scope="scope">
  46. <div style="max-height: 180px; overflow: auto">
  47. <div v-for="(item, index) in scope.row.course" :key="index" class="cd_course" @click="jump(item.courseId)">
  48. <el-tooltip :content="item.title">
  49. <span>{{ item.title }}</span>
  50. </el-tooltip>
  51. </div>
  52. </div>
  53. </template>
  54. </el-table-column>
  55. <el-table-column label="分类" prop="typename" min-width="15" align="center">
  56. </el-table-column>
  57. <el-table-column label="学校" prop="school" min-width="15" align="center">
  58. </el-table-column>
  59. <el-table-column label="负责人" prop="username" min-width="8" align="center">
  60. </el-table-column>
  61. <el-table-column label="协同人员" prop="cteacher" min-width="8" align="center">
  62. <template slot-scope="scope">
  63. <div>{{ scope.row.cteacher ? scope.row.cteacher : '—' }}</div>
  64. </template>
  65. </el-table-column>
  66. <el-table-column label="创建时间" prop="ctime" min-width="12" align="center">
  67. </el-table-column>
  68. <el-table-column label="更新时间" prop="time" min-width="12" align="center">
  69. </el-table-column>
  70. <el-table-column label="总计" min-width="15" align="center">
  71. <template slot-scope="scope">
  72. <div class="cd_d_span">
  73. <div>
  74. <div>
  75. <span>{{ scope.row.jdz.taskC }}</span><span>任务</span>
  76. </div>
  77. <div>
  78. <span>{{ scope.row.jdz.toolC }}</span><span>工具</span>
  79. </div>
  80. <!-- <div>
  81. <span>{{ scope.row.jdz.evalC }}</span
  82. ><span>评价</span>
  83. </div> -->
  84. <div>
  85. <span>{{ scope.row.jdz.fontC }}</span><span>字</span>
  86. </div>
  87. </div>
  88. </div>
  89. </template>
  90. </el-table-column>
  91. <el-table-column label="阶段1" v-if="mode" min-width="15" align="center">
  92. <template slot-scope="scope">
  93. <div v-if="scope.row.jd1">
  94. <div class="cd_d_span">
  95. <div>
  96. <span>{{ scope.row.jd1.taskC }}</span><span>任务</span>
  97. </div>
  98. <div>
  99. <span>{{ scope.row.jd1.toolC }}</span><span>工具</span>
  100. </div>
  101. <!-- <div>
  102. <span>{{ scope.row.jd1.evalC }}</span
  103. ><span>评价</span>
  104. </div> -->
  105. <div>
  106. <span>{{ scope.row.jd1.fontC }}</span><span>字</span>
  107. </div>
  108. </div>
  109. </div>
  110. <div v-else>—</div>
  111. </template>
  112. </el-table-column>
  113. <el-table-column label="阶段2" v-if="mode" min-width="15" align="center">
  114. <template slot-scope="scope">
  115. <div v-if="scope.row.jd2">
  116. <div class="cd_d_span">
  117. <div>
  118. <span>{{ scope.row.jd2.taskC }}</span><span>任务</span>
  119. </div>
  120. <div>
  121. <span>{{ scope.row.jd2.toolC }}</span><span>工具</span>
  122. </div>
  123. <!-- <div>
  124. <span>{{ scope.row.jd2.evalC }}</span
  125. ><span>评价</span>
  126. </div> -->
  127. <div>
  128. <span>{{ scope.row.jd2.fontC }}</span><span>字</span>
  129. </div>
  130. </div>
  131. </div>
  132. <div v-else>—</div>
  133. </template>
  134. </el-table-column>
  135. <el-table-column label="阶段3" v-if="mode" min-width="15" align="center">
  136. <template slot-scope="scope">
  137. <div v-if="scope.row.jd3">
  138. <div class="cd_d_span">
  139. <div>
  140. <span>{{ scope.row.jd3.taskC }}</span><span>任务</span>
  141. </div>
  142. <div>
  143. <span>{{ scope.row.jd3.toolC }}</span><span>工具</span>
  144. </div>
  145. <!-- <div>
  146. <span>{{ scope.row.jd3.evalC }}</span
  147. ><span>评价</span>
  148. </div> -->
  149. <div>
  150. <span>{{ scope.row.jd3.fontC }}</span><span>字</span>
  151. </div>
  152. </div>
  153. </div>
  154. <div v-else>—</div>
  155. </template>
  156. </el-table-column>
  157. <el-table-column label="阶段4" v-if="mode" min-width="15" align="center">
  158. <template slot-scope="scope">
  159. <div v-if="scope.row.jd4">
  160. <div class="cd_d_span">
  161. <div>
  162. <span>{{ scope.row.jd4.taskC }}</span><span>任务</span>
  163. </div>
  164. <div>
  165. <span>{{ scope.row.jd4.toolC }}</span><span>工具</span>
  166. </div>
  167. <!-- <div>
  168. <span>{{ scope.row.jd4.evalC }}</span
  169. ><span>评价</span>
  170. </div> -->
  171. <div>
  172. <span>{{ scope.row.jd4.fontC }}</span><span>字</span>
  173. </div>
  174. </div>
  175. </div>
  176. <div v-else>—</div>
  177. </template>
  178. </el-table-column>
  179. <el-table-column label="阶段5" v-if="mode" min-width="15" align="center">
  180. <template slot-scope="scope">
  181. <div v-if="scope.row.jd5">
  182. <div class="cd_d_span">
  183. <div>
  184. <span>{{ scope.row.jd5.taskC }}</span><span>任务</span>
  185. </div>
  186. <div>
  187. <span>{{ scope.row.jd5.toolC }}</span><span>工具</span>
  188. </div>
  189. <!-- <div>
  190. <span>{{ scope.row.jd5.evalC }}</span
  191. ><span>评价</span>
  192. </div> -->
  193. <div>
  194. <span>{{ scope.row.jd5.fontC }}</span><span>字</span>
  195. </div>
  196. </div>
  197. </div>
  198. <div v-else>—</div>
  199. </template>
  200. </el-table-column>
  201. <el-table-column label="阶段6" v-if="mode" min-width="15" align="center">
  202. <template slot-scope="scope">
  203. <div v-if="scope.row.jd6">
  204. <div class="cd_d_span">
  205. <div>
  206. <span>{{ scope.row.jd6.taskC }}</span><span>任务</span>
  207. </div>
  208. <div>
  209. <span>{{ scope.row.jd6.toolC }}</span><span>工具</span>
  210. </div>
  211. <!-- <div>
  212. <span>{{ scope.row.jd6.evalC }}</span
  213. ><span>评价</span>
  214. </div> -->
  215. <div>
  216. <span>{{ scope.row.jd6.fontC }}</span><span>字</span>
  217. </div>
  218. </div>
  219. </div>
  220. <div v-else>—</div>
  221. </template>
  222. </el-table-column>
  223. <el-table-column label="项目简介" v-if="!mode" min-width="15" align="center">
  224. <template slot-scope="scope">
  225. <div v-if="scope.row.brief">
  226. <!-- <el-tooltip :content="scope.row.brief"> -->
  227. <span>{{ scope.row.brief }}</span>
  228. <!-- </el-tooltip> -->
  229. </div>
  230. <div v-else>
  231. </div>
  232. </template>
  233. </el-table-column>
  234. <el-table-column label="项目所处阶段" prop="lastTask" min-width="15" align="center">
  235. <template slot-scope="scope">
  236. <div>{{ scope.row.lastTask ? scope.row.lastTask : '—' }}</div>
  237. </template>
  238. </el-table-column>
  239. <el-table-column label="操作" width="150px" align="center">
  240. <template slot-scope="scope">
  241. <!-- <div
  242. @click="getAll(scope.row)"
  243. >
  244. 查看全部
  245. </div> -->
  246. <el-button type="primary" size="small" @click="jump2(scope.row.course[0].courseId)">评审</el-button>
  247. <el-button type="primary" size="small" @click="setMan(scope.row)">导出</el-button>
  248. </template>
  249. </el-table-column>
  250. </el-table>
  251. <div class="student_page">
  252. <el-pagination
  253. background
  254. layout="prev, pager, next"
  255. :page-size="pageSize"
  256. :total="total"
  257. v-if="page && tableData.length"
  258. style="padding: 0px"
  259. @current-change="handleCurrentChange"
  260. ></el-pagination>
  261. </div>
  262. </div>
  263. <el-dialog title="查看" :visible.sync="dialogVisible" :append-to-body="true" width="620px" :before-close="handleClose"
  264. class="dialog_diy">
  265. <div v-if="dataArray.length">
  266. <div class="cd_d_box">
  267. <span>教师:</span><span>{{ data.username }}</span>
  268. </div>
  269. <div class="cd_d_box">
  270. <span>学校:</span><span>{{ data.school }}</span>
  271. </div>
  272. <div class="cd_d_jd">
  273. <div v-for="(item, index) in dataArray" :key="index" class="cd_d_jd_box">
  274. <div class="cd_d_jd_name">{{ "阶段" + (index + 1) }}</div>
  275. <div class="cd_d_jd_content cd_d_span">
  276. <div>
  277. <span>{{ data[item].taskC }}</span><span>任务</span>
  278. </div>
  279. <div>
  280. <span>{{ data[item].toolC }}</span><span>工具</span>
  281. </div>
  282. <!-- <div>
  283. <span>{{ data[item].evalC }}</span
  284. ><span>评价</span>
  285. </div> -->
  286. <div>
  287. <span>{{ data[item].fontC }}</span><span>字</span>
  288. </div>
  289. </div>
  290. </div>
  291. <div class="cd_d_jd_box">
  292. <div class="cd_d_jd_name">总计</div>
  293. <div class="cd_d_jd_content cd_d_span" style="background: #d4d4d4">
  294. <div>
  295. <span>{{ data["jdz"].taskC }}</span><span>任务</span>
  296. </div>
  297. <div>
  298. <span>{{ data["jdz"].toolC }}</span><span>工具</span>
  299. </div>
  300. <!-- <div>
  301. <span>{{ data["jdz"].evalC }}</span
  302. ><span>评价</span>
  303. </div> -->
  304. <div>
  305. <span>{{ data["jdz"].fontC }}</span><span>字</span>
  306. </div>
  307. </div>
  308. </div>
  309. </div>
  310. </div>
  311. <span slot="footer" class="dialog-footer">
  312. <el-button @click="dialogVisible = false">关闭</el-button>
  313. </span>
  314. </el-dialog>
  315. </div>
  316. </template>
  317. <script>
  318. export default {
  319. data() {
  320. return {
  321. tableData: [],
  322. isLoading: false,
  323. org: this.$route.query.org,
  324. oid: this.$route.query.oid,
  325. timer: null,
  326. dialogVisible: false,
  327. data: {},
  328. dataArray: [],
  329. choose: "",
  330. search: "",
  331. mode: false,
  332. courseTypeId: [],
  333. ttype: "",
  334. total: 0,
  335. page: 1,
  336. pageSize: 10,
  337. };
  338. },
  339. methods: {
  340. jump(cid) {
  341. window.parent.postMessage({ cid: cid, screenType: "3s" }, "*");
  342. },
  343. jump2(cid) {
  344. window.parent.postMessage({ cid: cid, screenType: "3s2" }, "*");
  345. },
  346. handleClose(done) {
  347. done();
  348. },
  349. tableRowClassName({ row, rowIndex }) {
  350. if ((rowIndex + 1) % 2 === 0) {
  351. return "even_row";
  352. } else {
  353. return "";
  354. }
  355. },
  356. toText(content) {
  357. if (content == '' && !content) return ''
  358. var str = content
  359. str = str.replace(/<xml>[\s\S]*?<\/xml>/ig, '')
  360. str = str.replace(/<style>[\s\S]*?<\/style>/ig, '')
  361. str = str.replace(/<\/?[^>]*>/g, '')
  362. str = str.replace(/[ | ]*\n/g, '\n')
  363. str = str.replace(/&nbsp;/ig, '')
  364. // console.log('****', content)
  365. // console.log('****', str)
  366. return str
  367. },
  368. getData() {
  369. let params = {
  370. org: this.org,
  371. oid: this.oid,
  372. type: this.ttype,
  373. page:this.page,
  374. pageSize:this.pageSize
  375. // this.org
  376. };
  377. this.ajax
  378. .get(this.$store.state.api + "selectCaseS2", params)
  379. .then((res) => {
  380. this.isLoading = false;
  381. let _res = res.data[0];
  382. this.total = res.data[0].length > 0 ? res.data[0][0].num : 0;
  383. // let _res2 = res.data[1];
  384. for (var i = 0; i < _res.length; i++) {
  385. let taskC = 0;
  386. let toolC = 0;
  387. let evalC = 0;
  388. let fontC = 0;
  389. let course = [];
  390. // for (var j = 0; j < _res2.length; j++) {
  391. // if (_res[i].userid == _res2[j].userid) {
  392. course.push({
  393. title: _res[i].title,
  394. courseId: _res[i].courseId,
  395. });
  396. var _chapter = JSON.parse(_res[i].chapters);
  397. for (var k = 0; k < _chapter.length; k++) {
  398. let taskC2 = 0;
  399. let toolC2 = 0;
  400. let evalC2 = 0;
  401. let fontC2 = 0;
  402. fontC2 += _chapter[k].dyName.length;
  403. taskC2 = _chapter[k].chapterInfo[0].taskJson.length;
  404. let _tasks = _chapter[k].chapterInfo[0].taskJson;
  405. for (var task = 0; task < _tasks.length; task++) {
  406. if (_tasks[task].eList) {
  407. evalC2 += _tasks[task].eList.length;
  408. }
  409. if (_tasks[task].toolArray.length > 0) {
  410. toolC2 += _tasks[task].toolArray.length;
  411. }
  412. fontC2 += _tasks[task].task.length;
  413. fontC2 += this.toText(_tasks[task].taskDetail).length;
  414. let _tools = _tasks[task].toolArray;
  415. for (var tool = 0; tool < _tools.length; tool++) {
  416. fontC2 += _tools[tool].toolDetail.length;
  417. }
  418. }
  419. if (_res[i]["jd" + (k + 1)]) {
  420. _res[i]["jd" + (k + 1)].taskC += taskC2;
  421. _res[i]["jd" + (k + 1)].toolC += toolC2;
  422. _res[i]["jd" + (k + 1)].evalC += evalC2;
  423. _res[i]["jd" + (k + 1)].fontC += fontC2;
  424. } else {
  425. _res[i]["jd" + (k + 1)] = {};
  426. _res[i]["jd" + (k + 1)].taskC = taskC2;
  427. _res[i]["jd" + (k + 1)].toolC = toolC2;
  428. _res[i]["jd" + (k + 1)].evalC = evalC2;
  429. _res[i]["jd" + (k + 1)].fontC = fontC2;
  430. }
  431. taskC += taskC2;
  432. toolC += toolC2;
  433. evalC += evalC2;
  434. fontC += fontC2;
  435. // }
  436. // }
  437. _res[i]["jdz"] = {};
  438. _res[i]["jdz"].taskC = taskC;
  439. _res[i]["jdz"].toolC = toolC;
  440. _res[i]["jdz"].evalC = evalC;
  441. _res[i]["jdz"].fontC = fontC;
  442. _res[i].course = course;
  443. }
  444. for (var tk = _chapter.length - 1; tk >= 0; tk--) {
  445. let _tasks = _chapter[tk].chapterInfo[0].taskJson;
  446. for (var ttask = _tasks.length - 1; ttask >= 0; ttask--) {
  447. let _tools = _tasks[ttask].toolArray;
  448. if (_tools.length) {
  449. _res[i].lastTask = `第${tk + 1}阶段任务${ttask + 1}步骤${_tools.length - 1}`
  450. break;
  451. } else {
  452. continue;
  453. }
  454. }
  455. if (_res[i].lastTask) {
  456. break;
  457. }
  458. }
  459. }
  460. if (this.search) {
  461. _res = _res.filter((a) => {
  462. return (
  463. a.school.indexOf(this.search) != -1 ||
  464. a.username.indexOf(this.search) != -1
  465. );
  466. });
  467. }
  468. if (this.choose == "school") {
  469. let array = _res.sort(function (a, b) {
  470. return a.school.localeCompare(b.school);
  471. });
  472. this.tableData = array.filter((item, index) => {
  473. item.number = index + 1
  474. return item;
  475. });;
  476. } else if (this.choose == "task") {
  477. let array = _res.sort(function (a, b) {
  478. // return a.jdz.taskC - b.jdz.taskC;
  479. return b.jdz.taskC - a.jdz.taskC;
  480. });
  481. this.tableData = array.filter((item, index) => {
  482. item.number = index + 1
  483. return item;
  484. });;
  485. } else if (this.choose == "font") {
  486. let array = _res.sort(function (a, b) {
  487. // return a.jdz.fontC - b.jdz.fontC;
  488. return b.jdz.fontC - a.jdz.fontC;
  489. });
  490. this.tableData = array.filter((item, index) => {
  491. item.number = index + 1
  492. return item;
  493. });;
  494. } else if (this.choose == "eval") {
  495. let array = _res.sort(function (a, b) {
  496. // return a.jdz.fontC - b.jdz.fontC;
  497. return b.jdz.evalC - a.jdz.evalC;
  498. });
  499. this.tableData = array.filter((item, index) => {
  500. item.number = index + 1
  501. return item;
  502. });;
  503. } else if (this.choose == "tool") {
  504. let array = _res.sort(function (a, b) {
  505. // return a.jdz.fontC - b.jdz.fontC;
  506. return b.jdz.toolC - a.jdz.toolC;
  507. });
  508. this.tableData = array.filter((item, index) => {
  509. item.number = index + 1
  510. return item;
  511. });
  512. } else {
  513. this.tableData = _res.filter((item, index) => {
  514. item.number = index + 1
  515. return item;
  516. });;
  517. }
  518. })
  519. .catch((err) => {
  520. this.isLoading = false;
  521. console.error(err);
  522. });
  523. },
  524. handleCurrentChange(val) {
  525. // console.log(`当前页: ${val}`);
  526. this.page = val;
  527. this.getData();
  528. },
  529. selectAllType() {
  530. let params = {
  531. org: this.org && this.org != "" ? this.org : "",
  532. oid: this.oid && this.oid != "" ? this.oid : "",
  533. };
  534. this.ajax
  535. .get(this.$store.state.api + "selectAllTypeS", params)
  536. .then((res) => {
  537. let _courseTypeId = [];
  538. if (res.data[2].length == 0 && res.data[3].length == 0) {
  539. for (var j = 0; j < res.data[1].length; j++) {
  540. if (res.data[1][j].pid == "34629ce3-d02f-11ec-8c78-005056b86db5" || res.data[1][j].pid == "2f8beae3-d030-11ec-8c78-005056b86db5") {
  541. _courseTypeId.push(res.data[1][j]); // 去除公共分类
  542. }
  543. }
  544. } else {
  545. if (res.data[2].length > 0) {
  546. for (var j = 0; j < res.data[2].length; j++) {
  547. _courseTypeId.push(res.data[2][j]); // 去除公共分类
  548. }
  549. }
  550. if (res.data[3].length > 0) {
  551. for (var j = 0; j < res.data[3].length; j++) {
  552. _courseTypeId.push(res.data[3][j]); // 去除公共分类
  553. }
  554. }
  555. }
  556. this.courseTypeId = _courseTypeId;
  557. })
  558. .catch((err) => {
  559. console.error(err);
  560. });
  561. },
  562. getAll(res) {
  563. this.data = res;
  564. let a = Object.keys(res);
  565. a = a.filter((el) => {
  566. return el.indexOf("jd") != -1 && el != "jdz";
  567. });
  568. this.dataArray = a;
  569. this.dialogVisible = true;
  570. },
  571. exportExcel() {
  572. if (!this.tableData.length) {
  573. this.$message.error('请等待加载数据')
  574. return;
  575. }
  576. var res = this.tableData;
  577. //如果value的json字段的key值和想要的headers值不一致时,可做如下更改
  578. //将和下面的Object.fromEntries结合,将json字段的key值改变为要求的excel的header值
  579. var array = [];
  580. for (var i = 0; i < res.length; i++) {
  581. var _json = {};
  582. _json["序号"] = res[i].number;
  583. _json["负责人"] = res[i].username;
  584. _json["项目"] = res[i].course[0].title;
  585. _json["分类"] = res[i].typename;
  586. _json["学校"] = res[i].school;
  587. _json["负责人"] = res[i].username;
  588. _json["协同人员"] = res[i].cteacher ? res[i].cteacher : '—';
  589. _json["创建时间"] = res[i].ctime;
  590. _json["更新事件"] = res[i].time;
  591. _json["总计"] = `${res[i].jdz.taskC}任务 ${res[i].jdz.toolC}工具 ${res[i].jdz.fontC}字数`;
  592. if (this.mode) {
  593. _json["阶段1"] = res[i].jd1 ? res[i].brief : '—';
  594. _json["阶段2"] = res[i].jd2 ? res[i].brief : '—';
  595. _json["阶段3"] = res[i].jd3 ? res[i].brief : '—';
  596. _json["阶段4"] = res[i].jd4 ? res[i].brief : '—';
  597. _json["阶段5"] = res[i].jd5 ? res[i].brief : '—';
  598. _json["阶段6"] = res[i].jd6 ? res[i].brief : '—';
  599. } else {
  600. _json["项目简介"] = res[i].brief ? res[i].brief : '—';
  601. }
  602. _json["项目所处阶段"] = res[i].lastTask ? res[i].lastTask : '—';
  603. array.push(_json);
  604. }
  605. var XLSX = require("xlsx");
  606. const workbook = XLSX.utils.book_new(); //创建一个新的工作簿对象
  607. let ws = XLSX.utils.json_to_sheet(array); //将json对象数组转化成工作表
  608. // ws["!cols"] = [
  609. // //设置每一列的宽度
  610. // { wch: 50 },
  611. // { wch: 50 },
  612. // { wch: 50 },
  613. // ];
  614. XLSX.utils.book_append_sheet(workbook, ws, "sheet1"); //把sheet添加到workbook里,第三个参数是sheet名
  615. XLSX.writeFile(workbook, "项目数据导出.xlsx");
  616. // const wopts = { bookType: "xlsx", bookSST: false, type: "array" };//写入的样式bookType:输出的文件类型,type:输出的数据类型,bookSST: 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
  617. // const wbout = XLSX.write(workbook, wopts);// 浏览器端和node共有的API,实际上node可以直接使用xlsx.writeFile来写入文件,但是浏览器没有该API
  618. // FileSaver.saveAs(new Blob([wbout], { type: "application/octet-stream" }), `${title} demo.xlsx`);//保存文件
  619. this.$message({
  620. message: "导出成功",
  621. type: "success",
  622. });
  623. },
  624. exportCourse(course, Man) {
  625. // 项目名称、项目创建人、协同人员、创建时间、修改时间、所属赛道、所属主题、项目详情简介;项目阶段数量、项目任务数量、项目进展
  626. // if possible 项目所处阶段、各阶段负责人/任务周期/协同者/任务描述/项目方案
  627. let _course = `<h1>${course.course[0].title}</h1>`
  628. let _people = `<h2>负责人:${course.username}</h2>`
  629. let _cteacher = `<h3>负责人:${course.cteacher}</h3>`
  630. let _time = `<h2>创建时间:${course.ctime} 修改时间:${course.time}</h2>`
  631. let _type = `<h2>分类:${course.typename}</h2>`
  632. let _detail = `<h2>项目详情:${course.brief}</h2>`
  633. let _jdZ = `<h2>项目阶段数量:${JSON.parse(course.chapters).length} 项目任务任数量:${course.jdz.taskC}</h2>`
  634. let _lasttask = ''
  635. if(course.lastTask){
  636. _lasttask = `<h2>项目所处阶段:${course.lastTask}</h2>`
  637. }
  638. let _chapter = JSON.parse(course.chapters)
  639. let chapterHTML = ''
  640. for (var i = 0; i < _chapter.length; i++) {
  641. chapterHTML += `<h2>第${i + 1}阶段-${_chapter[i].dyName}</h2>`
  642. let taskJson = _chapter[i].chapterInfo[0].taskJson
  643. for (var j = 0; j < taskJson.length; j++) {
  644. chapterHTML += `<h3>任务${j + 1}-${taskJson[j].task}</h3>`
  645. if (taskJson[j].time && taskJson[j].time.length) {
  646. chapterHTML += `<p>任务周期:${taskJson[j].time[0]}至${taskJson[j].time[1]}</p>`
  647. }
  648. if (taskJson[j].people) {
  649. chapterHTML += `<p>负责人:${this.getMan(Man, taskJson[j].people)}</p>`
  650. }
  651. if (taskJson[j].tcMember && taskJson[j].tcMember.length) {
  652. let tcMember = []
  653. for (var tc = 0; tc < taskJson[j].tcMember.length; tc++) {
  654. tcMember.push(this.getMan(Man, taskJson[j].tcMember[tc]))
  655. }
  656. chapterHTML += `<p>协同者:${tcMember.join(",")}</p>`
  657. }
  658. chapterHTML += `<div>任务描述</div>`
  659. chapterHTML += `<div>${taskJson[j].taskDetail}</div>`
  660. let _tool = taskJson[j].toolArray
  661. for (var tool = 0; tool < _tool.length; tool++) {
  662. if (_tool[tool].tool == 1) {
  663. chapterHTML+=`<h4>步骤${tool+1}:电子白板</h4>`
  664. } else if (_tool[tool].tool == 3) {
  665. chapterHTML+=`<h4>步骤${tool+1}:思维导图</h4>`
  666. } else if (_tool[tool].tool == 6) {
  667. chapterHTML+=`<h4>步骤${tool+1}:协同文档</h4>`
  668. } else if (_tool[tool].tool == 15) {
  669. chapterHTML+=`<h4>步骤${tool+1}:问答工具</h4>`
  670. } else if (_tool[tool].tool == 53) {
  671. chapterHTML+=`<h4>步骤${tool+1}:文件上传</h4>`
  672. } else if (_tool[tool].tool == 54) {
  673. chapterHTML+=`<h4>步骤${tool+1}:拍照</h4>`
  674. } else if (_tool[tool].tool == 55) {
  675. chapterHTML+=`<h4>步骤${tool+1}:压缩文件</h4>`
  676. } else if (_tool[tool].tool == 56) {
  677. chapterHTML+=`<h4>步骤${tool+1}:投票</h4>`
  678. } else if (_tool[tool].tool == 48) {
  679. chapterHTML+=`<h4>步骤${tool+1}:表格</h4>`
  680. } else if (_tool[tool].tool == 52) {
  681. chapterHTML+=`<h4>步骤${tool+1}:文档</h4>`
  682. }
  683. if(_tool[tool].toolDetail){
  684. chapterHTML += `<div>工具描述</div>`
  685. chapterHTML += `<div>${_tool[tool].toolDetail}</div>`
  686. }
  687. }
  688. }
  689. }
  690. var _html = _course + _people + _cteacher + _time +_type +_detail +_jdZ +_lasttask +chapterHTML;
  691. this.generate(course, _html);
  692. },
  693. getMan(manAarray, people) {
  694. let _people = "";
  695. if (manAarray.length) {
  696. for (var i = 0; i < manAarray.length; i++) {
  697. if (manAarray[i].userid == people) {
  698. _people = manAarray[i].name;
  699. break;
  700. }
  701. }
  702. }
  703. return _people ? _people : "";
  704. },
  705. setMan(course) {
  706. // let teacherJuri = this.teacherJuri2;
  707. this.ManAarray = [];
  708. let array = course.course_teacher.split(",")
  709. if (array.indexOf(course.userid) == -1) {
  710. array.push(course.userid);
  711. }
  712. let params = {
  713. uid: array.join(","),
  714. };
  715. this.ajax
  716. .get(this.$store.state.api + "getAllUserById", params)
  717. .then((res) => {
  718. this.exportCourse(course, res.data[0])
  719. })
  720. .catch((err) => {
  721. console.error(err);
  722. });
  723. },
  724. async generate(a, html) {
  725. // 将html文件中需要用到的数据挂载到store上
  726. this.$store.commit("update", ["report", html]);
  727. const content = `<!DOCTYPE html>
  728. <html lang="en">
  729. <head>
  730. <meta charset="UTF-8">
  731. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  732. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  733. <title>报告</title>
  734. </head>
  735. <body>
  736. ${this.$store.state.report}
  737. </body>
  738. </html>`;
  739. // debugger
  740. // 生成报告
  741. const link = document.createElement("a");
  742. let dname = a.course[0].title + "-" + a.username + ".html";
  743. // link.download = "报告.html"; // 文件名
  744. link.download = dname; // 文件名
  745. link.style.display = "none";
  746. // 创建文件流
  747. // 创建bolb实例时,内容一定要放在[]中
  748. const blob = new Blob([content], {
  749. type: "text/plain;charset='utf-8'",
  750. });
  751. link.href = window.URL.createObjectURL(blob);
  752. document.body.appendChild(link);
  753. link.click();
  754. document.body.removeChild(link);
  755. // saveAs(
  756. // htmlDocx.asBlob(content, {
  757. // orientation: "landscape", //跨域设置
  758. // }),
  759. // //文件名
  760. // "报告.doc"
  761. // );
  762. },
  763. },
  764. beforeDestroy() {
  765. clearInterval(this.timer);
  766. this.timer = null;
  767. },
  768. mounted() {
  769. this.isLoading = true;
  770. this.getData();
  771. this.selectAllType();
  772. this.timer = setInterval(() => {
  773. this.getData();
  774. }, 5000);
  775. },
  776. };
  777. </script>
  778. <style scoped>
  779. .student_input {
  780. width: 190px;
  781. font-size: 13px;
  782. padding: 0 10px;
  783. }
  784. .cd_body {
  785. height: 100%;
  786. width: 100%;
  787. }
  788. .pb_head {
  789. margin: 0 !important;
  790. width: 100% !important;
  791. display: flex;
  792. justify-content: space-between;
  793. }
  794. .student_head {
  795. margin-top: 10px;
  796. padding-bottom: 10px;
  797. display: flex;
  798. justify-content: space-between;
  799. }
  800. .head_left {
  801. display: flex;
  802. align-items: center;
  803. }
  804. .cd_title span {
  805. font-size: 25px;
  806. font-weight: 700;
  807. }
  808. .cd_table {
  809. width: 95%;
  810. margin: 0 auto;
  811. padding: 0 0 10px;
  812. }
  813. .el-table>>>.even_row {
  814. background-color: #f1f1f1 !important;
  815. }
  816. .dialog_diy>>>.el-dialog {
  817. background: #fafafa;
  818. }
  819. .dialog_diy>>>.el-dialog__header {
  820. background: #3d67bc !important;
  821. padding: 15px 20px;
  822. }
  823. .dialog_diy>>>.el-dialog__title {
  824. color: #fff;
  825. }
  826. .dialog_diy>>>.el-dialog__headerbtn {
  827. top: 19px;
  828. }
  829. .dialog_diy>>>.el-dialog__headerbtn .el-dialog__close {
  830. color: #fff;
  831. }
  832. .dialog_diy>>>.el-dialog__headerbtn .el-dialog__close:hover {
  833. color: #fff;
  834. }
  835. .cd_d_box {
  836. font-size: 16px;
  837. }
  838. .cd_d_box+.cd_d_box {
  839. margin-top: 10px;
  840. }
  841. .cd_d_jd {
  842. display: flex;
  843. flex-wrap: wrap;
  844. margin-top: 10px;
  845. }
  846. .cd_d_jd_box {
  847. width: 100px;
  848. display: flex;
  849. flex-direction: column;
  850. align-items: center;
  851. /* background: #eee; */
  852. border-radius: 5px;
  853. margin: 10px 15px 0 0;
  854. }
  855. .cd_d_jd_box {}
  856. .cd_d_jd_content {
  857. width: 100px;
  858. display: flex;
  859. flex-direction: column;
  860. align-items: center;
  861. background: #eee;
  862. border-radius: 5px;
  863. padding: 5px 0;
  864. }
  865. .cd_d_jd_content div+div {
  866. margin-top: 5px;
  867. }
  868. .cd_d_jd_content div span+span {
  869. margin-left: 5px;
  870. }
  871. .cd_d_jd_name {
  872. margin-bottom: 5px;
  873. color: #184ebd;
  874. }
  875. .cd_d_span div:nth-child(1) span:nth-child(1) {
  876. color: #3887fe;
  877. }
  878. .cd_d_span div:nth-child(2) span:nth-child(1) {
  879. color: #fe3987;
  880. }
  881. .cd_d_span div:nth-child(3) span:nth-child(1) {
  882. color: #10bb6e;
  883. }
  884. .cd_d_span div:nth-child(4) span:nth-child(1) {
  885. color: #3887fe;
  886. }
  887. .cd_d_span div span:nth-child(1) {
  888. margin-right: 5px;
  889. }
  890. .cd_course {
  891. cursor: pointer;
  892. width: 100%;
  893. display: flex;
  894. }
  895. .cd_course span {
  896. width: 100%;
  897. white-space: nowrap;
  898. overflow: hidden;
  899. text-overflow: ellipsis;
  900. }
  901. .table>>>.cell {
  902. padding: 0px 3px !important;
  903. }
  904. .student_page {
  905. width: 100%;
  906. margin: 20px auto;
  907. }
  908. /* .table >>> .el-table .cell, .table >>> .el-table--border td:first-child .cell, .table >>> .el-table--border th:first-child .cell{
  909. padding: 0 3px;
  910. } */
  911. </style>