faculty-forms.vue 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. <template>
  2. <el-form ref="form" :model="formModel" :rules="facultyRules">
  3. <mx-table :prop-defines="facultyTableDefines" :rows="formModel.rows">
  4. <template #batch="{key, label, prop}">
  5. <el-popover :ref="key" trigger="click" width="520">
  6. <div class="fx-column">
  7. <div class="fx-row fx-cen-cen f16">批量设置</div>
  8. <el-button-group class="mt20">
  9. <el-button type="primary" size="mini" @click="handleCheckAll">全选</el-button>
  10. <el-button type="primary" size="mini" @click="handleCheckReverse">反选</el-button>
  11. </el-button-group>
  12. <el-checkbox-group multiple v-model="batchData.subjectIds" class="mt3">
  13. <el-checkbox v-for="(sub,i) in rows" :key="i" :label="sub.subjectId">{{ sub.subjectName }}
  14. </el-checkbox>
  15. </el-checkbox-group>
  16. <div class="fx-row fx-bet-cen mt20">
  17. <el-input-number v-model="batchData.inputValue" :min="0" style="width: 120px"></el-input-number>
  18. <div class="fx-row fx-end-cen fx-1">
  19. <el-button size="small" @click="handleBatchCancel(key)">取消</el-button>
  20. <el-button type="primary" size="small" @click="handleBatchConfirm(key)">批量设置</el-button>
  21. </div>
  22. </div>
  23. </div>
  24. <el-button slot="reference" type="text">
  25. <span class="f-fff">{{ label }}</span>
  26. <i class="el-icon-caret-bottom f-fff"></i>
  27. </el-button>
  28. </el-popover>
  29. </template>
  30. <template #input="{row, key, label, $index, prop}">
  31. <el-form-item :prop="`rows[${$index}].${key}`" :rules="facultyRules[key]"
  32. class="form-item-readonly form-item-inner-error">
  33. <el-input-number v-model="row[key]" :min="0" :disabled="!!prop.disabled || row==sum"
  34. @change="handleInputChanged(key, row)&&$emit('change')"
  35. style="width: 120px"></el-input-number>
  36. </el-form-item>
  37. </template>
  38. </mx-table>
  39. </el-form>
  40. </template>
  41. <script>
  42. export default {
  43. name: 'faculty-forms',
  44. props: {
  45. rows: {
  46. type: Array,
  47. default: () => []
  48. }
  49. },
  50. data() {
  51. return {
  52. sum: { subjectName: '合计' },
  53. batchData: {
  54. subjectIds: [],
  55. inputValue: 0
  56. }
  57. }
  58. },
  59. computed: {
  60. formModel() {
  61. // fields - use demo field trigger
  62. this.rows.forEach((row) => this.handleInputChanged('teacherCount', row, false))
  63. this.rows.forEach((row) => this.handleInputChanged('levelClassesCount', row, false))
  64. // summary
  65. this.calculateSummary()
  66. // rebuild
  67. return {
  68. rows: [...this.rows, this.sum]
  69. }
  70. },
  71. facultyTableDefines() {
  72. return {
  73. subjectName: {
  74. label: '科目'
  75. },
  76. classesCountPrev: {
  77. label: '原周课时数',
  78. slot: 'input',
  79. slotHeader: 'batch',
  80. minWidth: '130px'
  81. },
  82. teacherCount: {
  83. label: '单科老师数量',
  84. slot: 'input',
  85. slotHeader: 'batch',
  86. minWidth: '130px'
  87. },
  88. teacherClassesCount: {
  89. label: '老师周课时数',
  90. slot: 'input',
  91. slotHeader: 'batch',
  92. minWidth: '130px'
  93. },
  94. classesCount: {
  95. label: '单科总课时数',
  96. slot: 'input',
  97. minWidth: '130px',
  98. disabled: true
  99. },
  100. levelClassesCount: {
  101. label: '等级考课时数',
  102. slot: 'input',
  103. slotHeader: 'batch',
  104. minWidth: '130px'
  105. },
  106. qualifiedClassesCount: {
  107. label: '合格考课时数',
  108. slot: 'input',
  109. slotHeader: 'batch',
  110. minWidth: '130px'
  111. }
  112. }
  113. },
  114. facultyRules() {
  115. const excludeFiles = ['subjectName', 'classesCount']
  116. const commonValidator = (rule, value, callback) => {
  117. const arrField = rule.field.split('.')
  118. let index = arrField.first()
  119. index = index.slice(index.indexOf('[') + 1, -1) * 1
  120. const field = arrField.last()
  121. const faculty = this.formModel.rows[index]
  122. const required = faculty['isOffical']
  123. if (required && !(value > 0)) {
  124. const displayName = this.facultyTableDefines[field]?.label || key
  125. return callback(displayName + '须>0')
  126. }
  127. callback()
  128. }
  129. const rules = {}
  130. Object.keys(this.facultyTableDefines).forEach(key => {
  131. if (!excludeFiles.includes(key)) {
  132. rules[key] = { validator: commonValidator }
  133. }
  134. })
  135. return rules
  136. }
  137. },
  138. methods: {
  139. handleCheckAll() {
  140. this.batchData.subjectIds = this.rows.map(s => s.subjectId)
  141. },
  142. handleCheckReverse() {
  143. this.batchData.subjectIds = this.rows
  144. .filter(s => !this.batchData.subjectIds.includes(s.subjectId))
  145. .map(s => s.subjectId)
  146. },
  147. handleBatchCancel(key) {
  148. this.$refs[key].doClose()
  149. },
  150. handleBatchConfirm(key) {
  151. if (!this.batchData.subjectIds.length) {
  152. this.msgError('批量设置必须至少选中1个科目')
  153. return
  154. }
  155. const toSetVal = this.batchData.inputValue
  156. const toSetSubjects = this.batchData.subjectIds
  157. this.rows.filter(r => toSetSubjects.includes(r.subjectId))
  158. .forEach(row => {
  159. row[key] = toSetVal
  160. this.handleInputChanged(key, row, false)
  161. })
  162. this.calculateSummary()
  163. this.handleBatchCancel(key)
  164. this.$emit('change')
  165. },
  166. handleInputChanged(key, row, calcSum = true) {
  167. // auto calc
  168. const helpFields = ['teacherCount', 'teacherClassesCount']
  169. const linkedField = 'classesCount'
  170. if (helpFields.includes(key)) {
  171. row[linkedField] = row.teacherCount * row.teacherClassesCount
  172. }
  173. // auto copy
  174. const equalFields = ['levelClassesCount', 'qualifiedClassesCount']
  175. if (equalFields.includes(key) && row['isFixed']) {
  176. const otherKeys = equalFields.filter(k => k != key)
  177. otherKeys.forEach(k => row[k] = row[key])
  178. }
  179. // auto sum
  180. if (calcSum) this.calculateSummary()
  181. return true
  182. },
  183. calculateSummary() {
  184. const excludeFiles = ['subjectName']
  185. Object.keys(this.facultyTableDefines).forEach(key => {
  186. if (!excludeFiles.includes(key)) {
  187. this.sum[key] = this.rows.sum(r => r[key])
  188. }
  189. })
  190. },
  191. validate() {
  192. console.log('faculty-forms validate')
  193. return this.$refs.form.validate()
  194. }
  195. }
  196. }
  197. </script>
  198. <style scoped>
  199. /deep/ .form-item-inner-error .el-form-item__error {
  200. left: 2px;
  201. bottom: 2px;
  202. top: auto;
  203. z-index: 2;
  204. }
  205. /deep/ .el-table__body tr:last-child,
  206. /deep/ .el-table__body tr:last-child:hover > td {
  207. font-weight: 600;
  208. background-color: #FDEAE1;
  209. }
  210. </style>