Merge branch 'main' of http://120.76.84.145:10101/gitblit/r/H5/smartBuilding
| | |
| | | export const projectHazardSourceMap = { |
| | | HIGH_ALTITUDE_OPERATION: '高处作业', |
| | | FIRE_OPERATION: '动火作业', |
| | | MASS_CONCRETE_POURING: '大体积混凝土浇筑', |
| | | CONFINED_SPACE_OPERATION: '有限空间作业', |
| | | ROAD_OCCUPATION_CONSTRUCTION: '占道施工', |
| | | LARGE_CONCRETE_CONSTRUCTION: '大体积混凝土浇筑', |
| | | LIMITED_SPACE_OPERATION: '有限空间作业', |
| | | OCCUPY_CONSTRUCTION: '占道施工', |
| | | SINGLE_PERSON_OPERATION: '单人操作及作业', |
| | | SPACE_CROSS_OPERATION: '空间交叉作业' |
| | | SPACE_INTERSECTION_OPERATION: '空间交叉作业' |
| | | } |
| | | |
| | | // 项目类型映射 |
| | | export const projectTypeMapNew = { |
| | | HOUSE_CONSTRUCTION: '房建工程', |
| | | MUNICIPAL_ADMINISTRATION: '市政工程', |
| | | FIXED_ASSETS: '固定资产' |
| | | } |
| | | |
| | | // 项目用途类型映射 |
| | | export const projectUsageTypeMapNew = { |
| | | RESIDENTIAL: '住宅', |
| | | COMMERCIAL: '商业', |
| | | ROAD: '道路', |
| | | BRIDGE: '桥梁', |
| | | TUNNEL_WORKS: '隧道工程', |
| | | RETAIL: '仓储', |
| | | FOOD: '餐饮', |
| | | EDUCATION: '教育', |
| | | MEDICAL_BEAUTY: '医疗美容', |
| | | ENTERTAINMENT: '娱乐', |
| | | HOTEL: '酒店', |
| | | REFIT: '翻新改造', |
| | | PUBLIC_PLACE: '公共场所', |
| | | ENERGY_STATION: '能源站', |
| | | MULTI_FUNCTION_COMPLEX: '综合体' |
| | | } |
| | | export const planTypeMap = { |
| | | SECURITY_CHECK: '安全检查', |
| | | QUALITY_CHECK: '质量检查', |
| | | COMPREHENSIVE_CHECK: '综合检查', |
| | | EQUIPMENT_CHECK: '设备检查', |
| | | OPERATION_CHECK: '运营检查' |
| | | } |
| | | export const errorLevelMap = { |
| | | P1: '一级隐患', |
| | | P2: '二级隐患', |
| | | P3: '三级隐患', |
| | | P4: '四级隐患' |
| | | } |
| | | |
| | | export const errorReviewStateMap = { |
| | | NOT_REFORMED: '未整改', |
| | | PARTIAL_REFORMED: '部分整改', |
| | | REFORMED: '已整改' |
| | | } |
| | | |
| | | /** |
| | |
| | | } |
| | | }) |
| | | } |
| | | |
| | |
| | | </div> |
| | | <!-- 搜索 --> |
| | | <div class="flex a-center gap--16 mt--24 mb--20"> |
| | | <!-- 开始时间 --> |
| | | <div |
| | | @click="handleClick(1)" |
| | | class="flex a-center j-between px--20 w--300 h--40 relative bgcolor1 picker" |
| | | > |
| | | <el-date-picker |
| | | v-model="dateTime" |
| | | v-model="startTime" |
| | | ref="datetime1" |
| | | type="datetime" |
| | | placeholder="" |
| | |
| | | <div |
| | | class="absolute w100 h100 flex a-center c-fff fs--14 SHS" |
| | | style="width: calc(100% - 20px)" |
| | | v-if="dateTxt" |
| | | v-if="startTimeTxt" |
| | | > |
| | | {{ dateTxt }} |
| | | {{ startTimeTxt }} |
| | | </div> |
| | | <div |
| | | v-else |
| | | class="absolute w100 h100 flex a-center c-fff fs--14 SHSR" |
| | | > |
| | | 请选择日期 |
| | | 请选择开始日期 |
| | | </div> |
| | | <img |
| | | src="../../assets/img/home/Shape@2x (6).png" |
| | | class="w--13 h--13 shrink0" |
| | | /> |
| | | </div> |
| | | <!-- 结束时间 --> |
| | | <div |
| | | @click="handleClick(2)" |
| | | class="flex a-center j-between px--20 w--300 h--40 relative bgcolor1 picker" |
| | | > |
| | | <el-date-picker |
| | | v-model="dateTime" |
| | | v-model="endTime" |
| | | ref="datetime2" |
| | | type="datetime" |
| | | placeholder="" |
| | |
| | | <div |
| | | class="absolute w100 h100 flex a-center c-fff fs--14 SHS" |
| | | style="width: calc(100% - 20px)" |
| | | v-if="dateTxt" |
| | | v-if="endTimeTxt" |
| | | > |
| | | {{ dateTxt }} |
| | | {{ endTimeTxt }} |
| | | </div> |
| | | <div |
| | | v-else |
| | | class="absolute w100 h100 flex a-center c-fff fs--14 SHSR" |
| | | > |
| | | 请选择日期 |
| | | 请选择结束日期 |
| | | </div> |
| | | <img |
| | | src="../../assets/img/home/Shape@2x (6).png" |
| | | class="w--13 h--13 shrink0" |
| | | /> |
| | | </div> |
| | | <!-- 搜索框 --> |
| | | <div |
| | | class="flex a-center j-between w--300 pl--20 h--40 relative bgcolor1 searchBox" |
| | | > |
| | | <el-select |
| | | filterable |
| | | v-model="projectId" |
| | | <el-input |
| | | v-model="searchContent" |
| | | placeholder="请输入搜索内容" |
| | | class="flex1" |
| | | > |
| | | <el-option |
| | | v-for="item in [1, 2]" |
| | | :key="item" |
| | | :label="item" |
| | | :value="item" |
| | | > |
| | | </el-option> |
| | | </el-select> |
| | | <div class="btn SHSR">搜索</div> |
| | | @keyup.enter.native="handleSearch" |
| | | /> |
| | | <div @click="handleSearch" class="btn SHSR">搜索</div> |
| | | </div> |
| | | </div> |
| | | <!-- 表格 --> |
| | | <CustomTable |
| | | :data="[{ projectName: '项目777' }, { projectName: '项目2' }]" |
| | | :data="tableData" |
| | | v-loading="loading" |
| | | height="800" |
| | | style="border: 2px solid #3d7fff" |
| | | > |
| | | <el-table-column label="序号"> |
| | | <template #default="{ row, $index }"> |
| | | {{ $index + 1 }} |
| | | <el-table-column label="序号" width="80"> |
| | | <template #default="{ $index }"> |
| | | {{ (currentPage - 1) * pageSize + $index + 1 }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="更新时间" prop="projectName" /> |
| | | <el-table-column label="项目详情" prop="projectName" /> |
| | | <el-table-column label="形象进度" prop="projectName" /> |
| | | <el-table-column label="危大工程" prop="projectName" /> |
| | | <el-table-column label="超危大工程" prop="projectName" /> |
| | | <el-table-column label="近一季度施工进展情况" prop="projectName" /> |
| | | <el-table-column label="操作"> |
| | | <el-table-column label="更新时间" prop="updateTime" width="180" /> |
| | | <el-table-column label="项目详情" prop="detail" show-overflow-tooltip /> |
| | | <el-table-column label="形象进度" prop="progress" width="150" /> |
| | | <el-table-column label="危大工程" width="150"> |
| | | <template #default="{ row }"> |
| | | <el-button |
| | | @click="detailVisible = true" |
| | | type="text" |
| | | class="btnColor" |
| | | {{ formatRiskData(row.dangerousOptions, "dangerous") }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="超危大工程" width="150"> |
| | | <template #default="{ row }"> |
| | | {{ formatRiskData(row.superDangerousOptions, "superDangerous") }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="风险源" width="150"> |
| | | <template #default="{ row }"> |
| | | {{ formatRiskData(row.hazardSource, "hazardSource") }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | | label="近一季度施工进展情况" |
| | | prop="progressThisSeason" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column label="操作" width="100" fixed="right"> |
| | | <template #default="{ row }"> |
| | | <el-button @click="showDetail(row)" type="text" class="btnColor" |
| | | >详情</el-button |
| | | > |
| | | </template> |
| | |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" |
| | | :current-page="currentPage" |
| | | :page-sizes="[100, 200, 300, 400]" |
| | | :page-size="10" |
| | | :total="400" |
| | | :page-sizes="[10, 20, 50, 100]" |
| | | :page-size="pageSize" |
| | | :total="total" |
| | | /> |
| | | </div> |
| | | <!-- 详情弹窗 --> |
| | | <CustomDialog title="项目详情" :visible.sync="detailVisible" width="1420px"> |
| | | <div class="oa" style="height: 700px"> |
| | | <div class="oa" style="height: 700px" v-if="detailData"> |
| | | <div class="mt--30"> |
| | | <div class="flex1"> |
| | | <div class="SHSR fs--16 lh--16 mb--17 color1">项目详情:</div> |
| | | <div class="lh--60 px--19 c-fff SHSBold fs--18 w100 bgcolor8"> |
| | | 计划名称计划名称计划名称 |
| | | {{ detailData.detail || "暂无数据" }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | <div class="flex1"> |
| | | <div class="SHSR fs--16 lh--16 mb--17 color1">形象进度:</div> |
| | | <div class="lh--60 px--19 c-fff SHSBold fs--18 w100 bgcolor8"> |
| | | 计划名称计划名称计划名称 |
| | | {{ detailData.progress || "暂无数据" }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | <div class="flex1"> |
| | | <div class="SHSR fs--16 lh--16 mb--17 color1">危大工程:</div> |
| | | <div class="flex a-center oa gap--14 flex-warp"> |
| | | <div v-for="item in 10" :key="item" class="tagItem">111</div> |
| | | <template v-if="parseRiskArray(detailData.dangerousOptions, 'dangerous').length > 0"> |
| | | <div |
| | | v-for="(item, index) in parseRiskArray(detailData.dangerousOptions, 'dangerous')" |
| | | :key="index" |
| | | class="tagItem" |
| | | > |
| | | {{ item }} |
| | | </div> |
| | | </template> |
| | | <div v-else class="c-fff fs--14 SHSR">暂无数据</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | <div class="flex1"> |
| | | <div class="SHSR fs--16 lh--16 mb--17 color1">超危大工程:</div> |
| | | <div class="flex a-center oa gap--14 flex-warp"> |
| | | <div v-for="item in 10" :key="item" class="tagItem">111</div> |
| | | <template v-if="parseRiskArray(detailData.superDangerousOptions, 'superDangerous').length > 0"> |
| | | <div |
| | | v-for="(item, index) in parseRiskArray(detailData.superDangerousOptions, 'superDangerous')" |
| | | :key="index" |
| | | class="tagItem" |
| | | > |
| | | {{ item }} |
| | | </div> |
| | | </template> |
| | | <div v-else class="c-fff fs--14 SHSR">暂无数据</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="mt--30"> |
| | | <div class="flex1"> |
| | | <div class="SHSR fs--16 lh--16 mb--17 color1">风险源:</div> |
| | | <div class="flex a-center oa gap--14 flex-warp"> |
| | | <template v-if="parseRiskArray(detailData.hazardSource, 'hazardSource').length > 0"> |
| | | <div |
| | | v-for="(item, index) in parseRiskArray(detailData.hazardSource, 'hazardSource')" |
| | | :key="index" |
| | | class="tagItem" |
| | | > |
| | | {{ item }} |
| | | </div> |
| | | </template> |
| | | <div v-else class="c-fff fs--14 SHSR">暂无数据</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | 近一季度施工进展情况: |
| | | </div> |
| | | <div class="lh--60 px--19 c-fff SHSBold fs--18 w100 bgcolor8"> |
| | | 计划名称计划名称计划名称 |
| | | {{ detailData.progressThisSeason || "暂无数据" }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | <div class="flex1"> |
| | | <div class="SHSR fs--16 lh--16 mb--17 color1">更新时间:</div> |
| | | <div class="lh--60 px--19 c-fff SHSBold fs--18 w100 bgcolor8"> |
| | | 2020-12-12 |
| | | {{ detailData.updateTime || "暂无数据" }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div v-else class="flex a-center j-center" style="height: 700px"> |
| | | <div class="c-fff fs--16 SHSR">暂无数据</div> |
| | | </div> |
| | | </CustomDialog> |
| | | </div> |
| | |
| | | <script> |
| | | import HeaderBox from "../header/index.vue"; |
| | | import moment from "moment"; |
| | | import { |
| | | getProjectDangerousSourceList, |
| | | getProjectDangerousSourceDetail, |
| | | } from "./service"; |
| | | import { getRiskSourceName } from "@/utils/riskSourceMap.js"; |
| | | |
| | | export default { |
| | | components: { HeaderBox }, |
| | | props: {}, |
| | | data() { |
| | | return { |
| | | dateTime: null, |
| | | startTime: null, // 开始时间 |
| | | endTime: null, // 结束时间 |
| | | startTimeTxt: "", // 开始时间显示文本 |
| | | endTimeTxt: "", // 结束时间显示文本 |
| | | projectId: null, |
| | | projectName: null, |
| | | dateTxt: "", |
| | | searchContent: "", // 搜索内容 |
| | | currentPage: 1, |
| | | pageSize: 10, |
| | | total: 0, |
| | | tableData: [], // 表格数据 |
| | | loading: false, // 加载状态 |
| | | detailVisible: false, |
| | | detailData: null, // 详情数据 |
| | | currentDetailId: null, // 当前查看详情的ID |
| | | }; |
| | | }, |
| | | computed: {}, |
| | | watch: { |
| | | dateTime: { |
| | | handler(newVal, oldVal) { |
| | | startTime: { |
| | | handler(newVal) { |
| | | if (newVal) { |
| | | this.dateTxt = moment(newVal).format("YYYY年MM月DD日 HH:mm:ss"); |
| | | this.startTimeTxt = moment(newVal).format("YYYY年MM月DD日 HH:mm:ss"); |
| | | } else { |
| | | this.startTimeTxt = ""; |
| | | } |
| | | }, |
| | | immediate: true, |
| | | }, |
| | | endTime: { |
| | | handler(newVal) { |
| | | if (newVal) { |
| | | this.endTimeTxt = moment(newVal).format("YYYY年MM月DD日 HH:mm:ss"); |
| | | } else { |
| | | this.endTimeTxt = ""; |
| | | } |
| | | }, |
| | | immediate: true, |
| | |
| | | this.projectId = this.$route.query.projectId; |
| | | this.projectName = this.$route.query.projectName; |
| | | }, |
| | | mounted() {}, |
| | | mounted() { |
| | | // 页面加载时获取列表数据 |
| | | this.getList(); |
| | | }, |
| | | methods: { |
| | | // 获取列表数据 |
| | | async getList() { |
| | | try { |
| | | this.loading = true; |
| | | const params = { |
| | | pageNum: this.currentPage, |
| | | pageSize: this.pageSize, |
| | | projectId: this.projectId, |
| | | }; |
| | | |
| | | // 添加可选参数 |
| | | if (this.startTime) { |
| | | params.startTime = moment(this.startTime).format( |
| | | "YYYY-MM-DD HH:mm:ss" |
| | | ); |
| | | } |
| | | if (this.endTime) { |
| | | params.endTime = moment(this.endTime).format("YYYY-MM-DD HH:mm:ss"); |
| | | } |
| | | if (this.searchContent) { |
| | | params.content = this.searchContent; |
| | | } |
| | | |
| | | const res = await getProjectDangerousSourceList(params); |
| | | if (res) { |
| | | this.tableData = (res && res.records) || (res && res.list) || []; |
| | | this.total = (res && res.total) || 0; |
| | | } |
| | | } catch (error) { |
| | | console.error("获取重大风险源列表失败:", error); |
| | | this.$message.error("获取列表数据失败"); |
| | | } finally { |
| | | this.loading = false; |
| | | } |
| | | }, |
| | | |
| | | // 格式化风险数据(用于表格显示) |
| | | formatRiskData(dataStr, type) { |
| | | if (!dataStr) return "-"; |
| | | try { |
| | | const dataArray = JSON.parse(dataStr); |
| | | if (!Array.isArray(dataArray) || dataArray.length === 0) return "-"; |
| | | |
| | | // 转换为中文名称并用顿号连接 |
| | | const names = dataArray.map(code => getRiskSourceName(type, code)); |
| | | return names.join("、"); |
| | | } catch (e) { |
| | | console.error("解析风险数据失败:", e); |
| | | return "-"; |
| | | } |
| | | }, |
| | | |
| | | // 解析风险数组(用于详情弹窗标签展示) |
| | | parseRiskArray(dataStr, type) { |
| | | if (!dataStr) return []; |
| | | try { |
| | | const dataArray = JSON.parse(dataStr); |
| | | if (!Array.isArray(dataArray)) return []; |
| | | |
| | | // 转换为中文名称数组 |
| | | return dataArray.map(code => getRiskSourceName(type, code)); |
| | | } catch (e) { |
| | | console.error("解析风险数据失败:", e); |
| | | return []; |
| | | } |
| | | }, |
| | | |
| | | // 搜索 |
| | | handleSearch() { |
| | | this.currentPage = 1; // 重置到第一页 |
| | | this.getList(); |
| | | }, |
| | | |
| | | // 每页条数改变 |
| | | handleSizeChange(val) { |
| | | console.log(`每页 ${val} 条`); |
| | | this.pageSize = val; |
| | | this.currentPage = 1; |
| | | this.getList(); |
| | | }, |
| | | |
| | | // 当前页改变 |
| | | handleCurrentChange(val) { |
| | | console.log(`当前页: ${val}`); |
| | | this.currentPage = val; |
| | | this.getList(); |
| | | }, |
| | | |
| | | // 点击日期选择器 |
| | | handleClick(type) { |
| | | this.$refs[`datetime${type}`].focus(); |
| | | }, |
| | | |
| | | // 查看详情 |
| | | async showDetail(row) { |
| | | try { |
| | | this.currentDetailId = row.id; |
| | | const res = await getProjectDangerousSourceDetail(row.id); |
| | | if (res) { |
| | | this.detailData = res; |
| | | this.detailVisible = true; |
| | | } |
| | | } catch (error) { |
| | | console.error("获取详情失败:", error); |
| | | this.$message.error("获取详情数据失败"); |
| | | } |
| | | }, |
| | | |
| | | // 返回 |
| | | backFun() { |
| | | this.$router.go(-1); |
| | | }, |
| | |
| | | border: 1px solid #307ad9; |
| | | box-sizing: border-box; |
| | | cursor: pointer; |
| | | |
| | | &:hover { |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | } |
| | | |
| New file |
| | |
| | | import request from '@/utils/request' |
| | | |
| | | // 获取项目重大风险源列表 |
| | | export const getProjectDangerousSourceList = async (data) => { |
| | | return request(`/project/getProjectDangerousSourceList`, { |
| | | method: 'post', data |
| | | }) |
| | | } |
| | | // 获取项目重大风险源详情 |
| | | export const getProjectDangerousSourceDetail = async (id) => { |
| | | return request(`/project/getProjectDangerousSourceDetail/${id}`, { |
| | | method: 'get' |
| | | }) |
| | | } |
| | |
| | | > |
| | | <el-select |
| | | filterable |
| | | v-model="projectId" |
| | | v-model="planId" |
| | | placeholder="请选择检查计划" |
| | | class="flex1" |
| | | clearable |
| | | @change="handleSearch" |
| | | > |
| | | <el-option |
| | | v-for="item in [1, 2]" |
| | | :key="item" |
| | | :label="item" |
| | | :value="item" |
| | | v-for="item in planList" |
| | | :key="item.id" |
| | | :label="item.name" |
| | | :value="item.id" |
| | | > |
| | | </el-option> |
| | | </el-select> |
| | |
| | | > |
| | | <el-select |
| | | filterable |
| | | v-model="projectId" |
| | | v-model="positionId" |
| | | placeholder="请选择岗位" |
| | | class="flex1" |
| | | clearable |
| | | @change="handleSearch" |
| | | > |
| | | <el-option |
| | | v-for="item in [1, 2]" |
| | | :key="item" |
| | | :label="item" |
| | | :value="item" |
| | | v-for="item in positionList" |
| | | :key="item.id" |
| | | :label="item.name" |
| | | :value="item.id" |
| | | > |
| | | </el-option> |
| | | </el-select> |
| | |
| | | class="flex a-center j-between px--20 w--300 h--40 relative bgcolor1 picker" |
| | | > |
| | | <el-date-picker |
| | | v-model="dateTime" |
| | | v-model="startTime" |
| | | ref="datetime1" |
| | | type="datetime" |
| | | placeholder="" |
| | | @change="handleSearch" |
| | | > |
| | | </el-date-picker> |
| | | <div |
| | | class="absolute w100 h100 flex a-center c-fff fs--14 SHS" |
| | | style="width: calc(100% - 20px)" |
| | | v-if="dateTxt" |
| | | v-if="startTimeTxt" |
| | | > |
| | | {{ dateTxt }} |
| | | {{ startTimeTxt }} |
| | | </div> |
| | | <div |
| | | v-else |
| | | class="absolute w100 h100 flex a-center c-fff fs--14 SHSR" |
| | | > |
| | | 请选择日期 |
| | | 请选择开始时间 |
| | | </div> |
| | | <img |
| | | src="../../assets/img/home/Shape@2x (6).png" |
| | |
| | | class="flex a-center j-between px--20 w--300 h--40 relative bgcolor1 picker" |
| | | > |
| | | <el-date-picker |
| | | v-model="dateTime" |
| | | v-model="endTime" |
| | | ref="datetime2" |
| | | type="datetime" |
| | | placeholder="" |
| | | @change="handleSearch" |
| | | > |
| | | </el-date-picker> |
| | | <div |
| | | class="absolute w100 h100 flex a-center c-fff fs--14 SHS" |
| | | style="width: calc(100% - 20px)" |
| | | v-if="dateTxt" |
| | | v-if="endTimeTxt" |
| | | > |
| | | {{ dateTxt }} |
| | | {{ endTimeTxt }} |
| | | </div> |
| | | <div |
| | | v-else |
| | | class="absolute w100 h100 flex a-center c-fff fs--14 SHSR" |
| | | > |
| | | 请选择日期 |
| | | 请选择结束时间 |
| | | </div> |
| | | <img |
| | | src="../../assets/img/home/Shape@2x (6).png" |
| | |
| | | <div |
| | | class="flex a-center j-between w--300 pl--20 h--40 relative bgcolor1 searchBox" |
| | | > |
| | | <el-select |
| | | filterable |
| | | v-model="projectId" |
| | | <el-input |
| | | v-model="searchText" |
| | | placeholder="请输入搜索内容" |
| | | class="flex1" |
| | | clearable |
| | | @keyup.enter.native="handleSearch" |
| | | > |
| | | <el-option |
| | | v-for="item in [1, 2]" |
| | | :key="item" |
| | | :label="item" |
| | | :value="item" |
| | | > |
| | | </el-option> |
| | | </el-select> |
| | | <div class="btn SHSR">搜索</div> |
| | | </el-input> |
| | | <div class="btn SHSR" @click="handleSearch">搜索</div> |
| | | </div> |
| | | </div> |
| | | <!-- 表格 --> |
| | | <CustomTable |
| | | :data="[ |
| | | { projectName: '项目777' }, |
| | | { projectName: '项目2' }, |
| | | { projectName: '项目4' }, |
| | | ]" |
| | | :data="tableData" |
| | | height="800" |
| | | style="border: 2px solid #3d7fff" |
| | | v-loading="loading" |
| | | > |
| | | <el-table-column label="计划名称" prop="projectName" /> |
| | | <el-table-column label="检查内容" prop="projectName" /> |
| | | <el-table-column label="岗位" prop="projectName" /> |
| | | <el-table-column label="问题备注" prop="projectName" /> |
| | | <el-table-column label="图片" prop="projectName"> |
| | | <template #default="{ row }" |
| | | ><div |
| | | <el-table-column label="计划名称" prop="planName" min-width="120" /> |
| | | <el-table-column label="检查内容" prop="checkContent" min-width="150" show-overflow-tooltip /> |
| | | <el-table-column label="岗位" prop="postName" min-width="100" /> |
| | | <el-table-column label="问题备注" prop="remark" min-width="150" show-overflow-tooltip /> |
| | | <el-table-column label="图片" min-width="80"> |
| | | <template #default="{ row }"> |
| | | <div |
| | | class="btnColor cursor-pointer" |
| | | :class="false && 'disableColor'" |
| | | @click="previewVisible = true" |
| | | :class="!row.img && 'disableColor'" |
| | | @click="row.img && previewImage(row)" |
| | | > |
| | | 1张 |
| | | {{ getImageCount(row.img) }}张 |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="检查时间" prop="projectName" /> |
| | | <el-table-column label="在岗情况" prop="projectName"> |
| | | <template #default="{ row, $index }"> |
| | | <el-table-column label="检查时间" prop="time" min-width="160" /> |
| | | <el-table-column label="在岗情况" min-width="120"> |
| | | <template #default="{ row }"> |
| | | <div class="flex a-center j-center"> |
| | | <div class="ripple"> |
| | | <div |
| | | class="ripple-wave wave-1" |
| | | :class="['bgColor33', 'bgColor66'][$index + 1]" |
| | | :class="stateMap[row.state] && stateMap[row.state].colorClass[0]" |
| | | ></div> |
| | | <div |
| | | class="ripple-wave wave-2" |
| | | :class="['bgColor44', 'bgColor77'][$index + 1]" |
| | | :class="stateMap[row.state] && stateMap[row.state].colorClass[1]" |
| | | ></div> |
| | | <div |
| | | class="ripple-wave wave-3" |
| | | :class="['bgColor55', 'bgColor88'][$index + 1]" |
| | | :class="stateMap[row.state] && stateMap[row.state].colorClass[2]" |
| | | ></div> |
| | | </div> |
| | | <div class="ml--6 SHSR">{{ $index }}</div> |
| | | <div class="ml--6 SHSR">{{ stateMap[row.state] ? stateMap[row.state].text : '-' }}</div> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作"> |
| | | <el-table-column label="操作" width="100"> |
| | | <template #default="{ row }"> |
| | | <el-button |
| | | @click="detailVisible = true" |
| | | @click="showDetail(row)" |
| | | type="text" |
| | | class="btnColor" |
| | | >详情</el-button |
| | |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" |
| | | :current-page="currentPage" |
| | | :page-sizes="[100, 200, 300, 400]" |
| | | :page-size="10" |
| | | :total="400" |
| | | :page-sizes="[10, 20, 50, 100]" |
| | | :page-size="pageSize" |
| | | :total="total" |
| | | /> |
| | | </div> |
| | | <!-- 详情弹窗 --> |
| | | <CustomDialog title="项目详情" :visible.sync="detailVisible" width="1420px"> |
| | | <div class="oa" style="height: 700px"> |
| | | <CustomDialog title="人员在岗详情" :visible.sync="detailVisible" width="1420px"> |
| | | <div class="oa" style="height: 700px" v-loading="detailLoading"> |
| | | <div class="flex j-between gap--30 mt--30"> |
| | | <div class="flex1"> |
| | | <div class="SHSR fs--16 lh--16 mb--17 color1">计划名称:</div> |
| | | <div class="lh--60 px--19 c-fff SHSBold fs--18 w100 bgcolor8"> |
| | | 计划名称计划名称计划名称 |
| | | {{ detailData.planName || '-' }} |
| | | </div> |
| | | </div> |
| | | <div class="flex1"> |
| | | <div class="SHSR fs--16 lh--16 mb--17 color1">项目名称:</div> |
| | | <div class="lh--60 px--19 c-fff SHSBold fs--18 w100 bgcolor8"> |
| | | 计划名称计划名称计划名称 |
| | | {{ projectName || '-' }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | <div class="flex1"> |
| | | <div class="SHSR fs--16 lh--16 mb--17 color1">检查内容:</div> |
| | | <div class="lh--60 px--19 c-fff SHSBold fs--18 w100 bgcolor8"> |
| | | 计划名称计划名称计划名称 |
| | | {{ detailData.checkContent || '-' }} |
| | | </div> |
| | | </div> |
| | | <div class="flex1"> |
| | | <div class="SHSR fs--16 lh--16 mb--17 color1">岗位:</div> |
| | | <div class="lh--60 px--19 c-fff SHSBold fs--18 w100 bgcolor8"> |
| | | 计划名称计划名称计划名称 |
| | | {{ detailData.postName || '-' }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | <div class="flex1"> |
| | | <div class="SHSR fs--16 lh--16 mb--17 color1">问题备注:</div> |
| | | <div class="lh--60 px--19 c-fff SHSBold fs--18 w100 bgcolor8"> |
| | | 计划名称计划名称计划名称 |
| | | {{ detailData.remark || '-' }} |
| | | </div> |
| | | </div> |
| | | <div class="flex1"> |
| | | <div class="SHSR fs--16 lh--16 mb--17 color1">在岗情况:</div> |
| | | <div class="lh--60 px--19 c-fff SHSBold fs--18 w100 bgcolor8"> |
| | | 计划名称计划名称计划名称 |
| | | <div class="lh--60 px--19 c-fff SHSBold fs--18 w100 bgcolor8 flex a-center"> |
| | | <div class="ripple mr--10" v-if="detailData.state"> |
| | | <div |
| | | class="ripple-wave wave-1" |
| | | :class="stateMap[detailData.state] && stateMap[detailData.state].colorClass[0]" |
| | | ></div> |
| | | <div |
| | | class="ripple-wave wave-2" |
| | | :class="stateMap[detailData.state] && stateMap[detailData.state].colorClass[1]" |
| | | ></div> |
| | | <div |
| | | class="ripple-wave wave-3" |
| | | :class="stateMap[detailData.state] && stateMap[detailData.state].colorClass[2]" |
| | | ></div> |
| | | </div> |
| | | {{ stateMap[detailData.state] ? stateMap[detailData.state].text : '-' }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | <div class="flex1"> |
| | | <div class="SHSR fs--16 lh--16 mb--17 color1">检查时间:</div> |
| | | <div class="lh--60 px--19 c-fff SHSBold fs--18 w100 bgcolor8"> |
| | | 2020-12-12 |
| | | {{ detailData.time || '-' }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | <div class="SHSR fs--16 lh--16 mb--17 color1">图片:</div> |
| | | <div class="flex a-center oa gap--14"> |
| | | <img |
| | | v-for="item in 6" |
| | | :key="item" |
| | | src="../../assets/img/home/@3x@2x.png" |
| | | class="w--150 h--120" |
| | | v-for="(item, index) in detailData.img ? detailData.img.split(',').filter(i => i) : []" |
| | | :key="index" |
| | | :src="item" |
| | | class="w--150 h--120 cursor-pointer" |
| | | style="object-fit: cover; border-radius: 4px;" |
| | | @click="previewImage(detailData)" |
| | | /> |
| | | <div v-if="!detailData.img || !detailData.img.split(',').filter(i => i).length" class="c-fff SHSR">暂无图片</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | <!-- 图片预览 --> |
| | | <CustomPreview |
| | | :show="previewVisible" |
| | | :imgArr="[]" |
| | | :imgArr="previewImages" |
| | | @close="previewVisible = false" |
| | | /> |
| | | </div> |
| | |
| | | <script> |
| | | import HeaderBox from "../header/index.vue"; |
| | | import moment from "moment"; |
| | | import { getPositionList, getPlanList, getProjectOnDutyList, getProjectOnDutyDetail } from "./service"; |
| | | |
| | | export default { |
| | | components: { HeaderBox }, |
| | | props: {}, |
| | | data() { |
| | | return { |
| | | dateTime: null, |
| | | startTime: null, |
| | | endTime: null, |
| | | projectId: null, |
| | | projectName: null, |
| | | dateTxt: "", |
| | | startTimeTxt: "", |
| | | endTimeTxt: "", |
| | | currentPage: 1, |
| | | pageSize: 10, |
| | | total: 0, |
| | | detailVisible: false, |
| | | previewVisible: false, |
| | | // 下拉框数据 |
| | | planList: [], // 计划列表 |
| | | positionList: [], // 岗位列表 |
| | | planId: null, // 选中的计划ID |
| | | positionId: null, // 选中的岗位ID |
| | | searchText: "", // 搜索内容 |
| | | // 表格数据 |
| | | tableData: [], |
| | | loading: false, |
| | | // 详情数据 |
| | | detailData: {}, |
| | | detailLoading: false, |
| | | // 图片预览数据 |
| | | previewImages: [], |
| | | }; |
| | | }, |
| | | computed: {}, |
| | | computed: { |
| | | // 在岗情况映射 |
| | | stateMap() { |
| | | return { |
| | | 1: { text: "在岗", colorClass: ["bgColor33", "bgColor44", "bgColor55"] }, |
| | | 2: { text: "未在岗", colorClass: ["wave-1", "wave-2", "wave-3"] }, |
| | | 3: { text: "请假", colorClass: ["bgColor66", "bgColor77", "bgColor88"] }, |
| | | }; |
| | | }, |
| | | }, |
| | | watch: { |
| | | dateTime: { |
| | | handler(newVal, oldVal) { |
| | | startTime: { |
| | | handler(newVal) { |
| | | if (newVal) { |
| | | this.dateTxt = moment(newVal).format("YYYY年MM月DD日 HH:mm:ss"); |
| | | this.startTimeTxt = moment(newVal).format("YYYY年MM月DD日 HH:mm:ss"); |
| | | } else { |
| | | this.startTimeTxt = ""; |
| | | } |
| | | }, |
| | | immediate: true, |
| | | }, |
| | | endTime: { |
| | | handler(newVal) { |
| | | if (newVal) { |
| | | this.endTimeTxt = moment(newVal).format("YYYY年MM月DD日 HH:mm:ss"); |
| | | } else { |
| | | this.endTimeTxt = ""; |
| | | } |
| | | }, |
| | | immediate: true, |
| | |
| | | this.projectId = this.$route.query.projectId; |
| | | this.projectName = this.$route.query.projectName; |
| | | }, |
| | | mounted() {}, |
| | | mounted() { |
| | | this.initData(); |
| | | }, |
| | | methods: { |
| | | // 初始化数据 |
| | | async initData() { |
| | | await this.getPlanListData(); |
| | | await this.getPositionListData(); |
| | | await this.getTableData(); |
| | | }, |
| | | |
| | | // 获取计划下拉框数据 |
| | | async getPlanListData() { |
| | | try { |
| | | const res = await getPlanList(); |
| | | if (res) { |
| | | this.planList = res || []; |
| | | } |
| | | } catch (error) { |
| | | console.error("获取计划列表失败:", error); |
| | | } |
| | | }, |
| | | |
| | | // 获取岗位下拉框数据 |
| | | async getPositionListData() { |
| | | try { |
| | | const res = await getPositionList(); |
| | | if (res) { |
| | | this.positionList = res || []; |
| | | } |
| | | } catch (error) { |
| | | console.error("获取岗位列表失败:", error); |
| | | } |
| | | }, |
| | | |
| | | // 获取表格数据 |
| | | async getTableData() { |
| | | this.loading = true; |
| | | try { |
| | | const params = { |
| | | pageNum: this.currentPage, |
| | | pageSize: this.pageSize, |
| | | projectId: this.projectId, |
| | | }; |
| | | |
| | | // 添加可选参数 |
| | | if (this.planId) params.planId = this.planId; |
| | | if (this.positionId) params.positionId = this.positionId; |
| | | if (this.startTime) { |
| | | params.startTime = moment(this.startTime).format( |
| | | "YYYY-MM-DD HH:mm:ss" |
| | | ); |
| | | } |
| | | if (this.endTime) { |
| | | params.endTime = moment(this.endTime).format("YYYY-MM-DD HH:mm:ss"); |
| | | } |
| | | if (this.searchText) params.remark = this.searchText; |
| | | |
| | | const res = await getProjectOnDutyList(params); |
| | | if (res) { |
| | | this.tableData = res.records || res.list || []; |
| | | this.total = res.total || 0; |
| | | } |
| | | } catch (error) { |
| | | console.error("获取列表数据失败:", error); |
| | | this.$message.error("获取列表数据失败"); |
| | | } finally { |
| | | this.loading = false; |
| | | } |
| | | }, |
| | | |
| | | // 搜索 |
| | | handleSearch() { |
| | | this.currentPage = 1; |
| | | this.getTableData(); |
| | | }, |
| | | |
| | | // 分页大小改变 |
| | | handleSizeChange(val) { |
| | | console.log(`每页 ${val} 条`); |
| | | this.pageSize = val; |
| | | this.currentPage = 1; |
| | | this.getTableData(); |
| | | }, |
| | | |
| | | // 当前页改变 |
| | | handleCurrentChange(val) { |
| | | console.log(`当前页: ${val}`); |
| | | this.currentPage = val; |
| | | this.getTableData(); |
| | | }, |
| | | |
| | | // 点击日期选择器 |
| | | handleClick(type) { |
| | | this.$refs[`datetime${type}`].focus(); |
| | | }, |
| | | |
| | | // 查看详情 |
| | | async showDetail(row) { |
| | | if (!row.id) { |
| | | this.$message.warning("数据异常,无法查看详情"); |
| | | return; |
| | | } |
| | | |
| | | this.detailVisible = true; |
| | | this.detailLoading = true; |
| | | |
| | | try { |
| | | const res = await getProjectOnDutyDetail(row.id); |
| | | if (res) { |
| | | this.detailData = res; |
| | | } else { |
| | | this.$message.error("获取详情失败"); |
| | | } |
| | | } catch (error) { |
| | | console.error("获取详情失败:", error); |
| | | this.$message.error("获取详情失败"); |
| | | } finally { |
| | | this.detailLoading = false; |
| | | } |
| | | }, |
| | | |
| | | // 预览图片 |
| | | previewImage(row) { |
| | | if (row.img) { |
| | | // 如果img是字符串,可能是逗号分隔的多张图片 |
| | | this.previewImages = row.img.split(",").filter((item) => item); |
| | | this.previewVisible = true; |
| | | } else { |
| | | this.$message.warning("暂无图片"); |
| | | } |
| | | }, |
| | | |
| | | // 获取图片数量 |
| | | getImageCount(img) { |
| | | if (!img) return 0; |
| | | return img.split(",").filter((item) => item).length; |
| | | }, |
| | | |
| | | // 返回 |
| | | backFun() { |
| | | this.$router.go(-1); |
| | | }, |
| | |
| | | } |
| | | } |
| | | |
| | | .disableColor { |
| | | color: #666 !important; |
| | | cursor: not-allowed !important; |
| | | } |
| | | |
| | | .btnColor { |
| | | color: #00ebfc; |
| | | } |
| New file |
| | |
| | | import request from '@/utils/request' |
| | | |
| | | // 获取岗位下拉框信息 |
| | | export const getPositionList = async (id) => { |
| | | return request(`/project/getPositionList`, { |
| | | method: 'get' |
| | | }) |
| | | } |
| | | // 获取计划下拉框信息 |
| | | export const getPlanList = async (id) => { |
| | | return request(`/project/getPlanList`, { |
| | | method: 'get' |
| | | }) |
| | | } |
| | | // 获取人员在岗列表 |
| | | export const getProjectOnDutyList = async (data) => { |
| | | return request(`/project/getProjectOnDutyList`, { |
| | | method: 'post', data |
| | | }) |
| | | } |
| | | // 获取人员在岗详情 |
| | | export const getProjectOnDutyDetail = async (id) => { |
| | | return request(`/project/getProjectOnDutyDetail/${id}`, { |
| | | method: 'get' |
| | | }) |
| | | } |
| New file |
| | |
| | | 1、计划下拉框信息 是get 无传参 响应:name 名称; id |
| | | 2、获取检查列表 post json传参 |
| | | 请求参数:pageNum 分页参数,当前页码;pageSize 分页参数,每页数量,默认为10;projectId 项目id |
| | | 响应参数: checkTime 检查时间 string |
| | | commentType 1模糊评价 2打分评价 integer |
| | | containDeviceRes 设备报告 1有 0无 integer |
| | | containSystemRes 安全报告 1有 0无 integer |
| | | fuzzyScore 模糊分数 string |
| | | id integer |
| | | planName 检查计划名称 string |
| | | planType 计划类型 integer |
| | | riskLevel 风险类型 integer |
| | | score 打分分数 string |
| | | 3、获取检查资料列表 get params传参 请求参数:planId planId |
| | | 响应参数: checkUserImg 检查人员照片 string |
| | | clientId integer(int32) |
| | | createTime string(date-time) |
| | | creatorId 创建人id integer(int32) |
| | | deleted 是否删除 false正常true删除 boolean |
| | | id integer(int32) |
| | | integrityNotification 廉政告知单 string |
| | | planId integer(int32) |
| | | planName 计划名称 string |
| | | projectId integer(int32) |
| | | projectName 项目名称 string |
| | | safetySlip 安全告知单 string |
| | | time 检查时间 string(date-time) |
| | | title 检查标题 string |
| | | 4、获取检查资料详情 get params传参 请求参数:id 检查资料id |
| | | 响应参数:checkUserImg 检查人员照片 string |
| | | clientId integer(int32) |
| | | createTime string(date-time) |
| | | creatorId 创建人id integer(int32) |
| | | deleted 是否删除 false正常true删除 boolean |
| | | id integer(int32) |
| | | integrityNotification 廉政告知单 string |
| | | planId integer(int32) |
| | | planName 计划名称 string |
| | | projectId integer(int32) |
| | | projectName 项目名称 string |
| | | safetySlip 安全告知单 string |
| | | time 检查时间 string(date-time) |
| | | title 检查标题 string |
| | | |
| | | |
| | |
| | | > |
| | | <el-select |
| | | filterable |
| | | v-model="projectId" |
| | | v-model="planType" |
| | | placeholder="请选择计划类型" |
| | | class="flex1" |
| | | clearable |
| | | > |
| | | <el-option |
| | | v-for="item in [1, 2]" |
| | | :key="item" |
| | | :label="item" |
| | | :value="item" |
| | | v-for="item in planOptions" |
| | | :key="item.id" |
| | | :label="item.name" |
| | | :value="item.id" |
| | | > |
| | | </el-option> |
| | | </el-select> |
| | |
| | | class="flex a-center j-between px--20 w--300 h--40 relative bgcolor1 picker" |
| | | > |
| | | <el-date-picker |
| | | v-model="dateTime" |
| | | v-model="startTime" |
| | | ref="datetime1" |
| | | type="datetime" |
| | | placeholder="" |
| | |
| | | <div |
| | | class="absolute w100 h100 flex a-center c-fff fs--14 SHS" |
| | | style="width: calc(100% - 20px)" |
| | | v-if="dateTxt" |
| | | v-if="startTimeTxt" |
| | | > |
| | | {{ dateTxt }} |
| | | {{ startTimeTxt }} |
| | | </div> |
| | | <div |
| | | v-else |
| | | class="absolute w100 h100 flex a-center c-fff fs--14 SHSR" |
| | | > |
| | | 请选择日期 |
| | | 请选择开始日期 |
| | | </div> |
| | | <img |
| | | src="../../assets/img/home/Shape@2x (6).png" |
| | |
| | | class="flex a-center j-between px--20 w--300 h--40 relative bgcolor1 picker" |
| | | > |
| | | <el-date-picker |
| | | v-model="dateTime" |
| | | v-model="endTime" |
| | | ref="datetime2" |
| | | type="datetime" |
| | | placeholder="" |
| | |
| | | <div |
| | | class="absolute w100 h100 flex a-center c-fff fs--14 SHS" |
| | | style="width: calc(100% - 20px)" |
| | | v-if="dateTxt" |
| | | v-if="endTimeTxt" |
| | | > |
| | | {{ dateTxt }} |
| | | {{ endTimeTxt }} |
| | | </div> |
| | | <div |
| | | v-else |
| | | class="absolute w100 h100 flex a-center c-fff fs--14 SHSR" |
| | | > |
| | | 请选择日期 |
| | | 请选择结束日期 |
| | | </div> |
| | | <img |
| | | src="../../assets/img/home/Shape@2x (6).png" |
| | |
| | | <div |
| | | class="flex a-center j-between w--300 pl--20 h--40 relative bgcolor1 searchBox" |
| | | > |
| | | <el-select |
| | | filterable |
| | | v-model="projectId" |
| | | <el-input |
| | | v-model="searchKeyword" |
| | | placeholder="请输入搜索内容" |
| | | class="flex1" |
| | | > |
| | | <el-option |
| | | v-for="item in [1, 2]" |
| | | :key="item" |
| | | :label="item" |
| | | :value="item" |
| | | > |
| | | </el-option> |
| | | </el-select> |
| | | <div class="btn SHSR">搜索</div> |
| | | clearable |
| | | @keyup.enter.native="handleSearch" |
| | | /> |
| | | <div @click="handleSearch" class="btn SHSR">搜索</div> |
| | | </div> |
| | | </div> |
| | | <!-- 表格 --> |
| | | <CustomTable |
| | | :data="[{ projectName: '项目777' }, { projectName: '项目2' }]" |
| | | :data="checkList" |
| | | height="800" |
| | | style="border: 2px solid #3d7fff" |
| | | v-loading="loading" |
| | | > |
| | | <el-table-column label="检查计划" prop="projectName" /> |
| | | <el-table-column label="计划类型" prop="projectName" /> |
| | | <el-table-column label="检查时间" prop="projectName" /> |
| | | <el-table-column label="本月检查风险" prop="projectName" /> |
| | | <el-table-column label="操作"> |
| | | <el-table-column label="检查计划" prop="planName" min-width="150" /> |
| | | <el-table-column label="计划类型" min-width="120"> |
| | | <template #default="{ row }"> |
| | | {{ formatPlanType(row.planType) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="检查时间" min-width="180"> |
| | | <template #default="{ row }"> |
| | | {{ formatTime(row.checkTime) }} |
| | | </template> |
| | | </el-table-column> |
| | | <!-- 以下列仅在非项目端(type != 2)时显示 --> |
| | | <el-table-column v-if="type != 2" label="风险等级" min-width="120"> |
| | | <template #default="{ row }"> |
| | | {{ formatRiskLevel(row.riskLevel) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column v-if="type != 2" label="评价方式" min-width="120"> |
| | | <template #default="{ row }"> |
| | | {{ formatCommentType(row.commentType) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column v-if="type != 2" label="评分" min-width="100"> |
| | | <template #default="{ row }"> |
| | | {{ getScoreDisplay(row) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="200" fixed="right"> |
| | | <template #default="{ row }"> |
| | | <el-button |
| | | @click="projectVisible = true" |
| | | @click="openCheckMaterialDialog(row)" |
| | | type="text" |
| | | class="btnColor" |
| | | >检查资料</el-button |
| | |
| | | class="h100 flex flex-column a-center j-between c-fff fs--16 SHSBold" |
| | | > |
| | | <div |
| | | @click="openReport('safe')" |
| | | @click="openReport('safe', row)" |
| | | class="py--12 w100 txt-center br--10 bgcolor6 cursor-pointer" |
| | | :class="{ disabled: row.containSystemRes !== 1 }" |
| | | > |
| | | 安全报告 |
| | | </div> |
| | | <div |
| | | @click="openReport('device')" |
| | | @click="openReport('device', row)" |
| | | class="py--12 w100 txt-center br--10 bgcolor7 cursor-pointer" |
| | | :class="{ disabled: row.containDeviceRes !== 1 }" |
| | | > |
| | | 设备报告 |
| | | </div> |
| | |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" |
| | | :current-page="currentPage" |
| | | :page-sizes="[100, 200, 300, 400]" |
| | | :page-size="10" |
| | | :total="400" |
| | | :page-sizes="[10, 20, 50, 100]" |
| | | :page-size="pageSize" |
| | | :total="total" |
| | | /> |
| | | </div> |
| | | <!-- 检查资料列表弹窗 --> |
| | | <CustomDialog title="项目" :visible.sync="projectVisible" width="1420px"> |
| | | <CustomDialog |
| | | title="检查资料列表" |
| | | :visible.sync="projectVisible" |
| | | width="1420px" |
| | | @close="closeProjectDialog" |
| | | > |
| | | <CustomTable |
| | | :data="[{ projectName: '项目777' }, { projectName: '项目2' }]" |
| | | :data="checkMaterialList" |
| | | height="630" |
| | | v-loading="loading" |
| | | > |
| | | <el-table-column label="检查标题" prop="projectName" /> |
| | | <el-table-column label="检查时间" prop="projectName" /> |
| | | <el-table-column label="安全告知单" prop="projectName" /> |
| | | <el-table-column label="检查人员照片" prop="projectName" /> |
| | | <el-table-column label="廉政告知单" prop="projectName" /> |
| | | <el-table-column label="操作"> |
| | | <el-table-column label="检查标题" prop="title" min-width="150" /> |
| | | <!-- 以下列仅在非项目端(type != 2)时显示 --> |
| | | <el-table-column v-if="type != 2" label="计划名称" prop="planName" min-width="150" /> |
| | | <el-table-column v-if="type != 2" label="项目名称" prop="projectName" min-width="150" /> |
| | | <el-table-column label="检查时间" min-width="180"> |
| | | <template #default="{ row }"> |
| | | {{ formatTime(row.time) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="安全告知单" min-width="100"> |
| | | <template #default="{ row }"> |
| | | {{ row.safetySlip ? "有" : "无" }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="检查人员照片" min-width="120"> |
| | | <template #default="{ row }"> |
| | | {{ row.checkUserImg ? "有" : "无" }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="廉政告知单" min-width="100"> |
| | | <template #default="{ row }"> |
| | | {{ row.integrityNotification ? "有" : "无" }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="100" fixed="right"> |
| | | <template #default="{ row }"> |
| | | <el-button |
| | | @click="detailVisible = true" |
| | | @click="openDetailDialog(row)" |
| | | type="text" |
| | | class="btnColor" |
| | | >详情</el-button |
| | |
| | | </CustomTable> |
| | | </CustomDialog> |
| | | <!-- 检查报告弹窗 --> |
| | | <CustomDialog title="检查报告" :visible.sync="reportVisible" width="1420px"> |
| | | <CustomDialog |
| | | title="检查报告" |
| | | :visible.sync="reportVisible" |
| | | width="1420px" |
| | | @close="closeReportDialog" |
| | | > |
| | | <div style="height: 691px" class="oa"> |
| | | <iframe |
| | | v-if="reportUrl" |
| | |
| | | height="100%" |
| | | frameborder="0" |
| | | ></iframe> |
| | | <div v-else class="flex a-center j-center h100 c-fff fs--16"> |
| | | 暂无报告数据 |
| | | </div> |
| | | </div> |
| | | </CustomDialog> |
| | | <!-- 检查资料详情弹窗 --> |
| | |
| | | title="检查资料详情" |
| | | :visible.sync="detailVisible" |
| | | width="1420px" |
| | | @close="closeDetailDialog" |
| | | > |
| | | <div class="oa" style="height: 700px"> |
| | | <div class="oa" style="height: 700px" v-loading="loading"> |
| | | <div class="flex j-between gap--30 mt--30"> |
| | | <div class="flex1"> |
| | | <div class="SHSR fs--16 lh--16 mb--17 color1">计划名称:</div> |
| | | <div class="lh--60 px--19 c-fff SHSBold fs--18 w100 bgcolor8"> |
| | | 计划名称计划名称计划名称 |
| | | {{ checkMaterialDetail.planName || "-" }} |
| | | </div> |
| | | </div> |
| | | <div class="flex1"> |
| | | <div class="SHSR fs--16 lh--16 mb--17 color1">项目名称:</div> |
| | | <div class="lh--60 px--19 c-fff SHSBold fs--18 w100 bgcolor8"> |
| | | 计划名称计划名称计划名称 |
| | | {{ checkMaterialDetail.projectName || "-" }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="flex j-between gap--30 mt--30"> |
| | | <div class="flex1"> |
| | | <div class="SHSR fs--16 lh--16 mb--17 color1">检测标题:</div> |
| | | <div class="SHSR fs--16 lh--16 mb--17 color1">检查标题:</div> |
| | | <div class="lh--60 px--19 c-fff SHSBold fs--18 w100 bgcolor8"> |
| | | 计划名称计划名称计划名称 |
| | | {{ checkMaterialDetail.title || "-" }} |
| | | </div> |
| | | </div> |
| | | <div class="flex1"> |
| | | <div class="SHSR fs--16 lh--16 mb--17 color1">检测时间:</div> |
| | | <div class="SHSR fs--16 lh--16 mb--17 color1">检查时间:</div> |
| | | <div class="lh--60 px--19 c-fff SHSBold fs--18 w100 bgcolor8"> |
| | | 计划名称计划名称计划名称 |
| | | {{ formatTime(checkMaterialDetail.time) }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="mt--30"> |
| | | <div class="flex1"> |
| | | <div class="SHSR fs--16 lh--16 mb--17 color1">安全告知单:</div> |
| | | <div class="flex a-center oa gap--14"> |
| | | <div |
| | | class="flex a-center oa gap--14" |
| | | v-if="parseImages(checkMaterialDetail.safetySlip).length > 0" |
| | | > |
| | | <img |
| | | v-for="item in 6" |
| | | :key="item" |
| | | src="../../assets/img/home/@3x@2x.png" |
| | | class="w--150 h--120" |
| | | v-for="(item, index) in parseImages( |
| | | checkMaterialDetail.safetySlip |
| | | )" |
| | | :key="index" |
| | | :src="item" |
| | | class="w--150 h--120 cursor-pointer" |
| | | @click="previewImage(item)" |
| | | /> |
| | | </div> |
| | | <div v-else class="c-fff fs--14 SHSR">暂无图片</div> |
| | | </div> |
| | | </div> |
| | | <div class="mt--30"> |
| | | <div class="flex1"> |
| | | <div class="SHSR fs--16 lh--16 mb--17 color1">检查人员照片:</div> |
| | | <div class="flex a-center oa gap--14"> |
| | | <div |
| | | class="flex a-center oa gap--14" |
| | | v-if="parseImages(checkMaterialDetail.checkUserImg).length > 0" |
| | | > |
| | | <img |
| | | v-for="item in 6" |
| | | :key="item" |
| | | src="../../assets/img/home/@3x@2x.png" |
| | | class="w--150 h--120" |
| | | v-for="(item, index) in parseImages( |
| | | checkMaterialDetail.checkUserImg |
| | | )" |
| | | :key="index" |
| | | :src="item" |
| | | class="w--150 h--120 cursor-pointer" |
| | | @click="previewImage(item)" |
| | | /> |
| | | </div> |
| | | <div v-else class="c-fff fs--14 SHSR">暂无图片</div> |
| | | </div> |
| | | </div> |
| | | <div class="mt--30"> |
| | | <div class="flex1"> |
| | | <div class="SHSR fs--16 lh--16 mb--17 color1">廉政告知单:</div> |
| | | <div class="flex a-center oa gap--14"> |
| | | <div |
| | | class="flex a-center oa gap--14" |
| | | v-if=" |
| | | parseImages(checkMaterialDetail.integrityNotification).length > |
| | | 0 |
| | | " |
| | | > |
| | | <img |
| | | v-for="item in 6" |
| | | :key="item" |
| | | src="../../assets/img/home/@3x@2x.png" |
| | | class="w--150 h--120" |
| | | v-for="(item, index) in parseImages( |
| | | checkMaterialDetail.integrityNotification |
| | | )" |
| | | :key="index" |
| | | :src="item" |
| | | class="w--150 h--120 cursor-pointer" |
| | | @click="previewImage(item)" |
| | | /> |
| | | </div> |
| | | <div v-else class="c-fff fs--14 SHSR">暂无图片</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | <script> |
| | | import HeaderBox from "../header/index.vue"; |
| | | import moment from "moment"; |
| | | import { |
| | | getPlanList, |
| | | getDeviceDetailCheckList, |
| | | getDeviceDetailCheckPlanList, |
| | | getDeviceDetailCheckPlanDetail, |
| | | } from "./service"; |
| | | import { planTypeMap } from "@/utils/riskSourceMap"; |
| | | |
| | | export default { |
| | | components: { HeaderBox }, |
| | | props: {}, |
| | | data() { |
| | | return { |
| | | dateTime: null, |
| | | // 搜索条件 |
| | | planType: "", // 计划类型 |
| | | startTime: null, // 开始时间 |
| | | endTime: null, // 结束时间 |
| | | searchKeyword: "", // 搜索关键词 |
| | | startTimeTxt: "", |
| | | endTimeTxt: "", |
| | | |
| | | // 项目信息 |
| | | projectId: null, |
| | | projectName: null, |
| | | dateTxt: "", |
| | | type: null, // 路由参数 type,用于判断是否为项目端 |
| | | |
| | | // 分页 |
| | | currentPage: 1, |
| | | pageSize: 10, |
| | | total: 0, |
| | | |
| | | // 列表数据 |
| | | planOptions: [], // 计划类型下拉选项 |
| | | checkList: [], // 检查列表 |
| | | checkMaterialList: [], // 检查资料列表 |
| | | checkMaterialDetail: {}, // 检查资料详情 |
| | | |
| | | // 弹窗控制 |
| | | projectVisible: false, |
| | | reportVisible: false, |
| | | detailVisible: false, |
| | | |
| | | // 当前选中的数据 |
| | | currentPlanId: null, // 当前选中的计划ID |
| | | currentCheckId: null, // 当前选中的检查资料ID |
| | | currentRow: null, // 当前选中的行数据 |
| | | |
| | | // 报告相关 |
| | | reportUrl: "", |
| | | safeReportUrl: |
| | | "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf", |
| | | deviceReportUrl: |
| | | "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf", |
| | | loading: false, |
| | | |
| | | // 枚举映射 |
| | | planTypeMap: planTypeMap, // 计划类型映射 |
| | | riskLevelMap: { |
| | | 0: "拒绝接受风险", |
| | | 1: "不可接受风险", |
| | | 2: "可接受风险", |
| | | 3: "可容忍风险", |
| | | 4: "可忽略风险", |
| | | }, |
| | | commentTypeMap: { |
| | | 1: "模糊评价", |
| | | 2: "打分评价", |
| | | }, |
| | | }; |
| | | }, |
| | | computed: {}, |
| | | watch: { |
| | | dateTime: { |
| | | handler(newVal, oldVal) { |
| | | startTime: { |
| | | handler(newVal) { |
| | | if (newVal) { |
| | | this.dateTxt = moment(newVal).format("YYYY年MM月DD日 HH:mm:ss"); |
| | | this.startTimeTxt = moment(newVal).format("YYYY年MM月DD日 HH:mm:ss"); |
| | | } else { |
| | | this.startTimeTxt = ""; |
| | | } |
| | | }, |
| | | immediate: true, |
| | | }, |
| | | endTime: { |
| | | handler(newVal) { |
| | | if (newVal) { |
| | | this.endTimeTxt = moment(newVal).format("YYYY年MM月DD日 HH:mm:ss"); |
| | | } else { |
| | | this.endTimeTxt = ""; |
| | | } |
| | | }, |
| | | immediate: true, |
| | |
| | | created() { |
| | | this.projectId = this.$route.query.projectId; |
| | | this.projectName = this.$route.query.projectName; |
| | | this.type = this.$route.query.type; // 获取路由参数 type |
| | | }, |
| | | mounted() {}, |
| | | mounted() { |
| | | this.initData(); |
| | | }, |
| | | methods: { |
| | | // 初始化数据 |
| | | async initData() { |
| | | await this.getPlanOptions(); |
| | | await this.getCheckList(); |
| | | }, |
| | | |
| | | // 获取计划类型下拉选项 |
| | | async getPlanOptions() { |
| | | try { |
| | | // 将 planTypeMap 转换为下拉选项格式 |
| | | // 下标作为 value 传给后端,中文名称作为 label 显示 |
| | | this.planOptions = Object.keys(this.planTypeMap).map((code, index) => ({ |
| | | id: index, // 下标用于传给后端 |
| | | name: this.planTypeMap[code], // 中文名称用于显示 |
| | | code: code, // 保存 code 用于参考 |
| | | })); |
| | | } catch (error) { |
| | | console.error("获取计划类型失败:", error); |
| | | this.$message.error("获取计划类型失败"); |
| | | } |
| | | }, |
| | | |
| | | // 获取检查列表 |
| | | async getCheckList() { |
| | | this.loading = true; |
| | | try { |
| | | const params = { |
| | | pageNum: this.currentPage, |
| | | pageSize: this.pageSize, |
| | | projectId: this.projectId, |
| | | }; |
| | | |
| | | // 添加可选搜索条件 |
| | | if (this.planType !== "" && this.planType !== null && this.planType !== undefined) { |
| | | params.planType = this.planType; // 传下标给后端(0, 1, 2...) |
| | | } |
| | | if (this.startTime) { |
| | | params.startTime = moment(this.startTime).format( |
| | | "YYYY-MM-DD HH:mm:ss" |
| | | ); |
| | | } |
| | | if (this.endTime) { |
| | | params.endTime = moment(this.endTime).format("YYYY-MM-DD HH:mm:ss"); |
| | | } |
| | | if (this.searchKeyword) { |
| | | params.planName = this.searchKeyword; // 计划名称 |
| | | } |
| | | |
| | | const res = await getDeviceDetailCheckList(params); |
| | | if (res && res) { |
| | | this.checkList = res.records || res.list || []; |
| | | this.total = res.total || 0; |
| | | } |
| | | } catch (error) { |
| | | console.error("获取检查列表失败:", error); |
| | | this.$message.error("获取检查列表失败"); |
| | | } finally { |
| | | this.loading = false; |
| | | } |
| | | }, |
| | | |
| | | // 搜索 |
| | | handleSearch() { |
| | | this.currentPage = 1; |
| | | this.getCheckList(); |
| | | }, |
| | | |
| | | // 重置搜索条件 |
| | | handleReset() { |
| | | this.planType = ""; |
| | | this.startTime = null; |
| | | this.endTime = null; |
| | | this.searchKeyword = ""; |
| | | this.currentPage = 1; |
| | | this.getCheckList(); |
| | | }, |
| | | |
| | | // 分页 - 每页条数改变 |
| | | handleSizeChange(val) { |
| | | console.log(`每页 ${val} 条`); |
| | | this.pageSize = val; |
| | | this.currentPage = 1; |
| | | this.getCheckList(); |
| | | }, |
| | | |
| | | // 分页 - 当前页改变 |
| | | handleCurrentChange(val) { |
| | | console.log(`当前页: ${val}`); |
| | | this.currentPage = val; |
| | | this.getCheckList(); |
| | | }, |
| | | |
| | | // 打开检查资料列表弹窗 |
| | | async openCheckMaterialDialog(row) { |
| | | this.currentRow = row; |
| | | this.currentPlanId = row.id; |
| | | this.projectVisible = true; |
| | | await this.getCheckMaterialList(); |
| | | }, |
| | | |
| | | // 获取检查资料列表 |
| | | async getCheckMaterialList() { |
| | | if (!this.currentPlanId) { |
| | | this.$message.warning("缺少计划ID"); |
| | | return; |
| | | } |
| | | |
| | | this.loading = true; |
| | | try { |
| | | const res = await getDeviceDetailCheckPlanList({ |
| | | planId: this.currentPlanId, |
| | | }); |
| | | if (res ) { |
| | | this.checkMaterialList = res; |
| | | } |
| | | } catch (error) { |
| | | console.error("获取检查资料列表失败:", error); |
| | | this.$message.error("获取检查资料列表失败"); |
| | | } finally { |
| | | this.loading = false; |
| | | } |
| | | }, |
| | | |
| | | // 打开检查资料详情弹窗 |
| | | async openDetailDialog(row) { |
| | | this.currentCheckId = row.id; |
| | | this.detailVisible = true; |
| | | await this.getCheckMaterialDetail(); |
| | | }, |
| | | |
| | | // 获取检查资料详情 |
| | | async getCheckMaterialDetail() { |
| | | if (!this.currentCheckId) { |
| | | this.$message.warning("缺少检查资料ID"); |
| | | return; |
| | | } |
| | | |
| | | this.loading = true; |
| | | try { |
| | | const res = await getDeviceDetailCheckPlanDetail({ |
| | | id: this.currentCheckId, |
| | | }); |
| | | if (res ) { |
| | | this.checkMaterialDetail = res; |
| | | } |
| | | } catch (error) { |
| | | console.error("获取检查资料详情失败:", error); |
| | | this.$message.error("获取检查资料详情失败"); |
| | | } finally { |
| | | this.loading = false; |
| | | } |
| | | }, |
| | | |
| | | // 打开报告 |
| | | openReport(type, row) { |
| | | this.currentRow = row; |
| | | if (type === "safe") { |
| | | // 安全报告 |
| | | if (row.containSystemRes === 1) { |
| | | this.reportUrl = row.systemReportUrl || ""; |
| | | } else { |
| | | this.$message.warning("暂无安全报告"); |
| | | return; |
| | | } |
| | | } else if (type === "device") { |
| | | // 设备报告 |
| | | if (row.containDeviceRes === 1) { |
| | | this.reportUrl = row.deviceReportUrl || ""; |
| | | } else { |
| | | this.$message.warning("暂无设备报告"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | if (this.reportUrl) { |
| | | this.reportVisible = true; |
| | | } else { |
| | | this.$message.warning("报告地址不存在"); |
| | | } |
| | | }, |
| | | |
| | | // 关闭检查资料列表弹窗 |
| | | closeProjectDialog() { |
| | | this.projectVisible = false; |
| | | this.checkMaterialList = []; |
| | | this.currentPlanId = null; |
| | | this.currentRow = null; |
| | | }, |
| | | |
| | | // 关闭检查资料详情弹窗 |
| | | closeDetailDialog() { |
| | | this.detailVisible = false; |
| | | this.checkMaterialDetail = {}; |
| | | this.currentCheckId = null; |
| | | }, |
| | | |
| | | // 关闭报告弹窗 |
| | | closeReportDialog() { |
| | | this.reportVisible = false; |
| | | this.reportUrl = ""; |
| | | }, |
| | | |
| | | // 日期选择器点击 |
| | | handleClick(type) { |
| | | this.$refs[`datetime${type}`].focus(); |
| | | }, |
| | | |
| | | // 返回 |
| | | backFun() { |
| | | this.$router.go(-1); |
| | | }, |
| | | openReport(type) { |
| | | if (type === "safe") { |
| | | this.reportUrl = this.safeReportUrl; |
| | | } else if (type === "device") { |
| | | this.reportUrl = this.deviceReportUrl; |
| | | } else { |
| | | this.reportUrl = ""; |
| | | |
| | | // 格式化时间 |
| | | formatTime(time) { |
| | | return time ? moment(time).format("YYYY-MM-DD HH:mm:ss") : "-"; |
| | | }, |
| | | |
| | | // 格式化风险等级 |
| | | formatRiskLevel(level) { |
| | | return this.riskLevelMap[level] || "-"; |
| | | }, |
| | | |
| | | // 格式化计划类型(后端返回的是下标,需要转换为中文名称) |
| | | formatPlanType(type) { |
| | | // 后端返回的是下标,需要根据下标找到对应的 code,再找到中文名称 |
| | | const planTypeCodes = Object.keys(this.planTypeMap); |
| | | if (type >= 0 && type < planTypeCodes.length) { |
| | | const code = planTypeCodes[type]; |
| | | return this.planTypeMap[code] || "-"; |
| | | } |
| | | this.reportVisible = !!this.reportUrl; |
| | | return "-"; |
| | | }, |
| | | |
| | | // 格式化评价类型 |
| | | formatCommentType(type) { |
| | | return this.commentTypeMap[type] || "-"; |
| | | }, |
| | | |
| | | // 获取分数显示 |
| | | getScoreDisplay(row) { |
| | | if (row.commentType === 1) { |
| | | return row.fuzzyScore || "-"; |
| | | } else if (row.commentType === 2) { |
| | | return row.score || "-"; |
| | | } |
| | | return "-"; |
| | | }, |
| | | |
| | | // 处理图片数组(字符串转数组) |
| | | parseImages(imgStr) { |
| | | if (!imgStr) return []; |
| | | if (Array.isArray(imgStr)) return imgStr; |
| | | try { |
| | | return imgStr.split(",").filter((item) => item); |
| | | } catch (error) { |
| | | return []; |
| | | } |
| | | }, |
| | | |
| | | // 预览图片 |
| | | previewImage(url) { |
| | | // 可以使用 el-image-viewer 或其他图片预览组件 |
| | | window.open(url, "_blank"); |
| | | }, |
| | | }, |
| | | }; |
| | |
| | | display: none; |
| | | } |
| | | |
| | | ::v-deep .el-input__inner { |
| | | background: transparent; |
| | | border: none; |
| | | color: #fff; |
| | | padding: 0; |
| | | } |
| | | |
| | | .btn { |
| | | position: absolute; |
| | | top: -2px; |
| | |
| | | color: #00ebfc; |
| | | } |
| | | |
| | | .disabled { |
| | | opacity: 0.5; |
| | | cursor: not-allowed !important; |
| | | } |
| | | |
| | | ::v-deep .el-descriptions { |
| | | .el-descriptions__body { |
| | | background-color: transparent; |
| New file |
| | |
| | | import request from '@/utils/request' |
| | | |
| | | // 获取计划下拉框信息 |
| | | export const getPlanList = async (id) => { |
| | | return request(`/project/getPlanList`, { |
| | | method: 'get' |
| | | }) |
| | | } |
| | | // 获取检查列表 |
| | | export const getDeviceDetailCheckList = async (data) => { |
| | | return request(`/project/getDeviceDetailCheckList`, { |
| | | method: 'post', data |
| | | }) |
| | | } |
| | | // 获取检查资料列表 |
| | | export const getDeviceDetailCheckPlanList = async (params) => { |
| | | return request(`/project/getDeviceDetailCheckPlanList`, { |
| | | method: 'get', params |
| | | }) |
| | | } |
| | | // 获取设备详情检查资料详情 |
| | | export const getDeviceDetailCheckPlanDetail = async (params) => { |
| | | return request(`/project/getDeviceDetailCheckPlanDetail`, { |
| | | method: 'get', params |
| | | }) |
| | | } |
| | |
| | | </div> |
| | | <div class="info-body"> |
| | | <div class="info-item" v-for="(item, index) in dangerTrendList" :key="index"> |
| | | <div class="item-type">{{ item.name || '-' }}</div> |
| | | <div class="item-type" :title="item.name || '-'">{{ item.name || '-' }}</div> |
| | | <div class="item-number"> |
| | | <div class="flex a--center"> |
| | | <div class="flex a--center"> |
| | |
| | | <template #content> |
| | | <div class="people-info"> |
| | | <div class="people-card"> |
| | | <div class="people-item" v-if="peopleList.length > 0"> |
| | | <div class="people-item" v-for="(item, index) in peopleList.slice(0, 3)" :key="index"> |
| | | <div class="people-chart"> |
| | | <el-progress :width="74" type="circle" :show-text="false" :percentage="25" define-back-color="#000" |
| | | color="#32C5FF" stroke-linecap="square"></el-progress> |
| | | <el-progress :width="74" type="circle" :show-text="false" :percentage="parseFloat(item.rate) || 0" |
| | | define-back-color="#000" color="#32C5FF" stroke-linecap="square"></el-progress> |
| | | <div class="progress-card"> |
| | | <div class="progress-num">{{ peopleList[0].rate }}</div> |
| | | <div class="progress-num">{{ item.rate }}</div> |
| | | <div class="progress-unit">%</div> |
| | | </div> |
| | | </div> |
| | | <div class="people-name">{{ peopleList[0].postName }}</div> |
| | | </div> |
| | | <div class="people-item" v-if="peopleList.length > 1"> |
| | | <div class="people-chart"> |
| | | <el-progress :width="74" type="circle" :show-text="false" :percentage="25" define-back-color="#000" |
| | | color="#32C5FF" stroke-linecap="square"></el-progress> |
| | | <div class="progress-card"> |
| | | <div class="progress-num">{{ peopleList[1].rate }}</div> |
| | | <div class="progress-unit">%</div> |
| | | </div> |
| | | </div> |
| | | <div class="people-name">{{ peopleList[1].name }}</div> |
| | | </div> |
| | | <div class="people-item" v-if="peopleList.length > 2"> |
| | | <div class="people-chart"> |
| | | <el-progress :width="74" type="circle" :show-text="false" :percentage="25" define-back-color="#000" |
| | | color="#32C5FF" stroke-linecap="square"></el-progress> |
| | | <div class="progress-card"> |
| | | <div class="progress-num">{{ peopleList[2].rate }}</div> |
| | | <div class="progress-unit">%</div> |
| | | </div> |
| | | </div> |
| | | <div class="people-name">{{ peopleList[1].name }}</div> |
| | | <div class="people-name">{{ item.postName || item.name }}</div> |
| | | </div> |
| | | </div> |
| | | <div class="people-card2"> |
| | | <div class="people-item mr--67" v-if="peopleList.length > 3"> |
| | | <div class="people-item" :class="{ 'mr--67': index === 0 }" |
| | | v-for="(item, index) in peopleList.slice(3, 5)" :key="index + 3"> |
| | | <div class="people-chart"> |
| | | <el-progress :width="74" type="circle" :show-text="false" :percentage="25" define-back-color="#000" |
| | | color="#32C5FF" stroke-linecap="square"></el-progress> |
| | | <el-progress :width="74" type="circle" :show-text="false" :percentage="parseFloat(item.rate) || 0" |
| | | define-back-color="#000" color="#32C5FF" stroke-linecap="square"></el-progress> |
| | | <div class="progress-card"> |
| | | <div class="progress-num">{{ peopleList[3].rate }}</div> |
| | | <div class="progress-num">{{ item.rate }}</div> |
| | | <div class="progress-unit">%</div> |
| | | </div> |
| | | </div> |
| | | <div class="people-name">{{ peopleList[1].name }}</div> |
| | | </div> |
| | | <div class="people-item" v-if="peopleList.length > 4"> |
| | | <div class="people-chart"> |
| | | <el-progress :width="74" type="circle" :show-text="false" :percentage="25" define-back-color="#000" |
| | | color="#32C5FF" stroke-linecap="square"></el-progress> |
| | | <div class="progress-card"> |
| | | <div class="progress-num">{{ peopleList[4].rate }}</div> |
| | | <div class="progress-unit">%</div> |
| | | </div> |
| | | </div> |
| | | <div class="people-name">{{ peopleList[1].name }}</div> |
| | | <div class="people-name">{{ item.name }}</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | <TitleBox> |
| | | <template #title>项目风险趋势 </template> |
| | | <template #right> |
| | | <div @click="handleClick" class="risk-picker"> |
| | | <el-date-picker v-model="dateRange" ref="datePicker" type="monthrange" range-separator="" |
| | | start-placeholder="" end-placeholder=""> |
| | | </el-date-picker> |
| | | <div class="risk-picker"> |
| | | <div class="risk-ab"> |
| | | <img src="../../assets/img/home/Shape@2x (6).png" class="pick-img" /> |
| | | |
| | |
| | | {{ dateTxt }} |
| | | </div> |
| | | </div> |
| | | |
| | | </div> |
| | | </template> |
| | | <template #content> |
| | |
| | | deviceTypes, |
| | | getProjectPersonInfo, |
| | | getProjectSource, |
| | | getDangerTrend |
| | | getDangerTrend, |
| | | getProjectDangerousTrend |
| | | } from './service.js' |
| | | import { |
| | | transformRiskSourceData |
| | |
| | | return { |
| | | mapView: null, |
| | | mapPromise: null, |
| | | dateRange: [moment().startOf("month"), moment().endOf("month")], //默认本月 |
| | | dateRange: [moment().subtract(5, 'months').startOf("month"), moment().endOf("month")], //默认近6个月 |
| | | markers: [], |
| | | projectId: '', |
| | | projectName: '', |
| | |
| | | { riskScale: '一般', content: '项目风险源内容3', status: '已完成' }, |
| | | { riskScale: '重大', content: '项目风险源内容4', status: '未开始' }, |
| | | { riskScale: '重大', content: '项目风险源内容5', status: '进行中' }, |
| | | ] |
| | | ], |
| | | // 项目风险趋势数据 |
| | | riskTrendData: { |
| | | xAxisData: [], |
| | | seriesData: [] |
| | | } |
| | | }; |
| | | }, |
| | | computed: { |
| | |
| | | moment(newVal[0]).format("YYYY -MM") + |
| | | " - " + |
| | | moment(newVal[1]).format("YYYY -MM"); |
| | | // 当日期范围改变时,重新获取风险趋势数据 |
| | | if (this.projectId) { |
| | | this.getProjectRiskTrend(); |
| | | } |
| | | } |
| | | }, |
| | | immediate: true, |
| | |
| | | getLoginInfo({ id: this.projectId, type: 2 }).then(res => { |
| | | console.log('res', res) |
| | | this.projectName = res.name |
| | | localStorage.setItem('commentType', res.commentType) |
| | | }) |
| | | this.getDetail() |
| | | this.getDangerTrendList() |
| | | this.getProjectRiskTrend() |
| | | } |
| | | }, |
| | | mounted() { |
| | |
| | | query: { |
| | | projectId: this.projectId, |
| | | projectName: this.projectName, |
| | | type: 2 |
| | | }, |
| | | }); |
| | | }, |
| | |
| | | // mapStyle: "amap://styles/darkblue", |
| | | layers: [satellite], |
| | | }); |
| | | |
| | | // 在地图中心添加marker |
| | | const marker = new AMap.Marker({ |
| | | position: [104.065617, 30.65695], // 使用地图中心点坐标 |
| | | icon: new AMap.Icon({ |
| | | image: require('../../assets/img/project/mark.png'), |
| | | size: new AMap.Size(30, 30), |
| | | imageSize: new AMap.Size(30, 30) |
| | | }), |
| | | offset: new AMap.Pixel(-15, -15) // 设置偏移量,使图标中心对准坐标点 |
| | | }); |
| | | |
| | | // 将marker添加到地图 |
| | | this.mapView.add(marker); |
| | | |
| | | // this.initCategoryMarkers(AMap); |
| | | }) |
| | | .catch((e) => { |
| | |
| | | // }); |
| | | return series; |
| | | }, |
| | | handleClick() { |
| | | this.$refs.datePicker.focus(); |
| | | // 风险等级转换为数值 (A->3, B->2, C->1) |
| | | levelToValue(level) { |
| | | if (!level) return null; |
| | | const levelStr = String(level).toUpperCase().trim(); |
| | | |
| | | // 处理 A、B、C 或 A类、B类、C类 |
| | | if (levelStr === 'A' || levelStr === 'A类') return 3; |
| | | if (levelStr === 'B' || levelStr === 'B类') return 2; |
| | | if (levelStr === 'C' || levelStr === 'C类') return 1; |
| | | |
| | | return null; |
| | | }, |
| | | // 数值转换为风险等级显示 (3->A类, 2->B类, 1->C类) |
| | | valueToLevel(value) { |
| | | if (value === 3) return 'A类'; |
| | | if (value === 2) return 'B类'; |
| | | if (value === 1) return 'C类'; |
| | | return ''; |
| | | }, |
| | | // 获取项目风险趋势数据 |
| | | async getProjectRiskTrend() { |
| | | if (!this.dateRange || this.dateRange.length !== 2) { |
| | | return; |
| | | } |
| | | |
| | | const params = { |
| | | projectId: this.projectId, |
| | | startTime: moment(this.dateRange[0]).format('YYYY-MM'), |
| | | endTime: moment(this.dateRange[1]).format('YYYY-MM') |
| | | }; |
| | | |
| | | try { |
| | | const res = await getProjectDangerousTrend(params); |
| | | console.log('项目风险趋势数据:', res); |
| | | |
| | | if (res && Array.isArray(res)) { |
| | | // 处理接口返回的数据 |
| | | this.riskTrendData.xAxisData = res.map(item => item.time || ''); |
| | | // 将A、B、C转换为数值 3、2、1 |
| | | this.riskTrendData.seriesData = res.map(item => { |
| | | const value = this.levelToValue(item.level); |
| | | console.log(`level: ${item.level} -> value: ${value}`); |
| | | return value; |
| | | }); |
| | | |
| | | console.log('转换后的数据:', { |
| | | xAxisData: this.riskTrendData.xAxisData, |
| | | seriesData: this.riskTrendData.seriesData |
| | | }); |
| | | |
| | | // 更新图表 |
| | | this.updateRiskChart(); |
| | | } |
| | | } catch (error) { |
| | | console.error('获取项目风险趋势失败:', error); |
| | | } |
| | | }, |
| | | // 更新风险趋势图表 |
| | | updateRiskChart() { |
| | | const riskChart = echarts.getInstanceByDom(document.getElementById('riskTrendChart')); |
| | | if (!riskChart) { |
| | | return; |
| | | } |
| | | |
| | | // 文本换行处理函数 |
| | | const formatLabel = (text, maxWidth = 4) => { |
| | | if (!text) return '' |
| | | const textStr = String(text) |
| | | // 如果文本长度超过最大宽度,进行换行 |
| | | if (textStr.length > maxWidth) { |
| | | let result = '' |
| | | for (let i = 0; i < textStr.length; i += maxWidth) { |
| | | result += textStr.substring(i, i + maxWidth) + '\n' |
| | | } |
| | | return result.trim() |
| | | } |
| | | return textStr |
| | | } |
| | | |
| | | const self = this; |
| | | |
| | | const option = { |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | show: true, |
| | | backgroundColor: 'rgba(0, 0, 0, 0.7)', |
| | | borderColor: '#32C5FF', |
| | | borderWidth: 1, |
| | | textStyle: { |
| | | color: '#fff', |
| | | fontSize: 12 |
| | | }, |
| | | formatter: function (params) { |
| | | if (params && params.length > 0) { |
| | | const param = params[0]; |
| | | const levelText = self.valueToLevel(param.value); |
| | | return `${param.name}<br/>${param.seriesName}: ${levelText}`; |
| | | } |
| | | return ''; |
| | | } |
| | | }, |
| | | legend: { |
| | | show: false |
| | | }, |
| | | grid: { |
| | | top: '10%', |
| | | bottom: '10%', |
| | | left: '10%', |
| | | right: '5%', |
| | | containLabel: true |
| | | }, |
| | | xAxis: { |
| | | data: this.riskTrendData.xAxisData, |
| | | axisTick: { show: true, alignWithLabel: true }, |
| | | axisLine: { |
| | | lineStyle: { |
| | | color: '#666' |
| | | } |
| | | }, |
| | | axisLabel: { |
| | | color: '#fff', |
| | | fontSize: 12, |
| | | interval: 0, |
| | | rotate: 0, |
| | | formatter: function (value) { |
| | | return formatLabel(value, 7) |
| | | }, |
| | | align: 'center', |
| | | verticalAlign: 'top', |
| | | lineHeight: 14, |
| | | width: 60, |
| | | overflow: 'break' |
| | | } |
| | | }, |
| | | yAxis: { |
| | | type: 'value', |
| | | min: 1, |
| | | max: 3, |
| | | interval: 1, |
| | | splitLine: { |
| | | show: true, |
| | | lineStyle: { |
| | | type: 'dashed', |
| | | color: 'rgba(255, 255, 255, .2)' |
| | | } |
| | | }, |
| | | axisLine: { |
| | | show: false |
| | | }, |
| | | axisTick: { |
| | | show: false |
| | | }, |
| | | axisLabel: { |
| | | color: '#fff', |
| | | fontSize: 12, |
| | | formatter: function (value) { |
| | | // Y轴自定义显示:1->C类, 2->B类, 3->A类 |
| | | if (value === 1) return 'C类'; |
| | | if (value === 2) return 'B类'; |
| | | if (value === 3) return 'A类'; |
| | | return ''; |
| | | }, |
| | | align: 'right', |
| | | verticalAlign: 'middle', |
| | | lineHeight: 14, |
| | | width: 30 |
| | | } |
| | | }, |
| | | series: [ |
| | | { |
| | | name: '风险等级', |
| | | type: 'line', |
| | | data: this.riskTrendData.seriesData, |
| | | smooth: false, |
| | | showSymbol: true, |
| | | symbol: 'circle', |
| | | symbolSize: 8, |
| | | itemStyle: { |
| | | color: '#32C5FF', |
| | | borderColor: '#32C5FF', |
| | | borderWidth: 2 |
| | | }, |
| | | lineStyle: { |
| | | width: 5, |
| | | color: { |
| | | type: 'linear', |
| | | x: 0, |
| | | y: 0, |
| | | x2: 1, |
| | | y2: 0, |
| | | colorStops: [ |
| | | { offset: 0, color: 'rgba(36, 81, 242, 1)' }, |
| | | { offset: 0.5, color: 'rgba(11, 204, 254, 1)' }, |
| | | { offset: 1, color: 'rgba(199, 160, 254, 1)' } |
| | | ] |
| | | } |
| | | } |
| | | } |
| | | ] |
| | | }; |
| | | |
| | | riskChart.setOption(option); |
| | | }, |
| | | // 初始化折线图 |
| | | initRiskChart() { |
| | |
| | | containLabel: true |
| | | }, |
| | | xAxis: { |
| | | data: ['2025年1月检查', '2025年2月检查', '2025年3月检查', '2025年4月检查', '2025年5月检查'], |
| | | data: this.riskTrendData.xAxisData.length > 0 ? this.riskTrendData.xAxisData : ['2025年1月检查', '2025年2月检查', '2025年3月检查', '2025年4月检查', '2025年5月检查'], |
| | | axisTick: { show: true, alignWithLabel: true }, |
| | | axisLine: { |
| | | lineStyle: { |
| | |
| | | }, |
| | | yAxis: { |
| | | type: 'value', |
| | | min: 1, |
| | | max: 3, |
| | | interval: 1, |
| | | splitLine: { |
| | | show: true, |
| | | lineStyle: { |
| | |
| | | color: '#fff', |
| | | fontSize: 12, |
| | | formatter: function (value) { |
| | | // Y轴标签格式化,最多3个字符,超出换行 |
| | | const text = String(value) |
| | | return formatLabel(text, 3) |
| | | // Y轴自定义显示:1->C类, 2->B类, 3->A类 |
| | | if (value === 1) return 'C类'; |
| | | if (value === 2) return 'B类'; |
| | | if (value === 3) return 'A类'; |
| | | return ''; |
| | | }, |
| | | // 文本对齐方式 |
| | | align: 'right', |
| | | verticalAlign: 'middle', |
| | | lineHeight: 14, |
| | | // 设置标签的最大宽度 |
| | | width: 30, |
| | | overflow: 'break' // 超出换行 |
| | | width: 30 |
| | | } |
| | | }, |
| | | series: [ |
| | | { |
| | | name: '风险等级', |
| | | type: 'line', |
| | | data: [10, 52, 20, 33, 39], |
| | | data: this.riskTrendData.seriesData.length > 0 ? this.riskTrendData.seriesData : [10, 52, 20, 33, 39], |
| | | smooth: false, // 不使用圆滑过渡 |
| | | showSymbol: false, // 不显示转折点 |
| | | lineStyle: { |
| | |
| | | position: absolute; |
| | | top: 109px; |
| | | left: 20px; |
| | | z-index: 2; |
| | | |
| | | .project-info { |
| | | padding: 14px; |
| | | height: 204px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: space-between; |
| | | overflow: auto; |
| | | gap: 8px; |
| | | overflow-y: auto; |
| | | overflow-x: hidden; |
| | | |
| | | // 自定义滚动条样式 |
| | | &::-webkit-scrollbar { |
| | | width: 4px; |
| | | } |
| | | |
| | | &::-webkit-scrollbar-track { |
| | | background: rgba(255, 255, 255, 0.1); |
| | | border-radius: 2px; |
| | | } |
| | | |
| | | &::-webkit-scrollbar-thumb { |
| | | background: rgba(50, 197, 255, 0.6); |
| | | border-radius: 2px; |
| | | |
| | | &:hover { |
| | | background: rgba(50, 197, 255, 0.8); |
| | | } |
| | | } |
| | | |
| | | .flex1 { |
| | | flex: 1; |
| | |
| | | .info-item { |
| | | display: flex; |
| | | gap: 10px; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .label { |
| | |
| | | font-size: 12px; |
| | | color: #ffffff; |
| | | line-height: 18px; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .item-number { |
| | |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | z-index: 1; |
| | | |
| | | .mid-info { |
| | | cursor: pointer; |
| | |
| | | position: absolute; |
| | | top: 109px; |
| | | right: 20px; |
| | | z-index: 3; |
| | | |
| | | .people-info { |
| | | height: 280px; |
| | |
| | | method: 'get', params |
| | | }) |
| | | } |
| | | |
| | | // 获取项目风险趋势 |
| | | export const getProjectDangerousTrend = async (params) => { |
| | | return request(`/project/getProjectDangerousTrend`, { |
| | | method: 'post', |
| | | data: params |
| | | }) |
| | | } |