Commit 7ac0e431 by 李宁

1

1 parent 7952694f
import request from '../../request' import request from '../../request'
/** /**
* 网格列表查询 * 订单列表查询
* @returns {AxiosPromise} * @returns {AxiosPromise}
*/ */
export function queryAllGridList(data) { export function queryOrderList(data) {
return request({ return request({
url: '/compass/api/grid/list', url: '/crm/getOrderList',
data, data,
}) })
} }
/**
* 订单列表导出
* @returns {AxiosPromise}
*/
export function exportOrderList(data) {
return request({
url: '/crm/exportOrders',
data,
responseType: 'blob'
})
}
/**
* 订单审核
* @returns {AxiosPromise}
*/
export function audioOrderList(data) {
return request({
url: '/crm/auditOrder',
data,
})
}
/**
* 订单金额批量修改
* @returns {AxiosPromise}
*/
export function updateOrderListMoney(data) {
return request({
url: '/crm/readExcelModifyOrder',
headers: {
'Content-Type': 'multipart/form-data'
},
data,
})
}
/**
* 订单金额修改
* @returns {AxiosPromise}
*/
export function updateOrderMoney(data) {
return request({
url: '/crm/updateOrderMoney',
data,
})
}
/** /**
* 获取该账号下可选的网格列表 * 订单crm修改
* @returns {AxiosPromise}
*/
export function updateOrderCrm(data) {
return request({
url: '/crm/updateCrmOrderId',
data,
})
}
/**
* 订单关闭
* @returns {AxiosPromise}
*/
export function closeOrder(data) {
return request({
url: '/crm/closeOrder',
data,
})
}
/**
* 订单日志
* @returns {AxiosPromise}
*/ */
export function queryGridList(data) { export function queryOrderLog(data) {
return request({ return request({
url: '/compass/api/grid/options', url: '/crm/getOrderLog',
data, data,
}) })
} }
\ No newline at end of file \ No newline at end of file
...@@ -3,10 +3,10 @@ import request from '../../request' ...@@ -3,10 +3,10 @@ import request from '../../request'
/** /**
* 业务酬金列表查询 * 业务酬金列表查询
*/ */
export function queryAllRewardList(data) { export function queryAllRewardList() {
return request({ return request({
url: '/crm/getJobsList', url: '/crm/getJobsList',
data, method: 'GET'
}) })
} }
...@@ -16,12 +16,15 @@ export function queryAllRewardList(data) { ...@@ -16,12 +16,15 @@ export function queryAllRewardList(data) {
export function uploadReward(formData) { export function uploadReward(formData) {
return request({ return request({
url: '/crm/readExcelJobs', url: '/crm/readExcelJobs',
headers: {
'Content-Type': 'multipart/form-data'
},
data: formData data: formData
}) })
} }
/** /**
* 业务酬金提交 * 业务酬金批量上传
*/ */
export function uploadRewardSave(data) { export function uploadRewardSave(data) {
return request({ return request({
...@@ -32,11 +35,11 @@ export function uploadRewardSave(data) { ...@@ -32,11 +35,11 @@ export function uploadRewardSave(data) {
/** /**
* 业务酬金修改 * 业务酬金新增和修改
*/ */
export function updateReward(data) { export function updateReward(data) {
return request({ return request({
url: '/crm/updateJob', url: data.id?'/crm/updateJob':'/crm/addJobs',
data, data,
}) })
} }
...@@ -47,7 +50,7 @@ export function updateReward(data) { ...@@ -47,7 +50,7 @@ export function updateReward(data) {
*/ */
export function delReward(data) { export function delReward(data) {
return request({ return request({
url: '/crm/updateJob', url: '/crm/delJob',
data, data,
}) })
} }
\ No newline at end of file \ No newline at end of file
...@@ -38,41 +38,9 @@ ...@@ -38,41 +38,9 @@
style="display: none" style="display: none"
/> />
<!-- 筛选条件区 -->
<el-card class="p-5">
<div class="flex items-center gap-3 w-full">
<!-- 搜索框 -->
<div class="flex-1 relative">
<Search class="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-neutral-500 z-10" />
<el-input
v-model="searchKeyword"
placeholder="搜索业务代码或业务名称..."
class="search-input"
clearable
/>
</div>
<!-- 查询按钮 -->
<div class="shrink-0">
<el-button
type="primary"
@click="handleSearch"
class="h-10"
>
查询
</el-button>
</div>
</div>
</el-card>
<!-- 业务规则表格 --> <!-- 业务规则表格 -->
<el-card class="p-5"> <el-card class="p-5">
<div class="flex items-center justify-between mb-4">
<div class="text-sm text-neutral-600">
{{ filteredRules.length }} 条记录
</div>
</div>
<div class="rounded-lg overflow-hidden"> <div class="rounded-lg overflow-hidden">
<el-table <el-table
:data="paginatedRules" :data="paginatedRules"
...@@ -81,35 +49,35 @@ ...@@ -81,35 +49,35 @@
:header-cell-style="{ backgroundColor: '#f3f4f6', color: '#374151', fontWeight: '500', borderBottom: '1px solid #e5e7eb' }" :header-cell-style="{ backgroundColor: '#f3f4f6', color: '#374151', fontWeight: '500', borderBottom: '1px solid #e5e7eb' }"
row-class-name="hover:bg-muted/30" row-class-name="hover:bg-muted/30"
> >
<el-table-column prop="businessCode" label="业务代码" min-width="120"> <el-table-column prop="jobId" label="业务代码" min-width="120">
<template #default="{ row }"> <template #default="{ row }">
<span class="font-mono">{{ row.businessCode }}</span> <span class="font-mono">{{ row.jobId }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="businessName" label="业务名称" min-width="150" /> <el-table-column prop="jobName" label="业务名称" min-width="150" />
<el-table-column label="预计酬金(元)" min-width="120"> <el-table-column label="预计酬金(元)" min-width="120">
<template #default="{ row }"> <template #default="{ row }">
¥{{ row.estimatedReward.toFixed(2) }} ¥{{ row.totalPrice.toFixed(2) }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="业务状态" min-width="100"> <el-table-column label="业务状态" min-width="100">
<template #default="{ row }"> <template #default="{ row }">
<el-tag <el-tag
:type="row.status === '生效中' ? 'success' : 'info'" :type="row.status === 1 ? 'success' : 'info'"
class="border-0" class="border-0"
> >
{{ row.status }} {{ row.status===1?'生效中':'已停用' }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="createTime" label="创建时间" min-width="150"> <el-table-column prop="createTime" label="创建时间" min-width="150">
<template #default="{ row }"> <template #default="{ row }">
{{ row.createTime || '-' }} {{ $utils.detailTime(row.createTime) }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="updateTime" label="更新时间" min-width="150"> <el-table-column prop="updateTime" label="更新时间" min-width="150">
<template #default="{ row }"> <template #default="{ row }">
{{ row.updateTime || '-' }} {{ $utils.detailTime(row.updateTime) }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" min-width="200" fixed="right"> <el-table-column label="操作" min-width="200" fixed="right">
...@@ -140,21 +108,6 @@ ...@@ -140,21 +108,6 @@
</template> </template>
</el-table> </el-table>
</div> </div>
<!-- 分页组件 -->
<div v-if="totalPages > 1" class="flex items-center justify-between px-6 py-4">
<div class="text-sm text-neutral-600">
显示第 {{ startIndex + 1 }}-{{ Math.min(endIndex, filteredRules.length) }} 条,共 {{ filteredRules.length }} 条
</div>
<el-pagination
v-model:current-page="currentPage"
:page-size="pageSize"
:total="filteredRules.length"
layout="prev, pager, next"
:pager-count="5"
small
/>
</div>
</el-card> </el-card>
<!-- 新建/编辑业务规则对话框 --> <!-- 新建/编辑业务规则对话框 -->
...@@ -200,8 +153,8 @@ ...@@ -200,8 +153,8 @@
<div> <div>
<label class="block text-sm font-medium text-neutral-700 mb-2">状态</label> <label class="block text-sm font-medium text-neutral-700 mb-2">状态</label>
<el-radio-group v-model="formData.status"> <el-radio-group v-model="formData.status">
<el-radio label="生效中">启用</el-radio> <el-radio label="1">生效</el-radio>
<el-radio label="已停用">停用</el-radio> <el-radio label="0">停用</el-radio>
</el-radio-group> </el-radio-group>
</div> </div>
</div> </div>
...@@ -227,13 +180,13 @@ ...@@ -227,13 +180,13 @@
<div class="flex items-center gap-4 p-4 bg-neutral-50 rounded-lg"> <div class="flex items-center gap-4 p-4 bg-neutral-50 rounded-lg">
<div class="flex items-center gap-2 flex-1"> <div class="flex items-center gap-2 flex-1">
<CheckCircle class="h-5 w-5 text-green-500" /> <CheckCircle class="h-5 w-5 text-green-500" />
<span>成功导入:</span> <span>正常</span>
<span class="text-green-500">{{ uploadResult?.success || 0 }}</span> <span class="text-green-500">{{ uploadResult?.success || 0 }}</span>
<span></span> <span></span>
</div> </div>
<div class="flex items-center gap-2 flex-1"> <div class="flex items-center gap-2 flex-1">
<AlertCircle class="h-5 w-5 text-red-500" /> <AlertCircle class="h-5 w-5 text-red-500" />
<span>导入失败:</span> <span>错误</span>
<span class="text-red-500">{{ uploadResult?.failed || 0 }}</span> <span class="text-red-500">{{ uploadResult?.failed || 0 }}</span>
<span></span> <span></span>
</div> </div>
...@@ -249,20 +202,12 @@ ...@@ -249,20 +202,12 @@
> >
{{ error }} {{ error }}
</div> </div>
<div
v-if="uploadResult.errors.length >= 20"
class="text-sm text-neutral-500 italic"
>
仅显示前20条错误信息...
</div>
</div> </div>
</div> </div>
</div> </div>
<template #footer> <template #footer>
<el-button type="primary" @click="showUploadResult = false"> <el-button type="primary" @click="submitExcelData">{{uploadResult.failed>0?'确定':'提交'}}</el-button>
确定
</el-button>
</template> </template>
</el-dialog> </el-dialog>
</div> </div>
...@@ -277,10 +222,10 @@ const { $api,$utils } = getCurrentInstance()!.appContext.config.globalProperties ...@@ -277,10 +222,10 @@ const { $api,$utils } = getCurrentInstance()!.appContext.config.globalProperties
// 业务规则类型定义 // 业务规则类型定义
interface BusinessRule { interface BusinessRule {
id: string id: string
businessCode: string jobId: string
businessName: string jobName: string
estimatedReward: number totalPrice: number
status: '生效中' | '已停用' status: '1' | '0'
createTime?: string createTime?: string
updateTime?: string updateTime?: string
} }
...@@ -308,7 +253,7 @@ const queryRewardList = async ()=>{ ...@@ -308,7 +253,7 @@ const queryRewardList = async ()=>{
const response = await $api.queryAllRewardList({}) const response = await $api.queryAllRewardList({})
if (response.c === 0 && response.d) { if (response.c === 0 && response.d) {
paginatedRules.value = response.d
} else { } else {
} }
...@@ -339,24 +284,10 @@ const formData = ref({ ...@@ -339,24 +284,10 @@ const formData = ref({
businessCode: '', businessCode: '',
businessName: '', businessName: '',
estimatedReward: 0, estimatedReward: 0,
status: '生效中' as '生效中' | '已停用' status: '1'
})
// 计算属性
const filteredRules = computed(() => {
return props.rules.filter(rule => {
const matchesSearch = !searchKeyword.value ||
rule.businessCode.toLowerCase().includes(searchKeyword.value.toLowerCase()) ||
rule.businessName.toLowerCase().includes(searchKeyword.value.toLowerCase())
return matchesSearch
})
}) })
const totalPages = computed(() => Math.ceil(filteredRules.value.length / pageSize.value)) const paginatedRules = ref([])
const startIndex = computed(() => (currentPage.value - 1) * pageSize.value)
const endIndex = computed(() => startIndex.value + pageSize.value)
const paginatedRules = computed(() => filteredRules.value.slice(startIndex.value, endIndex.value))
// 方法 // 方法
const handleSearch = () => { const handleSearch = () => {
...@@ -367,10 +298,10 @@ const handleOpenDialog = (rule?: BusinessRule) => { ...@@ -367,10 +298,10 @@ const handleOpenDialog = (rule?: BusinessRule) => {
if (rule) { if (rule) {
editingRule.value = rule editingRule.value = rule
formData.value = { formData.value = {
businessCode: rule.businessCode, businessCode: rule.jobId,
businessName: rule.businessName, businessName: rule.jobName,
estimatedReward: rule.estimatedReward, estimatedReward: rule.totalPrice,
status: rule.status status: rule.status+''
} }
} else { } else {
editingRule.value = null editingRule.value = null
...@@ -378,7 +309,7 @@ const handleOpenDialog = (rule?: BusinessRule) => { ...@@ -378,7 +309,7 @@ const handleOpenDialog = (rule?: BusinessRule) => {
businessCode: '', businessCode: '',
businessName: '', businessName: '',
estimatedReward: 0, estimatedReward: 0,
status: '生效中' status: '1'
} }
} }
isDialogOpen.value = true isDialogOpen.value = true
...@@ -391,30 +322,33 @@ const handleCloseDialog = () => { ...@@ -391,30 +322,33 @@ const handleCloseDialog = () => {
businessCode: '', businessCode: '',
businessName: '', businessName: '',
estimatedReward: 0, estimatedReward: 0,
status: '生效中' status: '1'
} }
} }
const handleSubmit = () => { const handleSubmit = async () => {
if (!formData.value.businessCode.trim() || !formData.value.businessName.trim() || formData.value.estimatedReward <= 0) { if (!formData.value.businessCode.trim() || !formData.value.businessName.trim() || formData.value.estimatedReward <= 0) {
ElMessage.error('请填写完整信息') ElMessage.error('请填写完整信息')
return return
} }
if (editingRule.value) { try {
emit('update', editingRule.value.id, { const response = await $api.updateReward({
businessCode: formData.value.businessCode, id: editingRule.value?editingRule.value.id:'',
businessName: formData.value.businessName, jobName: formData.value.businessName,
estimatedReward: formData.value.estimatedReward, jobId: formData.value.businessCode,
status: formData.value.status totalPrice: formData.value.estimatedReward,
})
} else {
emit('add', {
businessCode: formData.value.businessCode,
businessName: formData.value.businessName,
estimatedReward: formData.value.estimatedReward,
status: formData.value.status status: formData.value.status
}) })
if(response.c === 0){
ElMessage.success('新建成功')
queryRewardList()
}else{
ElMessage.error(response.m)
}
} catch (error) {
ElMessage.error('文件解析失败,请检查文件格式是否正确')
} }
handleCloseDialog() handleCloseDialog()
...@@ -435,7 +369,17 @@ const handleDeleteConfirm = async (id: string) => { ...@@ -435,7 +369,17 @@ const handleDeleteConfirm = async (id: string) => {
type: 'warning' type: 'warning'
} }
) )
emit('delete', id)
const response = await $api.delReward({
id
})
if(response.c === 0){
ElMessage.success('删除成功')
queryRewardList()
}else{
ElMessage.error(response.m || '删除失败')
}
} catch { } catch {
// 用户取消删除 // 用户取消删除
} }
...@@ -486,62 +430,63 @@ const handleFileChange = async (e: Event) => { ...@@ -486,62 +430,63 @@ const handleFileChange = async (e: Event) => {
} }
try { try {
const formData = new FormData() const fd = new FormData()
formData.append('file', file) fd.append('file', file)
const response = await $api.uploadReward(fd)
if(response.c === 0){
processUploadData(response.d.list)
}else{
ElMessage.error(response.m)
}
} catch (error) {
ElMessage.error('文件解析失败,请检查文件格式是否正确')
}
}
const response = await $api.uploadReward(formData) const submitExcelData = async ()=>{
if(uploadResult.value.failed > 0){
showUploadResult.value = false
return
}
console.log(response) try {
const response = await $api.uploadRewardSave({
list: excelShowdData.value
})
if(response.c === 0){
ElMessage.success('上传成功')
showUploadResult.value = false
queryRewardList()
}else{
ElMessage.error(response.m)
}
} catch (error) { } catch (error) {
console.error('文件解析失败:', error)
ElMessage.error('文件解析失败,请检查文件格式是否正确') ElMessage.error('文件解析失败,请检查文件格式是否正确')
} }
} }
const excelShowdData = ref([])
const processUploadData = (data: any[]) => { const processUploadData = (data: any[]) => {
const errors: string[] = [] const errors: string[] = []
let successCount = 0 let successCount = 0
let failedCount = 0 let failedCount = 0
excelShowdData.value = data
// 获取现有的业务代码集合 // 获取现有的业务代码集合
const existingCodes = new Set(props.rules.map(r => r.businessCode.toLowerCase())) const existingCodes = new Set(props.rules.map(r => r.businessCode.toLowerCase()))
data.forEach((row, index) => { data.forEach((row, index) => {
const rowNum = index + 2 // Excel行号(从1开始,跳过表头) const rowNum = index + 3 // Excel行号(从1开始,跳过表头)
// 验证必填字段
if (!row.businessName || !row.businessCode || !row.estimatedReward) {
errors.push(`第${rowNum}行:缺少必填字段`)
failedCount++
return
}
// 验证业务代码是否重复(与现有数据)
if (existingCodes.has(row.businessCode.toLowerCase())) {
errors.push(`第${rowNum}行:业务代码"${row.businessCode}"已存在,请修改后重新上传`)
failedCount++
return
}
// 验证酬金金额 if (row.memo) {
const amount = parseFloat(row.estimatedReward) errors.push(`第${rowNum}行:${row.memo}`)
if (isNaN(amount) || amount <= 0) {
errors.push(`第${rowNum}行:预计酬金格式不正确`)
failedCount++ failedCount++
return return
} }
// 验证通过,添加到系统 // 验证通过,添加到系统
try { try {
emit('add', {
businessCode: row.businessCode,
businessName: row.businessName,
estimatedReward: amount,
status: '生效中'
})
// 将新添加的代码加入集合,避免批量数据内部重复
existingCodes.add(row.businessCode.toLowerCase())
successCount++ successCount++
} catch (error) { } catch (error) {
errors.push(`第${rowNum}行:添加失败`) errors.push(`第${rowNum}行:添加失败`)
...@@ -553,17 +498,9 @@ const processUploadData = (data: any[]) => { ...@@ -553,17 +498,9 @@ const processUploadData = (data: any[]) => {
uploadResult.value = { uploadResult.value = {
success: successCount, success: successCount,
failed: failedCount, failed: failedCount,
errors: errors.slice(0, 20) // 最多显示20条错误 errors: errors
} }
showUploadResult.value = true showUploadResult.value = true
if (successCount > 0 && failedCount === 0) {
ElMessage.success(`成功导入${successCount}条业务规则`)
} else if (successCount > 0 && failedCount > 0) {
ElMessage.warning(`成功导入${successCount}条,失败${failedCount}条`)
} else {
ElMessage.error(`导入失败,共${failedCount}条错误`)
}
} }
</script> </script>
......
...@@ -224,8 +224,8 @@ ...@@ -224,8 +224,8 @@
<!-- 订单详情页面 --> <!-- 订单详情页面 -->
<OrderDetail <OrderDetail
v-else-if="activeView === 'order-detail' && selectedOrderId && getOrderById(selectedOrderId)" v-else-if="activeView === 'order-detail' && selectedOrderId"
:order="getOrderById(selectedOrderId)!" :order="selectedOrder"
:business-rules="businessRules" :business-rules="businessRules"
:current-user="currentUser" :current-user="currentUser"
@update="handleUpdateOrder" @update="handleUpdateOrder"
...@@ -315,6 +315,7 @@ const isSidebarCollapsed = ref(false) ...@@ -315,6 +315,7 @@ const isSidebarCollapsed = ref(false)
const activeMenu = ref<string>('orders') // 当前激活的菜单 const activeMenu = ref<string>('orders') // 当前激活的菜单
const activeView = ref<string>('orders') // 当前显示的视图 const activeView = ref<string>('orders') // 当前显示的视图
const selectedOrderId = ref<string | null>(null) // 当前查看的订单ID const selectedOrderId = ref<string | null>(null) // 当前查看的订单ID
const selectedOrder = ref<{}>(null) // 当前查看的订单ID
const userInfo = ref(localStorage.getItem('pcUserInfo') ? JSON.parse(localStorage.getItem('pcUserInfo') as string) : {}) const userInfo = ref(localStorage.getItem('pcUserInfo') ? JSON.parse(localStorage.getItem('pcUserInfo') as string) : {})
// 菜单配置 // 菜单配置
// const businessMenuItems = [ // const businessMenuItems = [
...@@ -464,6 +465,7 @@ const handleCommand = (command: string) => { ...@@ -464,6 +465,7 @@ const handleCommand = (command: string) => {
} }
} }
const handleViewOrderDetail = (order: any) => { const handleViewOrderDetail = (order: any) => {
selectedOrder.value = order
selectedOrderId.value = order.id selectedOrderId.value = order.id
activeView.value = 'order-detail' activeView.value = 'order-detail'
} }
......
...@@ -13,66 +13,17 @@ ...@@ -13,66 +13,17 @@
<h1 class="text-2xl font-bold text-neutral-900 m-0" style="margin-left: 8px;">订单详情</h1> <h1 class="text-2xl font-bold text-neutral-900 m-0" style="margin-left: 8px;">订单详情</h1>
</div> </div>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2" v-if="order.status !== '0'">
<!-- 待办理:关闭订单 + 提交审核 --> <el-button
<template v-if="order.businessStatus === '待办理'"> @click="isCloseDialogOpen = true"
<el-button v-if="order.auditStatus !== '1'"
@click="isCloseDialogOpen = true" class="border-neutral-500 text-neutral-700"
class="border-neutral-500 text-neutral-700" >
> 关闭订单
关闭订单 </el-button>
</el-button>
<el-button
type="primary"
@click="handleSaveCompleteInfo"
class="bg-brand-primary"
>
提交审核
</el-button>
</template>
<!-- 办理成功:关闭订单 + 提交审核 -->
<template v-else-if="order.businessStatus === '办理成功' && !order.reviewStatus">
<el-button
@click="isCloseDialogOpen = true"
class="border-neutral-500 text-neutral-700"
>
关闭订单
</el-button>
<el-button
type="primary"
@click="handleSubmitReview"
class="bg-brand-primary"
>
提交审核
</el-button>
</template>
<!-- 办理成功+审核驳回:关闭订单 + 重新提交审核 -->
<template v-else-if="order.businessStatus === '办理成功' && order.reviewStatus === '审核驳回'">
<el-button
@click="isCloseDialogOpen = true"
class="border-neutral-500 text-neutral-700"
>
关闭订单
</el-button>
<el-button
type="primary"
@click="handleSubmitReview"
class="bg-brand-primary"
>
重新提交审核
</el-button>
</template>
<!-- 待审核:关闭订单 + 驳回 + 通过 --> <!-- 待审核:关闭订单 + 驳回 + 通过 -->
<template v-else-if="order.businessStatus === '办理成功' && order.reviewStatus === '待审核' && currentUser?.role === 'admin'"> <template v-if="order.auditStatus === '0'">
<el-button
@click="isCloseDialogOpen = true"
class="border-neutral-500 text-neutral-700"
>
关闭订单
</el-button>
<el-dropdown @command="handleAuditCommand"> <el-dropdown @command="handleAuditCommand">
<el-button type="primary" class="bg-brand-primary"> <el-button type="primary" class="bg-brand-primary">
审核订单 审核订单
...@@ -93,15 +44,6 @@ ...@@ -93,15 +44,6 @@
</el-dropdown> </el-dropdown>
</template> </template>
<!-- 审核通过:仅显示关闭订单;业务状态为已关闭时不显示任何操作按钮 -->
<template v-else-if="order.businessStatus !== '已关闭'">
<el-button
@click="isCloseDialogOpen = true"
class="border-neutral-500 text-neutral-700"
>
关闭订单
</el-button>
</template>
</div> </div>
</div> </div>
...@@ -119,15 +61,15 @@ ...@@ -119,15 +61,15 @@
</div> </div>
<div> <div>
<label class="text-neutral-500 text-sm">能人</label> <label class="text-neutral-500 text-sm">能人</label>
<p class="mt-2 text-neutral-900">{{ order.registerPersonName }}</p> <p class="mt-2 text-neutral-900">{{ order.chinaPersonName }}</p>
</div> </div>
<div> <div>
<label class="text-neutral-500 text-sm">能人手机号</label> <label class="text-neutral-500 text-sm">能人手机号</label>
<p class="mt-2 text-neutral-900">{{ order.registerPersonPhone }}</p> <p class="mt-2 text-neutral-900">{{ order.chinaPersonPhone }}</p>
</div> </div>
<div> <div>
<label class="text-neutral-500 text-sm">登记时间</label> <label class="text-neutral-500 text-sm">登记时间</label>
<p class="mt-2 text-neutral-700">{{ order.registerTime }}</p> <p class="mt-2 text-neutral-700">{{ $utils.detailTime(order.createTime) }}</p>
</div> </div>
<div> <div>
<label class="text-neutral-500 text-sm">客户号码</label> <label class="text-neutral-500 text-sm">客户号码</label>
...@@ -135,67 +77,67 @@ ...@@ -135,67 +77,67 @@
</div> </div>
<div> <div>
<label class="text-neutral-500 text-sm">业务名称</label> <label class="text-neutral-500 text-sm">业务名称</label>
<p class="mt-2 text-neutral-900">{{ order.businessName }}</p> <p class="mt-2 text-neutral-900">{{ order.jobName }}</p>
</div> </div>
<div> <div>
<label class="text-neutral-500 text-sm">业务状态</label> <label class="text-neutral-500 text-sm">业务状态</label>
<div class="mt-2"> <div class="mt-2">
<span <span
:class="getBusinessStatusClass(order.businessStatus)" :class="getstatusClass(order.status)"
class="px-2 py-1 rounded text-xs font-medium" class="px-2 py-1 rounded text-xs font-medium"
> >
{{ order.businessStatus }} {{ getstatusName(order.status) }}
</span> </span>
</div> </div>
</div> </div>
<div v-if="order.reviewStatus"> <div v-if="order.auditStatus">
<label class="text-neutral-500 text-sm">审核状态</label> <label class="text-neutral-500 text-sm">审核状态</label>
<div class="mt-2"> <div class="mt-2">
<span <span
:class="getReviewStatusClass(order.reviewStatus)" :class="getauditStatusClass(order.auditStatus)"
class="px-2 py-1 rounded text-xs font-medium" class="px-2 py-1 rounded text-xs font-medium"
> >
{{ order.reviewStatus }} {{ getauditStatusName(order.auditStatus) }}
</span> </span>
</div> </div>
</div> </div>
<div v-if="order.remarks" class="col-span-2"> <div v-if="order.remarks" class="col-span-2">
<label class="text-neutral-500 text-sm">备注信息</label> <label class="text-neutral-500 text-sm">备注信息</label>
<p class="mt-2 text-neutral-700">{{ order.remarks }}</p> <p class="mt-2 text-neutral-700">{{ order.memo||'--' }}</p>
</div> </div>
</div> </div>
</el-card> </el-card>
<!-- 操作日志 --> <!-- 操作日志 -->
<el-card v-if="order.operationLogs && order.operationLogs.length > 0" class="p-6"> <el-card v-if="logData.length > 0" class="p-6">
<h3 class="text-neutral-900 font-bold mb-4">操作日志</h3> <h3 class="text-neutral-900 font-bold mb-4">操作日志</h3>
<div class="space-y-5"> <div class="space-y-5">
<div <div
v-for="(log, index) in order.operationLogs" v-for="(log, index) in logData"
:key="log.id" :key="log.id"
class="flex gap-4" class="flex gap-4"
> >
<div class="flex flex-col items-center"> <div class="flex flex-col items-center">
<div class="w-3 h-3 rounded-full bg-brand-primary"></div> <div class="w-3 h-3 rounded-full bg-brand-primary"></div>
<div <div
v-if="index < order.operationLogs!.length - 1" v-if="index < logData!.length - 1"
class="w-0.5 flex-1 bg-neutral-300 my-1" class="w-0.5 flex-1 bg-neutral-300 my-1"
></div> ></div>
</div> </div>
<div class="flex-1 pb-2"> <div class="flex-1 pb-2">
<div class="flex items-center gap-2 mb-1.5"> <div class="flex items-center gap-2 mb-1.5">
<span class="text-neutral-900">{{ log.action }}</span> <span class="text-neutral-900">{{ log.functionName }}</span>
<el-tag size="small" type="info">{{ log.operator }}</el-tag> <el-tag size="small" type="info">{{ log.operatorName }}</el-tag>
</div> </div>
<p class="text-sm text-neutral-600 mb-1">{{ log.details }}</p> <p class="text-sm text-neutral-600 mb-1">{{ log.detail.memo }}</p>
<p class="text-xs text-neutral-500">{{ log.time }}</p> <p class="text-xs text-neutral-500">{{ $utils.detailTime(log.createTime) }}</p>
</div> </div>
</div> </div>
</div> </div>
</el-card> </el-card>
<!-- 订单关闭信息 --> <!-- 订单关闭信息 -->
<el-card v-if="order.businessStatus === '已关闭' && order.closeReason" class="p-6 bg-neutral-50"> <el-card v-if="order.status === '0' && order.closeReason" class="p-6 bg-neutral-50">
<h3 class="text-neutral-900 font-bold mb-4">订单关闭信息</h3> <h3 class="text-neutral-900 font-bold mb-4">订单关闭信息</h3>
<div> <div>
<label class="text-neutral-700 text-sm">订单关闭原因</label> <label class="text-neutral-700 text-sm">订单关闭原因</label>
...@@ -218,11 +160,11 @@ ...@@ -218,11 +160,11 @@
</label> </label>
<el-input <el-input
v-if="canEditCompleteInfo" v-if="canEditCompleteInfo"
v-model="crmOrderNumber" v-model="crmOrderId"
placeholder="请输入CRM订单编号" placeholder="请输入CRM订单编号"
class="mt-2" class="mt-2"
/> />
<p v-else class="mt-2 text-neutral-700">{{ order.crmOrderNumber || '-' }}</p> <p v-else class="mt-2 text-neutral-700">{{ order.crmOrderId || '-' }}</p>
</div> </div>
<div> <div>
...@@ -237,57 +179,59 @@ ...@@ -237,57 +179,59 @@
/> />
<p v-else class="mt-2 text-neutral-700">{{ order.processRemark || '-' }}</p> <p v-else class="mt-2 text-neutral-700">{{ order.processRemark || '-' }}</p>
</div> </div>
<div v-if="!canEditCompleteInfo"> <el-button
<label class="text-neutral-900 text-sm">办结登记时间</label> type="primary"
<p class="mt-2 text-neutral-700">{{ order.completeTime || '-' }}</p> @click="handleSaveCrm"
</div> v-if="canEditCompleteInfo"
class="bg-brand-primary"
style="float: right;"
>
保存
</el-button>
</div> </div>
</el-card> </el-card>
<!-- 酬金信息区 --> <!-- 酬金信息区 -->
<el-card v-if="order.businessStatus !== '待办理'" class="p-6"> <el-card class="p-6">
<h3 class="text-neutral-900 font-bold mb-4">酬金信息</h3> <h3 class="text-neutral-900 font-bold mb-4">酬金信息</h3>
<div class="space-y-5"> <div class="space-y-5">
<!-- 预计酬金金额 --> <!-- 预计酬金金额 -->
<div> <div>
<label class="text-neutral-500 text-sm">预计酬金金额</label> <label class="text-neutral-500 text-sm">预计酬金金额</label>
<p class="mt-2 text-2xl text-neutral-900"> <p class="mt-2 text-2xl text-neutral-900">
¥{{ order.estimatedReward?.toFixed(2) || '0.00' }} ¥{{ order.preMoney?.toFixed(2) || '0.00' }}
</p> </p>
</div> </div>
<!-- 实际结酬金额 --> <!-- 实际结酬金额 -->
<div> <div>
<label class="text-neutral-900 text-sm"> <label class="text-neutral-900 text-sm">
实际结酬金额{{ canEditReward && order.reviewStatus !== '待审核' ? '(选填)' : '' }} 实际结酬金额{{ canEditReward && order.auditStatus !== '0' ? '(选填)' : '' }}
</label> </label>
<el-input <el-input
v-if="canEditReward && order.reviewStatus !== '待审核'" v-if="canEditReward && order.auditStatus !== '0'"
v-model="actualReward" v-model="realMoney"
type="Number"
placeholder="请输入实际结酬金额" placeholder="请输入实际结酬金额"
class="mt-2" class="mt-2"
> >
<template #prepend>¥</template> <template #prepend>¥</template>
</el-input> </el-input>
<p v-else class="mt-2 text-2xl text-success"> <p v-else class="mt-2 text-2xl text-success">
¥{{ order.actualReward?.toFixed(2) || '0.00' }} ¥{{ order.realMoney?.toFixed(2) || '0.00' }}
</p> </p>
</div> </div>
<!-- 审核通过时间 --> <el-button
<div v-if="order.reviewStatus === '审核通过' && order.paymentTime"> type="primary"
<label class="text-neutral-500 text-sm">审核通过时间</label> @click="handleSaveReward"
<p class="mt-2 text-neutral-900">{{ order.paymentTime }}</p> v-if="canEditReward"
</div> class="bg-brand-primary"
style="float: right;"
<!-- 审核驳回原因 --> >
<div v-if="order.rejectReason"> 提交审核
<label class="text-error text-sm">审核驳回原因</label> </el-button>
<div class="mt-3 p-3 bg-orange-50 border border-orange-200 rounded">
<p class="text-sm text-orange-900">{{ order.rejectReason }}</p>
</div>
</div>
</div> </div>
</el-card> </el-card>
</div> </div>
...@@ -378,14 +322,16 @@ ...@@ -378,14 +322,16 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed } from 'vue' import { ref, computed ,getCurrentInstance,onMounted} from 'vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { ArrowLeft, Check, X } from 'lucide-vue-next' import { ArrowLeft, Check, X } from 'lucide-vue-next'
import { ArrowDown } from '@element-plus/icons-vue' import { ArrowDown } from '@element-plus/icons-vue'
const { $api,$utils } = getCurrentInstance()!.appContext.config.globalProperties
// 类型定义 // 类型定义
type BusinessStatus = '待办理' | '办理成功' | '已关闭' type status = '-1' | '1' | '0'
type ReviewStatus = '待审核' | '审核通过' | '审核驳回' type auditStatus = '0' | '1' | '2'
interface OperationLog { interface OperationLog {
id: string id: string
...@@ -397,16 +343,16 @@ interface OperationLog { ...@@ -397,16 +343,16 @@ interface OperationLog {
interface Order { interface Order {
id: string id: string
registerPersonPhone: string chinaPersonPhone: string
registerPersonName: string chinaPersonName: string
customerPhone: string customerPhone: string
businessName: string job: string
registerTime: string createTime: string
businessStatus: BusinessStatus status: status
reviewStatus?: ReviewStatus auditStatus?: auditStatus
estimatedReward?: number preMoney?: number
actualReward?: number realMoney?: number
crmOrderNumber?: string crmOrderId?: string
completeTime?: string completeTime?: string
paymentTime?: string paymentTime?: string
rejectReason?: string rejectReason?: string
...@@ -419,8 +365,8 @@ interface Order { ...@@ -419,8 +365,8 @@ interface Order {
interface BusinessRule { interface BusinessRule {
id: string id: string
businessCode: string businessCode: string
businessName: string jobName: string
estimatedReward: number preMoney: number
status: string status: string
createTime: string createTime: string
updateTime?: string updateTime?: string
...@@ -442,12 +388,41 @@ const emit = defineEmits<{ ...@@ -442,12 +388,41 @@ const emit = defineEmits<{
}>() }>()
// 响应式数据 // 响应式数据
const crmOrderNumber = ref(props.order.crmOrderNumber || '') const crmOrderId = ref(props.order.crmOrderId || '')
const processRemark = ref(props.order.processRemark || '') const processRemark = ref(props.order.processRemark || '')
const actualReward = ref( const realMoney = ref(
props.order.actualReward !== undefined ? String(props.order.actualReward) : '' props.order.realMoney !== undefined ? String(props.order.realMoney) : ''
) )
onMounted(()=>{
queryLog()
})
const logData = ref([])
const queryLog = async ()=>{
try {
try {
const response = await $api.queryOrderLog({
id: props.order.id
})
if (response.c === 0) {
response.d.forEach(item=>{
item.detail = JSON.parse(item.parameter)
})
logData.value = response.d
} else {
ElMessage.error(response.m)
}
} catch (error) {
}
} catch (error) {
}
}
// 对话框状态 // 对话框状态
const isRejectDialogOpen = ref(false) const isRejectDialogOpen = ref(false)
const rejectReason = ref('') const rejectReason = ref('')
...@@ -456,100 +431,114 @@ const closeReason = ref('') ...@@ -456,100 +431,114 @@ const closeReason = ref('')
// 计算属性 // 计算属性
const canEditCompleteInfo = computed(() => { const canEditCompleteInfo = computed(() => {
return (props.order.businessStatus === '待办理' || props.order.businessStatus === '办理成功') && let p = props.order
props.order.reviewStatus !== '审核通过' &&
props.order.reviewStatus !== '待审核' return p.status==='-1' || (p.status==='1' && p.auditStatus!=='0' && p.auditStatus!=='1')
}) })
const canEditReward = computed(() => { const canEditReward = computed(() => {
return (props.order.businessStatus === '待办理' || props.order.businessStatus === '办理成功') && let p = props.order
props.order.reviewStatus !== '审核通过'
return p.status==='1' && p.auditStatus!=='0' && p.auditStatus!=='1'
}) })
// 方法 // 方法
// 状态样式映射 - 使用浅色背景样式(与订单监控页保持一致) // 状态样式映射 - 使用浅色背景样式(与订单监控页保持一致)
const getBusinessStatusClass = (status: BusinessStatus) => { const getstatusClass = (status: status) => {
const statusMap = { const statusMap = {
'待办理': 'bg-blue-100 text-blue-800', '-1': 'bg-blue-100 text-blue-800',
'办理成功': 'bg-green-100 text-green-800', '1': 'bg-green-100 text-green-800',
'已关闭': 'bg-gray-100 text-gray-800' '0': 'bg-gray-100 text-gray-800'
} }
return statusMap[status] || 'bg-gray-100 text-gray-800' return statusMap[status] || 'bg-gray-100 text-gray-800'
} }
const getstatusName = (status: status) => {
const statusMap = {
'-1': '待办理',
'1': '办理成功',
'0': '已关闭'
}
return statusMap[status] || '--'
}
const getReviewStatusClass = (status: ReviewStatus) => { const getauditStatusClass = (status: auditStatus) => {
const statusMap = { const statusMap = {
'待审核': 'bg-purple-100 text-purple-800', '0': 'bg-purple-100 text-purple-800',
'审核通过': 'bg-green-100 text-green-800', '1': 'bg-green-100 text-green-800',
'审核驳回': 'bg-orange-100 text-orange-800' '2': 'bg-orange-100 text-orange-800'
} }
return statusMap[status] || 'bg-gray-100 text-gray-800' return statusMap[status] || 'bg-gray-100 text-gray-800'
} }
const getauditStatusName = (status: auditStatus) => {
const statusMap = {
'0': '待审核',
'1': '审核通过',
'2': '审核驳回'
}
return statusMap[status] || '--'
}
// 待办理状态提交审核
const handleSaveCompleteInfo = () => { // crm保存
if (!crmOrderNumber.value.trim()) { const handleSaveCrm = async ()=>{
if (!crmOrderId.value.trim()) {
ElMessage.error('请填写CRM订单编号') ElMessage.error('请填写CRM订单编号')
return return
} }
const currentTime = new Date().toLocaleString('zh-CN') const response = await $api.updateOrderCrm({
id: props.order.id,
// 自动关联业务规则,获取预计酬金 crmOrderId: crmOrderId.value,
const businessRule = props.businessRules.find(rule => memo: processRemark.value
rule.businessName === props.order.businessName && rule.status === '生效中' })
)
// 实际发放酬金为选填项,未填写则使用预计酬金 if(response.c === 0){
let finalAmount = businessRule?.estimatedReward || 0 ElMessage.success('保存成功')
setTimeout(() => {
if (actualReward.value && actualReward.value.trim()) { emit('back')
const amount = parseFloat(actualReward.value) }, 1000)
}else{
ElMessage.error(response.m)
}
}
const handleSaveReward = async () => {
if (realMoney.value && realMoney.value.trim()) {
const amount = parseFloat(realMoney.value)
if (isNaN(amount) || amount < 0) { if (isNaN(amount) || amount < 0) {
ElMessage.error('请输入有效的实际发放酬金') ElMessage.error('请输入有效的实际发放酬金')
return return
} }
finalAmount = amount
}
const newLog = {
id: `LOG${Date.now()}`,
time: currentTime,
operator: '管理员',
action: '提交审核',
details: `CRM订单编号:${crmOrderNumber.value},提交给主管理员审核,实际发放酬金:¥${finalAmount.toFixed(2)}`
} }
emit('update', { const response = await $api.updateOrderMoney({
crmOrderNumber: crmOrderNumber.value, list: [{
processRemark: processRemark.value.trim(), id: props.order.id,
completeTime: currentTime, realMoney: realMoney.value
businessStatus: '办理成功', }]
reviewStatus: '待审核',
estimatedReward: businessRule?.estimatedReward,
actualReward: finalAmount,
rejectReason: undefined,
operationLogs: [...(props.order.operationLogs || []), newLog]
}) })
ElMessage.success('已提交审核,等待主管理员审核') if(response.c === 0){
ElMessage.success('提交成功')
setTimeout(() => {
emit('back')
}, 1000)
}else{
ElMessage.error(response.m)
}
setTimeout(() => {
emit('back')
}, 1000)
} }
// 提交审核(办理成功/审核驳回 → 待审核) // 提交审核(办理成功/审核驳回 → 待审核)
const handleSubmitReview = () => { const handleSubmitReview = () => {
if (!crmOrderNumber.value.trim()) { if (!crmOrderId.value.trim()) {
ElMessage.error('请填写CRM订单编号') ElMessage.error('请填写CRM订单编号')
return return
} }
let finalAmount = props.order.estimatedReward || 0 let finalAmount = props.order.preMoney || 0
if (actualReward.value && actualReward.value.trim()) { if (realMoney.value && realMoney.value.trim()) {
const amount = parseFloat(actualReward.value) const amount = parseFloat(realMoney.value)
if (isNaN(amount) || amount < 0) { if (isNaN(amount) || amount < 0) {
ElMessage.error('请输入有效的实际发放酬金') ElMessage.error('请输入有效的实际发放酬金')
return return
...@@ -562,14 +551,14 @@ const handleSubmitReview = () => { ...@@ -562,14 +551,14 @@ const handleSubmitReview = () => {
time: new Date().toLocaleString('zh-CN'), time: new Date().toLocaleString('zh-CN'),
operator: '管理员', operator: '管理员',
action: '提交审核', action: '提交审核',
details: `CRM订单编号:${crmOrderNumber.value},提交给主管理员审核,实际发放酬金:¥${finalAmount.toFixed(2)}` details: `CRM订单编号:${crmOrderId.value},提交给主管理员审核,实际发放酬金:¥${finalAmount.toFixed(2)}`
} }
emit('update', { emit('update', {
crmOrderNumber: crmOrderNumber.value, crmOrderId: crmOrderId.value,
processRemark: processRemark.value.trim(), processRemark: processRemark.value.trim(),
reviewStatus: '待审核', auditStatus: '0',
actualReward: finalAmount, realMoney: finalAmount,
rejectReason: undefined, rejectReason: undefined,
operationLogs: [...(props.order.operationLogs || []), newLog] operationLogs: [...(props.order.operationLogs || []), newLog]
}) })
...@@ -589,11 +578,11 @@ const handleApprove = () => { ...@@ -589,11 +578,11 @@ const handleApprove = () => {
time: currentTime, time: currentTime,
operator: '主管理员', operator: '主管理员',
action: '审核通过', action: '审核通过',
details: `主管审核通过,金额:¥${props.order.actualReward?.toFixed(2)}` details: `主管审核通过,金额:¥${props.order.realMoney?.toFixed(2)}`
} }
emit('update', { emit('update', {
reviewStatus: '审核通过', auditStatus: '1',
paymentTime: currentTime, paymentTime: currentTime,
operationLogs: [...(props.order.operationLogs || []), newLog] operationLogs: [...(props.order.operationLogs || []), newLog]
}) })
...@@ -621,7 +610,7 @@ const handleReject = () => { ...@@ -621,7 +610,7 @@ const handleReject = () => {
} }
emit('update', { emit('update', {
reviewStatus: '审核驳回', auditStatus: '2',
rejectReason: rejectReason.value, rejectReason: rejectReason.value,
operationLogs: [...(props.order.operationLogs || []), newLog] operationLogs: [...(props.order.operationLogs || []), newLog]
}) })
...@@ -636,33 +625,29 @@ const handleReject = () => { ...@@ -636,33 +625,29 @@ const handleReject = () => {
} }
// 关闭订单 // 关闭订单
const handleClose = () => { const handleClose = async () => {
if (!closeReason.value.trim()) { if (!closeReason.value.trim()) {
ElMessage.error('请填写关闭原因') ElMessage.error('请填写关闭原因')
return return
} }
const newLog = { const response = await $api.closeOrder({
id: `LOG${Date.now()}`, id: props.order.id,
time: new Date().toLocaleString('zh-CN'), memo: closeReason.value
operator: '管理员',
action: '关闭订单',
details: `关闭原因:${closeReason.value}`
}
emit('update', {
businessStatus: '已关闭',
closeReason: closeReason.value,
operationLogs: [...(props.order.operationLogs || []), newLog]
}) })
ElMessage.success('订单已关闭') if(response.c === 0){
isCloseDialogOpen.value = false
closeReason.value = '' ElMessage.success('订单已关闭')
isCloseDialogOpen.value = false
setTimeout(() => { closeReason.value = ''
emit('back')
}, 1000) setTimeout(() => {
emit('back')
}, 1000)
}else{
ElMessage.error(response.m)
}
} }
const handleAuditCommand = (command: string) => { const handleAuditCommand = (command: string) => {
......
...@@ -32,11 +32,21 @@ ...@@ -32,11 +32,21 @@
<el-card> <el-card>
<div class="flex items-center gap-2 w-full p-6"> <div class="flex items-center gap-2 w-full p-6">
<!-- 搜索框 --> <!-- 搜索框 -->
<div class="relative flex-[2]"> <div class="relative" style="width: 200px;">
<Search class="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-neutral-500 z-10" /> <Search class="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-neutral-500 z-10" />
<el-input <el-input
v-model="searchKeyword" v-model="customerPhone"
placeholder="输入订单ID、CRM订单编号、能人手机号、客户号码搜索" placeholder="客户号码"
class="search-input text-ellipsis-input"
clearable
/>
</div>
<div class="relative" style="width: 200px;">
<Search class="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-neutral-500 z-10" />
<el-input
v-model="chinaPersonPhone"
placeholder="登记人手机号"
class="search-input text-ellipsis-input" class="search-input text-ellipsis-input"
clearable clearable
/> />
...@@ -57,28 +67,28 @@ ...@@ -57,28 +67,28 @@
<!-- 全部业务状态 --> <!-- 全部业务状态 -->
<el-select v-model="businessStatusFilter" placeholder="全部业务状态" class="flex-1 bg-gray-100"> <el-select v-model="businessStatusFilter" placeholder="全部业务状态" class="flex-1 bg-gray-100">
<el-option label="全部业务状态" value="all" /> <el-option label="全部业务状态" value="" />
<el-option label="待办理" value="待办理" /> <el-option label="待办理" value="-1" />
<el-option label="办理成功" value="办理成功" /> <el-option label="办理成功" value="1" />
<el-option label="已关闭" value="已关闭" /> <el-option label="已关闭" value="0" />
</el-select> </el-select>
<!-- 全部审核状态 --> <!-- 全部审核状态 -->
<el-select v-model="reviewStatusFilter" placeholder="全部审核状态" class="flex-1 bg-gray-100"> <el-select v-model="reviewStatusFilter" placeholder="全部审核状态" class="flex-1 bg-gray-100">
<el-option label="全部审核状态" value="all" /> <el-option label="全部审核状态" value="" />
<el-option label="待审核" value="待审核" /> <el-option label="待审核" value="0" />
<el-option label="审核通过" value="审核通过" /> <el-option label="审核通过" value="1" />
<el-option label="审核驳回" value="审核驳回" /> <el-option label="审核驳回" value="2" />
</el-select> </el-select>
<!-- 全部业务 --> <!-- 全部业务 -->
<el-select v-model="businessNameFilter" placeholder="全部业务" class="flex-1 bg-gray-100"> <el-select v-model="businessNameFilter" placeholder="全部业务" class="flex-1 bg-gray-100">
<el-option label="全部业务" value="all" /> <el-option label="全部业务" value="" />
<el-option <el-option
v-for="businessName in uniqueBusinessNames" v-for="businessName in uniqueBusinessNames"
:key="businessName" :key="businessName.jobId"
:label="businessName" :label="businessName.jobName"
:value="businessName" :value="businessName.jobId"
/> />
</el-select> </el-select>
...@@ -113,80 +123,77 @@ ...@@ -113,80 +123,77 @@
</el-table-column> </el-table-column>
<!-- 能人 --> <!-- 能人 -->
<el-table-column prop="registerPersonName" label="能人" width="70" /> <el-table-column prop="chinaPersonName" label="能人" width="70" />
<!-- 能人手机号 --> <!-- 能人手机号 -->
<el-table-column prop="registerPersonPhone" label="能人手机号" width="110" show-overflow-tooltip> <el-table-column prop="chinaPersonPhone" label="能人手机号" width="130" show-overflow-tooltip>
<template #default="{ row }"> <template #default="{ row }">
<span class="font-mono">{{ row.registerPersonPhone }}</span> <span class="font-mono">{{ row.chinaPersonPhone }}</span>
</template> </template>
</el-table-column> </el-table-column>
<!-- 客户号码 --> <!-- 客户号码 -->
<el-table-column prop="customerPhone" label="客户号码" width="110" show-overflow-tooltip> <el-table-column prop="customerPhone" label="客户号码" width="130" show-overflow-tooltip>
<template #default="{ row }"> <template #default="{ row }">
<span class="font-mono">{{ row.customerPhone }}</span> <span class="font-mono">{{ row.customerPhone }}</span>
</template> </template>
</el-table-column> </el-table-column>
<!-- 业务名称 --> <!-- 业务名称 -->
<el-table-column prop="businessName" label="业务名称" min-width="100" /> <el-table-column prop="jobName" label="业务名称" min-width="100" />
<!-- 登记时间 --> <!-- 登记时间 -->
<el-table-column prop="registerTime" label="登记时间" width="140" show-overflow-tooltip /> <el-table-column prop="createTime" label="登记时间" min-width="140" show-overflow-tooltip>
<!-- 预计酬金 -->
<el-table-column prop="estimatedReward" label="预计酬金" width="90" align="right">
<template #default="{ row }"> <template #default="{ row }">
<span class="font-mono">¥{{ row.estimatedReward.toFixed(2) }}</span> <span class="font-mono">{{ $utils.detailTime(row.createTime) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<!-- 实际酬金 --> <!-- 预计酬金 -->
<el-table-column prop="actualReward" label="实际酬金" width="90" align="right"> <el-table-column prop="preMoney" label="预计酬金" width="90" align="right">
<template #default="{ row }"> <template #default="{ row }">
<span v-if="row.actualReward" class="font-mono">¥{{ row.actualReward.toFixed(2) }}</span> <span v-if="row.preMoney" class="font-mono">¥{{ row.preMoney }}</span>
<span v-else class="text-neutral-400">-</span> <span v-else class="text-neutral-400">--</span>
</template> </template>
</el-table-column> </el-table-column>
<!-- CRM订单编号 --> <!-- 实际酬金 -->
<el-table-column prop="crmOrderNumber" label="CRM订单编号" min-width="120" show-overflow-tooltip> <el-table-column prop="realMoney" label="实际酬金" width="90" align="right">
<template #default="{ row }"> <template #default="{ row }">
<span v-if="row.crmOrderNumber" class="font-mono text-[14px]">{{ row.crmOrderNumber }}</span> <span v-if="row.realMoney" class="font-mono">¥{{ row.realMoney }}</span>
<span v-else class="text-neutral-400">-</span> <span v-else class="text-neutral-400">--</span>
</template> </template>
</el-table-column> </el-table-column>
<!-- 办结登记时间 --> <!-- CRM订单编号 -->
<el-table-column prop="completeTime" label="办结登记时间" min-width="140" show-overflow-tooltip> <el-table-column prop="crmOrderId" label="CRM订单编号" min-width="120" show-overflow-tooltip>
<template #default="{ row }"> <template #default="{ row }">
<span v-if="row.completeTime">{{ row.completeTime }}</span> <span v-if="row.crmOrderId" class="font-mono text-[14px]">{{ row.crmOrderId }}</span>
<span v-else class="text-neutral-400">-</span> <span v-else class="text-neutral-400">--</span>
</template> </template>
</el-table-column> </el-table-column>
<!-- 业务状态 --> <!-- 业务状态 -->
<el-table-column prop="businessStatus" label="业务状态" width="90" fixed="right"> <el-table-column prop="status" label="业务状态" width="90" fixed="right">
<template #default="{ row }"> <template #default="{ row }">
<span <span
:class="getBusinessStatusClass(row.businessStatus)" :class="getBusinessStatusClass(row.status)"
class="px-2 py-1 rounded text-xs font-medium" class="px-2 py-1 rounded text-xs font-medium"
> >
{{ row.businessStatus }} {{ getBusinessStatusName(row.status) }}
</span> </span>
</template> </template>
</el-table-column> </el-table-column>
<!-- 审核状态 --> <!-- 审核状态 -->
<el-table-column prop="reviewStatus" label="审核状态" width="90" fixed="right"> <el-table-column prop="auditStatus" label="审核状态" width="90" fixed="right">
<template #default="{ row }"> <template #default="{ row }">
<span <span
v-if="row.reviewStatus" v-if="row.auditStatus"
:class="getReviewStatusClass(row.reviewStatus)" :class="getReviewStatusClass(row.auditStatus)"
class="px-2 py-1 rounded text-xs font-medium" class="px-2 py-1 rounded text-xs font-medium"
> >
{{ row.reviewStatus }} {{ getReviewStatusName(row.auditStatus) }}
</span> </span>
<span v-else class="text-neutral-400">-</span> <span v-else class="text-neutral-400">-</span>
</template> </template>
...@@ -205,7 +212,7 @@ ...@@ -205,7 +212,7 @@
详情 详情
</el-button> </el-button>
<el-button <el-button
v-if="row.reviewStatus === '待审核'" v-if="row.auditStatus === 0"
type="primary" type="primary"
link link
size="small" size="small"
...@@ -222,15 +229,15 @@ ...@@ -222,15 +229,15 @@
<!-- 分页 --> <!-- 分页 -->
<div class="flex justify-between items-center mt-4 py-3 px-6"> <div class="flex justify-between items-center mt-4 py-3 px-6">
<div class="text-sm text-neutral-600"> <div class="text-sm text-neutral-600">
{{ filteredOrders.length }} 条数据,当前第 {{ currentPage }}/{{ totalPages }} {{ totalElements }} 条数据,当前第 {{ currentPage }}/{{ totalPages }}
<span v-if="selectedOrderIds.length > 0" class="ml-2"> <span v-if="selectedOrderIds.length > 0" class="ml-2">
,已选择 {{ selectedOrderIds.length }} ,已选择 {{ selectedOrderIds.length }}
</span> </span>
</div> </div>
<div class="flex items-center gap-4"> <div class="flex items-center gap-4">
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<span class="text-sm text-neutral-600">每页条数</span> <span class="text-sm text-neutral-600" style="width: 60px;">每页条数</span>
<el-select v-model="pageSize" class="w-[180px]" size="small" @change="handlePageSizeChange"> <el-select v-model="pageSize" class="w-[180px]" style="width: 90px;" size="small" @change="handlePageSizeChange">
<el-option label="10 条/页" :value="10" /> <el-option label="10 条/页" :value="10" />
<el-option label="20 条/页" :value="20" /> <el-option label="20 条/页" :value="20" />
<el-option label="50 条/页" :value="50" /> <el-option label="50 条/页" :value="50" />
...@@ -240,7 +247,7 @@ ...@@ -240,7 +247,7 @@
<el-pagination <el-pagination
v-model:current-page="currentPage" v-model:current-page="currentPage"
:page-size="pageSize" :page-size="pageSize"
:total="filteredOrders.length" :total="totalElements"
layout="prev, pager, next" layout="prev, pager, next"
small small
@current-change="handleCurrentChange" @current-change="handleCurrentChange"
...@@ -251,9 +258,7 @@ ...@@ -251,9 +258,7 @@
<!-- 审核对话框 --> <!-- 审核对话框 -->
<el-dialog v-model="isReviewDialogOpen" title="订单审核" width="600px" class="single-review-dialog"> <el-dialog v-model="isReviewDialogOpen" title="订单审核" width="600px" class="single-review-dialog">
<div v-if="reviewingOrder" class="space-y-4"> <div class="space-y-4">
<div class="grid grid-cols-2 gap-6"> <div class="grid grid-cols-2 gap-6">
<!-- 左列 --> <!-- 左列 -->
<div class="space-y-4"> <div class="space-y-4">
...@@ -263,15 +268,15 @@ ...@@ -263,15 +268,15 @@
</div> </div>
<div class="flex items-center"> <div class="flex items-center">
<label class="text-sm text-neutral-500 shrink-0">能人</label> <label class="text-sm text-neutral-500 shrink-0">能人</label>
<p class="text-sm text-neutral-900" style="margin-left: 16px;">{{ reviewingOrder.registerPersonName }}</p> <p class="text-sm text-neutral-900" style="margin-left: 16px;">{{ reviewingOrder.chinaPersonName }}</p>
</div> </div>
<div class="flex items-center"> <div class="flex items-center">
<label class="text-sm text-neutral-500 shrink-0">CRM订单编号</label> <label class="text-sm text-neutral-500 shrink-0">CRM订单编号</label>
<p class="text-sm text-neutral-900 font-mono" style="margin-left: 16px;">{{ reviewingOrder.crmOrderNumber || '-' }}</p> <p class="text-sm text-neutral-900 font-mono" style="margin-left: 16px;">{{ reviewingOrder.crmOrderId || '-' }}</p>
</div> </div>
<div class="flex items-center"> <div class="flex items-center">
<label class="text-sm text-neutral-500 shrink-0">实际酬金</label> <label class="text-sm text-neutral-500 shrink-0">实际酬金</label>
<p class="text-sm font-mono text-green-600" style="margin-left: 16px;">¥{{ (reviewingOrder.actualReward || reviewingOrder.estimatedReward).toFixed(2) }}</p> <p class="text-sm font-mono text-green-600" style="margin-left: 16px;">¥{{ reviewingOrder.preMoney?.toFixed(2) || '--' }}</p>
</div> </div>
</div> </div>
...@@ -279,15 +284,15 @@ ...@@ -279,15 +284,15 @@
<div class="space-y-4"> <div class="space-y-4">
<div class="flex items-center"> <div class="flex items-center">
<label class="text-sm text-neutral-500 shrink-0">业务名称</label> <label class="text-sm text-neutral-500 shrink-0">业务名称</label>
<p class="text-sm text-neutral-900" style="margin-left: 16px;">{{ reviewingOrder.businessName }}</p> <p class="text-sm text-neutral-900" style="margin-left: 16px;">{{ reviewingOrder.jobName }}</p>
</div> </div>
<div class="flex items-center"> <div class="flex items-center">
<label class="text-sm text-neutral-500 shrink-0">客户号码</label> <label class="text-sm text-neutral-500 shrink-0">客户号码</label>
<p class="text-sm text-neutral-900 font-mono" style="margin-left: 16px;">{{ reviewingOrder.customerPhone }}</p> <p class="text-sm text-neutral-900 font-mono" style="margin-left: 16px;">{{ reviewingOrder.crmUserPhone }}</p>
</div> </div>
<div class="flex items-center"> <div class="flex items-center">
<label class="text-sm text-neutral-500 shrink-0">预计酬金</label> <label class="text-sm text-neutral-500 shrink-0">预计酬金</label>
<p class="text-sm font-mono text-blue-600" style="margin-left: 16px;">¥{{ reviewingOrder.estimatedReward.toFixed(2) }}</p> <p class="text-sm font-mono text-blue-600" style="margin-left: 16px;">¥{{ reviewingOrder.preMoney?.toFixed(2) || '--' }}</p>
</div> </div>
</div> </div>
</div> </div>
...@@ -434,8 +439,6 @@ ...@@ -434,8 +439,6 @@
</el-button> </el-button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
...@@ -545,10 +548,12 @@ ...@@ -545,10 +548,12 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue' import { ref, computed, onMounted, watch , getCurrentInstance} from 'vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { Download, Check, Edit3, Search, Upload, X } from 'lucide-vue-next' import { Download, Check, Edit3, Search, Upload, X } from 'lucide-vue-next'
const { $api,$utils } = getCurrentInstance()!.appContext.config.globalProperties
// Props // Props
interface Props { interface Props {
orders?: any[] orders?: any[]
...@@ -564,11 +569,12 @@ const props = withDefaults(defineProps<Props>(), { ...@@ -564,11 +569,12 @@ const props = withDefaults(defineProps<Props>(), {
const emit = defineEmits(['view-order-detail', 'update-order', 'orders-update']) const emit = defineEmits(['view-order-detail', 'update-order', 'orders-update'])
// 响应式数据 // 响应式数据
const searchKeyword = ref('') const customerPhone = ref('')
const chinaPersonPhone = ref('')
const dateRange = ref<[string, string] | null>(null) const dateRange = ref<[string, string] | null>(null)
const businessStatusFilter = ref('all') const businessStatusFilter = ref('')
const reviewStatusFilter = ref('all') const reviewStatusFilter = ref('')
const businessNameFilter = ref('all') const businessNameFilter = ref('')
const selectedOrderIds = ref<string[]>([]) const selectedOrderIds = ref<string[]>([])
const currentPage = ref(1) const currentPage = ref(1)
const pageSize = ref(20) const pageSize = ref(20)
...@@ -789,87 +795,65 @@ const generateMockOrders = (): Order[] => { ...@@ -789,87 +795,65 @@ const generateMockOrders = (): Order[] => {
} }
// 计算属性 // 计算属性
const uniqueBusinessNames = computed(() => { const uniqueBusinessNames = ref([])
return Array.from(new Set(orders.value.map(order => order.businessName))).sort() const totalPages = ref('')
}) const totalElements = ref('')
const paginatedOrders = ref([])
const filteredOrders = computed(() => {
return orders.value.filter(order => {
// 搜索关键词匹配
const matchSearch = !searchKeyword.value ||
order.id.includes(searchKeyword.value) ||
order.crmOrderNumber?.includes(searchKeyword.value) ||
order.registerPersonPhone.includes(searchKeyword.value) ||
order.customerPhone.includes(searchKeyword.value)
// 业务状态匹配
const matchBusinessStatus = businessStatusFilter.value === 'all' || order.businessStatus === businessStatusFilter.value
// 审核状态匹配
const matchReviewStatus = reviewStatusFilter.value === 'all' || order.reviewStatus === reviewStatusFilter.value
// 业务名称匹配
const matchBusinessName = businessNameFilter.value === 'all' || order.businessName === businessNameFilter.value
// 日期范围匹配
let matchDate = true
if (dateRange.value && dateRange.value.length === 2) {
const orderDate = new Date(order.registerTime.split(' ')[0])
const startDate = new Date(dateRange.value[0])
const endDate = new Date(dateRange.value[1])
matchDate = orderDate >= startDate && orderDate <= endDate
}
return matchSearch && matchBusinessStatus && matchReviewStatus && matchBusinessName && matchDate
})
})
const totalPages = computed(() => {
return Math.ceil(filteredOrders.value.length / pageSize.value)
})
const paginatedOrders = computed(() => {
const start = (currentPage.value - 1) * pageSize.value
const end = start + pageSize.value
return filteredOrders.value.slice(start, end)
})
// 状态样式映射 - 使用浅色背景样式 // 状态样式映射 - 使用浅色背景样式
const getBusinessStatusClass = (status: BusinessStatus) => { const getBusinessStatusClass = (status: BusinessStatus) => {
const statusMap = { const statusMap = {
'待办理': 'bg-blue-100 text-blue-800', '-1': 'bg-blue-100 text-blue-800',
'办理成功': 'bg-green-100 text-green-800', '1': 'bg-green-100 text-green-800',
'已关闭': 'bg-gray-100 text-gray-800' '0': 'bg-gray-100 text-gray-800'
} }
return statusMap[status] || 'bg-gray-100 text-gray-800' return statusMap[status] || 'bg-gray-100 text-gray-800'
} }
const getBusinessStatusName = (status: BusinessStatus) => {
const statusMap = {
'-1': '待办理',
'1': '办理成功',
'0': '已关闭'
}
return statusMap[status] || ''
}
const getReviewStatusClass = (status: ReviewStatus) => { const getReviewStatusClass = (status: ReviewStatus) => {
const statusMap = { const statusMap = {
'待审核': 'bg-purple-100 text-purple-800', '0': 'bg-purple-100 text-purple-800',
'审核通过': 'bg-green-100 text-green-800', '1': 'bg-green-100 text-green-800',
'审核驳回': 'bg-orange-100 text-orange-800' '2': 'bg-orange-100 text-orange-800'
} }
return statusMap[status] || 'bg-gray-100 text-gray-800' return statusMap[status] || 'bg-gray-100 text-gray-800'
} }
const getReviewStatusName = (status: ReviewStatus) => {
const statusMap = {
'0': '待审核',
'1': '审核通过',
'2': '审核驳回'
}
return statusMap[status] || '--'
}
// 判断行是否可选择(只有待审核的订单才能被选择) // 判断行是否可选择(只有待审核的订单才能被选择)
const isRowSelectable = (row: any) => { const isRowSelectable = (row: any) => {
return row.reviewStatus === '待审核' return row.auditStatus === 1
} }
// 事件处理 // 事件处理
const handleSearch = () => { const handleSearch = () => {
currentPage.value = 1 currentPage.value = 1
ElMessage.success('查询完成')
queryOrder()
} }
const handleReset = () => { const handleReset = () => {
searchKeyword.value = '' customerPhone.value = ''
chinaPersonPhone.value = ''
dateRange.value = null dateRange.value = null
businessStatusFilter.value = 'all' businessStatusFilter.value = ''
reviewStatusFilter.value = 'all' reviewStatusFilter.value = ''
businessNameFilter.value = 'all' businessNameFilter.value = ''
currentPage.value = 1 currentPage.value = 1
ElMessage.success('已重置筛选条件') ElMessage.success('已重置筛选条件')
} }
...@@ -906,11 +890,16 @@ const handleBatchModify = () => { ...@@ -906,11 +890,16 @@ const handleBatchModify = () => {
} }
const handleViewDetail = (order: any) => { const handleViewDetail = (order: any) => {
emit('view-order-detail', order) let param = {...order}
param.status += ''
param.auditStatus += ''
emit('view-order-detail', param)
} }
const handleApprove = (order: any) => { const handleApprove = (order: any) => {
reviewingOrder.value = order //reviewingOrder.value = order
isReviewDialogOpen.value = true isReviewDialogOpen.value = true
} }
...@@ -1067,10 +1056,14 @@ const handleConfirmBatchApprove = () => { ...@@ -1067,10 +1056,14 @@ const handleConfirmBatchApprove = () => {
const handlePageSizeChange = () => { const handlePageSizeChange = () => {
currentPage.value = 1 currentPage.value = 1
queryOrder()
} }
const handleCurrentChange = (page: number) => { const handleCurrentChange = (page: number) => {
currentPage.value = page currentPage.value = page
queryOrder()
} }
// 批量修改:模板下载 // 批量修改:模板下载
...@@ -1263,7 +1256,57 @@ onMounted(() => { ...@@ -1263,7 +1256,57 @@ onMounted(() => {
} else { } else {
orders.value = props.orders orders.value = props.orders
} }
queryOrder()
queryRule()
}) })
const queryRule = async ()=>{
try {
const response = await $api.queryAllRewardList({})
if (response.c === 0 && response.d) {
uniqueBusinessNames.value = response.d
} else {
}
} catch (error) {
}
}
const queryOrder = async ()=>{
try {
let start = ''
let end = ''
if(dateRange.value){
start = new Date(dateRange.value[0]).getTime()+''
end = (new Date(dateRange.value[1]).getTime()+24*60*60*1000-1)+''
}
const response = await $api.queryOrderList({
customerPhone: customerPhone.value,
chinaPersonPhone: chinaPersonPhone.value,
startTime: start,
endTime: end,
status: businessStatusFilter.value,
auditStatus: reviewStatusFilter.value,
jobId: businessNameFilter.value,
page: currentPage.value,
pageSize: pageSize.value
})
if(response.c === 0){
paginatedOrders.value = response.d.content
totalElements.value = response.d.totalElements
totalPages.value = response.d.totalPages
}else{
ElMessage.error(response.m)
}
} catch (error) {
}
}
// 监听props变化 // 监听props变化
watch(() => props.orders, (newOrders) => { watch(() => props.orders, (newOrders) => {
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!