lanan-system-vue/src/views/repair/tickets/Components/TicketsShow.vue
2025-10-11 15:58:55 +08:00

787 lines
30 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container">
<el-dialog
title="单据详情"
:visible.sync="dialogVisible"
width="80%"
v-dialogDrag
append-to-body
>
<div v-loading="loading" element-loading-text="数据加载中..." style="min-height: 200px;">
<el-card class="box-card">
<!-- 卡片头 -->
<div slot="header" class="clearfix">
<i class="el-icon-plus" />
<span>工单信息</span>
</div>
<!-- 卡片内容 -->
<div>
<el-descriptions
class="margin-top"
:column="4"
:size="'medium'"
border
style="margin-bottom: 1rem"
>
<el-descriptions-item>
<template slot="label"> 订单编号 </template>
{{ info.ticketNo }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 维修类别 </template>
<dict-tag
:type="DICT_TYPE.REPAIR_TYPE"
v-model="info.repairType"
/>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 状态 </template>
<dict-tag
:type="DICT_TYPE.REPAIR_TICKETS_WORK_STATUS"
v-model="info.ticketsWorkStatus"
/>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 客户名称 </template>
{{ info.userName }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 车牌号 </template>
{{ info.carNo }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 车系 </template>
{{ info.carBrandName }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 手机号 </template>
{{ info.userMobile }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 经办人姓名 </template>
{{ info.handleName }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 经办人电话 </template>
{{ info.handleMobile }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 创建时间 </template>
{{ parseTime(info.createTime, "{y}-{m}-{d}") }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 表显里程 </template>
{{ info.mileageTraveled }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 三包单位 </template>
{{ info.threePackUnits }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 保险名称 </template>
{{ info.insuranceName }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 管理费 </template>
{{ info.managerMoney }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 救援费 </template>
{{ info.rescueMoney }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 三包费 </template>
{{ info.threePackMoney }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 定损费 </template>
{{ info.confirmFaultMoney }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 预计完工 </template>
{{ parseTime(info.outTime, "{y}-{m}-{d}") }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 合计金额 </template>
{{ info.totalPrice }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 最近保养日期 </template>
{{ parseTime(info.maintenanceDate, "{y}-{m}-{d}") }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 最近保养里程 </template>
{{ info.maintenanceMileage }}
</el-descriptions-item>
<!-- <el-descriptions-item>-->
<!-- <template slot="label">-->
<!-- 参考成本-->
<!-- </template>-->
<!-- {{ info.cost }}-->
<!-- </el-descriptions-item>-->
<!-- <el-descriptions-item>-->
<!-- <template slot="label">-->
<!-- 参考毛利-->
<!-- </template>-->
<!-- {{ info.profit }}-->
<!-- </el-descriptions-item>-->
<!-- <el-descriptions-item>-->
<!-- <template slot="label">-->
<!-- 领料状态-->
<!-- </template>-->
<!-- <dict-tag :type="DICT_TYPE.REPAIR_PART_STATUS" v-model="info.partStatus"/>-->
<!-- </el-descriptions-item>-->
<el-descriptions-item>
<template slot="label"> 服务顾问 </template>
{{ info.adviserName }}
</el-descriptions-item>
<!-- <el-descriptions-item>-->
<!-- <template slot="label">-->
<!-- 所属门店-->
<!-- </template>-->
<!-- {{ info.corpId }}-->
<!-- </el-descriptions-item>-->
<el-descriptions-item>
<template slot="label"> 工单状态 </template>
<dict-tag
:type="DICT_TYPE.REPAIR_TICKETS_STATUS"
v-model="info.ticketsStatus"
/>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 备注 </template>
{{ info.remark }}
</el-descriptions-item>
</el-descriptions>
</div>
</el-card>
<el-card class="box-card" v-if="projects && projects.length > 0">
<!-- 卡片头 -->
<div slot="header" class="clearfix">
<i class="el-icon-plus" />
<span>项目信息</span>
</div>
<!-- 卡片内容 -->
<div>
<TicketItemShow :list="projects" list-type="project" />
</div>
</el-card>
<el-card class="box-card" v-if="wares && wares.length > 0">
<!-- 卡片头 -->
<div slot="header" class="clearfix">
<i class="el-icon-plus" />
<span>材料信息</span>
<el-switch
v-if="userRole === 'service_advisor'"
style="float: right; padding: 3px 0"
v-model="info.partShow"
active-text="客户可见"
inactive-text="客户不可见"
active-value="1"
inactive-value="0"
@change="changeShow"
>
</el-switch>
</div>
<!-- 卡片内容 -->
<div>
<TicketItemShow :list="wares" list-type="ware" />
</div>
</el-card>
<el-card class="box-card" v-if="others && others.length > 0">
<!-- 卡片头 -->
<div slot="header" class="clearfix">
<i class="el-icon-plus" />
<span>附加信息</span>
</div>
<!-- 卡片内容 -->
<div>
<TicketItemShow :list="others" list-type="other" />
</div>
</el-card>
<el-card class="box-card">
<div slot="header" class="clearfix">
<i class="el-icon-plus" />
<span>合计</span>
</div>
<div>
<el-descriptions
class="margin-top"
:column="3"
:size="'medium'"
border
style="margin-bottom: 1rem"
>
<el-descriptions-item>
<template slot="label"> 总数量 </template>
{{ totalCount }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 成本 </template>
{{ otherInfo.cost }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 总金额 </template>
{{ totalMoney }}
</el-descriptions-item>
</el-descriptions>
</div>
<div v-hasPermi="['repair:tick:profit']">
<el-descriptions
class="margin-top"
:column="2"
:size="'medium'"
border
style="margin-bottom: 1rem"
>
<el-descriptions-item>
<template slot="label"> 含工时项目毛利率 </template>
{{ otherInfo.profitRate * 100 }}%
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 不含工时项目的毛利率 </template>
{{ otherInfo.profitRateNo * 100 }}%
</el-descriptions-item>
</el-descriptions>
</div>
</el-card>
<el-card class="box-card" v-hasPermi="['repair:tick:profit']">
<!-- 卡片头 -->
<div slot="header" class="clearfix">
<i class="el-icon-plus" />
<span>工种</span>
</div>
<!-- 卡片内容 -->
<div>
<TicketsJobType :list="otherInfo.groupByJobType" list-type="other" />
</div>
</el-card>
</div>
<div slot="footer" class="dialog-footer">
<div class="button-container">
<PrintButton
ref="printButton"
print-title="工单详情"
@click="handlePrint"
>
<template #printContent>
<div class="print-content">
<h1 style="text-align: center">工单详情</h1>
<h2>工单信息</h2>
<table
class="print-table"
border="1"
cellspacing="0"
cellpadding="8"
style="
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
"
>
<tbody>
<tr>
<td><strong>订单编号</strong></td>
<td>{{ info.ticketNo }}</td>
<td><strong>维修类别</strong></td>
<td>
{{ getDictDataLabel(DICT_TYPE.REPAIR_TYPE, info.repairType) }}
</td>
</tr>
<tr>
<td><strong>状态</strong></td>
<td>
{{
getDictDataLabel(
DICT_TYPE.REPAIR_TICKETS_WORK_STATUS,
info.ticketsWorkStatus
)
}}
</td>
<td><strong>客户名称</strong></td>
<td>{{ info.userName }}</td>
</tr>
<tr>
<td><strong>车牌号</strong></td>
<td>{{ info.carNo }}</td>
<td><strong>车系</strong></td>
<td>{{ info.carBrandName }}</td>
</tr>
<tr>
<td><strong>手机号</strong></td>
<td>{{ info.userMobile }}</td>
<td><strong>经办人姓名</strong></td>
<td>{{ info.handleName }}</td>
</tr>
<tr>
<td><strong>经办人电话</strong></td>
<td>{{ info.handleMobile }}</td>
<td><strong>创建时间</strong></td>
<td>{{ parseTime(info.createTime, "{y}-{m}-{d}") }}</td>
</tr>
<tr>
<td><strong>表显里程</strong></td>
<td>{{ info.mileageTraveled }}</td>
<td><strong>三包单位</strong></td>
<td>{{ info.threePackUnits }}</td>
</tr>
<tr>
<td><strong>保险名称</strong></td>
<td>{{ info.insuranceName }}</td>
<td><strong>管理费</strong></td>
<td>{{ info.managerMoney }}</td>
</tr>
<tr>
<td><strong>救援费</strong></td>
<td>{{ info.rescueMoney }}</td>
<td><strong>三包费</strong></td>
<td>{{ info.threePackMoney }}</td>
</tr>
<tr>
<td><strong>定损费</strong></td>
<td>{{ info.confirmFaultMoney }}</td>
<td><strong>预计完工</strong></td>
<td>{{ parseTime(info.outTime, "{y}-{m}-{d}") }}</td>
</tr>
<tr>
<td><strong>合计金额</strong></td>
<td>{{ info.totalPrice }}</td>
<td><strong>最近保养日期</strong></td>
<td>
{{ parseTime(info.maintenanceDate, "{y}-{m}-{d}") }}
</td>
</tr>
<tr>
<td><strong>最近保养里程</strong></td>
<td>{{ info.maintenanceMileage }}</td>
<td><strong>服务顾问</strong></td>
<td>{{ info.adviserName }}</td>
</tr>
<tr>
<td><strong>工单状态</strong></td>
<td>
{{
getDictDataLabel(
DICT_TYPE.REPAIR_TICKETS_STATUS,
info.ticketsStatus
)
}}
</td>
<td><strong>备注</strong></td>
<td>{{ info.remark }}</td>
</tr>
</tbody>
</table>
<div v-if="projects && projects.length > 0">
<h2>项目信息</h2>
<table
class="print-table"
border="1"
cellspacing="0"
cellpadding="8"
style="
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
"
>
<thead>
<tr>
<th>序号</th>
<th>名称</th>
<th>规格</th>
<th>编码</th>
<th>单位</th>
<th>数量</th>
<th>单价</th>
<th>折扣</th>
<th v-if="checkPermi(['repair:tick:profit'])">毛利</th>
<th v-if="checkPermi(['repair:tick:profit'])">毛利率</th>
<th>金额</th>
<th>施工人员</th>
<th>服务顾问</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in projects" :key="item.id">
<td>{{ index + 1 }}</td>
<td>{{ item.project?.name }}</td>
<td>{{ item.project?.model }}</td>
<td>{{ item.project?.code }}</td>
<td>
{{
getDictDataLabel(
DICT_TYPE.REPAIR_UNIT,
item.project?.unit
)
}}
</td>
<td>{{ item.itemCount }}</td>
<td>{{ item.itemPrice }}</td>
<td>{{ item.itemDiscount }}</td>
<td v-if="checkPermi(['repair:tick:profit'])">
{{ item.itemProfit }}
</td>
<td v-if="checkPermi(['repair:tick:profit'])">
{{
item.itemProfitRate
? (item.itemProfitRate * 100).toFixed(2) + "%"
: ""
}}
</td>
<td>{{ item.itemMoney }}</td>
<td>{{ item.repairNames }}</td>
<td>{{ item.saleName }}</td>
<td>{{ item.remark }}</td>
</tr>
</tbody>
</table>
</div>
<div v-if="wares && wares.length > 0">
<h2>材料信息</h2>
<table
class="print-table"
border="1"
cellspacing="0"
cellpadding="8"
style="
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
"
>
<thead>
<tr>
<th>序号</th>
<th>名称</th>
<th>规格</th>
<th>编码</th>
<th>单位</th>
<th>数量</th>
<th>单价</th>
<th>折扣</th>
<th v-if="checkPermi(['repair:tick:profit'])">毛利</th>
<th v-if="checkPermi(['repair:tick:profit'])">毛利率</th>
<th>金额</th>
<th>施工人员</th>
<th>服务顾问</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in wares" :key="item.id">
<td>{{ index + 1 }}</td>
<td>{{ item.ware?.name }}</td>
<td>{{ item.ware?.model }}</td>
<td>{{ item.ware?.code }}</td>
<td>
{{
getDictDataLabel(DICT_TYPE.REPAIR_UNIT, item.ware?.unit)
}}
</td>
<td>{{ item.itemCount }}</td>
<td>{{ item.itemPrice }}</td>
<td>{{ item.itemDiscount }}</td>
<td v-if="checkPermi(['repair:tick:profit'])">
{{ item.itemProfit }}
</td>
<td v-if="checkPermi(['repair:tick:profit'])">
{{
item.itemProfitRate
? (item.itemProfitRate * 100).toFixed(2) + "%"
: ""
}}
</td>
<td>{{ item.itemMoney }}</td>
<td>{{ item.repairNames }}</td>
<td>{{ item.saleName }}</td>
<td>{{ item.remark }}</td>
</tr>
</tbody>
</table>
</div>
<div v-if="others && others.length > 0">
<h2>附加信息</h2>
<table
class="print-table"
border="1"
cellspacing="0"
cellpadding="8"
style="
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
"
>
<thead>
<tr>
<th>序号</th>
<th>名称</th>
<th>规格</th>
<th>编码</th>
<th>单位</th>
<th>数量</th>
<th>单价</th>
<th>折扣</th>
<th v-if="checkPermi(['repair:tick:profit'])">毛利</th>
<th v-if="checkPermi(['repair:tick:profit'])">毛利率</th>
<th>金额</th>
<th>施工人员</th>
<th>服务顾问</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in others" :key="item.id">
<td>{{ index + 1 }}</td>
<td>{{ item.other?.name }}</td>
<td>{{ item.other?.model }}</td>
<td>{{ item.other?.code }}</td>
<td>
{{
getDictDataLabel(DICT_TYPE.REPAIR_UNIT, item.other?.unit)
}}
</td>
<td>{{ item.itemCount }}</td>
<td>{{ item.itemPrice }}</td>
<td>{{ item.itemDiscount }}</td>
<td v-if="checkPermi(['repair:tick:profit'])">
{{ item.itemProfit }}
</td>
<td v-if="checkPermi(['repair:tick:profit'])">
{{
item.itemProfitRate
? (item.itemProfitRate * 100).toFixed(2) + "%"
: ""
}}
</td>
<td>{{ item.itemMoney }}</td>
<td>{{ item.repairNames }}</td>
<td>{{ item.saleName }}</td>
<td>{{ item.remark }}</td>
</tr>
</tbody>
</table>
</div>
<h2>合计</h2>
<table
class="print-table"
border="1"
cellspacing="0"
cellpadding="8"
style="
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
"
>
<tbody>
<tr>
<td><strong>总数量</strong></td>
<td>{{ totalCount }}</td>
<td><strong>成本</strong></td>
<td>{{ otherInfo.cost }}</td>
<td><strong>总金额</strong></td>
<td>{{ totalMoney }}</td>
</tr>
</tbody>
</table>
<div v-if="checkPermi(['repair:tick:profit'])">
<table
class="print-table"
border="1"
cellspacing="0"
cellpadding="8"
style="
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
"
>
<tbody>
<tr>
<td><strong>含工时项目毛利率</strong></td>
<td>{{ otherInfo.profitRate * 100 }}%</td>
<td><strong>不含工时项目的毛利率</strong></td>
<td>{{ otherInfo.profitRateNo * 100 }}%</td>
</tr>
</tbody>
</table>
<h2>工种</h2>
<table
class="print-table"
border="1"
cellspacing="0"
cellpadding="8"
style="
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
"
v-if="
otherInfo.groupByJobType &&
otherInfo.groupByJobType.length > 0
"
>
<thead>
<tr>
<th>工种</th>
<th>成本</th>
<th>售价</th>
<th>毛利</th>
<th>含工时毛利率</th>
<th>不含工时毛利率</th>
</tr>
</thead>
<tbody>
<tr
v-for="(item, index) in otherInfo.groupByJobType"
:key="index"
>
<td>{{ item.jobTypeName }}</td>
<td>{{ item.cost }}</td>
<td>{{ item.money }}</td>
<td>{{ item.profit }}</td>
<td>{{ (item.profitRateWithWork * 100).toFixed(2) }}%</td>
<td>
{{ (item.profitRateWithoutWork * 100).toFixed(2) }}%
</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
</PrintButton>
<el-button @click="dialogVisible = false">关闭</el-button>
</div>
</div>
</el-dialog>
</div>
</template>
<script>
import TicketItemShow from "@/views/repair/tickets/Components/TicketItemShow.vue";
import { getTicketsById, updateShow } from "@/api/repair/tickets/Tickets";
import TicketsJobType from "@/views/repair/tickets/Components/TicketsJobType.vue";
import PrintButton from "@/components/PrintButton";
import { getDictDataLabel } from "@/utils/dict";
import { checkPermi } from "@/utils/permission";
export default {
name: "TicketsShow",
props: {
userRole: String,
},
components: { TicketsJobType, TicketItemShow, PrintButton },
data() {
return {
dialogVisible: false,
info: {},
projects: [],
wares: [],
others: [],
allList: [],
totalCount: 0,
totalMoney: 0,
otherInfo: {},
loading: false // 添加加载状态
};
},
methods: {
checkPermi,
// 添加打开弹窗的方法,支持加载动画
open(row) {
// 返回 Promise 以便调用者可以正确处理异步操作
return new Promise((resolve, reject) => {
this.reset();
this.loading = true; // 开启加载状态
getTicketsById(row.id).then(res => {
this.allList = res.data.items;
this.computed();
this.projects = this.allList.filter((item) => item.project);
this.wares = this.allList.filter((item) => item.ware);
this.others = this.allList.filter((item) => item.other);
this.info = row;
this.otherInfo = res.data;
this.dialogVisible = true;
this.loading = false; // 关闭加载状态
resolve();
}).catch((error) => {
this.loading = false; // 出错时也关闭加载状态
reject(error);
});
});
},
async changeShow() {
try {
await updateShow(this.info.id, this.info.partShow);
} catch {}
},
reset() {
this.info = {};
this.projects = [];
this.wares = [];
this.others = [];
this.allList = [];
},
computed() {
this.totalCount = 0;
this.totalMoney = 0;
if (this.allList && this.allList.length > 0) {
this.totalCount = this.allList.reduce((acc, cur) => {
return acc + cur.itemCount;
}, 0);
this.totalMoney = this.allList.reduce((acc, cur) => {
return acc + cur.itemMoney;
}, 0);
}
},
handlePrint() {
this.$refs.printButton.handlePrint();
},
getDictDataLabel,
},
};
</script>
<style scoped lang="scss">
.box-card {
margin-bottom: 10px;
}
.print-table {
width: 100%;
border-collapse: collapse;
margin-bottom: 15px;
}
.print-table th,
.print-table td {
border: 1px solid #000;
padding: 8px 12px;
text-align: left;
}
.print-table th {
background-color: #f5f5f5;
font-weight: bold;
}
// 添加按钮容器样式使按钮位于右下角
.dialog-footer {
display: flex;
justify-content: flex-end;
align-items: center;
padding: 20px 0;
.button-container {
display: flex;
gap: 10px;
}
}
</style>