feat: 定价管理列表接口、计费规则、编辑和删除
| | |
| | | dev: { |
| | | // url: 'http://localhost:3000', |
| | | url: 'http://221.182.45.100:8000', |
| | | // url: 'http://221.182.45.100:8000', |
| | | }, |
| | | production: { |
| | | url: 'https://mock.apifox.cn/m1/4071143-0-default', |
| | |
| | | pid: 6, |
| | | }, |
| | | { |
| | | name: 'setPrice', |
| | | path: '/transaction/pricingManagement/setPrice', |
| | | title: '设置价格', |
| | | requiresAuth: true, |
| | | icon: 'icon-park-outline:vip-1', |
| | | menuType: 'page', |
| | | componentPath: '/transaction/pricingManagement/detail.vue', |
| | | id: 603, |
| | | pid: 6, |
| | | hide: true, // 不在菜单中显示 |
| | | activeMenu: '/transaction/pricingManagement', |
| | | }, |
| | | { |
| | | name: 'pricingDetail', |
| | | path: '/transaction/pricingManagement/detail', |
| | | title: '定价详情', |
| | |
| | | icon: 'icon-park-outline:vip-1', |
| | | menuType: 'page', |
| | | componentPath: '/transaction/pricingManagement/detail.vue', |
| | | id: 603, |
| | | id: 604, |
| | | pid: 6, |
| | | hide: true, // 不在菜单中显示 |
| | | activeMenu: '/transaction/pricingManagement', |
| | |
| | | icon: 'icon-park-outline:vip-1', |
| | | menuType: 'page', |
| | | componentPath: '/transaction/pricingManagement/rules.vue', |
| | | id: 604, |
| | | id: 605, |
| | | pid: 6, |
| | | hide: true, // 不在菜单中显示 |
| | | activeMenu: '/transaction/pricingManagement', |
| | |
| | | icon: 'icon-park-outline:alarm', |
| | | menuType: 'page', |
| | | componentPath: '/transaction/transactionStrategy/index.vue', |
| | | id: 605, |
| | | id: 606, |
| | | pid: 6, |
| | | }, |
| | | { |
| | |
| | | icon: 'icon-park-outline:alarm', |
| | | menuType: 'page', |
| | | componentPath: '/transaction/navigationAndRoutePlanning/index.vue', |
| | | id: 606, |
| | | id: 607, |
| | | pid: 6, |
| | | }, |
| | | { |
| | |
| | | |
| | | // 导出订单Excel |
| | | export function exportOrderExcel(params: any) { |
| | | return request.Post<Service.ResponseResult<any>>('/order/api/v1/order/exportExcel', params, { responseType: 'blob' }) |
| | | return request.Post<Service.ResponseResult<any>>('/order/api/v1/order/exportExcel', params) |
| | | } |
| | | |
| | | // 改派订单 |
| | |
| | | } |
| | | |
| | | /** 订单评价 */ |
| | | |
| | | |
| | | // 获取订单评价列表 |
| | | export function getOrderEvaluateList(params: any) { |
| | |
| | | export function editTradingStrategy(params: any) { |
| | | return request.Post<Service.ResponseResult<any>>('/operation/api/v1/tradingStrategy/edit', params) |
| | | } |
| | | |
| | | |
| | | // 定价管理 |
| | | |
| | | |
| | | /** 获取定价列表 */ |
| | | export function getPricingList(params: any) { |
| | | return request.Post<Service.ResponseResult<any>>('/operation/api/v1/pricing/pageList', params) |
| | | } |
| | | |
| | | /** 添加定价 */ |
| | | export function addPricing(params: any) { |
| | | return request.Post<Service.ResponseResult<any>>('/operation/api/v1/pricing/add', params) |
| | | } |
| | | |
| | | /** 设置价格 */ |
| | | export function setPricing(params: any) { |
| | | return request.Post<Service.ResponseResult<any>>('/operation/api/v1/pricing/setPrice', params) |
| | | } |
| | | |
| | | /** 删除定价 */ |
| | | export function deletePricing(id: any) { |
| | | return request.Delete<Service.ResponseResult<any>>('/operation/api/v1/pricing/deleteById?id=' + id) |
| | | } |
| | | |
| | | /** 获取定价详情 */ |
| | | export function getPricingDetail(id: any) { |
| | | return request.Get<Service.ResponseResult<any>>('/operation/api/v1/pricing/queryById?id=' + id) |
| | | } |
| | | |
| | | /** 计费规则 */ |
| | | export function setRule(params: any) { |
| | | return request.Post<Service.ResponseResult<any>>('/operation/api/v1/pricing/setRule', params) |
| | | } |
| | |
| | | <script setup lang="ts"> |
| | | import { useBoolean } from '@/hooks' |
| | | import { fetchRoleList } from '@/service' |
| | | import { getCityList, addPricing, getPricingDetail } from '@/service/api/transaction' |
| | | import type { FormItemRule } from 'naive-ui' |
| | | |
| | | interface Props { |
| | | modalName?: string |
| | | } |
| | | |
| | | const dialog = useDialog() |
| | | |
| | | const { |
| | | modalName = '', |
| | |
| | | const emit = defineEmits<{ |
| | | open: [] |
| | | close: [] |
| | | refresh: [] |
| | | }>() |
| | | |
| | | const { bool: modalVisible, setTrue: showModal, setFalse: hiddenModal } = useBoolean(false) |
| | |
| | | const { bool: submitLoading, setTrue: startLoading, setFalse: endLoading } = useBoolean(false) |
| | | |
| | | const formDefault = { |
| | | name: '', |
| | | city: null, |
| | | vehicleModel: 'Robotaxi', |
| | | cityId: '', |
| | | remark: '', |
| | | rules: '1', |
| | | channel: '', |
| | | pricingType: 1, |
| | | channel: '小鹏小程序', |
| | | } |
| | | const formModel = ref({ ...formDefault }) |
| | | let data: any = {} |
| | | |
| | | type ModalType = 'add' | 'view' | 'edit' |
| | | const modalType = shallowRef<ModalType>('add') |
| | |
| | | return `${titleMap[modalType.value]}${modalName}` |
| | | }) |
| | | |
| | | async function openModal(type: ModalType = 'add', data: any) { |
| | | async function openModal(type: ModalType = 'add', id: string) { |
| | | emit('open') |
| | | modalType.value = type |
| | | showModal() |
| | | getRoleList() |
| | | // 重置数据 |
| | | data = {} |
| | | // 获取城市列表数据 |
| | | await getCityListData(type, id) |
| | | // 等待数据获取完成后再显示模态框 |
| | | const handlers = { |
| | | async add() { |
| | | formModel.value = { ...formDefault } |
| | |
| | | }, |
| | | } |
| | | await handlers[type]() |
| | | // 在所有数据加载完成后显示模态框 |
| | | showModal() |
| | | } |
| | | |
| | | function closeModal() { |
| | | formModel.value = { ...formDefault } |
| | | hiddenModal() |
| | | endLoading() |
| | | emit('close') |
| | |
| | | const handlers = { |
| | | async add() { |
| | | return new Promise((resolve) => { |
| | | setTimeout(() => { |
| | | window.$message.success('模拟新增成功') |
| | | resolve(true) |
| | | }, 2000) |
| | | addPricing(formModel.value).then((res) => { |
| | | if (res.code === 200) { |
| | | window.$message.success('新增成功') |
| | | resolve(true) |
| | | } else { |
| | | resolve(false) |
| | | } |
| | | }) |
| | | }) |
| | | }, |
| | | async edit() { |
| | | return new Promise((resolve) => { |
| | | setTimeout(() => { |
| | | window.$message.success('模拟编辑成功') |
| | | resolve(true) |
| | | }, 2000) |
| | | }) |
| | | return true |
| | | }, |
| | | async view() { |
| | | return true |
| | |
| | | } |
| | | await formRef.value?.validate() |
| | | startLoading() |
| | | await handlers[modalType.value]() && closeModal() |
| | | const result = await handlers[modalType.value]() |
| | | endLoading() |
| | | if (result) { |
| | | if (modalType.value === 'add') { |
| | | dialog.create({ |
| | | title: '创建成功,是否去设置价格?', |
| | | content: '', |
| | | positiveText: '设置价格', |
| | | negativeText: '稍后', |
| | | draggable: true, |
| | | onPositiveClick: () => { |
| | | |
| | | }, |
| | | onNegativeClick: () => { |
| | | emit('refresh') |
| | | closeModal() |
| | | } |
| | | }) |
| | | } else { |
| | | emit('refresh') |
| | | closeModal() |
| | | } |
| | | } |
| | | } |
| | | |
| | | const rules = { |
| | | name: { |
| | | vehicleModel: { |
| | | required: true, |
| | | message: '请输入名称', |
| | | trigger: 'blur', |
| | |
| | | message: '请输入渠道', |
| | | trigger: 'blur', |
| | | }, |
| | | city: { |
| | | cityId: { |
| | | type: 'number', |
| | | required: true, |
| | | message: '请选择适用城市', |
| | | trigger: 'change', |
| | | }, |
| | | rules: { |
| | | } as FormItemRule, |
| | | pricingType: { |
| | | type: 'number', |
| | | required: true, |
| | | message: '请选择计费规则', |
| | | trigger: 'change', |
| | | }, |
| | | } |
| | | |
| | | const options = ref() |
| | | async function getRoleList() { |
| | | const { data } = await fetchRoleList() |
| | | options.value = data |
| | | } as FormItemRule, |
| | | } |
| | | |
| | | const routePlanOptions = computed(() => [ |
| | | { |
| | | label: '动态计费', |
| | | value: '1', |
| | | value: 1, |
| | | }, |
| | | { |
| | | label: '一口价', |
| | | value: '2', |
| | | value: 2, |
| | | }, |
| | | ]) |
| | | |
| | | const cityList = ref<any[]>([]) |
| | | |
| | | const getCityListData = async (type: ModalType, id: string) => { |
| | | try { |
| | | const res = await getCityList() |
| | | if (res.code === 200) { |
| | | cityList.value = res.data || [] |
| | | cityList.value.forEach((item) => { |
| | | item.label = item.name |
| | | item.value = Number(item.id) |
| | | }) |
| | | } |
| | | } finally { |
| | | if (type !== 'add') { |
| | | await getPricingDetailData(id) |
| | | } |
| | | } |
| | | } |
| | | |
| | | const getPricingDetailData = async (id: string) => { |
| | | const res = await getPricingDetail(id) |
| | | if (res.code === 200) { |
| | | data = res.data || {} |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <template> |
| | |
| | | content: true, |
| | | action: true, |
| | | }"> |
| | | <n-form ref="formRef" :rules="rules" :model="formModel" :disabled="modalType === 'view'" require-mark-placement="left" > |
| | | <n-form-item label="车型" path="name"> |
| | | <n-input v-model:value="formModel.name" /> |
| | | </n-form-item> |
| | | <n-form-item label="渠道" path="channel"> |
| | | <n-input v-model:value="formModel.channel" /> |
| | | </n-form-item> |
| | | <n-form-item label="城市" path="city"> |
| | | <PcaCascader v-model:value="formModel.city" /> |
| | | </n-form-item> |
| | | <n-form-item label="说明" path="remark"> |
| | | <n-input v-model:value="formModel.remark" type="textarea" /> |
| | | </n-form-item> |
| | | <n-form-item label="计费规则" path="rules"> |
| | | <n-radio-group v-model:value="formModel.rules" name="rules"> |
| | | <n-space> |
| | | <n-radio v-for="option in routePlanOptions" :key="option.value" :value="option.value"> |
| | | {{ option.label }} |
| | | </n-radio> |
| | | </n-space> |
| | | </n-radio-group> |
| | | </n-form-item> |
| | | <n-form ref="formRef" :rules="rules" :model="formModel" :disabled="modalType === 'view'" |
| | | require-mark-placement="left"> |
| | | <n-form-item label="车型" path="vehicleModel"> |
| | | <n-input v-model:value="formModel.vehicleModel" disabled /> |
| | | </n-form-item> |
| | | <n-form-item label="渠道" path="channel"> |
| | | <n-input v-model:value="formModel.channel" disabled /> |
| | | </n-form-item> |
| | | <n-form-item label="城市" path="cityId"> |
| | | <n-select v-model:value="formModel.cityId" :options="cityList" /> |
| | | </n-form-item> |
| | | <n-form-item label="说明" path="remark"> |
| | | <n-input v-model:value="formModel.remark" type="textarea" /> |
| | | </n-form-item> |
| | | <n-form-item label="计费规则" path="pricingType"> |
| | | <n-radio-group v-model:value="formModel.pricingType" name="pricingType"> |
| | | <n-space> |
| | | <n-radio v-for="option in routePlanOptions" :key="option.value" :value="option.value"> |
| | | {{ option.label }} |
| | | </n-radio> |
| | | </n-space> |
| | | </n-radio-group> |
| | | </n-form-item> |
| | | </n-form> |
| | | <template #action> |
| | | <n-space justify="center"> |
| | |
| | | <script setup lang="tsx"> |
| | | import type { DataTableColumns, FormInst } from 'naive-ui' |
| | | import { useBoolean } from '@/hooks' |
| | | import { fetchUserPage } from '@/service' |
| | | import { NButton, NPopconfirm, NSpace } from 'naive-ui' |
| | | import { getPricingList, deletePricing } from '@/service/api/transaction' |
| | | import SearchPanel from '@/components/custom/SearchPanel.vue' |
| | | import TableModal from './components/TableModal.vue' |
| | | import {useRouter} from 'vue-router' |
| | |
| | | const { t } = useI18n() |
| | | |
| | | const initialModel = { |
| | | condition_1: '', |
| | | condition_2: '', |
| | | condition_3: null, |
| | | vehicleModel: '', |
| | | cityName: '', |
| | | } |
| | | const model = ref({ ...initialModel }) |
| | | function handleResetSearch() { |
| | |
| | | const formRef = ref<FormInst | null>() |
| | | const modalRef = ref() |
| | | |
| | | const pageParams = ref({ |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | }) |
| | | |
| | | function delteteUser(id: number) { |
| | | window.$message.success(`删除用户id:${id}`) |
| | | deletePricing(id).then((res) => { |
| | | if (res.code === 200) { |
| | | window.$message.success('删除成功') |
| | | } |
| | | }).finally(() => { |
| | | getList() |
| | | }) |
| | | } |
| | | |
| | | const columns = computed<DataTableColumns<any>>(() =>[ |
| | |
| | | { |
| | | title: '车型', |
| | | align: 'center', |
| | | key: 'carType', |
| | | key: 'vehicleModel', |
| | | ellipsis: true |
| | | }, |
| | | { |
| | | title: '开通城市', |
| | | title: '适用城市', |
| | | align: 'center', |
| | | key: 'city', |
| | | key: 'useCity', |
| | | ellipsis: true |
| | | }, |
| | | { |
| | | title: '渠道', |
| | | align: 'center', |
| | | key: 'channel', |
| | | ellipsis: true |
| | | ellipsis: true, |
| | | }, |
| | | { |
| | | title: '计费规则', |
| | | align: 'center', |
| | | key: 'pricingRules', |
| | | key: 'pricingType', |
| | | ellipsis: true, |
| | | render: (row) => { |
| | | return row.pricingRules === 1 ? '动态计费' : '一口价' |
| | | return row.pricingType === 1 ? '动态计费' : '一口价' |
| | | }, |
| | | }, |
| | | { |
| | |
| | | <NButton |
| | | text |
| | | type='primary' |
| | | onClick={() => modalRef.value.openModal('edit', row)} |
| | | onClick={() => modalRef.value.openModal('edit', row.id)} |
| | | > |
| | | 编辑 |
| | | </NButton> |
| | |
| | | const filterItems = computed(() => [ |
| | | { |
| | | label: '车型', |
| | | path: 'condition_1', |
| | | render: () => <n-input v-model:value={model.value.condition_1} />, |
| | | path: 'vehicleModel', |
| | | render: () => <n-input v-model:value={model.value.vehicleModel} />, |
| | | }, |
| | | { |
| | | label: '城市', |
| | | path: 'condition_1', |
| | | render: () => <n-input v-model:value={model.value.condition_1} />, |
| | | path: 'cityName', |
| | | render: () => <n-input v-model:value={model.value.cityName} />, |
| | | }, |
| | | ]) |
| | | |
| | |
| | | |
| | | async function getList() { |
| | | startLoading() |
| | | setTimeout(() => { |
| | | listData.value = [ |
| | | { |
| | | id: 1, |
| | | city: '四川省成都市', |
| | | carType: 'RoboTaxi', |
| | | channel: '小鹏小程序', |
| | | pricingRules: 1, |
| | | createTime: '2023-01-01 10:00:00', |
| | | updateTime: '2023-01-01 10:00:00', |
| | | }, |
| | | { |
| | | id: 2, |
| | | city: '四川省成都市', |
| | | carType: 'RoboTaxi', |
| | | channel: '小鹏小程序', |
| | | pricingRules: 2, |
| | | createTime: '2023-01-01 10:00:00', |
| | | updateTime: '2023-01-01 10:00:00', |
| | | }, |
| | | ] |
| | | const params = { |
| | | ...pageParams.value, |
| | | cityName: model.value.cityName, |
| | | vehicleModel: model.value.vehicleModel, |
| | | } |
| | | getPricingList(params).then((res) => { |
| | | listData.value = res.data.records || [] |
| | | listData.value.forEach((item: any, index: number) => { |
| | | item.serialNumber = index + 1 |
| | | }) |
| | | count.value = 1 |
| | | count.value = res.data.total || res.data.records?.length |
| | | }).finally(() => { |
| | | endLoading() |
| | | }, 500) |
| | | }) |
| | | } |
| | | onMounted(() => { |
| | | getList() |
| | | }) |
| | | |
| | | function changePage(page: number, size: number) { |
| | | window.$message.success(`分页器:${page},${size}`) |
| | | pageParams.value.pageNum = page |
| | | pageParams.value.pageSize = size |
| | | getList() |
| | | } |
| | | |
| | | </script> |
| | | |
| | | <template> |
| | | <n-flex> |
| | | <n-flex class="roboTaxi"> |
| | | <NSpace vertical class="flex-1"> |
| | | <n-card> |
| | | <div class="roboTaxi-form-card"> |
| | | <n-form ref="formRef" :model="model" label-placement="left" inline :show-feedback="false"> |
| | | <SearchPanel> |
| | | <n-gi v-for="item in filterItems" :key="item.path"> |
| | |
| | | </n-form-item> |
| | | </n-gi> |
| | | <template #action> |
| | | <NButton strong secondary @click="handleResetSearch"> |
| | | <template #icon> |
| | | <icon-park-outline-redo /> |
| | | </template> |
| | | <NButton strong @click="handleResetSearch"> |
| | | {{ $t('common.reset') }} |
| | | </NButton> |
| | | <NButton type="primary" @click="getList"> |
| | | <template #icon> |
| | | <icon-park-outline-search /> |
| | | </template> |
| | | {{ $t('common.search') }} |
| | | </NButton> |
| | | </template> |
| | | </SearchPanel> |
| | | </n-form> |
| | | </n-card> |
| | | </div> |
| | | |
| | | <n-card class="flex-1"> |
| | | <template #header> |
| | | <NButton type="primary" @click="modalRef.openModal('add')"> |
| | | <template #icon> |
| | | <icon-park-outline-add-one /> |
| | | </template> |
| | | 新增定价 |
| | | </NButton> |
| | | <n-flex justify="flex-end"> |
| | | <NButton type="primary" secondary @click="modalRef.openModal('add')"> |
| | | 新增定价 |
| | | </NButton> |
| | | </n-flex> |
| | | </template> |
| | | <NSpace vertical> |
| | | <n-data-table :columns="columns" :data="listData" :loading="loading" /> |
| | | <NSpace vertical :size="16"> |
| | | <n-data-table :columns="columns" :data="listData" :loading="loading" :bordered="false" :header-height="18" |
| | | :row-height="18" /> |
| | | <Pagination :count="count" @change="changePage" /> |
| | | </NSpace> |
| | | |
| | | <TableModal ref="modalRef" modal-name="定价" /> |
| | | <TableModal ref="modalRef" modal-name="定价" @refresh="getList" /> |
| | | </n-card> |
| | | </NSpace> |
| | | </n-flex> |
| | |
| | | import { NButton, NSpace } from 'naive-ui' |
| | | import { useRoute, useRouter } from 'vue-router' |
| | | import { useTabStore } from '@/store' |
| | | import { setRule, getPricingDetail } from '@/service/api/transaction' |
| | | |
| | | const route = useRoute() |
| | | const router = useRouter() |
| | |
| | | const text = ref('') |
| | | |
| | | const handleSubmit = async () => { |
| | | handleCancel() |
| | | const res = await setRule({ |
| | | id: route.query.id as string, |
| | | priceRule: text.value, |
| | | }) |
| | | if (res.code === 200) { |
| | | window.$message.success('保存成功') |
| | | handleCancel() |
| | | } |
| | | } |
| | | |
| | | const handleCancel = () => { |
| | |
| | | router.back() |
| | | } |
| | | |
| | | onMounted(() => { |
| | | const getPricingDetailData = async (id: string) => { |
| | | const res = await getPricingDetail(id) |
| | | if (res.code === 200) { |
| | | text.value = res.data?.priceRule || '' |
| | | } |
| | | } |
| | | |
| | | onMounted(() => { |
| | | getPricingDetailData(route.query.id as string) |
| | | }) |
| | | </script> |
| | | |