diff --git a/src/api/inspectionDataManage/inspectionReporter.js b/src/api/inspectionDataManage/inspectionReporter.js index 60c3271..25b107a 100644 --- a/src/api/inspectionDataManage/inspectionReporter.js +++ b/src/api/inspectionDataManage/inspectionReporter.js @@ -20,10 +20,12 @@ export function getPatrolReport(lineId,filter) { }); } -export function getPatrolReportShaoxing(url, lineId, filter) { +export function getPatrolReportShaoxing(url, lineId, filter, stationCode) { + // 汇聚态:走聚合代理,stationCode 取点击的报告所属站 + const prefix = stationCode ? "/agg/proxy" : ""; return request({ - url: `/patrol/insreport/shaoxing/${url}/${lineId}/${filter}`, + url: `${prefix}/patrol/insreport/shaoxing/${url}/${lineId}/${filter}`, method: "get", - params: {}, + params: stationCode ? { stationCode } : {}, }); } diff --git a/src/api/portal/index.js b/src/api/portal/index.js index 62a544b..60c12f1 100644 --- a/src/api/portal/index.js +++ b/src/api/portal/index.js @@ -84,3 +84,46 @@ export function stopRealtimeVideo(query) { noAlert: true }); } + +// 汇聚侧云台控制:按摄像头所属站点代理转发 +// stationCode 取当前控制摄像头所在站(而非顶部站名筛选),以查询串方式传递 +export function aggPtzControl(payload) { + const { stationCode, ...data } = payload || {}; + return request({ + url: "/agg/proxy/patrol/preset/ptzControl", + method: "post", + params: { stationCode }, + data, + noAlert: true + }); +} + +// 汇聚侧预置位列表:路径与单站一致(cameraCode 按 # 拆成 device/domain 放路径上),仅追加 ?stationCode +export function aggPresetList(payload) { + const { stationCode, cameraCode } = payload || {}; + const value = String(cameraCode || ""); + const separatorIndex = value.indexOf("#"); + if (separatorIndex <= 0 || separatorIndex === value.length - 1) { + return Promise.reject(new Error("摄像机编码格式不正确")); + } + const device = encodeURIComponent(value.slice(0, separatorIndex)); + const domain = encodeURIComponent(value.slice(separatorIndex + 1)); + return request({ + url: `/agg/proxy/patrol/preset/presetList/${device}/${domain}`, + method: "get", + params: { stationCode }, + noAlert: true + }); +} + +// 汇聚侧预置位保存:按摄像头所属站点代理转发 +export function aggPresetCreate(payload) { + const { stationCode, ...data } = payload || {}; + return request({ + url: "/agg/proxy/patrol/preset/presetCreate", + method: "post", + params: { stationCode }, + data, + noAlert: true + }); +} diff --git a/src/api/videosMonitor/index.js b/src/api/videosMonitor/index.js index 406161f..e0b1cd0 100644 --- a/src/api/videosMonitor/index.js +++ b/src/api/videosMonitor/index.js @@ -1,4 +1,5 @@ import request from "@/utils/request"; +import store from "@/store"; import { defectList } from "../home/index"; /** @@ -229,11 +230,13 @@ export function analysisDefectList(params) { * @param {*} data * @returns */ - export function analysisDefectListShaoxing(params) { + export function analysisDefectListShaoxing(params, stationCode) { + // 汇聚态:走聚合代理,stationCode 取点击的任务所属站 + const prefix = stationCode ? "/agg/proxy" : ""; return request({ - url: `/patrol/analysis/list_v2_ex`, + url: `${prefix}/patrol/analysis/list_v2_ex`, method: "get", - params, + params: stationCode ? { ...params, stationCode } : params, }); } @@ -317,14 +320,27 @@ export function getDefectAlarmList(params = {}) { }); } /** - * 缺陷记录卡片的列表 + * 缺陷记录卡片的列表(支持 pageNum/pageSize/desc/pointName 等服务端筛选) * @param {*} data * @returns */ export function defectRecordList(params) { + // 汇聚态由拦截器映射改写为 /agg/patrol/analysis/defect/list;单站保持原路径(服务端 algName 筛选) return request({ url: `/patrol/analysis/defect/list`, method: "get", params, }); } + +/** + * 缺陷类型下拉选项:汇聚态 descOptions;单站 algNameOptions(算法名称) + * @returns + */ +export function defectDescOptions() { + const isAgg = store.getters.fromPortal; + return request({ + url: isAgg ? `/agg/analysis/defect/algNameOptions` : `/patrol/analysis/defect/algNameOptions`, + method: "get", + }); +} diff --git a/src/layout/components/AppMain.vue b/src/layout/components/AppMain.vue index 2746d6e..54f69ed 100644 --- a/src/layout/components/AppMain.vue +++ b/src/layout/components/AppMain.vue @@ -20,7 +20,9 @@ export default { return this.$store.state.tagsView.cachedViews }, key() { - return this.$route.path + // 拼上工作台选中的站名编码:切换站名时仅重建当前页面(重新拉取数据),导航栏不整页刷新 + const stationCode = this.$store.getters.workspaceStationCode || '' + return this.$route.path + (stationCode ? '||' + stationCode : '') } }, watch: { diff --git a/src/layout/components/Sidebar/index.vue b/src/layout/components/Sidebar/index.vue index aa64f8c..8b52730 100644 --- a/src/layout/components/Sidebar/index.vue +++ b/src/layout/components/Sidebar/index.vue @@ -50,7 +50,7 @@ export default { }, computed: { ...mapState(["settings"]), - ...mapGetters(["sidebarRouters", "sidebar", "roles"]), + ...mapGetters(["sidebarRouters", "sidebar", "roles", "fromPortal"]), // admin 账号显示全部导航,其余账号只显示默认菜单 isAdminAccount() { if ((this.roles || []).indexOf("admin") !== -1) return true; @@ -80,7 +80,10 @@ export default { const isTaskManagement = ["巡检任务管理", "巡视任务管理"].includes(title); const isImplementationPoints = !this.isAdminAccount && isImplementationPointsMenu(route); const isTemporarilyHiddenRootMenu = depth === 0 && temporarilyHiddenRootMenus.has(title); - if (isTaskManagement || isImplementationPoints || isTemporarilyHiddenRootMenu) return result; + // 汇聚门户进入的会话:历史回放暂时隐藏 + const isHistoryPlaybackHidden = this.fromPortal && + ["/video-playback", "/inspection-workspace/video-playback"].includes(route.path); + if (isTaskManagement || isImplementationPoints || isTemporarilyHiddenRootMenu || isHistoryPlaybackHidden) return result; result.push({ ...route, diff --git a/src/layout/index.vue b/src/layout/index.vue index e6c6eaf..b849b38 100644 --- a/src/layout/index.vue +++ b/src/layout/index.vue @@ -23,7 +23,23 @@ @click="goModule(item.path)" >{{ item.label }} - + + + + + @@ -41,6 +57,7 @@ import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components' import ResizeMixin from './mixin/ResizeHandler' import { mapState, mapGetters } from 'vuex' import variables from '@/assets/styles/variables.scss' +import { getStationList } from '@/api/portal' export default { name: 'Layout', @@ -55,7 +72,9 @@ export default { data() { return { // 侧边栏宽度档位:0=160px,1=200px,2=240px,3=280px,随子菜单展开层级加深 - sidebarWidthLevel: 0 + sidebarWidthLevel: 0, + // 汇聚态站名筛选选项 + stationOptions: [] } }, mixins: [ResizeMixin], @@ -83,7 +102,20 @@ export default { isPatrolWorkspace() { return this.$route.matched.some(route => route.meta && route.meta.patrolWorkspace) }, - ...mapGetters(['fromPortal']), + // 侧边栏宽度档位 ≥1 时给侧边栏容器加宽(修复模板引用未定义属性的告警) + sidebarWide() { + return this.sidebarWidthLevel >= 1 + }, + ...mapGetters(['fromPortal', 'workspaceStationCode']), + // 选中值存于 store(sessionStorage 持久化),跨页面保持 + stationCode: { + get() { + return this.workspaceStationCode || '' + }, + set(value) { + this.$store.dispatch('siteContext/setWorkspaceStation', value) + } + }, // 从门户跳转进入时展示:首页回门户,动环巡检为当前单站系统 moduleLinks() { if (!this.fromPortal) return [] @@ -103,7 +135,18 @@ export default { return variables; } }, + mounted() { + if (this.fromPortal) this.loadStationOptions() + }, methods: { + // 站名下拉选项:与汇聚首页同款接口 + loadStationOptions() { + getStationList({}).then(response => { + this.stationOptions = Array.isArray(response && response.data) ? response.data : [] + }).catch(() => { + this.stationOptions = [] + }) + }, goModule(path) { if (this.$route.path !== path) this.$router.push({ path }).catch(() => undefined) }, @@ -186,6 +229,34 @@ export default { align-items: stretch; } + /* 汇聚态站名筛选:靠行最右 */ + .module-station-select { + width: 150px; + + ::v-deep .el-input__inner { + height: 28px; + line-height: 28px; + background: rgba(16, 30, 84, 0.65); + border-color: rgba(84, 130, 255, 0.35); + color: #eef4ff; + font-size: 12px; + + &::placeholder { + color: rgba(159, 180, 232, 0.65); + } + } + + ::v-deep .el-input__suffix { + display: flex; + align-items: center; + height: 28px; + } + + ::v-deep .el-input__icon { + line-height: 28px; + } + } + .module-link { position: relative; min-width: 90px; diff --git a/src/store/getters.js b/src/store/getters.js index 87a5f27..1e045ea 100644 --- a/src/store/getters.js +++ b/src/store/getters.js @@ -21,5 +21,6 @@ const getters = { siteName: state => state.siteContext.siteName, inSite: state => state.siteContext.siteId !== undefined && state.siteContext.siteId !== null, fromPortal: state => state.siteContext.fromPortal, + workspaceStationCode: state => state.siteContext.workspaceStationCode, } export default getters diff --git a/src/store/modules/siteContext.js b/src/store/modules/siteContext.js index eb13058..50c224a 100644 --- a/src/store/modules/siteContext.js +++ b/src/store/modules/siteContext.js @@ -5,6 +5,8 @@ const SITE_KEY = "portal_site"; // 是否从汇聚门户跳转进入单站视图(会话级标记,直接输地址打开时不带) const FROM_KEY = "portal_from"; +// 汇聚门户工作台顶部"站名"下拉选中的站(会话级) +const WORKSPACE_STATION_KEY = "portal_ws_station"; function readSite() { try { @@ -22,7 +24,8 @@ const siteContext = { return { siteId: site ? site.id : undefined, siteName: site ? site.name : "", - fromPortal: sessionStorage.getItem(FROM_KEY) === "1" + fromPortal: sessionStorage.getItem(FROM_KEY) === "1", + workspaceStationCode: sessionStorage.getItem(WORKSPACE_STATION_KEY) || "" }; }, mutations: { @@ -42,6 +45,14 @@ const siteContext = { } else { sessionStorage.removeItem(SITE_KEY); } + }, + SET_WORKSPACE_STATION(state, code) { + state.workspaceStationCode = code || ""; + if (code) { + sessionStorage.setItem(WORKSPACE_STATION_KEY, code); + } else { + sessionStorage.removeItem(WORKSPACE_STATION_KEY); + } } }, actions: { @@ -49,6 +60,10 @@ const siteContext = { markFromPortal({ commit }) { commit("SET_FROM_PORTAL", true); }, + // 工作台顶部站名下拉选择 + setWorkspaceStation({ commit }, code) { + commit("SET_WORKSPACE_STATION", code); + }, // 进入单站视图 enterSite({ commit }, site) { commit("SET_SITE", site); @@ -62,6 +77,7 @@ const siteContext = { fromPortal: state => state.fromPortal, siteId: state => state.siteId, siteName: state => state.siteName, + workspaceStationCode: state => state.workspaceStationCode, // 是否处于单站视图 inSite: state => state.siteId !== undefined && state.siteId !== null } diff --git a/src/utils/request.js b/src/utils/request.js index e5a56aa..5719f45 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -18,6 +18,39 @@ let downloadLoadingInstance; export let isRelogin = { show: false }; axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8' + +// 汇聚门户(动环巡检)只读会话的接口改写映射: +// 从门户进入且未进入单站视图时,动环业务查询统一走后端聚合接口(agg)。 +// key/value 不含查询参数,按 url(忽略首部斜杠)全等匹配, +// 因此 /relation/right、/patrol/insreport/{id}/{filter} 等衍生接口不会被误改。 +const AGG_API_MAP = { + 'patrol/taskstatus/list': 'agg/taskstatus/list', + 'patrol/task/taskInfo_v2': 'agg/proxy/patrol/task/taskInfo_v2', + 'patrol/task/getPatrolPointName': 'agg/proxy/patrol/task/getPatrolPointName', + 'patrol/task/list': 'agg/task/list', + 'basedata/prodevmnt/device/treeAreaDeviceSelectFilterByPreset/relation': 'patrol/agg/tree/device', + 'basedata/patrolpointmnt/patrolpoint/list/monitor/relation': 'agg/patrolpoint/list/monitor', + 'patrol/insreport/list': 'agg/insreport/list', + 'patrol/calender/year': 'agg/calender/year', + 'patrol/calender/month': 'agg/calender/month', + 'patrol/calender/day': 'agg/calender/day', + 'patrol/analysis/defect/list': 'agg/analysis/defect/list' +} + +// 汇聚门户工作台顶部"站名"下拉:选中站后,下列查询接口统一携带 stationCode +// (前缀匹配;缺陷类型下拉选项 algNameOptions 也按选中站过滤) +const AGG_STATION_CODE_PATHS = [ + '/agg/taskstatus/list', + '/agg/task/list', + '/agg/insreport/list', + '/agg/calender/', + '/agg/tree/channel', + '/patrol/agg/tree/device', + '/agg/patrolpoint/list/monitor', + '/agg/analysis/defect/list', + '/agg/analysis/defect/algNameOptions' +] + // 创建axios实例 const service = axios.create({ // axios中请求配置有baseURL选项,表示请求URL公共部分 @@ -28,6 +61,16 @@ const service = axios.create({ // request拦截器 service.interceptors.request.use(config => { + // 汇聚门户只读会话:动环业务接口改写为聚合接口(单站/嵌入会话不受影响) + if (store.getters.fromPortal && !store.getters.inSite && typeof config.url === "string") { + const mapped = AGG_API_MAP[config.url.replace(/^\/+/, "")] + if (mapped) config.url = "/" + mapped + // 工作台顶部站名下拉:选中站后给列表/树查询带上 stationCode("全部场站"不传) + const wsCode = store.getters.workspaceStationCode + if (wsCode && config.method === "get" && AGG_STATION_CODE_PATHS.some(p => config.url.indexOf(p) === 0)) { + config.params = Object.assign({}, config.params, { stationCode: wsCode }) + } + } // 是否需要设置 token const isToken = (config.headers || {}).isToken === false // 是否需要防止数据重复提交 @@ -89,7 +132,7 @@ service.interceptors.request.use(config => { function LoginEntity() { let username; - let password; + let password; } diff --git a/src/views/cards/defectRecord/index.vue b/src/views/cards/defectRecord/index.vue index 7ed887f..6311547 100644 --- a/src/views/cards/defectRecord/index.vue +++ b/src/views/cards/defectRecord/index.vue @@ -11,13 +11,11 @@ {{ total }} + + + + @@ -128,7 +143,7 @@