fix(review-meeting): 优化会议附件卡片样式并防止重复提交
- 优化卡片布局为现代风格,支持长文件名完整显示 - 添加 isSubmitting 状态防止快速连续点击导致重复创建会议 - 按钮在提交中禁用并显示"提交中..."文字 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>pull/874/head
parent
b3eaefc511
commit
9b94f733ba
|
|
@ -187,10 +187,10 @@
|
||||||
v-if="!isView"
|
v-if="!isView"
|
||||||
type="button"
|
type="button"
|
||||||
class="btn-primary"
|
class="btn-primary"
|
||||||
:disabled="formLoading"
|
:disabled="formLoading || isSubmitting"
|
||||||
@click="submitForm"
|
@click="submitForm"
|
||||||
>
|
>
|
||||||
{{ formLoading ? '提交中...' : '提交' }}
|
{{ formLoading || isSubmitting ? '提交中...' : '提交' }}
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn-default" @click="handleBack">返回</button>
|
<button type="button" class="btn-default" @click="handleBack">返回</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -239,8 +239,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button type="primary" :disabled="agendaDialogLoading" @click="handleDialogConfirm">
|
<el-button type="primary" :disabled="agendaDialogLoading || isSubmitting" @click="handleDialogConfirm">
|
||||||
确定
|
{{ agendaDialogLoading || isSubmitting ? '提交中...' : '确定' }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
@ -291,6 +291,7 @@ const formLoading = ref(false)
|
||||||
const expertOptions = ref<any[]>([])
|
const expertOptions = ref<any[]>([])
|
||||||
const isProjectsModified = ref(false)
|
const isProjectsModified = ref(false)
|
||||||
const meetingLocationOptions = ['东5楼326', '南6楼203', '南6楼207']
|
const meetingLocationOptions = ['东5楼326', '南6楼203', '南6楼207']
|
||||||
|
const isSubmitting = ref(false) // 防止重复提交
|
||||||
|
|
||||||
// 上传会议附件弹窗
|
// 上传会议附件弹窗
|
||||||
const agendaDialogVisible = ref(false)
|
const agendaDialogVisible = ref(false)
|
||||||
|
|
@ -619,7 +620,7 @@ const buildAgendaGenerateData = (): ReviewMeetingAgendaGenerateReqVO | undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
const submitForm = async () => {
|
const submitForm = async () => {
|
||||||
if (formLoading.value) return
|
if (formLoading.value || isSubmitting.value) return
|
||||||
const valid = await formRef.value?.validate().catch(() => false)
|
const valid = await formRef.value?.validate().catch(() => false)
|
||||||
if (!valid) return
|
if (!valid) return
|
||||||
if (formData.meetingTimeRange?.length === 2) {
|
if (formData.meetingTimeRange?.length === 2) {
|
||||||
|
|
@ -628,6 +629,7 @@ const submitForm = async () => {
|
||||||
}
|
}
|
||||||
// 编辑模式且有议程附件:直接保存
|
// 编辑模式且有议程附件:直接保存
|
||||||
if (isEdit.value && formData.agendaAttachmentUrl) {
|
if (isEdit.value && formData.agendaAttachmentUrl) {
|
||||||
|
isSubmitting.value = true
|
||||||
formLoading.value = true
|
formLoading.value = true
|
||||||
try {
|
try {
|
||||||
const projects = buildScheduledProjects()
|
const projects = buildScheduledProjects()
|
||||||
|
|
@ -658,6 +660,7 @@ const submitForm = async () => {
|
||||||
router.push({ name: 'ReviewMeeting' })
|
router.push({ name: 'ReviewMeeting' })
|
||||||
} finally {
|
} finally {
|
||||||
formLoading.value = false
|
formLoading.value = false
|
||||||
|
isSubmitting.value = false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 新建模式或编辑模式下议程附件为空:弹出上传议程附件弹窗
|
// 新建模式或编辑模式下议程附件为空:弹出上传议程附件弹窗
|
||||||
|
|
@ -711,10 +714,12 @@ const handleDialogGenerateAgenda = async () => {
|
||||||
|
|
||||||
// 弹窗确定按钮 - 真正保存草稿
|
// 弹窗确定按钮 - 真正保存草稿
|
||||||
const handleDialogConfirm = async () => {
|
const handleDialogConfirm = async () => {
|
||||||
|
if (agendaDialogLoading.value || isSubmitting.value) return
|
||||||
if (!formData.agendaAttachmentUrl) {
|
if (!formData.agendaAttachmentUrl) {
|
||||||
ElMessage.warning('请上传或生成议程附件')
|
ElMessage.warning('请上传或生成议程附件')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
isSubmitting.value = true
|
||||||
agendaDialogLoading.value = true
|
agendaDialogLoading.value = true
|
||||||
try {
|
try {
|
||||||
const projects = buildScheduledProjects()
|
const projects = buildScheduledProjects()
|
||||||
|
|
@ -736,6 +741,7 @@ const handleDialogConfirm = async () => {
|
||||||
router.push({ name: 'ReviewMeeting' })
|
router.push({ name: 'ReviewMeeting' })
|
||||||
} finally {
|
} finally {
|
||||||
agendaDialogLoading.value = false
|
agendaDialogLoading.value = false
|
||||||
|
isSubmitting.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1031,38 +1037,87 @@ const handleBack = () => {
|
||||||
.attachment-cards {
|
.attachment-cards {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
.attachment-card {
|
.attachment-card {
|
||||||
flex: 1;
|
background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
|
||||||
background-color: #fff;
|
border: 1px solid #e8eaef;
|
||||||
border: 1px solid #e1e7f0;
|
border-radius: 8px;
|
||||||
border-radius: 4px;
|
padding: 12px 14px;
|
||||||
overflow: hidden;
|
min-width: 320px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
.attachment-card:hover {
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||||
|
border-color: #d0d4dc;
|
||||||
}
|
}
|
||||||
.attachment-card-header {
|
.attachment-card-header {
|
||||||
padding: 1px 6px;
|
display: flex;
|
||||||
background-color: #f5f7fa;
|
align-items: center;
|
||||||
border-bottom: 1px solid #e1e7f0;
|
gap: 6px;
|
||||||
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
.attachment-card-title {
|
.attachment-card-title {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #333;
|
color: #6b7280;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
}
|
}
|
||||||
.attachment-card-body {
|
.attachment-card-body {
|
||||||
padding: 2px 6px;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
}
|
}
|
||||||
.attachment-file-info {
|
.attachment-file-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 4px;
|
gap: 8px;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.attachment-file-info .el-link {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #3b82f6;
|
||||||
|
font-weight: 500;
|
||||||
|
word-break: break-all;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 100px;
|
||||||
|
}
|
||||||
|
.attachment-file-info .el-link:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.attachment-file-info .el-tag {
|
||||||
|
background-color: #eef2ff;
|
||||||
|
color: #6366f1;
|
||||||
|
border-color: #e0e7ff;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.attachment-file-info .el-text {
|
||||||
|
color: #9ca3af;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.attachment-file-info .el-button {
|
||||||
|
color: #ef4444;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.attachment-file-info .el-button:hover {
|
||||||
|
color: #dc2626;
|
||||||
}
|
}
|
||||||
.minutes-ai-line {
|
.minutes-ai-line {
|
||||||
margin-top: 2px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 4px;
|
gap: 6px;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
padding-top: 4px;
|
||||||
|
border-top: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
.minutes-ai-line .el-tag {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.minutes-ai-line .el-text {
|
||||||
|
color: #9ca3af;
|
||||||
|
font-size: 11px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue