CourseWeightManage.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. <template>
  2. <div class="course-weight-manage">
  3. <div class="part-box part-box-pad">
  4. <p>说明:</p>
  5. <p>
  6. 1.课程目标评价依据来源于平时成绩和期末考试成绩二部分,请录入平时成绩,期末成绩整体权重及各目标的权重;
  7. </p>
  8. <p>2.各课程目标下评价方式平时成绩部分总权重应等于100%;</p>
  9. </div>
  10. <div class="part-box part-box-pad">
  11. <el-table :data="tableSetData" style="max-width: 1000px" border>
  12. <el-table-column
  13. prop="courseTargetName"
  14. label="课程目标"
  15. ></el-table-column>
  16. <el-table-column label="平时成绩" width="160">
  17. <template slot-scope="scope">
  18. <div v-if="scope.row.type === 'sum'">
  19. <el-input-number
  20. v-model="customRate"
  21. class="width-80"
  22. size="small"
  23. :min="0"
  24. :max="100"
  25. :step="1"
  26. step-strictly
  27. :controls="false"
  28. >
  29. </el-input-number>
  30. <span style="margin-left: 5px">%</span>
  31. </div>
  32. <el-button
  33. v-else
  34. type="text"
  35. class="btn-act-primary"
  36. @click="toEdit(scope.row)"
  37. >
  38. 查看详情
  39. </el-button>
  40. </template>
  41. </el-table-column>
  42. <el-table-column label="期末成绩" width="160">
  43. <template slot-scope="scope">
  44. <div v-if="scope.row.type === 'sum'">
  45. <el-input-number
  46. v-model="defaultRate"
  47. class="width-80"
  48. size="small"
  49. :min="0"
  50. :max="100"
  51. :step="1"
  52. step-strictly
  53. :controls="false"
  54. >
  55. </el-input-number>
  56. <span style="margin-left: 5px">%</span>
  57. </div>
  58. </template>
  59. </el-table-column>
  60. <el-table-column label="目标整体权重" width="160">
  61. <template slot-scope="scope">
  62. <div v-if="scope.row.type === 'sum'">100%</div>
  63. <div v-else>
  64. <el-input-number
  65. v-model="scope.row.totalWeight"
  66. class="width-50"
  67. size="small"
  68. :min="0"
  69. :max="100"
  70. :step="1"
  71. step-strictly
  72. :controls="false"
  73. >
  74. </el-input-number>
  75. <span style="margin-left: 5px">%</span>
  76. </div>
  77. </template>
  78. </el-table-column>
  79. </el-table>
  80. <div class="text-center" style="margin: 20px 0">
  81. <el-button type="primary" :loading="loading" @click="submit"
  82. >保存</el-button
  83. >
  84. </div>
  85. <el-table
  86. v-if="resultDataList.length && cwStatus.currentSettingStatus"
  87. :data="resultDataList"
  88. :header-cell-style="{ textAlign: 'center' }"
  89. :cell-style="{ textAlign: 'center' }"
  90. :span-method="spanMethod"
  91. >
  92. <el-table-column
  93. prop="courseTargetName"
  94. label="课程目标"
  95. width="140"
  96. ></el-table-column>
  97. <el-table-column
  98. prop="degreeRequirement"
  99. label="支撑毕业要求"
  100. min-width="200"
  101. ></el-table-column>
  102. <el-table-column prop="totalWeight" label="目标整体权重" width="110">
  103. <template slot-scope="scope">{{ scope.row.totalWeight }}%</template>
  104. </el-table-column>
  105. <el-table-column label="考核/评价环节及目标分值">
  106. <el-table-column
  107. v-for="(item, eindex) in fullEvaluationList"
  108. :key="item.evaluationId"
  109. :label="item.evaluationName"
  110. >
  111. <template slot-scope="scope">
  112. {{
  113. scope.row.evaluationList[eindex].enable
  114. ? scope.row.evaluationList[eindex].targetScore
  115. : ""
  116. }}
  117. </template>
  118. </el-table-column>
  119. </el-table-column>
  120. <el-table-column label="目标分值统计" width="120">
  121. <template slot-scope="scope">
  122. {{ getEvaluationSumScore(scope.row.evaluationList) }}
  123. </template>
  124. </el-table-column>
  125. </el-table>
  126. </div>
  127. <!-- ModifyTargetEvaluation -->
  128. <modify-target-evaluation
  129. ref="ModifyTargetEvaluation"
  130. :sources="evaluationSources"
  131. :target="curTarget"
  132. @modified="targetEvaluationModified"
  133. ></modify-target-evaluation>
  134. </div>
  135. </template>
  136. <script>
  137. import { courseWeightDetail, courseWeightSave } from "../../api";
  138. import { calcSum } from "@/plugins/utils";
  139. import { mapState, mapActions } from "vuex";
  140. import ModifyTargetEvaluation from "./ModifyTargetEvaluation.vue";
  141. export default {
  142. name: "course-weight-manage",
  143. components: { ModifyTargetEvaluation },
  144. props: {
  145. course: {
  146. type: Object,
  147. default() {
  148. return {};
  149. },
  150. },
  151. },
  152. data() {
  153. return {
  154. defaultRate: 0,
  155. customRate: 0,
  156. tableSetData: [],
  157. evaluationList: [],
  158. fullEvaluationList: [],
  159. resultDataList: [],
  160. curTarget: {},
  161. evaluationSources: [],
  162. loading: false,
  163. };
  164. },
  165. computed: {
  166. ...mapState("base", ["cwStatus"]),
  167. lastNo() {
  168. return this.evaluationList.length - 1;
  169. },
  170. },
  171. mounted() {
  172. this.initData();
  173. },
  174. methods: {
  175. ...mapActions("base", ["updateCwStatus"]),
  176. async initData() {
  177. await this.updateCwStatus({
  178. teachCourseId: this.course.id,
  179. });
  180. await this.getList();
  181. if (this.cwStatus.currentSettingStatus) {
  182. this.updateResultDataList();
  183. }
  184. },
  185. async getList() {
  186. const res = await courseWeightDetail({
  187. teachCourseId: this.course.id,
  188. });
  189. this.defaultRate = res.defaultRate;
  190. this.customRate = res.customRate;
  191. this.transformData(res.submitForm || []);
  192. },
  193. transformData(data) {
  194. if (!data || !data.length) return [];
  195. this.evaluationList = data[0].evaluationList
  196. .filter((evaluation) => evaluation.evaluationType !== "DEFAULT")
  197. .map((evaluation) => {
  198. return { ...evaluation };
  199. });
  200. this.fullEvaluationList = data[0].evaluationList.map((evaluation) => {
  201. return { ...evaluation };
  202. });
  203. this.tableSetData = data;
  204. this.tableSetData.push({
  205. type: "sum",
  206. courseTargetId: "",
  207. courseTargetName: "合计",
  208. });
  209. },
  210. toEdit(row) {
  211. this.curTarget = row;
  212. this.updateEvaluationSources();
  213. this.$refs.ModifyTargetEvaluation.open();
  214. },
  215. updateEvaluationSources() {
  216. const unvalidEvaluations = [];
  217. this.tableSetData.forEach((item) => {
  218. if (item.type === "sum") return;
  219. if (item.courseTargetId === this.curTarget.courseTargetId) return;
  220. unvalidEvaluations.push(
  221. ...item.evaluationList
  222. .filter((elem) => elem.enable)
  223. .map((elem) => elem.evaluationId)
  224. );
  225. });
  226. this.evaluationSources = this.evaluationList.filter(
  227. (item) => !unvalidEvaluations.includes(item.evaluationId)
  228. );
  229. },
  230. targetEvaluationModified(data) {
  231. const valDict = {};
  232. data.forEach((item) => {
  233. valDict[item.evaluationId] = item.weight;
  234. });
  235. console.log(data, valDict);
  236. this.curTarget.evaluationList.forEach((evaluation, index) => {
  237. if (evaluation.evaluationType === "DEFAULT") return;
  238. evaluation.enable = valDict[evaluation.evaluationId] !== undefined;
  239. evaluation.weight = valDict[evaluation.evaluationId] || null;
  240. });
  241. console.log(this.curTarget);
  242. },
  243. getEvaluationSumScore(evaluationList) {
  244. const num = calcSum(
  245. evaluationList.map((item) => (item.enable ? item.targetScore : 0))
  246. );
  247. return num.toFixed(2);
  248. },
  249. spanMethod({ rowIndex, columnIndex }) {
  250. const lineCount = this.resultDataList.length - 1;
  251. if (rowIndex === lineCount) {
  252. if (columnIndex === 0) {
  253. return [1, 2];
  254. } else if (columnIndex === 1) {
  255. return [0, 0];
  256. }
  257. }
  258. },
  259. updateResultDataList() {
  260. // 更新合计
  261. const dataList = this.tableSetData.slice(0, -1);
  262. const tatolEvaluation = this.fullEvaluationList.map(
  263. (evaluation, eindex) => {
  264. const targetScore = calcSum(
  265. dataList.map((item) => item.evaluationList[eindex].targetScore || 0)
  266. );
  267. return {
  268. evaluationName: evaluation.evaluationName,
  269. enable: true,
  270. weight: null,
  271. targetScore,
  272. };
  273. }
  274. );
  275. this.resultDataList = [
  276. ...dataList,
  277. {
  278. courseTargetId: "total",
  279. courseTargetName: "合计",
  280. degreeRequirement: "",
  281. totalWeight: calcSum(dataList.map((item) => item.totalWeight || 0)),
  282. evaluationList: tatolEvaluation,
  283. },
  284. ];
  285. },
  286. checkDataList() {
  287. // 整体权重设置
  288. if (!this.customRate) {
  289. this.$message.error("请输入平时成绩权重");
  290. return;
  291. }
  292. if (!this.defaultRate) {
  293. this.$message.error("请输入期末成绩权重");
  294. return;
  295. }
  296. if (this.defaultRate + this.customRate !== 100) {
  297. this.$message.error("平均成绩权重与期末成绩权重合计不等于100%");
  298. return;
  299. }
  300. const dataList = this.tableSetData.slice(0, -1);
  301. // 目标整体权重
  302. if (dataList.some((item) => !item.totalWeight)) {
  303. this.$message.error("请设置所有目标的目标整体权重");
  304. return;
  305. }
  306. const totalWeight = calcSum(
  307. dataList.map((item) => item.totalWeight || 0)
  308. );
  309. if (totalWeight !== 100) {
  310. this.$message.error("目标整体权重合计不等于100%");
  311. return;
  312. }
  313. return true;
  314. },
  315. async submit() {
  316. if (this.loading) return;
  317. if (!this.checkDataList()) return;
  318. this.loading = true;
  319. const res = await courseWeightSave({
  320. teachCourseId: this.course.id,
  321. defaultRate: this.defaultRate,
  322. customRate: this.customRate,
  323. submitForm: this.tableSetData.slice(0, -1),
  324. }).catch(() => {});
  325. this.loading = false;
  326. if (!res) return;
  327. this.initData();
  328. this.$message.success("保存成功!");
  329. },
  330. },
  331. };
  332. </script>