Câu hỏi

<template>
<el-dialog
title="查看审核记录"
:visible.sync="dialogVisible"
:before-close="handleClose"
center
width="1440px"
custom-class="recorddialog"
>
<div class="dialogcontent">
<div class="bookinfo">
<el-row :gutter="20">
<el-col :span="7">
<img :src="bookInfo.coverUrl" alt="封面" class="bookimg" />
</el-col>
<el-col :span="7" class="bookmiddle">
<div class="fl">
<div class="lable">教材名称:</div>
<div class="value">{{ bookInfo.materialName }}</div>
</div>
<div class="fl">
<div class="lable">主编:</div>
<div class="value">{{ bookInfo.chiefEditor }}</div>
</div>
<div class="fl">
<div class="lable">申请人:</div>
<div class="value">{{ bookInfo.approverName }}</div>
</div>
</el-col>
<el-col :span="10" class="bookmiddle">
<div class="fl">
<div class="lable">申请人联系方式:</div>
<div class="value">{{ bookInfo.contactInfo }}</div>
</div>
<div class="fl">
<div class="lable">申请时间:</div>
<div class="value">{{ bookInfo.createTime }}</div>
</div>
</el-col>
</el-row>
</div>
<div class="title">
<div class="fl">
<div class="title-text">审核状态:</div>
<div class="title-line">
{{ materialStatusMap[bookInfo.status] || '--' }}
</div>
</div>
<div class="fl">
<div class="title-text">当前环节:</div>
<div class="title-line">
{{ huanjiesMap[bookInfo.nowStatus] || '--' }}
</div>
</div>
<template v-if="isRejected">
<div class="fl">
<div class="title-text">上传:</div>
<div class="title-line">
<div class="file-link" v-if="stepError.processUrl && stepError.processUrl.length">【审查意见表】</div>
<span v-else>--</span>
</div>
</div>
<div class="fl">
<div class="title-text">退稿意见:</div>
<div class="title-line">
<el-popover
v-if="stepError.opinion"
placement="top"
width="420"
trigger="hover"
popper-class="custom-popover"
>
<div class="review-content">{{ stepError.opinion }}</div>
<span slot="reference" class="file-link">查看全部</span>
</el-popover>
<span v-else>暂无内容</span>
</div>
</div>
</template>
</div>
<div class="step">
<el-steps :active="active" :process-status="processStatus">
<el-step
v-for="(step, index) in steps"
:key="index"
:title="step.approverStatusString"
>
<template slot="icon">
<img
:src="getStepIcon(step, index)"
class="step-icon"
/>
</template>
<template slot="description">
<div
class="step-description"
v-if="step.approverStatusString !== '完成' && index <= active"
>
<div class="step-operator">{{ step.approverName }}</div>
<div class="step-time">{{ step.approvalTimeString }}</div>
<div class="step-files">
<div class="review-section">
<span class="chuantext">审查意见:</span>
<el-popover
placement="top"
width="420"
trigger="hover"
popper-class="custom-popover"
v-if="step.opinion"
>
<div class="review-content">
{{ step.opinion }}
</div>
<span slot="reference" class="file-link">查看全部</span>
</el-popover>
<span class="empty-text" v-else>暂无内容</span>
</div>
<div class="upload-section">
<span class="chuantext">上传:</span>
<div class="file-list">
<template
v-if="
(step.processUrl && step.processUrl.length) ||
(step.sendVersionUrl && step.sendVersionUrl.length)
"
>
<template
v-if="step.processUrl && step.processUrl.length"
>
<div
v-for="(item, pIndex) in showFiles(
step.processUrl,
'process_' + index
)"
:key="'process_' + pIndex"
class="file-link"
>
【审查意见表】
</div>
</template>
<template
v-if="
step.sendVersionUrl && step.sendVersionUrl.length
"
>
<div
v-for="(item, sIndex) in showFiles(
step.sendVersionUrl,
'version_' + index
)"
:key="'version_' + sIndex"
class="file-link"
>
【发版意见表】
</div>
</template>
<div
v-if="
(step.processUrl && step.processUrl.length > 2) ||
(step.sendVersionUrl &&
step.sendVersionUrl.length > 2)
"
class="toggle-files"
@click="
toggleFiles('process_' + index)
toggleFiles('version_' + index)
"
>
{{
showAllFiles['process_' + index] ? '收起' : '展开'
}}
<i
:class="[
'el-icon-arrow-down',
{
'is-reverse': showAllFiles['process_' + index],
},
]"
></i>
</div>
</template>
<span class="empty-text" v-else>--</span>
</div>
</div>
</div>
</div>
</template>
</el-step>
</el-steps>
</div>

<div class="bookmsg">
<div class="info-item">
<div class="info-label">ISBN:</div>
<div class="info-value">{{ bookInfo.isbn }}</div>
</div>
<div class="info-item">
<div class="info-label">层次:</div>
<div class="info-value">{{ getOneClassTypeNames() }}</div>
</div>
<div class="info-item">
<div class="info-label">定价:</div>
<div class="info-value">{{ bookInfo.price }}</div>
</div>
<div class="info-item">
<div class="info-label">出版时间:</div>
<div class="info-value">{{ bookInfo.createTime }}</div>
</div>
</div>
</div>
<span slot="footer" class="dialogfooter">
<el-button @click="handleClose">取 消</el-button>
<el-button type="primary" @click="handleSubmit">确 定</el-button>
</span>
</el-dialog>
</template>

<script>
import { materialStatusMap, huanjiesMap } from '@/utils/status-tool.js'
import { queryMaterialProcess } from '@/api/index.js'

export default {
data() {
return {
dialogVisible: false,
materialStatusMap,
huanjiesMap,
bookInfo: {
materialName: '',
coverUrl: '',
chiefEditor: '',
status: '',
},
active: 0,
showAllFiles: {},
finishedIcon: require('@/assets/greenstep.png'),
processingIcon: require('@/assets/bluestep.png'),
defaultIcon: require('@/assets/huistep.png'),
errorIcon: require('@/assets/redstep.png'),
steps: [],
stepError: {},
statusColor: {
0: 'process',
1: 'finish ',
2: 'error ',
},
processStatus: 'process',
}
},
computed: {
isRejected() {
return this.bookInfo.status == 2 || this.bookInfo.nowStatus == 9;
}
},
methods: {
getOneClassTypeNames() {
const categoryList = this.bookInfo.pressMaterialCategoryList
if (!categoryList || !categoryList.length) {
return '--'
}

const typeNames = categoryList.map((item) => item.oneClassTypeName)
return typeNames.join('、')
},
show(row) {
this.dialogVisible = true
this.bookInfo = row
queryMaterialProcess({ materialId: row.id }).then((res) => {
if (res.status == 0) {
let arrayData = res.data
let currentIndex = 0
for (let i = 0; i < arrayData.length; i++) {
if (arrayData[i].nodeType == 9) {
this.stepError = arrayData.splice(i, 1)[0]
break
}
}
this.steps = arrayData
for (let i = 0; i < arrayData.length; i++) {
if (arrayData[i].status == 0 || arrayData[i].status == 2) {
currentIndex = i
break
}
}
this.active = currentIndex >= 0 ? currentIndex : 0
this.processStatus = this.statusColor[this.steps[currentIndex].status]
}
})
},
getStepIcon(step, index) {
if (step.status == 2) {
return this.errorIcon
}
if (index < this.active) {
return this.finishedIcon
}
if (index == this.active) {
return this.processingIcon
}
return this.defaultIcon
},
handleClose() {
this.dialogVisible = false
this.bookInfo = {
materialName: '',
coverUrl: '',
chiefEditor: '',
}
},
handleSubmit() {
this.dialogVisible = false
},
showFiles(files, index) {
if (!files) return []
if (this.showAllFiles[index]) {
return files
}
return files.slice(0, 2)
},
toggleFiles(index) {
this.$set(this.showAllFiles, index, !this.showAllFiles[index])
},
},
}
</script>

<style lang="scss" scoped>
.view-more {
color: #386cfc;
cursor: pointer;
margin-top: 8px;
font-size: 14px;
margin-left: 5px;
}
.bookinfo {
height: 164px;
padding: 12px;
margin-bottom: 20px;
background-color: #fafafa;
}
.bookimg {
width: 106px;
height: 140px;
border-radius: 4px 4px 4px 4px;
margin-left: 80px;
}
.bookmiddle {
padding-top: 20px;
}
.fl {
display: flex;
margin-bottom: 16px;
}
.lable {
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 16px;
color: #2e2f33;
min-width: 140px;
text-align: right;
}
.value {
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 16px;
color: #2e2f33;
}
.title {
display: flex;
text-align: center;
justify-content: flex-start;
width: 100%;

.fl {
display: flex;
margin-right: 60px;
}
.file-link {
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 14px;
color: #386cfc;
cursor: pointer;
}
}

.title-text {
font-size: 16px;
margin-right: 10px;
}

.title-line {
font-size: 16px;
color: #333;
}
.toggle-files {
color: #386cfc;
cursor: pointer;
margin-top: 8px;
font-size: 14px;
display: inline-flex;
align-items: center;

.el-icon-arrow-down {
margin-left: 4px;
transition: transform 0.3s;

&.is-reverse {
transform: rotate(180deg);
}
}
}
.review-content {
font-size: 14px;
line-height: 1.5;
color: #333;
word-break: break-all;
}
.bookmsg {
border-top: 1px solid #ebecf0;
border-bottom: 1px solid #ebecf0;
padding: 20px 4px;
display: flex;
}
.info-item {
display: flex;
min-width: 164px;
margin-right: 40px;
}
.info-label {
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 16px;
color: #2e2f33;
}
.info-value {
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 16px;
color: #2e2f33;
margin-left: 4px;
}
</style>
<style lang="scss">
.is-finish .el-step__line {
color: #23c240;
border-color: #23c240;
background-color: #23c240 !important;
}
</style>
<style lang="scss">

