질문

<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="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 || [];
// 查找并提取退稿节点(nodeType=9)的数据
// 存在退稿数据,从数组中移除并保存到stepError中
const errorIndex = arrayData.findIndex((item) => item.nodeType == 9);
if (errorIndex >= 0) {
this.stepError = arrayData.splice(errorIndex, 1)[0];
}

this.steps = arrayData;

// 查找当前激活的步骤索引
// status=0表示进行中,status=2表示退稿
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';
}
});
},
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: '',
status: '',
}
},
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>
有个问题,我的审核状态是草稿的时候,步骤条不能有任何状态,并且全都是灰色的呀。

사고

审阅状态变化

用户提到,当审阅状态为草稿时,步骤条(el-steps 组件)应该全都变灰,且无任何状态信息。这让我想到审阅进度的清晰度和步骤的可见性。

代码审查状态影响审查进度显示

检查代码逻辑

我正在查看代码中的数据和方法,特别是 show 函数,它如何找到当前激活的步骤索引,并根据步骤状态设置流程状态。在模板中,activeprocessStatus 被传递给 el-steps 组件。

代码更新

我正在思考如何调整代码以便在状态为'draft'时将active设置为-1或null。这样,getStepIcon方法可以在确认了bookInfo.status为'draft'后相应调整图标。

探讨状态设定

我观察到,’draft' 状态应设置 active 为 null 或 undefined。这有助于在 'show' 方法中正确处理状态。而在 'getStepIcon' 方法中,相应调整状态可能更为合适。

답변

你好,针对你提出的问题,当审核状态为“草稿”时,步骤条不应显示任何状态,且全都是灰色的。

问题原因:

目前的代码逻辑在计算步骤条的 activeprocessStatus 时,没有针对“草稿”状态进行特殊处理,导致即使在草稿状态下,步骤条仍然会根据默认逻辑显示状态。

解决方案:

我们需要在计算 activeprocessStatus 时,判断当前的审核状态是否为“草稿”。如果是草稿状态,我们可以将 active 设置为 -1,并将 processStatus 设置为 'wait',这样步骤条就不会显示任何激活的步骤,且所有步骤都将以灰色显示。

具体修改如下:

  1. data 中添加草稿状态的常量:
export default { data() { return { // ... 其他数据 DRAFT_STATUS: 0, // 假设草稿状态的值为0,请根据实际情况调整 } }, // ... 其他代码 }
  1. show 方法中,添加对草稿状态的判断:
show(row) { this.dialogVisible = true; this.bookInfo = row; queryMaterialProcess({ materialId: row.id }).then((res) => { if (res.status == 0) { let arrayData = res.data || []; // ... 处理退稿节点的代码 this.steps = arrayData; // **新增的草稿状态判断** if (this.bookInfo.status == this.DRAFT_STATUS) { // 草稿状态,步骤条不显示激活步骤,全部为灰色 this.active = -1; this.processStatus = 'wait'; } else { // 非草稿状态,按照原有逻辑计算 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'; } } }); },
  1. 修改 getStepIcon 方法,处理 active-1 的情况:
getStepIcon(step, index) { if (this.active === -1) { // 草稿状态,所有步骤使用默认灰色图标 return this.defaultIcon; } if (step.status == 2) { return this.errorIcon; } if (index < this.active) { return this.finishedIcon; } if (index == this.active) { return this.processingIcon; } return this.defaultIcon; },
  1. 在样式中,确保 processStatus'wait' 时,步骤条显示为灰色:
/* 已有的样式,无需修改 */

注意事项:

  • 请确认草稿状态的 status 值,在代码中我假设为 0,如有不同请调整 DRAFT_STATUS 的值。
  • 以上修改确保当审核状态为草稿时,active-1processStatus'wait',步骤条不显示任何激活的步骤,且所有步骤都是灰色的。

总结:

通过在逻辑中添加对草稿状态的特殊处理,可以实现你期望的效果。当审核状态为草稿时,步骤条将不会有任何状态,全部显示为灰色。

希望以上解决方案能帮助到你,如有其他问题,欢迎继续讨论!

이 Q&A 공유하기