后端优化报销单访问策略和常量定义,增强退回原因和审批状态 流转,前端完善退回对话框和审批交互组件,新增报销申请关联 模型,优化文档中心行数据和审批收件箱工具函数,增强引导 流程和会话模型,补充单元测试覆盖。
152 lines
3.7 KiB
Vue
152 lines
3.7 KiB
Vue
<template>
|
|
<ConfirmDialog
|
|
:open="open"
|
|
:badge="badge"
|
|
badge-tone="info"
|
|
:title="title"
|
|
:description="description"
|
|
cancel-text="返回核对"
|
|
:confirm-text="confirmText"
|
|
:busy-text="busyText"
|
|
confirm-tone="primary"
|
|
confirm-icon="mdi mdi-check-circle-outline"
|
|
:busy="busy"
|
|
@close="emit('close')"
|
|
@confirm="emit('confirm')"
|
|
>
|
|
<div class="submit-confirm-summary" aria-label="领导审批通过摘要">
|
|
<div class="submit-confirm-row">
|
|
<span>单据编号</span>
|
|
<strong>{{ documentNo }}</strong>
|
|
</div>
|
|
<div class="submit-confirm-row">
|
|
<span>当前节点</span>
|
|
<strong>{{ node }}</strong>
|
|
</div>
|
|
<div class="submit-confirm-row">
|
|
<span>{{ summaryLabel }}</span>
|
|
<strong>{{ nextStage }}</strong>
|
|
</div>
|
|
</div>
|
|
|
|
<label class="approval-opinion-field">
|
|
<span>
|
|
{{ opinionTitle }}
|
|
<em v-if="opinionRequired">必填</em>
|
|
</span>
|
|
<textarea
|
|
:value="currentOpinion"
|
|
maxlength="500"
|
|
:required="opinionRequired"
|
|
:disabled="busy"
|
|
:placeholder="opinionPlaceholder"
|
|
:aria-label="opinionTitle"
|
|
@input="handleOpinionInput"
|
|
></textarea>
|
|
<small>
|
|
<span>{{ opinionHint }}</span>
|
|
<strong>{{ currentOpinion.length }}/500</strong>
|
|
</small>
|
|
</label>
|
|
</ConfirmDialog>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { computed } from 'vue'
|
|
|
|
import ConfirmDialog from '../shared/ConfirmDialog.vue'
|
|
|
|
const props = defineProps({
|
|
open: { type: Boolean, required: true },
|
|
badge: { type: String, required: true },
|
|
title: { type: String, required: true },
|
|
description: { type: String, required: true },
|
|
confirmText: { type: String, required: true },
|
|
busyText: { type: String, required: true },
|
|
busy: { type: Boolean, required: true },
|
|
documentNo: { type: [String, Number], required: true },
|
|
node: { type: String, default: '' },
|
|
summaryLabel: { type: String, required: true },
|
|
nextStage: { type: String, required: true },
|
|
opinionTitle: { type: String, required: true },
|
|
opinion: { type: String, default: '' },
|
|
opinionPlaceholder: { type: String, default: '' },
|
|
opinionHint: { type: String, default: '' },
|
|
opinionRequired: { type: Boolean, default: false }
|
|
})
|
|
|
|
const emit = defineEmits(['close', 'confirm', 'update:opinion'])
|
|
|
|
const currentOpinion = computed(() => String(props.opinion || ''))
|
|
|
|
function handleOpinionInput(event) {
|
|
emit('update:opinion', event.target.value)
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.approval-opinion-field {
|
|
display: grid;
|
|
gap: 8px;
|
|
margin-top: 14px;
|
|
}
|
|
|
|
.approval-opinion-field > span {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
color: #334155;
|
|
font-size: 12px;
|
|
font-weight: 850;
|
|
}
|
|
|
|
.approval-opinion-field em {
|
|
border-radius: 999px;
|
|
padding: 2px 7px;
|
|
background: rgba(var(--theme-primary-rgb), .1);
|
|
color: var(--theme-primary-active);
|
|
font-style: normal;
|
|
font-size: 11px;
|
|
font-weight: 850;
|
|
}
|
|
|
|
.approval-opinion-field textarea {
|
|
width: 100%;
|
|
min-height: 96px;
|
|
resize: vertical;
|
|
padding: 12px;
|
|
border: 1px solid #d7e0ea;
|
|
border-radius: 8px;
|
|
background: #fff;
|
|
color: #0f172a;
|
|
font-size: 13px;
|
|
line-height: 1.6;
|
|
outline: none;
|
|
}
|
|
|
|
.approval-opinion-field textarea:focus {
|
|
border-color: rgba(var(--theme-primary-rgb), .5);
|
|
box-shadow: 0 0 0 3px var(--theme-focus-ring);
|
|
}
|
|
|
|
.approval-opinion-field small {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 12px;
|
|
color: #64748b;
|
|
font-size: 12px;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.approval-opinion-field small span {
|
|
min-width: 0;
|
|
}
|
|
|
|
.approval-opinion-field small strong {
|
|
flex: 0 0 auto;
|
|
color: var(--theme-primary-active);
|
|
font-weight: 850;
|
|
}
|
|
</style>
|