Commit 8e7e552c by 李宁

开发完成提交

1 parent 7ac0e431
......@@ -35,7 +35,7 @@ export function audioOrderList(data) {
}
/**
* 订单金额批量修改
* 订单金额批量修改:表格上传
* @returns {AxiosPromise}
*/
export function updateOrderListMoney(data) {
......
......@@ -129,7 +129,7 @@
<span class="text-neutral-900">{{ log.functionName }}</span>
<el-tag size="small" type="info">{{ log.operatorName }}</el-tag>
</div>
<p class="text-sm text-neutral-600 mb-1">{{ log.detail.memo }}</p>
<p class="text-sm text-neutral-600 mb-1">{{ log.detail.memo || log.detail.auditMemo}}</p>
<p class="text-xs text-neutral-500">{{ $utils.detailTime(log.createTime) }}</p>
</div>
</div>
......@@ -401,26 +401,22 @@ onMounted(()=>{
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)
})
response.d.forEach(item=>{
item.detail = JSON.parse(item.parameter)
})
logData.value = response.d
logData.value = response.d
} else {
ElMessage.error(response.m)
}
} catch (error) {
}
} catch (error) {
}
}
// 对话框状态
......@@ -571,57 +567,61 @@ const handleSubmitReview = () => {
}
// 审核通过
const handleApprove = () => {
const currentTime = new Date().toLocaleString('zh-CN')
const newLog = {
id: `LOG${Date.now()}`,
time: currentTime,
operator: '主管理员',
action: '审核通过',
details: `主管审核通过,金额:¥${props.order.realMoney?.toFixed(2)}`
}
emit('update', {
auditStatus: '1',
paymentTime: currentTime,
operationLogs: [...(props.order.operationLogs || []), newLog]
})
const handleApprove = async () => {
try {
const response = await $api.audioOrderList({
list:[{
id: props.order.id,
auditStatus: '1'
}]
})
if (response.c === 0) {
ElMessage.success('审核通过!')
ElMessage.success('审核通过!')
setTimeout(() => {
emit('back')
}, 1000)
setTimeout(() => {
emit('back')
}, 1000)
} else {
ElMessage.error(response.m)
}
} catch (error) {
}
}
// 审核驳回
const handleReject = () => {
const handleReject = async () => {
if (!rejectReason.value.trim()) {
ElMessage.error('请填写驳回原因')
return
}
const newLog = {
id: `LOG${Date.now()}`,
time: new Date().toLocaleString('zh-CN'),
operator: '主管理员',
action: '审核驳回',
details: `驳回原因:${rejectReason.value}`
try {
const response = await $api.audioOrderList({
list:[{
id: props.order.id,
auditStatus: '2',
auditMemo: rejectReason.value
}]
})
if (response.c === 0) {
ElMessage.success('已驳回订单')
isRejectDialogOpen.value = false
setTimeout(()=>{
rejectReason.value = ''
},0)
setTimeout(() => {
emit('back')
}, 1000)
} else {
ElMessage.error(response.m)
}
} catch (error) {
}
emit('update', {
auditStatus: '2',
rejectReason: rejectReason.value,
operationLogs: [...(props.order.operationLogs || []), newLog]
})
ElMessage.success('已驳回订单')
isRejectDialogOpen.value = false
rejectReason.value = ''
setTimeout(() => {
emit('back')
}, 1000)
}
// 关闭订单
......
......@@ -116,7 +116,7 @@
<el-table-column type="selection" width="50" :selectable="isRowSelectable" />
<!-- 订单ID -->
<el-table-column prop="id" label="订单ID" width="140" show-overflow-tooltip>
<el-table-column prop="id" label="订单ID" width="200" show-overflow-tooltip>
<template #default="{ row }">
<span class="font-mono text-[14px]">{{ row.id }}</span>
</template>
......@@ -276,7 +276,7 @@
</div>
<div class="flex items-center">
<label class="text-sm text-neutral-500 shrink-0">实际酬金</label>
<p class="text-sm font-mono text-green-600" style="margin-left: 16px;">¥{{ reviewingOrder.preMoney?.toFixed(2) || '--' }}</p>
<p class="text-sm font-mono text-green-600" style="margin-left: 16px;">¥{{ reviewingOrder.realMoney?.toFixed(2) || '--' }}</p>
</div>
</div>
......@@ -288,7 +288,7 @@
</div>
<div class="flex items-center">
<label class="text-sm text-neutral-500 shrink-0">客户号码</label>
<p class="text-sm text-neutral-900 font-mono" style="margin-left: 16px;">{{ reviewingOrder.crmUserPhone }}</p>
<p class="text-sm text-neutral-900 font-mono" style="margin-left: 16px;">{{ reviewingOrder.customerPhone }}</p>
</div>
<div class="flex items-center">
<label class="text-sm text-neutral-500 shrink-0">预计酬金</label>
......@@ -335,10 +335,10 @@
<div class="flex-1">
<p class="text-sm font-medium text-neutral-900">订单ID: {{ order.id }}</p>
<p class="text-xs text-neutral-600 mt-1">
业务类型:{{ order.businessName }} |
预计酬金:¥{{ order.estimatedReward.toFixed(2) }}
<span v-if="order.actualReward">
| 实际酬金:¥{{ order.actualReward.toFixed(2) }}
业务类型:{{ order.jobName }} |
预计酬金:¥{{ order.preMoney?.toFixed(2)||'--' }}
<span v-if="order.realMoney">
| 实际酬金:¥{{ order.realMoney.toFixed(2) }}
</span>
</p>
</div>
......@@ -451,25 +451,24 @@
</div>
<el-table :data="batchPreviewRows" height="260" border stripe>
<el-table-column prop="orderId" label="订单ID" min-width="160" />
<el-table-column prop="id" label="订单ID" min-width="160" />
<el-table-column prop="currentReward" label="当前酬金" width="100" align="right">
<template #default="{ row }">
<span class="font-mono">¥{{ Number(row.currentReward).toFixed(2) }}</span>
<span class="font-mono">¥{{ '--' }}</span>
</template>
</el-table-column>
<el-table-column prop="newReward" label="新酬金" width="100" align="right">
<el-table-column prop="realMoney" label="新酬金" width="100" align="right">
<template #default="{ row }">
<span class="font-mono">¥{{ Number(row.newReward).toFixed(2) }}</span>
<span class="font-mono">¥{{ Number(row.realMoney).toFixed(2) }}</span>
</template>
</el-table-column>
<el-table-column prop="remark" label="备注" min-width="140" show-overflow-tooltip />
<el-table-column prop="status" label="校验" width="80">
<template #default="{ row }">
<el-tag v-if="row.status === 'OK'" type="success" size="small">有效</el-tag>
<el-tag v-if="!row.memo" type="success" size="small">有效</el-tag>
<el-tag v-else type="danger" size="small">无效</el-tag>
</template>
</el-table-column>
<el-table-column prop="error" label="错误信息" min-width="180" show-overflow-tooltip />
<el-table-column prop="memo" label="错误信息" min-width="180" show-overflow-tooltip />
</el-table>
</div>
</div>
......@@ -837,13 +836,15 @@ const getReviewStatusName = (status: ReviewStatus) => {
// 判断行是否可选择(只有待审核的订单才能被选择)
const isRowSelectable = (row: any) => {
return row.auditStatus === 1
return row.auditStatus === 0
}
// 事件处理
const handleSearch = () => {
currentPage.value = 1
// 清空选中状态,防止按钮禁用问题
selectedOrderIds.value = []
queryOrder()
}
......@@ -862,8 +863,43 @@ const handleSelectionChange = (selection: any[]) => {
selectedOrderIds.value = selection.map(item => item.id)
}
const handleExport = () => {
ElMessage.success('导出功能开发中')
const handleExport = async () => {
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 res = await $api.exportOrderList({
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(res.type == 'blob') {
let fileJson = {
content: res.value,
fileType: 'xlsx',
fileName: '登记订单数据'
}
$utils.exportExcel(fileJson)
} else {
let errorText
try {
errorText = res.value.msg
} catch(e) {
errorText = '网络异常,请稍后重试'
}
ElMessage.error(errorText)
}
}
const handleBatchReview = () => {
......@@ -871,9 +907,10 @@ const handleBatchReview = () => {
ElMessage.error('请选择要审核的订单')
return
}
// 确保只对待审核的订单进行批量审核
const pendingOrders = orders.value.filter(order =>
selectedOrderIds.value.includes(order.id) && order.reviewStatus === '待审核'
const pendingOrders = paginatedOrders.value.filter(order =>
selectedOrderIds.value.includes(order.id) && order.auditStatus === 0
)
if (pendingOrders.length === 0) {
ElMessage.error('所选订单中没有待审核的订单')
......@@ -899,36 +936,37 @@ const handleViewDetail = (order: any) => {
}
const handleApprove = (order: any) => {
//reviewingOrder.value = order
reviewingOrder.value = order
isReviewDialogOpen.value = true
}
const handleConfirmApprove = () => {
const handleConfirmApprove = async () => {
if (reviewingOrder.value) {
const currentTime = new Date().toLocaleString('zh-CN')
const order = orders.value.find(o => o.id === reviewingOrder.value.id)
const order = paginatedOrders.value.find(o => o.id === reviewingOrder.value.id)
if (order) {
// 更新订单状态
order.reviewStatus = '审核通过'
order.paymentTime = currentTime
// 添加操作日志
if (!order.operationLogs) {
order.operationLogs = []
try {
const response = await $api.audioOrderList({
list:[{
id: order.id,
auditStatus: '1'
}]
})
if (response.c === 0) {
ElMessage.success(`订单 ${reviewingOrder.value.id} 审核通过`)
isReviewDialogOpen.value = false
setTimeout(()=>{
reviewingOrder.value = null
},0)
queryOrder()
} else {
ElMessage.error(response.m)
}
} catch (error) {
}
order.operationLogs.push({
id: `LOG${order.id}_${Date.now()}`,
time: currentTime,
operator: '主管理员',
action: '审核通过',
details: `主管审核通过,金额:¥${order.actualReward?.toFixed(2) || order.estimatedReward.toFixed(2)}`
})
emit('orders-update', orders.value)
}
ElMessage.success(`订单 ${reviewingOrder.value.id} 审核通过`)
isReviewDialogOpen.value = false
reviewingOrder.value = null
}
}
......@@ -937,121 +975,111 @@ const handleReject = () => {
isRejectDialogOpen.value = true
}
const handleConfirmReject = () => {
const handleConfirmReject = async() => {
if (!rejectReason.value.trim()) {
ElMessage.error('请填写驳回原因')
return
}
if (reviewingOrder.value) {
const currentTime = new Date().toLocaleString('zh-CN')
const order = orders.value.find(o => o.id === reviewingOrder.value.id)
const order = paginatedOrders.value.find(o => o.id === reviewingOrder.value.id)
if (order) {
// 更新订单状态
order.reviewStatus = '审核驳回'
order.rejectReason = rejectReason.value
// 添加操作日志
if (!order.operationLogs) {
order.operationLogs = []
try {
const response = await $api.audioOrderList({
list:[{
id: order.id,
auditStatus: '2',
auditMemo: rejectReason.value
}]
})
if (response.c === 0) {
ElMessage.success(`订单 ${reviewingOrder.value.id} 已驳回`)
isReviewDialogOpen.value = false
isRejectDialogOpen.value = false
setTimeout(()=>{
reviewingOrder.value = null
rejectReason.value = ''
},0)
queryOrder()
} else {
ElMessage.error(response.m)
}
} catch (error) {
}
order.operationLogs.push({
id: `LOG${order.id}_${Date.now()}`,
time: currentTime,
operator: '主管理员',
action: '审核驳回',
details: `驳回原因:${rejectReason.value}`
})
emit('orders-update', orders.value)
}
ElMessage.success(`订单 ${reviewingOrder.value.id} 已驳回`)
isReviewDialogOpen.value = false
isRejectDialogOpen.value = false
reviewingOrder.value = null
rejectReason.value = ''
}
}
const handleConfirmBatchReject = () => {
const handleConfirmBatchReject = async () => {
if (batchReviewOrders.value.length === 0) {
ElMessage.error('没有待审核的订单')
return
}
const currentTime = new Date().toLocaleString('zh-CN')
let rejectCount = 0
let list = []
batchReviewOrders.value.forEach(order => {
const orderInList = orders.value.find(o => o.id === order.id)
if (orderInList && orderInList.reviewStatus === '待审核') {
orderInList.reviewStatus = '审核驳回'
orderInList.rejectReason = '批量审核驳回'
if (!orderInList.operationLogs) {
orderInList.operationLogs = []
}
orderInList.operationLogs.push({
id: `LOG${orderInList.id}_${Date.now()}_${Math.random()}`,
time: currentTime,
operator: '主管理员',
action: '审核驳回',
details: '批量审核驳回:未通过主管复核'
})
rejectCount++
}
list.push({
id: order.id,
auditStatus: '2',
auditMemo: batchRejectReason.value
})
})
selectedOrderIds.value = []
batchReviewOrders.value = []
isBatchReviewDialogOpen.value = false
batchRejectReason.value = ''
showBatchRejectReason.value = false
emit('orders-update', orders.value)
ElMessage.success(`成功批量驳回 ${rejectCount} 个订单`)
const response = await $api.audioOrderList({
list: list
})
if (response.c === 0) {
ElMessage.success(`成功批量驳回 ${batchReviewOrders.value.length} 个订单`)
isBatchReviewDialogOpen.value = false
showBatchRejectReason.value = false
setTimeout(() => {
selectedOrderIds.value = []
batchReviewOrders.value = []
batchRejectReason.value = ''
}, 0);
queryOrder()
} else {
ElMessage.error(response.m)
}
}
const handleConfirmBatchApprove = () => {
const handleConfirmBatchApprove = async () => {
if (batchReviewOrders.value.length === 0) {
ElMessage.error('没有待审核的订单')
return
}
const currentTime = new Date().toLocaleString('zh-CN')
let successCount = 0
let list = []
batchReviewOrders.value.forEach(order => {
const orderInList = orders.value.find(o => o.id === order.id)
if (orderInList && orderInList.reviewStatus === '待审核') {
// 更新订单状态
orderInList.reviewStatus = '审核通过'
orderInList.paymentTime = currentTime
// 添加操作日志
if (!orderInList.operationLogs) {
orderInList.operationLogs = []
}
orderInList.operationLogs.push({
id: `LOG${orderInList.id}_${Date.now()}_${Math.random()}`,
time: currentTime,
operator: '主管理员',
action: '审核通过',
details: `主管批量审核通过,金额:¥${orderInList.actualReward?.toFixed(2) || orderInList.estimatedReward.toFixed(2)}`
})
successCount++
}
list.push({
id: order.id,
auditStatus: '1'
})
})
const response = await $api.audioOrderList({
list: list
})
// 清空选择
selectedOrderIds.value = []
batchReviewOrders.value = []
isBatchReviewDialogOpen.value = false
emit('orders-update', orders.value)
ElMessage.success(`成功批量审核通过 ${successCount} 个订单`)
if (response.c === 0) {
ElMessage.success(`成功批量审核通过 ${batchReviewOrders.value.length} 个订单`)
isBatchReviewDialogOpen.value = false
setTimeout(() => {
selectedOrderIds.value = []
batchReviewOrders.value = []
}, 0);
queryOrder()
} else {
ElMessage.error(response.m)
}
}
const handlePageSizeChange = () => {
......@@ -1068,19 +1096,21 @@ const handleCurrentChange = (page: number) => {
// 批量修改:模板下载
const downloadBatchTemplate = () => {
const header = ['订单ID', '当前酬金', '新酬金', '备注']
const sample = [
['ORD20251107XXX', '50.00', '55.00', '调整酬金'],
['ORD20251107YYY', '30.00', '35.00', '补贴']
]
const lines = [header, ...sample].map(cols => cols.join(',')).join('\n')
const blob = new Blob([lines], { type: 'text/csv;charset=utf-8;' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = '批量修改模板.csv'
a.click()
URL.revokeObjectURL(url)
try {
// 创建下载链接
const link = document.createElement('a')
// 使用相对路径,确保本地和线上都能正常访问
link.href = './static/file/order_tem.xlsx'
link.download = '批量修改酬金模板.xlsx'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
ElMessage.success('模板下载成功')
} catch (error) {
console.error('下载模板失败:', error)
ElMessage.error('模板下载失败,请稍后重试')
}
}
// 批量修改:重置状态
......@@ -1114,71 +1144,18 @@ const parseCsv = (text: string): string[][] => {
}
// 校验并映射为预览行
const buildPreviewRows = (rows: string[][]) => {
const header = rows[0] || []
const body = rows.slice(1)
const getIndex = (name: string) => header.findIndex(h => h.replace(/\s/g, '') === name)
const idxOrderId = getIndex('订单ID')
const idxCurrent = getIndex('当前酬金')
const idxNew = getIndex('新酬金')
const idxRemark = getIndex('备注')
const buildPreviewRows = (list:any[]) => {
const preview: any[] = []
const valid: any[] = []
const invalid: any[] = []
if (idxOrderId === -1 || idxNew === -1) {
ElMessage.error('模板列缺失,请使用系统模板:需要包含 订单ID、新酬金')
return { preview, valid, invalid }
}
const maxCount = 100
if (body.length > maxCount) {
ElMessage.warning(`仅解析前 ${maxCount} 条记录,其余将忽略`)
}
const limitRows = body.slice(0, maxCount)
limitRows.forEach((cols, i) => {
const orderId = cols[idxOrderId] || ''
const newRewardStr = cols[idxNew] || ''
const remark = idxRemark >= 0 ? (cols[idxRemark] || '') : ''
const order = orders.value.find(o => o.id === orderId)
const currentReward = order?.actualReward ?? order?.estimatedReward
let status = 'OK'
let error = ''
if (!orderId) {
status = 'ERROR'
error = '订单ID为空'
} else if (!order) {
status = 'ERROR'
error = '订单不存在'
}
list.forEach(item=>{
preview.push(item)
const newReward = Number(newRewardStr)
if (Number.isNaN(newReward)) {
status = 'ERROR'
error = error ? `${error}; 新酬金非数字` : '新酬金非数字'
} else if (newReward < 0 || newReward > 1000) {
status = 'ERROR'
error = error ? `${error}; 新酬金需在0~1000之间` : '新酬金需在0~1000之间'
}
const row = {
orderId,
currentReward: currentReward ?? '',
newReward: Number.isNaN(newReward) ? '' : newReward,
remark,
status,
error
}
preview.push(row)
if (status === 'OK') {
valid.push(row)
} else {
invalid.push(row)
if(item.memo){
invalid.push(item)
}else{
valid.push(item)
}
})
......@@ -1186,36 +1163,72 @@ const buildPreviewRows = (rows: string[][]) => {
}
// 上传变更
const handleBatchFileChange = (file: any) => {
const handleBatchFileChange = async (file: any) => {
if (!file?.raw) return
const raw: File = file.raw
batchFileName.value = raw.name
const reader = new FileReader()
reader.onload = () => {
const text = String(reader.result || '')
const rows = parseCsv(text)
const { preview, valid, invalid } = buildPreviewRows(rows)
batchPreviewRows.value = preview
batchValidRows.value = valid
batchInvalidRows.value = invalid
batchParseDone.value = true
if (valid.length === 0) {
ElMessage.warning('未检测到有效记录,请检查文件内容')
}
// 验证文件大小(2MB)
const maxSize = 2 * 1024 * 1024
if (raw.size > maxSize) {
ElMessage.error('文件大小超过2MB限制,请压缩后重新上传')
return
}
// 验证文件格式
const fileName = raw.name.toLowerCase()
if (!fileName.endsWith('.csv') && !fileName.endsWith('.xlsx')) {
ElMessage.error('目前仅支持 csv和xlsx 格式的文件')
return
}
reader.onerror = () => {
batchFileName.value = raw.name
try {
const fd = new FormData()
fd.append('file', raw)
const response = await $api.updateOrderListMoney(fd)
if(response.c === 0){
const { preview, valid, invalid } = buildPreviewRows(response.d.list)
batchPreviewRows.value = preview
batchValidRows.value = valid
batchInvalidRows.value = invalid
batchParseDone.value = true
if (valid.length === 0) {
ElMessage.warning('未检测到有效记录,请检查文件内容')
}
}else{
ElMessage.error(response.m)
}
} catch (error) {
ElMessage.error('读取文件失败,请重试')
}
reader.readAsText(raw, 'utf-8')
}
const closeBatchDialog = () => {
isBatchModifyDialogOpen.value = false
}
const openVerifyDialog = () => {
isVerifyDialogOpen.value = true
const openVerifyDialog = async () => {
const response = await $api.updateOrderMoney({
list: batchPreviewRows.value
})
if(response.c === 0){
ElMessage.success(`成功修改 ${batchPreviewRows.value.length} 个订单`)
isVerifyDialogOpen.value = false
isBatchModifyDialogOpen.value = false
setTimeout(()=>{
resetBatchState()
},0)
queryOrder()
}else{
ElMessage.error(response.m)
}
}
// 执行变更(演示校验码:123456)
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!