summary.vue 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. <template>
  2. <ele-modal
  3. :visible.sync="visible"
  4. title="培训总结"
  5. width="60vw"
  6. append-to-body
  7. :close-on-click-modal="false"
  8. :maxable="true"
  9. @close="cancel"
  10. >
  11. <el-form
  12. ref="form"
  13. :model="form"
  14. :rules="rules"
  15. label-width="130px"
  16. class="el-form-box"
  17. v-loading="loading"
  18. >
  19. <!-- 培训基本信息(只读,带自培训记录带出) -->
  20. <el-row :gutter="20">
  21. <el-col :span="8">
  22. <el-form-item label="培训项目:">
  23. <el-input :value="info.trainingProject" disabled placeholder="-" />
  24. </el-form-item>
  25. </el-col>
  26. <el-col :span="8">
  27. <el-form-item label="地点:">
  28. <el-input :value="info.location" disabled placeholder="-" />
  29. </el-form-item>
  30. </el-col>
  31. <el-col :span="8">
  32. <el-form-item label="培训讲师:">
  33. <el-input :value="info.trainingLecturer" disabled placeholder="-" />
  34. </el-form-item>
  35. </el-col>
  36. </el-row>
  37. <el-row :gutter="20">
  38. <el-col :span="8">
  39. <el-form-item label="讲师资质:">
  40. <el-input
  41. :value="info.lecturerQualification"
  42. disabled
  43. placeholder="-"
  44. />
  45. </el-form-item>
  46. </el-col>
  47. <el-col :span="8">
  48. <el-form-item label="计划人数:">
  49. <el-input :value="info.plannedCount" disabled placeholder="-" />
  50. </el-form-item>
  51. </el-col>
  52. <el-col :span="8">
  53. <el-form-item label="实到人数:">
  54. <el-input
  55. :value="info.actualCount"
  56. disabled
  57. placeholder="请输入实到人数"
  58. />
  59. </el-form-item>
  60. </el-col>
  61. </el-row>
  62. <el-row :gutter="20">
  63. <el-col :span="8">
  64. <el-form-item label="培训时段:">
  65. <el-input :value="trainingPeriod" disabled placeholder="-" />
  66. </el-form-item>
  67. </el-col>
  68. <el-col :span="8">
  69. <el-form-item label="教学方式:">
  70. <el-input :value="info.teachingMethod" disabled placeholder="-" />
  71. </el-form-item>
  72. </el-col>
  73. <el-col :span="8">
  74. <el-form-item label="培训类别:" prop="trainingCategories">
  75. <el-checkbox-group v-model="form.trainingCategories">
  76. <el-checkbox
  77. v-for="item in trainingCategoryOptions"
  78. :key="item.value"
  79. :label="item.value"
  80. >
  81. {{ item.label }}
  82. </el-checkbox>
  83. </el-checkbox-group>
  84. </el-form-item>
  85. </el-col>
  86. </el-row>
  87. <el-form-item label="教材:" prop="teachingMaterial">
  88. <el-input
  89. v-model="form.teachingMaterial"
  90. type="textarea"
  91. :rows="2"
  92. maxlength="500"
  93. show-word-limit
  94. placeholder="请输入教材(最多500字)"
  95. />
  96. </el-form-item>
  97. <el-form-item label="评价形式:" prop="evaluationForm">
  98. <el-input
  99. v-model="form.evaluationForm"
  100. type="textarea"
  101. :rows="2"
  102. maxlength="500"
  103. show-word-limit
  104. placeholder="请输入评价形式(最多500字)"
  105. />
  106. </el-form-item>
  107. <el-form-item label="培训总结:" prop="trainingSummary">
  108. <el-input
  109. v-model="form.trainingSummary"
  110. type="textarea"
  111. :rows="4"
  112. maxlength="2000"
  113. show-word-limit
  114. placeholder="请输入培训总结(最多2000字)"
  115. />
  116. </el-form-item>
  117. <el-form-item label="效果追踪评价:" prop="trackingEvaluation">
  118. <el-input
  119. v-model="form.trackingEvaluation"
  120. type="textarea"
  121. :rows="4"
  122. maxlength="2000"
  123. show-word-limit
  124. placeholder="请输入培训效果追踪评价(最多2000字)"
  125. />
  126. </el-form-item>
  127. <el-form-item label="总结附件:" prop="summaryAttachments">
  128. <fileMain v-model="form.summaryAttachments" type="add" />
  129. </el-form-item>
  130. </el-form>
  131. <template v-slot:footer>
  132. <el-button type="primary" :loading="saving" @click="save()"
  133. >保存</el-button
  134. >
  135. <el-button @click="cancel">取消</el-button>
  136. </template>
  137. </ele-modal>
  138. </template>
  139. <script>
  140. import { getById, saveSummary } from '@/api/offlineTraining/index.js';
  141. import {
  142. TEACHING_METHOD_OPTIONS,
  143. SUMMARY_TRAINING_CATEGORY_OPTIONS,
  144. toValueArray,
  145. toValueString,
  146. toLabelString
  147. } from '../constants';
  148. const defForm = {
  149. trainingId: '',
  150. trainingCategories: [],
  151. teachingMaterial: '',
  152. evaluationForm: '',
  153. trainingSummary: '',
  154. trackingEvaluation: '',
  155. summaryAttachments: []
  156. };
  157. const defInfo = {
  158. trainingProject: '',
  159. location: '',
  160. trainingLecturer: '',
  161. lecturerQualification: '',
  162. plannedCount: '',
  163. actualCount: '',
  164. startTime: '',
  165. endTime: '',
  166. teachingMethod: ''
  167. };
  168. export default {
  169. data() {
  170. return {
  171. visible: false,
  172. loading: false,
  173. saving: false,
  174. info: JSON.parse(JSON.stringify(defInfo)),
  175. trainingCategoryOptions: SUMMARY_TRAINING_CATEGORY_OPTIONS,
  176. form: JSON.parse(JSON.stringify(defForm)),
  177. rules: {
  178. teachingMaterial: [
  179. { max: 500, message: '教材不能超过500字', trigger: 'blur' }
  180. ],
  181. evaluationForm: [
  182. { max: 500, message: '评价形式不能超过500字', trigger: 'blur' }
  183. ],
  184. trainingSummary: [
  185. { max: 2000, message: '培训总结不能超过2000字', trigger: 'blur' }
  186. ],
  187. trackingEvaluation: [
  188. {
  189. max: 2000,
  190. message: '培训效果追踪评价不能超过2000字',
  191. trigger: 'blur'
  192. }
  193. ]
  194. }
  195. };
  196. },
  197. computed: {
  198. // 培训时段:开始时间 ~ 结束时间
  199. trainingPeriod() {
  200. const { startTime, endTime } = this.info;
  201. if (startTime && endTime) {
  202. return `${startTime} ~ ${endTime}`;
  203. }
  204. return startTime || endTime || '';
  205. }
  206. },
  207. methods: {
  208. async open(row) {
  209. this.visible = true;
  210. this.loading = true;
  211. this.info = {
  212. ...JSON.parse(JSON.stringify(defInfo)),
  213. trainingProject: (row && row.trainingProject) || ''
  214. };
  215. this.form = { ...JSON.parse(JSON.stringify(defForm)), trainingId: row.id };
  216. try {
  217. const detail = await getById(row.id);
  218. const summary = (detail && detail.summary) || {};
  219. this.info = this.mapDetailToInfo(detail);
  220. this.form = {
  221. trainingId: row.id,
  222. trainingCategories: toValueArray(summary.trainingCategories),
  223. teachingMaterial: summary.teachingMaterial || '',
  224. evaluationForm: summary.evaluationForm || '',
  225. trainingSummary: summary.trainingSummary || '',
  226. trackingEvaluation: summary.trackingEvaluation || '',
  227. summaryAttachments: toValueArray(summary.summaryAttachments)
  228. };
  229. } catch (error) {
  230. this.$message.error(error.message || '获取培训总结失败');
  231. } finally {
  232. this.loading = false;
  233. this.$nextTick(() => {
  234. this.$refs.form && this.$refs.form.clearValidate();
  235. });
  236. }
  237. },
  238. // 培训记录基本信息(只读展示)
  239. mapDetailToInfo(detail) {
  240. const data = detail || {};
  241. return {
  242. trainingProject: data.trainingProject || '',
  243. location: data.location || '',
  244. trainingLecturer: data.trainingLecturer || '',
  245. lecturerQualification: data.lecturerQualification || '',
  246. plannedCount:
  247. data.plannedCount === undefined || data.plannedCount === null
  248. ? ''
  249. : data.plannedCount,
  250. actualCount:
  251. data.actualCount === undefined || data.actualCount === null
  252. ? ''
  253. : data.actualCount,
  254. startTime: data.startTime || '',
  255. endTime: data.endTime || '',
  256. teachingMethod: toLabelString(
  257. TEACHING_METHOD_OPTIONS,
  258. data.teachingMethod
  259. )
  260. };
  261. },
  262. cancel() {
  263. this.visible = false;
  264. this.info = JSON.parse(JSON.stringify(defInfo));
  265. this.form = JSON.parse(JSON.stringify(defForm));
  266. this.$refs.form && this.$refs.form.clearValidate();
  267. },
  268. save() {
  269. this.$refs.form.validate(async (valid) => {
  270. if (!valid) return;
  271. this.saving = true;
  272. try {
  273. await saveSummary({
  274. trainingId: this.form.trainingId,
  275. trainingCategories: toValueString(this.form.trainingCategories),
  276. teachingMaterial: this.form.teachingMaterial,
  277. evaluationForm: this.form.evaluationForm,
  278. trainingSummary: this.form.trainingSummary,
  279. trackingEvaluation: this.form.trackingEvaluation,
  280. summaryAttachments: (this.form.summaryAttachments || []).join(',')
  281. });
  282. this.$message.success('培训总结保存成功');
  283. this.cancel();
  284. this.$emit('reload');
  285. } catch (error) {
  286. this.$message.error(error.message || '保存失败');
  287. } finally {
  288. this.saving = false;
  289. }
  290. });
  291. }
  292. }
  293. };
  294. </script>
  295. <style lang="scss" scoped>
  296. .el-form-box {
  297. max-height: calc(100vh - 300px);
  298. overflow-y: auto;
  299. padding-right: 10px;
  300. }
  301. </style>