Sfoglia il codice sorgente

Merge branch 'equipManage' into dev

huoyi 1 mese fa
parent
commit
534625ef4a

+ 9 - 0
src/api/home-new/home-new.js

@@ -139,3 +139,12 @@ export function getPushMessage(query) {
139 139
     params: query
140 140
   })
141 141
 }
142
+
143
+//查询设备台账列表全量
144
+export function getDeviceList(query) {
145
+  return request({
146
+    url: '/equipment/ledger/notice',
147
+    method: 'get',
148
+    params: query
149
+  })
150
+}

+ 6 - 0
src/pages.json

@@ -321,6 +321,12 @@
321 321
       }
322 322
     },
323 323
     {
324
+      "path": "pages/selfCheck/index",
325
+      "style": {
326
+        "navigationBarTitleText": "定/自检"
327
+      }
328
+    },
329
+    {
324 330
       "path": "pages/seizeStatistics/index",
325 331
       "style": {
326 332
         "navigationBarTitleText": "查获统计"

+ 263 - 0
src/pages/home-new/components/selfCheck.vue

@@ -0,0 +1,263 @@
1
+<template>
2
+    <view class="self-check-container">
3
+        <view class="self-check-header">
4
+            <text class="header-title">定/自检</text>
5
+            <text class="view-all" @click="goToSelfCheckPage('all')">查看全部</text>
6
+        </view>
7
+
8
+        <view class="self-check-content">
9
+            <!-- 已过期定检提醒 -->
10
+            <view class="check-section" v-if="expiredItems.length > 0">
11
+                <view class="section-header">
12
+                    <text class="section-title">已过期定检提醒</text>
13
+                    <text class="view-more" @click="goToSelfCheckPage('expired')">查看更多</text>
14
+                </view>
15
+                <view class="check-item" v-for="(item, index) in expiredItems" :key="index">
16
+                    <view class="item-indicator expired"></view>
17
+                    <view class="item-content">
18
+                        <view class="item-row">
19
+                            <text class="item-label">{{ item.name }}</text>
20
+                            <text class="item-label">{{ item.serialNumber }}</text>
21
+                            <text class="item-date">{{ item.date }}</text>
22
+                        </view>
23
+                        <view class="item-row">
24
+                            <text class="item-label">{{ item.location }}</text>
25
+                            <text class="item-role">{{ item.role }}</text>
26
+                        </view>
27
+                    </view>
28
+                </view>
29
+            </view>
30
+
31
+            <!-- 两周内到期提醒 -->
32
+            <view class="check-section" v-if="twoWeeksItems.length > 0">
33
+                <view class="section-header">
34
+                    <text class="section-title">两周内到期提醒</text>
35
+                    <text class="view-more" @click="goToSelfCheckPage('twoWeeks')">查看更多</text>
36
+                </view>
37
+                <view class="check-item" v-for="(item, index) in twoWeeksItems" :key="index">
38
+                    <view class="item-indicator urgent"></view>
39
+                    <view class="item-content">
40
+                        <view class="item-row">
41
+                            <text class="item-label">{{ item.name }}</text>
42
+                            <text class="item-label">{{ item.serialNumber }}</text>
43
+                            <text class="item-date">{{ item.date }}</text>
44
+                        </view>
45
+                        <view class="item-row">
46
+                            <text class="item-label">{{ item.location }}</text>
47
+                            <text class="item-role">{{ item.role }}</text>
48
+                        </view>
49
+                    </view>
50
+                </view>
51
+            </view>
52
+
53
+            <!-- 一月内检到期提醒 -->
54
+            <view class="check-section" v-if="oneMonthItems.length > 0">
55
+                <view class="section-header">
56
+                    <text class="section-title">一月内检到期提醒</text>
57
+                    <text class="view-more" @click="goToSelfCheckPage('oneMonth')">查看更多</text>
58
+                </view>
59
+                <view class="check-item" v-for="(item, index) in oneMonthItems" :key="index">
60
+                    <view class="item-indicator normal"></view>
61
+                    <view class="item-content">
62
+                        <view class="item-row">
63
+                            <text class="item-label">{{ item.name }}</text>
64
+                            <text class="item-label">{{ item.serialNumber }}</text>
65
+                            <text class="item-date">{{ item.date }}</text>
66
+                        </view>
67
+                        <view class="item-row">
68
+                            <text class="item-label">{{ item.location }}</text>
69
+                            <text class="item-role">{{ item.role }}</text>
70
+                        </view>
71
+                    </view>
72
+                </view>
73
+            </view>
74
+        </view>
75
+    </view>
76
+</template>
77
+
78
+<script>
79
+import { getDeviceList } from "@/api/home-new/home-new";
80
+
81
+export default {
82
+    name: 'SelfCheck',
83
+    data() {
84
+        return {
85
+            // 已过期定检数据
86
+            expiredItems: [],
87
+            // 两周内到期数据
88
+            twoWeeksItems: [],
89
+            // 一月内到期数据
90
+            oneMonthItems: []
91
+        }
92
+    },
93
+    mounted() {
94
+        this.fetchDeviceList();
95
+    },
96
+    methods: {
97
+        goToSelfCheckPage(tab) {
98
+            uni.navigateTo({
99
+                url: `/pages/selfCheck/index?tab=${tab}`
100
+            });
101
+        },
102
+        fetchDeviceList() {
103
+            // 分别请求三种颜色的数据
104
+            Promise.all([
105
+                getDeviceList({ colorType: 'RED' }),      // 已过期 - 红色
106
+                getDeviceList({ colorType: 'ORANGE' }),   // 两周内到期 - 橙色
107
+                getDeviceList({ colorType: 'YELLOW' })     // 一月内到期 - 黄色
108
+            ]).then(results => {
109
+                // 处理红色数据(已过期)
110
+                if (results[0].code === 200) {
111
+                    this.expiredItems = (results[0].data || []).slice(0, 2).map(item => this.formatDeviceItem(item));
112
+                }
113
+                // 处理橙色数据(两周内到期)
114
+                if (results[1].code === 200) {
115
+                    this.twoWeeksItems = (results[1].data || []).slice(0, 2).map(item => this.formatDeviceItem(item));
116
+                }
117
+                // 处理黄色数据(一月内到期)
118
+                if (results[2].code === 200) {
119
+                    this.oneMonthItems = (results[2].data || []).slice(0, 2).map(item => this.formatDeviceItem(item));
120
+                }
121
+            }).catch(err => {
122
+                console.error('获取设备列表失败', err);
123
+            });
124
+        },
125
+        formatDeviceItem(item) {
126
+            return {
127
+                name: item.equipmentName || '空',
128
+                serialNumber: item.equipmentCode || '空',
129
+                location: item.installationLocation || '空',
130
+                role:`${item.inspectionTeamLeaderName || ''}、${item.inspectionTeamMember1Name || ''}、${item.inspectionTeamMember2Name || ''}`|| '空',
131
+                date: this.formatDate(item.nextInspectionDueDate)|| '空'
132
+            };
133
+        },
134
+        formatDate(dateStr) {
135
+            if (!dateStr) return '';
136
+            const date = new Date(dateStr);
137
+            const year = date.getFullYear();
138
+            const month = String(date.getMonth() + 1).padStart(2, '0');
139
+            const day = String(date.getDate()).padStart(2, '0');
140
+            return `${year}-${month}-${day}`;
141
+        }
142
+    }
143
+}
144
+</script>
145
+
146
+<style scoped>
147
+.self-check-container {
148
+    width: 100%;
149
+    padding: 12px;
150
+    background-color: #f5f7fa;
151
+}
152
+
153
+.self-check-header {
154
+    display: flex;
155
+    justify-content: space-between;
156
+    align-items: center;
157
+    margin-bottom: 12px;
158
+}
159
+
160
+.header-title {
161
+    font-size: 20px;
162
+    font-weight: bold;
163
+    color: #333;
164
+}
165
+
166
+.view-all {
167
+    font-size: 14px;
168
+    color: #409eff;
169
+}
170
+
171
+.self-check-content {
172
+    background-color: #fff;
173
+    border-radius: 12px;
174
+    padding: 12px;
175
+}
176
+
177
+.check-section {
178
+    margin-bottom: 16px;
179
+}
180
+
181
+.check-section:last-child {
182
+    margin-bottom: 0;
183
+}
184
+
185
+.section-header {
186
+    display: flex;
187
+    justify-content: space-between;
188
+    align-items: center;
189
+    margin-bottom: 10px;
190
+}
191
+
192
+.section-title {
193
+    font-size: 16px;
194
+    font-weight: bold;
195
+    color: #333;
196
+}
197
+
198
+.view-more {
199
+    font-size: 14px;
200
+    color: #409eff;
201
+}
202
+
203
+.check-item {
204
+    display: flex;
205
+    align-items: flex-start;
206
+    padding: 10px 0;
207
+    border-bottom: 1px solid #f0f0f0;
208
+}
209
+
210
+.check-item:last-child {
211
+    border-bottom: none;
212
+}
213
+
214
+.item-indicator {
215
+    width: 6px;
216
+    border-radius: 3px;
217
+    margin-right: 10px;
218
+    flex-shrink: 0;
219
+}
220
+
221
+.item-indicator.expired {
222
+    background-color: #FF0000;
223
+    height: 48px;
224
+}
225
+
226
+.item-indicator.urgent {
227
+    background-color: #FFA500;
228
+    height: 48px;
229
+}
230
+
231
+.item-indicator.normal {
232
+    background-color: #FFD700;
233
+    height: 48px;
234
+}
235
+
236
+.item-content {
237
+    flex: 1;
238
+    display: flex;
239
+    flex-direction: column;
240
+    gap: 6px;
241
+}
242
+
243
+.item-row {
244
+    display: flex;
245
+    justify-content: space-between;
246
+    align-items: center;
247
+}
248
+
249
+.item-label {
250
+    font-size: 14px;
251
+    color: #333;
252
+}
253
+
254
+.item-date {
255
+    font-size: 14px;
256
+    color: #333;
257
+}
258
+
259
+.item-role {
260
+    font-size: 14px;
261
+    color: #333;
262
+}
263
+</style>

+ 37 - 28
src/pages/home-new/index.vue

@@ -35,41 +35,47 @@
35 35
             <Notice ref="notice" />
36 36
             <MessagePush ref="messagePush" />
37 37
 
38
-            <!-- 时间范围选择 -->
39
-            <div class="time-range-section">
40
-                <div class="time-tags-container">
41
-                    <div v-for="tag in timeTags" :key="tag.value"
42
-                        :class="['time-tag', { 'active': selectedTimeRange === tag.value, 'time-range-label': tag.isLabel }]"
43
-                        @click="tag.isLabel ? null : handleTimeTagClick(tag)">
44
-                        {{ tag.label }}
45
-                    </div>
46
-
47
-                    <!-- 自定义时间显示 - 紧跟自定义时间标签 -->
48
-                    <div v-if="selectedTimeRange === 'custom'" class="custom-time-inline">
49
-                        <uni-datetime-picker v-model="dateRange" type="daterange" rangeSeparator="至"
50
-                            @change="handleDateRangeChange" class="date-range-picker" :clear-icon="false" />
51
-                        <div class="days-count">共 {{ totalDays }} 天</div>
38
+            <!-- 当 currentDepartment === '设备维修中心' 时显示 SelfCheck 组件 -->
39
+            <SelfCheck v-if="this.userInfo.includes('设备维修中心')" />
40
+
41
+            <!-- 当 currentDepartment !== '设备维修中心' 时显示原内容 -->
42
+            <template v-else>
43
+                <!-- 时间范围选择 -->
44
+                <div class="time-range-section">
45
+                    <div class="time-tags-container">
46
+                        <div v-for="tag in timeTags" :key="tag.value"
47
+                            :class="['time-tag', { 'active': selectedTimeRange === tag.value, 'time-range-label': tag.isLabel }]"
48
+                            @click="tag.isLabel ? null : handleTimeTagClick(tag)">
49
+                            {{ tag.label }}
50
+                        </div>
51
+
52
+                        <!-- 自定义时间显示 - 紧跟自定义时间标签 -->
53
+                        <div v-if="selectedTimeRange === 'custom'" class="custom-time-inline">
54
+                            <uni-datetime-picker v-model="dateRange" type="daterange" rangeSeparator="至"
55
+                                @change="handleDateRangeChange" class="date-range-picker" :clear-icon="false" />
56
+                            <div class="days-count">共 {{ totalDays }} 天</div>
57
+                        </div>
52 58
                     </div>
53 59
                 </div>
54
-            </div>
55 60
 
56
-            <!-- TypeDetail组件 -->
57
-            <TypeDetail :data-list="typeDetailData" @sort-change="handleSortChange" />
61
+                <!-- TypeDetail组件 -->
62
+                <TypeDetail :data-list="typeDetailData" @sort-change="handleSortChange" />
58 63
 
59
-            <!-- TotalDetail组件 -->
60
-            <TotalDetail :homePageWholeData="homePageWholeData" :start-date="startDate" :end-date="endDate"
61
-                :time-range="selectedTimeRange" :selectedRole="selectedRole" />
64
+                <!-- TotalDetail组件 -->
65
+                <TotalDetail :homePageWholeData="homePageWholeData" :start-date="startDate" :end-date="endDate"
66
+                    :time-range="selectedTimeRange" :selectedRole="selectedRole" />
62 67
 
63 68
 
64
-            <!-- QualityControlAnalysis组件 -->
65
-            <QualityControlAnalysis v-if="role.includes('zhijianke') || role.includes('test')"
66
-                :checkProblemDistributionData="checkProblemDistributionData"
67
-                :accuracyAnalysisData="accuracyAnalysisData" :prohibitedTop3Data="prohibitedTop3Data"
68
-                :concealmentPositionTop1Data="concealmentPositionTop1Data" />
69
+                <!-- QualityControlAnalysis组件 -->
70
+                <QualityControlAnalysis v-if="role.includes('zhijianke') || role.includes('test')"
71
+                    :checkProblemDistributionData="checkProblemDistributionData"
72
+                    :accuracyAnalysisData="accuracyAnalysisData" :prohibitedTop3Data="prohibitedTop3Data"
73
+                    :concealmentPositionTop1Data="concealmentPositionTop1Data" />
69 74
 
70
-            <!-- PerformanceAnalysis组件 -->
71
-            <PerformanceAnalysis v-if="role.includes('zhijianke') || role.includes('test')"
72
-                :performanceData="performanceData" />
75
+                <!-- PerformanceAnalysis组件 -->
76
+                <PerformanceAnalysis v-if="role.includes('zhijianke') || role.includes('test')"
77
+                    :performanceData="performanceData" />
78
+            </template>
73 79
         </div>
74 80
     </view>
75 81
 </template>
@@ -86,6 +92,7 @@ import Notice from "@/pages/home/components/notice.vue";
86 92
 import SelectTag from "@/components/select-tag/select-tag.vue";
87 93
 import TypeDetail from "@/pages/home-new/components/type-detail.vue";
88 94
 import TotalDetail from "@/pages/home-new/components/total-detail.vue";
95
+import SelfCheck from "@/pages/home-new/components/selfCheck.vue";
89 96
 import { getUserProfile, getAppListByRoleId, getAppList } from "@/api/system/user";
90 97
 import { getAttendanceList } from "@/api/attendance/attendance"
91 98
 import { getUnreadCount } from "@/api/check/checkTask"
@@ -104,6 +111,7 @@ export default {
104 111
         SelectTag,
105 112
         TypeDetail,
106 113
         TotalDetail,
114
+        SelfCheck,
107 115
         QualityControlAnalysis,
108 116
         PerformanceAnalysis,
109 117
         uniDatetimePicker,
@@ -111,6 +119,7 @@ export default {
111 119
     },
112 120
     data() {
113 121
         return {
122
+            currentDepartment: '设备维修中心', // 用于控制显示不同内容的变量
114 123
             checkerId: this.$store.state.user.id,
115 124
             userInfo: '',
116 125
             todayCheckInTime: '未打卡',

+ 288 - 0
src/pages/selfCheck/index.vue

@@ -0,0 +1,288 @@
1
+<template>
2
+    <home-container :customStyle="{ background: 'none',padding: '0' }" >
3
+        <view class="self-check-page">
4
+            <!-- 标签页区域 -->
5
+            <view class="tabs-section">
6
+                <view v-for="(tab, index) in tabs" :key="index"
7
+                    :class="['tab-item', { 'active': currentTab === tab.value }]"
8
+                    @click="switchTab(tab.value)">
9
+                    <text class="tab-text">{{ tab.label }}</text>
10
+                </view>
11
+            </view>
12
+
13
+            <!-- 卡片列表区域 -->
14
+            <view class="cards-section">
15
+                <view class="check-card" v-for="(item, index) in filteredItems" :key="index">
16
+                    <view class="card-content">
17
+                        <view class="card-row">
18
+                            <text class="card-label">{{ item.name }}</text>
19
+                            <text class="card-label">{{ item.serialNumber }}</text>
20
+                            <text class="card-date">{{ item.date }}</text>
21
+                        </view>
22
+                        <view class="card-row" style="justify-content: flex-start;">
23
+                            <text class="card-label">{{ item.location }}</text>
24
+                            <text class="card-role" style="margin-left: 10px;">{{ item.role }}</text>
25
+                        </view>
26
+                    </view>
27
+                    <view :class="['status-tag', getStatusClass(item.colorType)]">
28
+                        {{ getStatusText(item.colorType) }}
29
+                    </view>
30
+                </view>
31
+            </view>
32
+        </view>
33
+    </home-container>
34
+</template>
35
+
36
+<script>
37
+import HomeContainer from "@/components/HomeContainer.vue";
38
+import { getDeviceList } from "@/api/home-new/home-new";
39
+
40
+export default {
41
+    name: 'SelfCheckPage',
42
+    components: {
43
+        HomeContainer
44
+    },
45
+    data() {
46
+        return {
47
+            currentTab: 'all',
48
+            tabs: [
49
+                { label: '全部', value: 'all' },
50
+                { label: '两周临期', value: 'twoWeeks' },
51
+                { label: '一月临期', value: 'oneMonth' },
52
+                { label: '已过期', value: 'expired' }
53
+            ],
54
+            allItems: [],
55
+            redItems: [],
56
+            orangeItems: [],
57
+            yellowItems: []
58
+        }
59
+    },
60
+    onLoad(options) {
61
+        // 接收跳转参数
62
+        if (options && options.tab) {
63
+            this.currentTab = options.tab;
64
+        }
65
+        this.fetchDeviceList();
66
+    },
67
+    computed: {
68
+        filteredItems() {
69
+            switch(this.currentTab) {
70
+                case 'all':
71
+                    return this.allItems;
72
+                case 'expired':
73
+                    return this.redItems;
74
+                case 'twoWeeks':
75
+                    return this.orangeItems;
76
+                case 'oneMonth':
77
+                    return this.yellowItems;
78
+                default:
79
+                    return [];
80
+            }
81
+        }
82
+    },
83
+    methods: {
84
+        switchTab(tabValue) {
85
+            this.currentTab = tabValue;
86
+            this.fetchDeviceList();
87
+        },
88
+        getStatusClass(colorType) {
89
+            switch(colorType) {
90
+                case 'RED':
91
+                    return 'expired';
92
+                case 'ORANGE':
93
+                    return 'urgent';
94
+                case 'YELLOW':
95
+                    return 'normal';
96
+                default:
97
+                    return '';
98
+            }
99
+        },
100
+        getStatusText(colorType) {
101
+            switch(colorType) {
102
+                case 'RED':
103
+                    return '已过期';
104
+                case 'ORANGE':
105
+                    return '两周临期';
106
+                case 'YELLOW':
107
+                    return '一月临期';
108
+                default:
109
+                    return '';
110
+            }
111
+        },
112
+        fetchDeviceList() {
113
+            // 根据当前 tab 请求不同的接口
114
+            let colorType = '';
115
+            switch(this.currentTab) {
116
+                case 'all':
117
+                    colorType = 'MIXED';
118
+                    break;
119
+                case 'expired':
120
+                    colorType = 'RED';
121
+                    break;
122
+                case 'twoWeeks':
123
+                    colorType = 'ORANGE';
124
+                    break;
125
+                case 'oneMonth':
126
+                    colorType = 'YELLOW';
127
+                    break;
128
+            }
129
+            
130
+            getDeviceList({ colorType }).then(res => {
131
+                if (res.code === 200) {
132
+                    const data = res.data || [];
133
+                    switch(this.currentTab) {
134
+                        case 'all':
135
+                            this.allItems = data.map(item => this.formatDeviceItem(item));
136
+                            break;
137
+                        case 'expired':
138
+                            this.redItems = data.map(item => this.formatDeviceItem(item));
139
+                            break;
140
+                        case 'twoWeeks':
141
+                            this.orangeItems = data.map(item => this.formatDeviceItem(item));
142
+                            break;
143
+                        case 'oneMonth':
144
+                            this.yellowItems = data.map(item => this.formatDeviceItem(item));
145
+                            break;
146
+                    }
147
+                }
148
+            }).catch(err => {
149
+                console.error('获取设备列表失败', err);
150
+            });
151
+        },
152
+        formatDeviceItem(item) {
153
+            return {
154
+                name: item.equipmentName || '空',
155
+                serialNumber: item.equipmentCode || '空',
156
+                location: item.installationLocation || '空',
157
+                role: `${item.inspectionTeamLeaderName || ''}、${item.inspectionTeamMember1Name || ''}、${item.inspectionTeamMember2Name || ''}` || '空',
158
+                date: this.formatDate(item.nextInspectionDueDate) || '空',
159
+                colorType: item.colorType || 'YELLOW'
160
+            };
161
+        },
162
+        formatDate(dateStr) {
163
+            if (!dateStr) return '';
164
+            const date = new Date(dateStr);
165
+            const year = date.getFullYear();
166
+            const month = String(date.getMonth() + 1).padStart(2, '0');
167
+            const day = String(date.getDate()).padStart(2, '0');
168
+            return `${year}-${month}-${day}`;
169
+        }
170
+    }
171
+}
172
+</script>
173
+
174
+<style scoped>
175
+.self-check-page {
176
+    width: 100%;
177
+    min-height: 100vh;
178
+    background-color: #fff;
179
+}
180
+
181
+.tabs-section {
182
+    display: flex;
183
+    padding: 10px;
184
+    border-bottom: 1px solid #f0f0f0;
185
+}
186
+
187
+.tab-item {
188
+    margin-right: 20px;
189
+    padding: 5px 0;
190
+    position: relative;
191
+}
192
+
193
+.tab-item:last-child {
194
+    margin-right: 0;
195
+}
196
+
197
+.tab-text {
198
+    font-size: 16px;
199
+    color: #999;
200
+}
201
+
202
+.tab-item.active .tab-text {
203
+    color: #409eff;
204
+    font-weight: bold;
205
+}
206
+
207
+.tab-item.active::after {
208
+    content: '';
209
+    position: absolute;
210
+    bottom: 0;
211
+    left: 0;
212
+    right: 0;
213
+    height: 3px;
214
+    background-color: #409eff;
215
+}
216
+
217
+.cards-section {
218
+    padding: 10px;
219
+}
220
+
221
+.check-card {
222
+    background-color: #fff;
223
+    border-radius: 10px;
224
+    padding: 12px;
225
+    margin-bottom: 12px;
226
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
227
+    display: flex;
228
+    justify-content: space-between;
229
+    align-items: flex-start;
230
+}
231
+
232
+.card-content {
233
+    flex: 1;
234
+    display: flex;
235
+    flex-direction: column;
236
+    gap: 8px;
237
+}
238
+
239
+.card-row {
240
+    display: flex;
241
+    justify-content: space-between;
242
+    align-items: center;
243
+}
244
+
245
+.card-label {
246
+    font-size: 14px;
247
+    color: #333;
248
+}
249
+
250
+.card-date {
251
+    font-size: 14px;
252
+    color: #333;
253
+}
254
+
255
+.card-role {
256
+    font-size: 14px;
257
+    color: #333;
258
+}
259
+
260
+.status-tag {
261
+    padding: 4px 12px;
262
+    border-radius:10px 0  10px 0;
263
+    font-size: 14px;
264
+    font-weight: bold;
265
+    margin: -12px -12px -12px 0;
266
+    align-self: flex-end;
267
+}
268
+
269
+.status-tag.expired {
270
+    background-color: #FF0000;
271
+    color: #fff;
272
+}
273
+
274
+.status-tag.urgent {
275
+    background-color: #FFA500;
276
+    color: #fff;
277
+}
278
+
279
+.status-tag.normal {
280
+    background-color: #FFD700;
281
+    color: #333;
282
+}
283
+</style>
284
+
285
+
286
+
287
+
288
+