<script setup lang="tsx">
|
import type { DataTableColumns, FormInst } from 'naive-ui'
|
import { NButton, NEllipsis, NSpace } from 'naive-ui'
|
import { onActivated, watch } from 'vue'
|
import { useRouter } from 'vue-router'
|
import dayjs from 'dayjs'
|
import { useBoolean } from '@/hooks'
|
import { downloadFile } from '@/utils'
|
import { batchOperation, batchSetElectronic, deleteVehicle, exportVehicleExcel, getVehicleById, getVehicleImportTemplate, getVehiclePageList, importVehicleExcel } from '@/service/api/vehicle'
|
import { fetchElectronicFenceAreaList } from '@/service/api/point'
|
import SearchPanel from '@/components/custom/SearchPanel.vue'
|
import OperationLogModal from '@/components/custom/OperationLogModal.vue'
|
import CompleteVehicleInfoModal from './components/CompleteVehicleInfoModal.vue'
|
import EditVehicleModal from './components/EditVehicleModal.vue'
|
import ConfirmDialog from '@/components/ConfirmDialog/index.vue'
|
|
const router = useRouter()
|
const dialog = useDialog()
|
const { bool: loading, setTrue: startLoading, setFalse: endLoading } = useBoolean(false)
|
|
const initialModel = {
|
vehicleCode: '', // 车辆编码
|
plateNumber: '', // 车牌号
|
vehicleVin: '', // VIN码
|
status: null, // 状态
|
entryTime: null, // 入库时间
|
vehicleAttribute: null, // 车辆属性
|
}
|
const model = ref({ ...initialModel })
|
|
const count = ref(0)
|
const listData = ref<any[]>([])
|
const pagination = reactive({
|
page: 1,
|
pageSize: 10,
|
})
|
|
function handleResetSearch() {
|
model.value = { ...initialModel }
|
pagination.page = 1
|
pagination.pageSize = 10
|
handleSearch()
|
}
|
|
function handleSearch() {
|
pagination.page = 1
|
getVehicleList()
|
}
|
|
// 车辆状态选项
|
const vehicleStatusOptions = [
|
{ label: '待完善信息', value: '1' },
|
{ label: '待运营', value: '2' },
|
{ label: '保险/年检过期', value: '3' },
|
]
|
|
// 车辆属性选项
|
const vehicleAttributeOptions = [
|
{ label: '测试', value: 1 },
|
{ label: '运营', value: 2 },
|
]
|
|
const isVehicleStatusSelectOpen = ref(false)
|
const isVehicleAttributeSelectOpen = ref(false)
|
|
const filterItems = computed(() => [
|
{
|
label: '车辆编码',
|
path: 'vehicleCode',
|
render: () => <n-input v-model:value={model.value.vehicleCode} placeholder="请输入车辆编码" />,
|
},
|
{
|
label: '车牌号',
|
path: 'plateNumber',
|
render: () => <n-input v-model:value={model.value.plateNumber} placeholder="请输入车牌号" />,
|
},
|
{
|
label: 'VIN码',
|
path: 'vehicleVin',
|
render: () => <n-input v-model:value={model.value.vehicleVin} placeholder="请输入VIN码" />,
|
},
|
{
|
label: '状态',
|
path: 'status',
|
render: () => (
|
<n-select
|
v-model:value={model.value.status}
|
options={vehicleStatusOptions}
|
clearable
|
placeholder="请选择状态"
|
onUpdate:show={(val: any) => isVehicleStatusSelectOpen.value = val}
|
>
|
{{
|
arrow: () => (
|
<img
|
src="https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/e120f81c-9f15-4e1a-9938-22252898edf9.png"
|
class={`arrow-icon ${isVehicleStatusSelectOpen.value ? 'arrow-icon--open' : ''}`}
|
style={{ width: '16px', height: '16px' }}
|
alt="arrow"
|
/>
|
),
|
empty: () => (
|
<div class="flex-center">
|
<img
|
src="/src/assets/element-img/no-data.png"
|
style={{ width: '50%' }}
|
/>
|
</div>
|
),
|
}}
|
</n-select>
|
),
|
},
|
{
|
label: '入库时间',
|
path: 'entryTime',
|
render: () => (
|
<n-date-picker
|
v-model:value={model.value.entryTime}
|
type="daterange"
|
clearable
|
actions={[]}
|
format="yyyy/MM/dd"
|
close-on-select={true}
|
start-placeholder="开始时间"
|
end-placeholder="结束时间"
|
separator="-"
|
/>
|
),
|
},
|
{
|
label: '车辆属性',
|
path: 'vehicleAttribute',
|
render: () => (
|
<n-select
|
v-model:value={model.value.vehicleAttribute}
|
options={vehicleAttributeOptions}
|
clearable
|
placeholder="请选择车辆属性"
|
onUpdate:show={(val: any) => isVehicleAttributeSelectOpen.value = val}
|
>
|
{{
|
arrow: () => (
|
<img
|
src="https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/e120f81c-9f15-4e1a-9938-22252898edf9.png"
|
class={`arrow-icon ${isVehicleAttributeSelectOpen.value ? 'arrow-icon--open' : ''}`}
|
style={{ width: '16px', height: '16px' }}
|
alt="arrow"
|
/>
|
),
|
empty: () => (
|
<div class="flex-center">
|
<img
|
src="/src/assets/element-img/no-data.png"
|
style={{ width: '50%' }}
|
/>
|
</div>
|
),
|
}}
|
</n-select>
|
),
|
},
|
])
|
|
// 文件导入相关
|
const fileInputRef = ref<HTMLInputElement | null>(null)
|
|
// 状态映射
|
const statusMap: Record<string, { bgColor: string, color: string, text: string }> = {
|
1: { bgColor: '#FFF8E6', color: '#FF9000', text: '待完善信息' },
|
2: { bgColor: '#FFF8E6', color: '#FF9000', text: '待运营' },
|
3: { bgColor: '#FFECE6', color: '#E12F1F', text: '保险/年检过期' },
|
}
|
|
// 运营区域选项
|
const operationAreaOptions = ref<{ label: string, value: string | number }[]>([])
|
|
// 获取运营区域列表
|
async function getOperationAreaList() {
|
try {
|
const { data } = await fetchElectronicFenceAreaList()
|
if (data) {
|
// 过滤出 areaType 为 1 的运营区域
|
operationAreaOptions.value = data
|
.filter((item: any) => item.areaType === 1)
|
.map((item: any) => ({
|
label: item.areaName,
|
value: item.electronicId,
|
}))
|
}
|
}
|
catch (error) {
|
console.error('获取运营区域失败:', error)
|
}
|
}
|
|
onMounted(() => {
|
getOperationAreaList()
|
})
|
|
// 设置运营区域弹窗
|
const showAreaModal = ref(false)
|
const areaFormRef = ref<FormInst | null>(null)
|
const areaFormModel = ref({
|
operationArea: null as string | null,
|
})
|
const selectedVehicles = ref<any[]>([])
|
const showOperationLogModal = ref(false)
|
|
// 完善车辆信息弹窗
|
const showCompleteInfoModal = ref(false)
|
const currentVehicle = ref<any>(null)
|
const infoModalType = ref<'complete' | 'update'>('complete') // complete: 完善信息, update: 更新信息
|
|
// 编辑车辆弹窗
|
const showEditModal = ref(false)
|
const editVehicle = ref<any>(null)
|
const editMode = ref<'add' | 'edit'>('edit')
|
|
// 通用二次确认对话框
|
const showConfirmDialog = ref(false)
|
const confirmDialogConfig = ref({
|
title: '',
|
description: '',
|
cancelText: '取消',
|
confirmText: '确定',
|
onConfirm: async () => {},
|
onCancel: () => {
|
showConfirmDialog.value = false
|
},
|
})
|
// 表单验证规则
|
const areaFormRules = {
|
operationArea: {
|
required: true,
|
message: '请选择运营区域',
|
trigger: ['blur', 'change'],
|
},
|
}
|
|
// 表格列定义
|
const columns = computed<DataTableColumns<any>>(() => [
|
{
|
type: 'selection',
|
width: 30,
|
fixed: 'left',
|
align: 'center',
|
},
|
{
|
title: '序号',
|
key: 'index',
|
fixed: 'left',
|
width: 60,
|
align: 'left',
|
resizable: true,
|
render: (row, index) => <span>{index + 1}</span>,
|
},
|
{
|
title: '车辆编码',
|
align: 'left',
|
width: 120,
|
key: 'vehicleCode',
|
ellipsis: true,
|
fixed: 'left',
|
resizable: true,
|
render: row => (
|
<NEllipsis style="width: 100%;cursor: pointer;" tooltip>
|
{row.vehicleCode || '-'}
|
</NEllipsis>
|
),
|
},
|
{
|
title: '车牌号',
|
align: 'left',
|
width: 120,
|
key: 'plateNumber',
|
resizable: true,
|
render: row => (
|
<span style="color: #0068FF;cursor: pointer;" onClick={() => handleDetail(row)}>
|
{row.plateNumber || '-'}
|
{' '}
|
</span>
|
),
|
},
|
{
|
title: 'VIN码',
|
align: 'left',
|
width: 120,
|
key: 'vehicleVin',
|
resizable: true,
|
},
|
{
|
title: '型号',
|
align: 'left',
|
width: 120,
|
key: 'vehicleModelName',
|
resizable: true,
|
},
|
{
|
title: '车辆属性',
|
align: 'left',
|
width: 120,
|
key: 'vehicleAttribute',
|
resizable: true,
|
render: (row) => {
|
const option = vehicleAttributeOptions.find(opt => String(opt.value) === String(row.vehicleAttribute))
|
return option ? option.label : (row.vehicleAttribute || '-')
|
},
|
},
|
{
|
title: '采购来源',
|
align: 'left',
|
width: 120,
|
key: 'procurementSource',
|
resizable: true,
|
ellipsis: true,
|
},
|
{
|
title: '运营区域',
|
align: 'left',
|
width: 120,
|
key: 'electronicId',
|
resizable: true,
|
render: (row) => {
|
if (row.electronicName)
|
return row.electronicName
|
const option = operationAreaOptions.value.find(opt => String(opt.value) === String(row.electronicId))
|
return option ? option.label : (row.electronicId || '-')
|
},
|
},
|
{
|
title: '状态',
|
align: 'left',
|
key: 'status',
|
width: 120,
|
resizable: true,
|
render: (row) => {
|
const status = statusMap[String(row.status)] || { bgColor: '#FFF8E6', color: '#FF9000', text: row.status }
|
return (
|
<n-tag
|
type={row.status === 3 ? 'error' : 'warning'}
|
bordered={false}
|
>
|
{status.text || ''}
|
</n-tag>
|
)
|
// return <span style={`background-color: ${status.bgColor}; color: ${status.color}; padding: 1px 8px; border-radius: 4px;font-size: 12px;`}>{status.text}</span>
|
},
|
},
|
{
|
title: '入库时间',
|
align: 'left',
|
width: 160,
|
key: 'warehousingTime',
|
render: row => row.warehousingTime ? dayjs(row.warehousingTime).format('YYYY/MM/DD HH:mm') : '-',
|
},
|
{
|
title: '操作',
|
align: 'left',
|
key: 'actions',
|
fixed: 'right',
|
width: 140,
|
// resizable: true,
|
render: (row) => {
|
return (
|
<NSpace wrap={false} size={8}>
|
{row.status == '1' && (
|
<NButton
|
text
|
v-permission="50116"
|
type="primary"
|
onClick={() => handleCompleteInfo(row)}
|
>
|
完善信息
|
</NButton>
|
)}
|
{row.status == '2' && (
|
<NButton
|
text
|
v-permission="50117"
|
type="primary"
|
onClick={() => handleStartOperation(row)}
|
>
|
开始运营
|
</NButton>
|
)}
|
{row.status == '3' && (
|
<NButton
|
text
|
v-permission="50118"
|
type="primary"
|
onClick={() => handleUpdateInfo(row)}
|
>
|
更新信息
|
</NButton>
|
)}
|
<NButton
|
text
|
v-permission="50119"
|
type="primary"
|
onClick={() => handleDetail(row)}
|
>
|
详情
|
</NButton>
|
{/* <NButton
|
text
|
v-permission="50120"
|
type="primary"
|
onClick={() => handleEdit(row)}
|
>
|
编辑
|
</NButton> */}
|
<NButton
|
text
|
v-permission="50121"
|
type="primary"
|
onClick={() => handleDelete(row!)}
|
>
|
删除
|
</NButton>
|
</NSpace>
|
)
|
},
|
},
|
])
|
|
const tableScrollX = computed(() => {
|
const widthList = columns.value.map((col: any) => {
|
const width = col?.width ?? col?.minWidth ?? 0
|
return typeof width === 'number' ? width : 0
|
})
|
const totalWidth = widthList.reduce((sum, w) => sum + w, 0)
|
return Math.min(totalWidth, 1600)
|
})
|
|
async function getVehicleList() {
|
startLoading()
|
try {
|
const params = {
|
...model.value,
|
pageNum: pagination.page,
|
pageSize: pagination.pageSize,
|
vehicleAttribute: model.value.vehicleAttribute || 0,
|
startTime: '',
|
endTime: '',
|
}
|
|
// 处理时间范围
|
if (model.value.entryTime && model.value.entryTime.length === 2) {
|
params.startTime = dayjs(model.value.entryTime[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss')
|
params.endTime = dayjs(model.value.entryTime[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss')
|
}
|
delete params.entryTime
|
|
const { data } = await getVehiclePageList(params)
|
if (data) {
|
listData.value = data.records || []
|
count.value = data.total || 0
|
}
|
}
|
finally {
|
endLoading()
|
}
|
}
|
|
function handleAdd() {
|
router.push('/assetManagement/vehicleManagement/inventoryVehicle/add')
|
}
|
|
function handleBatchSetArea() {
|
// 检查是否有选中的车辆
|
if (selectedVehicles.value.length === 0) {
|
window.$message.warning('请先选择要设置运营区域的车辆')
|
return
|
}
|
|
// 重置表单
|
areaFormModel.value.operationArea = null
|
showAreaModal.value = true
|
}
|
|
function handleAreaModalConfirm() {
|
areaFormRef.value?.validate(async (errors) => {
|
if (!errors) {
|
const res = await batchSetElectronic({
|
electronicId: areaFormModel.value.operationArea!,
|
ids: selectedVehicles.value.map(item => item.id),
|
})
|
// 只要 code == 200 即表示成功
|
if (res && (res as any).code === 200) {
|
window.$message.success('批量设置运营区域成功')
|
showAreaModal.value = false
|
selectedVehicles.value = []
|
checkedRowKeys.value = []
|
getVehicleList()
|
}
|
}
|
})
|
}
|
|
function handleAreaModalCancel() {
|
showAreaModal.value = false
|
}
|
|
async function handleBatchOperation() {
|
if (selectedVehicles.value.length === 0) {
|
window.$message.warning('请先选择要操作的车辆')
|
return
|
}
|
const idStr = selectedVehicles.value.map(item => item.id).join(',')
|
dialog.warning({
|
title: '确认开始运营',
|
content: () => `确认对选中的 ${selectedVehicles.value.length} 辆车辆执行开始运营吗?`,
|
negativeText: '取消',
|
positiveText: '确定',
|
// confirmText: '确定',
|
maskClosable: false,
|
autoFocus: false,
|
onPositiveClick: async () => {
|
const res = await batchOperation(idStr)
|
if (res && (res as any).code === 200) {
|
window.$message.success('批量运营成功')
|
selectedVehicles.value = []
|
checkedRowKeys.value = []
|
getVehicleList()
|
}
|
else {
|
// window.$message.error((res as any).message || '批量运营失败')
|
}
|
showConfirmDialog.value = false
|
},
|
onNegativeClick: () => {
|
showConfirmDialog.value = false
|
},
|
})
|
// showConfirmDialog.value = true
|
}
|
|
// 下载模板
|
async function handleDownloadTemplate() {
|
try {
|
const response = await getVehicleImportTemplate()
|
if (response instanceof Blob) {
|
downloadFile(response, `车辆导入模板_${new Date().getTime()}.xlsx`)
|
window.$message.success('下载成功')
|
}
|
else {
|
window.$message.error('下载失败:接口未返回正确的文件模板')
|
}
|
}
|
catch (error) {
|
console.error('下载模板失败:', error)
|
}
|
}
|
|
function handleImport() {
|
fileInputRef.value?.click()
|
}
|
|
// 处理文件选择
|
async function handleFileChange(event: Event) {
|
const target = event.target as HTMLInputElement
|
const file = target.files?.[0]
|
if (!file)
|
return
|
|
try {
|
const { code } = await importVehicleExcel(file)
|
if (code === 200) {
|
window.$message.success('导入成功')
|
handleSearch()
|
}
|
// else {
|
// window.$message.error(message || '导入失败')
|
// }
|
}
|
catch (error) {
|
console.error('导入失败:', error)
|
}
|
finally {
|
// 清空 input 方便下次选择同一个文件
|
target.value = ''
|
}
|
}
|
|
async function handleExport() {
|
const params = {
|
...model.value,
|
}
|
// 处理时间范围
|
if (model.value.entryTime && model.value.entryTime.length === 2) {
|
params.startTime = dayjs(model.value.entryTime[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss')
|
params.endTime = dayjs(model.value.entryTime[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss')
|
}
|
delete params.entryTime
|
|
const response = await exportVehicleExcel(params)
|
if (response instanceof Blob) {
|
downloadFile(response, `在库车辆列表_${new Date().getTime()}.xlsx`)
|
window.$message.success('导出成功')
|
}
|
}
|
|
function handleCompleteInfo(row: any) {
|
currentVehicle.value = row
|
infoModalType.value = 'complete'
|
showCompleteInfoModal.value = true
|
}
|
|
function handleCompleteInfoSuccess() {
|
// 刷新列表
|
handleSearch()
|
}
|
|
async function handleStartOperation(row: any) {
|
if (!row?.id) {
|
window.$message.warning('车辆信息不完整,无法开始运营')
|
return
|
}
|
dialog.warning({
|
title: '确认开始运营',
|
content: () => {
|
return (
|
<div>
|
确认对车辆
|
<span style="color:#0068FF">{row.plateNumber || row.vehicleCode || row.id}</span>
|
{' '}
|
执行开始运营吗?
|
</div>
|
)
|
},
|
negativeText: '取消',
|
positiveText: '确定',
|
maskClosable: false,
|
autoFocus: false,
|
onPositiveClick: async () => {
|
const res = await batchOperation(String(row.id))
|
if (res && (res as any).code === 200) {
|
window.$message.success(`开始运营: ${row.plateNumber}`)
|
getVehicleList()
|
}
|
showConfirmDialog.value = false
|
},
|
})
|
// showConfirmDialog.value = true
|
}
|
|
function handleUpdateInfo(row: any) {
|
currentVehicle.value = row
|
infoModalType.value = 'update'
|
showCompleteInfoModal.value = true
|
}
|
|
function handleOpenOperationLog() {
|
showOperationLogModal.value = true
|
}
|
|
function handleDetail(row: any) {
|
router.push({
|
name: 'inventoryVehicleDetail',
|
query: {
|
id: row.id,
|
type: 'inventory',
|
},
|
})
|
}
|
|
function handleEdit(row: any) {
|
editMode.value = 'edit'
|
editVehicle.value = row
|
showEditModal.value = true
|
}
|
|
function handleEditSuccess() {
|
// 刷新列表
|
handleSearch()
|
}
|
|
function handleDelete(row: any) {
|
window.$dialog.warning({
|
title: '是否确认删除',
|
content: () => {
|
return (
|
<div>
|
确认删除车辆
|
<span style="color:#0068FF">{row.plateNumber}</span>
|
{' '}
|
吗?
|
</div>
|
)
|
},
|
positiveText: '确定',
|
negativeText: '取消',
|
onPositiveClick: async () => {
|
const { code } = await deleteVehicle(row.id)
|
if (code === 200) {
|
window.$message.success('删除车辆成功')
|
getVehicleList() // 刷新列表
|
}
|
},
|
})
|
}
|
|
// let handlingQueryAction = false
|
async function consumeActionQuery() {
|
// if (handlingQueryAction)
|
// return
|
|
const query = { ...router.currentRoute.value.query } as any
|
if (!query.id || !query.action)
|
return
|
|
// handlingQueryAction = true
|
try {
|
let targetVehicle = null
|
// if (!targetVehicle) {
|
const res = await getVehicleById(String(query.id))
|
|
if (res && (res as any).code === 200 && (res as any).data)
|
targetVehicle = (res as any).data
|
// }
|
|
if (targetVehicle) {
|
if (query.action === 'completeInfo')
|
handleCompleteInfo(targetVehicle)
|
else if (query.action === 'updateInfo')
|
handleUpdateInfo(targetVehicle)
|
else if (query.action === 'edit')
|
handleEdit(targetVehicle)
|
}
|
}
|
finally {
|
// handlingQueryAction = false
|
}
|
}
|
|
onMounted(() => {
|
getOperationAreaList()
|
getVehicleList()
|
consumeActionQuery()
|
})
|
|
onActivated(() => {
|
if (window.sessionStorage.getItem('inventoryVehicleNeedRefresh') === '1') {
|
window.sessionStorage.removeItem('inventoryVehicleNeedRefresh')
|
getVehicleList()
|
}
|
})
|
|
// watch(
|
// () => router.currentRoute.value.query,
|
// () => {
|
// consumeActionQuery()
|
// },
|
// { immediate: true },
|
// )
|
|
// delete query.id
|
// delete query.action
|
// router.replace({ query })
|
|
watch(
|
() => showCompleteInfoModal,
|
(val) => {
|
if (!val.value) {
|
const query = { ...router.currentRoute.value.query } as any
|
delete query.id
|
delete query.action
|
router.replace({ query })
|
}
|
},
|
{ deep: true },
|
)
|
watch(
|
() => showEditModal,
|
(val) => {
|
if (!val.value) {
|
const query = { ...router.currentRoute.value.query } as any
|
delete query.id
|
delete query.action
|
router.replace({ query })
|
}
|
},
|
{ deep: true },
|
)
|
|
function changePage(page: number, pageSize: number) {
|
pagination.page = page
|
pagination.pageSize = pageSize
|
getVehicleList()
|
}
|
|
// 表格行选择
|
const checkedRowKeys = ref<Array<string | number>>([])
|
function handleCheck(rowKeys: Array<string | number>, rows: any[]) {
|
checkedRowKeys.value = rowKeys
|
selectedVehicles.value = rows
|
}
|
</script>
|
|
<template>
|
<div class="roboTaxi w-full h-full">
|
<div class="flex-1 flex flex-col">
|
<div class="roboTaxi-form-card mb-12px">
|
<n-form
|
ref="formRef"
|
:model="model"
|
label-placement="left"
|
inline
|
:show-feedback="false"
|
>
|
<SearchPanel :default-collapsed="false">
|
<n-gi v-for="item in filterItems" :key="item.path">
|
<n-form-item :label="item.label" :path="item.path">
|
<component :is="item.render" />
|
</n-form-item>
|
</n-gi>
|
<template #action>
|
<NButton @click="handleResetSearch">
|
{{ $t("common.reset") }}
|
</NButton>
|
<NButton type="primary" @click="getVehicleList">
|
{{ $t("common.search") }}
|
</NButton>
|
</template>
|
</SearchPanel>
|
</n-form>
|
</div>
|
|
<n-card class="flex-1 robotaxi-table-card">
|
<template #header>
|
<n-flex justify="space-between" align="center">
|
<div class="flex gap-2 items-center">
|
<NButton v-permission="50122" @click="handleOpenOperationLog">
|
操作日志
|
</NButton>
|
<span
|
v-if="checkedRowKeys.length > 0"
|
style="color: rgba(23, 31, 38, 0.6); font-weight: 400"
|
>
|
{{
|
$t("accountManagement.messages.selectedRecords", {
|
count: checkedRowKeys.length,
|
})
|
}}
|
</span>
|
<NButton
|
v-permission="50112"
|
style="color: #171f26"
|
:disabled="checkedRowKeys.length === 0"
|
@click="handleBatchSetArea"
|
>
|
批量设置运营区域
|
</NButton>
|
<NButton
|
v-permission="50113"
|
style="color: #171f26"
|
:disabled="checkedRowKeys.length === 0"
|
@click="handleBatchOperation"
|
>
|
批量运营
|
</NButton>
|
</div>
|
<NSpace>
|
<NButton
|
v-permission="50114"
|
style="color: #171f26"
|
@click="handleDownloadTemplate"
|
>
|
下载模板
|
</NButton>
|
<NButton
|
v-permission="50114"
|
style="color: #171f26"
|
@click="handleImport"
|
>
|
导入
|
</NButton>
|
<NButton
|
v-permission="50115"
|
style="color: #171f26"
|
@click="handleExport"
|
>
|
导出
|
</NButton>
|
<NButton
|
v-permission="50111"
|
type="primary"
|
secondary
|
@click="handleAdd"
|
>
|
新增
|
</NButton>
|
</NSpace>
|
</n-flex>
|
</template>
|
<div class="flex-1 flex flex-col h-full">
|
<n-data-table
|
v-model:checked-row-keys="checkedRowKeys"
|
class="flex-1"
|
:columns="columns"
|
:data="listData"
|
:loading="loading"
|
:scroll-x="tableScrollX"
|
:row-key="(row: any) => row.id"
|
flex-height
|
:bordered="false"
|
:header-height="18"
|
:row-height="18"
|
@update:checked-row-keys="handleCheck"
|
>
|
<template #empty>
|
<div class="flex-center">
|
<img
|
src="/src/assets/element-img/no-data.png"
|
style="width: 123px; height: 125px"
|
>
|
</div>
|
</template>
|
</n-data-table>
|
<Pagination
|
:count="count"
|
:page="pagination.page"
|
:page-size="pagination.pageSize"
|
class="robotaxi-pagination mt-12px"
|
@change="changePage"
|
/>
|
</div>
|
</n-card>
|
</div>
|
|
<!-- 通用确认弹窗 -->
|
<ConfirmDialog
|
v-model:visible="showConfirmDialog"
|
:title="confirmDialogConfig.title"
|
:description="confirmDialogConfig.description"
|
:cancel-text="confirmDialogConfig.cancelText"
|
:confirm-text="confirmDialogConfig.confirmText"
|
@confirm="confirmDialogConfig.onConfirm"
|
@cancel="confirmDialogConfig.onCancel"
|
/>
|
<OperationLogModal v-model:show="showOperationLogModal" />
|
|
<!-- 批量设置运营区域弹窗 -->
|
<n-modal
|
v-model:show="showAreaModal"
|
preset="card"
|
title="批量设置运营区域"
|
style="width: 400px"
|
:mask-closable="false"
|
:segmented="{
|
content: true,
|
action: true,
|
}"
|
:content-style="{
|
padding: '16px 24px 24px 24px',
|
}"
|
>
|
<n-form
|
ref="areaFormRef"
|
:model="areaFormModel"
|
:rules="areaFormRules"
|
label-placement="top"
|
require-mark-placement="left"
|
class="area-form"
|
>
|
<n-form-item
|
label="选择运营区域"
|
path="operationArea"
|
style="margin-bottom: 0"
|
>
|
<n-select
|
v-model:value="areaFormModel.operationArea"
|
:options="operationAreaOptions"
|
placeholder="请选择"
|
filterable
|
clearable
|
style="width: 100%"
|
>
|
<template #arrow>
|
<img
|
src="https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/e120f81c-9f15-4e1a-9938-22252898edf9.png"
|
class="arrow-icon"
|
style="width: 16px; height: 16px"
|
alt="arrow"
|
>
|
</template>
|
<template #empty>
|
<div class="flex-center">
|
<img
|
src="/src/assets/element-img/no-data.png"
|
style="width: 50%"
|
alt="no-data"
|
>
|
</div>
|
</template>
|
</n-select>
|
</n-form-item>
|
</n-form>
|
|
<template #action>
|
<NSpace justify="end" :size="8">
|
<NButton
|
style="padding: 7px 29px; border-radius: 4px"
|
@click="handleAreaModalCancel"
|
>
|
取消
|
</NButton>
|
<NButton
|
type="primary"
|
style="padding: 7px 29px; border-radius: 4px"
|
@click="handleAreaModalConfirm"
|
>
|
保存
|
</NButton>
|
</NSpace>
|
</template>
|
</n-modal>
|
|
<!-- 完善车辆信息弹窗 -->
|
<CompleteVehicleInfoModal
|
v-model:show="showCompleteInfoModal"
|
:type="infoModalType"
|
:vehicle-data="currentVehicle"
|
@success="handleCompleteInfoSuccess"
|
/>
|
|
<!-- 编辑车辆弹窗 -->
|
<EditVehicleModal
|
v-model:show="showEditModal"
|
:vehicle-data="editVehicle"
|
:mode="editMode"
|
@success="handleEditSuccess"
|
/>
|
|
<input
|
ref="fileInputRef"
|
type="file"
|
style="display: none"
|
accept=".xlsx, .xls"
|
@change="handleFileChange"
|
>
|
</div>
|
</template>
|
|
<style scoped lang="scss">
|
.area-form :deep(.n-form-item-label) {
|
padding-bottom: 8px !important;
|
font-size: 13px;
|
color: #333;
|
font-weight: 400;
|
}
|
|
.area-form :deep(.n-form-item-label__asterisk) {
|
color: #ff4d4f;
|
}
|
|
:deep(.n-card__action) {
|
background-color: transparent !important;
|
}
|
</style><!-- index.vue -->
|