|
|
@@ -3,6 +3,16 @@
|
|
|
<!-- 左侧部门树 -->
|
|
|
<DeptTree @node-click="handleDeptNodeClick" v-model:collapsed="isLeftContentCollapsed" />
|
|
|
<el-col :span="isLeftContentCollapsed ? 24 : 20" :xs="24">
|
|
|
+ <div class="ptw-stats mb-15px">
|
|
|
+ <div class="ptw-stats-card">
|
|
|
+ <div class="ptw-stats-card__label">作业票总数</div>
|
|
|
+ <div class="ptw-stats-card__value">{{ totalStaticCount }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="ptw-stats-chart-card">
|
|
|
+ <div class="ptw-stats-card__label">作业票分类统计</div>
|
|
|
+ <Echart :height="220" :options="staticChartOptions" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
<div class="bg-white rounded-sm px-2 py-2">
|
|
|
<!-- 搜索工作栏 -->
|
|
|
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true">
|
|
|
@@ -527,6 +537,7 @@ import DeptTree from '@/views/system/user/DeptTree2.vue'
|
|
|
import { handleTree, defaultProps } from '@/utils/tree'
|
|
|
import * as DeptApi from '@/api/system/dept'
|
|
|
import { ElMessageBox, ElMessage } from 'element-plus'
|
|
|
+import type { EChartsOption } from 'echarts'
|
|
|
const deptList2 = ref<Tree[]>([]) // 树形结构
|
|
|
import { formatDate } from '@/utils/formatTime'
|
|
|
import { useUserStore } from '@/store/modules/user'
|
|
|
@@ -551,9 +562,16 @@ const queryParams = reactive({
|
|
|
pageNo: 1,
|
|
|
pageSize: 10,
|
|
|
ptwXh: '',
|
|
|
- ptwNo: ''
|
|
|
+ ptwNo: '',
|
|
|
+ deptId: ''
|
|
|
})
|
|
|
|
|
|
+type StaticItem = {
|
|
|
+ classify: string
|
|
|
+ count: number
|
|
|
+ sort?: number
|
|
|
+}
|
|
|
+
|
|
|
const queryParams2 = reactive({
|
|
|
pageNo: 1,
|
|
|
pageSize: 10,
|
|
|
@@ -673,6 +691,7 @@ const handleExport = async () => {
|
|
|
/** 首页处理部门被点击 */
|
|
|
const handleDeptNodeClick = async (row) => {
|
|
|
queryParams.deptId = row.id
|
|
|
+ await getStatic()
|
|
|
await getList()
|
|
|
}
|
|
|
|
|
|
@@ -686,6 +705,7 @@ const handleQuery = () => {
|
|
|
const resetQuery = () => {
|
|
|
queryParams.deptId = ''
|
|
|
queryFormRef.value?.resetFields()
|
|
|
+ getStatic()
|
|
|
handleQuery()
|
|
|
}
|
|
|
|
|
|
@@ -852,13 +872,104 @@ const extractFileName = (url: string): string => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+let staticList = ref<StaticItem[]>([])
|
|
|
+const totalStaticCount = computed(() =>
|
|
|
+ staticList.value.reduce((sum: number, item: StaticItem) => sum + Number(item.count || 0), 0)
|
|
|
+)
|
|
|
+const staticChartOptions = computed<EChartsOption>(() => ({
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'axis',
|
|
|
+ axisPointer: {
|
|
|
+ type: 'shadow'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ grid: {
|
|
|
+ left: 16,
|
|
|
+ right: 16,
|
|
|
+ top: 24,
|
|
|
+ bottom: 24,
|
|
|
+ containLabel: true
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: 'category',
|
|
|
+ data: staticList.value.map((item: StaticItem) => item.classify),
|
|
|
+ axisTick: {
|
|
|
+ show: false
|
|
|
+ },
|
|
|
+ axisLine: {
|
|
|
+ lineStyle: {
|
|
|
+ color: '#d9e2ef'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ axisLabel: {
|
|
|
+ color: '#6b7280',
|
|
|
+ fontSize: 12,
|
|
|
+ interval: 0
|
|
|
+ }
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: 'value',
|
|
|
+ axisLine: {
|
|
|
+ show: false
|
|
|
+ },
|
|
|
+ axisTick: {
|
|
|
+ show: false
|
|
|
+ },
|
|
|
+ axisLabel: {
|
|
|
+ color: '#94a3b8',
|
|
|
+ fontSize: 12
|
|
|
+ },
|
|
|
+ splitLine: {
|
|
|
+ lineStyle: {
|
|
|
+ color: '#edf2f7',
|
|
|
+ type: 'dashed'
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ type: 'bar',
|
|
|
+ barWidth: 32,
|
|
|
+ data: staticList.value.map((item: StaticItem) => item.count),
|
|
|
+ itemStyle: {
|
|
|
+ borderRadius: [8, 8, 0, 0],
|
|
|
+ color: {
|
|
|
+ type: 'linear',
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ x2: 0,
|
|
|
+ y2: 1,
|
|
|
+ colorStops: [
|
|
|
+ { offset: 0, color: '#79b8ff' },
|
|
|
+ { offset: 1, color: '#2f78f6' }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ },
|
|
|
+ label: {
|
|
|
+ show: true,
|
|
|
+ position: 'top',
|
|
|
+ color: '#2563eb',
|
|
|
+ fontSize: 12,
|
|
|
+ fontWeight: 700
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]
|
|
|
+}))
|
|
|
+async function getStatic() {
|
|
|
+ const deptId = queryParams.deptId || userStore.user.deptId
|
|
|
+ const res = await QHSEPtwApi.getPtwCategory(deptId)
|
|
|
+ staticList.value = Array.isArray(res)
|
|
|
+ ? [...res].sort((a: StaticItem, b: StaticItem) => (a.sort || 0) - (b.sort || 0))
|
|
|
+ : []
|
|
|
+}
|
|
|
+
|
|
|
onMounted(async () => {
|
|
|
getList()
|
|
|
deptList2.value = handleTree(await DeptApi.getSimpleDeptList())
|
|
|
|
|
|
const users = await getUserProfile()
|
|
|
userInfo.value = users
|
|
|
- console.log('xxxxxxxxxxxxxxxxxx', userInfo.value)
|
|
|
+ getStatic()
|
|
|
})
|
|
|
|
|
|
let personDialogVisible = ref(false)
|
|
|
@@ -1027,6 +1138,54 @@ const handleRadioChange2 = (row: any) => {
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
+.ptw-stats {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: 240px minmax(0, 1fr);
|
|
|
+ gap: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.ptw-stats-card,
|
|
|
+.ptw-stats-chart-card {
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.ptw-stats-card {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: center;
|
|
|
+ min-height: 220px;
|
|
|
+ background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);
|
|
|
+}
|
|
|
+
|
|
|
+.ptw-stats-card__label {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #64748b;
|
|
|
+ margin-bottom: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.ptw-stats-card__value {
|
|
|
+ font-size: 42px;
|
|
|
+ line-height: 1;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #1d4ed8;
|
|
|
+}
|
|
|
+
|
|
|
+.ptw-stats-chart-card {
|
|
|
+ min-width: 0;
|
|
|
+}
|
|
|
+
|
|
|
+@media (max-width: 768px) {
|
|
|
+ .ptw-stats {
|
|
|
+ grid-template-columns: 1fr;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ptw-stats-card {
|
|
|
+ min-height: 160px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
.file-name-text {
|
|
|
display: block;
|
|
|
white-space: nowrap;
|