添加 内勤 付款 财务收款 及统计 车辆加车系关键字采集
This commit is contained in:
@@ -0,0 +1,300 @@
|
||||
<template>
|
||||
<div class="stocking-page">
|
||||
<div class="stocking-toolbar boxshadow">
|
||||
<div class="toolbar-left"></div>
|
||||
<div class="toolbar-right">
|
||||
<el-input
|
||||
v-model="keyword"
|
||||
placeholder="请输入客户名称"
|
||||
clearable
|
||||
style="width: 260px"
|
||||
@keyup.enter="getList"
|
||||
>
|
||||
<template #suffix>
|
||||
<el-icon class="clickable" @click="getList"><Search /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="boxshadow">
|
||||
<el-tabs v-model="activeTab">
|
||||
<el-tab-pane label="未认领" name="not"></el-tab-pane>
|
||||
<el-tab-pane label="已认领" name="already"></el-tab-pane>
|
||||
<el-tab-pane label="超时未认领" name="timeout"></el-tab-pane>
|
||||
</el-tabs>
|
||||
<ArtTable
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:loading="loading"
|
||||
:data="tableData"
|
||||
:currentPage="pagination.currentPage"
|
||||
:pageSize="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:row-class-name="tableRowClassName"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn label="创建日期" prop="created_at" min-width="160" />
|
||||
<!-- <ElTableColumn label="付款来源" prop="country_name" min-width="120" /> -->
|
||||
<ElTableColumn label="汇款人" prop="remitter" min-width="120" />
|
||||
<ElTableColumn label="账户" prop="account_name" min-width="120" />
|
||||
<ElTableColumn label="账币" prop="currency_name" min-width="120" />
|
||||
<ElTableColumn label="金额" prop="amount" min-width="120" />
|
||||
<ElTableColumn label="计时" prop="amount" min-width="120">
|
||||
<template #default="scope">
|
||||
<span
|
||||
v-if="!scope.row.payment_apply_id"
|
||||
:class="getCountdownClass(scope.row.claim_timeout_time)"
|
||||
>
|
||||
<span class="custom-clock-icon" style="vertical-align: middle; margin-right: 4px">
|
||||
<i class="iconfont-sys"></i>
|
||||
</span>
|
||||
{{ getCountdown(scope.row.claim_timeout_time) }}
|
||||
</span>
|
||||
<span v-else class="countdown-success">已认领</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="操作" fixed="right" min-width="140" align="center">
|
||||
<template #default="scope">
|
||||
<ElRow :gutter="10" justify="center">
|
||||
<el-link
|
||||
type="primary"
|
||||
underline="never"
|
||||
@click="handleView(scope.row)"
|
||||
style="margin-right: 8px"
|
||||
>
|
||||
<i class="iconfont-sys"></i> 查看
|
||||
</el-link>
|
||||
<el-link
|
||||
v-if="!scope.row.payment_apply_id"
|
||||
type="success"
|
||||
underline="never"
|
||||
@click="handleClaim(scope.row)"
|
||||
>
|
||||
<i class="iconfont-sys"></i> 认领
|
||||
</el-link>
|
||||
</ElRow>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
</div>
|
||||
|
||||
<!-- 付款记录选择对话框 -->
|
||||
<PaymentRecordDialog
|
||||
v-model="paymentDialogVisible"
|
||||
:receipt-id="currentReceiptId"
|
||||
@confirm="handlePaymentRecordConfirm"
|
||||
/>
|
||||
<!-- 付款记录详情查看对话框 -->
|
||||
<ClaimRecordDetailDialog v-model="detailDialogVisible" :payment-id="currentPaymentId" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { manageService } from '@/api/adminApi'
|
||||
import { financeService } from '@/api/admin/finance'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { useAuth } from '@/composables/useAuth'
|
||||
import PaymentRecordDialog from '@/components/custom/PaymentRecordDialog.vue'
|
||||
import ClaimRecordDetailDialog from '@/components/custom/ClaimRecordDetailDialog.vue'
|
||||
import dayjs from 'dayjs'
|
||||
defineOptions({ name: 'Adminclaim' })
|
||||
const { hasAuth } = useAuth()
|
||||
const loading = ref(false)
|
||||
const keyword = ref('')
|
||||
const tableRef = ref()
|
||||
const tableData = ref<any[]>([])
|
||||
const pagination = reactive({ currentPage: 1, pageSize: 10, total: 0 })
|
||||
const activeTab = ref('not')
|
||||
const detailDialogVisible = ref(false)
|
||||
// 付款记录对话框相关
|
||||
const paymentDialogVisible = ref(false)
|
||||
const currentReceiptId = ref<string | number>('')
|
||||
watch([keyword], () => {
|
||||
pagination.currentPage = 1
|
||||
getList()
|
||||
// 不自动请求,保持与截图行为一致,点击搜索或回车触发
|
||||
})
|
||||
watch([activeTab], () => {
|
||||
pagination.currentPage = 1
|
||||
getList()
|
||||
})
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const { currentPage, pageSize } = pagination
|
||||
const params = {
|
||||
current: currentPage,
|
||||
size: pageSize,
|
||||
payment_apply: activeTab.value,
|
||||
keyword: keyword.value
|
||||
}
|
||||
|
||||
const { records, current, size, total } = await financeService.getReceiptList(params)
|
||||
tableData.value = records || []
|
||||
Object.assign(pagination, { currentPage: current, pageSize: size, total })
|
||||
} catch (error) {
|
||||
console.error('获取列表失败:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleSizeChange = (size: number) => {
|
||||
pagination.pageSize = size
|
||||
getList()
|
||||
}
|
||||
const handleCurrentChange = (page: number) => {
|
||||
pagination.currentPage = page
|
||||
getList()
|
||||
}
|
||||
const currentPaymentId = ref<string | number>('')
|
||||
const handleView = async (params: any) => {
|
||||
detailDialogVisible.value = true
|
||||
currentPaymentId.value = params.id
|
||||
await financeService.getReceiptDetail(params)
|
||||
}
|
||||
// 处理认领操作
|
||||
const handleClaim = (row: any) => {
|
||||
currentReceiptId.value = row.id
|
||||
paymentDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 处理付款记录确认绑定
|
||||
const handlePaymentRecordConfirm = async (paymentRecord: any) => {
|
||||
try {
|
||||
const params = {
|
||||
id: currentReceiptId.value,
|
||||
payment_apply_id: paymentRecord.id
|
||||
}
|
||||
|
||||
await financeService.bindPaymentRecord(params)
|
||||
ElMessage.success('认领成功')
|
||||
getList() // 刷新列表
|
||||
} catch (error) {
|
||||
console.error('认领失败:', error)
|
||||
ElMessage.error('认领失败,请稍后重试')
|
||||
}
|
||||
}
|
||||
|
||||
const handleDelete = () => {}
|
||||
const timer = ref(0)
|
||||
const refreshKey = ref(0)
|
||||
onMounted(() => {
|
||||
getList()
|
||||
timer.value = window.setInterval(() => {
|
||||
refreshKey.value++
|
||||
}, 1000)
|
||||
})
|
||||
function getCountdown(targetDate: string) {
|
||||
// 让 refreshKey 成为依赖,确保每秒刷新
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
||||
refreshKey.value
|
||||
const now = dayjs()
|
||||
const target = dayjs(targetDate, 'YYYY-MM-DD HH:mm:ss')
|
||||
if (!target.isValid()) return '时间格式错误'
|
||||
const diff = target.diff(now)
|
||||
if (diff <= 0) return '已超时'
|
||||
const days = Math.floor(diff / (1000 * 60 * 60 * 24))
|
||||
const hours = Math.floor((diff / (1000 * 60 * 60)) % 24)
|
||||
const minutes = Math.floor((diff / (1000 * 60)) % 60)
|
||||
const seconds = Math.floor((diff / 1000) % 60)
|
||||
return `${days > 0 ? days + '天' : ''}${hours}小时${minutes}分${seconds}秒`
|
||||
}
|
||||
|
||||
function getCountdownClass(targetDate: string) {
|
||||
const now = dayjs()
|
||||
const target = dayjs(targetDate, 'YYYY-MM-DD HH:mm:ss')
|
||||
if (!target.isValid() || target.diff(now) <= 0) {
|
||||
return 'countdown-danger'
|
||||
}
|
||||
return 'countdown-success'
|
||||
}
|
||||
const tableRowClassName = ({ row }: { row: any }) => {
|
||||
const flag = Number(row?.claim_timeout)
|
||||
return flag === 1 ? 'row-claim-timeout' : ''
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
:deep(.row-claim-timeout) {
|
||||
background-color: #ffc9c9 !important;
|
||||
}
|
||||
:deep(.el-tabs__nav-wrap:after){
|
||||
background: #fff;
|
||||
}
|
||||
.countdown-danger {
|
||||
color: #ff0000 !important;
|
||||
}
|
||||
|
||||
.countdown-success {
|
||||
color: #00a43f !important;
|
||||
}
|
||||
.avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 6px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.stocking-page {
|
||||
background: var(--art-main-bg-color);
|
||||
min-height: 100vh;
|
||||
}
|
||||
.stocking-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
padding: 12px 16px;
|
||||
background: var(--art-main-bg-color);
|
||||
}
|
||||
.toolbar-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.toolbar-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
// 创建收款记录 - 弹窗样式对齐设计图
|
||||
.receipt-dialog {
|
||||
.receipt-form {
|
||||
.el-form-item {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.upload-demo {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
// justify-content: flex-end;
|
||||
// border: 1px dashed #dcdfe6;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.avatarimg {
|
||||
width: 60px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
width: 200px;
|
||||
height: 40px;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
:deep(.receipt-dialog .el-dialog__footer) {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,832 @@
|
||||
<template>
|
||||
<div class="stocking-page">
|
||||
<div class="stocking-toolbar boxshadow">
|
||||
<div class="toolbar-left">
|
||||
<ElButton
|
||||
type="primary"
|
||||
v-ripple
|
||||
@click="handleCreate"
|
||||
v-if="hasAuth('receipt_records@add')"
|
||||
>
|
||||
创建收款记录
|
||||
</ElButton>
|
||||
</div>
|
||||
<div class="toolbar-right">
|
||||
<el-input
|
||||
v-model="keyword"
|
||||
placeholder="请输入客户名称"
|
||||
clearable
|
||||
style="width: 260px"
|
||||
@keyup.enter="getList"
|
||||
>
|
||||
<template #suffix>
|
||||
<el-icon class="clickable" @click="getList"><Search /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="boxshadow">
|
||||
<ArtTable
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:key="tableData.length"
|
||||
:loading="loading"
|
||||
:data="tableData"
|
||||
:currentPage="pagination.currentPage"
|
||||
:pageSize="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:row-class-name="tableRowClassName"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn label="创建日期" prop="created_at" min-width="140" />
|
||||
<!-- <ElTableColumn label="付款来源" prop="country_name" min-width="160" /> -->
|
||||
<ElTableColumn label="汇款人" prop="remitter" min-width="120" />
|
||||
<ElTableColumn label="账户" prop="account_short_desc" min-width="120" />
|
||||
<ElTableColumn label="币种" prop="currency_name" min-width="120" />
|
||||
<ElTableColumn label="金额" prop="amount" min-width="120" />
|
||||
<ElTableColumn label="折让金额(含手续费)" prop="discount_amount" min-width="120" />
|
||||
<ElTableColumn label="认领状态" prop="payment_apply_id" min-width="120">
|
||||
<template #default="scope">
|
||||
<span
|
||||
v-if="scope.row.payment_apply_id == 0 || scope.row.payment_apply_id == null"
|
||||
class="text-danger"
|
||||
>
|
||||
未认领
|
||||
</span>
|
||||
<span v-else class="text-success">已认领</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="入账" prop="id" min-width="120">
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.received_at">{{ scope.row.received_at }}</span>
|
||||
<el-button v-else type="primary" size="small" @click="handlebtn(scope.row)">
|
||||
确认入账
|
||||
</el-button>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="操作" fixed="right" min-width="180" align="center">
|
||||
<template #default="scope">
|
||||
<ElRow :gutter="10" justify="center">
|
||||
<el-link
|
||||
v-if="hasAuth('receipt_records@show')"
|
||||
type="primary"
|
||||
underline="never"
|
||||
@click="handleView(scope.row)"
|
||||
style="margin-right: 8px"
|
||||
>
|
||||
<i class="iconfont-sys"></i> 查看
|
||||
</el-link>
|
||||
<el-link
|
||||
v-if="hasAuth('receipt_records@update')"
|
||||
type="success"
|
||||
underline="never"
|
||||
@click="handleEdit(scope.row)"
|
||||
style="margin-right: 8px"
|
||||
>
|
||||
<i class="iconfont-sys"></i> 修改
|
||||
</el-link>
|
||||
<!-- <el-link
|
||||
v-if="hasAuth('receipt_records@destroy')"
|
||||
type="danger"
|
||||
underline="never"
|
||||
@click="handleDelete()"
|
||||
style="margin-right: 8px"
|
||||
>
|
||||
<i class="iconfont-sys"></i> 作废
|
||||
</el-link> -->
|
||||
<el-link
|
||||
v-if="hasAuth('receipt_records@history')"
|
||||
type="warning"
|
||||
underline="never"
|
||||
@click="handleHistory(scope.row)"
|
||||
>
|
||||
<i class="iconfont-sys"></i> 历史记录
|
||||
</el-link>
|
||||
</ElRow>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
</div>
|
||||
|
||||
<!-- 新建/编辑收款记录 - 通用弹窗 -->
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:title="isEdit ? '编辑收款记录' : '创建收款记录'"
|
||||
width="900px"
|
||||
class="receipt-dialog"
|
||||
>
|
||||
<el-form
|
||||
ref="createFormRef"
|
||||
:model="form"
|
||||
:rules="createRules"
|
||||
label-width="180px"
|
||||
class="receipt-form"
|
||||
>
|
||||
<ElRow :gutter="12" class="item-row-wrap">
|
||||
<!-- <ElCol :sm="24" :md="12" :lg="12">
|
||||
<el-form-item label="付款来源">
|
||||
<el-select v-model="form.country_id" placeholder="请选择付款国家">
|
||||
<el-option
|
||||
v-for="item in countryOptions"
|
||||
:key="item.id"
|
||||
:label="item.cn_addrs"
|
||||
:value="item.id"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</ElCol> -->
|
||||
<ElCol :sm="24" :md="12" :lg="12">
|
||||
<el-form-item label="汇款人">
|
||||
<el-input v-model="form.remitter" placeholder="请填写汇款人" />
|
||||
</el-form-item>
|
||||
</ElCol>
|
||||
<ElCol :sm="24" :md="12" :lg="12">
|
||||
<el-form-item label="收款账户">
|
||||
<el-select v-model="form.account_id" placeholder="请选择收款账户">
|
||||
<el-option
|
||||
v-for="item in accountOptions"
|
||||
:key="item.id"
|
||||
:label="item.short_desc"
|
||||
:value="item.id"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</ElCol>
|
||||
<ElCol :sm="24" :md="12" :lg="12">
|
||||
<el-form-item label="币种">
|
||||
<el-select v-model="form.currency_id" placeholder="请选择币种">
|
||||
<el-option
|
||||
v-for="item in currencyOptions"
|
||||
:key="item.id"
|
||||
:label="item.currency_name"
|
||||
:value="item.id"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</ElCol>
|
||||
<ElCol :sm="24" :md="12" :lg="12">
|
||||
<el-form-item label="金额">
|
||||
<el-input v-model="form.amount" placeholder="请填写金额" />
|
||||
</el-form-item>
|
||||
</ElCol>
|
||||
<ElCol :sm="24" :md="12" :lg="12">
|
||||
<el-form-item label="到账时间">
|
||||
<el-date-picker
|
||||
v-model="form.arrived_at"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
type="date"
|
||||
placeholder="请选择到账时间"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</ElCol>
|
||||
<!-- <ElCol :sm="24" :md="12" :lg="12">
|
||||
<el-form-item label="折让金额">
|
||||
<el-input v-model="form.discount_amount" placeholder="请填写折让金额" />
|
||||
</el-form-item>
|
||||
</ElCol> -->
|
||||
<ElCol :sm="24" :md="12" :lg="12" v-if="isEdit">
|
||||
<el-form-item label="收汇凭证号">
|
||||
<el-input v-model="form.voucher_no" placeholder="请填写收汇凭证号" />
|
||||
</el-form-item>
|
||||
</ElCol>
|
||||
<!-- <ElCol :sm="24" :md="12" :lg="12">
|
||||
<el-form-item label="实际汇率(出纳)">
|
||||
<el-input v-model="form.exchange_rate" placeholder="请填写实际汇率" />
|
||||
</el-form-item>
|
||||
</ElCol> -->
|
||||
<ElCol :sm="24" :md="12" :lg="12">
|
||||
<el-form-item label="总金额(人民币)实际汇率">
|
||||
<el-input
|
||||
v-model="form.total_amount_cny"
|
||||
placeholder="请填写总金额(人民币)实际汇率"
|
||||
/>
|
||||
</el-form-item>
|
||||
</ElCol>
|
||||
<ElCol :sm="24" :md="12" :lg="12">
|
||||
<el-form-item label="是否转回内地">
|
||||
<el-radio-group v-model="form.is_domestic_return">
|
||||
<el-radio :label="0">否</el-radio>
|
||||
<el-radio :label="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</ElCol>
|
||||
<ElCol :sm="24" :md="24" :lg="24">
|
||||
<el-form-item label="外汇到账回单(出纳)">
|
||||
<el-upload
|
||||
class="upload-demo"
|
||||
:action="actionImageUplode"
|
||||
:headers="uploadHeaders"
|
||||
:on-success="handleUploadSuccess1"
|
||||
:show-file-list="false"
|
||||
:multiple="true"
|
||||
>
|
||||
<img :src="imageUrl1" alt="" class="avatarimg" />
|
||||
<input type="hidden" v-model="form.fx_receipt_file" />
|
||||
</el-upload>
|
||||
<div
|
||||
v-if="Array.isArray(form.fx_receipt_file) && form.fx_receipt_file.length"
|
||||
style="margin-top: 8px"
|
||||
>
|
||||
<div
|
||||
v-for="(u, i) in form.fx_receipt_file"
|
||||
:key="i"
|
||||
style="display: flex; align-items: center; gap: 8px; margin-bottom: 6px"
|
||||
>
|
||||
<img
|
||||
v-if="
|
||||
/\.(png|jpe?g|gif|webp|bmp|svg)(\?|$)/i.test(
|
||||
(u.file_full || '').split('?')[0]
|
||||
)
|
||||
"
|
||||
:src="u.file_full"
|
||||
style="
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
object-fit: cover;
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--el-border-color);
|
||||
"
|
||||
/>
|
||||
<a
|
||||
v-else
|
||||
:href="u.file_full"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
style="
|
||||
flex: 1;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: 200px;
|
||||
"
|
||||
>{{ u.file_name }}</a
|
||||
>
|
||||
<el-button link type="danger" @click="removeVoucher(i)" style="width: 80px"
|
||||
>移除</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<el-button type="primary" @click="handleSubmit">提交</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
v-model="dialogVisibleshow"
|
||||
title="查看收款记录"
|
||||
width="900px"
|
||||
class="receipt-dialog"
|
||||
>
|
||||
<div class="info-grid">
|
||||
<div class="info-item">
|
||||
<label>创建日期:</label>
|
||||
<span>{{ formshow.created_at }}</span>
|
||||
</div>
|
||||
<!-- <div class="info-item">
|
||||
<label>付款来源:</label>
|
||||
<span>{{ formshow.country_name || '—' }}</span>
|
||||
</div> -->
|
||||
<div class="info-item">
|
||||
<label>汇款人:</label>
|
||||
<span>{{ formshow.remitter || '—' }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>账户:</label>
|
||||
<span>{{ formshow.account_name || '—' }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>币种:</label>
|
||||
<span>{{ formshow.currency_name || '—' }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>金额:</label>
|
||||
<span class="amount">{{ formshow.amount }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>到账时间:</label>
|
||||
<span>{{ formshow.arrived_at || '—' }}</span>
|
||||
</div>
|
||||
<!-- <div class="info-item">
|
||||
<label>折让金额:</label>
|
||||
<span>{{ formshow.discount_amount || '—' }}</span>
|
||||
</div> -->
|
||||
<div class="info-item">
|
||||
<label>收汇凭证号:</label>
|
||||
<span>{{ formshow.voucher_no || '—' }}</span>
|
||||
</div>
|
||||
<!-- <div class="info-item">
|
||||
<label>实际汇率(出纳):</label>
|
||||
<span>{{ formshow.exchange_rate || '—' }}</span>
|
||||
</div> -->
|
||||
<div class="info-item">
|
||||
<label>总金额(人民币)实际汇率:</label>
|
||||
<span>{{ formshow.total_amount_cny || '—' }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>是否转回内地:</label>
|
||||
<span>{{ formshow.is_domestic_return == 1 ? '是' : '否' }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>外汇到账回单:</label>
|
||||
<div>
|
||||
<p v-for="(item, index) in formshow.fx_receipt_file" :key="index">
|
||||
<el-image
|
||||
v-if="
|
||||
/\.(png|jpe?g|gif|webp|bmp|svg)(\?|$)/i.test((item.file_full || '').split('?')[0])
|
||||
"
|
||||
:src="item.file_full"
|
||||
:preview-src-list="item.file_full ? [item.file_full] : []"
|
||||
style="width: 100px; height: 100px"
|
||||
/>
|
||||
<a
|
||||
v-else
|
||||
:href="item.file_full"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
style="
|
||||
flex: 1;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: 200px;
|
||||
"
|
||||
>{{ item.file_name }}</a
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- 历史记录 -->
|
||||
<el-dialog
|
||||
v-model="timelineDialogVisible"
|
||||
title="历史记录"
|
||||
width="600px"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
class="approval-dialog"
|
||||
>
|
||||
<div class="approval-content">
|
||||
<!-- 头部信息 -->
|
||||
<Timeline :records="approvalRecords" />
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { commonService } from '@/api/commonApi'
|
||||
import { financeService } from '@/api/admin/finance'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { useAuth } from '@/composables/useAuth'
|
||||
import imageUrl1 from '@/assets/img/crm/upimg.png'
|
||||
import { useUploadHeaders } from '@/composables/useUploadHeaders'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
const Timeline = defineAsyncComponent(() => import('@/components/custom/Timeline.vue'))
|
||||
const { uploadHeaders } = useUploadHeaders()
|
||||
let actionImageUplode = `${import.meta.env.VITE_API_URL}/ticket/upload?scene=receipt_records`
|
||||
defineOptions({ name: 'AdminReceiptRecords' })
|
||||
const approvalRecords = ref<any[]>([])
|
||||
const { hasAuth } = useAuth()
|
||||
const loading = ref(false)
|
||||
const dialogVisibleshow = ref(false)
|
||||
const timelineDialogVisible = ref(false)
|
||||
const keyword = ref('')
|
||||
const tableRef = ref()
|
||||
const tableData = ref<any[]>([])
|
||||
const pagination = reactive({ currentPage: 1, pageSize: 10, total: 0 })
|
||||
//国家
|
||||
const countryOptions = ref<any[]>([])
|
||||
const fetchCountryOptions = async () => {
|
||||
try {
|
||||
const res = await commonService.getCountrySelect()
|
||||
res.forEach((item: any) => {
|
||||
item.cn_addrs = item.cn_addr + '(' + item.en_addr + ')'
|
||||
})
|
||||
countryOptions.value = res || []
|
||||
} catch {
|
||||
countryOptions.value = []
|
||||
}
|
||||
}
|
||||
//账户
|
||||
const accountOptions = ref<any[]>([])
|
||||
const fetchAccountOptions = async () => {
|
||||
try {
|
||||
const res = await commonService.getAccountSelect()
|
||||
accountOptions.value = res || []
|
||||
} catch {
|
||||
accountOptions.value = []
|
||||
}
|
||||
}
|
||||
//币种
|
||||
const currencyOptions = ref<any[]>([])
|
||||
const fetchCurrencyOptions = async () => {
|
||||
try {
|
||||
const res = await commonService.getCurrencySelect()
|
||||
currencyOptions.value = res || []
|
||||
} catch {
|
||||
currencyOptions.value = []
|
||||
}
|
||||
}
|
||||
|
||||
// 审批弹出框相关
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
|
||||
watch([keyword], () => {
|
||||
pagination.currentPage = 1
|
||||
getList()
|
||||
// 不自动请求,保持与截图行为一致,点击搜索或回车触发
|
||||
})
|
||||
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const { currentPage, pageSize } = pagination
|
||||
const params = {
|
||||
current: currentPage,
|
||||
size: pageSize,
|
||||
keyword: keyword.value
|
||||
}
|
||||
|
||||
const { records, current, size, total } = await financeService.getReceiptList(params)
|
||||
tableData.value = records || []
|
||||
Object.assign(pagination, { currentPage: current, pageSize: size, total })
|
||||
} catch (error) {
|
||||
console.error('获取列表失败:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
const tableRowClassName = ({ row }: { row: any }) => {
|
||||
const flag = Number(row?.claim_timeout)
|
||||
return flag === 1 ? 'row-claim-timeout' : ''
|
||||
}
|
||||
|
||||
const handleSizeChange = (size: number) => {
|
||||
pagination.pageSize = size
|
||||
getList()
|
||||
}
|
||||
const handleCurrentChange = (page: number) => {
|
||||
pagination.currentPage = page
|
||||
getList()
|
||||
}
|
||||
|
||||
// 新建/编辑弹窗通用状态
|
||||
const dialogVisible = ref(false)
|
||||
const createLoading = ref(false)
|
||||
const isEdit = ref(false)
|
||||
const currentId = ref<string | number | null>(null)
|
||||
const createFormRef = ref<FormInstance>()
|
||||
interface FileInfo {
|
||||
file_name?: string
|
||||
file_full?: string
|
||||
file_src?: string
|
||||
}
|
||||
const form = ref({
|
||||
remitter: '',
|
||||
account_id: '',
|
||||
currency_id: '',
|
||||
amount: '',
|
||||
arrived_at: new Date().toISOString().split('T')[0],
|
||||
voucher_no: '',
|
||||
total_amount_cny: '',
|
||||
is_domestic_return: 0,
|
||||
fx_receipt_file: [] as FileInfo[],
|
||||
fx_receipt_file_list: [] as object[]
|
||||
})
|
||||
const createRules: FormRules = {
|
||||
remitter: [{ required: true, message: '请输入汇款人', trigger: 'blur' }],
|
||||
account_id: [{ required: true, message: '请选择账户', trigger: 'change' }],
|
||||
currency_id: [{ required: true, message: '请选择币种', trigger: 'change' }]
|
||||
}
|
||||
const formshow = ref({
|
||||
created_at: '',
|
||||
country_name: '',
|
||||
remitter: '',
|
||||
account_name: '',
|
||||
currency_name: '',
|
||||
amount: '',
|
||||
arrived_at: '',
|
||||
voucher_no: '',
|
||||
total_amount_cny: '',
|
||||
is_domestic_return: 0,
|
||||
fx_receipt_file: [] as FileInfo[],
|
||||
fx_receipt_file_full: '',
|
||||
fx_receipt_file_list: [] as object[]
|
||||
})
|
||||
const resetCreateForm = () => {
|
||||
Object.assign(form.value, {
|
||||
remitter: '',
|
||||
account_id: '',
|
||||
currency_id: '',
|
||||
amount: '',
|
||||
arrived_at: new Date().toISOString().split('T')[0],
|
||||
voucher_no: '',
|
||||
total_amount_cny: '',
|
||||
is_domestic_return: 0,
|
||||
fx_receipt_file: [] as FileInfo[],
|
||||
fx_receipt_file_list: []
|
||||
})
|
||||
currentId.value = null
|
||||
createFormRef.value?.clearValidate?.()
|
||||
}
|
||||
|
||||
const handleCreate = async () => {
|
||||
resetCreateForm()
|
||||
isEdit.value = false
|
||||
fetchAccountOptions()
|
||||
fetchCurrencyOptions()
|
||||
fetchCountryOptions()
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
const handleSubmit = () => {
|
||||
createFormRef.value?.validate?.(async (valid: boolean) => {
|
||||
if (!valid) return
|
||||
try {
|
||||
createLoading.value = true
|
||||
// TODO: 根据新增/编辑调用对应接口
|
||||
if (isEdit.value) {
|
||||
const formData = { ...form.value }
|
||||
// if ('fx_receipt_file_list' in formData) {
|
||||
// delete formData.fx_receipt_file_list
|
||||
// }
|
||||
const forms = { ...formData, id: currentId.value }
|
||||
const { message } = await financeService.updateReceipt({
|
||||
remitter: forms.remitter,
|
||||
account_id: forms.account_id,
|
||||
currency_id: forms.currency_id,
|
||||
amount: forms.amount,
|
||||
arrived_at: forms.arrived_at,
|
||||
voucher_no: forms.voucher_no,
|
||||
total_amount_cny: forms.total_amount_cny,
|
||||
is_domestic_return: forms.is_domestic_return,
|
||||
fx_receipt_file: forms.fx_receipt_file,
|
||||
id: forms.id
|
||||
})
|
||||
ElMessage.success(message)
|
||||
} else {
|
||||
const formData = { ...form.value }
|
||||
const { message } = await financeService.addReceipt({
|
||||
remitter: formData.remitter,
|
||||
account_id: formData.account_id,
|
||||
currency_id: formData.currency_id,
|
||||
amount: formData.amount,
|
||||
arrived_at: formData.arrived_at,
|
||||
voucher_no: formData.voucher_no,
|
||||
total_amount_cny: formData.total_amount_cny,
|
||||
is_domestic_return: formData.is_domestic_return,
|
||||
fx_receipt_file: formData.fx_receipt_file
|
||||
})
|
||||
ElMessage.success(message)
|
||||
}
|
||||
dialogVisible.value = false
|
||||
getList()
|
||||
} finally {
|
||||
createLoading.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
const handleView = (row?: any) => {
|
||||
// const fx_receipt_file_full = []
|
||||
// if (row.fx_receipt_file_full) {
|
||||
// fx_receipt_file_full.push(row.fx_receipt_file_full)
|
||||
// }
|
||||
formshow.value = row
|
||||
// formshow.value.fx_receipt_file_list = fx_receipt_file_full
|
||||
dialogVisibleshow.value = true
|
||||
}
|
||||
const handleEdit = (row?: any) => {
|
||||
resetCreateForm()
|
||||
isEdit.value = true
|
||||
currentId.value = row?.id ?? null
|
||||
if (row && typeof row === 'object') {
|
||||
// form.value.country_id = row.country_id ?? form.value.country_id
|
||||
form.value.remitter = row.remitter ?? form.value.remitter
|
||||
form.value.account_id = row.account_id ?? form.value.account_id
|
||||
form.value.currency_id = row.currency_id ?? form.value.currency_id
|
||||
form.value.amount = row.amount ?? form.value.amount
|
||||
form.value.arrived_at = row.arrived_at ?? form.value.arrived_at
|
||||
// form.value.discount_amount = row.discount_amount ?? form.value.discount_amount
|
||||
form.value.voucher_no = row.voucher_no ?? form.value.voucher_no
|
||||
form.value.total_amount_cny = row.total_amount_cny ?? form.value.total_amount_cny
|
||||
// form.value.exchange_rate = row.exchange_rate ?? form.value.exchange_rate
|
||||
form.value.is_domestic_return = row.is_domestic_return ?? form.value.is_domestic_return
|
||||
form.value.fx_receipt_file = row.fx_receipt_file ?? form.value.fx_receipt_file
|
||||
form.value.fx_receipt_file_list = row.fx_receipt_file ?? form.value.fx_receipt_file
|
||||
|
||||
// const fx_receipt_file_full = []
|
||||
// if (row.fx_receipt_file_full) {
|
||||
// fx_receipt_file_full.push(row.fx_receipt_file_full)
|
||||
// }
|
||||
// form.value.fx_receipt_file_list = Array.isArray(fx_receipt_file_full)
|
||||
// ? fx_receipt_file_full
|
||||
// : form.value.fx_receipt_file_list
|
||||
}
|
||||
fetchAccountOptions()
|
||||
fetchCurrencyOptions()
|
||||
fetchCountryOptions()
|
||||
dialogVisible.value = true
|
||||
}
|
||||
const handlebtn = (row?: any) => {
|
||||
ElMessageBox.prompt('你是否确认入账?确认入账请填写入账实时汇率!', '入账', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
inputPattern: /^(?!\s*$).+/,
|
||||
inputErrorMessage: '请填写入账实时汇率'
|
||||
}).then(({ value }) => {
|
||||
console.log(value)
|
||||
financeService.confirmReceipt({ id: row.id, exchange_rate: value }).then((res) => {
|
||||
ElMessage.success(res.message)
|
||||
getList()
|
||||
})
|
||||
})
|
||||
}
|
||||
// const handleDelete = () => {
|
||||
// ElMessageBox.confirm('确定删除吗?', '提示', {
|
||||
// confirmButtonText: '确定',
|
||||
// cancelButtonText: '取消',
|
||||
// type: 'warning'
|
||||
// }).then(() => {
|
||||
// financeService.deleteReceipt({ id: currentId.value }).then((res) => {
|
||||
// ElMessage.success(res.message)
|
||||
// getList()
|
||||
// })
|
||||
// })
|
||||
// }
|
||||
const handleHistory = (row: any) => {
|
||||
financeService.getReceiptHistory({ receipt_id: row.id }).then((res) => {
|
||||
timelineDialogVisible.value = true
|
||||
approvalRecords.value = res.records || []
|
||||
// ElMessage.success(res.message)
|
||||
// getList()
|
||||
})
|
||||
|
||||
// history.push('/admin/finance/receipt_records_history')
|
||||
}
|
||||
// function handleUploadSuccess1(response: any) {
|
||||
// const fileName = response?.data?.file_name || ''
|
||||
// const fileUrl = response?.data?.file_url || response?.data?.full_url || response?.url || ''
|
||||
// form.value.fx_receipt_file = [form.value.fx_receipt_file, fileName].filter(Boolean).join(',')
|
||||
// const list = Array.isArray(form.value.fx_receipt_file_list)
|
||||
// ? form.value.fx_receipt_file_list
|
||||
// : []
|
||||
// list.push(fileUrl)
|
||||
// form.value.fx_receipt_file_list = [...list]
|
||||
// ElMessage.success(response.message)
|
||||
// }
|
||||
function handleUploadSuccess1(response: any) {
|
||||
const fileName = response?.data?.file_name || ''
|
||||
const fileUrl = response?.data?.file_url || response?.data?.full_url || response?.url || ''
|
||||
const names = Array.isArray(form.value.fx_receipt_file) ? [...form.value.fx_receipt_file] : []
|
||||
const files = ref({
|
||||
file_src: '',
|
||||
file_name: '',
|
||||
file_full: ''
|
||||
})
|
||||
files.value.file_src = fileName
|
||||
files.value.file_name = response?.data?.original_name || ''
|
||||
files.value.file_full = response?.data?.file_url || ''
|
||||
if (fileName) names.push(files.value)
|
||||
form.value.fx_receipt_file = names
|
||||
const list = Array.isArray(form.value.fx_receipt_file_list)
|
||||
? form.value.fx_receipt_file_list
|
||||
: []
|
||||
list.push(fileUrl)
|
||||
form.value.fx_receipt_file_list = [...list]
|
||||
ElMessage.success(response.message)
|
||||
}
|
||||
// 预览项移除(同步预览数组与提交字段)
|
||||
function removeVoucher(index: number) {
|
||||
// const list = Array.isArray(form.value.fx_receipt_file_list)
|
||||
// ? [...form.value.fx_receipt_file_list]
|
||||
// : []
|
||||
// if (index < 0 || index >= list.length) return
|
||||
// list.splice(index, 1)
|
||||
// form.value.fx_receipt_file_list = list
|
||||
// const names = (form.value.fx_receipt_file || '').split(',').filter(Boolean)
|
||||
// if (index < names.length) names.splice(index, 1)
|
||||
// form.value.fx_receipt_file = names.join(',')
|
||||
|
||||
const list = Array.isArray(form.value.fx_receipt_file_list)
|
||||
? [...form.value.fx_receipt_file_list]
|
||||
: []
|
||||
if (index < 0 || index >= list.length) return
|
||||
list.splice(index, 1)
|
||||
form.value.fx_receipt_file_list = list
|
||||
const names = Array.isArray(form.value.fx_receipt_file) ? [...form.value.fx_receipt_file] : []
|
||||
if (index < names.length) names.splice(index, 1)
|
||||
form.value.fx_receipt_file = names
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
:deep(.row-claim-timeout) {
|
||||
background-color: #ffc9c9 !important;
|
||||
}
|
||||
.avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 6px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.stocking-page {
|
||||
background: var(--art-main-bg-color);
|
||||
min-height: 100vh;
|
||||
}
|
||||
.stocking-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
padding: 12px 16px;
|
||||
background: var(--art-main-bg-color);
|
||||
}
|
||||
.toolbar-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.toolbar-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
// 创建收款记录 - 弹窗样式对齐设计图
|
||||
.receipt-dialog {
|
||||
.receipt-form {
|
||||
.el-form-item {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.upload-demo {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
// justify-content: flex-end;
|
||||
// border: 1px dashed #dcdfe6;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.avatarimg {
|
||||
width: 60px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
width: 200px;
|
||||
height: 40px;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
.info-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 16px;
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
// padding: 8px 0;
|
||||
|
||||
label {
|
||||
font-weight: 500;
|
||||
color: #666;
|
||||
min-width: 100px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #333;
|
||||
flex: 1;
|
||||
|
||||
&.amount {
|
||||
font-weight: 600;
|
||||
color: #3d7bff;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.receipt-dialog .el-dialog__footer) {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -42,7 +42,12 @@
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<div class="table-container boxshadow">
|
||||
<ElButton type="primary" v-ripple @click="handleAdd">新增车辆</ElButton>
|
||||
<div class="btntab">
|
||||
<ElButton type="primary" v-ripple @click="handleAdd">新增车辆</ElButton>
|
||||
<ElButton type="success" v-ripple @click="crawlKeywordfn"
|
||||
>通过车系名称查找抓取车辆</ElButton
|
||||
>
|
||||
</div>
|
||||
<ArtTable
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
@@ -988,14 +993,76 @@
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
<!-- 关键字 车型抓取弹出框 -->
|
||||
<ElDialog v-model="keywordDialogVisible" title="关键字-车型采集" width="900px" align-center>
|
||||
<div class="collect-models-container">
|
||||
<div style="display: flex; gap: 12px">
|
||||
<el-form-item label="关键字:" label-width="70px">
|
||||
<el-input
|
||||
v-model="carkeyword"
|
||||
placeholder="请输入关键字"
|
||||
clearable
|
||||
@keyup.enter="getcarkeyword"
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="getcarkeyword" v-ripple>采集</el-button>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="collect-models-content">
|
||||
<div v-if="modelLstLoading" class="loading-container">
|
||||
<ElLoading text="正在采集车型数据..." />
|
||||
</div>
|
||||
<div v-else-if="!modelLst || modelLst.length === 0" class="empty-container">
|
||||
<ElEmpty description="暂无车型数据" />
|
||||
</div>
|
||||
<div v-else class="models-table-container">
|
||||
<ElTable
|
||||
:data="modelLst"
|
||||
style="width: 100%"
|
||||
max-height="400"
|
||||
@selection-change="handleModelSelectionChange"
|
||||
>
|
||||
<ElTableColumn type="selection" width="55" />
|
||||
<ElTableColumn prop="brand_name" label="品牌" width="100" />
|
||||
<ElTableColumn prop="series_name" label="车系" width="120" />
|
||||
<ElTableColumn prop="title" label="车型名称" min-width="200" show-overflow-tooltip />
|
||||
<ElTableColumn prop="year" label="年款" width="80" />
|
||||
<ElTableColumn prop="msrp" label="指导价" width="120">
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.msrp" class="price-text">
|
||||
¥{{ formatPrice(scope.row.msrp) }}
|
||||
</span>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</ElTable>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="keywordclose">取消</ElButton>
|
||||
<ElButton
|
||||
type="primary"
|
||||
@click="saveKeywordModels"
|
||||
:disabled="selectedModels.length === 0"
|
||||
>
|
||||
保存选中车型 ({{ selectedModels.length }})
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus'
|
||||
import { vehicleService } from '@/api/vehicleApi'
|
||||
import { commonService } from '@/api/commonApi'
|
||||
defineOptions({ name: 'AdminVehicleList' })
|
||||
|
||||
// 搜索表单
|
||||
const searchForm = reactive({
|
||||
keyword: '',
|
||||
@@ -1233,7 +1300,77 @@
|
||||
pagination.currentPage = page
|
||||
getList()
|
||||
}
|
||||
|
||||
//抓取车辆
|
||||
const keywordDialogVisible = ref(false)
|
||||
const carkeyword = ref('')
|
||||
const keywordModelsData = ref<any>({})
|
||||
const modelLst = ref<any>([])
|
||||
const modelLstLoading = ref(false)
|
||||
const crawlKeywordfn = async () => {
|
||||
keywordDialogVisible.value = true
|
||||
carkeyword.value = ''
|
||||
keywordModelsData.value = {}
|
||||
modelLst.value = []
|
||||
}
|
||||
const keywordclose = () => {
|
||||
keywordDialogVisible.value = false
|
||||
carkeyword.value = ''
|
||||
keywordModelsData.value = {}
|
||||
modelLst.value = []
|
||||
}
|
||||
const handleModelSelectionChange = (selection: any[]) => {
|
||||
selectedModels.value = selection
|
||||
}
|
||||
const selectedModels = ref<any[]>([])
|
||||
const getcarkeyword = async () => {
|
||||
modelLstLoading.value = true
|
||||
selectedModels.value = []
|
||||
const loading = ElLoading.service({
|
||||
lock: true,
|
||||
text: 'Loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
try {
|
||||
const res = await commonService.getcrawlKeyword({ keyword: carkeyword.value })
|
||||
keywordModelsData.value = res
|
||||
modelLst.value = res.model
|
||||
console.log(modelLst.value)
|
||||
} finally {
|
||||
loading.close()
|
||||
modelLstLoading.value = false
|
||||
}
|
||||
}
|
||||
const saveKeywordModels = async () => {
|
||||
if (selectedModels.value.length === 0) {
|
||||
ElMessage.warning('请选择要保存的车型')
|
||||
return
|
||||
}
|
||||
await commonService.crawlModelCreate({
|
||||
series_id: keywordModelsData.value.series.id ? keywordModelsData.value.series.id : 0,
|
||||
brand_id: keywordModelsData.value.brand.id ? keywordModelsData.value.brand.id : 0,
|
||||
models: selectedModels.value
|
||||
})
|
||||
ElMessage.success(`成功保存 ${selectedModels.value.length} 个车型`)
|
||||
keywordDialogVisible.value = false
|
||||
getList()
|
||||
}
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
Object.keys(formData).forEach((key) => {
|
||||
if (key === 'is_active') {
|
||||
;(formData as any)[key] = 1
|
||||
} else if (key === 'currency') {
|
||||
;(formData as any)[key] = 'CNY'
|
||||
} else {
|
||||
;(formData as any)[key] = ''
|
||||
}
|
||||
})
|
||||
formRef.value?.clearValidate()
|
||||
// 重置选项数据
|
||||
modelsOptions.value = []
|
||||
seriesOptions.value = []
|
||||
brandOptions.value = []
|
||||
}
|
||||
// 新增车辆
|
||||
const handleAdd = async () => {
|
||||
dialogTitle.value = '新增车辆'
|
||||
@@ -1249,26 +1386,20 @@
|
||||
loadColorOptions()
|
||||
loadDictOptions()
|
||||
dialogTitle.value = '编辑车辆'
|
||||
|
||||
// 先清空表单和选项数据,避免监听器干扰
|
||||
resetForm()
|
||||
|
||||
// 使用 nextTick 确保 DOM 更新后再设置数据
|
||||
await nextTick()
|
||||
|
||||
// 设置表单数据
|
||||
Object.assign(formData, row)
|
||||
|
||||
// 立即检查车系名称是否被清空并重新设置
|
||||
setTimeout(() => {
|
||||
if (!formData.series_name) {
|
||||
formData.series_name = row.series_name
|
||||
}
|
||||
}, 1)
|
||||
|
||||
// 先加载品牌选项
|
||||
await loadBrandOptions()
|
||||
|
||||
// 如果品牌已选择,加载车系选项
|
||||
if (row.brand_code) {
|
||||
await loadSeriesOptions(row.brand_code)
|
||||
@@ -1281,7 +1412,6 @@
|
||||
await loadSeriesOptions(matchedBrand.brand_code)
|
||||
}
|
||||
}
|
||||
|
||||
// 如果车系已选择,加载车型选项
|
||||
if (row.series_code) {
|
||||
// 先尝试用原始的车系代码加载
|
||||
@@ -1305,7 +1435,6 @@
|
||||
await loadModelsOptions(matchedSeries.series_code)
|
||||
}
|
||||
}
|
||||
|
||||
// 如果仍然没有车型选项,但有车系信息,尝试再次加载
|
||||
if (modelsOptions.value.length === 0 && (row.series_code || row.series_name)) {
|
||||
// 使用当前表单中的车系代码重新加载
|
||||
@@ -1313,7 +1442,6 @@
|
||||
await loadModelsOptions(formData.series_code)
|
||||
}
|
||||
}
|
||||
|
||||
// 确保车系代码与车系名称匹配(在选项数据加载完成后)
|
||||
// 如果车系名称被清空,重新设置
|
||||
if (!formData.series_name && row.series_name) {
|
||||
@@ -1397,25 +1525,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
Object.keys(formData).forEach((key) => {
|
||||
if (key === 'is_active') {
|
||||
;(formData as any)[key] = 1
|
||||
} else if (key === 'currency') {
|
||||
;(formData as any)[key] = 'CNY'
|
||||
} else {
|
||||
;(formData as any)[key] = ''
|
||||
}
|
||||
})
|
||||
formRef.value?.clearValidate()
|
||||
|
||||
// 重置选项数据
|
||||
modelsOptions.value = []
|
||||
seriesOptions.value = []
|
||||
brandOptions.value = []
|
||||
}
|
||||
|
||||
// 提交表单
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
@@ -1456,18 +1565,15 @@
|
||||
ElMessage.warning('请先选择车系')
|
||||
return
|
||||
}
|
||||
|
||||
const matched = seriesOptions.value.find((s: any) => s.series_code === formData.series_code)
|
||||
if (!matched) {
|
||||
ElMessage.warning('未找到对应的车系信息')
|
||||
return
|
||||
}
|
||||
|
||||
currentCollectSeries.value = matched
|
||||
collectModelsDialogVisible.value = true
|
||||
collectModelsData.value = []
|
||||
selectedModelId.value = ''
|
||||
|
||||
// 调用车型采集
|
||||
collectVehicleModels(matched)
|
||||
}
|
||||
@@ -1475,10 +1581,8 @@
|
||||
const collectVehicleModels = async (series: any) => {
|
||||
try {
|
||||
collectModelsLoading.value = true
|
||||
|
||||
// 调用后端接口获取车型数据
|
||||
const response = await vehicleService.collectVehicleModels({ brand_series_id: series.id })
|
||||
|
||||
// 后端返回的数据格式为数组
|
||||
collectModelsData.value = response || []
|
||||
selectedModelId.value = ''
|
||||
@@ -1582,7 +1686,6 @@
|
||||
() => formData.series_name,
|
||||
(newSeriesName, oldSeriesName) => {
|
||||
if (!newSeriesName) return
|
||||
|
||||
const matchedSeries = seriesOptions.value.find(
|
||||
(s: any) => s.series_name === newSeriesName || s.name === newSeriesName
|
||||
)
|
||||
@@ -1801,6 +1904,10 @@
|
||||
.table-container {
|
||||
background: var(--art-main-bg-color);
|
||||
}
|
||||
.btntab {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
// 表单样式
|
||||
.vehicle-form {
|
||||
|
||||
Reference in New Issue
Block a user