fix:轮胎数据汇总
This commit is contained in:
438
src/views/car/renewalorder/RenewalOrderForm.vue
Normal file
438
src/views/car/renewalorder/RenewalOrderForm.vue
Normal file
@@ -0,0 +1,438 @@
|
||||
<template>
|
||||
<Dialog :title="dialogTitle" v-model="dialogVisible" width="1200px">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
label-width="120px"
|
||||
v-loading="formLoading"
|
||||
>
|
||||
<el-divider content-position="left">车辆信息</el-divider>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="汽车品牌" prop="carBrand">
|
||||
<el-input v-model="formData.carBrand" placeholder="请输入汽车品牌" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="车型" prop="carModel">
|
||||
<el-input v-model="formData.carModel" placeholder="请输入车型" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="车牌号" prop="licensePlate">
|
||||
<el-input v-model="formData.licensePlate" placeholder="请输入车牌号" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="厂牌型号" prop="factoryModel">
|
||||
<el-input v-model="formData.factoryModel" placeholder="请输入厂牌型号" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="车架号" prop="vin">
|
||||
<el-input v-model="formData.vin" placeholder="请输入车架号" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="发动机号" prop="engineNo">
|
||||
<el-input v-model="formData.engineNo" placeholder="请输入发动机号" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="发票日期" prop="invoiceDate">
|
||||
<el-date-picker
|
||||
v-model="formData.invoiceDate"
|
||||
type="date"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="选择发票日期"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="发票金额" prop="invoiceAmount">
|
||||
<el-input-number
|
||||
v-model="formData.invoiceAmount"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:step="0.01"
|
||||
controls-position="right"
|
||||
placeholder="请输入发票金额"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="购买时公里数" prop="purchaseMileage">
|
||||
<el-input v-model="formData.purchaseMileage" placeholder="请输入购买时公里数" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="发票图片" prop="invoiceUrl">
|
||||
<UploadImg v-model="formData.invoiceUrl" :file-size="10" :file-type="['image/jpeg', 'image/png', 'image/jpg', 'image/gif']" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-divider content-position="left">购买方信息</el-divider>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="服务购买方" prop="serviceBuyer">
|
||||
<el-input v-model="formData.serviceBuyer" placeholder="请输入服务购买方" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="车辆购买方" prop="carBuyer">
|
||||
<el-input v-model="formData.carBuyer" placeholder="请输入车辆购买方" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="证件类型" prop="certType">
|
||||
<el-select v-model="formData.certType" placeholder="请选择证件类型" style="width: 100%">
|
||||
<el-option label="请选择字典生成" value="" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="证件号码" prop="certNo">
|
||||
<el-input v-model="formData.certNo" placeholder="请输入证件号码" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="联系电话" prop="mobile">
|
||||
<el-input v-model="formData.mobile" placeholder="请输入联系电话" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="会员邮箱" prop="memberEmail">
|
||||
<el-input v-model="formData.memberEmail" placeholder="请输入会员邮箱" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="联系地址" prop="contactAddress">
|
||||
<el-input v-model="formData.contactAddress" placeholder="请输入联系地址" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="门店" prop="storeId">
|
||||
<el-select
|
||||
v-model="formData.storeId"
|
||||
placeholder="请选择门店"
|
||||
filterable
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="store in storeList"
|
||||
:key="store.id"
|
||||
:label="store.storeName"
|
||||
:value="store.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-divider content-position="left">产品信息</el-divider>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="续保产品" prop="productId">
|
||||
<el-select
|
||||
v-model="formData.productId"
|
||||
placeholder="请选择续保产品"
|
||||
filterable
|
||||
style="width: 100%"
|
||||
@change="handleProductChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="product in productList"
|
||||
:key="product.id"
|
||||
:label="product.productName"
|
||||
:value="product.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="服务产品" prop="serviceProduct">
|
||||
<el-input v-model="formData.serviceProduct" placeholder="选择产品后自动填充" readonly />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="产品时效" prop="productValidity">
|
||||
<el-input v-model="formData.productValidity" placeholder="选择产品后自动填充" readonly />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="产品费用" prop="productFee">
|
||||
<el-input-number
|
||||
v-model="formData.productFee"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:step="0.01"
|
||||
controls-position="right"
|
||||
placeholder="请输入产品费用"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="原厂质保时长" prop="originalWarrantyYears">
|
||||
<el-input v-model="formData.originalWarrantyYears" placeholder="请输入原厂质保时长" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="原厂质保里程" prop="originalWarrantyMileage">
|
||||
<el-input v-model="formData.originalWarrantyMileage" placeholder="请输入原厂质保里程" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="结算方式" prop="settlementMethod">
|
||||
<el-input v-model="formData.settlementMethod" placeholder="请输入结算方式" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="录单人" prop="inputUser">
|
||||
<el-input v-model="formData.inputUser" placeholder="请输入录单人" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-divider content-position="left">其他信息</el-divider>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="formData.remark" type="textarea" :rows="3" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="合同备注" prop="contractRemark">
|
||||
<el-input v-model="formData.contractRemark" type="textarea" :rows="3" placeholder="请输入合同备注" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { RenewalOrderApi, RenewalOrderVO } from '@/api/car/renewalorder'
|
||||
import { RenewalProductApi, RenewalProductVO } from '@/api/car/renewalproduct'
|
||||
import { StoreApi, StoreVO } from '@/api/tire/store'
|
||||
import UploadImg from '@/components/UploadFile/src/UploadImg.vue'
|
||||
|
||||
/** 车辆续保订单 表单 */
|
||||
defineOptions({ name: 'RenewalOrderForm' })
|
||||
|
||||
const { t } = useI18n() // 国际化
|
||||
const message = useMessage() // 消息弹窗
|
||||
|
||||
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||
const dialogTitle = ref('') // 弹窗的标题
|
||||
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
||||
const formType = ref('') // 表单的类型:create - 新增;update - 修改
|
||||
const productList = ref<RenewalProductVO[]>([]) // 续保产品列表
|
||||
const storeList = ref<StoreVO[]>([]) // 门店列表
|
||||
const formData = ref({
|
||||
id: undefined,
|
||||
carBrand: undefined,
|
||||
carModel: undefined,
|
||||
licensePlate: undefined,
|
||||
factoryModel: undefined,
|
||||
invoiceAmount: undefined,
|
||||
purchaseMileage: undefined,
|
||||
engineNo: undefined,
|
||||
vin: undefined,
|
||||
invoiceDate: undefined,
|
||||
invoiceUrl: undefined,
|
||||
serviceBuyer: undefined,
|
||||
carBuyer: undefined,
|
||||
certType: undefined,
|
||||
mobile: undefined,
|
||||
certNo: undefined,
|
||||
contactAddress: undefined,
|
||||
memberEmail: undefined,
|
||||
storeId: undefined,
|
||||
productId: undefined,
|
||||
serviceProduct: undefined,
|
||||
productValidity: undefined,
|
||||
originalWarrantyYears: undefined,
|
||||
originalWarrantyMileage: undefined,
|
||||
productFee: undefined,
|
||||
settlementMethod: undefined,
|
||||
remark: undefined,
|
||||
inputUser: undefined,
|
||||
contractRemark: undefined
|
||||
})
|
||||
const formRules = reactive({
|
||||
licensePlate: [{ required: true, message: '车牌号不能为空', trigger: 'blur' }],
|
||||
productId: [{ required: true, message: '续保产品不能为空', trigger: 'change' }]
|
||||
})
|
||||
const formRef = ref() // 表单 Ref
|
||||
|
||||
/** 获取门店列表 */
|
||||
const getStoreList = async () => {
|
||||
try {
|
||||
const data = await StoreApi.getStorePage({ pageNo: 1, pageSize: -1 })
|
||||
storeList.value = data.list || []
|
||||
} catch (error) {
|
||||
console.error('获取门店列表失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
/** 获取续保产品列表 */
|
||||
const getProductList = async () => {
|
||||
try {
|
||||
const data = await RenewalProductApi.getRenewalProductPage({ pageNo: 1, pageSize: -1 })
|
||||
productList.value = data.list || []
|
||||
} catch (error) {
|
||||
console.error('获取续保产品列表失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
/** 处理产品选择变化 */
|
||||
const handleProductChange = async (productId: number) => {
|
||||
if (!productId) {
|
||||
formData.value.serviceProduct = undefined
|
||||
formData.value.productValidity = undefined
|
||||
return
|
||||
}
|
||||
try {
|
||||
const product = await RenewalProductApi.getRenewalProduct(productId)
|
||||
// 回显服务产品和产品时效(产品时效 = 产品内容)
|
||||
formData.value.serviceProduct = product.productName || ''
|
||||
formData.value.productValidity = product.productContent || ''
|
||||
} catch (error) {
|
||||
console.error('获取产品详情失败:', error)
|
||||
message.error('获取产品详情失败')
|
||||
}
|
||||
}
|
||||
|
||||
/** 打开弹窗 */
|
||||
const open = async (type: string, id?: number) => {
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = t('action.' + type)
|
||||
formType.value = type
|
||||
resetForm()
|
||||
// 加载门店列表和产品列表
|
||||
await Promise.all([getStoreList(), getProductList()])
|
||||
// 修改时,设置数据
|
||||
if (id) {
|
||||
formLoading.value = true
|
||||
try {
|
||||
const data = await RenewalOrderApi.getRenewalOrder(id)
|
||||
// 处理发票日期:如果是Date对象或时间戳,转换为字符串格式 YYYY-MM-DD
|
||||
if (data.invoiceDate) {
|
||||
if (data.invoiceDate instanceof Date) {
|
||||
const year = data.invoiceDate.getFullYear()
|
||||
const month = String(data.invoiceDate.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(data.invoiceDate.getDate()).padStart(2, '0')
|
||||
data.invoiceDate = `${year}-${month}-${day}`
|
||||
} else if (typeof data.invoiceDate === 'number' || typeof data.invoiceDate === 'string') {
|
||||
// 如果是时间戳或字符串,尝试转换
|
||||
const date = new Date(data.invoiceDate)
|
||||
if (!isNaN(date.getTime())) {
|
||||
const year = date.getFullYear()
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(date.getDate()).padStart(2, '0')
|
||||
data.invoiceDate = `${year}-${month}-${day}`
|
||||
}
|
||||
}
|
||||
}
|
||||
formData.value = data
|
||||
} finally {
|
||||
formLoading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
||||
|
||||
/** 提交表单 */
|
||||
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
||||
const submitForm = async () => {
|
||||
// 校验表单
|
||||
await formRef.value.validate()
|
||||
// 提交请求
|
||||
formLoading.value = true
|
||||
try {
|
||||
const data = formData.value as unknown as RenewalOrderVO
|
||||
if (formType.value === 'create') {
|
||||
await RenewalOrderApi.createRenewalOrder(data)
|
||||
message.success(t('common.createSuccess'))
|
||||
} else {
|
||||
await RenewalOrderApi.updateRenewalOrder(data)
|
||||
message.success(t('common.updateSuccess'))
|
||||
}
|
||||
dialogVisible.value = false
|
||||
// 发送操作成功的事件
|
||||
emit('success')
|
||||
} finally {
|
||||
formLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 重置表单 */
|
||||
const resetForm = () => {
|
||||
formData.value = {
|
||||
id: undefined,
|
||||
carBrand: undefined,
|
||||
carModel: undefined,
|
||||
licensePlate: undefined,
|
||||
factoryModel: undefined,
|
||||
invoiceAmount: undefined,
|
||||
purchaseMileage: undefined,
|
||||
engineNo: undefined,
|
||||
vin: undefined,
|
||||
invoiceDate: undefined,
|
||||
invoiceUrl: undefined,
|
||||
serviceBuyer: undefined,
|
||||
carBuyer: undefined,
|
||||
certType: undefined,
|
||||
mobile: undefined,
|
||||
certNo: undefined,
|
||||
contactAddress: undefined,
|
||||
memberEmail: undefined,
|
||||
storeId: undefined,
|
||||
productId: undefined,
|
||||
serviceProduct: undefined,
|
||||
productValidity: undefined,
|
||||
originalWarrantyYears: undefined,
|
||||
originalWarrantyMileage: undefined,
|
||||
productFee: undefined,
|
||||
settlementMethod: undefined,
|
||||
remark: undefined,
|
||||
inputUser: undefined,
|
||||
contractRemark: undefined
|
||||
}
|
||||
formRef.value?.resetFields()
|
||||
}
|
||||
</script>
|
||||
160
src/views/car/renewalorder/components/SalesTrendChart.vue
Normal file
160
src/views/car/renewalorder/components/SalesTrendChart.vue
Normal file
@@ -0,0 +1,160 @@
|
||||
<template>
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="font-bold">销售趋势分析</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-skeleton :loading="loading" animated>
|
||||
<Echart :height="400" :options="echartsOption" />
|
||||
</el-skeleton>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { CarStatisticsApi } from '@/api/car/statistics'
|
||||
import { EChartsOption } from 'echarts'
|
||||
import { erpPriceTableColumnFormatter } from '@/utils'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import Echart from '@/components/Echart/src/Echart.vue'
|
||||
|
||||
defineOptions({ name: 'SalesTrendChart' })
|
||||
|
||||
const props = defineProps({
|
||||
queryParams: propTypes.object.def({})
|
||||
})
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
/** 折线图配置 */
|
||||
const echartsOption = reactive<EChartsOption>({
|
||||
dataset: {
|
||||
dimensions: ['date', 'amount'],
|
||||
source: []
|
||||
},
|
||||
grid: {
|
||||
left: 20,
|
||||
right: 20,
|
||||
bottom: 20,
|
||||
top: 40,
|
||||
containLabel: true
|
||||
},
|
||||
legend: {
|
||||
top: 10
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'cross'
|
||||
},
|
||||
formatter: (params: any) => {
|
||||
let result = params[0].name + '<br/>'
|
||||
params.forEach((item: any) => {
|
||||
result += `${item.seriesName}: ${erpPriceTableColumnFormatter(null, null, item.value, null)}<br/>`
|
||||
})
|
||||
return result
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
axisTick: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: '金额',
|
||||
axisTick: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '销售金额',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
areaStyle: {},
|
||||
itemStyle: {
|
||||
color: '#409EFF'
|
||||
}
|
||||
}
|
||||
],
|
||||
toolbox: {
|
||||
feature: {
|
||||
dataZoom: {
|
||||
yAxisIndex: false
|
||||
},
|
||||
brush: {
|
||||
type: ['lineX', 'clear']
|
||||
},
|
||||
saveAsImage: { show: true, name: '销售趋势分析' }
|
||||
}
|
||||
}
|
||||
}) as EChartsOption
|
||||
|
||||
/** 加载数据 */
|
||||
const loadData = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
// 获取门店销售趋势和业务员销售趋势
|
||||
const [storeTrend, salespersonTrend] = await Promise.all([
|
||||
CarStatisticsApi.getStoreSalesTrend(props.queryParams),
|
||||
CarStatisticsApi.getSalespersonSalesTrend(props.queryParams)
|
||||
])
|
||||
|
||||
// 合并数据,按日期汇总
|
||||
const trendMap = new Map()
|
||||
|
||||
// 处理门店趋势数据
|
||||
if (storeTrend && Array.isArray(storeTrend)) {
|
||||
storeTrend.forEach((item: any) => {
|
||||
const key = item.date
|
||||
if (!trendMap.has(key)) {
|
||||
trendMap.set(key, { date: key, amount: 0 })
|
||||
}
|
||||
trendMap.get(key).amount += item.amount || 0
|
||||
})
|
||||
}
|
||||
|
||||
// 处理业务员趋势数据
|
||||
if (salespersonTrend && Array.isArray(salespersonTrend)) {
|
||||
salespersonTrend.forEach((item: any) => {
|
||||
const key = item.date
|
||||
if (!trendMap.has(key)) {
|
||||
trendMap.set(key, { date: key, amount: 0 })
|
||||
}
|
||||
trendMap.get(key).amount += item.amount || 0
|
||||
})
|
||||
}
|
||||
|
||||
// 转换为数组并排序
|
||||
const trendData = Array.from(trendMap.values()).sort((a, b) =>
|
||||
new Date(a.date).getTime() - new Date(b.date).getTime()
|
||||
)
|
||||
|
||||
// 更新图表数据
|
||||
if (echartsOption.dataset && echartsOption.dataset['source']) {
|
||||
echartsOption.dataset['source'] = trendData
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取销售趋势失败:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.queryParams,
|
||||
() => {
|
||||
loadData()
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
loadData()
|
||||
})
|
||||
|
||||
defineExpose({ loadData })
|
||||
</script>
|
||||
@@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="font-bold">业务员开单率分析</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-table v-loading="loading" :data="list" max-height="500">
|
||||
<el-table-column label="业务员" align="center" prop="salespersonName" min-width="120" />
|
||||
<el-table-column label="门店" align="center" prop="storeName" min-width="120" />
|
||||
<el-table-column label="订单数" align="center" prop="orderCount" min-width="100" />
|
||||
<el-table-column label="平均开单天数" align="center" prop="averageOrderDays" min-width="120">
|
||||
<template #default="scope">
|
||||
{{ scope.row.averageOrderDays ? scope.row.averageOrderDays + '天' : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="30天开单率" align="center" prop="orderRate30Days" min-width="120">
|
||||
<template #default="scope">
|
||||
{{ scope.row.orderRate30Days ? (scope.row.orderRate30Days * 100).toFixed(2) + '%' : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="平均订单金额" align="center" prop="averageOrderAmount" :formatter="priceFormatter" min-width="120" />
|
||||
<el-table-column label="距上次开单" align="center" prop="lastOrderDays" min-width="120">
|
||||
<template #default="scope">
|
||||
<el-tag :type="getLastOrderDaysType(scope.row.lastOrderDays)">
|
||||
{{ scope.row.lastOrderDays !== null ? scope.row.lastOrderDays + '天' : '-' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { CarStatisticsApi, SalespersonStatisticsVO } from '@/api/car/statistics'
|
||||
import { erpPriceTableColumnFormatter } from '@/utils'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
|
||||
defineOptions({ name: 'SalespersonOrderRateAnalysis' })
|
||||
|
||||
const props = defineProps({
|
||||
queryParams: propTypes.object.def({})
|
||||
})
|
||||
|
||||
const loading = ref(false)
|
||||
const list = ref<SalespersonStatisticsVO[]>([])
|
||||
|
||||
/** 金额格式化 */
|
||||
const priceFormatter = erpPriceTableColumnFormatter
|
||||
|
||||
/** 根据距上次开单天数返回标签类型 */
|
||||
const getLastOrderDaysType = (days: number | null) => {
|
||||
if (days === null) return 'info'
|
||||
if (days <= 7) return 'success'
|
||||
if (days <= 30) return 'warning'
|
||||
return 'danger'
|
||||
}
|
||||
|
||||
/** 加载数据 */
|
||||
const loadData = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const data = await CarStatisticsApi.getSalespersonOrderRate(props.queryParams)
|
||||
list.value = data || []
|
||||
} catch (error) {
|
||||
console.error('获取业务员开单率分析失败:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.queryParams,
|
||||
() => {
|
||||
loadData()
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
loadData()
|
||||
})
|
||||
|
||||
defineExpose({ loadData })
|
||||
</script>
|
||||
125
src/views/car/renewalorder/components/SalespersonRank.vue
Normal file
125
src/views/car/renewalorder/components/SalespersonRank.vue
Normal file
@@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="font-bold">业务员销售排行</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-skeleton :loading="loading" animated>
|
||||
<Echart :height="400" :options="echartsOption" />
|
||||
</el-skeleton>
|
||||
<!-- 排行列表 -->
|
||||
<el-table v-loading="loading" :data="list" class="mt-4" max-height="300">
|
||||
<el-table-column label="排名" align="center" type="index" width="60" />
|
||||
<el-table-column label="业务员" align="center" prop="salespersonName" min-width="120" />
|
||||
<el-table-column label="门店" align="center" prop="storeName" min-width="120" />
|
||||
<el-table-column label="销售金额" align="center" prop="totalAmount" :formatter="priceFormatter" min-width="120" />
|
||||
<el-table-column label="订单数" align="center" prop="orderCount" min-width="100" />
|
||||
<el-table-column label="平均订单金额" align="center" prop="averageOrderAmount" :formatter="priceFormatter" min-width="120" />
|
||||
</el-table>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { CarStatisticsApi, SalespersonStatisticsVO } from '@/api/car/statistics'
|
||||
import { EChartsOption } from 'echarts'
|
||||
import { erpPriceTableColumnFormatter } from '@/utils'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import Echart from '@/components/Echart/src/Echart.vue'
|
||||
|
||||
defineOptions({ name: 'SalespersonRank' })
|
||||
|
||||
const props = defineProps({
|
||||
queryParams: propTypes.object.def({})
|
||||
})
|
||||
|
||||
const loading = ref(false)
|
||||
const list = ref<SalespersonStatisticsVO[]>([])
|
||||
|
||||
/** 金额格式化 */
|
||||
const priceFormatter = erpPriceTableColumnFormatter
|
||||
|
||||
/** 横向柱状图配置 */
|
||||
const echartsOption = reactive<EChartsOption>({
|
||||
dataset: {
|
||||
dimensions: ['salespersonName', 'totalAmount'],
|
||||
source: []
|
||||
},
|
||||
grid: {
|
||||
left: 20,
|
||||
right: 20,
|
||||
bottom: 20,
|
||||
top: 20,
|
||||
containLabel: true
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
},
|
||||
formatter: (params: any) => {
|
||||
const data = params[0]
|
||||
return `${data.name}<br/>销售金额: ${erpPriceTableColumnFormatter(null, null, data.value, null)}`
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'value',
|
||||
name: '销售金额'
|
||||
},
|
||||
yAxis: {
|
||||
type: 'category',
|
||||
name: '业务员',
|
||||
axisLabel: {
|
||||
interval: 0
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '销售金额',
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
color: '#67C23A'
|
||||
}
|
||||
}
|
||||
],
|
||||
toolbox: {
|
||||
feature: {
|
||||
saveAsImage: { show: true, name: '业务员销售排行' }
|
||||
}
|
||||
}
|
||||
}) as EChartsOption
|
||||
|
||||
/** 加载数据 */
|
||||
const loadData = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const data = await CarStatisticsApi.getSalespersonRank(props.queryParams)
|
||||
list.value = (data || []).slice(0, 10) // 取前10名
|
||||
// 更新图表数据
|
||||
if (echartsOption.dataset && echartsOption.dataset['source']) {
|
||||
echartsOption.dataset['source'] = list.value.map(item => ({
|
||||
salespersonName: item.salespersonName,
|
||||
totalAmount: item.totalAmount
|
||||
}))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取业务员销售排行失败:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.queryParams,
|
||||
() => {
|
||||
loadData()
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
loadData()
|
||||
})
|
||||
|
||||
defineExpose({ loadData })
|
||||
</script>
|
||||
84
src/views/car/renewalorder/components/StoreAnalysis.vue
Normal file
84
src/views/car/renewalorder/components/StoreAnalysis.vue
Normal file
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="font-bold">门店分析数据</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-table v-loading="loading" :data="list" max-height="500">
|
||||
<el-table-column label="门店名称" align="center" prop="storeName" min-width="150" />
|
||||
<el-table-column label="订单数" align="center" prop="orderCount" min-width="100" />
|
||||
<el-table-column label="平均开单天数" align="center" prop="averageOrderDays" min-width="120">
|
||||
<template #default="scope">
|
||||
{{ scope.row.averageOrderDays ? scope.row.averageOrderDays + '天' : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="30天开单率" align="center" prop="orderRate30Days" min-width="120">
|
||||
<template #default="scope">
|
||||
{{ scope.row.orderRate30Days ? (scope.row.orderRate30Days * 100).toFixed(2) + '%' : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="平均订单金额" align="center" prop="averageOrderAmount" :formatter="priceFormatter" min-width="120" />
|
||||
<el-table-column label="距上次开单" align="center" prop="lastOrderDays" min-width="120">
|
||||
<template #default="scope">
|
||||
<el-tag :type="getLastOrderDaysType(scope.row.lastOrderDays)">
|
||||
{{ scope.row.lastOrderDays !== null ? scope.row.lastOrderDays + '天' : '-' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { CarStatisticsApi, StoreSalesStatisticsVO } from '@/api/car/statistics'
|
||||
import { erpPriceTableColumnFormatter } from '@/utils'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
|
||||
defineOptions({ name: 'StoreAnalysis' })
|
||||
|
||||
const props = defineProps({
|
||||
queryParams: propTypes.object.def({})
|
||||
})
|
||||
|
||||
const loading = ref(false)
|
||||
const list = ref<StoreSalesStatisticsVO[]>([])
|
||||
|
||||
/** 金额格式化 */
|
||||
const priceFormatter = erpPriceTableColumnFormatter
|
||||
|
||||
/** 根据距上次开单天数返回标签类型 */
|
||||
const getLastOrderDaysType = (days: number | null) => {
|
||||
if (days === null) return 'info'
|
||||
if (days <= 7) return 'success'
|
||||
if (days <= 30) return 'warning'
|
||||
return 'danger'
|
||||
}
|
||||
|
||||
/** 加载数据 */
|
||||
const loadData = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const data = await CarStatisticsApi.getStoreOrderRate(props.queryParams)
|
||||
list.value = data || []
|
||||
} catch (error) {
|
||||
console.error('获取门店分析数据失败:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.queryParams,
|
||||
() => {
|
||||
loadData()
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
loadData()
|
||||
})
|
||||
|
||||
defineExpose({ loadData })
|
||||
</script>
|
||||
138
src/views/car/renewalorder/components/StoreSalesStatistics.vue
Normal file
138
src/views/car/renewalorder/components/StoreSalesStatistics.vue
Normal file
@@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="font-bold">门店销售统计</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-skeleton :loading="loading" animated>
|
||||
<Echart :height="400" :options="echartsOption" />
|
||||
</el-skeleton>
|
||||
<!-- 数据表格 -->
|
||||
<el-table v-loading="loading" :data="list" class="mt-4" max-height="300">
|
||||
<el-table-column label="门店名称" align="center" prop="storeName" min-width="150" />
|
||||
<el-table-column label="销售金额" align="center" prop="totalAmount" :formatter="priceFormatter" min-width="120" />
|
||||
<el-table-column label="订单数" align="center" prop="orderCount" min-width="100" />
|
||||
<el-table-column label="平均订单金额" align="center" prop="averageOrderAmount" :formatter="priceFormatter" min-width="120" />
|
||||
<el-table-column label="平均开单天数" align="center" prop="averageOrderDays" min-width="120">
|
||||
<template #default="scope">
|
||||
{{ scope.row.averageOrderDays ? scope.row.averageOrderDays + '天' : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="30天开单率" align="center" prop="orderRate30Days" min-width="120">
|
||||
<template #default="scope">
|
||||
{{ scope.row.orderRate30Days ? (scope.row.orderRate30Days * 100).toFixed(2) + '%' : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="距上次开单" align="center" prop="lastOrderDays" min-width="120">
|
||||
<template #default="scope">
|
||||
{{ scope.row.lastOrderDays !== null ? scope.row.lastOrderDays + '天' : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { CarStatisticsApi, StoreSalesStatisticsVO } from '@/api/car/statistics'
|
||||
import { EChartsOption } from 'echarts'
|
||||
import { erpPriceTableColumnFormatter } from '@/utils'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import Echart from '@/components/Echart/src/Echart.vue'
|
||||
|
||||
defineOptions({ name: 'StoreSalesStatistics' })
|
||||
|
||||
const props = defineProps({
|
||||
queryParams: propTypes.object.def({})
|
||||
})
|
||||
|
||||
const loading = ref(false)
|
||||
const list = ref<StoreSalesStatisticsVO[]>([])
|
||||
|
||||
/** 金额格式化 */
|
||||
const priceFormatter = erpPriceTableColumnFormatter
|
||||
|
||||
/** 柱状图配置 */
|
||||
const echartsOption = reactive<EChartsOption>({
|
||||
dataset: {
|
||||
dimensions: ['storeName', 'totalAmount'],
|
||||
source: []
|
||||
},
|
||||
grid: {
|
||||
left: 20,
|
||||
right: 20,
|
||||
bottom: 40,
|
||||
top: 20,
|
||||
containLabel: true
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
},
|
||||
formatter: (params: any) => {
|
||||
const data = params[0]
|
||||
return `${data.name}<br/>销售金额: ${erpPriceTableColumnFormatter(null, null, data.value, null)}`
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
axisLabel: {
|
||||
rotate: 45,
|
||||
interval: 0
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: '销售金额'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '销售金额',
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
color: '#409EFF'
|
||||
}
|
||||
}
|
||||
],
|
||||
toolbox: {
|
||||
feature: {
|
||||
saveAsImage: { show: true, name: '门店销售统计' }
|
||||
}
|
||||
}
|
||||
}) as EChartsOption
|
||||
|
||||
/** 加载数据 */
|
||||
const loadData = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const data = await CarStatisticsApi.getStoreSalesStatistics(props.queryParams)
|
||||
list.value = data || []
|
||||
// 更新图表数据
|
||||
if (echartsOption.dataset && echartsOption.dataset['source']) {
|
||||
echartsOption.dataset['source'] = list.value.map(item => ({
|
||||
storeName: item.storeName,
|
||||
totalAmount: item.totalAmount
|
||||
}))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取门店销售统计失败:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.queryParams,
|
||||
() => {
|
||||
loadData()
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
loadData()
|
||||
})
|
||||
|
||||
defineExpose({ loadData })
|
||||
</script>
|
||||
41
src/views/car/renewalorder/components/SummaryCard.vue
Normal file
41
src/views/car/renewalorder/components/SummaryCard.vue
Normal file
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<el-card shadow="never" v-loading="loading">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<div class="text-gray-500 text-sm mb-2">{{ title }}</div>
|
||||
<div class="text-2xl font-bold text-gray-800">
|
||||
{{ formatValue(value) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-4xl text-gray-300">
|
||||
<Icon :icon="icon" />
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { erpPriceTableColumnFormatter } from '@/utils'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
|
||||
defineOptions({ name: 'SummaryCard' })
|
||||
|
||||
const props = defineProps({
|
||||
title: propTypes.string.def(''),
|
||||
value: propTypes.oneOfType([Number, String]).def(0),
|
||||
loading: propTypes.bool.def(false),
|
||||
icon: propTypes.string.def('ep:money'),
|
||||
isAmount: propTypes.bool.def(false)
|
||||
})
|
||||
|
||||
const formatValue = (val: any) => {
|
||||
if (val === null || val === undefined) return '0'
|
||||
if (props.isAmount) {
|
||||
return erpPriceTableColumnFormatter(null, null, val, null)
|
||||
}
|
||||
if (typeof val === 'number') {
|
||||
return val.toLocaleString()
|
||||
}
|
||||
return val
|
||||
}
|
||||
</script>
|
||||
167
src/views/car/renewalorder/dashboard.vue
Normal file
167
src/views/car/renewalorder/dashboard.vue
Normal file
@@ -0,0 +1,167 @@
|
||||
<template>
|
||||
<ContentWrap>
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form
|
||||
class="-mb-15px"
|
||||
:model="queryParams"
|
||||
ref="queryFormRef"
|
||||
:inline="true"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-form-item label="时间范围" prop="times">
|
||||
<el-date-picker
|
||||
v-model="queryParams.times"
|
||||
:shortcuts="defaultShortcuts"
|
||||
class="!w-240px"
|
||||
end-placeholder="结束日期"
|
||||
start-placeholder="开始日期"
|
||||
type="daterange"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="门店" prop="storeId">
|
||||
<el-select
|
||||
v-model="queryParams.storeId"
|
||||
placeholder="请选择门店"
|
||||
clearable
|
||||
class="!w-240px"
|
||||
>
|
||||
<el-option
|
||||
v-for="store in storeList"
|
||||
:key="store.id"
|
||||
:label="store.name"
|
||||
:value="store.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
|
||||
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ContentWrap>
|
||||
|
||||
<!-- 看板内容 -->
|
||||
<div class="flex flex-col">
|
||||
<!-- 统计卡片 -->
|
||||
<el-row :gutter="16" class="row">
|
||||
<el-col :md="6" :sm="12" :xs="24">
|
||||
<SummaryCard title="总订单金额" :value="summaryData?.totalAmount" :loading="loading" />
|
||||
</el-col>
|
||||
<el-col :md="6" :sm="12" :xs="24">
|
||||
<SummaryCard title="总订单数" :value="summaryData?.totalOrderCount" :loading="loading" />
|
||||
</el-col>
|
||||
<el-col :md="6" :sm="12" :xs="24">
|
||||
<SummaryCard title="平均订单金额" :value="summaryData?.averageOrderAmount" :loading="loading" />
|
||||
</el-col>
|
||||
<el-col :md="6" :sm="12" :xs="24">
|
||||
<SummaryCard title="活跃门店数" :value="summaryData?.activeStoreCount" :loading="loading" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 图表区域 -->
|
||||
<el-row :gutter="16" class="row">
|
||||
<!-- 门店销售统计 -->
|
||||
<el-col :md="12" :sm="24" :xs="24">
|
||||
<StoreSalesStatistics :query-params="queryParams" />
|
||||
</el-col>
|
||||
<!-- 业务员销售排行 -->
|
||||
<el-col :md="12" :sm="24" :xs="24">
|
||||
<SalespersonRank :query-params="queryParams" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 分析数据 -->
|
||||
<el-row :gutter="16" class="row">
|
||||
<!-- 业务员开单率分析 -->
|
||||
<el-col :md="12" :sm="24" :xs="24">
|
||||
<SalespersonOrderRateAnalysis :query-params="queryParams" />
|
||||
</el-col>
|
||||
<!-- 门店分析数据 -->
|
||||
<el-col :md="12" :sm="24" :xs="24">
|
||||
<StoreAnalysis :query-params="queryParams" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 销售趋势 -->
|
||||
<el-row :gutter="16" class="row">
|
||||
<el-col :span="24">
|
||||
<SalesTrendChart :query-params="queryParams" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defaultShortcuts } from '@/utils/formatTime'
|
||||
import { CarStatisticsApi } from '@/api/car/statistics'
|
||||
import SummaryCard from './components/SummaryCard.vue'
|
||||
import StoreSalesStatistics from './components/StoreSalesStatistics.vue'
|
||||
import SalespersonRank from './components/SalespersonRank.vue'
|
||||
import SalespersonOrderRateAnalysis from './components/SalespersonOrderRateAnalysis.vue'
|
||||
import StoreAnalysis from './components/StoreAnalysis.vue'
|
||||
import SalesTrendChart from './components/SalesTrendChart.vue'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
/** 车辆续保订单看板 */
|
||||
defineOptions({ name: 'RenewalOrderDashboard' })
|
||||
|
||||
const loading = ref(true)
|
||||
const queryFormRef = ref()
|
||||
const storeList = ref<any[]>([]) // 门店列表
|
||||
const summaryData = ref<any>({})
|
||||
|
||||
const queryParams = reactive({
|
||||
times: [
|
||||
// 默认显示最近30天的数据
|
||||
dayjs().subtract(30, 'day').format('YYYY-MM-DD 00:00:00'),
|
||||
dayjs().format('YYYY-MM-DD 23:59:59')
|
||||
],
|
||||
storeId: undefined
|
||||
})
|
||||
|
||||
/** 获取汇总数据 */
|
||||
const getSummaryData = async () => {
|
||||
try {
|
||||
loading.value = true
|
||||
// 这里可以调用汇总接口,暂时使用模拟数据
|
||||
summaryData.value = {
|
||||
totalAmount: 0,
|
||||
totalOrderCount: 0,
|
||||
averageOrderAmount: 0,
|
||||
activeStoreCount: 0
|
||||
}
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
getSummaryData()
|
||||
}
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields()
|
||||
queryParams.times = [
|
||||
dayjs().subtract(30, 'day').format('YYYY-MM-DD 00:00:00'),
|
||||
dayjs().format('YYYY-MM-DD 23:59:59')
|
||||
]
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
/** 初始化 **/
|
||||
onMounted(() => {
|
||||
getSummaryData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.row {
|
||||
.el-col {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
313
src/views/car/renewalorder/index.vue
Normal file
313
src/views/car/renewalorder/index.vue
Normal file
@@ -0,0 +1,313 @@
|
||||
<template>
|
||||
<ContentWrap>
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form
|
||||
class="-mb-15px"
|
||||
:model="queryParams"
|
||||
ref="queryFormRef"
|
||||
:inline="true"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-form-item label="车牌号" prop="licensePlate">
|
||||
<el-input
|
||||
v-model="queryParams.licensePlate"
|
||||
placeholder="请输入车牌号"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
class="!w-240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="服务购买方" prop="serviceBuyer">
|
||||
<el-input
|
||||
v-model="queryParams.serviceBuyer"
|
||||
placeholder="请输入服务购买方"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
class="!w-240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="联系电话" prop="mobile">
|
||||
<el-input
|
||||
v-model="queryParams.mobile"
|
||||
placeholder="请输入联系电话"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
class="!w-240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="车架号" prop="vin">
|
||||
<el-input
|
||||
v-model="queryParams.vin"
|
||||
placeholder="请输入车架号"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
class="!w-240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="门店" prop="storeId">
|
||||
<el-select
|
||||
v-model="queryParams.storeId"
|
||||
placeholder="请选择门店"
|
||||
clearable
|
||||
filterable
|
||||
class="!w-240px"
|
||||
>
|
||||
<el-option
|
||||
v-for="store in storeList"
|
||||
:key="store.id"
|
||||
:label="store.storeName"
|
||||
:value="store.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间" prop="createTime">
|
||||
<el-date-picker
|
||||
v-model="queryParams.createTime"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
type="daterange"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
|
||||
class="!w-220px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
|
||||
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
@click="openForm('create')"
|
||||
v-hasPermi="['car:renewal-order:create']"
|
||||
>
|
||||
<Icon icon="ep:plus" class="mr-5px" /> 新增
|
||||
</el-button>
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
@click="handleExport"
|
||||
:loading="exportLoading"
|
||||
v-hasPermi="['car:renewal-order:export']"
|
||||
>
|
||||
<Icon icon="ep:download" class="mr-5px" /> 导出
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ContentWrap>
|
||||
|
||||
<!-- 列表 -->
|
||||
<ContentWrap>
|
||||
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
|
||||
<el-table-column type="index" label="序号" align="center" width="60" />
|
||||
<el-table-column label="车牌号" align="center" prop="licensePlate" width="120">
|
||||
<template #default="scope">
|
||||
<span
|
||||
v-if="scope.row.licensePlate"
|
||||
class="license-plate-link"
|
||||
@click="openForm('update', scope.row.id)"
|
||||
>
|
||||
{{ scope.row.licensePlate }}
|
||||
</span>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="汽车品牌" align="center" prop="carBrand" />
|
||||
<el-table-column label="车型" align="center" prop="carModel" />
|
||||
<el-table-column label="厂牌型号" align="center" prop="factoryModel" />
|
||||
<el-table-column label="发票金额" align="center" prop="invoiceAmount" :formatter="priceFormatter" />
|
||||
<el-table-column label="购买时公里数" align="center" prop="purchaseMileage" />
|
||||
<el-table-column label="发动机号" align="center" prop="engineNo" />
|
||||
<el-table-column label="车架号" align="center" prop="vin" />
|
||||
<el-table-column label="发票日期" align="center" prop="invoiceDate" :formatter="dateFormatter2" />
|
||||
<el-table-column label="发票图片" align="center" prop="invoiceUrl" width="120">
|
||||
<template #default="scope">
|
||||
<el-image
|
||||
v-if="scope.row.invoiceUrl"
|
||||
:src="scope.row.invoiceUrl"
|
||||
:preview-src-list="[scope.row.invoiceUrl]"
|
||||
preview-teleported
|
||||
fit="cover"
|
||||
class="h-60px w-60px cursor-pointer"
|
||||
lazy
|
||||
/>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="服务购买方" align="center" prop="serviceBuyer" />
|
||||
<el-table-column label="车辆购买方" align="center" prop="carBuyer" />
|
||||
<el-table-column label="证件类型" align="center" prop="certType" />
|
||||
<el-table-column label="联系电话" align="center" prop="mobile" />
|
||||
<el-table-column label="证件号码" align="center" prop="certNo" />
|
||||
<el-table-column label="联系地址" align="center" prop="contactAddress" />
|
||||
<el-table-column label="会员邮箱" align="center" prop="memberEmail" />
|
||||
<el-table-column label="门店" align="center" prop="storeName" />
|
||||
<el-table-column label="服务产品" align="center" prop="serviceProduct" />
|
||||
<el-table-column label="产品时效" align="center" prop="productValidity" />
|
||||
<el-table-column label="原厂质保时长" align="center" prop="originalWarrantyYears" />
|
||||
<el-table-column label="原厂质保里程" align="center" prop="originalWarrantyMileage" />
|
||||
<el-table-column label="产品费用" align="center" prop="productFee" :formatter="priceFormatter" />
|
||||
<el-table-column label="结算方式" align="center" prop="settlementMethod" />
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="录单人" align="center" prop="inputUser" />
|
||||
<el-table-column label="合同备注" align="center" prop="contractRemark" />
|
||||
<el-table-column
|
||||
label="创建时间"
|
||||
align="center"
|
||||
prop="createTime"
|
||||
:formatter="dateFormatter"
|
||||
width="180px"
|
||||
/>
|
||||
<el-table-column label="操作" align="center" min-width="120px">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
@click="openForm('update', scope.row.id)"
|
||||
v-hasPermi="['car:renewal-order:update']"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
link
|
||||
type="danger"
|
||||
@click="handleDelete(scope.row.id)"
|
||||
v-hasPermi="['car:renewal-order:delete']"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页 -->
|
||||
<Pagination
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNo"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</ContentWrap>
|
||||
|
||||
<!-- 表单弹窗:添加/修改 -->
|
||||
<RenewalOrderForm ref="formRef" @success="getList" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { dateFormatter, dateFormatter2 } from '@/utils/formatTime'
|
||||
import { erpPriceTableColumnFormatter } from '@/utils'
|
||||
import download from '@/utils/download'
|
||||
import { RenewalOrderApi, RenewalOrderVO } from '@/api/car/renewalorder'
|
||||
import { StoreApi, StoreVO } from '@/api/tire/store'
|
||||
import RenewalOrderForm from './RenewalOrderForm.vue'
|
||||
|
||||
/** 车辆续保订单 列表 */
|
||||
defineOptions({ name: 'RenewalOrder' })
|
||||
|
||||
const message = useMessage() // 消息弹窗
|
||||
const { t } = useI18n() // 国际化
|
||||
|
||||
const loading = ref(true) // 列表的加载中
|
||||
const list = ref<RenewalOrderVO[]>([]) // 列表的数据
|
||||
const total = ref(0) // 列表的总页数
|
||||
const storeList = ref<StoreVO[]>([]) // 门店列表
|
||||
const queryParams = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
licensePlate: undefined,
|
||||
serviceBuyer: undefined,
|
||||
mobile: undefined,
|
||||
vin: undefined,
|
||||
storeId: undefined,
|
||||
createTime: []
|
||||
})
|
||||
const queryFormRef = ref() // 搜索的表单
|
||||
const exportLoading = ref(false) // 导出的加载中
|
||||
|
||||
/** 查询列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const data = await RenewalOrderApi.getRenewalOrderPage(queryParams)
|
||||
list.value = data.list
|
||||
total.value = data.total
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.pageNo = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields()
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
/** 添加/修改操作 */
|
||||
const formRef = ref()
|
||||
const openForm = (type: string, id?: number) => {
|
||||
formRef.value.open(type, id)
|
||||
}
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (id: number) => {
|
||||
try {
|
||||
// 删除的二次确认
|
||||
await message.delConfirm()
|
||||
// 发起删除
|
||||
await RenewalOrderApi.deleteRenewalOrder(id)
|
||||
message.success(t('common.delSuccess'))
|
||||
// 刷新列表
|
||||
await getList()
|
||||
} catch {}
|
||||
}
|
||||
|
||||
/** 导出按钮操作 */
|
||||
const handleExport = async () => {
|
||||
try {
|
||||
// 导出的二次确认
|
||||
await message.exportConfirm()
|
||||
// 发起导出
|
||||
exportLoading.value = true
|
||||
const data = await RenewalOrderApi.exportRenewalOrder(queryParams)
|
||||
download.excel(data, '车辆续保订单.xls')
|
||||
} catch {
|
||||
} finally {
|
||||
exportLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 获取门店列表 */
|
||||
const getStoreList = async () => {
|
||||
try {
|
||||
const data = await StoreApi.getStorePage({ pageNo: 1, pageSize: -1 })
|
||||
storeList.value = data.list || []
|
||||
} catch (error) {
|
||||
console.error('获取门店列表失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
/** 金额格式化 */
|
||||
const priceFormatter = erpPriceTableColumnFormatter
|
||||
|
||||
/** 初始化 **/
|
||||
onMounted(() => {
|
||||
getStoreList()
|
||||
getList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.license-plate-link {
|
||||
color: #409eff;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.license-plate-link:hover {
|
||||
color: #66b1ff;
|
||||
}
|
||||
</style>
|
||||
130
src/views/car/renewalproduct/RenewalProductForm.vue
Normal file
130
src/views/car/renewalproduct/RenewalProductForm.vue
Normal file
@@ -0,0 +1,130 @@
|
||||
<template>
|
||||
<Dialog :title="dialogTitle" v-model="dialogVisible" width="900px">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
label-width="120px"
|
||||
v-loading="formLoading"
|
||||
>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="产品名称" prop="productName">
|
||||
<el-input v-model="formData.productName" placeholder="请输入产品名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="产品类别" prop="productType">
|
||||
<el-select v-model="formData.productType" placeholder="请选择产品类别" style="width: 100%">
|
||||
<el-option
|
||||
v-for="dict in getStrDictOptions(DICT_TYPE.CAR_RENEWAL_PRODUCT_TYPE)"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="产品内容" prop="productContent">
|
||||
<el-input v-model="formData.productContent" type="textarea" :rows="3" placeholder="请输入产品内容" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="产品备注" prop="remark">
|
||||
<el-input v-model="formData.remark" type="textarea" :rows="3" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { getStrDictOptions, DICT_TYPE } from '@/utils/dict'
|
||||
import { RenewalProductApi, RenewalProductVO } from '@/api/car/renewalproduct'
|
||||
|
||||
/** 车辆续保产品信息 表单 */
|
||||
defineOptions({ name: 'RenewalProductForm' })
|
||||
|
||||
const { t } = useI18n() // 国际化
|
||||
const message = useMessage() // 消息弹窗
|
||||
|
||||
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||
const dialogTitle = ref('') // 弹窗的标题
|
||||
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
||||
const formType = ref('') // 表单的类型:create - 新增;update - 修改
|
||||
const formData = ref({
|
||||
id: undefined,
|
||||
productName: undefined,
|
||||
productContent: undefined,
|
||||
productType: undefined,
|
||||
remark: undefined
|
||||
})
|
||||
const formRules = reactive({
|
||||
productName: [{ required: true, message: '产品名称不能为空', trigger: 'blur' }],
|
||||
productType: [{ required: true, message: '产品类别不能为空', trigger: 'change' }]
|
||||
})
|
||||
const formRef = ref() // 表单 Ref
|
||||
|
||||
/** 打开弹窗 */
|
||||
const open = async (type: string, id?: number) => {
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = t('action.' + type)
|
||||
formType.value = type
|
||||
resetForm()
|
||||
// 修改时,设置数据
|
||||
if (id) {
|
||||
formLoading.value = true
|
||||
try {
|
||||
formData.value = await RenewalProductApi.getRenewalProduct(id)
|
||||
} finally {
|
||||
formLoading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
||||
|
||||
/** 提交表单 */
|
||||
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
||||
const submitForm = async () => {
|
||||
// 校验表单
|
||||
await formRef.value.validate()
|
||||
// 提交请求
|
||||
formLoading.value = true
|
||||
try {
|
||||
const data = formData.value as unknown as RenewalProductVO
|
||||
if (formType.value === 'create') {
|
||||
await RenewalProductApi.createRenewalProduct(data)
|
||||
message.success(t('common.createSuccess'))
|
||||
} else {
|
||||
await RenewalProductApi.updateRenewalProduct(data)
|
||||
message.success(t('common.updateSuccess'))
|
||||
}
|
||||
dialogVisible.value = false
|
||||
// 发送操作成功的事件
|
||||
emit('success')
|
||||
} finally {
|
||||
formLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 重置表单 */
|
||||
const resetForm = () => {
|
||||
formData.value = {
|
||||
id: undefined,
|
||||
productName: undefined,
|
||||
productContent: undefined,
|
||||
productType: undefined,
|
||||
remark: undefined
|
||||
}
|
||||
formRef.value?.resetFields()
|
||||
}
|
||||
</script>
|
||||
211
src/views/car/renewalproduct/index.vue
Normal file
211
src/views/car/renewalproduct/index.vue
Normal file
@@ -0,0 +1,211 @@
|
||||
<template>
|
||||
<ContentWrap>
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form
|
||||
class="-mb-15px"
|
||||
:model="queryParams"
|
||||
ref="queryFormRef"
|
||||
:inline="true"
|
||||
label-width="68px"
|
||||
>
|
||||
<el-form-item label="产品名称" prop="productName">
|
||||
<el-input
|
||||
v-model="queryParams.productName"
|
||||
placeholder="请输入产品名称"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
class="!w-240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="产品类别" prop="productType">
|
||||
<el-select
|
||||
v-model="queryParams.productType"
|
||||
placeholder="请选择产品类别"
|
||||
clearable
|
||||
class="!w-240px"
|
||||
>
|
||||
<el-option
|
||||
v-for="dict in getStrDictOptions(DICT_TYPE.CAR_RENEWAL_PRODUCT_TYPE)"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间" prop="createTime">
|
||||
<el-date-picker
|
||||
v-model="queryParams.createTime"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
type="daterange"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
|
||||
class="!w-220px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
|
||||
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
@click="openForm('create')"
|
||||
v-hasPermi="['car:renewal-product:create']"
|
||||
>
|
||||
<Icon icon="ep:plus" class="mr-5px" /> 新增
|
||||
</el-button>
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
@click="handleExport"
|
||||
:loading="exportLoading"
|
||||
v-hasPermi="['car:renewal-product:export']"
|
||||
>
|
||||
<Icon icon="ep:download" class="mr-5px" /> 导出
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ContentWrap>
|
||||
|
||||
<!-- 列表 -->
|
||||
<ContentWrap>
|
||||
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
|
||||
<el-table-column type="index" label="序号" align="center" width="60" />
|
||||
<el-table-column label="产品名称" align="center" prop="productName" />
|
||||
<el-table-column label="产品内容" align="center" prop="productContent" />
|
||||
<el-table-column label="产品类别" align="center" prop="productType">
|
||||
<template #default="scope">
|
||||
<dict-tag :type="DICT_TYPE.CAR_RENEWAL_PRODUCT_TYPE" :value="scope.row.productType" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column
|
||||
label="创建时间"
|
||||
align="center"
|
||||
prop="createTime"
|
||||
:formatter="dateFormatter"
|
||||
width="180px"
|
||||
/>
|
||||
<el-table-column label="操作" align="center" min-width="120px">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
@click="openForm('update', scope.row.id)"
|
||||
v-hasPermi="['car:renewal-product:update']"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
link
|
||||
type="danger"
|
||||
@click="handleDelete(scope.row.id)"
|
||||
v-hasPermi="['car:renewal-product:delete']"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页 -->
|
||||
<Pagination
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNo"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</ContentWrap>
|
||||
|
||||
<!-- 表单弹窗:添加/修改 -->
|
||||
<RenewalProductForm ref="formRef" @success="getList" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getStrDictOptions, DICT_TYPE } from '@/utils/dict'
|
||||
import { dateFormatter } from '@/utils/formatTime'
|
||||
import download from '@/utils/download'
|
||||
import { RenewalProductApi, RenewalProductVO } from '@/api/car/renewalproduct'
|
||||
import RenewalProductForm from './RenewalProductForm.vue'
|
||||
|
||||
/** 车辆续保产品信息 列表 */
|
||||
defineOptions({ name: 'RenewalProduct' })
|
||||
|
||||
const message = useMessage() // 消息弹窗
|
||||
const { t } = useI18n() // 国际化
|
||||
|
||||
const loading = ref(true) // 列表的加载中
|
||||
const list = ref<RenewalProductVO[]>([]) // 列表的数据
|
||||
const total = ref(0) // 列表的总页数
|
||||
const queryParams = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
productName: undefined,
|
||||
productType: undefined,
|
||||
createTime: []
|
||||
})
|
||||
const queryFormRef = ref() // 搜索的表单
|
||||
const exportLoading = ref(false) // 导出的加载中
|
||||
|
||||
/** 查询列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const data = await RenewalProductApi.getRenewalProductPage(queryParams)
|
||||
list.value = data.list
|
||||
total.value = data.total
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.pageNo = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields()
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
/** 添加/修改操作 */
|
||||
const formRef = ref()
|
||||
const openForm = (type: string, id?: number) => {
|
||||
formRef.value.open(type, id)
|
||||
}
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (id: number) => {
|
||||
try {
|
||||
// 删除的二次确认
|
||||
await message.delConfirm()
|
||||
// 发起删除
|
||||
await RenewalProductApi.deleteRenewalProduct(id)
|
||||
message.success(t('common.delSuccess'))
|
||||
// 刷新列表
|
||||
await getList()
|
||||
} catch {}
|
||||
}
|
||||
|
||||
/** 导出按钮操作 */
|
||||
const handleExport = async () => {
|
||||
try {
|
||||
// 导出的二次确认
|
||||
await message.exportConfirm()
|
||||
// 发起导出
|
||||
exportLoading.value = true
|
||||
const data = await RenewalProductApi.exportRenewalProduct(queryParams)
|
||||
download.excel(data, '车辆续保产品信息.xls')
|
||||
} catch {
|
||||
} finally {
|
||||
exportLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 初始化 **/
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user