lanan-system-vue/src/views/repair/statistics/index.vue

344 lines
9.1 KiB
Vue
Raw Normal View History

2025-10-09 09:54:13 +08:00
<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>
2025-11-13 16:07:47 +08:00
<!-- 工单列表弹窗 -->
<el-dialog
:title="dialogTitle"
:visible.sync="listDialogVisible"
width="80%"
v-if="listDialogVisible"
>
<TicketManagerItem
:is-type="dialogQueryParams.selectType"
:user-role="userRole"
:external-query-params="dialogQueryParams"
:show-view-only="true"
@close="listDialogVisible = false"
/>
</el-dialog>
2025-10-09 09:54:13 +08:00
</div>
</template>
<script>
import request from "@/utils/request";
import { formatCurrency, getDictByCode, getDateRange } from "@/utils/utils";
// import { checkPermi } from "@/utils/permission";
2025-11-13 16:07:47 +08:00
import TicketManagerItem from "@/views/repair/tickets/Components/TicketManagerItem.vue";
2025-10-09 09:54:13 +08:00
export default {
name: "DetailPagePC",
dicts: ["repair_type"],
2025-11-13 16:07:47 +08:00
components: {
TicketManagerItem
},
2025-10-09 09:54:13 +08:00
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: {},
2025-11-13 16:07:47 +08:00
// 弹窗相关
listDialogVisible: false,
dialogTitle: "",
dialogQueryParams: {},
userRole: "all" // 默认角色,实际应用中可能需要动态获取
2025-10-09 09:54:13 +08:00
};
},
async mounted() {
this.queryParams.dateRange = getDateRange("day");
// this.loadFinanceVisibility();
this.loadData();
2025-11-13 16:07:47 +08:00
this.getDict();
2025-10-09 09:54:13 +08:00
},
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);
2025-11-13 16:07:47 +08:00
// 设置弹窗标题
this.dialogTitle = this.dictData[repairType] ?
`${this.dictData[repairType]}工单列表` :
`${this.getSelectTypeName(selectType)}工单列表`;
2025-10-09 09:54:13 +08:00
2025-11-13 16:07:47 +08:00
// 设置查询参数
this.dialogQueryParams = {
selectType: selectType,
repairType: repairType,
searchTimeArray: this.queryParams.dateRange
};
// 显示弹窗
this.listDialogVisible = true;
2025-10-09 09:54:13 +08:00
},
goListByPayStatus(payStatus) {
2025-11-13 16:07:47 +08:00
// 设置弹窗标题
this.dialogTitle = this.getPayStatusName(payStatus) + "工单列表";
// 设置查询参数
this.dialogQueryParams = {
payStatus: payStatus,
searchTimeArray: this.queryParams.dateRange
};
// 显示弹窗
this.listDialogVisible = true;
},
getSelectTypeName(selectType) {
const typeMap = {
'jinchang': '进厂',
'weixiuzhong': '维修中',
'yijungong': '已竣工',
'yijiaoche': '已交车',
'weijiesuan': '未结算',
'zaichang': '在厂'
};
return typeMap[selectType] || '工单';
},
getPayStatusName(payStatus) {
const statusMap = {
'receivable': '应收款',
'receivedAmount': '已收款',
'pendingAmount': '待收款'
};
return statusMap[payStatus] || '工单';
2025-10-09 09:54:13 +08:00
},
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;
}
2025-11-13 16:07:47 +08:00
</style>