Просмотр исходного кода

feat(inspection): 优化巡检分页记忆及多项展示调整

- 巡检列表按账号、项目、标段、模块分别记忆每页条数
- 趋势图改为完成占比统计,移除需整改占比逻辑
- 整改人员查询改为展示本轮所有未完成整改人
- 菜单badge数为0时隐藏,整改/批复页隐藏状态筛选
- 整改意见为空时不再显示"未填写整改意见"提示
- 安全巡检流程标签"上报"改为"审批中"
- 文件列表表格内容居中对齐
caipin 1 неделя назад
Родитель
Сommit
785d112e53

+ 1 - 0
app/const/safe_inspection.js

@@ -6,4 +6,5 @@ inspection.stage = { legacy: 0, report: 1, rectification: 2, reply: 3 };
 inspection.stageString = ['旧流程', '上报', '整改', '批复'];
 inspection.filter.status.reply = 13;
 inspection.filter.statusString[13] = '批复中';
+inspection.statusButtonClass[inspection.status.checkNoPre] = 'btn-success';
 module.exports = inspection;

+ 1 - 0
app/controller/quality_controller.js

@@ -623,6 +623,7 @@ module.exports = app => {
                 const pageInfo = {
                     page,
                     pageSizeSelect: 1,
+                    pageSizeCacheKey: 'inspection-pageSize:' + ctx.session.sessionUser.accountId + ':' + ctx.path.replace(/\/$/, ''),
                     pageSize,
                     total_num: total,
                     total: Math.ceil(total / pageSize),

+ 1 - 0
app/controller/safe_controller.js

@@ -683,6 +683,7 @@ module.exports = app => {
                 const pageInfo = {
                     page,
                     pageSizeSelect: 1,
+                    pageSizeCacheKey: 'inspection-pageSize:' + ctx.session.sessionUser.accountId + ':' + ctx.path.replace(/\/$/, ''),
                     pageSize,
                     total_num: total,
                     total: Math.ceil(total / pageSize),

+ 71 - 4
app/public/js/global.js

@@ -262,7 +262,7 @@ $(function(){
     })
 });
 
-function setChangeFilterData(orderLocal, filterString = '') {
+function setChangeFilterData(orderLocal, filterString = '', pageSize = getLocalCache('account-pageSize')) {
     const filterData = [];
     const orderSetting = getLocalCache(orderLocal);
     if(orderSetting) {
@@ -270,9 +270,7 @@ function setChangeFilterData(orderLocal, filterString = '') {
         filterData.push('sort=' + orders[0]);
         filterData.push('order=' + orders[1]);
     }
-    if (getLocalCache('account-pageSize')) {
-        filterData.push('pageSize=' + getLocalCache('account-pageSize'));
-    }
+    if (pageSize) filterData.push('pageSize=' + pageSize);
     filterString = filterString ? filterString + '&' : filterString + '?';
     if (filterData.length > 0) filterString = filterString + filterData.join('&');
     return filterString;
@@ -1337,4 +1335,73 @@ const posShowCache = 'zh-pos-show';
 
 $(document).ready(function () {
   $('.modal').draggable({handle: '.modal-header'});
+  bindInspectionPageSize();
 });
+
+// 电脑版巡检列表按账号、项目、标段、模块和栏目分别记忆每页条数。
+function getInspectionPageSizeKey(url = window.location.href) {
+    if (typeof userID === 'undefined') return null;
+    try {
+        const target = new URL(url, window.location.href);
+        if (target.origin !== window.location.origin || !/^\/sp\/[^/]+\/(quality|safe)\/tender\/\d+\/inspection(?:\/(rectification|approval))?\/?$/.test(target.pathname)) return null;
+        return 'inspection-pageSize:' + userID + ':' + target.pathname.replace(/\/$/, '');
+    } catch (err) {
+        return null;
+    }
+}
+
+function getInspectionPageSize(url = window.location.href) {
+    const key = getInspectionPageSizeKey(url);
+    if (!key) return null;
+    const sizes = [15, 30, 50, 100];
+    try {
+        const cached = Number(getLocalCache(key));
+        if (sizes.includes(cached)) return cached;
+    } catch (err) {
+        // 本地存储不可用时,使用地址中的条数或默认值。
+    }
+    const size = Number(new URL(url, window.location.href).searchParams.get('pageSize'));
+    return sizes.includes(size) ? size : 15;
+}
+
+function inspectionPageUrl(url) {
+    const size = getInspectionPageSize(url);
+    if (!size) return url;
+    const target = new URL(url, window.location.href);
+    target.searchParams.set('pageSize', size);
+    return target.pathname + target.search + target.hash;
+}
+
+function restoreInspectionPageSize() {
+    const key = getInspectionPageSizeKey();
+    if (!key) return;
+    const size = getInspectionPageSize();
+    try {
+        setLocalCache(key, size);
+    } catch (err) {
+        // 不影响本次分页及导航。
+    }
+    const target = new URL(window.location.href);
+    if (Number(target.searchParams.get('pageSize') || 15) !== size) {
+        target.searchParams.set('pageSize', size);
+        target.searchParams.delete('page');
+        window.location.replace(target.pathname + target.search + target.hash);
+    }
+}
+
+function bindInspectionPageSize() {
+    restoreInspectionPageSize();
+    function updateLink() {
+        const link = $(this);
+        const href = link.attr('href');
+        if (!href || href.charAt(0) === '#' || link.closest('#zhankaiSelect').length) return;
+        const target = inspectionPageUrl(href);
+        if (target !== href) link.attr('href', target);
+    }
+    $('a[href]').each(updateLink);
+    // 同时覆盖折叠菜单重新渲染及详情页返回列表的入口。
+    $(document).on('click.inspectionPageSize', 'a[href]', updateLink);
+    $(window).on('pageshow.inspectionPageSize', function (event) {
+        if (event.originalEvent && event.originalEvent.persisted) restoreInspectionPageSize();
+    });
+}

+ 4 - 8
app/public/js/quality_inspection.js

@@ -252,7 +252,7 @@ $(document).ready(() => {
     $('#status_select a').on('click', function () {
         const status = $(this).data('val');
         let url = `/sp/${spid}/quality/tender/${tenderId}/inspection`;
-        const filterString = setChangeFilterData('quality-inspection-'+ tenderId +'-list-order', status !== 0 ? '?status='+ status : '');
+        const filterString = setChangeFilterData('quality-inspection-'+ tenderId +'-list-order', status !== 0 ? '?status='+ status : '', getInspectionPageSize(url));
         if (filterString) url = url + filterString;
         window.location.href = url;
     });
@@ -287,9 +287,7 @@ $(document).ready(() => {
         }
         filterData.push('sort='+ $(this).val());
         filterData.push('order=' + $('#order-radio input[name="paixu"]:checked').val());
-        if (getLocalCache('account-pageSize')) {
-            filterData.push('pageSize=' + getLocalCache('account-pageSize'));
-        }
+        filterData.push('pageSize=' + getInspectionPageSize());
         if (filterData.length > 0) {
             link += '?' + filterData.join('&');
         }
@@ -305,9 +303,7 @@ $(document).ready(() => {
         }
         filterData.push('sort='+ $('#sort-radio input[name="paizhi"]:checked').val());
         filterData.push('order=' + $(this).val());
-        if (getLocalCache('account-pageSize')) {
-            filterData.push('pageSize=' + getLocalCache('account-pageSize'));
-        }
+        filterData.push('pageSize=' + getInspectionPageSize());
         if (filterData.length > 0) {
             link += '?' + filterData.join('&');
         }
@@ -325,7 +321,7 @@ $(document).ready(() => {
         $('#file-content').empty();
         let html = '';
         files.forEach((file, idx) => {
-            html += `<tr><td><a href="${file.filepath}" target="_blank">${file.filename}</a></td><td>${file.username}</td><td>${moment(file.upload_time).format('YYYY-MM-DD HH:mm:ss')}</td><td><a href="/sp/${spid}/quality/tender/${file.tid}/inspection/${file.qiid}/information/file/${file.id}/download" class="mr-2"><i class="fa fa-download"></i></a></td></tr>`
+            html += `<tr><td><a href="${file.filepath}" target="_blank">${file.filename}</a></td><td class="text-center">${file.username}</td><td class="text-center">${moment(file.upload_time).format('YYYY-MM-DD HH:mm:ss')}</td><td class="text-center"><a href="/sp/${spid}/quality/tender/${file.tid}/inspection/${file.qiid}/information/file/${file.id}/download"><i class="fa fa-download"></i></a></td></tr>`
         })
         $('#file-content').append(html);
     }

+ 1 - 3
app/public/js/quality_inspection_information.js

@@ -361,9 +361,7 @@ $(document).ready(function () {
                 const filterData = [];
                 filterData.push('sort='+ orders[0]);
                 filterData.push('order=' + orders[1]);
-                if (getLocalCache('account-pageSize')) {
-                    filterData.push('pageSize=' + getLocalCache('account-pageSize'));
-                }
+                filterData.push('pageSize=' + getInspectionPageSize(link));
                 if (filterData.length > 0) {
                     link += '?' + filterData.join('&');
                 }

+ 17 - 8
app/public/js/quality_inspection_overview.js

@@ -43,9 +43,9 @@ $(document).ready(function () {
                 // 上报、批复分别使用现有列表入口,避免合并统计后跳转到单一阶段。
                 setTimeout(function () { $('#quality-overview-approval').dropdown('toggle').trigger('focus'); }, 0);
             } else if (event.data.key === 'rectification') {
-                window.location.href = inspectionUrl + '/rectification';
+                window.location.href = inspectionPageUrl(inspectionUrl + '/rectification');
             } else if (event.data.key === 'completed') {
-                window.location.href = inspectionUrl + '?status=3';
+                window.location.href = inspectionPageUrl(inspectionUrl + '?status=3');
             }
         });
         charts.push(pie);
@@ -53,18 +53,18 @@ $(document).ready(function () {
     const trend = qualityInspectionOverview.trend;
     const trendChart = echarts.init(document.getElementById('quality-overview-trend'));
     trendChart.setOption({
-        tooltip: { trigger: 'axis', axisPointer: { type: 'cross' } },
-        legend: { data: ['首次上报数', '完成数', '需整改占比'] },
+        tooltip: { trigger: 'axis', axisPointer: { type: 'cross' }, formatter: formatQualityInspectionTrendTooltip },
+        legend: { data: ['提交巡检', '完成巡检', '完成占比'] },
         grid: { left: 15, right: 25, top: 65, bottom: 20, containLabel: true },
         xAxis: { type: 'category', data: trend.months },
         yAxis: [
             { type: 'value', name: '数量(单)', min: 0, minInterval: 1 },
-            { type: 'value', name: '比例(%)', min: 0, max: 100, axisLabel: { formatter: '{value}%' } },
+            { type: 'value', name: '比例(%)', min: 0, axisLabel: { formatter: '{value}%' } },
         ],
         series: [
-            { name: '首次上报数', type: 'bar', data: trend.submitted, itemStyle: { color: '#007bff' }, barMaxWidth: 24 },
-            { name: '完成数', type: 'bar', data: trend.completed, itemStyle: { color: '#28a745' }, barMaxWidth: 24 },
-            { name: '需整改占比', type: 'line', yAxisIndex: 1, data: trend.ratios, itemStyle: { color: '#f0ad00' }, symbolSize: 6 },
+            { name: '提交巡检', type: 'bar', data: trend.submitted, itemStyle: { color: '#007bff' }, barMaxWidth: 24 },
+            { name: '完成巡检', type: 'bar', data: trend.completed, itemStyle: { color: '#28a745' }, barMaxWidth: 24 },
+            { name: '完成占比', type: 'line', yAxisIndex: 1, data: trend.ratios, itemStyle: { color: '#f0ad00' }, symbolSize: 6 },
         ],
     });
     charts.push(trendChart);
@@ -78,3 +78,12 @@ $(document).ready(function () {
         charts.forEach(function (chart) { chart.dispose(); });
     });
 });
+
+function formatQualityInspectionTrendTooltip(items) {
+    if (!items.length) return '';
+    const title = echarts.format.encodeHTML(items[0].axisValueLabel || items[0].name);
+    return title + '<br/>' + items.map(function (item) {
+        const unit = item.seriesName === '完成占比' ? '%' : '';
+        return item.marker + echarts.format.encodeHTML(item.seriesName) + ':' + Number(item.value) + unit;
+    }).join('<br/>');
+}

+ 4 - 8
app/public/js/safe_inspection.js

@@ -252,7 +252,7 @@ $(document).ready(() => {
     $('#status_select a').on('click', function () {
         const status = $(this).data('val');
         let url = `/sp/${spid}/safe/tender/${tenderId}/inspection`;
-        const filterString = setChangeFilterData('safe-inspection-'+ tenderId +'-list-order', status !== 0 ? '?status='+ status : '');
+        const filterString = setChangeFilterData('safe-inspection-'+ tenderId +'-list-order', status !== 0 ? '?status='+ status : '', getInspectionPageSize(url));
         if (filterString) url = url + filterString;
         window.location.href = url;
     });
@@ -287,9 +287,7 @@ $(document).ready(() => {
         }
         filterData.push('sort='+ $(this).val());
         filterData.push('order=' + $('#order-radio input[name="paixu"]:checked').val());
-        if (getLocalCache('account-pageSize')) {
-            filterData.push('pageSize=' + getLocalCache('account-pageSize'));
-        }
+        filterData.push('pageSize=' + getInspectionPageSize());
         if (filterData.length > 0) {
             link += '?' + filterData.join('&');
         }
@@ -305,9 +303,7 @@ $(document).ready(() => {
         }
         filterData.push('sort='+ $('#sort-radio input[name="paizhi"]:checked').val());
         filterData.push('order=' + $(this).val());
-        if (getLocalCache('account-pageSize')) {
-            filterData.push('pageSize=' + getLocalCache('account-pageSize'));
-        }
+        filterData.push('pageSize=' + getInspectionPageSize());
         if (filterData.length > 0) {
             link += '?' + filterData.join('&');
         }
@@ -325,7 +321,7 @@ $(document).ready(() => {
         $('#file-content').empty();
         let html = '';
         files.forEach((file, idx) => {
-            html += `<tr><td><a href="${file.filepath}" target="_blank">${file.filename}</a></td><td>${file.username}</td><td>${moment(file.upload_time).format('YYYY-MM-DD HH:mm:ss')}</td><td><a href="/sp/${spid}/safe/tender/${file.tid}/inspection/${file.qiid}/information/file/${file.id}/download" class="mr-2"><i class="fa fa-download"></i></a></td></tr>`
+            html += `<tr><td><a href="${file.filepath}" target="_blank">${file.filename}</a></td><td class="text-center">${file.username}</td><td class="text-center">${moment(file.upload_time).format('YYYY-MM-DD HH:mm:ss')}</td><td class="text-center"><a href="/sp/${spid}/safe/tender/${file.tid}/inspection/${file.qiid}/information/file/${file.id}/download"><i class="fa fa-download"></i></a></td></tr>`
         })
         $('#file-content').append(html);
     }

+ 1 - 3
app/public/js/safe_inspection_information.js

@@ -361,9 +361,7 @@ $(document).ready(function () {
                 const filterData = [];
                 filterData.push('sort='+ orders[0]);
                 filterData.push('order=' + orders[1]);
-                if (getLocalCache('account-pageSize')) {
-                    filterData.push('pageSize=' + getLocalCache('account-pageSize'));
-                }
+                filterData.push('pageSize=' + getInspectionPageSize(link));
                 if (filterData.length > 0) {
                     link += '?' + filterData.join('&');
                 }

+ 2 - 2
app/public/js/safe_inspection_overview.js

@@ -43,9 +43,9 @@ $(document).ready(function () {
                 // 上报、批复分别使用现有列表入口,避免合并统计后跳转到单一阶段。
                 setTimeout(function () { $('#safe-overview-approval').dropdown('toggle').trigger('focus'); }, 0);
             } else if (event.data.key === 'rectification') {
-                window.location.href = inspectionUrl + '/rectification';
+                window.location.href = inspectionPageUrl(inspectionUrl + '/rectification');
             } else if (event.data.key === 'completed') {
-                window.location.href = inspectionUrl + '?status=3';
+                window.location.href = inspectionPageUrl(inspectionUrl + '?status=3');
             }
         });
         charts.push(pie);

+ 10 - 13
app/service/quality_inspection.js

@@ -382,14 +382,13 @@ module.exports = app => {
 
         async getOverviewRectifiers(tid, ids) {
             if (!ids.length) return [];
-            // ids 来自当前标段的整改清单,只批量读取这十条记录的待处理人员。
+            // 展示本轮所有未完成整改人,包括正在处理及尚未轮到的人员。
             const sql = 'SELECT b.qiid, b.aid, p.name FROM ?? b JOIN ?? a ON a.id = b.qiid AND a.tid = b.tid' +
                 ' LEFT JOIN ?? p ON p.id = b.aid WHERE a.tid = ? AND a.id IN (?)' +
-                ' AND b.times = a.times AND b.is_old = 0 AND b.status = 12' +
-                ' AND ((a.flow_version = 1 AND b.flow_stage = 2 AND b.stage_round = a.stage_round) OR (a.flow_version = 0 AND b.is_rectification = 1))' +
-                ' AND (a.flow_version = 0 OR NOT EXISTS (SELECT 1 FROM ?? c WHERE c.qiid = b.qiid AND c.times = b.times AND c.flow_stage = 2 AND c.stage_round = b.stage_round AND c.is_old = 0 AND c.status IN (1, 12) AND (c.audit_order < b.audit_order OR (c.audit_order = b.audit_order AND c.id < b.id))))' +
-                ' ORDER BY b.`order`, b.id';
-            const sqlParam = [this.ctx.service.qualityInspectionAudit.tableName, this.tableName, this.ctx.service.projectAccount.tableName, tid, ids, this.ctx.service.qualityInspectionAudit.tableName];
+                ' AND b.times = a.times AND b.is_old = 0' +
+                ' AND ((a.flow_version = 1 AND b.flow_stage = 2 AND b.stage_round = a.stage_round AND b.status IN (1, 12)) OR (a.flow_version = 0 AND b.is_rectification = 1 AND b.status = 12))' +
+                ' ORDER BY b.audit_order, b.`order`, b.id';
+            const sqlParam = [this.ctx.service.qualityInspectionAudit.tableName, this.tableName, this.ctx.service.projectAccount.tableName, tid, ids];
             return await this.db.query(sql, sqlParam);
         }
 
@@ -397,23 +396,21 @@ module.exports = app => {
             // 首次上报保留历史轮次和被替换节点;完成时间只取当前已完成流程的最终阶段。
             const sql = 'SELECT YEAR(v.first_report_time) AS report_year, MONTH(v.first_report_time) AS report_month,' +
                 ' YEAR(v.completed_time) AS completed_year, MONTH(v.completed_time) AS completed_month,' +
-                ' COUNT(*) AS inspection_count, SUM(v.needs_rectification) AS rectification_count FROM (' +
-                ' SELECT a.id, CASE WHEN a.flow_version = 1 THEN CASE WHEN a.need_rectification = 1 THEN 1 ELSE 0 END' +
-                ' ELSE CASE WHEN a.rectification_uid > 0 THEN 1 ELSE 0 END END AS needs_rectification,' +
+                ' COUNT(*) AS inspection_count FROM (' +
+                ' SELECT a.id,' +
                 ' MIN(CASE WHEN (a.flow_version = 1 AND b.flow_stage = 1) OR (a.flow_version = 0 AND b.is_rectification = 0)' +
                 ' THEN b.begin_time END) AS first_report_time,' +
                 ' MAX(CASE WHEN a.status = 3 AND b.times = a.times AND b.is_old = 0 AND b.status = 3' +
                 ' AND ((a.flow_version = 1 AND b.flow_stage = a.flow_stage AND b.stage_round = a.stage_round)' +
                 ' OR (a.flow_version = 0 AND b.is_rectification = 1)) THEN b.end_time END) AS completed_time' +
                 ' FROM ?? a LEFT JOIN ?? b ON b.qiid = a.id AND b.tid = a.tid WHERE a.tid = ?' +
-                ' GROUP BY a.id, a.flow_version, a.need_rectification, a.rectification_uid' +
+                ' GROUP BY a.id' +
                 ' ) v WHERE v.first_report_time IS NOT NULL OR v.completed_time IS NOT NULL' +
                 ' GROUP BY YEAR(v.first_report_time), MONTH(v.first_report_time), YEAR(v.completed_time), MONTH(v.completed_time)';
             const sqlParam = [this.tableName, this.ctx.service.qualityInspectionAudit.tableName, tid];
             const rows = await this.db.query(sql, sqlParam);
             const submitted = Array(12).fill(0);
             const completed = Array(12).fill(0);
-            const needsRectification = Array(12).fill(0);
             for (const row of rows) {
                 const reportYear = Number(row.report_year);
                 const completedYear = Number(row.completed_year);
@@ -421,7 +418,6 @@ module.exports = app => {
                 const completedMonth = Number(row.completed_month);
                 if (reportYear === year && reportMonth >= 1 && reportMonth <= 12) {
                     submitted[reportMonth - 1] += Number(row.inspection_count);
-                    needsRectification[reportMonth - 1] += Number(row.rectification_count);
                 }
                 if (completedYear === year && completedMonth >= 1 && completedMonth <= 12) {
                     completed[completedMonth - 1] += Number(row.inspection_count);
@@ -429,7 +425,8 @@ module.exports = app => {
             }
             return {
                 year, months: submitted.map((count, index) => year + '年' + (index + 1) + '月'), submitted, completed,
-                ratios: submitted.map((count, index) => (count ? Number((needsRectification[index] * 100 / count).toFixed(1)) : 0)),
+                // 完成巡检按整单最终完成月份统计,提交巡检按首次提交月份统计。
+                ratios: submitted.map((count, index) => (count ? Number((completed[index] * 100 / count).toFixed(1)) : 0)),
                 hasData: submitted.some(count => count > 0) || completed.some(count => count > 0),
             };
         }

+ 7 - 7
app/service/safe_inspection.js

@@ -276,7 +276,8 @@ module.exports = app => {
 
         setFlowLabel(inspection) {
             const status = inspection.status === undefined ? inspection.mstatus : inspection.status;
-            inspection.flowLabel = inspection.flow_version === 1 && [2, 6, 12].includes(status) ? auditConst.stageString[inspection.flow_stage] + '中' : auditConst.statusString[status];
+            const stageLabel = inspection.flow_stage === auditConst.stage.report ? '审批中' : auditConst.stageString[inspection.flow_stage] + '中';
+            inspection.flowLabel = inspection.flow_version === 1 && [2, 6, 12].includes(status) ? stageLabel : auditConst.statusString[status];
             inspection.actionLabel = status === 1 || status === 5 ? '上报' : status === 12 ? '整改' : inspection.flow_version === 1 && inspection.flow_stage === 3 ? '批复' : '审批';
         }
 
@@ -382,14 +383,13 @@ module.exports = app => {
 
         async getOverviewRectifiers(tid, ids) {
             if (!ids.length) return [];
-            // ids 来自当前标段的整改清单,只批量读取这十条记录的待处理人员。
+            // 展示本轮所有未完成整改人,包括正在处理及尚未轮到的人员。
             const sql = 'SELECT b.qiid, b.aid, p.name FROM ?? b JOIN ?? a ON a.id = b.qiid AND a.tid = b.tid' +
                 ' LEFT JOIN ?? p ON p.id = b.aid WHERE a.tid = ? AND a.id IN (?)' +
-                ' AND b.times = a.times AND b.is_old = 0 AND b.status = 12' +
-                ' AND ((a.flow_version = 1 AND b.flow_stage = 2 AND b.stage_round = a.stage_round) OR (a.flow_version = 0 AND b.is_rectification = 1))' +
-                ' AND (a.flow_version = 0 OR NOT EXISTS (SELECT 1 FROM ?? c WHERE c.qiid = b.qiid AND c.times = b.times AND c.flow_stage = 2 AND c.stage_round = b.stage_round AND c.is_old = 0 AND c.status IN (1, 12) AND (c.audit_order < b.audit_order OR (c.audit_order = b.audit_order AND c.id < b.id))))' +
-                ' ORDER BY b.`order`, b.id';
-            const sqlParam = [this.ctx.service.safeInspectionAudit.tableName, this.tableName, this.ctx.service.projectAccount.tableName, tid, ids, this.ctx.service.safeInspectionAudit.tableName];
+                ' AND b.times = a.times AND b.is_old = 0' +
+                ' AND ((a.flow_version = 1 AND b.flow_stage = 2 AND b.stage_round = a.stage_round AND b.status IN (1, 12)) OR (a.flow_version = 0 AND b.is_rectification = 1 AND b.status = 12))' +
+                ' ORDER BY b.audit_order, b.`order`, b.id';
+            const sqlParam = [this.ctx.service.safeInspectionAudit.tableName, this.tableName, this.ctx.service.projectAccount.tableName, tid, ids];
             return await this.db.query(sql, sqlParam);
         }
 

+ 8 - 1
app/view/layout/page.ejs

@@ -82,6 +82,9 @@
         },
         pageUrl: function(type, page, current){
             let queryData = JSON.parse('<%- pageInfo.queryData %>');
+            <% if (pageInfo.pageSizeCacheKey) { %>
+            queryData.pageSize = <%- pageInfo.pageSize %>;
+            <% } %>
             // 如果没有附带查询条件则直接返回
             if (Object.keys(queryData).length <= 0) {
                 return "?page=" + page;
@@ -143,6 +146,10 @@
     }
 
     $('#zhankaiSelect a').on('click', function () {
-        setLocalCache('account-pageSize', $(this).data('size'));
+        try {
+            setLocalCache(<%- JSON.stringify(pageInfo.pageSizeCacheKey || 'account-pageSize') %>, $(this).data('size'));
+        } catch (err) {
+            // 本地存储不可用时,仍可通过链接切换本次每页条数。
+        }
     })
 </script>

+ 1 - 1
app/view/quality/inspection.ejs

@@ -39,7 +39,7 @@
                         </div>
                     </div>
                 </div>
-                <div class="d-inline-block">
+                <div class="<%= /\/inspection\/(rectification|approval)\/?$/.test(ctx.path) ? 'd-none' : 'd-inline-block' %>">
                     <div class="btn-group">
                         <button type="button" class="btn btn-sm btn-light text-primary dropdown-toggle" data-toggle="dropdown" data-status="<%- status %>" id="zhankai"><% if (status !== 0) { %><%- filter.statusString[status] %>(<%- filter.count[status] %>)<% } else { %>全部<% } %></button>
                         <div class="dropdown-menu" aria-labelledby="zhankai" id="status_select">

+ 2 - 2
app/view/quality/inspection_flow.ejs

@@ -120,7 +120,7 @@
                                                                     <span class="ml-auto pl-2 text-<%= personTone %>"><% if (!node.origin && node.auditors.length > 1) { %><small class="mr-1"><%= flowStatusText[audit.status] %></small><% } %><i class="fa <%= node.origin || audit.status === 3 ? 'fa-check-circle' : [2, 12].includes(audit.status) ? 'fa-commenting' : [5, 6].includes(audit.status) ? 'fa-reply' : audit.status === 4 ? 'fa-stop-circle' : 'fa-circle-o' %>" aria-hidden="true"></i></span>
                                                                 <% } %>
                                                             </div>
-                                                            <div class="bg-light flow-opinion mt-1" aria-label="<%= phase.stage === 2 ? '整改意见' : '处理意见' %>"><i class="fa fa-commenting-o mr-1" aria-hidden="true"></i><%= audit.opinion || (phase.stage === 2 ? '未填写整改意见' : '') %></div>
+                                                            <div class="bg-light flow-opinion mt-1" aria-label="<%= phase.stage === 2 ? '整改意见' : '处理意见' %>"><i class="fa fa-commenting-o mr-1" aria-hidden="true"></i><%= audit.opinion || '' %></div>
                                                         </div>
                                                     <% }); %>
                                                 </div>
@@ -164,7 +164,7 @@
                                             <small class="text-muted">整改日期:<%= audit.rectification_date ? moment(audit.rectification_date).format('YYYY-MM-DD') : '' %></small>
                                         <% } %>
                                         <% if (!mobileFlow && phase.stage === 2) { %>
-                                            <div class="bg-light flow-opinion mt-1" aria-label="整改意见"><i class="fa fa-commenting-o mr-1" aria-hidden="true"></i><%= audit.opinion || '未填写整改意见' %></div>
+                                            <div class="bg-light flow-opinion mt-1" aria-label="整改意见"><i class="fa fa-commenting-o mr-1" aria-hidden="true"></i><%= audit.opinion || '' %></div>
                                         <% } else if (audit.opinion && !(phase.stage === 2 && inspection.rectificationPower && audit.aid === ctx.session.sessionUser.accountId && audit.status === 12)) { %><p class="mb-0 mt-2"><%= audit.opinion %></p><% } %>
                                         <% if (mobileFlow && phase.stage !== 2 && inspection.shenpiPower && inspection.flow_stage === phase.stage && audit.aid === ctx.session.sessionUser.accountId && audit.status === 2) { %>
                                             <div class="mt-2">

+ 5 - 5
app/view/quality/inspection_overview.ejs

@@ -76,15 +76,15 @@
             </div>
             <div class="card mb-3">
                 <div class="card-header d-flex align-items-center">
-                    <strong>整改趋势</strong>
+                    <strong>巡检完成趋势</strong>
                 </div>
                 <div class="card-body">
-                    <% if (!overview.trend.hasData) { %><p class="text-center text-muted mb-0"><%= overview.trend.year %>年暂无上报或完成记录</p><% } %>
-                    <div id="quality-overview-trend" class="overview-trend" role="img" aria-label="<%= overview.trend.year %>年巡检上报、完成及需整改占比趋势"></div>
+                    <% if (!overview.trend.hasData) { %><p class="text-center text-muted mb-0"><%= overview.trend.year %>年暂无提交或完成巡检记录</p><% } %>
+                    <div id="quality-overview-trend" class="overview-trend" role="img" aria-label="<%= overview.trend.year %>年提交巡检、完成巡检及完成占比趋势"></div>
                 </div>
                 <div class="card-footer text-muted small">
-                    <div>首次上报数按实际首次提交月份统计,退回重报不重复计数;完成数按整个流程最终完成月份统计。</div>
-                    <div>需整改占比为该月首次上报记录中,按当前保存的整改设置计算的需整改比例;趋势统计当年数据,上方展示当前状态。</div>
+                    <div>提交巡检按实际首次提交月份统计,退回重报不重复计数;完成巡检按整张巡检单最终完成月份统计。</div>
+                    <div>完成占比=完成巡检 ÷ 提交巡检 × 100%;按当月统计,当月无提交巡检时显示0%。</div>
                 </div>
             </div>
         </div>

+ 2 - 2
app/view/quality/sub_memu_list.ejs

@@ -15,14 +15,14 @@ const menuCounts = typeof filter !== 'undefined' && filter.count && filter.statu
 <div class="nav-box quality-inspection-menu">
     <ul class="nav-list list-unstyled">
         <li class="<%= ctx.url.includes('/inspection/rectification') ? 'active' : '' %>">
-            <a href="/sp/<%- ctx.subProject.id %>/quality/tender/<%= ctx.tender.id %>/inspection/rectification"><span class="ml-3">巡检整改</span><span class="badge badge-warning quality-inspection-menu-count"><%= menuCounts.rectification === undefined || menuCounts.rectification === null ? '—' : menuCounts.rectification %></span></a>
+            <a href="/sp/<%- ctx.subProject.id %>/quality/tender/<%= ctx.tender.id %>/inspection/rectification"><span class="ml-3">巡检整改</span><% if (menuCounts.rectification > 0) { %><span class="badge badge-warning quality-inspection-menu-count"><%= menuCounts.rectification %></span><% } %></a>
         </li>
     </ul>
 </div>
 <div class="nav-box quality-inspection-menu">
     <ul class="nav-list list-unstyled">
         <li class="<%= ctx.url.includes('/inspection/approval') ? 'active' : '' %>">
-            <a href="/sp/<%- ctx.subProject.id %>/quality/tender/<%= ctx.tender.id %>/inspection/approval"><span class="ml-3">巡检批复</span><span class="badge badge-warning quality-inspection-menu-count"><%= menuCounts.reply === undefined || menuCounts.reply === null ? '—' : menuCounts.reply %></span></a>
+            <a href="/sp/<%- ctx.subProject.id %>/quality/tender/<%= ctx.tender.id %>/inspection/approval"><span class="ml-3">巡检批复</span><% if (menuCounts.reply > 0) { %><span class="badge badge-warning quality-inspection-menu-count"><%= menuCounts.reply %></span><% } %></a>
         </li>
     </ul>
 </div>

+ 1 - 1
app/view/safe/inspection.ejs

@@ -39,7 +39,7 @@
                         </div>
                     </div>
                 </div>
-                <div class="d-inline-block">
+                <div class="<%= /\/inspection\/(rectification|approval)\/?$/.test(ctx.path) ? 'd-none' : 'd-inline-block' %>">
                     <div class="btn-group">
                         <button type="button" class="btn btn-sm btn-light text-primary dropdown-toggle" data-toggle="dropdown" data-status="<%- status %>" id="zhankai"><% if (status !== 0) { %><%- filter.statusString[status] %>(<%- filter.count[status] %>)<% } else { %>全部<% } %></button>
                         <div class="dropdown-menu" aria-labelledby="zhankai" id="status_select">

+ 2 - 2
app/view/safe/inspection_flow.ejs

@@ -120,7 +120,7 @@
                                                                     <span class="ml-auto pl-2 text-<%= personTone %>"><% if (!node.origin && node.auditors.length > 1) { %><small class="mr-1"><%= flowStatusText[audit.status] %></small><% } %><i class="fa <%= node.origin || audit.status === 3 ? 'fa-check-circle' : [2, 12].includes(audit.status) ? 'fa-commenting' : [5, 6].includes(audit.status) ? 'fa-reply' : audit.status === 4 ? 'fa-stop-circle' : 'fa-circle-o' %>" aria-hidden="true"></i></span>
                                                                 <% } %>
                                                             </div>
-                                                            <div class="bg-light flow-opinion mt-1" aria-label="<%= phase.stage === 2 ? '整改意见' : '处理意见' %>"><i class="fa fa-commenting-o mr-1" aria-hidden="true"></i><%= audit.opinion || (phase.stage === 2 ? '未填写整改意见' : '') %></div>
+                                                            <div class="bg-light flow-opinion mt-1" aria-label="<%= phase.stage === 2 ? '整改意见' : '处理意见' %>"><i class="fa fa-commenting-o mr-1" aria-hidden="true"></i><%= audit.opinion || '' %></div>
                                                         </div>
                                                     <% }); %>
                                                 </div>
@@ -164,7 +164,7 @@
                                             <small class="text-muted">整改日期:<%= audit.rectification_date ? moment(audit.rectification_date).format('YYYY-MM-DD') : '' %></small>
                                         <% } %>
                                         <% if (!mobileFlow && phase.stage === 2) { %>
-                                            <div class="bg-light flow-opinion mt-1" aria-label="整改意见"><i class="fa fa-commenting-o mr-1" aria-hidden="true"></i><%= audit.opinion || '未填写整改意见' %></div>
+                                            <div class="bg-light flow-opinion mt-1" aria-label="整改意见"><i class="fa fa-commenting-o mr-1" aria-hidden="true"></i><%= audit.opinion || '' %></div>
                                         <% } else if (audit.opinion && !(phase.stage === 2 && inspection.rectificationPower && audit.aid === ctx.session.sessionUser.accountId && audit.status === 12)) { %><p class="mb-0 mt-2"><%= audit.opinion %></p><% } %>
                                         <% if (mobileFlow && phase.stage !== 2 && inspection.shenpiPower && inspection.flow_stage === phase.stage && audit.aid === ctx.session.sessionUser.accountId && audit.status === 2) { %>
                                             <div class="mt-2">

+ 2 - 2
app/view/safe/sub_memu_list.ejs

@@ -12,14 +12,14 @@ const menuCounts = typeof filter !== 'undefined' && filter.count && filter.statu
 <div class="nav-box safe-inspection-menu">
     <ul class="nav-list list-unstyled">
         <li class="<%= ctx.url.includes('/inspection/rectification') ? 'active' : '' %>">
-            <a href="/sp/<%- ctx.subProject.id %>/safe/tender/<%= ctx.tender.id %>/inspection/rectification"><span class="ml-3">巡检整改</span><span class="badge badge-warning safe-inspection-menu-count"><%= menuCounts.rectification === undefined || menuCounts.rectification === null ? '—' : menuCounts.rectification %></span></a>
+            <a href="/sp/<%- ctx.subProject.id %>/safe/tender/<%= ctx.tender.id %>/inspection/rectification"><span class="ml-3">巡检整改</span><% if (menuCounts.rectification > 0) { %><span class="badge badge-warning safe-inspection-menu-count"><%= menuCounts.rectification %></span><% } %></a>
         </li>
     </ul>
 </div>
 <div class="nav-box safe-inspection-menu">
     <ul class="nav-list list-unstyled">
         <li class="<%= ctx.url.includes('/inspection/approval') ? 'active' : '' %>">
-            <a href="/sp/<%- ctx.subProject.id %>/safe/tender/<%= ctx.tender.id %>/inspection/approval"><span class="ml-3">巡检批复</span><span class="badge badge-warning safe-inspection-menu-count"><%= menuCounts.reply === undefined || menuCounts.reply === null ? '—' : menuCounts.reply %></span></a>
+            <a href="/sp/<%- ctx.subProject.id %>/safe/tender/<%= ctx.tender.id %>/inspection/approval"><span class="ml-3">巡检批复</span><% if (menuCounts.reply > 0) { %><span class="badge badge-warning safe-inspection-menu-count"><%= menuCounts.reply %></span><% } %></a>
         </li>
     </ul>
 </div>