element 中的table表头动态渲染
https://blog.csdn.net/heixiuheixiu666/article/details/104705024/
Element 动态表头渲染表格
https://qiaoyajun.blog.csdn.net/article/details/90552744?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link
vue+element实现动态表格:根据后台返回的属性名和字段动态生成可变表格
https://blog.csdn.net/weixin_43714266/article/details/90644450?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-7.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-7.no_search_link
vue element 中的table动态渲染实现(动态表头)
https://www.jb51.net/article/174739.htm
1 /* eslint-disable handle-callback-err */ 2 <template> 3 <div class="app-container"> 4 <h2 style="text-align:center">{{ checktitle }}({{ checkTime }})</h2> 5 <p style="text-align:right">考核对象:{{ person }} 所属组织:{{ company }}</p> 6 <div style="display:flex; justify-content: space-between; margin-bottom:20px"> 7 <span style="color:#3c99dc; font-size:16px" /> 8 <div style="position: relative; height: 26px; right:0;"> 9 <ct-button v-if="addFlag === '1'" size="mini" @click="addLine">新增指标</ct-button> 10 <ct-button type="save" size="mini" @click="dosave">暂存</ct-button> 11 <ct-button type="submit" size="mini" @click="submit">提交</ct-button> 12 <ct-button size="mini" @click="goback">返回</ct-button> 13 </div> 14 </div> 15 16 <div v-cloak class="table-wrapper"> 17 <div class="work-task"> 18 <div class="left-title">工作任务</div> 19 <div class="right-contnet"> 20 <el-table 21 style=" 100%" 22 border 23 :data="tableList" 24 :header-cell-style="{background:'#fff', color:'#555', fontWeight: 'normal'}" 25 > 26 <el-table-column 27 v-for="(item, index) in tableLabels" 28 :key="index" 29 :property="item.colId" 30 :width="item.colWidth" 31 align="center" 32 :label="item.colName" 33 > 34 <template slot-scope="scope"> 35 <div v-if="!scope.row.canEdit && !item.editable"> 36 <span>{{ scope.row[scope.column.property] }}</span> 37 </div> 38 <div v-if="scope.row.canEdit || item.editable"> 39 <el-input 40 v-if="item.colType === '4'" 41 v-model="scope.row[scope.column.property]" 42 type="textarea" 43 :rows="2" 44 placeholder="请输入内容" 45 /> 46 <el-input 47 v-else-if="item.colType === '0'" 48 v-model="scope.row[scope.column.property]" 49 placeholder="请输入内容" 50 /> 51 <el-input 52 v-else-if="item.colType === '1' || item.colType === '3'" 53 v-model.number="scope.row[scope.column.property]" 54 placeholder="请输入评分" 55 @blur="check(scope.row[scope.column.property])" 56 /> 57 </div> 58 </template> 59 </el-table-column> 60 <el-table-column label="操作" align="center" width="61"> 61 <template slot-scope="scope"> 62 <el-button v-if="scope.row.canEdit" type="text" @click.native.prevent="deleteRow(scope.row)"> 63 删除 64 </el-button> 65 </template> 66 </el-table-column> 67 </el-table> 68 </div> 69 </div> 70 <div class="total-score"> 71 <div class="left-title">总分</div> 72 <div class="right-content"> 73 <div 74 v-for="(item, index) in totalObjList" 75 :key="index" 76 class="table-item" 77 :style="styleObject(item)" 78 >{{ item.value }}</div> 79 <div class="last" /> 80 </div> 81 </div> 82 <div class="assess-option"> 83 <div class="left-title">考核意见</div> 84 <div class="right-content"> 85 <div v-for="(item, index) in commentList" :key="index" class="comment-item"> 86 <span class="task-name">{{ item.taskName }}</span> 87 <span class="user-name"> 操作人:{{ item.userName }}</span> 88 <span class="end-time">日期:{{ item.endTime }}</span> 89 <span class="comment">意见:{{ item.comment }}</span> 90 </div> 91 </div> 92 </div> 93 </div> 94 95 <div v-if="submitDialogVisible"> 96 <el-dialog 97 title="考核审批" 98 :visible.sync="submitDialogVisible" 99 width="30%" 100 class="dialog-style" 101 > 102 <submit-form 103 :process-id="$route.query.processId" 104 :node-id="nodeId" 105 :table-list="tableList" 106 @after-submit="afterSubmit" 107 /> 108 </el-dialog> 109 </div> 110 </div> 111 </template> 112 113 <script> 114 import { queryTaskInfo, tempStorage } from '@/api/period/workflow' 115 import SubmitForm from '@/views/workflow/submitForm' 116 export default { 117 components: { 118 SubmitForm 119 }, 120 data() { 121 return { 122 checktitle: '', 123 checkTime: '', 124 person: '', 125 company: '', 126 127 tableLabels: [], 128 tableList: [], 129 commentList: [], 130 totalScores: [], 131 totalObj: {}, 132 133 scoreLists: [], 134 submitDialogVisible: false, 135 weightScore: 0, 136 nodeId: '', 137 138 totalObjList: [], 139 addFlag: false 140 } 141 }, 142 computed: { 143 styleObject() { 144 return (item) => { 145 if (item.width) { 146 return { 147 flexGrow: 0, 148 flexShrink: 0, 149 flexBasis: item.width + 'px' 150 } 151 } else { 152 return { 153 flexGrow: 1, 154 flexShrink: 1, 155 flexBasis: 0 156 } 157 } 158 } 159 } 160 }, 161 watch: { 162 tableList: { 163 deep: true, 164 handler(val, oldVal) { 165 this.computedTotal() 166 } 167 } 168 }, 169 created() { 170 this.queryTask() 171 }, 172 methods: { 173 queryTask() { 174 const query = { 175 processId: this.$route.query.processId, 176 nodeId: this.$route.query.nodeId 177 } 178 queryTaskInfo(query).then(res => { 179 this.tableLabels = res.data.headers 180 this.tableList = res.data.tableDatas 181 this.commentList = res.data.comments 182 this.checktitle = res.data.title 183 this.checkTime = res.data.time 184 this.person = res.data.currentUserName 185 this.company = res.data.orgName 186 this.nodeId = res.data.nodeId 187 this.addFlag = res.data.nodeSet.addDataFlag 188 this.computedTotal() 189 }) 190 }, 191 computedTotal() { 192 this.totalObjList = [] 193 const scoreData = [] 194 if (this.tableList.length === 0) { 195 for (let i = 0; i < this.tableLabels.length; i++) { 196 const item1 = this.tableLabels[i] 197 if (item1.colType === '0' || item1.colType === '4') { 198 scoreData.push({ 199 [item1.colId]: '' 200 }) 201 } else { 202 scoreData.push({ 203 [item1.colId]: 0 204 }) 205 } 206 } 207 208 scoreData.forEach(item => { 209 for (const key in item) { 210 this.totalObjList.push({ 211 nodeId: key, 212 value: item[key] 213 }) 214 } 215 }) 216 this.totalObjList.forEach((item, index) => { 217 item['width'] = this.tableLabels[index].colWidth 218 }) 219 } else if (this.tableList.length > 0) { 220 for (let i = 0; i < this.tableLabels.length; i++) { 221 const item1 = this.tableLabels[i] 222 for (let j = 0; j < this.tableList.length; j++) { 223 const item2 = this.tableList[j] 224 if (item1.colType === '0' || item1.colType === '4') { 225 scoreData.push({ 226 [item1.colId]: '' 227 }) 228 } else { 229 scoreData.push({ 230 [item1.colId]: item2[item1.colId] 231 }) 232 } 233 } 234 } 235 236 this.scoreLists = [] 237 scoreData.map(item => { 238 for (const key in item) { 239 this.scoreLists.length ? this.addArr(this.scoreLists, item, key) : this.scoreLists.push(item) 240 } 241 }) 242 243 this.totalObjList = [] 244 this.scoreLists.forEach(item => { 245 for (const key in item) { 246 this.totalObjList.push({ 247 nodeId: key, 248 value: item[key] 249 }) 250 } 251 }) 252 this.totalObjList.forEach((item, index) => { 253 item['width'] = this.tableLabels[index].colWidth 254 }) 255 } 256 }, 257 addArr(newArr, value, key) { 258 newArr.map(newVal => { 259 if (newVal[key] || newArr.some(item => item.hasOwnProperty(key))) { 260 if (newVal[key] || newVal[key] === 0) { 261 newVal[key] = value[key] + newVal[key] 262 } 263 } else { 264 newArr.push(value) 265 } 266 }) 267 return newArr 268 }, 269 addLine() { 270 const obj = { 271 canEdit: true, 272 rowNo: this.tableList.length 273 } 274 this.tableLabels.forEach(item => { 275 if (item.colType === '0' || item.colType === '4') { 276 obj[item.colId] = '' 277 } else { 278 obj[item.colId] = 0 279 } 280 }) 281 this.tableList.push(obj) 282 }, 283 deleteRow(item) { 284 const index = this.tableList.indexOf(item) 285 this.tableList.splice(index, 1) 286 }, 287 goback() { 288 this.$router.go(-1) 289 }, 290 isPositiveInt(str) { // 非负整数 291 var g = /^[1-9]d*|0$/ 292 return g.test(str) 293 }, 294 check(val) { 295 if (val && !this.isPositiveInt(val)) { 296 this.$message({ 297 message: '分数只能为非负整数', 298 type: 'warning' 299 }) 300 } 301 }, 302 dosave() { 303 if (this.tableList.length === 0) { 304 this.$message({ 305 message: '至少填写一条指标', 306 type: 'warning' 307 }) 308 return 309 } 310 // this.tableList.forEach(item => { 311 // delete item.canEdit 312 // }) 313 const query = { 314 processId: this.$route.query.processId, 315 nodeId: this.nodeId, 316 rows: this.tableList 317 } 318 tempStorage(query).then(res => { 319 if (res.code === 1) { 320 this.$message({ 321 message: '暂存成功', 322 type: 'success' 323 }) 324 } 325 }).catch(err => { 326 this.$message({ 327 message: err, 328 type: 'warning' 329 }) 330 }) 331 }, 332 submit() { 333 this.scoreLists.forEach((item, index) => { 334 if (this.tableLabels[index].colName === '权重') { 335 for (const key in item) { 336 this.weightScore = item[key] 337 } 338 } 339 }) 340 341 if (this.weightScore !== 100) { 342 this.$message({ 343 message: '权重总分必须为100', 344 type: 'warning' 345 }) 346 return 347 } 348 let confirmMsg = '确定提交吗?' 349 350 for (let k = 0; k < this.tableList.length; k++) { 351 const tableItem = this.tableList[k] 352 for (const g in tableItem) { 353 if (g !== ('rowNo' || 'adId') && !isNaN(tableItem[g]) && tableItem[g] === 0) { 354 confirmMsg = '存在评分为0,确定提交吗?' 355 } 356 } 357 } 358 359 this.$confirm(confirmMsg, '提示', { 360 confirmButtonText: '确定', 361 cancelButtonText: '取消', 362 type: 'warning' 363 }).then(() => { 364 this.submitDialogVisible = true 365 }).catch((err) => { 366 console.log(err) 367 }) 368 }, 369 afterSubmit() { 370 this.submitDialogVisible = false 371 this.$router.go(-1) 372 } 373 } 374 } 375 </script> 376 377 <style lang="scss" scoped> 378 [v-cloak]{ 379 display: none !important; 380 } 381 382 $borderColor: #d2d2d2; 383 /deep/ .el-table { 384 border-collapse: collapse !important; 385 border-spacing: 0 !important; 386 } 387 /deep/ .el-table td, 388 /deep/ .el-table th.is-leaf { 389 border-bottom: 1px solid $borderColor; 390 } 391 /deep/ .el-table--border td, 392 /deep/ .el-table--border th, 393 /deep/ .el-table__body-wrapper .el-table--border.is-scrolling-left~.el-table__fixed { 394 border-right: 1px solid $borderColor; 395 } 396 397 /deep/ .el-table--border, 398 /deep/ .el-table--group { 399 border: 1px solid $borderColor; 400 border-bottom: 0 none; 401 } 402 .table-wrapper { 403 margin-top: 20px; 404 font-size: 14px; 405 color: #606266; 406 .left-title { 407 flex: 0 0 160px; 408 border-left: 1px solid $borderColor; 409 border-top: 1px solid $borderColor; 410 border-bottom: 1px solid $borderColor; 411 display: flex; 412 justify-content: center; 413 align-items: center; 414 } 415 .work-task { 416 display: flex; 417 .right-contnet { 418 overflow: hidden; 419 flex: 1; 420 .el-table { 421 100%; 422 } 423 /deep/ .el-table tbody tr:hover > td { 424 background-color: transparent !important; 425 } 426 } 427 .table-header { 428 display: flex; 429 } 430 } 431 .total-score { 432 display: flex; 433 .left-title { 434 160px; 435 height: 48px; 436 border-top: none; 437 border-right: 1px solid $borderColor; 438 } 439 .right-content { 440 flex: 1; 441 display: flex; 442 border-right: 1px solid $borderColor; 443 .table-item { 444 flex: 1; 445 display: flex; 446 justify-content: center; 447 align-items: center; 448 border-right: 1px solid $borderColor; 449 border-bottom: 1px solid $borderColor; 450 position: relative; 451 left: 1px; 452 } 453 .last { 454 61px; 455 border-bottom: 1px solid $borderColor; 456 } 457 } 458 } 459 460 .assess-option { 461 display: flex; 462 .left-title { 463 160px; 464 min-height: 48px; 465 border-top: none; 466 border-right: 1px solid $borderColor; 467 border-bottom: 1px solid $borderColor; 468 } 469 .right-content { 470 flex: 1; 471 line-height: 24px; 472 padding: 10px; 473 border-right: 1px solid $borderColor; 474 border-bottom: 1px solid $borderColor; 475 .comment-item { 476 margin-bottom: 10px; 477 &:last-child{ 478 margin-bottom: 0; 479 } 480 } 481 .task-name { 482 margin-right: 20px; 483 } 484 .user-name { 485 margin-right: 20px; 486 } 487 .end-time { 488 margin-right: 20px; 489 } 490 } 491 } 492 } 493 </style>