526 lines
16 KiB
Vue
526 lines
16 KiB
Vue
<template>
|
||
<div class="report-page">
|
||
<el-card>
|
||
<template #header>
|
||
<div class="card-header">
|
||
<div>
|
||
<span>报备管理</span>
|
||
<el-tag type="info" size="small" style="margin-left: 10px">
|
||
保护期:{{ protectDays }} 天
|
||
</el-tag>
|
||
</div>
|
||
<el-button type="primary" @click="handleAdd" v-if="!userStore.isAdmin">
|
||
<el-icon><Plus /></el-icon>
|
||
提交报备
|
||
</el-button>
|
||
</div>
|
||
</template>
|
||
|
||
<!-- 查询表单 -->
|
||
<el-form :inline="true" :model="queryForm" class="query-form">
|
||
<el-form-item label="客户名称">
|
||
<el-input v-model="queryForm.customerName" placeholder="请输入客户名称" clearable />
|
||
</el-form-item>
|
||
<el-form-item label="状态" style="width: 180px;">
|
||
<el-select v-model="queryForm.status" placeholder="请选择状态" clearable>
|
||
<el-option label="待审核" :value="0" />
|
||
<el-option label="已通过" :value="1" />
|
||
<el-option label="已驳回" :value="2" />
|
||
<el-option label="已失效" :value="3" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item>
|
||
<el-button type="primary" @click="handleQuery">
|
||
<el-icon><Search /></el-icon>
|
||
查询
|
||
</el-button>
|
||
<el-button @click="handleReset">重置</el-button>
|
||
</el-form-item>
|
||
</el-form>
|
||
|
||
<!-- 数据表格 -->
|
||
<el-table :data="tableData" border stripe v-loading="loading">
|
||
<el-table-column prop="dealerName" label="经销商" />
|
||
<el-table-column prop="customerName" label="客户名称" />
|
||
<el-table-column prop="customerPhone" label="联系电话" />
|
||
<el-table-column prop="description" label="报备说明" show-overflow-tooltip />
|
||
<el-table-column prop="status" label="状态">
|
||
<template #default="{ row }">
|
||
<el-tag v-if="row.status === 0" type="warning">待审核</el-tag>
|
||
<el-tag v-else-if="row.status === 1" type="success">已通过</el-tag>
|
||
<el-tag v-else-if="row.status === 2" type="danger">已驳回</el-tag>
|
||
<el-tag v-else type="info">已失效</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="protectEndDate" label="保护期截止" width="180">
|
||
<template #default="{ row }">
|
||
{{ formatDate(row.protectEndDate) }}
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="createdAt" label="创建时间" width="180" />
|
||
<el-table-column label="操作" width="250" fixed="right">
|
||
<template #default="{ row }">
|
||
<el-button link type="primary" @click="handleView(row)">查看</el-button>
|
||
<el-button
|
||
v-if="row.status === 1"
|
||
link
|
||
type="info"
|
||
@click="handleShowProgress(row)"
|
||
>
|
||
进展
|
||
</el-button>
|
||
<el-button
|
||
v-if="userStore.isAdmin && row.status === 0"
|
||
link
|
||
type="success"
|
||
@click="handleAudit(row)"
|
||
>
|
||
审核
|
||
</el-button>
|
||
<el-button
|
||
v-if="!userStore.isAdmin && row.status === 0"
|
||
link
|
||
type="danger"
|
||
@click="handleWithdraw(row)"
|
||
>
|
||
撤回
|
||
</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<!-- 分页 -->
|
||
<el-config-provider :locale="zhCn">
|
||
<el-pagination
|
||
v-model:current-page="queryForm.current"
|
||
v-model:page-size="queryForm.size"
|
||
:total="total"
|
||
:page-sizes="[10, 20, 50, 100]"
|
||
layout="total, sizes, prev, pager, next, jumper"
|
||
prev-text="上一页"
|
||
next-text="下一页"
|
||
@size-change="fetchData"
|
||
@current-change="fetchData"
|
||
style="margin-top: 20px; justify-content: flex-end"
|
||
/>
|
||
</el-config-provider>
|
||
</el-card>
|
||
|
||
<!-- 提交报备对话框 -->
|
||
<el-dialog v-model="dialogVisible" title="提交报备" width="600px" @close="handleDialogClose">
|
||
<el-form ref="formRef" :model="formData" :rules="rules" label-width="100px">
|
||
<el-form-item label="客户" prop="customerId">
|
||
<el-select
|
||
v-model="formData.customerId"
|
||
placeholder="请选择客户"
|
||
filterable
|
||
remote
|
||
:remote-method="searchCustomer"
|
||
:loading="searchLoading"
|
||
style="width: 100%"
|
||
>
|
||
<el-option
|
||
v-for="item in customerOptions"
|
||
:key="item.id"
|
||
:label="item.name"
|
||
:value="item.id"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="报备说明" prop="description">
|
||
<el-input
|
||
v-model="formData.description"
|
||
type="textarea"
|
||
:rows="4"
|
||
placeholder="请输入报备说明"
|
||
/>
|
||
</el-form-item>
|
||
</el-form>
|
||
<template #footer>
|
||
<el-button @click="dialogVisible = false">取消</el-button>
|
||
<el-button type="primary" @click="handleSubmit">提交</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
|
||
<!-- 审核对话框 -->
|
||
<el-dialog v-model="auditDialogVisible" title="审核报备" width="600px">
|
||
<el-form :model="auditForm" label-width="100px">
|
||
<el-form-item label="审核结果">
|
||
<el-radio-group v-model="auditForm.approved">
|
||
<el-radio :label="true">通过</el-radio>
|
||
<el-radio :label="false">驳回</el-radio>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
<el-form-item label="驳回原因" prop="rejectReason" v-if="!auditForm.approved">
|
||
<el-input
|
||
v-model="auditForm.rejectReason"
|
||
type="textarea"
|
||
:rows="4"
|
||
placeholder="请输入驳回原因"
|
||
/>
|
||
</el-form-item>
|
||
</el-form>
|
||
<template #footer>
|
||
<el-button @click="auditDialogVisible = false">取消</el-button>
|
||
<el-button type="primary" @click="handleAuditSubmit">确定</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
|
||
<!-- 进展记录对话框 -->
|
||
<el-dialog v-model="progressDialogVisible" title="报备进展记录" width="1000px" @close="handleProgressDialogClose">
|
||
<el-card>
|
||
<template #header>
|
||
<div class="card-header">
|
||
<span>添加进展记录</span>
|
||
</div>
|
||
</template>
|
||
<el-form ref="progressFormRef" :model="progressFormData" :rules="progressRules" label-width="100px">
|
||
<el-form-item label="进展内容" prop="progressContent">
|
||
<el-input
|
||
v-model="progressFormData.progressContent"
|
||
type="textarea"
|
||
:rows="4"
|
||
placeholder="请输入进展内容"
|
||
/>
|
||
</el-form-item>
|
||
</el-form>
|
||
<template #footer>
|
||
<el-button v-if="editingProgressId" @click="handleCancelEdit">取消编辑</el-button>
|
||
<el-button type="primary" @click="handleSaveProgress">{{ editingProgressId ? '保存修改' : '添加' }}</el-button>
|
||
</template>
|
||
</el-card>
|
||
|
||
<el-divider content-position="left">进展记录列表</el-divider>
|
||
|
||
<el-table :data="progressList" border stripe v-loading="progressLoading">
|
||
<el-table-column prop="progressContent" label="进展内容" show-overflow-tooltip />
|
||
<el-table-column prop="createdAt" label="创建时间" width="180" />
|
||
<el-table-column prop="updatedAt" label="更新时间" width="180" />
|
||
<el-table-column label="操作" width="150" fixed="right">
|
||
<template #default="{ row }">
|
||
<el-button
|
||
v-if="!userStore.isAdmin"
|
||
link
|
||
type="primary"
|
||
@click="handleEditProgress(row)"
|
||
>
|
||
编辑
|
||
</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, reactive, onMounted } from 'vue'
|
||
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'element-plus'
|
||
import { useUserStore } from '@/stores/user'
|
||
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
|
||
import { getReportPage, createReport, auditReport, withdrawReport } from '@/api/report'
|
||
import { getProgressByReportId, createProgress, updateProgress } from '@/api/report-progress'
|
||
import { searchCustomerByName } from '@/api/customer'
|
||
import { getConfigValue } from '@/api/system'
|
||
import type { Report, ReportForm, ReportProgress, ReportProgressForm } from '@/types'
|
||
|
||
const userStore = useUserStore()
|
||
|
||
const protectDays = ref<number>(90)
|
||
|
||
const loading = ref(false)
|
||
const tableData = ref<Report[]>([])
|
||
const total = ref(0)
|
||
const dialogVisible = ref(false)
|
||
const auditDialogVisible = ref(false)
|
||
const auditReportId = ref<number>()
|
||
const formRef = ref<FormInstance>()
|
||
const searchLoading = ref(false)
|
||
const customerOptions = ref<Array<{ id: number; name: string }>>([])
|
||
|
||
// 进展记录相关
|
||
const progressDialogVisible = ref(false)
|
||
const progressFormRef = ref<FormInstance>()
|
||
const progressFormData = reactive<ReportProgressForm>({
|
||
reportId: 0,
|
||
progressContent: ''
|
||
})
|
||
const progressList = ref<ReportProgress[]>([])
|
||
const editingProgressId = ref<number | undefined>()
|
||
const progressLoading = ref(false)
|
||
|
||
const progressRules: FormRules = {
|
||
progressContent: [{ required: true, message: '请输入进展内容', trigger: 'blur' }]
|
||
}
|
||
|
||
const queryForm = reactive({
|
||
current: 1,
|
||
size: 10,
|
||
customerName: '',
|
||
status: undefined as number | undefined
|
||
})
|
||
|
||
const formData = reactive<ReportForm>({
|
||
customerId: null,
|
||
description: ''
|
||
})
|
||
|
||
const auditForm = reactive({
|
||
approved: true,
|
||
rejectReason: ''
|
||
})
|
||
|
||
const rules: FormRules = {
|
||
customerId: [{ required: true, message: '请选择客户', trigger: 'change' }]
|
||
}
|
||
|
||
// 格式化日期,去掉时分秒
|
||
const formatDate = (dateStr: string | null | undefined) => {
|
||
if (!dateStr) return '-'
|
||
return dateStr.split(' ')[0] // 只保留日期部分,去掉时间
|
||
}
|
||
|
||
// 显示进展记录对话框
|
||
const handleShowProgress = async (row: Report) => {
|
||
progressFormData.reportId = row.id
|
||
progressFormData.progressContent = ''
|
||
editingProgressId.value = undefined
|
||
await fetchProgressList(row.id)
|
||
progressDialogVisible.value = true
|
||
}
|
||
|
||
// 获取进展记录列表
|
||
const fetchProgressList = async (reportId: number) => {
|
||
progressLoading.value = true
|
||
try {
|
||
const res = await getProgressByReportId(reportId)
|
||
progressList.value = res
|
||
} catch (error) {
|
||
console.error('获取进展记录失败', error)
|
||
progressList.value = []
|
||
} finally {
|
||
progressLoading.value = false
|
||
}
|
||
}
|
||
|
||
// 保存进展记录
|
||
const handleSaveProgress = async () => {
|
||
if (!progressFormRef.value) return
|
||
await progressFormRef.value.validate(async (valid) => {
|
||
if (valid) {
|
||
try {
|
||
if (editingProgressId.value) {
|
||
// 编辑模式
|
||
await updateProgress(editingProgressId.value, progressFormData)
|
||
ElMessage.success('更新成功')
|
||
} else {
|
||
// 新增模式
|
||
await createProgress(progressFormData)
|
||
ElMessage.success('添加成功')
|
||
}
|
||
// 重新获取进展记录列表
|
||
await fetchProgressList(progressFormData.reportId)
|
||
// 重置表单
|
||
progressFormData.progressContent = ''
|
||
editingProgressId.value = undefined
|
||
} catch (error) {
|
||
console.error('保存进展记录失败', error)
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
// 编辑进展记录
|
||
const handleEditProgress = (row: ReportProgress) => {
|
||
editingProgressId.value = row.id
|
||
progressFormData.progressContent = row.progressContent
|
||
}
|
||
|
||
// 取消编辑
|
||
const handleCancelEdit = () => {
|
||
editingProgressId.value = undefined
|
||
progressFormData.progressContent = ''
|
||
}
|
||
|
||
// 关闭进展记录对话框
|
||
const handleProgressDialogClose = () => {
|
||
progressDialogVisible.value = false
|
||
progressFormRef.value?.resetFields()
|
||
progressFormData.progressContent = ''
|
||
editingProgressId.value = undefined
|
||
progressList.value = []
|
||
}
|
||
|
||
// 查询数据
|
||
const fetchData = async () => {
|
||
loading.value = true
|
||
try {
|
||
const res = await getReportPage(queryForm)
|
||
tableData.value = res.records
|
||
total.value = res.total
|
||
} catch (error) {
|
||
console.error('查询失败', error)
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
// 搜索客户
|
||
const searchCustomer = async (query: string) => {
|
||
if (!query) return
|
||
searchLoading.value = true
|
||
try {
|
||
const res = await searchCustomerByName(query)
|
||
customerOptions.value = res
|
||
} catch (error) {
|
||
console.error('搜索客户失败', error)
|
||
} finally {
|
||
searchLoading.value = false
|
||
}
|
||
}
|
||
|
||
// 查询按钮
|
||
const handleQuery = () => {
|
||
queryForm.current = 1
|
||
fetchData()
|
||
}
|
||
|
||
// 重置按钮
|
||
const handleReset = () => {
|
||
queryForm.customerName = ''
|
||
queryForm.status = undefined
|
||
queryForm.current = 1
|
||
fetchData()
|
||
}
|
||
|
||
// 新增按钮
|
||
const handleAdd = () => {
|
||
dialogVisible.value = true
|
||
}
|
||
|
||
// 查看详情
|
||
const handleView = (row: Report) => {
|
||
ElMessageBox.alert(
|
||
`
|
||
<div style="line-height: 2;">
|
||
<p><strong>经销商:</strong>${row.dealerName}</p>
|
||
<p><strong>客户名称:</strong>${row.customerName}</p>
|
||
<p><strong>联系电话:</strong>${row.customerPhone || '-'}</p>
|
||
<p><strong>报备说明:</strong>${row.description || '-'}</p>
|
||
<p><strong>状态:</strong>${row.statusDesc}</p>
|
||
<p><strong>驳回原因:</strong>${row.rejectReason || '-'}</p>
|
||
<p><strong>保护期:</strong>${formatDate(row.protectStartDate)} ~ ${formatDate(row.protectEndDate)}</p>
|
||
</div>
|
||
`,
|
||
'报备详情',
|
||
{
|
||
dangerouslyUseHTMLString: true,
|
||
confirmButtonText: '关闭'
|
||
}
|
||
)
|
||
}
|
||
|
||
// 审核按钮
|
||
const handleAudit = (row: Report) => {
|
||
auditReportId.value = row.id
|
||
auditForm.approved = true
|
||
auditForm.rejectReason = ''
|
||
auditDialogVisible.value = true
|
||
}
|
||
|
||
// 撤回按钮
|
||
const handleWithdraw = async (row: Report) => {
|
||
try {
|
||
await ElMessageBox.confirm(
|
||
'确定要撤回该报备吗?',
|
||
'提示',
|
||
{
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}
|
||
)
|
||
await withdrawReport(row.id)
|
||
ElMessage.success('撤回成功')
|
||
fetchData()
|
||
} catch (error) {
|
||
// 取消撤回
|
||
}
|
||
}
|
||
|
||
// 提交报备
|
||
const handleSubmit = async () => {
|
||
if (!formRef.value) return
|
||
await formRef.value.validate(async (valid) => {
|
||
if (valid) {
|
||
try {
|
||
await createReport(formData)
|
||
ElMessage.success('提交成功')
|
||
dialogVisible.value = false
|
||
fetchData()
|
||
} catch (error) {
|
||
console.error('提交失败', error)
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
// 审核提交
|
||
const handleAuditSubmit = async () => {
|
||
if (!auditReportId.value) return
|
||
if (!auditForm.approved && !auditForm.rejectReason) {
|
||
ElMessage.warning('请输入驳回原因')
|
||
return
|
||
}
|
||
try {
|
||
await auditReport(auditReportId.value, auditForm)
|
||
ElMessage.success('审核成功')
|
||
auditDialogVisible.value = false
|
||
fetchData()
|
||
} catch (error) {
|
||
console.error('审核失败', error)
|
||
}
|
||
}
|
||
|
||
// 对话框关闭
|
||
const handleDialogClose = () => {
|
||
formRef.value?.resetFields()
|
||
Object.assign(formData, {
|
||
customerId: null,
|
||
description: ''
|
||
})
|
||
customerOptions.value = []
|
||
}
|
||
|
||
// 获取保护期配置
|
||
const fetchProtectDays = async () => {
|
||
try {
|
||
const res = await getConfigValue('report.protect.days')
|
||
protectDays.value = parseInt(res) || 90
|
||
} catch (error) {
|
||
console.error('获取配置失败', error)
|
||
}
|
||
}
|
||
|
||
onMounted(() => {
|
||
fetchProtectDays()
|
||
fetchData()
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
.report-page {
|
||
width: 100%;
|
||
}
|
||
|
||
.card-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.query-form {
|
||
margin-bottom: 20px;
|
||
}
|
||
</style>
|