feat: 新增估值管理模块和审核列表功能
- 新增估值管理一级菜单目录 - 新增审核列表二级菜单 - 实现审核列表页面,支持查看详情和审核操作 - 添加估值评估相关API接口定义 - 支持审核通过和拒绝操作
This commit is contained in:
parent
082b9b7902
commit
e062fc6607
24
docs/sql/add_valuation_menu.sql
Normal file
24
docs/sql/add_valuation_menu.sql
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
-- 新增估值管理菜单
|
||||||
|
-- 创建时间: 2025-11-13
|
||||||
|
|
||||||
|
-- 插入一级目录:估值管理
|
||||||
|
INSERT INTO menu (id, name, menu_type, icon, path, 'order', parent_id, is_hidden, component, keepalive, redirect, created_at, updated_at)
|
||||||
|
VALUES
|
||||||
|
(18, '估值管理', 'catalog', 'carbon:calculator', '/valuation', 4, 0, 0, 'Layout', 0, '/valuation/audit', datetime('now'), datetime('now'));
|
||||||
|
|
||||||
|
-- 插入二级菜单:审核列表
|
||||||
|
INSERT INTO menu (id, name, menu_type, icon, path, 'order', parent_id, is_hidden, component, keepalive, redirect, created_at, updated_at)
|
||||||
|
VALUES
|
||||||
|
(19, '审核列表', 'menu', 'carbon:task-approved', 'audit', 1, 18, 0, '/valuation/audit', 0, NULL, datetime('now'), datetime('now'));
|
||||||
|
|
||||||
|
-- 为管理员角色分配菜单权限
|
||||||
|
INSERT INTO role_menu (role_id, menu_id)
|
||||||
|
VALUES
|
||||||
|
(1, 18),
|
||||||
|
(1, 19);
|
||||||
|
|
||||||
|
-- 为普通用户角色分配菜单权限
|
||||||
|
INSERT INTO role_menu (role_id, menu_id)
|
||||||
|
VALUES
|
||||||
|
(2, 18),
|
||||||
|
(2, 19);
|
||||||
@ -53,4 +53,13 @@ export default {
|
|||||||
deleteInvoice: (params = {}) => request.delete('/invoice/delete', { params }),
|
deleteInvoice: (params = {}) => request.delete('/invoice/delete', { params }),
|
||||||
updateInvoiceStatus: (data = {}) => request.post('/invoice/update-status', data),
|
updateInvoiceStatus: (data = {}) => request.post('/invoice/update-status', data),
|
||||||
remindInvoice: (data = {}) => request.post('/invoice/remind', data),
|
remindInvoice: (data = {}) => request.post('/invoice/remind', data),
|
||||||
|
// valuation (估值评估)
|
||||||
|
getValuationList: (params = {}) => request.get('/valuation', { params }),
|
||||||
|
getValuationById: (params = {}) => request.get(`/valuation/${params.valuation_id}`),
|
||||||
|
createValuation: (data = {}) => request.post('/valuation', data),
|
||||||
|
updateValuation: (data = {}) => request.put(`/valuation/${data.id}`, data),
|
||||||
|
deleteValuation: (params = {}) => request.delete(`/valuation/${params.valuation_id}`),
|
||||||
|
approveValuation: (data = {}) => request.post(`/valuation/${data.valuation_id}/approve`, data),
|
||||||
|
rejectValuation: (data = {}) => request.post(`/valuation/${data.valuation_id}/reject`, data),
|
||||||
|
updateValuationNotes: (data = {}) => request.put(`/valuation/${data.valuation_id}/admin-notes`, data),
|
||||||
}
|
}
|
||||||
|
|||||||
394
web/src/views/valuation/audit/index.vue
Normal file
394
web/src/views/valuation/audit/index.vue
Normal file
@ -0,0 +1,394 @@
|
|||||||
|
<script setup>
|
||||||
|
import { h, onMounted, ref, resolveDirective, withDirectives } from 'vue'
|
||||||
|
import {
|
||||||
|
NButton,
|
||||||
|
NForm,
|
||||||
|
NFormItem,
|
||||||
|
NInput,
|
||||||
|
NTag,
|
||||||
|
NPopconfirm,
|
||||||
|
NSelect,
|
||||||
|
NDatePicker,
|
||||||
|
NInputNumber,
|
||||||
|
NSpace,
|
||||||
|
} from 'naive-ui'
|
||||||
|
|
||||||
|
import CommonPage from '@/components/page/CommonPage.vue'
|
||||||
|
import QueryBarItem from '@/components/query-bar/QueryBarItem.vue'
|
||||||
|
import CrudModal from '@/components/table/CrudModal.vue'
|
||||||
|
import CrudTable from '@/components/table/CrudTable.vue'
|
||||||
|
|
||||||
|
import { formatDate, renderIcon } from '@/utils'
|
||||||
|
import { useCRUD } from '@/composables'
|
||||||
|
import api from '@/api'
|
||||||
|
import TheIcon from '@/components/icon/TheIcon.vue'
|
||||||
|
|
||||||
|
defineOptions({ name: '审核列表' })
|
||||||
|
|
||||||
|
const $table = ref(null)
|
||||||
|
const queryItems = ref({})
|
||||||
|
const vPermission = resolveDirective('permission')
|
||||||
|
|
||||||
|
// 审核状态选项
|
||||||
|
const statusOptions = [
|
||||||
|
{ label: '全部', value: '' },
|
||||||
|
{ label: '待审核', value: 'pending' },
|
||||||
|
{ label: '已完成', value: 'approved' },
|
||||||
|
{ label: '已拒绝', value: 'rejected' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const {
|
||||||
|
modalVisible,
|
||||||
|
modalTitle,
|
||||||
|
modalAction,
|
||||||
|
modalLoading,
|
||||||
|
handleSave,
|
||||||
|
modalForm,
|
||||||
|
modalFormRef,
|
||||||
|
handleEdit,
|
||||||
|
handleDelete,
|
||||||
|
handleAdd,
|
||||||
|
} = useCRUD({
|
||||||
|
name: '估值评估',
|
||||||
|
initForm: {},
|
||||||
|
doCreate: api.createValuation,
|
||||||
|
doUpdate: api.updateValuation,
|
||||||
|
doDelete: api.deleteValuation,
|
||||||
|
refresh: () => $table.value?.handleSearch(),
|
||||||
|
})
|
||||||
|
|
||||||
|
// 审核备注弹窗
|
||||||
|
const approvalModalVisible = ref(false)
|
||||||
|
const approvalModalTitle = ref('')
|
||||||
|
const approvalForm = ref({
|
||||||
|
valuation_id: null,
|
||||||
|
admin_notes: '',
|
||||||
|
action: '', // 'approve' or 'reject'
|
||||||
|
})
|
||||||
|
const approvalFormRef = ref(null)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
$table.value?.handleSearch()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 状态标签渲染
|
||||||
|
const renderStatus = (status) => {
|
||||||
|
const statusMap = {
|
||||||
|
pending: { type: 'warning', text: '待审核' },
|
||||||
|
approved: { type: 'success', text: '已完成' },
|
||||||
|
rejected: { type: 'error', text: '已拒绝' },
|
||||||
|
}
|
||||||
|
const config = statusMap[status] || { type: 'default', text: '未知' }
|
||||||
|
return h(NTag, { type: config.type }, { default: () => config.text })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式化金额
|
||||||
|
const formatAmount = (amount) => {
|
||||||
|
if (!amount) return '-'
|
||||||
|
return `¥${Number(amount).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: '编号',
|
||||||
|
key: 'id',
|
||||||
|
width: 80,
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '手机号',
|
||||||
|
key: 'phone',
|
||||||
|
width: 120,
|
||||||
|
align: 'center',
|
||||||
|
ellipsis: { tooltip: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '微信号',
|
||||||
|
key: 'wechat',
|
||||||
|
width: 120,
|
||||||
|
align: 'center',
|
||||||
|
ellipsis: { tooltip: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '评估结果',
|
||||||
|
key: 'valuation_result',
|
||||||
|
width: 120,
|
||||||
|
align: 'center',
|
||||||
|
render(row) {
|
||||||
|
return formatAmount(row.valuation_result)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '提交时间',
|
||||||
|
key: 'created_at',
|
||||||
|
width: 160,
|
||||||
|
align: 'center',
|
||||||
|
render(row) {
|
||||||
|
return formatDate(row.created_at)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '审核时间',
|
||||||
|
key: 'reviewed_at',
|
||||||
|
width: 160,
|
||||||
|
align: 'center',
|
||||||
|
render(row) {
|
||||||
|
return row.reviewed_at ? formatDate(row.reviewed_at) : '-'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
key: 'status',
|
||||||
|
width: 100,
|
||||||
|
align: 'center',
|
||||||
|
render(row) {
|
||||||
|
return renderStatus(row.status)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
key: 'actions',
|
||||||
|
width: 150,
|
||||||
|
align: 'center',
|
||||||
|
fixed: 'right',
|
||||||
|
render(row) {
|
||||||
|
return [
|
||||||
|
// 审核按钮 - 仅待审核状态显示
|
||||||
|
row.status === 'pending' &&
|
||||||
|
h(
|
||||||
|
NButton,
|
||||||
|
{
|
||||||
|
size: 'small',
|
||||||
|
type: 'primary',
|
||||||
|
style: 'margin-right: 8px;',
|
||||||
|
onClick: () => handleApprove(row),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
default: () => '审核',
|
||||||
|
icon: renderIcon('mdi:check-circle-outline', { size: 16 }),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
// 查看按钮
|
||||||
|
h(
|
||||||
|
NButton,
|
||||||
|
{
|
||||||
|
size: 'small',
|
||||||
|
type: 'info',
|
||||||
|
onClick: () => handleView(row),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
default: () => '查看',
|
||||||
|
icon: renderIcon('mdi:eye-outline', { size: 16 }),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
// 打开审核弹窗
|
||||||
|
function handleApprove(row) {
|
||||||
|
approvalForm.value = {
|
||||||
|
valuation_id: row.id,
|
||||||
|
admin_notes: '',
|
||||||
|
action: 'approve',
|
||||||
|
}
|
||||||
|
approvalModalTitle.value = '审核估值评估'
|
||||||
|
approvalModalVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查看详情
|
||||||
|
function handleView(row) {
|
||||||
|
handleEdit(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交审核
|
||||||
|
async function submitApproval(action) {
|
||||||
|
try {
|
||||||
|
await approvalFormRef.value?.validate()
|
||||||
|
|
||||||
|
const apiCall = action === 'approve' ? api.approveValuation : api.rejectValuation
|
||||||
|
|
||||||
|
await apiCall({
|
||||||
|
valuation_id: approvalForm.value.valuation_id,
|
||||||
|
admin_notes: approvalForm.value.admin_notes,
|
||||||
|
})
|
||||||
|
|
||||||
|
$message.success(action === 'approve' ? '审核通过成功' : '审核拒绝成功')
|
||||||
|
approvalModalVisible.value = false
|
||||||
|
$table.value?.handleSearch()
|
||||||
|
} catch (error) {
|
||||||
|
if (error?.message) {
|
||||||
|
$message.error(error.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const approvalRules = {
|
||||||
|
admin_notes: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入审核备注',
|
||||||
|
trigger: ['input', 'blur'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<CommonPage show-footer title="审核列表">
|
||||||
|
<!-- 表格 -->
|
||||||
|
<CrudTable
|
||||||
|
ref="$table"
|
||||||
|
v-model:query-items="queryItems"
|
||||||
|
:columns="columns"
|
||||||
|
:get-data="api.getValuationList"
|
||||||
|
>
|
||||||
|
<template #queryBar>
|
||||||
|
<QueryBarItem label="手机号" :label-width="60">
|
||||||
|
<NInput
|
||||||
|
v-model:value="queryItems.phone"
|
||||||
|
clearable
|
||||||
|
type="text"
|
||||||
|
placeholder="请输入手机号"
|
||||||
|
@keypress.enter="$table?.handleSearch()"
|
||||||
|
/>
|
||||||
|
</QueryBarItem>
|
||||||
|
<QueryBarItem label="微信号" :label-width="60">
|
||||||
|
<NInput
|
||||||
|
v-model:value="queryItems.wechat"
|
||||||
|
clearable
|
||||||
|
type="text"
|
||||||
|
placeholder="请输入微信号"
|
||||||
|
@keypress.enter="$table?.handleSearch()"
|
||||||
|
/>
|
||||||
|
</QueryBarItem>
|
||||||
|
<QueryBarItem label="提交时间" :label-width="80">
|
||||||
|
<NDatePicker
|
||||||
|
v-model:value="queryItems.created_at"
|
||||||
|
type="daterange"
|
||||||
|
clearable
|
||||||
|
placeholder="请选择提交时间"
|
||||||
|
style="width: 240px"
|
||||||
|
@update:value="$table?.handleSearch()"
|
||||||
|
/>
|
||||||
|
</QueryBarItem>
|
||||||
|
<QueryBarItem label="审核时间" :label-width="80">
|
||||||
|
<NDatePicker
|
||||||
|
v-model:value="queryItems.reviewed_at"
|
||||||
|
type="daterange"
|
||||||
|
clearable
|
||||||
|
placeholder="请选择审核时间"
|
||||||
|
style="width: 240px"
|
||||||
|
@update:value="$table?.handleSearch()"
|
||||||
|
/>
|
||||||
|
</QueryBarItem>
|
||||||
|
<QueryBarItem label="状态" :label-width="40">
|
||||||
|
<NSelect
|
||||||
|
v-model:value="queryItems.status"
|
||||||
|
:options="statusOptions"
|
||||||
|
placeholder="请选择状态"
|
||||||
|
clearable
|
||||||
|
style="width: 150px"
|
||||||
|
@update:value="$table?.handleSearch()"
|
||||||
|
/>
|
||||||
|
</QueryBarItem>
|
||||||
|
</template>
|
||||||
|
</CrudTable>
|
||||||
|
|
||||||
|
<!-- 查看详情弹窗 -->
|
||||||
|
<CrudModal
|
||||||
|
v-model:visible="modalVisible"
|
||||||
|
:title="modalTitle"
|
||||||
|
:loading="modalLoading"
|
||||||
|
:show-footer="false"
|
||||||
|
>
|
||||||
|
<NForm
|
||||||
|
ref="modalFormRef"
|
||||||
|
label-placement="left"
|
||||||
|
label-align="left"
|
||||||
|
:label-width="120"
|
||||||
|
:model="modalForm"
|
||||||
|
>
|
||||||
|
<NFormItem label="编号">
|
||||||
|
<span>{{ modalForm.id }}</span>
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem label="手机号">
|
||||||
|
<span>{{ modalForm.phone }}</span>
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem label="微信号">
|
||||||
|
<span>{{ modalForm.wechat }}</span>
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem label="评估结果">
|
||||||
|
<span>{{ formatAmount(modalForm.valuation_result) }}</span>
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem label="资产名称">
|
||||||
|
<span>{{ modalForm.asset_name || '-' }}</span>
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem label="所属机构">
|
||||||
|
<span>{{ modalForm.institution || '-' }}</span>
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem label="所属行业">
|
||||||
|
<span>{{ modalForm.industry || '-' }}</span>
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem label="非遗等级">
|
||||||
|
<span>{{ modalForm.heritage_level || '-' }}</span>
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem label="提交时间">
|
||||||
|
<span>{{ formatDate(modalForm.created_at) }}</span>
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem label="审核时间">
|
||||||
|
<span>{{ modalForm.reviewed_at ? formatDate(modalForm.reviewed_at) : '-' }}</span>
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem label="状态">
|
||||||
|
{{ renderStatus(modalForm.status) }}
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem label="管理员备注">
|
||||||
|
<span>{{ modalForm.admin_notes || '-' }}</span>
|
||||||
|
</NFormItem>
|
||||||
|
</NForm>
|
||||||
|
</CrudModal>
|
||||||
|
|
||||||
|
<!-- 审核弹窗 -->
|
||||||
|
<CrudModal
|
||||||
|
v-model:visible="approvalModalVisible"
|
||||||
|
:title="approvalModalTitle"
|
||||||
|
:show-footer="false"
|
||||||
|
>
|
||||||
|
<NForm
|
||||||
|
ref="approvalFormRef"
|
||||||
|
label-placement="left"
|
||||||
|
label-align="left"
|
||||||
|
:label-width="100"
|
||||||
|
:model="approvalForm"
|
||||||
|
:rules="approvalRules"
|
||||||
|
>
|
||||||
|
<NFormItem label="审核备注" path="admin_notes">
|
||||||
|
<NInput
|
||||||
|
v-model:value="approvalForm.admin_notes"
|
||||||
|
type="textarea"
|
||||||
|
:rows="4"
|
||||||
|
placeholder="请输入审核备注"
|
||||||
|
/>
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem>
|
||||||
|
<NSpace>
|
||||||
|
<NButton type="success" @click="submitApproval('approve')">
|
||||||
|
<template #icon>
|
||||||
|
<TheIcon icon="mdi:check-circle-outline" :size="16" />
|
||||||
|
</template>
|
||||||
|
通过
|
||||||
|
</NButton>
|
||||||
|
<NButton type="error" @click="submitApproval('reject')">
|
||||||
|
<template #icon>
|
||||||
|
<TheIcon icon="mdi:close-circle-outline" :size="16" />
|
||||||
|
</template>
|
||||||
|
拒绝
|
||||||
|
</NButton>
|
||||||
|
<NButton @click="approvalModalVisible = false">取消</NButton>
|
||||||
|
</NSpace>
|
||||||
|
</NFormItem>
|
||||||
|
</NForm>
|
||||||
|
</CrudModal>
|
||||||
|
</CommonPage>
|
||||||
|
</template>
|
||||||
Loading…
x
Reference in New Issue
Block a user