This commit is contained in:
wangjiming
2026-08-03 09:34:08 +08:00
parent b975de02da
commit 15c4223f2c
43 changed files with 4498 additions and 234 deletions

View File

@@ -0,0 +1,128 @@
<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue'
import { ElMessage } from 'element-plus'
import DataTablePage from '@/components/DataTablePage.vue'
import { getApprovalInstances, decideApproval, type ApprovalInstance } from '@/api/modules/approval'
import { getUsers, type SystemUser } from '@/api/modules/system'
const loading = ref(false)
const instances = ref<ApprovalInstance[]>([])
const users = ref<SystemUser[]>([])
const statusFilter = ref<string | undefined>(undefined)
const showDecide = ref(false)
const current = ref<ApprovalInstance | null>(null)
const decision = ref({ step_index: 0, approver_id: '', approved: true, comment: '' })
const statusOptions = [
{ label: '待审批', value: 'pending' },
{ label: '已通过', value: 'approved' },
{ label: '已拒绝', value: 'rejected' },
]
async function load() {
loading.value = true
try {
instances.value = await getApprovalInstances(statusFilter.value)
} finally {
loading.value = false
}
}
async function loadUsers() {
try {
users.value = await getUsers()
} catch {
users.value = []
}
}
function userName(id?: string) {
if (!id) return '—'
return users.value.find((u) => u.id === id)?.username || id
}
function openDecide(inst: ApprovalInstance) {
current.value = inst
const step = inst.steps.find((s) => s.status === 'pending')
decision.value = { step_index: step ? step.step_index : 0, approver_id: '', approved: true, comment: '' }
showDecide.value = true
}
async function submitDecision() {
if (!current.value) return
if (!decision.value.approver_id) {
ElMessage.warning('请选择审批人')
return
}
await decideApproval(current.value.id, decision.value.step_index, {
approver_id: decision.value.approver_id,
approved: decision.value.approved,
comment: decision.value.comment,
})
ElMessage.success('审批已提交')
showDecide.value = false
load()
}
onMounted(() => {
loadUsers()
load()
})
</script>
<template>
<div class="page">
<DataTablePage title="审批实例" :data="instances" :loading="loading" searchable search-fields="resource_type,resource_id">
<template #toolbar-extra>
<el-select v-model="statusFilter" placeholder="状态" clearable style="width: 140px" @change="load">
<el-option v-for="s in statusOptions" :key="s.value" :label="s.label" :value="s.value" />
</el-select>
</template>
<template #columns>
<el-table-column prop="resource_type" label="资源类型" min-width="120" />
<el-table-column prop="resource_id" label="资源 ID" min-width="160" show-overflow-tooltip />
<el-table-column prop="applicant_id" label="申请人" min-width="120">
<template #default="{ row }">{{ userName(row.applicant_id) }}</template>
</el-table-column>
<el-table-column prop="status" label="状态" min-width="100" />
<el-table-column prop="current_step" label="当前步骤" min-width="100" />
<el-table-column prop="create_time" label="创建时间" min-width="180" />
</template>
<template #actions="{ row }">
<el-button v-if="row.status === 'pending'" link type="primary" @click="openDecide(row)">审批</el-button>
</template>
</DataTablePage>
<el-dialog v-model="showDecide" title="审批决策" width="480px">
<el-form label-width="80px" v-if="current">
<el-form-item label="实例">
{{ current.resource_type }} / {{ current.resource_id }}
</el-form-item>
<el-form-item label="步骤">
{{ decision.step_index + 1 }}
</el-form-item>
<el-form-item label="审批人" required>
<el-select v-model="decision.approver_id" filterable style="width: 100%">
<el-option v-for="u in users" :key="u.id" :label="u.username" :value="u.id" />
</el-select>
</el-form-item>
<el-form-item label="结果">
<el-radio-group v-model="decision.approved">
<el-radio :value="true">通过</el-radio>
<el-radio :value="false">拒绝</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="意见">
<el-input v-model="decision.comment" type="textarea" :rows="3" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="showDecide = false">取消</el-button>
<el-button type="primary" @click="submitDecision">提交</el-button>
</template>
</el-dialog>
</div>
</template>
<style scoped lang="scss">
.page { padding: 16px; }
</style>