.recorddialog {
.el-dialog__title {
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 500;
font-size: 20px;
color: #2e2f33;
}
.el-dialog__close {
color: #333;
font-size: 24px;
}
border-radius: 8px;
.el-steps {
.el-step__head.is-finish {
color: #23c240;
border-color: #23c240;
}
.el-step.is-finish {
.el-step__line {
color: #23c240;
border-color: #23c240;
background-color: #23c240 !important;
}
}

.el-step__head.is-process {
color: #4080ff;
border-color: #4080ff;
}

.el-step__head.is-wait {
color: #cccccc;
border-color: #cccccc;
}

.el-step__line {
background-color: #cccccc;
}

.el-step__title {
font-size: 16px;
font-weight: 400;

&.is-finish {
color: #23c240;
}
&.is-process {
color: #4080ff;
}
&.is-wait {
color: #999;
}
}

.step-icon {
width: 24px;
height: 24px;
object-fit: contain;
}

.step-description {
font-size: 14px;
color: #666;
.step-operator {
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 500;
font-size: 16px;
color: #2e2f33;
}
.step-time {
margin: 8px 0;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 14px;
color: #8a8c89;
}

.step-files {
.chuantext {
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 14px;
color: #8a8c89;
}
.review-section,
.upload-section {
display: flex;
align-items: flex-start;
margin-bottom: 8px;
}
.file-link {
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 14px;
color: #386cfc;
cursor: pointer;
}
.file-list {
flex: 1;
}
}
}
}
}

.custom-popover {
background: #ffffff;
border-radius: 8px;
box-shadow: 0 0px 20px 0 rgba(0, 0, 0, 0.08);
border: 1px solid #ebeef5;
padding: 12px 16px 8px 16px;

.popper__arrow,
.popper__arrow::after {
position: absolute;
display: block;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
}

&[x-placement^='top'] {
margin-bottom: 12px;

.popper__arrow {
bottom: -16px;
left: 50%;
margin-right: 3px;
border-width: 16px 16px 0;
border-top-color: #ffffff;
}
}

.review-content {
font-size: 14px;
line-height: 1.6;
color: #333333;
word-break: break-all;
max-height: 200px;
overflow-y: auto;
padding-right: 5px;
&::-webkit-scrollbar {
width: 6px;
}

&::-webkit-scrollbar-thumb {
background: #cccccc;
border-radius: 3px;
}

&::-webkit-scrollbar-track {
background: #fafafa;
}
}
}
</style>

我想问下,show方法和getStepIcon方法有什么可以优化的地方吗 可以简化代码吗?还有哪些地方可以优化

Suy nghĩ

审查和优化

我正在全面审查Vue.js单文件组件的show方法和getStepIcon方法,目的是发现和建议代码简化或优化的可能性。

分析代码

我正在研究 show 方法和 getStepIcon 方法的代码,试图理解其逻辑和功能。

处理查询数据

我正在处理中,提取类别名称,处理步骤和状态,显示对话框或关闭对话框。

展示对话框

我正在处理显示对话框的方法,显示选定行的数据,并且查询与该数据相关的流程。这个过程中,我正在检测节点类型和状态,确定步骤和状态颜色。

设置和处理

我在做的是设置对话框、传递书籍信息,调用查询材料过程,处理响应数据。然后,迭代数据找到特定类型和状态的项目。最后,更新进度状态。

优化代码

我在思考利用数组方法而非for循环,是否能更简洁地处理show方法的代码,尤其是如何确保steps[currentIndex]在使用前已定义。

优化代码结构

我正在学习如何将旧的循环结构简化为更紧凑且易于理解的可读性,使用了 findIndex 方法来查找和定位符合条件的项。

我发现currentIndex初始化为0时,如果没有找到匹配的状态,currentIndex会保持为0。我在想是否可以将currentIndex初始化为-1,并且在循环后将this.active设置为currentIndex >= 0 ? currentIndex : 0

getStepIcon方法中,我注意到最后一个return比前几行的缩进多了一个层次。考虑是否可以使用switch case或对象映射来简化代码逻辑。

考虑方法简化

我正在查看getStepIcon方法的实现,尝试将条件映射到图标上,以便更简洁地呈现逻辑。

优化代码逻辑

在优化show方法时,主要是通过精简逻辑和提升代码可读性来减少代码量,同时保持功能完整性。

审视BookInfo属性

我在查看bookInfo的属性时发现它还包含status属性。考虑是否应该将bookInfo重置为初始状态以确保数据一致性。

优化代码结构

我正在分析 showFilestoggleFiles 方法,发现在 showFiles 方法中可以使用数组方法来简化代码。

代码审查正在确保所有变数有值

优化代码

现在我正在重新审视代码,发现可以减少冗长的for循环,通过应用Array方法如findIndex来简化代码,提升可读性和简洁性。

Trả lời

Certainly! Your show and getStepIcon methods can indeed be optimized for better readability and conciseness. Here are some suggestions:

1. Optimize the show Method

Current Implementation:

show(row) { this.dialogVisible = true; this.bookInfo = row; queryMaterialProcess({ materialId: row.id }).then((res) => { if (res.status == 0) { let arrayData = res.data; let currentIndex = 0; for (let i = 0; i < arrayData.length; i++) { if (arrayData[i].nodeType == 9) { this.stepError = arrayData.splice(i, 1)[0]; break; } } this.steps = arrayData; for (let i = 0; i < arrayData.length; i++) { if (arrayData[i].status == 0 || arrayData[i].status == 2) { currentIndex = i; break; } } this.active = currentIndex >= 0 ? currentIndex : 0; this.processStatus = this.statusColor[this.steps[currentIndex].status]; } }); },

Optimized Version:

show(row) { this.dialogVisible = true; this.bookInfo = row; queryMaterialProcess({ materialId: row.id }).then((res) => { if (res.status === 0) { let arrayData = res.data || []; // Extract the step with nodeType == 9 const errorIndex = arrayData.findIndex((item) => item.nodeType === 9); if (errorIndex >= 0) { this.stepError = arrayData.splice(errorIndex, 1)[0]; } this.steps = arrayData; // Find the current active step index const currentIndex = arrayData.findIndex( (item) => item.status === 0 || item.status === 2 ); this.active = currentIndex >= 0 ? currentIndex : 0; const currentStep = this.steps[this.active] || {}; this.processStatus = this.statusColor[currentStep.status] || 'process'; } }); },

Explanation:

  • Use Array Methods: Replace for loops with array methods like findIndex, which makes the code more concise and easier to read.
  • Handle Undefined Values: Use default values and optional chaining to prevent errors if steps[currentIndex] is undefined.
  • Consistent Equality Checks: Use === instead of == for strict equality checks, which is a good practice in JavaScript.

2. Simplify the getStepIcon Method

Current Implementation:

getStepIcon(step, index) { if (step.status == 2) { return this.errorIcon; } if (index < this.active) { return this.finishedIcon; } if (index == this.active) { return this.processingIcon; } return this.defaultIcon; },

Optimized Version:

getStepIcon(step, index) { if (step.status === 2) { return this.errorIcon; } else if (index < this.active) { return this.finishedIcon; } else if (index === this.active) { return this.processingIcon; } else { return this.defaultIcon; } },

Explanation:

  • Consistent Indentation: Ensure proper indentation for better readability.
  • Use else if Statements: This makes the logic flow clearer by indicating that only one of the conditions will be true.

3. Other Optimization Suggestions

  • Use Optional Chaining and Nullish Coalescing: In methods like getOneClassTypeNames, you can use optional chaining (?.) and nullish coalescing (??) to handle undefined or null values more gracefully.

    Optimized Method:

    getOneClassTypeNames() { const typeNames = this.bookInfo.pressMaterialCategoryList?.map( (item) => item.oneClassTypeName ); return typeNames?.length ? typeNames.join('、') : '--'; },
  • Handle Undefined Properties in handleClose: Ensure that all properties of bookInfo are reset when the dialog is closed.

    handleClose() { this.dialogVisible = false; this.bookInfo = { materialName: '', coverUrl: '', chiefEditor: '', status: '', // Include other properties as needed }; },
  • Use Destructuring for Cleaner Code: When dealing with objects, destructuring can make your code cleaner and more readable.

    queryMaterialProcess({ materialId: row.id }).then(({ status, data }) => { if (status === 0) { // Your code here } });
  • Error Handling: Add error handling for the API call to handle cases where the promise is rejected.

    queryMaterialProcess({ materialId: row.id }) .then((res) => { // Your existing code }) .catch((error) => { console.error('Error fetching material process:', error); // Handle the error as needed });

Summary

  • Use Modern JavaScript Features: Leveraging array methods like findIndex and map can simplify loops.
  • Maintain Consistent Coding Practices: Use strict equality checks (===), consistent indentation, and clear conditionals.
  • Enhance Readability: Simplify methods where possible, and use comments if necessary to explain complex logic.

By implementing these optimizations, your code will be more maintainable, readable, and efficient.

Chia sẻ Q&A này