| | |
| | | "editor.formatOnSave": false, |
| | | // Auto fix |
| | | "editor.codeActionsOnSave": { |
| | | "source.fixAll.eslint": "explicit", |
| | | "source.fixAll.eslint": false, |
| | | "source.organizeImports": "never" |
| | | }, |
| | | // Silent the stylistic rules in you IDE, but still auto fix them |
| | |
| | | border: none !important; |
| | | } |
| | | |
| | | .n-pro-layout__sidebar { |
| | | height: calc(100vh - 68px); |
| | | overflow-y: auto; |
| | | display: block !important; |
| | | scrollbar-width: none; |
| | | &::-webkit-scrollbar { |
| | | display: none; |
| | | } |
| | | } |
| | | |
| | | .n-pro-layout__content { |
| | | margin-top: 76px !important; |
| | | } |
| | |
| | | } |
| | | |
| | | .roboTaxi { |
| | | height: calc(100vh - 76px - 24px); |
| | | display: flex; |
| | | flex-direction: column; |
| | | |
| | | .roboTaxi-form-card { |
| | | width: 100%; |
| | | height: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | padding: 12px; |
| | |
| | | .n-base-selection-input__content { |
| | | font-size: 13px; |
| | | } |
| | | |
| | | .robotaxi-table-card { |
| | | display: flex; |
| | | flex-direction: column; |
| | | overflow: hidden; |
| | | |
| | | .n-card__content { |
| | | .robotaxi-table { |
| | | } |
| | | .robotaxi-pagination { |
| | | // position: sticky; |
| | | // bottom: 0; |
| | | // background-color: #FFF; |
| | | // z-index: 100; |
| | | // margin-top: 12px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .n-modal { |
| | |
| | | |
| | | .n-card-header { |
| | | padding: 16px 24px; |
| | | |
| | | .n-card-header__main { |
| | | font-size: 16px; |
| | | line-height: 24px; |
| | |
| | | const position = e.target.getPosition() |
| | | formModel.value.locationLon = position.lng |
| | | formModel.value.locationLat = position.lat |
| | | |
| | | // 触发验证 |
| | | formRef.value?.validate( |
| | | (errors) => { |
| | | // 验证完成 |
| | | }, |
| | | (rule) => rule?.key === 'location' |
| | | ) |
| | | |
| | | // 逆地理编码获取地址 |
| | | const geocoder = new AMap.Geocoder() |
| | | geocoder.getAddress([position.lng, position.lat], (status: string, result: any) => { |
| | | if (status === 'complete' && result.info === 'OK') { |
| | | formModel.value.locationAddress = result.regeocode.formattedAddress |
| | | formRef.value?.validate( |
| | | (rule) => { |
| | | return rule?.key === 'locationAddress' |
| | | } |
| | | ) |
| | | } |
| | | }) |
| | | }) |
| | |
| | | const position = e.target.getPosition() |
| | | formModel.value.locationLon = position.lng |
| | | formModel.value.locationLat = position.lat |
| | | |
| | | // 触发验证 |
| | | formRef.value?.validate( |
| | | (errors) => { |
| | | // 验证完成 |
| | | }, |
| | | (rule) => rule?.key === 'location' |
| | | ) |
| | | |
| | | // 逆地理编码获取地址 |
| | | const geocoder = new AMap.Geocoder() |
| | | geocoder.getAddress([position.lng, position.lat], (status: string, result: any) => { |
| | | if (status === 'complete' && result.info === 'OK') { |
| | | formModel.value.locationAddress = result.regeocode.formattedAddress |
| | | formRef.value?.validate( |
| | | (rule) => { |
| | | return rule?.key === 'locationAddress' |
| | | } |
| | | ) |
| | | } |
| | | }) |
| | | }) |
| | |
| | | console.log(result, '逆地理编码结果') |
| | | if (status === 'complete' && result.info === 'OK') { |
| | | formModel.value.locationAddress = result.regeocode.formattedAddress |
| | | formRef.value?.validate( |
| | | (rule) => { |
| | | return rule?.key === 'locationAddress' |
| | | } |
| | | ) |
| | | } |
| | | }) |
| | | }) |
| | |
| | | formModel.value.locationLat = poi.location.lat |
| | | formModel.value.locationAddress = poi.name |
| | | |
| | | // 触发验证 |
| | | formRef.value?.validate( |
| | | (errors) => { |
| | | // 验证完成 |
| | | }, |
| | | (rule) => rule?.key === 'location' |
| | | ) |
| | | |
| | | if (marker) { |
| | | marker.setPosition([poi.location.lng, poi.location.lat]) |
| | | } else { |
| | |
| | | formModel.value.locationLon = position.lng |
| | | formModel.value.locationLat = position.lat |
| | | |
| | | // 触发验证 |
| | | formRef.value?.validate( |
| | | (errors) => { |
| | | // 验证完成 |
| | | }, |
| | | (rule) => rule?.key === 'location' |
| | | ) |
| | | |
| | | // 逆地理编码获取地址 |
| | | const geocoder = new AMap.Geocoder() |
| | | geocoder.getAddress([position.lng, position.lat], (status: string, result: any) => { |
| | | if (status === 'complete' && result.info === 'OK') { |
| | | formModel.value.locationAddress = result.regeocode.formattedAddress |
| | | formRef.value?.validate( |
| | | (rule) => { |
| | | return rule?.key === 'locationAddress' |
| | | } |
| | | ) |
| | | } |
| | | }) |
| | | }) |
| | |
| | | const handleConfirm = async () => { |
| | | try { |
| | | await formRef.value?.validate() |
| | | return |
| | | emit('confirm', formModel.value) |
| | | show.value = false |
| | | resetForm() |
| | |
| | | map.remove(marker) |
| | | marker = null |
| | | } |
| | | resetForm() |
| | | } |
| | | }) |
| | | |
| | |
| | | |
| | | <template> |
| | | <n-modal v-model:show="show" :mask-closable="false" preset="card" :title="mode === 'edit' ? '编辑打卡地址' : '新增打卡地址'" |
| | | class="w-900px" :segmented="{ |
| | | class="w-900px" :auto-focus="false" :segmented="{ |
| | | content: true, |
| | | action: true, |
| | | }"> |
| | |
| | | </template> |
| | | </n-modal> |
| | | |
| | | <EditMonthModal v-model:show="showEditModal" :current-month="selectedMonth" @confirm="handleConfirmEdit" /> |
| | | <EditMonthModal v-model:show="showEditModal" :current-month="dayjs(selectedMonth).valueOf()" @confirm="handleConfirmEdit" /> |
| | | |
| | | <CopyScheduleModal v-model:show="showCopyModal" /> |
| | | </div> |
| | |
| | | <script setup lang="tsx"> |
| | | import type { DataTableColumns, FormInst, DataTableRowKey } from 'naive-ui' |
| | | import type { DataTableColumns, DataTableRowKey, FormInst } from 'naive-ui' |
| | | import { useBoolean } from '@/hooks' |
| | | import { getOrderList, cancelAndCloseOrder, exportOrderExcel, deleteOrder, getFleetList } from '@/service/api/transaction' |
| | | import { cancelAndCloseOrder, deleteOrder, exportOrderExcel, getFleetList, getOrderList } from '@/service/api/transaction' |
| | | import { getRegionCascader } from '@/service/api/operations' |
| | | import { NButton, NSpace, NTag, useMessage } from 'naive-ui' |
| | | import SearchPanel from '@/components/custom/SearchPanel.vue' |
| | |
| | | { |
| | | type: 'selection', |
| | | width: 40, |
| | | fixed: 'left' |
| | | fixed: 'left', |
| | | }, |
| | | { |
| | | title: t('transaction.orderNo'), |
| | | key: 'orderNumber', |
| | | width: 150, |
| | | resizable: true, |
| | | fixed: 'left' |
| | | fixed: 'left', |
| | | }, |
| | | { |
| | | title: t('transaction.orderTime'), |
| | | key: 'createTime', |
| | | width: 160, |
| | | resizable: true |
| | | resizable: true, |
| | | }, |
| | | { |
| | | title: t('transaction.orderSource'), |
| | |
| | | resizable: true, |
| | | render(row) { |
| | | return row.orderSource === 1 ? '小鹏小程序' : '-' |
| | | } |
| | | }, |
| | | }, |
| | | { |
| | | title: t('transaction.pickupTime'), |
| | | key: 'rideTime', |
| | | width: 160, |
| | | resizable: true |
| | | resizable: true, |
| | | }, |
| | | { |
| | | title: t('transaction.userNickname'), |
| | | key: 'nickName', |
| | | width: 120, |
| | | resizable: true |
| | | resizable: true, |
| | | }, |
| | | { |
| | | title: t('transaction.userPhone'), |
| | | key: 'phoneNumber', |
| | | width: 120, |
| | | resizable: true |
| | | resizable: true, |
| | | }, |
| | | { |
| | | title: t('transaction.pickupLocation'), |
| | |
| | | width: 160, |
| | | resizable: true, |
| | | ellipsis: { |
| | | tooltip: true |
| | | } |
| | | tooltip: true, |
| | | }, |
| | | }, |
| | | { |
| | | title: t('transaction.dropoffLocation'), |
| | |
| | | width: 160, |
| | | resizable: true, |
| | | ellipsis: { |
| | | tooltip: true |
| | | } |
| | | tooltip: true, |
| | | }, |
| | | }, |
| | | { |
| | | title: t('transaction.selectedVehicleType'), |
| | | key: 'vehicleModel', |
| | | width: 120, |
| | | resizable: true |
| | | resizable: true, |
| | | }, |
| | | { |
| | | title: t('transaction.acceptedVehicleType'), |
| | | key: 'plateNumber', |
| | | width: 120, |
| | | resizable: true |
| | | resizable: true, |
| | | }, |
| | | { |
| | | title: t('transaction.affiliatedFleet'), |
| | | key: 'fleetName', |
| | | width: 120, |
| | | resizable: true |
| | | resizable: true, |
| | | }, |
| | | { |
| | | title: t('transaction.orderAmount'), |
| | |
| | | resizable: true, |
| | | render(row) { |
| | | return row.orderMoney ? `¥${row.orderMoney}` : '-' |
| | | } |
| | | }, |
| | | }, |
| | | { |
| | | title: t('transaction.status'), |
| | |
| | | NTag, |
| | | { |
| | | type: statusOptions.find(item => item.value === row.status)?.type || 'default', |
| | | style: row.status === 9 ? { |
| | | color: '#764DFF', |
| | | backgroundColor: '#F6F0FF', |
| | | } : {}, |
| | | bordered: false |
| | | style: row.status === 9 |
| | | ? { |
| | | color: '#764DFF', |
| | | backgroundColor: '#F6F0FF', |
| | | } |
| | | : {}, |
| | | bordered: false, |
| | | }, |
| | | { |
| | | default: () => statusOptions.find(item => item.value === row.status)?.label || '-' |
| | | } |
| | | default: () => statusOptions.find(item => item.value === row.status)?.label || '-', |
| | | }, |
| | | ) |
| | | } |
| | | }, |
| | | }, |
| | | { |
| | | title: '操作', |
| | | key: 'actions', |
| | | width: 200, |
| | | // width: 200, |
| | | fixed: 'right', |
| | | render: (row) => { |
| | | return ( |
| | | <NSpace> |
| | | {(row.status === 1 || row.status === 2 || row.status === 3 || row.status === 4) && <NButton |
| | | text |
| | | v-permission="60113" |
| | | type="primary" |
| | | onClick={() => { |
| | | dialog.create({ |
| | | title: '是否确认取消订单?', |
| | | content: '', |
| | | positiveText: '确定', |
| | | negativeText: '取消', |
| | | draggable: true, |
| | | onPositiveClick: () => { |
| | | cancelAndCloseOrder({ orderId: row.id!, type: 1 }).then(res => { |
| | | if (res.code === 200) { |
| | | message.success('取消订单成功') |
| | | getList() |
| | | } |
| | | }) |
| | | } |
| | | }) |
| | | }} |
| | | > |
| | | 取消订单 |
| | | </NButton>} |
| | | {row.status === 5 && <NButton |
| | | text |
| | | v-permission="60114" |
| | | type="primary" |
| | | onClick={() => { |
| | | dialog.create({ |
| | | title: '是否确认关闭订单?', |
| | | content: '', |
| | | positiveText: '确定', |
| | | negativeText: '取消', |
| | | draggable: true, |
| | | onPositiveClick: () => { |
| | | cancelAndCloseOrder({ orderId: row.id!, type: 2 }).then(res => { |
| | | if (res.code === 200) { |
| | | message.success('关闭订单成功') |
| | | getList() |
| | | } |
| | | }) |
| | | } |
| | | }) |
| | | }} |
| | | > |
| | | 关闭订单 |
| | | </NButton>} |
| | | {row.status === 6 && <NButton |
| | | text |
| | | type="primary" |
| | | v-permission="60115" |
| | | onClick={() => modalRef1.value.openModal(row)} |
| | | > |
| | | 改价 |
| | | </NButton>} |
| | | { (row.status === 2 || row.status === 3 || row.status === 4 )&& <NButton |
| | | text |
| | | v-permission="60116" |
| | | type="primary" |
| | | onClick={() => modalRef.value.openModal(row)} |
| | | > |
| | | 改派 |
| | | </NButton>} |
| | | {(row.status === 1 || row.status === 2 || row.status === 3 || row.status === 4) && ( |
| | | <NButton |
| | | text |
| | | v-permission="60113" |
| | | type="primary" |
| | | onClick={() => { |
| | | dialog.create({ |
| | | title: '是否确认取消订单?', |
| | | content: '', |
| | | positiveText: '确定', |
| | | negativeText: '取消', |
| | | draggable: true, |
| | | onPositiveClick: () => { |
| | | cancelAndCloseOrder({ orderId: row.id!, type: 1 }).then((res) => { |
| | | if (res.code === 200) { |
| | | message.success('取消订单成功') |
| | | getList() |
| | | } |
| | | }) |
| | | }, |
| | | }) |
| | | }} |
| | | > |
| | | 取消订单 |
| | | </NButton> |
| | | )} |
| | | {row.status === 5 && ( |
| | | <NButton |
| | | text |
| | | v-permission="60114" |
| | | type="primary" |
| | | onClick={() => { |
| | | dialog.create({ |
| | | title: '是否确认关闭订单?', |
| | | content: '', |
| | | positiveText: '确定', |
| | | negativeText: '取消', |
| | | draggable: true, |
| | | onPositiveClick: () => { |
| | | cancelAndCloseOrder({ orderId: row.id!, type: 2 }).then((res) => { |
| | | if (res.code === 200) { |
| | | message.success('关闭订单成功') |
| | | getList() |
| | | } |
| | | }) |
| | | }, |
| | | }) |
| | | }} |
| | | > |
| | | 关闭订单 |
| | | </NButton> |
| | | )} |
| | | {row.status === 6 && ( |
| | | <NButton |
| | | text |
| | | type="primary" |
| | | v-permission="60115" |
| | | onClick={() => modalRef1.value.openModal(row)} |
| | | > |
| | | 改价 |
| | | </NButton> |
| | | )} |
| | | { (row.status === 2 || row.status === 3 || row.status === 4) && ( |
| | | <NButton |
| | | text |
| | | v-permission="60116" |
| | | type="primary" |
| | | onClick={() => modalRef.value.openModal(row)} |
| | | > |
| | | 改派 |
| | | </NButton> |
| | | )} |
| | | <NButton |
| | | text |
| | | v-permission="60111" |
| | |
| | | name: 'orderDetail', |
| | | query: { |
| | | orderId: row.id!, |
| | | } |
| | | }, |
| | | }) |
| | | }} |
| | | > |
| | |
| | | negativeText: '取消', |
| | | draggable: true, |
| | | onPositiveClick: () => { |
| | | deleteOrder(row.id!).then(res => { |
| | | deleteOrder(row.id!).then((res) => { |
| | | if (res.code === 200) { |
| | | message.success('删除订单成功') |
| | | getList() |
| | |
| | | { |
| | | label: t('transaction.channel'), |
| | | path: 'orderSource', |
| | | render: () => <n-select v-model:value={model.value.orderSource} options={chanleOptions} />, |
| | | },{ |
| | | render: () => <n-select v-model:value={model.value.orderSource} options={chanleOptions} />, |
| | | }, |
| | | { |
| | | label: t('transaction.city'), |
| | | path: 'cityCode', |
| | | render: () => <n-cascader v-model:value={model.value.cityCode} options={pcaOptions.value} value-field="code" label-field="name" check-strategy="all" clearable />, |
| | |
| | | { |
| | | label: t('transaction.orderTime'), |
| | | path: 'orderTime', |
| | | render: () => <n-date-picker v-model:value={model.value.orderTime} type="daterange" clearable /> |
| | | render: () => <n-date-picker v-model:value={model.value.orderTime} type="daterange" clearable />, |
| | | }, |
| | | ]) |
| | | |
| | |
| | | startTime: model.value.orderTime ? dayjs(model.value.orderTime?.[0]).format('YYYY-MM-DD') : null, |
| | | endTime: model.value.orderTime ? dayjs(model.value.orderTime?.[1]).format('YYYY-MM-DD') : null, |
| | | } |
| | | getOrderList(params).then(res => { |
| | | getOrderList(params).then((res) => { |
| | | if (res.code === 200) { |
| | | count.value = res.data.total || res.data.records?.length |
| | | listData.value = res.data.records || [] |
| | |
| | | }) |
| | | } |
| | | |
| | | const handleExport =async () => { |
| | | async function handleExport() { |
| | | const params = { |
| | | ...pageParams.value, |
| | | status: model.value.status, |
| | |
| | | } |
| | | |
| | | function formatCascaderData(list: any[]) { |
| | | return list.map(item => { |
| | | return list.map((item) => { |
| | | const newItem = { ...item } |
| | | if (newItem.children && newItem.children.length > 0) { |
| | | newItem.children = formatCascaderData(newItem.children) |
| | | } else { |
| | | } |
| | | else { |
| | | delete newItem.children |
| | | } |
| | | return newItem |
| | |
| | | getList() |
| | | fetchCascaderData() |
| | | fetchFleetList() |
| | | console.log('formRef', formRef.value.style) |
| | | }) |
| | | |
| | | function handleCheck(rowKeys: DataTableRowKey[]) { |
| | |
| | | </script> |
| | | |
| | | <template> |
| | | <n-flex class="roboTaxi w-full"> |
| | | <NSpace vertical class="flex-1 w-full"> |
| | | <div class="roboTaxi-form-card"> |
| | | <n-form ref="formRef" :model="model" label-placement="left" inline :show-feedback="false"> |
| | | <SearchPanel showToggle> |
| | | <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 strong @click="handleResetSearch"> |
| | | {{ $t('common.reset') }} |
| | | </NButton> |
| | | <NButton type="primary" @click="getList"> |
| | | {{ $t('common.search') }} |
| | | </NButton> |
| | | </template> |
| | | </SearchPanel> |
| | | </n-form> |
| | | </div> |
| | | |
| | | <n-card class="flex-1" > |
| | | <template #header> |
| | | <n-flex justify="flex-start" v-permission="60112"> |
| | | <NButton strong @click="handleExport"> |
| | | 批量导出订单 |
| | | <div class="roboTaxi w-full h-full"> |
| | | <!-- <NSpace vertical class="flex-1 w-full"> --> |
| | | <div ref="formRef" class="roboTaxi-form-card mb-12px"> |
| | | <n-form :model="model" label-placement="left" inline :show-feedback="false"> |
| | | <SearchPanel show-toggle> |
| | | <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 strong @click="handleResetSearch"> |
| | | {{ $t('common.reset') }} |
| | | </NButton> |
| | | </n-flex> |
| | | </template> |
| | | <NSpace vertical> |
| | | <n-data-table :row-key="rowKey" :scroll-x="1950" :columns="columns" :data="listData" :loading="loading" :bordered="false" |
| | | :header-height="18" :row-height="18" @update:checked-row-keys="handleCheck" /> |
| | | <Pagination :count="count" @change="changePage" /> |
| | | </NSpace> |
| | | </n-card> |
| | | <TableModal ref="modalRef" modal-name="改派" /> |
| | | <Modal ref="modalRef1" modal-name="改价" /> |
| | | </NSpace> |
| | | </n-flex> |
| | | <NButton type="primary" @click="getList"> |
| | | {{ $t('common.search') }} |
| | | </NButton> |
| | | </template> |
| | | </SearchPanel> |
| | | </n-form> |
| | | </div> |
| | | |
| | | <n-card class="flex-1 robotaxi-table-card"> |
| | | <template #header> |
| | | <n-flex v-permission="60112" justify="flex-start"> |
| | | <NButton strong @click="handleExport"> |
| | | 批量导出订单 |
| | | </NButton> |
| | | </n-flex> |
| | | </template> |
| | | <div class="h-full flex flex-col"> |
| | | <n-data-table |
| | | class="robotaxi-table" :row-key="rowKey" :scroll-x="1950" :columns="columns" :data="listData" :loading="loading" :bordered="false" |
| | | :header-height="18" :row-height="18" :max-height="tableMaxHeight" |
| | | /> |
| | | <Pagination :count="count" class="robotaxi-pagination" @change="changePage" /> |
| | | </div> |
| | | </n-card> |
| | | <TableModal ref="modalRef" modal-name="改派" /> |
| | | <Modal ref="modalRef1" modal-name="改价" /> |
| | | <!-- </NSpace> --> |
| | | </div> |
| | | </template> |