Merge branch 'master' into rescue
This commit is contained in:
commit
659ed62893
44
src/components/CommonTimeSelect/index.vue
Normal file
44
src/components/CommonTimeSelect/index.vue
Normal file
@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<div class="common-time-select">
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="yyyy-MM-dd"
|
||||
@change="handleChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'CommonTimeSelect',
|
||||
props: {
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dateRange: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
immediate: true,
|
||||
handler(newVal) {
|
||||
this.dateRange = [...newVal]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleChange(value) {
|
||||
this.$emit('input', value)
|
||||
this.$emit('change', value)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
598
src/utils/utils.js
Normal file
598
src/utils/utils.js
Normal file
@ -0,0 +1,598 @@
|
||||
import request from '@/utils/request';
|
||||
import {
|
||||
setStorageWithExpiry,
|
||||
getStorageWithExpiry
|
||||
} from '@/utils/auth'
|
||||
|
||||
export function getWXStatusHeight() {
|
||||
// #ifdef MP-WEIXIN
|
||||
// 获取距上
|
||||
const barTop = wx.getSystemInfoSync().statusBarHeight
|
||||
// 获取胶囊按钮位置信息
|
||||
const menuButtonInfo = wx.getMenuButtonBoundingClientRect()
|
||||
// 获取导航栏高度
|
||||
const barHeight = menuButtonInfo.height + (menuButtonInfo.top - barTop) * 2
|
||||
let barWidth = menuButtonInfo.width
|
||||
console.log('menuButtonInfo', menuButtonInfo)
|
||||
let barLeftPosition = 375 - menuButtonInfo.right + menuButtonInfo.width
|
||||
let menuButtonLeft = menuButtonInfo.left
|
||||
let menuButtonRight = menuButtonInfo.right
|
||||
return {
|
||||
barHeight,
|
||||
barTop,
|
||||
barWidth,
|
||||
barLeftPosition,
|
||||
menuButtonLeft,
|
||||
menuButtonRight
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据订单的状态获取订单的文字展示状态(这个状态范围少,是按李总意思整理出来的状态)
|
||||
* @param ticketsStatus 订单状态
|
||||
* @param isHandover 是否交车
|
||||
*/
|
||||
export function getOrderStatusText(ticketsStatus, isHandover) {
|
||||
let str = "已进厂";
|
||||
if ("04" == ticketsStatus) {
|
||||
//待派工
|
||||
str = "待维修"
|
||||
} else if ("05" == ticketsStatus) {
|
||||
//维修中
|
||||
str = "维修中"
|
||||
} else if ("01" == ticketsStatus) {
|
||||
//待取车结算
|
||||
if ("1" == isHandover) {
|
||||
//已交车
|
||||
str = "已交车未结算"
|
||||
} else {
|
||||
//未交车
|
||||
str = "未交车未结算"
|
||||
}
|
||||
} else if ("06" == ticketsStatus) {
|
||||
//挂单/记账
|
||||
if ("1" == isHandover) {
|
||||
//已交车
|
||||
str = "已交车已结算"
|
||||
} else {
|
||||
//未交车
|
||||
str = "已结算未交车"
|
||||
}
|
||||
} else if ("07" == ticketsStatus) {
|
||||
//待通知客户取车
|
||||
str = "已竣工"
|
||||
} else if ("02" == ticketsStatus) {
|
||||
//已结账
|
||||
if ("1" == isHandover) {
|
||||
//已交车
|
||||
str = "已交车已结算"
|
||||
} else {
|
||||
//未交车
|
||||
str = "已结算未交车"
|
||||
}
|
||||
} else if ("03" == ticketsStatus) {
|
||||
//已作废
|
||||
str = "已作废"
|
||||
} else if ("08" == ticketsStatus) {
|
||||
//已作废
|
||||
str = "已完成"
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据订单的状态获取订单的文字展示状态(这个状态多,就是系统初始状态)
|
||||
* @param ticketsStatus 订单状态
|
||||
* @param isHandover 是否交车
|
||||
*/
|
||||
export function getOrderStatusTextAll(ticketsStatus, isHandover) {
|
||||
let str = "已进厂";
|
||||
if ("04" == ticketsStatus) {
|
||||
//待派工
|
||||
str = "待派工"
|
||||
} else if ("05" == ticketsStatus) {
|
||||
//维修中
|
||||
str = "维修中"
|
||||
} else if ("01" == ticketsStatus) {
|
||||
//待取车结算
|
||||
if ("1" == isHandover) {
|
||||
//已交车
|
||||
str = "已交车未结算"
|
||||
} else {
|
||||
//未交车
|
||||
str = "未交车未结算"
|
||||
}
|
||||
} else if ("06" == ticketsStatus) {
|
||||
//挂单/记账
|
||||
str = "已挂单/记账待交车"
|
||||
if ("1" == isHandover) {
|
||||
//已交车
|
||||
str = "已交车已结算"
|
||||
} else {
|
||||
//未交车
|
||||
str = "已结算未交车"
|
||||
}
|
||||
} else if ("07" == ticketsStatus) {
|
||||
//待通知客户取车
|
||||
str = "待通知客户取车"
|
||||
} else if ("02" == ticketsStatus) {
|
||||
//已结账
|
||||
if ("1" == isHandover) {
|
||||
//已交车
|
||||
str = "已交车已结算"
|
||||
} else {
|
||||
//未交车
|
||||
str = "已结算未交车"
|
||||
}
|
||||
} else if ("03" == ticketsStatus) {
|
||||
//已作废
|
||||
str = "已作废"
|
||||
} else if ("08" == ticketsStatus) {
|
||||
//已作废
|
||||
str = "已完成"
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询字典可选值
|
||||
* @param dictCode
|
||||
*/
|
||||
export function getDictByCode(dictCode) {
|
||||
let dictArray = getStorageWithExpiry(dictCode);
|
||||
if (null == dictArray || undefined == dictArray) {
|
||||
request({
|
||||
url: '/admin-api/system/dict-data/type',
|
||||
method: 'get',
|
||||
params: {
|
||||
type: dictCode
|
||||
}
|
||||
}).then((res) => {
|
||||
console.log(res)
|
||||
if (res.code == 200) {
|
||||
setStorageWithExpiry(dictCode, res.data, 3600)
|
||||
return res.data
|
||||
}
|
||||
})
|
||||
} else {
|
||||
return dictArray
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 工单记录操作日志
|
||||
* @param id 工单主表id
|
||||
* @param ticketsWorkStatus 工单主表状态
|
||||
* @param itemId 工单子表id
|
||||
* @param itemStatus 工单子表状态
|
||||
* @param recordType 操作类型 对应后端枚举:RecordTypeEnum
|
||||
* @param remark 备注
|
||||
* @param image 图片相对路径,多个英文逗号隔开
|
||||
* @param finishType 完成类型 01:完成并移交下一班组、02:完成并移交总检、03:完成工单
|
||||
* @param nextName 下一班组名称
|
||||
*/
|
||||
export function saveTicketsRecords(id, ticketsWorkStatus, itemId, itemStatus, recordType, remark, image, finishType,
|
||||
nextName) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let dataObj = {
|
||||
id: id,
|
||||
ticketsWorkStatus: ticketsWorkStatus,
|
||||
item: {
|
||||
id: itemId,
|
||||
itemStatus: itemStatus
|
||||
},
|
||||
recordType: recordType,
|
||||
remark: remark,
|
||||
finishType: finishType,
|
||||
nextName: nextName,
|
||||
image: image
|
||||
}
|
||||
request({
|
||||
url: '/admin-api/repair/tickets/updateStatus',
|
||||
method: 'POST',
|
||||
data: dataObj
|
||||
}).then((res) => {
|
||||
console.log(res)
|
||||
if (res.code == 200) {
|
||||
uni.showToast({
|
||||
title: '操作成功',
|
||||
icon: 'none'
|
||||
})
|
||||
resolve(1);
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '操作失败,请联系管理员',
|
||||
icon: 'none'
|
||||
})
|
||||
reject(0);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 翻译字典
|
||||
* @param dictCode
|
||||
*/
|
||||
export async function getDictTextByCodeAndValue(dictCode, value) {
|
||||
let dictArray = getStorageWithExpiry(dictCode);
|
||||
if (null == dictArray || undefined == dictArray) {
|
||||
let res = await request({
|
||||
url: '/admin-api/system/dict-data/type',
|
||||
method: 'get',
|
||||
params: {
|
||||
type: dictCode
|
||||
}
|
||||
})
|
||||
if (res.code == 200) {
|
||||
setStorageWithExpiry(dictCode, res.data, 3600)
|
||||
dictArray = res.data
|
||||
let dictObj = dictArray.find(item => item.value == value)
|
||||
if (dictObj) {
|
||||
return dictObj.label
|
||||
} else {
|
||||
return "未知数据"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let dictObj = dictArray.find(item => item.value == value)
|
||||
if (dictObj) {
|
||||
return dictObj.label
|
||||
} else {
|
||||
return "未知数据"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function formatTimestamp(timestamp) {
|
||||
// 将时间戳转换为Date对象
|
||||
const date = new Date(timestamp);
|
||||
// 获取年月日时分秒
|
||||
const year = date.getFullYear();
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
||||
const day = date.getDate().toString().padStart(2, '0');
|
||||
const hours = date.getHours().toString().padStart(2, '0');
|
||||
const minutes = date.getMinutes().toString().padStart(2, '0');
|
||||
const seconds = date.getSeconds().toString().padStart(2, '0');
|
||||
// 组合成日期时间字符串
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将时间戳转换为指定格式的日期字符串
|
||||
* @param {number} timestamp - 时间戳(毫秒)
|
||||
* @param {string} [format='YYYY-MM-DD'] - 日期格式,默认为 'YYYY-MM-DD'
|
||||
* @returns {string} - 格式化的日期字符串
|
||||
*/
|
||||
export function formatTimestampCustom(timestamp, format = 'YYYY-MM-DD') {
|
||||
const date = new Date(timestamp);
|
||||
|
||||
const year = date.getFullYear();
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
||||
const day = date.getDate().toString().padStart(2, '0');
|
||||
const hour = date.getHours().toString().padStart(2, '0');
|
||||
const minute = date.getMinutes().toString().padStart(2, '0');
|
||||
const second = date.getSeconds().toString().padStart(2, '0');
|
||||
|
||||
const replaceMap = {
|
||||
'YYYY': year,
|
||||
'MM': month,
|
||||
'DD': day,
|
||||
'HH': hour,
|
||||
'mm': minute,
|
||||
'ss': second
|
||||
};
|
||||
|
||||
return format.replace(/YYYY|MM|DD|HH|mm|ss/g, match => replaceMap[match]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化金额
|
||||
* @param {string|number} amount - 金额
|
||||
* @returns {string} - 格式化后的金额
|
||||
*/
|
||||
export function formatCurrency(amount) {
|
||||
if (amount === undefined || amount === null || amount === '') {
|
||||
return '0.00';
|
||||
}
|
||||
// 处理可能的字符串类型金额
|
||||
const num = typeof amount === 'string' ? parseFloat(amount) : amount;
|
||||
// 检查是否是有效数字
|
||||
if (isNaN(num)) {
|
||||
return '0.00';
|
||||
}
|
||||
// 格式化金额,保留两位小数
|
||||
return num.toLocaleString('zh-CN', {
|
||||
minimumFractionDigits: 2,
|
||||
numberOfDigits: 2
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 组装订单对象
|
||||
* @param order
|
||||
*/
|
||||
export function builderOrder(order) {
|
||||
return {
|
||||
id: order.id,
|
||||
orderNo: order.ticketNo,
|
||||
flag: 1,
|
||||
ticketsStatus: order.ticketsStatus,
|
||||
ticketsWorkStatus: order.ticketsWorkStatus,
|
||||
flagStr: getOrderStatusTextAll(order.ticketsStatus, order.isHandover),
|
||||
carNum: order.carNo,
|
||||
nowRepairId: order.nowRepairId,
|
||||
carModel: order.carBrandName,
|
||||
userName: order.userName,
|
||||
userPhone: order.userMobile,
|
||||
counselorName: order.adviserName,
|
||||
canOperate: order.canOperate,
|
||||
...order,
|
||||
}
|
||||
}
|
||||
|
||||
export function formatDate(timestamp) {
|
||||
// 将时间戳转换为Date对象
|
||||
const date = new Date(timestamp);
|
||||
// 获取年月日时分秒
|
||||
const year = date.getFullYear();
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
||||
const day = date.getDate().toString().padStart(2, '0');
|
||||
// 组合成日期时间字符串
|
||||
return `${year}-${month}-${day}`;
|
||||
}
|
||||
|
||||
//转换为double
|
||||
// utils.js
|
||||
export function convertToDouble(value, decimalPlaces = 1) {
|
||||
if (value !== undefined && value !== null) {
|
||||
const parsedValue = parseFloat(value);
|
||||
if (!isNaN(parsedValue)) {
|
||||
return parsedValue.toFixed(decimalPlaces);
|
||||
} else {
|
||||
console.error('转换失败,值不是有效的数字');
|
||||
return '0.0'; // 可以设置一个默认值
|
||||
}
|
||||
} else {
|
||||
console.error('值不存在');
|
||||
return '0.0'; // 可以设置一个默认值
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成一个16位的纯数字的唯一ID
|
||||
* 生成策略 head + 当前时间戳 + 随机数
|
||||
* @param head 前缀
|
||||
*/
|
||||
export function createUniqueCodeByHead(head = '') {
|
||||
const min = 100; // 最小值
|
||||
const max = 999; // 最大值
|
||||
return head.toString() + Date.now().toString() + Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造树
|
||||
* @param items 原对象数组
|
||||
* @param idKey 主标识
|
||||
* @param parentKey 父标识
|
||||
* @param mapping 映射Map
|
||||
*/
|
||||
export function buildTree(items, idKey, parentKey, mapping = null) {
|
||||
const result = []; // 存储最终的树形结构
|
||||
const itemMap = {}; // 用于快速查找对象
|
||||
|
||||
// 首先将所有项放入map中,便于后续快速查找
|
||||
for (const item of items) {
|
||||
itemMap[item[idKey]] = {
|
||||
...item,
|
||||
children: []
|
||||
};
|
||||
}
|
||||
|
||||
// 遍历每个项,构建树形结构
|
||||
for (const item of items) {
|
||||
const id = item[idKey];
|
||||
const parentId = item[parentKey];
|
||||
|
||||
const node = itemMap[id];
|
||||
if (parentId !== null && itemMap[parentId]) {
|
||||
// 如果有父ID,并且父节点存在,则将当前节点加入到其父节点的children数组中
|
||||
itemMap[parentId].children.push(node);
|
||||
} else {
|
||||
// 如果没有父ID,或者找不到对应的父节点,则认为这是根节点
|
||||
result.push(node);
|
||||
}
|
||||
}
|
||||
|
||||
if (mapping) {
|
||||
return mapTree(result, mapping)
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 映射函数
|
||||
function mapTree(tree, mapping) {
|
||||
if (!tree || !Array.isArray(tree)) {
|
||||
return tree;
|
||||
}
|
||||
|
||||
const mappedTree = tree.map(item => {
|
||||
const mappedItem = {};
|
||||
for (const key in item) {
|
||||
if (key === 'children') {
|
||||
// 递归处理 children 数组
|
||||
if (mapping.children) {
|
||||
mappedItem[mapping.children] = mapTree(item[key], mapping);
|
||||
} else {
|
||||
mappedItem[key] = mapTree(item[key], mapping);
|
||||
}
|
||||
} else if (key in mapping) {
|
||||
// 根据映射规则转换属性
|
||||
const targetKey = mapping[key];
|
||||
mappedItem[targetKey] = item[key];
|
||||
}
|
||||
}
|
||||
return mappedItem;
|
||||
});
|
||||
|
||||
return mappedTree;
|
||||
}
|
||||
|
||||
export function formatDateChinese(timestamp) {
|
||||
// 将时间戳转换为Date对象
|
||||
const date = new Date(timestamp);
|
||||
// 获取年月日时分秒
|
||||
const year = date.getFullYear();
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
||||
const day = date.getDate().toString().padStart(2, '0');
|
||||
// 组合成日期时间字符串
|
||||
return `${year}年${month}月${day}日`;
|
||||
}
|
||||
|
||||
export function formatDateTimeToMinute(timestamp) {
|
||||
// 将时间戳转换为 Date 对象
|
||||
const date = new Date(timestamp);
|
||||
// 获取年月日时分
|
||||
const year = date.getFullYear();
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
||||
const day = date.getDate().toString().padStart(2, '0');
|
||||
const hours = date.getHours().toString().padStart(2, '0');
|
||||
const minutes = date.getMinutes().toString().padStart(2, '0');
|
||||
// 组合成日期时间字符串(格式:yyyy-MM-dd hh:mm)
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
||||
}
|
||||
|
||||
export function getDateRange(type) {
|
||||
const now = new Date()
|
||||
let start, end
|
||||
|
||||
if (type === 'week') {
|
||||
// 获取本周的开始(周一)和结束(周日)
|
||||
const day = now.getDay() || 7 // Sunday 为 0,设为 7
|
||||
start = new Date(now)
|
||||
start.setDate(now.getDate() - day + 1)
|
||||
|
||||
end = new Date(start)
|
||||
end.setDate(start.getDate() + 6)
|
||||
} else if (type === 'month') {
|
||||
// 获取本月的开始和结束
|
||||
start = new Date(now.getFullYear(), now.getMonth(), 1)
|
||||
end = new Date(now.getFullYear(), now.getMonth() + 1, 0) // 本月最后一天
|
||||
} else if (type === 'day') {
|
||||
// 获取当天的开始和结束(00:00:00 到 23:59:59)
|
||||
start = new Date(now)
|
||||
start.setHours(0, 0, 0, 0)
|
||||
|
||||
end = new Date(now)
|
||||
end.setHours(23, 59, 59, 999)
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
|
||||
return [
|
||||
formatDateCus(start),
|
||||
formatDateCus(end)
|
||||
]
|
||||
}
|
||||
|
||||
export function formatDateCus(date) {
|
||||
const y = date.getFullYear()
|
||||
const m = (date.getMonth() + 1).toString().padStart(2, '0')
|
||||
const d = date.getDate().toString().padStart(2, '0')
|
||||
return `${y}-${m}-${d}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 将扁平数组转换为树形结构,并支持按 sort 字段排序
|
||||
* @param {Array} data 源数据
|
||||
* @param {String} id 节点ID字段名,默认为 'id'
|
||||
* @param {String} parentId 父节点ID字段名,默认为 'parentId'
|
||||
* @param {String} children 子节点字段名,默认为 'children'
|
||||
* @param {Number|String} rootId 根节点ID值,默认为最小的parentId或0
|
||||
* @param {String} sortKey 排序字段名,默认为 'sort'
|
||||
* @returns {Array} 树形结构数据
|
||||
*/
|
||||
export function handleTree(data, id, parentId, children, rootId, sortKey) {
|
||||
// 参数默认值处理
|
||||
id = id || 'id';
|
||||
parentId = parentId || 'parentId';
|
||||
children = children || 'children';
|
||||
sortKey = sortKey || 'sort';
|
||||
|
||||
// 自动计算根节点ID(取最小的parentId,若无则用0)
|
||||
rootId = rootId || Math.min(...data.map(item => item[parentId])) || 0;
|
||||
|
||||
// 深拷贝源数据以避免污染原数组
|
||||
const cloneData = JSON.parse(JSON.stringify(data));
|
||||
|
||||
// 先对所有数据进行排序(确保父节点在前)
|
||||
cloneData.sort((a, b) => {
|
||||
const aSort = a[sortKey] ?? 0; // 使用空值合并运算符处理undefined
|
||||
const bSort = b[sortKey] ?? 0;
|
||||
return aSort - bSort; // 升序排序
|
||||
});
|
||||
|
||||
// 构建哈希表加速查找
|
||||
const nodeMap = {};
|
||||
cloneData.forEach(item => {
|
||||
nodeMap[item[id]] = item;
|
||||
item[children] = []; // 初始化children数组
|
||||
});
|
||||
|
||||
// 构建树形结构
|
||||
const tree = [];
|
||||
cloneData.forEach(item => {
|
||||
if (item[parentId] === rootId) {
|
||||
// 根节点直接加入结果
|
||||
tree.push(item);
|
||||
} else {
|
||||
// 非根节点找到父节点并插入
|
||||
const parent = nodeMap[item[parentId]];
|
||||
parent?.[children]?.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
// 递归排序所有子节点
|
||||
const sortChildren = (nodes) => {
|
||||
nodes.forEach(node => {
|
||||
if (node[children]?.length) {
|
||||
node[children].sort((a, b) => {
|
||||
const aSort = a[sortKey] ?? 0;
|
||||
const bSort = b[sortKey] ?? 0;
|
||||
return aSort - bSort;
|
||||
});
|
||||
sortChildren(node[children]);
|
||||
}
|
||||
});
|
||||
};
|
||||
sortChildren(tree);
|
||||
|
||||
return tree.length ? tree : data; // 空树时返回原数据
|
||||
}
|
||||
|
||||
/**
|
||||
* 将树形结构数据转成 uniapp multiSelector picker 可用的二维数组
|
||||
* @param {Array} tree 树形结构数据
|
||||
* @param {String} labelKey 节点显示字段,默认为 'name'
|
||||
* @param {String} childrenKey 子节点字段,默认为 'children'
|
||||
* @returns {Array} picker二维数组,例如 [[一级], [二级], [三级]...]
|
||||
*/
|
||||
export function toPickerData(tree, labelKey = 'name', childrenKey = 'children') {
|
||||
const result = []
|
||||
|
||||
function buildColumns(nodes, level = 0) {
|
||||
if (!nodes || !nodes.length) return
|
||||
// 当前层级的所有 name
|
||||
result[level] = nodes.map(n => n[labelKey])
|
||||
// 默认取第一个子节点继续递归
|
||||
if (nodes[0][childrenKey] && nodes[0][childrenKey].length) {
|
||||
buildColumns(nodes[0][childrenKey], level + 1)
|
||||
}
|
||||
}
|
||||
|
||||
buildColumns(tree, 0)
|
||||
return result
|
||||
}
|
||||
346
src/views/drivingSchool/drivingSchoolInsurance/index123.vue
Normal file
346
src/views/drivingSchool/drivingSchoolInsurance/index123.vue
Normal file
@ -0,0 +1,346 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="120px">
|
||||
|
||||
<el-form-item label="保险公司名称" prop="company">
|
||||
<el-input
|
||||
v-model="queryParams.company"
|
||||
placeholder="请输入保险公司名称"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="车牌号" prop="carNo">
|
||||
<el-input
|
||||
v-model="queryParams.carNo"
|
||||
placeholder="请输入车牌号"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-plus"
|
||||
size="mini"
|
||||
@click="handleAdd"
|
||||
>新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="el-icon-delete"
|
||||
size="mini"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
>删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="el-icon-download"
|
||||
size="mini"
|
||||
@click="handleExport"
|
||||
>导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="insuranceList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="负责人1" align="center" prop="userName" />
|
||||
<el-table-column label="负责人2" align="center" prop="userNames" />
|
||||
<!-- <el-table-column label="车辆" align="center" prop="carName" />-->
|
||||
<el-table-column label="车牌号" align="carNo" prop="carNo" />
|
||||
<el-table-column label="保险公司名称" align="center" prop="company" />
|
||||
<el-table-column label="内容" align="center" prop="content">
|
||||
<template slot-scope="scope">
|
||||
<el-button @click="viewContentFun(scope.row.content)" type="text" slot="reference">查看</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="保险金额" align="center" prop="money" />
|
||||
<el-table-column label="保险到期时间" align="center" prop="insuranceTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.insuranceTime, '{y}-{m}-{d}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
>修改</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 添加或修改保险管理对话框 -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="750px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="120px">
|
||||
<el-form-item label="负责人1" prop="userName">
|
||||
<el-input v-model="form.userName" placeholder="请输入负责人1" />
|
||||
</el-form-item>
|
||||
<el-form-item label="负责人2" prop="userNames">
|
||||
<el-input v-model="form.userNames" placeholder="请输入负责人2" />
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="车辆" prop="carId">
|
||||
<template>
|
||||
<el-select v-model="form.carId" placeholder="请选择车辆">
|
||||
<el-option
|
||||
v-for="item in carLists"
|
||||
:key="item.id"
|
||||
:label="item.carModel"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-form-item>-->
|
||||
<el-form-item label="车牌号" prop="carNo">
|
||||
<el-input v-model="form.carNo" placeholder="请输入车牌号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="保险公司名称" prop="company">
|
||||
<el-input v-model="form.company" placeholder="请输入保险公司名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="保险内容" prop="content">
|
||||
<editor v-model="form.content" :min-height="192"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="保险金额" prop="money">
|
||||
<el-input v-model="form.money" placeholder="请输入保险金额" />
|
||||
</el-form-item>
|
||||
<el-form-item label="保险到期时间" prop="insuranceTime">
|
||||
<el-date-picker clearable
|
||||
v-model="form.insuranceTime"
|
||||
type="date"
|
||||
value-format="yyyy-MM-dd"
|
||||
placeholder="请选择保险到期时间">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-dialog title="查看" :visible.sync="viewFlag" width="65%" append-to-body>
|
||||
<div style="box-sizing: border-box;padding: 15px;overflow: hidden" v-html="viewContent"></div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listInsurance, getInsurance, delInsurance, addInsurance, updateInsurance ,listCards} from "./api/insurance";
|
||||
import editor from '@/components/Editor/index.vue'
|
||||
export default {
|
||||
name: "Insurance",
|
||||
components: {editor},
|
||||
data() {
|
||||
return {
|
||||
viewContent:"",
|
||||
viewFlag:false,
|
||||
carLists:[],
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 选中数组
|
||||
ids: [],
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 保险管理表格数据
|
||||
insuranceList: [],
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
deptId: null,
|
||||
userId: null,
|
||||
carId: null,
|
||||
company: null,
|
||||
content: null,
|
||||
money: null,
|
||||
insuranceTime: null,
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
userName: [
|
||||
{ required: true, message: "负责人不能为空", trigger: "blur" }
|
||||
],
|
||||
carId: [
|
||||
{ required: true, message: "车辆id不能为空", trigger: "blur" }
|
||||
],
|
||||
company: [
|
||||
{ required: true, message: "保险公司名称不能为空", trigger: "blur" }
|
||||
],
|
||||
content: [
|
||||
{ required: true, message: "保险内容不能为空", trigger: "blur" }
|
||||
],
|
||||
money: [
|
||||
{ required: true, message: "保险金额不能为空", trigger: "blur" }
|
||||
],
|
||||
insuranceTime: [
|
||||
{ required: true, message: "保险到期时间不能为空", trigger: "blur" }
|
||||
],
|
||||
carNo: [
|
||||
{ required: true, message: "保险到期时间不能为空", trigger: "blur" }
|
||||
],
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
this.listCards();
|
||||
},
|
||||
methods: {
|
||||
|
||||
viewContentFun(data){
|
||||
this.viewContent =data;
|
||||
this.viewFlag = true;
|
||||
},
|
||||
|
||||
listCards(){
|
||||
listCards().then(response => {
|
||||
this.carLists = response.data;
|
||||
});
|
||||
},
|
||||
/** 查询保险管理列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
listInsurance(this.queryParams).then(response => {
|
||||
this.insuranceList = response.data.records;
|
||||
this.total = response.data.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
// 取消按钮
|
||||
cancel() {
|
||||
this.open = false;
|
||||
this.reset();
|
||||
},
|
||||
// 表单重置
|
||||
reset() {
|
||||
this.form = {
|
||||
id: null,
|
||||
deptId: null,
|
||||
userId: null,
|
||||
carId: null,
|
||||
company: null,
|
||||
content: null,
|
||||
money: null,
|
||||
insuranceTime: null,
|
||||
createTime: null,
|
||||
createBy: null,
|
||||
updateTime: null,
|
||||
updateBy: null
|
||||
};
|
||||
this.resetForm("form");
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
// 多选框选中数据
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.id)
|
||||
this.single = selection.length!==1
|
||||
this.multiple = !selection.length
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.open = true;
|
||||
this.title = "添加保险管理";
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.reset();
|
||||
const id = row.id || this.ids
|
||||
getInsurance(id).then(response => {
|
||||
this.form = response.data;
|
||||
this.open = true;
|
||||
this.title = "修改保险管理";
|
||||
});
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
if (this.form.id != null) {
|
||||
updateInsurance(this.form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
} else {
|
||||
addInsurance(this.form).then(response => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const ids = row.id || this.ids;
|
||||
this.$modal.confirm('是否确认删除保险管理编号为"' + ids + '"的数据项?').then(function() {
|
||||
return delInsurance(ids);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => {});
|
||||
},
|
||||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
this.download('drivingSchool/system/insurance/export', {
|
||||
...this.queryParams
|
||||
}, `insurance_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
315
src/views/inspection/businessStatistics/StatisticsDialog.vue
Normal file
315
src/views/inspection/businessStatistics/StatisticsDialog.vue
Normal file
@ -0,0 +1,315 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:title="dialogTitle"
|
||||
:visible.sync="visible"
|
||||
width="80%"
|
||||
top="5vh"
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<div class="statistics-dialog">
|
||||
<div class="time-selector">
|
||||
<common-time-select v-model="currentRange" @change="handleTimeChange" />
|
||||
</div>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<div class="loading-state" v-if="loading">
|
||||
<i class="el-icon-loading"></i>
|
||||
<span>数据加载中...</span>
|
||||
</div>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<div class="empty-state" v-else-if="datas.length === 0">
|
||||
<div class="empty-text">暂无数据</div>
|
||||
</div>
|
||||
|
||||
<!-- 根据不同ID显示不同内容 -->
|
||||
<div class="content-area" v-else>
|
||||
<!-- 客户来源统计 -->
|
||||
<div v-if="(id == 1 || id == 5)" class="customer-source">
|
||||
<el-table :data="datas" style="width: 100%">
|
||||
<el-table-column prop="name" label="客户来源" />
|
||||
<el-table-column prop="theNum" label="数量" />
|
||||
<el-table-column prop="theAmount" label="公示金额" />
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 检测车型统计 -->
|
||||
<div v-if="id == 2" class="car-model-stats">
|
||||
<el-table :data="datas" style="width: 100%">
|
||||
<el-table-column prop="goodsTitle" label="车型" />
|
||||
<el-table-column prop="theNum" label="数量" />
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 待收款统计 -->
|
||||
<div v-if="id == 3 || id == 7" class="pending-payment">
|
||||
<el-table
|
||||
:data="datas"
|
||||
style="width: 100%"
|
||||
@row-click="handlePendingPaymentRowClick"
|
||||
>
|
||||
<el-table-column prop="sourceName" label="渠道" />
|
||||
<el-table-column prop="pendingCount" label="台次" />
|
||||
<el-table-column prop="pendingAmountYuan" label="金额" />
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 检测类型统计 -->
|
||||
<div v-if="id == 4" class="inspection-type">
|
||||
<el-table :data="datas" style="width: 100%">
|
||||
<el-table-column prop="skuName" label="检测类型" />
|
||||
<el-table-column prop="orderCount" label="订单数量" />
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 资料统计 -->
|
||||
<div v-if="id == 6" class="document-stats">
|
||||
<el-table :data="datas" style="width: 100%">
|
||||
<el-table-column prop="fileName" label="文件名称" />
|
||||
<el-table-column prop="createTime" label="上传时间" />
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- WorkOrderList 弹窗 -->
|
||||
<el-dialog
|
||||
title="工单详情"
|
||||
:visible.sync="workOrderListVisible"
|
||||
width="80%"
|
||||
top="5vh"
|
||||
append-to-body
|
||||
v-if="workOrderListVisible"
|
||||
>
|
||||
<WorkOrderList
|
||||
:show-search="true"
|
||||
:show-summary="true"
|
||||
:external-query-params="workOrderListQueryParams"
|
||||
ref="workOrderList"
|
||||
/>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="workOrderListVisible = false">关闭</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as statisticsApi from './api/statistics'
|
||||
import CommonTimeSelect from '@/components/CommonTimeSelect'
|
||||
import WorkOrderList from '@/views/partner/components/WorkOrderList.vue'
|
||||
|
||||
export default {
|
||||
name: 'StatisticsDialog',
|
||||
components: {
|
||||
CommonTimeSelect,
|
||||
WorkOrderList
|
||||
},
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
id: {
|
||||
type: [String, Number],
|
||||
required: true
|
||||
},
|
||||
dataId: {
|
||||
type: [String, Number],
|
||||
default: null
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
range: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
extraParams: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentRange: [],
|
||||
datas: [],
|
||||
loading: false,
|
||||
// WorkOrderList 弹窗相关
|
||||
workOrderListVisible: false,
|
||||
workOrderListQueryParams: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
dialogTitle() {
|
||||
const titles = {
|
||||
1: '客户来源统计',
|
||||
2: '检测车型统计',
|
||||
3: '代收款',
|
||||
4: '检测类型统计',
|
||||
5: '客户来源统计',
|
||||
6: '资料统计',
|
||||
7: '来源-待收款'
|
||||
}
|
||||
return titles[this.id] || '统计详情'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
visible(val) {
|
||||
if (val) {
|
||||
this.currentRange = [...this.range]
|
||||
this.loadData()
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// 确保组件挂载时如果可见就加载数据
|
||||
if (this.visible) {
|
||||
this.currentRange = [...this.range]
|
||||
this.loadData()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClose() {
|
||||
this.$emit('update:visible', false)
|
||||
},
|
||||
|
||||
handleTimeChange(range) {
|
||||
this.currentRange = range
|
||||
this.loadData()
|
||||
},
|
||||
|
||||
async loadData() {
|
||||
this.loading = true
|
||||
try {
|
||||
const params = {
|
||||
startTime: this.currentRange[0],
|
||||
endTime: this.currentRange[1],
|
||||
...this.extraParams
|
||||
}
|
||||
|
||||
let response
|
||||
switch (this.id) {
|
||||
case 1:
|
||||
response = await statisticsApi.getStaticsTable3Detail({ ...params, remark: this.type })
|
||||
break
|
||||
case 2:
|
||||
response = await statisticsApi.getStaticsTable4(params)
|
||||
break
|
||||
case 3:
|
||||
response = await statisticsApi.getStaticsTable5(params)
|
||||
break
|
||||
case 4:
|
||||
response = await statisticsApi.queryInspectionSkuList(params)
|
||||
break
|
||||
case 5:
|
||||
response = await statisticsApi.customerSourceCount({ ...params, businessId: this.dataId })
|
||||
break
|
||||
case 6:
|
||||
response = await statisticsApi.getFileByType({ ...params, servicePackageId: 'jiance' })
|
||||
this.processFileData(response.data)
|
||||
break
|
||||
case 7:
|
||||
response = await statisticsApi.channelMoneyStaticsByBusi({ ...params, busi: this.type })
|
||||
break
|
||||
default:
|
||||
console.warn('Unknown statistics type:', this.id)
|
||||
}
|
||||
|
||||
if (response && response.data) {
|
||||
// 特殊处理某些返回数据格式不同的接口
|
||||
if (this.id === 4) {
|
||||
// 检测类型统计接口返回的是数组
|
||||
this.datas = Array.isArray(response.data) ? response.data : []
|
||||
} else if (this.id === 6) {
|
||||
// 资料统计已经在 processFileData 中处理
|
||||
} else {
|
||||
// 其他接口通常返回对象,其中包含 list 或 data 属性
|
||||
this.datas = response.data.list || response.data.data || response.data || []
|
||||
}
|
||||
} else {
|
||||
this.datas = []
|
||||
}
|
||||
} catch (error) {
|
||||
this.$message.error('数据加载失败: ' + (error.message || ''))
|
||||
console.error(error)
|
||||
this.datas = []
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
|
||||
processFileData(data) {
|
||||
if (this.type === 'add') {
|
||||
this.datas = data.insertFile || []
|
||||
} else if (this.type === 'update') {
|
||||
this.datas = data.updateFile || []
|
||||
} else {
|
||||
this.datas = []
|
||||
}
|
||||
},
|
||||
|
||||
// 处理待收款统计行点击事件
|
||||
handlePendingPaymentRowClick(row) {
|
||||
// 设置 WorkOrderList 查询参数
|
||||
this.workOrderListQueryParams = {
|
||||
datetimeRange: this.currentRange,
|
||||
customerSource: row.sourceName,
|
||||
...this.extraParams
|
||||
};
|
||||
|
||||
// 显示 WorkOrderList 弹窗
|
||||
this.workOrderListVisible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.statistics-dialog {
|
||||
.time-selector {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.loading-state {
|
||||
text-align: center;
|
||||
padding: 60px 0;
|
||||
|
||||
i {
|
||||
font-size: 24px;
|
||||
color: #409EFF;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 60px 0;
|
||||
|
||||
.empty-text {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.content-area {
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
// 添加行hover样式提示
|
||||
::v-deep .el-table__row {
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
119
src/views/inspection/businessStatistics/api/statistics.js
Normal file
119
src/views/inspection/businessStatistics/api/statistics.js
Normal file
@ -0,0 +1,119 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 检测数量统计
|
||||
export function getStaticsTable2(params) {
|
||||
return request({
|
||||
url: '/partnerOwn/partner/staticsTable2',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 营业额统计
|
||||
export function getStaticsTable1(params) {
|
||||
return request({
|
||||
url: '/partnerOwn/partner/staticsTable1',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 业务渠道统计
|
||||
export function getStaticsTable3(params) {
|
||||
return request({
|
||||
url: '/partnerOwn/partner/staticsTable3',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 检测车型统计
|
||||
export function getStaticsTable4(params) {
|
||||
return request({
|
||||
url: '/partnerOwn/partner/staticsTable4',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 待收款统计
|
||||
export function getStaticsTable5(params) {
|
||||
return request({
|
||||
url: '/partnerOwn/partner/staticsTable5',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 资料统计
|
||||
export function getFileStatistics(params) {
|
||||
return request({
|
||||
url: '/partnerOwn/partner/fileStatistics',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 检测类型统计
|
||||
export function queryInspectionSkuList(params) {
|
||||
return request({
|
||||
url: '/partnerOwn/partner/queryInspectionSkuList',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 成交金额图表
|
||||
export function chartLineInspectionAmount(params) {
|
||||
return request({
|
||||
url: '/partnerOwn/partner/chartLineInspectionAmount',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 检测数量图表
|
||||
export function chartLineInspectionNum(params) {
|
||||
return request({
|
||||
url: '/partnerOwn/partner/chartLineInspectionNum',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 客户来源统计详情
|
||||
export function getStaticsTable3Detail(params) {
|
||||
return request({
|
||||
url: '/partnerOwn/partner/staticsTable3Detail',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 根据类型获取文件
|
||||
export function getFileByType(params) {
|
||||
return request({
|
||||
url: '/partnerOwn/partner/getFileByType',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 渠道金额统计
|
||||
export function channelMoneyStaticsByBusi(params) {
|
||||
return request({
|
||||
url: '/partnerOwn/partner/channelMoneyStaticsByBusi',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 渠道金额统计
|
||||
export function customerSourceCount(params) {
|
||||
return request({
|
||||
url: '/partnerOwn/partner/customerSourceCount',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
620
src/views/inspection/businessStatistics/index.vue
Normal file
620
src/views/inspection/businessStatistics/index.vue
Normal file
@ -0,0 +1,620 @@
|
||||
<template>
|
||||
<div class="business-statistics">
|
||||
<div class="header">
|
||||
<h1>{{ titles }}</h1>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<!-- 检测数量统计 -->
|
||||
<el-card class="stat-card">
|
||||
<div class="title_">检测数量统计</div>
|
||||
<div class="card-content">
|
||||
<common-time-select v-model="ranges" @change="slectRangeInspectionCount"></common-time-select>
|
||||
<div class="stats-grid">
|
||||
<div class="stat-item" @click="openWorkOrderList({ chooseStatus: '1' })">
|
||||
<div class="text_">订单数量</div>
|
||||
<div class="value">{{ data2.allNum || 0 }}</div>
|
||||
</div>
|
||||
<div class="stat-item" @click="openWorkOrderList({ chooseStatus: '3' })">
|
||||
<div class="text_">完成数量</div>
|
||||
<div class="value">{{ data2.ywcNum || 0 }}</div>
|
||||
</div>
|
||||
<div class="stat-item" @click="openWorkOrderList({ status: '2' })">
|
||||
<div class="text_">检测中数量</div>
|
||||
<div class="value">{{ data2.jxzNum || 0 }}</div>
|
||||
</div>
|
||||
<div class="stat-item" @click="openWorkOrderList({ chooseStatus: '5' })">
|
||||
<div class="text_">重检数量</div>
|
||||
<div class="value">{{ data2.reinspectNum || 0 }}</div>
|
||||
</div>
|
||||
<div class="stat-item" @click="openWorkOrderList({ chooseStatus: '6' })">
|
||||
<div class="text_">复检数量</div>
|
||||
<div class="value">{{ data2.recheckNum || 0 }}</div>
|
||||
</div>
|
||||
<div class="stat-item" @click="openWorkOrderList({ chooseStatus: '4' })">
|
||||
<div class="text_">退办理数量</div>
|
||||
<div class="value">{{ data2.tblNum || 0 }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 营业额统计 -->
|
||||
<el-card class="stat-card">
|
||||
<div class="title_">营业额统计</div>
|
||||
<div class="card-content">
|
||||
<common-time-select v-model="rangeYYE" @change="slectRangeYYECount"></common-time-select>
|
||||
<div class="stats-grid">
|
||||
<div class="stat-item" @click="showOrderStatisticDialog('')">
|
||||
<div class="text_">公示价格</div>
|
||||
<div class="value">{{ data1.gsAmount || 0 }}</div>
|
||||
</div>
|
||||
<div class="stat-item" @click="showOrderStatisticDialog('')">
|
||||
<div class="text_">应收款</div>
|
||||
<div class="value">{{ data1.yskAmount || 0 }}</div>
|
||||
</div>
|
||||
<div class="stat-item" @click="showOrderStatisticDialog('1')">
|
||||
<div class="text_">已收款</div>
|
||||
<div class="value">{{ data1.yjsAmount || 0 }}</div>
|
||||
</div>
|
||||
<div class="stat-item" @click="showOrderStatisticDialog('0')">
|
||||
<div class="text_">待收款</div>
|
||||
<div class="value">{{ data1.dsAmount || 0 }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 业务渠道统计 -->
|
||||
<el-card class="stat-card">
|
||||
<div class="title_">业务渠道统计</div>
|
||||
<div class="card-content">
|
||||
<common-time-select v-model="rangeBusiness" @change="slectRangeBusinessCount"></common-time-select>
|
||||
<div v-if="data3.length > 0" class="channel-table">
|
||||
<div class="table-header">
|
||||
<div class="col l_">业务渠道</div>
|
||||
<div class="col n_">数量</div>
|
||||
<div class="col r_">公示金额</div>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<div
|
||||
v-for="(item,index) in data3"
|
||||
:key="index"
|
||||
class="table-row"
|
||||
@click="showDetailDialog(5, item.id)"
|
||||
>
|
||||
<div class="col l_">
|
||||
<span :class="'channel-tag channel-tag--' + (index % 4)">{{ item.name }}</span>
|
||||
</div>
|
||||
<div class="col n_">{{ item.theNum }}</div>
|
||||
<div class="col r_">{{ item.theAmount }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="no-data">暂无数据…</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 资料统计 -->
|
||||
<el-card class="stat-card">
|
||||
<div class="title_">资料统计</div>
|
||||
<div class="card-content">
|
||||
<common-time-select v-model="rangeZL" @change="slectRangeZLCount"></common-time-select>
|
||||
<div class="stats-grid">
|
||||
<div class="stat-item" @click="showDetailDialog2(6, 'add')">
|
||||
<div class="text_">新增</div>
|
||||
<div class="value">{{ fileRes.addCount || 0 }}</div>
|
||||
</div>
|
||||
<div class="stat-item" @click="showDetailDialog2(6, 'update')">
|
||||
<div class="text_">修改</div>
|
||||
<div class="value">{{ fileRes.updateCount || 0 }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 检测车型统计 -->
|
||||
<el-card class="stat-card">
|
||||
<div class="title-header">
|
||||
<div class="title_">检测车型统计</div>
|
||||
<el-button type="text" @click="showDetailDialog(2)">更多 ></el-button>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<common-time-select v-model="rangeGoods" @change="slectRangeGoodsCount"></common-time-select>
|
||||
<div v-if="data4.length > 0" class="stats-grid">
|
||||
<div class="stat-item" v-for="(item,index) in data4" :key="index">
|
||||
<div class="text_">{{ item.goodsTitle || '' }}</div>
|
||||
<div class="value">{{ item.theNum || '' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="no-data">暂无数据…</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 检测类型统计 -->
|
||||
<el-card class="stat-card">
|
||||
<div class="title-header">
|
||||
<div class="title_">检测类型统计</div>
|
||||
<el-button type="text" @click="showDetailDialog(4)">更多 ></el-button>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<common-time-select v-model="rangeSku" @change="slectRangeSkuCount"></common-time-select>
|
||||
<div v-if="skuList.length > 0" class="stats-grid">
|
||||
<div class="stat-item" v-for="(skuData, index) in skuList" :key="index">
|
||||
<div class="text_">{{ skuData.skuName }}</div>
|
||||
<div class="value">{{ skuData.orderCount || 0 }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="no-data">暂无数据…</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 待收款 -->
|
||||
<el-card class="stat-card">
|
||||
<div class="title-header">
|
||||
<div class="title_">待收款</div>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<common-time-select v-model="rangeDsk" @change="slectRangeDskCount"></common-time-select>
|
||||
<div v-if="data5.length === 0" class="no-data">暂无数据…</div>
|
||||
<div v-else class="stats-grid">
|
||||
<div
|
||||
class="stat-item multi-line"
|
||||
v-for="(item, index) in data5"
|
||||
:key="index"
|
||||
@click="showDetailDialog2(7, item.channel)"
|
||||
>
|
||||
<div class="text_">渠道:{{ item.channel || '' }}</div>
|
||||
<div class="sub-text">金额:{{ item.theAmount || '' }}</div>
|
||||
<div class="sub-text">台次:{{ item.order_count || '' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 统计详情弹窗 -->
|
||||
<statistics-dialog
|
||||
v-if="detailDialog.visible"
|
||||
:visible.sync="detailDialog.visible"
|
||||
:id="detailDialog.id"
|
||||
:data-id="detailDialog.dataId"
|
||||
:type="detailDialog.type"
|
||||
:range="detailDialog.range"
|
||||
/>
|
||||
|
||||
<!-- WorkOrderList 弹窗 -->
|
||||
<el-dialog
|
||||
title="工单详情"
|
||||
:visible.sync="workOrderListVisible"
|
||||
width="80%"
|
||||
top="5vh"
|
||||
append-to-body
|
||||
v-if="workOrderListVisible"
|
||||
>
|
||||
<WorkOrderList
|
||||
:show-search="true"
|
||||
:show-summary="true"
|
||||
:external-query-params="workOrderListQueryParams"
|
||||
ref="workOrderList"
|
||||
/>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="workOrderListVisible = false">关闭</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as statisticsApi from './api/statistics'
|
||||
import CommonTimeSelect from '@/components/CommonTimeSelect'
|
||||
import StatisticsDialog from './StatisticsDialog'
|
||||
import WorkOrderList from '@/views/partner/components/WorkOrderList.vue'
|
||||
|
||||
export default {
|
||||
name: 'BusinessStatistics',
|
||||
components: {
|
||||
CommonTimeSelect,
|
||||
StatisticsDialog,
|
||||
WorkOrderList
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
titles: "业务统计",
|
||||
// 统计数据
|
||||
data1: {},
|
||||
data2: {},
|
||||
data3: [],
|
||||
data4: [],
|
||||
data5: [],
|
||||
fileRes: {},
|
||||
skuList: [],
|
||||
// 时间范围
|
||||
ranges: [],
|
||||
rangeYYE: [],
|
||||
rangeBusiness: [],
|
||||
rangeZL: [],
|
||||
rangeGoods: [],
|
||||
rangeSku: [],
|
||||
rangeDsk: [],
|
||||
// 弹窗控制
|
||||
detailDialog: {
|
||||
visible: false,
|
||||
id: null,
|
||||
dataId: null,
|
||||
type: null,
|
||||
range: []
|
||||
},
|
||||
orderStatisticDialog: {
|
||||
visible: false,
|
||||
status: null
|
||||
},
|
||||
// WorkOrderList 弹窗控制
|
||||
workOrderListVisible: false,
|
||||
workOrderListQueryParams: {}
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
await this.initTimeRange()
|
||||
await this.loadAllData()
|
||||
},
|
||||
methods: {
|
||||
// 初始化时间范围
|
||||
initTimeRange() {
|
||||
const currentTime = this.$dayjs().format('YYYY-MM-DD')
|
||||
const ranges = [
|
||||
'ranges', 'rangeYYE', 'rangeBusiness', 'rangeZL',
|
||||
'rangeGoods', 'rangeSku', 'rangeDsk'
|
||||
]
|
||||
ranges.forEach(range => {
|
||||
this[range] = [currentTime, currentTime]
|
||||
})
|
||||
},
|
||||
|
||||
// 加载所有数据
|
||||
async loadAllData() {
|
||||
try {
|
||||
await Promise.all([
|
||||
this.getServerData1(),
|
||||
this.getServerData2(),
|
||||
this.getServerData3(),
|
||||
this.getInspectionSku(),
|
||||
this.getfive()
|
||||
])
|
||||
} catch (error) {
|
||||
this.$message.error('数据加载失败')
|
||||
console.error(error)
|
||||
}
|
||||
},
|
||||
|
||||
// 打开 WorkOrderList 弹窗
|
||||
openWorkOrderList(filters = {}) {
|
||||
return;
|
||||
// 设置查询参数,包括时间范围和筛选条件
|
||||
this.workOrderListQueryParams = {
|
||||
datetimeRange: this.ranges,
|
||||
...filters
|
||||
};
|
||||
|
||||
// 显示弹窗
|
||||
this.workOrderListVisible = true;
|
||||
},
|
||||
|
||||
// 显示详情弹窗
|
||||
showDetailDialog(id, dataId = null) {
|
||||
this.detailDialog = {
|
||||
visible: true,
|
||||
id,
|
||||
dataId,
|
||||
range: this.getRangeByType(id)
|
||||
}
|
||||
},
|
||||
|
||||
showDetailDialog2(id, type) {
|
||||
this.detailDialog = {
|
||||
visible: true,
|
||||
id,
|
||||
type,
|
||||
range: this.getRangeByType(id)
|
||||
}
|
||||
},
|
||||
|
||||
// 显示订单统计弹窗
|
||||
showOrderStatisticDialog(status) {
|
||||
// this.orderStatisticDialog = {
|
||||
// visible: true,
|
||||
// status
|
||||
// }
|
||||
},
|
||||
|
||||
showOrderCountDialog(type, data) {
|
||||
// 根据业务逻辑处理
|
||||
this.showDetailDialog(type, data)
|
||||
},
|
||||
|
||||
// 根据类型获取时间范围
|
||||
getRangeByType(id) {
|
||||
const rangeMap = {
|
||||
1: this.ranges,
|
||||
2: this.rangeGoods,
|
||||
3: this.rangeDsk,
|
||||
4: this.rangeSku,
|
||||
5: this.rangeBusiness,
|
||||
6: this.rangeZL,
|
||||
7: this.rangeDsk
|
||||
}
|
||||
return rangeMap[id] || this.ranges
|
||||
},
|
||||
|
||||
// 各种数据获取方法
|
||||
async slectRangeInspectionCount(e) {
|
||||
this.ranges = e
|
||||
await this.getServerData2()
|
||||
},
|
||||
|
||||
async slectRangeYYECount(e) {
|
||||
this.rangeYYE = e
|
||||
await this.getServerData1()
|
||||
},
|
||||
|
||||
async slectRangeBusinessCount(e) {
|
||||
this.rangeBusiness = e
|
||||
await this.getServerData3()
|
||||
},
|
||||
|
||||
async slectRangeZLCount(e) {
|
||||
this.rangeZL = e
|
||||
await this.getFileStatistics()
|
||||
},
|
||||
|
||||
async slectRangeGoodsCount(e) {
|
||||
this.rangeGoods = e
|
||||
await this.getStaticsTable4()
|
||||
},
|
||||
|
||||
async slectRangeSkuCount(e) {
|
||||
this.rangeSku = e
|
||||
await this.getInspectionSku()
|
||||
},
|
||||
|
||||
async slectRangeDskCount(e) {
|
||||
this.rangeDsk = e
|
||||
await this.getStaticsTable5()
|
||||
},
|
||||
|
||||
// API调用方法
|
||||
async getServerData1() {
|
||||
const params = {
|
||||
startTime: this.rangeYYE[0],
|
||||
endTime: this.rangeYYE[1]
|
||||
}
|
||||
const res = await statisticsApi.getStaticsTable1(params)
|
||||
this.data1 = res.data
|
||||
},
|
||||
|
||||
async getServerData2() {
|
||||
const params = {
|
||||
startTime: this.ranges[0],
|
||||
endTime: this.ranges[1]
|
||||
}
|
||||
const res = await statisticsApi.getStaticsTable2(params)
|
||||
this.data2 = res.data
|
||||
},
|
||||
|
||||
async getServerData3() {
|
||||
const params = {
|
||||
startTime: this.rangeBusiness[0],
|
||||
endTime: this.rangeBusiness[1]
|
||||
}
|
||||
const res = await statisticsApi.getStaticsTable3(params)
|
||||
this.data3 = res.data
|
||||
},
|
||||
|
||||
async getStaticsTable4() {
|
||||
const params = {
|
||||
startTime: this.rangeGoods[0],
|
||||
endTime: this.rangeGoods[1]
|
||||
}
|
||||
const res = await statisticsApi.getStaticsTable4(params)
|
||||
this.data4 = res.data
|
||||
},
|
||||
|
||||
async getStaticsTable5() {
|
||||
const params = {
|
||||
startTime: this.rangeDsk[0],
|
||||
endTime: this.rangeDsk[1]
|
||||
}
|
||||
const res = await statisticsApi.getStaticsTable5(params)
|
||||
this.data5 = res.data
|
||||
},
|
||||
|
||||
async getFileStatistics() {
|
||||
const params = {
|
||||
servicePackageId: 'jiance',
|
||||
startTime: this.rangeZL[0],
|
||||
endTime: this.rangeZL[1]
|
||||
}
|
||||
const res = await statisticsApi.getFileStatistics(params)
|
||||
this.fileRes = res.data
|
||||
},
|
||||
|
||||
async getInspectionSku() {
|
||||
const params = {
|
||||
startTime: this.rangeSku[0],
|
||||
endTime: this.rangeSku[1]
|
||||
}
|
||||
const res = await statisticsApi.queryInspectionSkuList(params)
|
||||
this.skuList = res.data
|
||||
},
|
||||
|
||||
async getfive() {
|
||||
await Promise.all([
|
||||
this.getServerData1(),
|
||||
this.getServerData2(),
|
||||
this.getServerData3(),
|
||||
this.getStaticsTable4(),
|
||||
this.getStaticsTable5(),
|
||||
this.getFileStatistics()
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.business-statistics {
|
||||
padding: 20px;
|
||||
background: #f4f5f6;
|
||||
min-height: 100vh;
|
||||
|
||||
.header {
|
||||
margin-bottom: 20px;
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
color: #101A3E;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
margin-bottom: 20px;
|
||||
|
||||
.title_ {
|
||||
font-size: 16px;
|
||||
color: #101A3E;
|
||||
margin-bottom: 15px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.title-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-content {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 15px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
background: #F7F8FC;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
background: #e8f4ff;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
&.multi-line {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.text_ {
|
||||
font-size: 14px;
|
||||
color: #101A3E;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #0D2E8D;
|
||||
}
|
||||
|
||||
.sub-text {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.channel-table {
|
||||
margin-top: 20px;
|
||||
|
||||
.table-header {
|
||||
display: flex;
|
||||
background: #F7F8FC;
|
||||
padding: 15px;
|
||||
border-radius: 8px 8px 0 0;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.table-body {
|
||||
border: 1px solid #F7F8FC;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.table-row {
|
||||
display: flex;
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid #E3ECFB;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s;
|
||||
|
||||
&:hover {
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.col {
|
||||
&.l_ { width: 33%; }
|
||||
&.n_ { width: 33%; text-align: center; }
|
||||
&.r_ { width: 33%; text-align: right; }
|
||||
}
|
||||
}
|
||||
|
||||
.channel-tag {
|
||||
display: inline-block;
|
||||
padding: 4px 12px;
|
||||
border-radius: 8px;
|
||||
font-size: 12px;
|
||||
|
||||
&--0 { background: #f6f0e5; }
|
||||
&--1 { background: #e6e6f9; }
|
||||
&--2 { background: #e2ebfb; }
|
||||
&--3 { background: #e4eff1; }
|
||||
}
|
||||
|
||||
.no-data {
|
||||
text-align: center;
|
||||
color: #999;
|
||||
padding: 40px 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.business-statistics {
|
||||
.container {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -120,6 +120,45 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 新增产值统计打印部分 -->
|
||||
<div class="print-section" v-if="baseDataInfo.outputMoneyStatistics">
|
||||
<h2>检测产值统计</h2>
|
||||
<table class="print-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>类型</th>
|
||||
<th>产值</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>初检公示产值</td>
|
||||
<td>
|
||||
{{ (baseDataInfo.outputMoneyStatistics && baseDataInfo.outputMoneyStatistics.initialInspectionOutputValue) || 0 }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>复检公示产值</td>
|
||||
<td>
|
||||
{{ (baseDataInfo.outputMoneyStatistics && baseDataInfo.outputMoneyStatistics.recheckInspectionOutputValue) || 0 }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>初检合格产值</td>
|
||||
<td>
|
||||
{{ (baseDataInfo.outputMoneyStatistics && baseDataInfo.outputMoneyStatistics.initialInspectionPassOutputValue) || 0 }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>复检合格产值</td>
|
||||
<td>
|
||||
{{ (baseDataInfo.outputMoneyStatistics && baseDataInfo.outputMoneyStatistics.recheckInspectionPassOutputValue) || 0 }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</PrintButton>
|
||||
@ -204,6 +243,48 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 新增的产值统计 -->
|
||||
<div class="db_">
|
||||
<div class="min_box">
|
||||
<div class="ds_" style="margin-bottom: 0px;">
|
||||
<img src="./assets/icon3.png" />
|
||||
<div>初检公示产值</div>
|
||||
</div>
|
||||
<div class="num_2">
|
||||
{{ (baseDataInfo.outputMoneyStatistics && baseDataInfo.outputMoneyStatistics.initialInspectionOutputValue) || 0 }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="min_box">
|
||||
<div class="ds_" style="margin-bottom: 0px;">
|
||||
<img src="./assets/icon4.png" />
|
||||
<div>复检公示产值</div>
|
||||
</div>
|
||||
<div class="num_2">
|
||||
{{ (baseDataInfo.outputMoneyStatistics && baseDataInfo.outputMoneyStatistics.recheckInspectionOutputValue) || 0 }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="db_">
|
||||
<div class="min_box">
|
||||
<div class="ds_" style="margin-bottom: 0px;">
|
||||
<img src="./assets/icon3.png" />
|
||||
<div>初检合格产值</div>
|
||||
</div>
|
||||
<div class="num_2">
|
||||
{{ (baseDataInfo.outputMoneyStatistics && baseDataInfo.outputMoneyStatistics.initialInspectionPassOutputValue) || 0 }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="min_box">
|
||||
<div class="ds_" style="margin-bottom: 0px;">
|
||||
<img src="./assets/icon4.png" />
|
||||
<div>复检合格产值</div>
|
||||
</div>
|
||||
<div class="num_2">
|
||||
{{ (baseDataInfo.outputMoneyStatistics && baseDataInfo.outputMoneyStatistics.recheckInspectionPassOutputValue) || 0 }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
@ -241,6 +322,7 @@ export default {
|
||||
staffInfo: {},
|
||||
goodsStatistics: [],
|
||||
inspectionStatistics: {},
|
||||
outputMoneyStatistics: {}, // 添加新字段
|
||||
},
|
||||
projectCount: {
|
||||
children: [],
|
||||
|
||||
526
src/views/partner/components/WorkOrderList.vue
Normal file
526
src/views/partner/components/WorkOrderList.vue
Normal file
@ -0,0 +1,526 @@
|
||||
<template>
|
||||
<div class="work-order-list">
|
||||
<el-form
|
||||
:model="queryParams"
|
||||
ref="queryForm"
|
||||
size="small"
|
||||
:inline="true"
|
||||
v-show="showSearch"
|
||||
label-width="68px"
|
||||
>
|
||||
<el-form-item label="车牌号" prop="carNum">
|
||||
<el-input
|
||||
v-model="queryParams.carModelOrCarYear"
|
||||
placeholder="请输入车牌号"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="车龄" prop="carYear">
|
||||
<el-input
|
||||
v-model="queryParams.carYear"
|
||||
placeholder="请输入车龄"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="检测类型" prop="goodsTitle">
|
||||
<el-select
|
||||
v-model="queryParams.skuName"
|
||||
placeholder="请选择检测类型"
|
||||
clearable
|
||||
>
|
||||
<el-option
|
||||
v-for="dict in skuNames"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="业务渠道" prop="businessChannel">
|
||||
<el-select
|
||||
v-model="queryParams.businessChannel"
|
||||
filterable
|
||||
clearable
|
||||
placeholder="请选择业务渠道"
|
||||
>
|
||||
<el-option
|
||||
v-for="dict in businessList"
|
||||
:key="dict.id"
|
||||
:label="dict.name"
|
||||
:value="dict.name"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="客户来源" prop="customerSource">
|
||||
<el-select
|
||||
v-model="queryParams.customerSource"
|
||||
filterable
|
||||
clearable
|
||||
placeholder="请选择客户来源"
|
||||
>
|
||||
<el-option
|
||||
v-for="dict in customerData"
|
||||
:key="dict.id"
|
||||
:label="dict.name"
|
||||
:value="dict.name"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="支付方式" prop="payType">
|
||||
<el-select
|
||||
v-model="queryParams.payType"
|
||||
placeholder="支付方式"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
>
|
||||
<el-option
|
||||
v-for="dict in payTypeOptions"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="筛选类型" prop="dateType">
|
||||
<el-select
|
||||
v-model="queryParams.dateType"
|
||||
placeholder="请选择日期类型"
|
||||
clearable
|
||||
style="width: 180px"
|
||||
>
|
||||
<el-option label="检测时间" value="jcTime"/>
|
||||
<el-option label="保险到期时间(交强)" value="bxTime"/>
|
||||
<el-option label="保险到期时间(商业)" value="bxVehicleTime"/>
|
||||
<el-option label="下次年检时间" value="nextInspectionTime"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="datetimeRange">
|
||||
<el-date-picker
|
||||
v-model="queryParams.datetimeRange"
|
||||
type="daterange"
|
||||
value-format="yyyy-MM-dd"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
>
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-search"
|
||||
size="mini"
|
||||
@click="handleQuery"
|
||||
>搜索
|
||||
</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<div class="summary-info" v-if="showSummary">
|
||||
<span>公示应收价格汇总:{{ moneyData.goodsPriceSum / 100 }} 元</span>
|
||||
<span style="margin-left: 3%">实付金额汇总:{{ moneyData.payMoneySum / 100 }} 元</span>
|
||||
</div>
|
||||
|
||||
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="infoList"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center"/>
|
||||
<el-table-column label="车牌号" align="center">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.carNum || scope.row.certificateNum || "----" }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="业务渠道" align="center" prop="businessChannel"></el-table-column>
|
||||
<el-table-column label="客户来源" align="center" prop="customerSource"></el-table-column>
|
||||
<el-table-column label="车主姓名" prop="buyName"></el-table-column>
|
||||
<el-table-column label="车主手机号" prop="buyPhone"></el-table-column>
|
||||
<el-table-column label="检测结果" align="center" prop="isPass">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.isPass == '0'">不合格</span>
|
||||
<span v-else-if="scope.row.isPass == '1'">合格</span>
|
||||
<span v-else>进行中</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="车辆类型" align="center" prop="goodsTitle"/>
|
||||
<el-table-column label="检测项目" align="center" prop="skuName"/>
|
||||
<el-table-column label="公示应收价格" align="center" prop="realPayMoney" width="100">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.goodsPrice / 100 }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="实收金额" align="center" prop="realPayMoney">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.realPayMoney / 100 }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="收款时间" align="center" prop="payTime"/>
|
||||
<el-table-column label="接待员手机号" align="center" prop="workerPhone"/>
|
||||
<el-table-column label="支付方式" align="center" prop="payType">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ getDictLabel(payTypeOptions, scope.row.payType) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="承保公司" align="center" prop="insuranceCompanyName"/>
|
||||
<el-table-column label="下次年检时间" align="center" prop="nextInspectionDate"/>
|
||||
<el-table-column label="交强险到期日期" align="center" prop="insuranceExpiryDate"/>
|
||||
<el-table-column label="商业险到期日期" align="center" prop="vehicleInsuranceExpiryDate"/>
|
||||
<el-table-column label="开始时间" align="center" prop="startTime"/>
|
||||
<el-table-column label="结束时间" align="center" prop="endTime"/>
|
||||
|
||||
<!-- <slot name="table-actions" slot-scope="scope" :row="scope.row"></slot> -->
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listWorkOrder, workOrderData, getCustomerSource } from '@/views/partner/api/workOrder.js'
|
||||
import Pagination from '@/components/Pagination/index.vue'
|
||||
|
||||
export default {
|
||||
name: 'WorkOrderList',
|
||||
components: {
|
||||
Pagination
|
||||
},
|
||||
props: {
|
||||
showSearch: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showSummary: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showStatisticsBtn: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
payTypeOptions: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
// 外部传入的查询参数
|
||||
externalQueryParams: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 选中数组
|
||||
ids: [],
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 表格数据
|
||||
infoList: [{
|
||||
"createTime": 1760160863000,
|
||||
"updateTime": 1760160863000,
|
||||
"creator": "4561",
|
||||
"updater": "4561",
|
||||
"deleted": false,
|
||||
"tenantId": 180,
|
||||
"id": 8517,
|
||||
"inspectionOrderId": 9557,
|
||||
"userId": 10247,
|
||||
"buyName": "刘剑峰",
|
||||
"buyPhone": "15884197348",
|
||||
"userAddress": "四川省泸州市龙马潭区安宁镇柏杨村二十社4号",
|
||||
"unitName": "",
|
||||
"customerSourceId": 190,
|
||||
"businessChannelId": 188,
|
||||
"partnerId": null,
|
||||
"workId": 4561,
|
||||
"workerName": "何梅芳",
|
||||
"workerPhone": "19161426141",
|
||||
"workerAvatar": null,
|
||||
"categoryId": 10,
|
||||
"carNum": "川EAQ001",
|
||||
"certificateNum": "",
|
||||
"carModel": "江淮牌HFC1037DKLSR",
|
||||
"carNature": "非营运",
|
||||
"carStatus": "",
|
||||
"carIdNo": "LJ11PABDXPC021805",
|
||||
"carRegisterDate": 1691942400000,
|
||||
"isPass": null,
|
||||
"isRetrial": null,
|
||||
"remark": null,
|
||||
"recheckCount": 0,
|
||||
"reinspectCount": 0,
|
||||
"businessChannel": "合作商家",
|
||||
"otherName": "何梅芳",
|
||||
"status": "0",
|
||||
"startTime": "2025-10-11 13:34",
|
||||
"endTime": null,
|
||||
"makeCert": null,
|
||||
"year": "2025",
|
||||
"month": "2025-10",
|
||||
"day": "2025-10-11",
|
||||
"customerSource": "三益汽贸",
|
||||
"leadManId": null,
|
||||
"meetManId": 4561,
|
||||
"isMeetCar": "1",
|
||||
"lastTitle": null,
|
||||
"goodsName": null,
|
||||
"realPayMoney": null,
|
||||
"reduceMoney": 0,
|
||||
"orderNo": null,
|
||||
"goodsId": 912,
|
||||
"goodsPrice": 45000,
|
||||
"goodsTitle": "3.5T以下轻型货车(含皮卡)",
|
||||
"partnerName": null,
|
||||
"skuName": "年审",
|
||||
"skuId": "71",
|
||||
"payType": null,
|
||||
"orderStatus": "0",
|
||||
"nextMaintenanceDate": null,
|
||||
"nextInspectionDate": null,
|
||||
"roleId": null,
|
||||
"payTime": null,
|
||||
"otherPhone": "19161426141",
|
||||
"driverLicenesImg": null,
|
||||
"isPayOnline": null,
|
||||
"isPickCar": "0",
|
||||
"nowOrderNum": 1,
|
||||
"returnCarUserId": null,
|
||||
"isReturnCar": 0,
|
||||
"returnType": null,
|
||||
"inspectionWorkNodes": null,
|
||||
"workNodeId": null,
|
||||
"dealUserId": null,
|
||||
"workNodeStatus": null,
|
||||
"selectType": null,
|
||||
"projectName": null,
|
||||
"leadManName": null,
|
||||
"additionalRecording": null,
|
||||
"orderId": null,
|
||||
"appointmentId": null,
|
||||
"sourceType": null,
|
||||
"meetCarId": null,
|
||||
"meetAddress": null,
|
||||
"latitude": null,
|
||||
"longitude": null,
|
||||
"appointmentDay": null,
|
||||
"appointmentTime": null,
|
||||
"meetType": null,
|
||||
"content": null,
|
||||
"inspectionInfoId": null,
|
||||
"isMeetPickCar": null,
|
||||
"pickCarAddress": null,
|
||||
"cashierConfirm": null,
|
||||
"cashierConfirmRemark": null,
|
||||
"cashierConfirmTime": null,
|
||||
"accountingConfirm": null,
|
||||
"accountingConfirmRemark": null,
|
||||
"insuranceExpiryDate": null,
|
||||
"vehicleInsuranceExpiryDate": null,
|
||||
"insuranceCompanyName": null,
|
||||
"datetimeRange": null,
|
||||
"settlementAmount": null,
|
||||
"settlementUser": null,
|
||||
"settlementDiscount": null,
|
||||
"receivablesAccount": null
|
||||
}],
|
||||
// 客户来源数据
|
||||
customerData: [],
|
||||
// 业务渠道数据
|
||||
businessList: [],
|
||||
// 检测类型选项
|
||||
skuNames: [
|
||||
{ label: "年审", value: "年审" },
|
||||
{ label: "上户", value: "上户" },
|
||||
{ label: "非定检", value: "非定检" },
|
||||
{ label: "双燃料", value: "双燃料" },
|
||||
{ label: "其他检测", value: "其他检测" }
|
||||
],
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
dateType: 'jcTime',
|
||||
...this.externalQueryParams
|
||||
},
|
||||
// 金额汇总数据
|
||||
moneyData: {
|
||||
payMoneySum: 0,
|
||||
goodsPriceSum: 0
|
||||
},
|
||||
// 统计弹窗相关
|
||||
statisticsDialogVisible: false,
|
||||
statisticsId: 1, // 默认统计类型
|
||||
statisticsRange: [], // 时间范围
|
||||
statisticsExtraParams: {}, // 额外参数
|
||||
statisticsDialogComponent: null // 动态加载的组件
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
this.customerSource()
|
||||
this.business()
|
||||
},
|
||||
watch: {
|
||||
externalQueryParams: {
|
||||
handler(newVal) {
|
||||
this.queryParams = {
|
||||
...this.queryParams,
|
||||
...newVal
|
||||
}
|
||||
this.getList()
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 查询列表 */
|
||||
getList() {
|
||||
this.loading = true
|
||||
listWorkOrder(this.queryParams).then(response => {
|
||||
console.log('API Response:', response);
|
||||
|
||||
// 确保正确处理响应数据
|
||||
if (response && response.data) {
|
||||
this.infoList = response.data.records || response.data.list || response.data || []
|
||||
this.total = response.data.total || 0
|
||||
} else {
|
||||
this.infoList = []
|
||||
this.total = 0
|
||||
}
|
||||
|
||||
this.loading = false
|
||||
console.log('Processed infoList:', this.infoList);
|
||||
}).catch(error => {
|
||||
console.error('Error fetching work orders:', error)
|
||||
this.infoList = []
|
||||
this.total = 0
|
||||
this.loading = false
|
||||
})
|
||||
|
||||
workOrderData(this.queryParams).then(response => {
|
||||
this.moneyData = response.data
|
||||
}).catch(error => {
|
||||
console.error('Error fetching work order data:', error)
|
||||
})
|
||||
},
|
||||
|
||||
/** 获取客户来源 */
|
||||
customerSource() {
|
||||
const data = { type: 1 }
|
||||
getCustomerSource(data).then(res => {
|
||||
this.customerData = res.data
|
||||
})
|
||||
},
|
||||
|
||||
/** 获取业务渠道 */
|
||||
business() {
|
||||
const data = { type: 0 }
|
||||
getCustomerSource(data).then(res => {
|
||||
this.businessList = res.data
|
||||
})
|
||||
},
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1
|
||||
this.getList()
|
||||
this.$emit('query-change', this.queryParams)
|
||||
},
|
||||
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.queryParams = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
dateType: 'jcTime'
|
||||
}
|
||||
this.handleQuery()
|
||||
},
|
||||
|
||||
/** 多选框选中数据 */
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.id)
|
||||
this.$emit('selection-change', selection)
|
||||
},
|
||||
|
||||
/** 获取字典标签 */
|
||||
getDictLabel(dictOptions, value) {
|
||||
const dict = dictOptions.find(item => item.value === value)
|
||||
return dict ? dict.label : ''
|
||||
},
|
||||
|
||||
/** 刷新列表 */
|
||||
refresh() {
|
||||
this.getList()
|
||||
},
|
||||
|
||||
/** 打开统计弹窗 */
|
||||
openStatisticsDialog() {
|
||||
// 设置时间范围
|
||||
if (this.queryParams.datetimeRange && this.queryParams.datetimeRange.length === 2) {
|
||||
this.statisticsRange = [...this.queryParams.datetimeRange];
|
||||
} else {
|
||||
// 如果没有选择时间范围,默认最近30天
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 30 * 24 * 60 * 60 * 1000);
|
||||
this.statisticsRange = [this.formatDate(start), this.formatDate(end)];
|
||||
}
|
||||
|
||||
// 设置额外参数
|
||||
this.statisticsExtraParams = {
|
||||
businessChannel: this.queryParams.businessChannel,
|
||||
customerSource: this.queryParams.customerSource,
|
||||
skuName: this.queryParams.skuName,
|
||||
payType: this.queryParams.payType
|
||||
};
|
||||
|
||||
// 设置统计类型,这里默认设置为1(客户来源统计)
|
||||
this.statisticsId = 1;
|
||||
|
||||
// 动态加载组件
|
||||
this.loadStatisticsDialogComponent();
|
||||
|
||||
// 显示弹窗
|
||||
this.statisticsDialogVisible = true;
|
||||
},
|
||||
|
||||
/** 格式化日期 */
|
||||
formatDate(date) {
|
||||
const year = date.getFullYear();
|
||||
const month = ('0' + (date.getMonth() + 1)).slice(-2);
|
||||
const day = ('0' + date.getDate()).slice(-2);
|
||||
return year + '-' + month + '-' + day;
|
||||
},
|
||||
|
||||
/** 动态加载统计弹窗组件 */
|
||||
async loadStatisticsDialogComponent() {
|
||||
if (!this.statisticsDialogComponent) {
|
||||
const { default: StatisticsDialog } = await import('@/views/inspection/businessStatistics/StatisticsDialog.vue');
|
||||
this.statisticsDialogComponent = StatisticsDialog;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.summary-info {
|
||||
margin-bottom: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
190
src/views/repair/Components/AddCarForm.vue
Normal file
190
src/views/repair/Components/AddCarForm.vue
Normal file
@ -0,0 +1,190 @@
|
||||
<template>
|
||||
<el-dialog title="添加车辆信息" :visible.sync="dialogVisible" width="800px" @close="handleClose">
|
||||
<el-form ref="carForm" :model="car" :rules="rules" label-width="120px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="车牌号" prop="licenseNumber">
|
||||
<el-input v-model="car.licenseNumber" placeholder="请输入车牌号" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="发动机号码" prop="engineNumber">
|
||||
<el-input v-model="car.engineNumber" placeholder="请输入发动机号码" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="车架号" prop="vin">
|
||||
<el-input v-model="car.vin" placeholder="请输入车架号" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="车辆品牌" prop="carBrand">
|
||||
<CarBrandSelector v-model="car.carBrand" ref="brandSelector" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="车辆型号" prop="carModel">
|
||||
<el-input v-model="car.carModel" placeholder="请输入车辆型号" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="车辆类别" prop="carCategory">
|
||||
<el-select v-model="car.carCategory" placeholder="请选择车辆类别">
|
||||
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.DICT_CAR_CATEGORY)" :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="8">
|
||||
<el-form-item label="车辆性质" prop="carNature">
|
||||
<el-select v-model="car.carNature" placeholder="请选择车辆性质">
|
||||
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.DICT_CAR_NATURE)" :key="dict.value"
|
||||
:label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="注册日期" prop="carRegisterDate">
|
||||
<el-date-picker clearable v-model="car.carRegisterDate" type="date" value-format="timestamp"
|
||||
placeholder="选择车辆注册日期" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="车辆颜色" prop="carColor">
|
||||
<el-input v-model="car.carColor" placeholder="请输入车辆颜色" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="下次年检日期" prop="nextInspectionDate">
|
||||
<el-date-picker clearable v-model="car.nextInspectionDate" type="date" value-format="timestamp"
|
||||
placeholder="选择下次年检日期" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="保险到期日期" prop="insuranceExpiryDate">
|
||||
<el-date-picker clearable v-model="car.insuranceExpiryDate" type="date" value-format="timestamp"
|
||||
placeholder="选择保险到期日期" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="handleClose">取消</el-button>
|
||||
<el-button type="primary" @click="submitForm">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '@/utils/request';
|
||||
import { Message } from 'element-ui';
|
||||
import CarBrandSelector from '@/layout/components/CarBrandSelector/index.vue';
|
||||
import { DICT_TYPE, getDictDatas } from '@/utils/dict';
|
||||
import { getCarBrand } from '@/api/base/carbrand';
|
||||
|
||||
export default {
|
||||
name: "AddCarForm",
|
||||
components: {
|
||||
CarBrandSelector
|
||||
},
|
||||
props: {
|
||||
customerInfo: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialogVisible: false,
|
||||
car: {
|
||||
licenseNumber: '',
|
||||
engineNumber: '',
|
||||
vin: '',
|
||||
brandAndModel: [],
|
||||
carModel: '',
|
||||
carCategory: '',
|
||||
carNature: '',
|
||||
carRegisterDate: '',
|
||||
carColor: '',
|
||||
nextInspectionDate: '',
|
||||
insuranceExpiryDate: ''
|
||||
},
|
||||
rules: {
|
||||
licenseNumber: [
|
||||
{ required: true, message: '请输入车牌号', trigger: 'blur' }
|
||||
],
|
||||
carBrand: [
|
||||
{ required: true, message: '请选择车辆品牌', trigger: 'change' }
|
||||
],
|
||||
carModel: [
|
||||
{ required: false, message: '请输入车辆型号', trigger: 'blur' }
|
||||
],
|
||||
carCategory: [
|
||||
{ required: true, message: '车辆类别不能为空', trigger: 'blur' }
|
||||
],
|
||||
carNature: [
|
||||
{ required: true, message: '车辆性质不能为空', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
open() {
|
||||
this.dialogVisible = true;
|
||||
},
|
||||
handleClose() {
|
||||
this.$refs.carForm.resetFields();
|
||||
this.dialogVisible = false;
|
||||
},
|
||||
async submitForm() {
|
||||
try {
|
||||
// 使用Promise包装validate方法确保正确处理
|
||||
await new Promise((resolve, reject) => {
|
||||
this.$refs.carForm.validate((valid) => {
|
||||
if (valid) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(new Error('表单验证失败'));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.customerInfo.car=this.car;
|
||||
|
||||
|
||||
const createResult = await request({
|
||||
url: '/base/custom/saveCustomerAndCar',
|
||||
method: 'post',
|
||||
data: this.customerInfo
|
||||
});
|
||||
|
||||
// 弹窗绑定成功
|
||||
Message.success('添加车辆成功');
|
||||
this.$emit('success', {
|
||||
id: createResult.carId,
|
||||
...this.car,
|
||||
frameNumber: this.car.vin // 保持与原接口一致
|
||||
});
|
||||
this.handleClose();
|
||||
} catch (error) {
|
||||
// 不显示表单验证失败的错误提示,因为Element UI已经处理
|
||||
if (error.message !== '表单验证失败') {
|
||||
console.error('添加车辆失败:', error);
|
||||
Message.error('添加车辆失败,请重试!');
|
||||
}
|
||||
}
|
||||
},
|
||||
getDictDatas(type) {
|
||||
return getDictDatas(type);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@ -1,17 +1,27 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-select v-model="carSelected" clearable>
|
||||
<el-option v-for="car in carList" :key="car.id" :label="car.licenseNumber" :value="car.id"/>
|
||||
</el-select>
|
||||
<div style="display: flex; align-items: center;">
|
||||
<el-select v-model="carSelected" clearable style="width: 200px;">
|
||||
<el-option v-for="car in carList" :key="car.id" :label="car.licenseNumber" :value="car.id"/>
|
||||
</el-select>
|
||||
<el-button type="primary" size="small" @click="addNewCar" style="margin-left: 8px;">
|
||||
新增车辆
|
||||
</el-button>
|
||||
</div>
|
||||
<AddCarForm ref="addCarForm" :customer-info="customerInfo" @success="handleCarAddSuccess" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import {remindCarMainPage} from "@/api/base/carmain";
|
||||
import AddCarForm from "./AddCarForm.vue";
|
||||
|
||||
export default {
|
||||
name: "CarChoose",
|
||||
components: {
|
||||
AddCarForm
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Object
|
||||
@ -19,6 +29,10 @@ export default {
|
||||
cusName: {
|
||||
type: String,
|
||||
},
|
||||
customerInfo: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
inList:{
|
||||
type: Object,
|
||||
default: null,
|
||||
@ -79,6 +93,16 @@ export default {
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
},
|
||||
addNewCar() {
|
||||
// 打开新增车辆表单
|
||||
this.$refs.addCarForm.open();
|
||||
},
|
||||
handleCarAddSuccess(carInfo) {
|
||||
// 新增成功后刷新车辆列表
|
||||
this.getCarList();
|
||||
// 自动选中新添加的车辆
|
||||
this.carSelected = carInfo.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,8 +62,10 @@ export default {
|
||||
}
|
||||
},
|
||||
getWorkType(val){
|
||||
if (!val) return ''
|
||||
const data = this.getDictDatas(DICT_TYPE.REPAIR_WORK_TYPE)
|
||||
return data.find(item => item.value === val).label
|
||||
const item = data.find(item => item.value === val)
|
||||
return item ? item.label : ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
287
src/views/repair/statistics/index.vue
Normal file
287
src/views/repair/statistics/index.vue
Normal file
@ -0,0 +1,287 @@
|
||||
<template>
|
||||
<div class="detail-container">
|
||||
<!-- 顶部导航 -->
|
||||
<!-- <el-row class="navbar" type="flex" align="middle">
|
||||
<el-col :span="2">
|
||||
<el-button icon="el-icon-arrow-left" @click="goBack" circle></el-button>
|
||||
</el-col>
|
||||
<el-col :span="20" class="navbar-title">详情页</el-col>
|
||||
</el-row> -->
|
||||
|
||||
<!-- 选项卡 -->
|
||||
<el-tabs v-model="currentTab" @tab-click="switchTab">
|
||||
<el-tab-pane
|
||||
v-for="(item, index) in tapList"
|
||||
:key="index"
|
||||
:label="item.label"
|
||||
:name="index.toString()"
|
||||
></el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<!-- 日期选择 -->
|
||||
<el-date-picker
|
||||
v-model="queryParams.dateRange"
|
||||
type="daterange"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
@change="loadData"
|
||||
format="yyyy-MM-dd"
|
||||
value-format="yyyy-MM-dd"
|
||||
style="margin-bottom: 20px"
|
||||
></el-date-picker>
|
||||
|
||||
<!-- 统计卡片 -->
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6" v-for="(sKey, idx) in statsData" :key="idx">
|
||||
<!-- 外层卡片点击 -->
|
||||
<el-card
|
||||
shadow="hover"
|
||||
class="section-card"
|
||||
@click.native="goList(sKey.selectType)"
|
||||
>
|
||||
<div slot="header" class="section-header">
|
||||
<span class="section-tag">{{ sKey.name }}</span>
|
||||
<span class="section-total">{{ sKey.total }} 台次</span>
|
||||
</div>
|
||||
|
||||
<el-row :gutter="10" class="section-body">
|
||||
<el-col :span="12" v-for="(item, i) in sKey.children" :key="i">
|
||||
<!-- 内层点击绑定到 div 并阻止冒泡 -->
|
||||
<div
|
||||
class="kv"
|
||||
@click.stop="goList(sKey.selectType, item.repairType)"
|
||||
>
|
||||
<div class="kv-number">{{ item.count }}</div>
|
||||
<div class="kv-label">{{ dictData[item.repairType] }}</div>
|
||||
<dict-tag :type="'repair_type'" :value="item.repairType" />
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 财务信息 -->
|
||||
<div class="finance">
|
||||
<el-card shadow="hover" class="fin-card receivable">
|
||||
<div class="fin-top">
|
||||
<span class="fin-title">应收款</span>
|
||||
<el-button
|
||||
type="text"
|
||||
icon="el-icon-view"
|
||||
@click.stop="toggleFinance('receivable')"
|
||||
></el-button>
|
||||
</div>
|
||||
<div class="fin-amount" @click="goListByPayStatus('receivable')">
|
||||
{{
|
||||
financeVisibility.receivable
|
||||
? formatCurrency(otherInfo.receivableAmount || 0)
|
||||
: "*****"
|
||||
}}
|
||||
</div>
|
||||
<div class="fin-bottom" @click="goListByPayStatus('receivable')">
|
||||
<span>{{ otherInfo.receivableCount }} 台次</span>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="hover" class="fin-card collected">
|
||||
<div class="fin-top">
|
||||
<span class="fin-title">已收款</span>
|
||||
<el-button
|
||||
type="text"
|
||||
icon="el-icon-view"
|
||||
@click.stop="toggleFinance('collected')"
|
||||
></el-button>
|
||||
</div>
|
||||
<div class="fin-amount" @click="goListByPayStatus('receivedAmount')">
|
||||
{{
|
||||
financeVisibility.collected
|
||||
? formatCurrency(otherInfo.receivedAmount)
|
||||
: "*****"
|
||||
}}
|
||||
</div>
|
||||
<div class="fin-bottom" @click="goListByPayStatus('receivedAmount')">
|
||||
<span>{{ otherInfo.receivedCount }} 台次</span>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="hover" class="fin-card pending">
|
||||
<div class="fin-top">
|
||||
<span class="fin-title">待收款</span>
|
||||
<el-button
|
||||
type="text"
|
||||
icon="el-icon-view"
|
||||
@click.stop="toggleFinance('pending')"
|
||||
></el-button>
|
||||
</div>
|
||||
<div class="fin-amount" @click="goListByPayStatus('pendingAmount')">
|
||||
{{
|
||||
financeVisibility.pending
|
||||
? formatCurrency(otherInfo.pendingAmount)
|
||||
: "*****"
|
||||
}}
|
||||
</div>
|
||||
<div class="fin-bottom" @click="goListByPayStatus('pendingAmount')">
|
||||
<span>{{ otherInfo.pendingCount }} 台次</span>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from "@/utils/request";
|
||||
import { formatCurrency, getDictByCode, getDateRange } from "@/utils/utils";
|
||||
// import { checkPermi } from "@/utils/permission";
|
||||
|
||||
export default {
|
||||
name: "DetailPagePC",
|
||||
dicts: ["repair_type"],
|
||||
data() {
|
||||
return {
|
||||
currentTab: "0",
|
||||
queryParams: {
|
||||
dateRange: [],
|
||||
},
|
||||
tapList: [
|
||||
{ label: "本日", value: "day" },
|
||||
{ label: "本月", value: "month" },
|
||||
{ label: "全部", value: "all" },
|
||||
],
|
||||
statsData: [],
|
||||
financeVisibility: {
|
||||
receivable: false,
|
||||
collected: false,
|
||||
pending: false,
|
||||
},
|
||||
dictData: {},
|
||||
otherInfo: {},
|
||||
};
|
||||
},
|
||||
async mounted() {
|
||||
this.queryParams.dateRange = getDateRange("day");
|
||||
// this.loadFinanceVisibility();
|
||||
this.loadData();
|
||||
},
|
||||
methods: {
|
||||
// checkPermi,
|
||||
switchTab(tab) {
|
||||
this.currentTab = tab.name;
|
||||
const { value } = this.tapList[tab.name];
|
||||
this.queryParams.dateRange = getDateRange(value);
|
||||
this.loadData();
|
||||
},
|
||||
async getDict() {
|
||||
const list = await getDictByCode("repair_type");
|
||||
this.dictData =
|
||||
list?.reduce((map, item) => {
|
||||
map[item.value] = item.label;
|
||||
return map;
|
||||
}, {}) ?? {};
|
||||
},
|
||||
loadData() {
|
||||
request({
|
||||
url: "/repair/tickets/getBossNumStatistics",
|
||||
method: "get",
|
||||
params: this.queryParams,
|
||||
}).then((res) => {
|
||||
if (res.data) {
|
||||
this.statsData = res.data.stats;
|
||||
this.otherInfo = res.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
goList(selectType, repairType) {
|
||||
console.log(selectType, repairType, 6666);
|
||||
|
||||
// 跳转路由
|
||||
this.$router.push({
|
||||
path: "/repair/tickets/ticket-manager",
|
||||
query: {
|
||||
selectType: selectType,
|
||||
repairType: repairType,
|
||||
},
|
||||
});
|
||||
},
|
||||
goListByPayStatus(payStatus) {
|
||||
// 跳转路由
|
||||
this.$router.push({
|
||||
path: "/repair/tickets/ticket-manager",
|
||||
query: { payStatus: payStatus },
|
||||
});
|
||||
},
|
||||
formatCurrency(amount) {
|
||||
return formatCurrency(amount);
|
||||
},
|
||||
toggleFinance(key) {
|
||||
this.financeVisibility[key] = !this.financeVisibility[key];
|
||||
localStorage.setItem(
|
||||
"financeVisibility",
|
||||
JSON.stringify(this.financeVisibility)
|
||||
);
|
||||
},
|
||||
loadFinanceVisibility() {
|
||||
try {
|
||||
const saved = JSON.parse(localStorage.getItem("financeVisibility"));
|
||||
if (saved) this.financeVisibility = saved;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
},
|
||||
goBack() {
|
||||
this.$router.back();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.detail-container {
|
||||
padding: 20px;
|
||||
}
|
||||
.navbar-title {
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.section-card {
|
||||
cursor: pointer;
|
||||
}
|
||||
.section-tag {
|
||||
font-weight: 600;
|
||||
color: #2a6cff;
|
||||
}
|
||||
.section-total {
|
||||
float: right;
|
||||
}
|
||||
.kv-number {
|
||||
font-weight: 700;
|
||||
font-size: 18px;
|
||||
}
|
||||
.kv-label {
|
||||
color: #7f8fa4;
|
||||
}
|
||||
.finance {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.fin-card {
|
||||
flex: 1;
|
||||
cursor: pointer;
|
||||
padding: 20px;
|
||||
}
|
||||
.fin-title {
|
||||
font-size: 14px;
|
||||
color: #7f8fa4;
|
||||
}
|
||||
.fin-amount {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
margin: 10px 0;
|
||||
}
|
||||
.fin-bottom {
|
||||
font-size: 14px;
|
||||
color: #7f8fa4;
|
||||
}
|
||||
</style>
|
||||
@ -269,16 +269,24 @@ export default {
|
||||
if (!row.id || property !== 'goods') {
|
||||
// 保存cell
|
||||
this.saveCellClick(row, cell)
|
||||
cell.querySelector('.item__txt').style.display = 'none'
|
||||
cell.querySelector('.item__input').style.display = 'inline'
|
||||
cell.querySelector('input').focus()
|
||||
// 添加空值检查,确保DOM元素存在
|
||||
const itemTxt = cell.querySelector('.item__txt')
|
||||
const itemInput = cell.querySelector('.item__input')
|
||||
const inputElement = cell.querySelector('input')
|
||||
|
||||
if (itemTxt) itemTxt.style.display = 'none'
|
||||
if (itemInput) itemInput.style.display = 'inline'
|
||||
if (inputElement) inputElement.focus()
|
||||
}
|
||||
}
|
||||
},
|
||||
/** 取消编辑状态 */
|
||||
cancelEditable(cell) {
|
||||
cell.querySelector('.item__txt').style.display = 'inline'
|
||||
cell.querySelector('.item__input').style.display = 'none'
|
||||
const itemTxt = cell.querySelector('.item__txt')
|
||||
const itemInput = cell.querySelector('.item__input')
|
||||
|
||||
if (itemTxt) itemTxt.style.display = 'inline'
|
||||
if (itemInput) itemInput.style.display = 'none'
|
||||
},
|
||||
/** 保存进入编辑的cell */
|
||||
saveCellClick(row, cell) {
|
||||
|
||||
@ -24,7 +24,8 @@
|
||||
<template slot="label">
|
||||
车辆选择
|
||||
</template>
|
||||
<CarChoose v-model="selectCar" :cus-name="selectUser.cusName" :in-list="carInData"/>
|
||||
<CarChoose v-if="selectUser && selectUser.id" v-model="selectCar" :cus-name="selectUser.cusName" :customer-info="selectUser" :in-list="carInData"/>
|
||||
<span v-else>请先选择客户</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item>
|
||||
<template slot="label">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user