TrainingPlanCourseMatrix.vue 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. <template>
  2. <div class="part-box part-box-pad course-matrix">
  3. <el-table
  4. :data="dataList"
  5. border
  6. :cell-style="cellStyleHandle"
  7. :summary-method="getSummaries"
  8. show-summary
  9. >
  10. <el-table-column label="课程信息" align="center" fixed="left" width="300">
  11. <el-table-column
  12. label="课程名称(代码)"
  13. width="240"
  14. show-overflow-tooltip
  15. >
  16. <template slot-scope="scope">
  17. {{ scope.row.courseName }}({{ scope.row.courseCode }})
  18. </template>
  19. </el-table-column>
  20. <el-table-column
  21. label="学分"
  22. prop="credit"
  23. width="60"
  24. align="center"
  25. ></el-table-column>
  26. </el-table-column>
  27. <el-table-column label="毕业要求" align="center">
  28. <template v-if="hasSubRequirements">
  29. <el-table-column
  30. v-for="(column, cindex) in columns"
  31. :key="cindex"
  32. :label="column.name"
  33. align="center"
  34. >
  35. <el-table-column
  36. v-for="subr in column.subRequirements"
  37. :key="subr.name"
  38. align="center"
  39. :prop="`${column.name}_${subr.name}`"
  40. >
  41. <template slot="header">
  42. <span v-if="subr.name === 'null'"></span>
  43. <template v-else>
  44. <span>{{ subr.name }}</span>
  45. <el-tooltip v-if="subr.content" effect="dark" placement="top">
  46. <div slot="content" class="tooltip-area">
  47. {{ subr.content }}
  48. </div>
  49. <i class="el-icon-info ml-1 tooltip-info-icon"></i>
  50. </el-tooltip>
  51. </template>
  52. </template>
  53. <template slot-scope="scope">
  54. <el-input-number
  55. v-if="scope.row.canEdit"
  56. v-model="scope.row[`${column.name}_${subr.name}`].value"
  57. class="width-50"
  58. :min="0"
  59. :max="1"
  60. :step="0.01"
  61. step-strictly
  62. :controls="false"
  63. size="mini"
  64. @change="
  65. () =>
  66. unitChange(
  67. scope.row,
  68. `${column.name}_${subr.name}`,
  69. subr.columnIndex
  70. )
  71. "
  72. ></el-input-number>
  73. <span v-else>{{
  74. scope.row[`${column.name}_${subr.name}`].value
  75. }}</span>
  76. </template>
  77. </el-table-column>
  78. </el-table-column>
  79. </template>
  80. <template v-else>
  81. <el-table-column
  82. v-for="(column, cindex) in columns"
  83. :key="cindex"
  84. :label="column.name"
  85. align="center"
  86. :prop="`${column.name}_null`"
  87. >
  88. <template slot-scope="scope">
  89. <el-input-number
  90. v-if="scope.row.canEdit"
  91. v-model="scope.row[`${column.name}_null`].value"
  92. class="width-50"
  93. :min="0"
  94. :max="1"
  95. :step="0.01"
  96. step-strictly
  97. :controls="false"
  98. size="mini"
  99. @change="
  100. () =>
  101. unitChange(
  102. scope.row,
  103. `${column.name}_null`,
  104. column.columnIndex
  105. )
  106. "
  107. ></el-input-number>
  108. <span v-else>{{ scope.row[`${column.name}_null`].value }}</span>
  109. </template>
  110. </el-table-column>
  111. </template>
  112. </el-table-column>
  113. </el-table>
  114. </div>
  115. </template>
  116. <script>
  117. import {
  118. trainingPlanCourseMatrixDetail,
  119. trainingPlanCourseMatrixSave,
  120. } from "../../api";
  121. import { calcSum } from "@/plugins/utils";
  122. export default {
  123. name: "training-plan-course-matrix",
  124. props: {
  125. rowData: {
  126. type: Object,
  127. default() {
  128. return {};
  129. },
  130. },
  131. },
  132. data() {
  133. return {
  134. dataList: [],
  135. columns: [],
  136. hasSubRequirements: false,
  137. loading: false,
  138. errorIndexs: [],
  139. warningColumnIndexs: [],
  140. };
  141. },
  142. mounted() {
  143. this.getList();
  144. },
  145. methods: {
  146. async getList() {
  147. const res = await trainingPlanCourseMatrixDetail({
  148. cultureProgramId: this.rowData.id,
  149. });
  150. const tableData = res || [];
  151. this.dataList = tableData.map((item, index) => {
  152. if (!index) this.parseColumns(item.requirements);
  153. const nitem = {
  154. courseId: item.courseId,
  155. courseCode: item.courseCode,
  156. courseName: item.courseName,
  157. canEdit: item.canEdit,
  158. };
  159. item.requirements.forEach((requirement) => {
  160. requirement.subRequirements.forEach((subr) => {
  161. nitem[`${requirement.name}_${subr.name + ""}`] = {
  162. id: subr.id,
  163. value: subr.scale || undefined,
  164. };
  165. });
  166. });
  167. return nitem;
  168. });
  169. this.initWarningColumnIndexs();
  170. },
  171. parseColumns(requirements) {
  172. this.hasSubRequirements = requirements.some(
  173. (item) => item.subRequirements[0].name !== null
  174. );
  175. if (!this.hasSubRequirements) {
  176. this.columns = requirements.map((item, index) => {
  177. return { name: item.name, columnIndex: index + 1 };
  178. });
  179. return;
  180. }
  181. let cindex = 1;
  182. this.columns = requirements.map((item) => {
  183. return {
  184. name: item.name,
  185. subRequirements: item.subRequirements.map((subr) => {
  186. return {
  187. name: subr.name + "",
  188. columnIndex: ++cindex,
  189. content: subr.content,
  190. };
  191. }),
  192. };
  193. });
  194. },
  195. updateErrorIndexs([rowIndex, columnIndex]) {
  196. const pos = this.errorIndexs.findIndex((item) => item[1] === columnIndex);
  197. if (pos !== -1) {
  198. this.errorIndexs.splice(pos, 1);
  199. }
  200. this.errorIndexs.push([rowIndex, columnIndex]);
  201. },
  202. clearErrorIndexs(columnIndex) {
  203. this.errorIndexs = this.errorIndexs.filter(
  204. (item) => item[1] !== columnIndex
  205. );
  206. },
  207. initWarningColumnIndexs() {
  208. const warningColumnIndexs = [];
  209. this.columns.forEach((column) => {
  210. column.subRequirements.forEach((subr) => {
  211. const key = `${column.name}_${subr.name}`;
  212. const totalVal = calcSum(
  213. this.dataList.map((item) =>
  214. item[key].value ? Math.floor(item[key].value * 100) : 0
  215. )
  216. );
  217. if (totalVal < 100) warningColumnIndexs.push(subr.columnIndex);
  218. });
  219. });
  220. this.warningColumnIndexs = warningColumnIndexs;
  221. },
  222. updateWarningColumnIndexs(columnIndex, type) {
  223. const pos = this.warningColumnIndexs.findIndex(
  224. (item) => item === columnIndex
  225. );
  226. if (pos !== -1) {
  227. if (type === "remove") {
  228. this.warningColumnIndexs.splice(pos, 1);
  229. }
  230. } else {
  231. if (type === "add") {
  232. this.warningColumnIndexs.push(columnIndex);
  233. }
  234. }
  235. },
  236. async unitChange(row, key, columnIndex) {
  237. const [fieldName, nodeName] = key.split("_");
  238. const totalVal = calcSum(
  239. this.dataList.map((item) =>
  240. item[key].value ? Math.floor(item[key].value * 100) : 0
  241. )
  242. );
  243. if (totalVal < 100) {
  244. this.updateWarningColumnIndexs(columnIndex, "add");
  245. } else {
  246. this.updateWarningColumnIndexs(columnIndex, "remove");
  247. }
  248. if (totalVal > 100) {
  249. const columnName =
  250. nodeName === "null" ? fieldName : `${fieldName}:${nodeName}`;
  251. this.$message.error(`${columnName}列总和大于1,当前修改值将不会保存!`);
  252. const rowIndex = this.dataList.findIndex(
  253. (item) => item.courseCode === row.courseCode
  254. );
  255. this.updateErrorIndexs([rowIndex, columnIndex]);
  256. return;
  257. }
  258. let saveData = [];
  259. const curColumnHasError = this.errorIndexs.some(
  260. (item) => item[1] === columnIndex
  261. );
  262. if (curColumnHasError) {
  263. saveData = this.dataList.map((item) => {
  264. return {
  265. id: item[key].id,
  266. scale: item[key].value,
  267. };
  268. });
  269. } else {
  270. saveData = [
  271. {
  272. id: row[key].id,
  273. scale: row[key].value,
  274. },
  275. ];
  276. }
  277. this.clearErrorIndexs(columnIndex);
  278. await trainingPlanCourseMatrixSave(saveData);
  279. },
  280. cellStyleHandle({ rowIndex, columnIndex }) {
  281. let style = undefined;
  282. if (this.warningColumnIndexs.includes(columnIndex)) {
  283. style = {
  284. backgroundColor: "#fdecdc",
  285. };
  286. }
  287. if (!this.errorIndexs.length) return style;
  288. if (
  289. this.errorIndexs.some(
  290. (item) => rowIndex === item[0] && columnIndex === item[1]
  291. )
  292. ) {
  293. style = {
  294. backgroundColor: "#fde2e2",
  295. };
  296. }
  297. return style;
  298. },
  299. // spanMethod({ rowIndex, columnIndex }) {
  300. // if (rowIndex === 0 && columnIndex === 0) {
  301. // return { rowspan: 2, colspan: this.hasSubRequirements ? 2 : 1 };
  302. // }
  303. // },
  304. getSummaries(param) {
  305. const { columns } = param;
  306. const sums = [];
  307. columns.forEach((column, index) => {
  308. if (index === 0) {
  309. sums[index] = "合计";
  310. return;
  311. }
  312. if (index === 1) {
  313. sums[index] = "";
  314. return;
  315. }
  316. const total = calcSum(
  317. this.dataList.map((item) =>
  318. item[column.property].value ? item[column.property].value * 100 : 0
  319. )
  320. );
  321. sums[index] = (total / 100).toFixed(2);
  322. });
  323. return sums;
  324. },
  325. },
  326. };
  327. </script>