Index.vue 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035
  1. <template>
  2. <el-row :gutter="24">
  3. <el-col :span="16">
  4. <el-card class="box-card" v-loading="auditLoading">
  5. <template #header>
  6. <div class="card-header">
  7. <span>
  8. <img :src="ywdbIcon" alt="" />
  9. 待办
  10. </span>
  11. <!-- <el-button link type="default"-->
  12. <!-- >查看更多 <el-icon><ArrowRight /></el-icon-->
  13. <!-- ></el-button>-->
  14. </div>
  15. </template>
  16. <div v-if="showTodoList" class="audit-list">
  17. <template v-for="todo in todoList" :key="todo.title">
  18. <div
  19. v-show="todo.task > 0"
  20. class="audit-item cursor-pointer"
  21. @click="() => handleRouteTo(todo)"
  22. >
  23. <img :src="todo.iconUrl" alt="" />
  24. <div>
  25. <i v-if="typeof todo.task === 'number'">{{ todo.task }}</i>
  26. <span class="todo-title-row">
  27. <span v-if="todo.equipType === 'boiler'" class="equip-tag-boiler">[锅]</span>
  28. <span v-if="todo.equipType === 'pipe'" class="equip-tag-pipe">[管]</span>
  29. {{ todo.title }}
  30. </span>
  31. </div>
  32. </div>
  33. </template>
  34. </div>
  35. <el-empty v-else description="暂无待办数据" />
  36. </el-card>
  37. <el-card class="box-card" v-loading="auditLoading">
  38. <template #header>
  39. <div class="card-header">
  40. <span>
  41. <img :src="ywdbIcon" alt="" />
  42. 审批
  43. </span>
  44. <!-- <el-button link type="default"-->
  45. <!-- >查看更多 <el-icon><ArrowRight /></el-icon-->
  46. <!-- ></el-button>-->
  47. </div>
  48. </template>
  49. <div v-if="showAuditList" class="audit-list">
  50. <template v-for="todo in auditTodoList" :key="todo.title">
  51. <div
  52. v-show="todo.task > 0"
  53. class="audit-item cursor-pointer"
  54. @click="() => handleRouteTo(todo)"
  55. >
  56. <img :src="todo.iconUrl" alt="" />
  57. <div>
  58. <i>{{ todo.task }}</i>
  59. <span class="todo-title-row">
  60. <span v-if="todo.equipType === 'boiler'" class="equip-tag-boiler">[锅]</span>
  61. <span v-if="todo.equipType === 'pipe'" class="equip-tag-pipe">[管]</span>
  62. {{ todo.title }}
  63. </span>
  64. </div>
  65. </div>
  66. </template>
  67. </div>
  68. <el-empty v-else description="暂无审批数据" />
  69. </el-card>
  70. <el-card class="box-card">
  71. <template #header>
  72. <div class="card-header">
  73. <span>
  74. <img :src="tzIcon" alt="" />
  75. 通知公告
  76. </span>
  77. <!-- <el-button v-if="noticeList.length" link type="default" @click="toMoreNotice"-->
  78. <!-- >查看更多 <el-icon><ArrowRight /></el-icon-->
  79. <!-- ></el-button>-->
  80. </div>
  81. </template>
  82. <div class="todo-list">
  83. <template v-if="noticeList.length">
  84. <div
  85. class="notice-item"
  86. v-for="notice in noticeList"
  87. :key="notice.title"
  88. @click="
  89. toPage(
  90. '/fwpt/noticeMgn/detail',
  91. {
  92. id: notice.id
  93. },
  94. 1
  95. )
  96. "
  97. >
  98. <div class="title ellipsis1" style="min-width: 0">
  99. <span class="newFlag color-#fff text-12px" v-if="notice.readStatus == 0">NEW</span>
  100. {{ notice.title }}
  101. </div>
  102. <div class="sub-info">
  103. <span
  104. >来自于 <i>{{ msgTypeMap[notice.type] || '未知' }}</i></span
  105. >
  106. <span>{{
  107. notice.createTime ? dayJs(notice.createTime).format('YYYY-MM-DD HH:mm:ss') : '-'
  108. }}</span>
  109. </div>
  110. </div>
  111. </template>
  112. <template v-else>
  113. <el-empty style="flex: 1" description="暂无公告" />
  114. </template>
  115. </div>
  116. </el-card>
  117. </el-col>
  118. <el-col :span="8">
  119. <div class="risk-alert-wrap">
  120. <RiskAlertCard
  121. equip-type="boiler"
  122. :fetch-my="getBoilerMyAlert"
  123. :fetch-dept="getBoilerDeptAlert"
  124. />
  125. <RiskAlertCard
  126. equip-type="pipe"
  127. :fetch-my="getPipeMyAlert"
  128. :fetch-dept="getPipeDeptAlert"
  129. />
  130. </div>
  131. <el-card class="box-card">
  132. <template #header>
  133. <div class="card-header">
  134. <span>
  135. <img :src="kjrkIcon" alt="" />
  136. 快捷入口
  137. </span>
  138. </div>
  139. </template>
  140. <div class="todo-list quick-access-list">
  141. <div
  142. v-for="todo in quickAccessList"
  143. :key="todo.title"
  144. class="todo-item quick-access-item cursor-pointer"
  145. @click="() => handleRouteTo(todo)"
  146. >
  147. <img :src="todo.iconUrl" alt="" />
  148. <div>
  149. <span>{{ todo.title }}</span>
  150. </div>
  151. </div>
  152. </div>
  153. </el-card>
  154. </el-col>
  155. </el-row>
  156. </template>
  157. <script lang="ts" setup>
  158. import { useUserStore } from '@/store/modules/user'
  159. import { useWatermark } from '@/hooks/web/useWatermark'
  160. import { ArrowRight, List } from '@element-plus/icons-vue'
  161. import {
  162. getTodoList,
  163. getAuditTodoList,
  164. getBoilerMyAlert,
  165. getBoilerDeptAlert,
  166. getPipeMyAlert,
  167. getPipeDeptAlert
  168. } from '@/api/common/home'
  169. import { IndexTodoApi } from '@/api/pressure2/indextodo'
  170. import RiskAlertCard from './components/RiskAlertCard.vue'
  171. import yjIcon from '@/assets/imgs/index_imgs/约检@2x.png'
  172. import jhpqIcon from '@/assets/imgs/index_imgs/计划排期@2x.png'
  173. import jhdtIcon from '@/assets/imgs/index_imgs/计划待调@2x.png'
  174. import zlfpIcon from '@/assets/imgs/index_imgs/资料分配@2x.png'
  175. import zlshIcon from '@/assets/imgs/index_imgs/资料审核@2x.png'
  176. import rwdshIcon from '@/assets/imgs/index_imgs/任务单审核@2x.png'
  177. import rwdzfIcon from '@/assets/imgs/index_imgs/任务单作废@2x.png'
  178. import jljhIcon from '@/assets/imgs/index_imgs/记录校合@2x.png'
  179. import bgspIcon from '@/assets/imgs/index_imgs/报告审批@2x.png'
  180. import jjgqbgIcon from '@/assets/imgs/index_imgs/部门快要过期的报告@2x.png'
  181. import lqapIcon from '@/assets/imgs/index_imgs/临期临安排计划的企业.png'
  182. import ywdbIcon from '@/assets/imgs/index_imgs/业务待办@2x.png'
  183. import fxIcon from '@/assets/imgs/index_imgs/风险@2x.png'
  184. import tzIcon from '@/assets/imgs/index_imgs/通知@2x.png'
  185. import zldjIcon from '@/assets/imgs/index_imgs/资料登记@2x.png'
  186. import qtyjIcon from '@/assets/imgs/index_imgs/前台约检@2x.png'
  187. import shzxIcon from '@/assets/imgs/index_imgs/审核中心@2x.png'
  188. import gdyyIcon from '@/assets/imgs/index_imgs/更多应用@2x.png'
  189. import kjrkIcon from '@/assets/imgs/index_imgs/快捷入口@2x.png'
  190. import { noticeApi } from '@/api/laboratory/noticeService'
  191. import dayJs from 'dayjs'
  192. import { useRouter } from 'vue-router'
  193. const router = useRouter()
  194. const userStore = useUserStore()
  195. const msgTypeMap = {
  196. 1: '系统公告',
  197. 2: '系统消息'
  198. }
  199. // 业务待办列表(锅炉和管道分别显示)
  200. const todoList = ref([
  201. {
  202. title: '计划表',
  203. key: 'boilerScheduleCount',
  204. equipType: 'boiler',
  205. iconUrl: zlfpIcon,
  206. task: 0,
  207. routerName: 'ScheduleBoiler'
  208. },
  209. {
  210. title: '任务确认',
  211. key: 'boilerTaskOrderConfirmCount',
  212. equipType: 'boiler',
  213. iconUrl: jhpqIcon,
  214. task: 0,
  215. routerName: 'BoilerCheckerTaskList',
  216. },
  217. {
  218. title: '检验录入',
  219. key: 'boilerMyTaskCount',
  220. equipType: 'boiler',
  221. iconUrl: jhdtIcon,
  222. task: 0,
  223. routerName: 'BoilerMyTask',
  224. },
  225. {
  226. title: '报告编制',
  227. key: 'boilerPrepareReportCount',
  228. equipType: 'boiler',
  229. iconUrl: zlfpIcon,
  230. task: 0,
  231. routerName: 'BoilerReportPreparationList'
  232. },
  233. {
  234. title: '计划表',
  235. key: 'pipeScheduleCount',
  236. equipType: 'pipe',
  237. iconUrl: zlfpIcon,
  238. task: 0,
  239. routerName: 'SchedulePipe'
  240. },
  241. {
  242. title: '任务确认',
  243. key: 'pipeTaskOrderConfirmCount',
  244. equipType: 'pipe',
  245. iconUrl: jhpqIcon,
  246. task: 0,
  247. routerName: 'PipeCheckerTaskList',
  248. },
  249. {
  250. title: '检验录入',
  251. key: 'pipeMyTaskCount',
  252. equipType: 'pipe',
  253. iconUrl: jhdtIcon,
  254. task: 0,
  255. routerName: 'PipeMyTask',
  256. },
  257. {
  258. title: '报告编制',
  259. key: 'pipePrepareReportCount',
  260. equipType: 'pipe',
  261. iconUrl: zlfpIcon,
  262. task: 0,
  263. routerName: 'PipeReportPreparationList'
  264. }
  265. ])
  266. // 业务审批列表(锅炉和管道分别显示)
  267. const auditLoading = ref(false)
  268. const auditTodoList = ref([
  269. {
  270. title: '模板审核',
  271. key: 'reportTemplateCount',
  272. iconUrl: bgspIcon,
  273. task: 0,
  274. routerName: 'TemplateAudit'
  275. },
  276. {
  277. title: '记录校核',
  278. key: 'boilerRecheckOrderItemCount',
  279. equipType: 'boiler',
  280. iconUrl: jljhIcon,
  281. task: 0,
  282. routerName: 'BoilerCheckerRecordCheck'
  283. },
  284. {
  285. title: '上报市局审核',
  286. key: 'boilerReportCityBureauCount',
  287. equipType: 'boiler',
  288. iconUrl: rwdshIcon,
  289. task: 0,
  290. routerName: 'appointmentconfirmorderCityBureauListPressure2'
  291. },
  292. {
  293. title: '受理单审核',
  294. key: 'boilerAcceptOrderCount',
  295. equipType: 'boiler',
  296. iconUrl: jljhIcon,
  297. task: 0,
  298. routerName: 'AcceptOrderAuditBoiler'
  299. },
  300. {
  301. title: '缴费单待校核',
  302. key: 'boilerPressureNonTaxCount',
  303. equipType: 'boiler',
  304. iconUrl: zlshIcon,
  305. task: 0,
  306. routerName: 'PaymentReceiptApprovePressure2'
  307. },
  308. {
  309. title: '任务单修改审核',
  310. key: 'boilerTaskOrderCount',
  311. equipType: 'boiler',
  312. iconUrl: rwdshIcon,
  313. task: 0,
  314. routerName: 'TaskOrderReviewBoiler'
  315. },
  316. {
  317. title: '检验意见通知书审核',
  318. key: 'boilerPressureInspectionOpinionNoticeCount',
  319. equipType: 'boiler',
  320. iconUrl: jljhIcon,
  321. task: 0,
  322. routerName: 'AuditInspectionCommentsNoticeBoiler'
  323. },
  324. {
  325. title: '检验方案审核',
  326. key: 'boilerPressureInspectionSchemeCount',
  327. equipType: 'boiler',
  328. iconUrl: zlshIcon,
  329. task: 0,
  330. routerName: 'InspectionPlanAuditBoiler'
  331. },
  332. {
  333. title: '操作指导书审核',
  334. key: 'boilerPressureWorkingInstructionCount',
  335. equipType: 'boiler',
  336. iconUrl: rwdshIcon,
  337. task: 0,
  338. routerName: 'WorkInstructionAuditBoiler'
  339. },
  340. // OA流程:锅炉审核/审批
  341. { title: '锅炉审核', key: 'boilerCheckCount', equipType: 'boiler', iconUrl: bgspIcon, task: 0, routerPath: '/gljy/report-check-boiler', oaType: true },
  342. { title: '锅炉审批', key: 'boilerRatifyCount', equipType: 'boiler', iconUrl: bgspIcon, task: 0, routerPath: '/gljy/report-ratify-boiler', oaType: true },
  343. {
  344. title: '记录校核',
  345. key: 'pipeRecheckOrderItemCount',
  346. equipType: 'pipe',
  347. iconUrl: jljhIcon,
  348. task: 0,
  349. routerName: 'PipeCheckerRecordCheck'
  350. },
  351. {
  352. title: '上报市局审核',
  353. key: 'pipeReportCityBureauCount',
  354. equipType: 'pipe',
  355. iconUrl: rwdshIcon,
  356. task: 0,
  357. routerName: 'appointmentconfirmorderCityBureauListPressure2'
  358. },
  359. {
  360. title: '受理单审核',
  361. key: 'pipeAcceptOrderCount',
  362. equipType: 'pipe',
  363. iconUrl: jljhIcon,
  364. task: 0,
  365. routerName: 'AcceptOrderAuditPipe'
  366. },
  367. {
  368. title: '缴费单待校核',
  369. key: 'pipePressureNonTaxCount',
  370. equipType: 'pipe',
  371. iconUrl: zlshIcon,
  372. task: 0,
  373. routerName: 'PaymentReceiptApprovePressure2'
  374. },
  375. {
  376. title: '任务单修改审核',
  377. key: 'pipeTaskOrderCount',
  378. equipType: 'pipe',
  379. iconUrl: rwdshIcon,
  380. task: 0,
  381. routerName: 'TaskOrderReviewPipe'
  382. },
  383. {
  384. title: '检验意见通知书审核',
  385. key: 'pipePressureInspectionOpinionNoticeCount',
  386. equipType: 'pipe',
  387. iconUrl: jljhIcon,
  388. task: 0,
  389. routerName: 'AuditInspectionCommentsNoticePipe'
  390. },
  391. {
  392. title: '检验方案审核',
  393. key: 'pipePressureInspectionSchemeCount',
  394. equipType: 'pipe',
  395. iconUrl: zlshIcon,
  396. task: 0,
  397. routerName: 'InspectionPlanAuditPipe'
  398. },
  399. {
  400. title: '操作指导书审核',
  401. key: 'pipePressureWorkingInstructionCount',
  402. equipType: 'pipe',
  403. iconUrl: rwdshIcon,
  404. task: 0,
  405. routerName: 'WorkInstructionAuditPipe'
  406. },
  407. // OA流程:管道审核/审批
  408. { title: '管道审核', key: 'pipeCheckCount', equipType: 'pipe', iconUrl: bgspIcon, task: 0, routerPath: '/gdjy/report-check-pipe', oaType: true },
  409. { title: '管道审批', key: 'pipeRatifyCount', equipType: 'pipe', iconUrl: bgspIcon, task: 0, routerPath: '/gdjy/report-ratify-pipe', oaType: true },
  410. ])
  411. const showAuditList = computed(() => {
  412. return auditTodoList.value.some((item: any) => item.task > 0)
  413. })
  414. const showTodoList = computed(() => {
  415. return todoList.value.some((item: any) => item.task > 0)
  416. })
  417. // 风险预警列表
  418. const riskTodoList = ref([
  419. {
  420. title: '部门快要过期的报告',
  421. iconUrl: jjgqbgIcon,
  422. task: 0
  423. },
  424. {
  425. title: '临期临安排计划的企业',
  426. iconUrl: lqapIcon,
  427. task: 0
  428. }
  429. ])
  430. // 快捷入口
  431. const quickAccessList = ref([
  432. {
  433. title: '锅炉档案',
  434. iconUrl: zldjIcon,
  435. routerUrl: '',
  436. routerName: 'EquipBoiler'
  437. },
  438. {
  439. title: '管道档案',
  440. iconUrl: shzxIcon,
  441. routerUrl: '',
  442. routerName: 'PipeEquipment'
  443. },
  444. {
  445. title: '前台约检',
  446. iconUrl: qtyjIcon,
  447. routerUrl: '',
  448. routerName: 'NewPressurePlan'
  449. },
  450. {
  451. title: '更多应用',
  452. iconUrl: gdyyIcon,
  453. routerUrl: ''
  454. }
  455. ])
  456. const handleRouteTo = (item: any) => {
  457. const { id } = userStore.getUser
  458. // 支持直接路径跳转(OA审批卡片等)
  459. if (item.routerPath) {
  460. router.push({ path: item.routerPath })
  461. return
  462. }
  463. if (item.routerName) {
  464. // 检查路由是否存在(无菜单权限时路由不会被注册)
  465. const routeExists = router.getRoutes().some(r => r.name === item.routerName)
  466. if (!routeExists) {
  467. ElMessage.warning('暂无权限访问该页面')
  468. return
  469. }
  470. // 特殊处理任务单跳转:默认带上 inspectorIds 和 taskStatusList 参数
  471. const query: any = {
  472. searchUserId: id,
  473. ...(item.routerQuery || {})
  474. }
  475. router.push({
  476. name: item.routerName,
  477. query
  478. })
  479. }
  480. }
  481. // 获取首页待办/审核统计数据(新接口:压力2 index-todo 表,锅炉管道分别展示)
  482. const fetchAllCounts = async () => {
  483. auditLoading.value = true
  484. try {
  485. const result = await IndexTodoApi.getTodoCount()
  486. // 直接映射 API 返回字段到待办/审核列表的 key
  487. todoList.value = todoList.value.map((item: any) => {
  488. if (result[item.key] !== undefined) {
  489. item.task = result[item.key]
  490. }
  491. return item
  492. })
  493. auditTodoList.value = auditTodoList.value.map((item: any) => {
  494. // OA类型的卡片(锅炉/管道审核审批)使用独立接口加载数据,此处跳过
  495. if (item.oaType) return item
  496. if (result[item.key] !== undefined) {
  497. item.task = result[item.key]
  498. }
  499. return item
  500. })
  501. } finally {
  502. auditLoading.value = false
  503. }
  504. }
  505. // 获取OA待办中锅炉/管道审核、审批数量(独立接口,不阻塞首页主查询)
  506. const fetchOATodoCount = async () => {
  507. try {
  508. const result = await IndexTodoApi.getOATodoCount()
  509. auditTodoList.value = auditTodoList.value.map((item: any) => {
  510. if (item.oaType && result[item.key] !== undefined) {
  511. item.task = result[item.key]
  512. }
  513. return item
  514. })
  515. } catch (err) {
  516. console.error('获取OA待办统计失败', err)
  517. }
  518. }
  519. // 旧逻辑保留(注释)
  520. // const fetchTodoList = ...
  521. // const fetchAuditTodoList = ...
  522. // 通知公告
  523. const noticeList = ref<any>([])
  524. /**
  525. * 查询公告列表(前5条)
  526. */
  527. const selectNoticeList = async () => {
  528. try {
  529. const res = await noticeApi.getNoticeList({
  530. pageNo: 1,
  531. pageSize: 5
  532. })
  533. let { list = [] } = res
  534. noticeList.value = list
  535. } catch (err) {}
  536. }
  537. /**
  538. * 跳转页面
  539. * @param path 跳转路径
  540. * @param query 跳转参数
  541. * @param type 跳转类型 1 点击公告进行阅读功能 2 普通跳转
  542. */
  543. const toPage = async (path = '', query: Record<string, any> = {}, type = 2) => {
  544. if (!path) {
  545. ElMessage.warning('暂无配置跳转路径')
  546. return
  547. }
  548. try {
  549. if (type === 1) {
  550. const { id } = query
  551. if (id) {
  552. await noticeApi.readNotice({ laboratoryAnnouncementId: id, readStatus: 1 })
  553. }
  554. }
  555. await router.push({
  556. path,
  557. query
  558. })
  559. } catch (error) {
  560. console.error('页面跳转失败:', error)
  561. ElMessage.error('页面跳转失败')
  562. }
  563. }
  564. /**
  565. * 去往查看更多公告页面
  566. */
  567. const toMoreNotice = () => {
  568. if (!noticeList.value.length) {
  569. ElMessage.warning('暂无更多公告可查看')
  570. return
  571. }
  572. router.push({
  573. path: '/laboratory/allNotice'
  574. })
  575. }
  576. // fetchTodoList()
  577. // fetchAuditTodoList()
  578. fetchAllCounts()
  579. fetchOATodoCount()
  580. selectNoticeList()
  581. </script>
  582. <style lang="scss" scoped>
  583. .newFlag {
  584. background: linear-gradient(270deg, #ff6341 0%, #ff3618 100%);
  585. border-radius: 4px 0px 4px 0px;
  586. line-height: 22px;
  587. padding: 2px 6px;
  588. margin-right: 8px;
  589. }
  590. .ellipsis1 {
  591. text-overflow: -o-ellipsis-lastline;
  592. overflow: hidden;
  593. text-overflow: ellipsis;
  594. display: -webkit-box;
  595. -webkit-line-clamp: 1;
  596. line-clamp: 1;
  597. -webkit-box-orient: vertical;
  598. word-break: break-all;
  599. }
  600. .box-card {
  601. margin-bottom: 20px;
  602. border-radius: 12px;
  603. box-shadow: 0px 2px 14px 0px rgba(43, 99, 255, 0.1);
  604. padding: 17px 22px 24px;
  605. :deep(.el-card__header) {
  606. padding: 0 0 8px 0;
  607. }
  608. :deep(.el-card__body) {
  609. padding: 0;
  610. padding-top: 16px;
  611. .todo-list {
  612. display: flex;
  613. flex-direction: row;
  614. flex-wrap: wrap;
  615. width: 100%;
  616. gap: 16px;
  617. .todo-item {
  618. display: flex;
  619. align-items: flex-end;
  620. flex: 1 0 calc(25% - 16px);
  621. padding: 15px 13px 11px;
  622. background: rgba(73, 120, 246, 0.05);
  623. border-radius: 4px;
  624. img {
  625. width: 54px;
  626. height: 54px;
  627. }
  628. div {
  629. padding-left: 9px;
  630. padding-bottom: 5px;
  631. i,
  632. span {
  633. display: block;
  634. font-style: initial;
  635. }
  636. i {
  637. font-family: Arial, Arial;
  638. color: #4978f6;
  639. font-size: 20px;
  640. }
  641. span {
  642. font-weight: 600;
  643. font-size: 14px;
  644. color: #41475c;
  645. line-height: 20px;
  646. }
  647. }
  648. &:nth-child(5) {
  649. flex: 0 0 calc(25% - 12px);
  650. }
  651. &:last-child {
  652. flex-grow: 1;
  653. max-width: 100%;
  654. margin-right: 0;
  655. }
  656. &:hover {
  657. transform: translateY(-3px); // 轻微上浮效果
  658. box-shadow: 0 4px 12px rgba(73, 120, 246, 0.15); // 添加阴影
  659. background: rgba(73, 120, 246, 0.1); // 背景色加深
  660. img {
  661. transform: scale(1.05); // 图片轻微放大
  662. }
  663. span {
  664. color: #2c64ff; // 文字颜色变化
  665. }
  666. }
  667. }
  668. // .task-todo-item:last-child {
  669. // justify-content: center;
  670. // align-items: center;
  671. // div {
  672. // display: flex;
  673. // align-items: center;
  674. // span {
  675. // color: #4978f6;
  676. // }
  677. // }
  678. // }
  679. .risk-todo-item {
  680. position: relative;
  681. height: 110px;
  682. align-items: center;
  683. padding-left: 24px;
  684. box-sizing: border-box;
  685. img {
  686. position: absolute;
  687. left: 0;
  688. top: 0;
  689. width: 100%;
  690. height: 100%;
  691. }
  692. div {
  693. position: relative;
  694. z-index: 2;
  695. padding: 0;
  696. span {
  697. margin-bottom: 8px;
  698. font-size: 18px;
  699. color: #41475c;
  700. line-height: 28px;
  701. font-weight: 600;
  702. }
  703. i {
  704. font-size: 20px;
  705. color: #e0534e;
  706. line-height: 28px;
  707. font-weight: 600;
  708. }
  709. }
  710. }
  711. .quick-access-item {
  712. transition: all 0.3s ease;
  713. flex: 1 0 calc(50% - 16px);
  714. flex-direction: column;
  715. align-items: flex-start;
  716. &:hover {
  717. transform: translateY(-3px); // 轻微上浮效果
  718. box-shadow: 0 4px 12px rgba(73, 120, 246, 0.15); // 添加阴影
  719. background: rgba(73, 120, 246, 0.1); // 背景色加深
  720. img {
  721. transform: scale(1.05); // 图片轻微放大
  722. }
  723. span {
  724. color: #2c64ff; // 文字颜色变化
  725. }
  726. }
  727. span {
  728. transition: color 0.3s ease; // 文字颜色过渡
  729. }
  730. img {
  731. width: auto;
  732. height: 44px;
  733. object-fit: cover;
  734. transition: transform 0.3s ease; // 图片过渡效果
  735. }
  736. div {
  737. padding: 0;
  738. padding-top: 13px;
  739. }
  740. }
  741. .notice-item {
  742. padding: 12px;
  743. background: rgba(73, 120, 246, 0.05);
  744. border-radius: 4px;
  745. width: 100%;
  746. cursor: pointer;
  747. &:hover {
  748. background: rgba(73, 120, 246, 0.1); // 悬停时背景色加深
  749. transform: translateY(-2px); // 轻微上浮效果
  750. box-shadow: 0 2px 8px rgba(73, 120, 246, 0.1); // 添加阴影
  751. .title {
  752. color: #2c64ff; // 标题颜色变化
  753. }
  754. .sub-info {
  755. i {
  756. color: #4978f6; // 来源文字颜色变化
  757. }
  758. }
  759. }
  760. .title {
  761. font-family:
  762. PingFangSC,
  763. PingFang SC;
  764. font-weight: 500;
  765. font-size: 14px;
  766. color: rgba(0, 0, 0, 0.85);
  767. line-height: 22px;
  768. text-align: left;
  769. font-style: normal;
  770. }
  771. .sub-info {
  772. display: flex;
  773. justify-content: space-between;
  774. margin-top: 12px;
  775. font-size: 12px;
  776. color: rgba(0, 0, 0, 0.5);
  777. i {
  778. font-style: normal;
  779. color: #2c64ff;
  780. }
  781. }
  782. }
  783. }
  784. .audit-list {
  785. display: grid;
  786. grid-template-columns: repeat(4, 1fr);
  787. width: 100%;
  788. gap: 16px;
  789. .audit-item {
  790. display: flex;
  791. align-items: flex-end;
  792. padding: 15px 13px 11px;
  793. background: rgba(73, 120, 246, 0.05);
  794. border-radius: 4px;
  795. img {
  796. width: 54px;
  797. height: 54px;
  798. }
  799. div {
  800. padding-left: 9px;
  801. padding-bottom: 5px;
  802. i,
  803. span {
  804. display: block;
  805. font-style: initial;
  806. }
  807. i {
  808. font-family: Arial, Arial;
  809. color: #4978f6;
  810. font-size: 20px;
  811. }
  812. span {
  813. font-weight: 600;
  814. font-size: 14px;
  815. color: #41475c;
  816. line-height: 20px;
  817. }
  818. }
  819. &:hover {
  820. transform: translateY(-3px); // 轻微上浮效果
  821. box-shadow: 0 4px 12px rgba(73, 120, 246, 0.15); // 添加阴影
  822. background: rgba(73, 120, 246, 0.1); // 背景色加深
  823. img {
  824. transform: scale(1.05); // 图片轻微放大
  825. }
  826. span {
  827. color: #2c64ff; // 文字颜色变化
  828. }
  829. }
  830. }
  831. .task-todo-item:last-child {
  832. justify-content: center;
  833. align-items: center;
  834. div {
  835. display: flex;
  836. align-items: center;
  837. span {
  838. color: #4978f6;
  839. }
  840. }
  841. }
  842. .risk-todo-item {
  843. position: relative;
  844. height: 110px;
  845. align-items: center;
  846. padding-left: 24px;
  847. box-sizing: border-box;
  848. img {
  849. position: absolute;
  850. left: 0;
  851. top: 0;
  852. width: 100%;
  853. height: 100%;
  854. }
  855. div {
  856. position: relative;
  857. z-index: 2;
  858. padding: 0;
  859. span {
  860. margin-bottom: 8px;
  861. font-size: 18px;
  862. color: #41475c;
  863. line-height: 28px;
  864. font-weight: 600;
  865. }
  866. i {
  867. font-size: 20px;
  868. color: #e0534e;
  869. line-height: 28px;
  870. font-weight: 600;
  871. }
  872. }
  873. }
  874. .quick-access-item {
  875. transition: all 0.3s ease;
  876. flex: 1 0 calc(50% - 16px);
  877. flex-direction: column;
  878. align-items: flex-start;
  879. &:hover {
  880. transform: translateY(-3px); // 轻微上浮效果
  881. box-shadow: 0 4px 12px rgba(73, 120, 246, 0.15); // 添加阴影
  882. background: rgba(73, 120, 246, 0.1); // 背景色加深
  883. img {
  884. transform: scale(1.05); // 图片轻微放大
  885. }
  886. span {
  887. color: #2c64ff; // 文字颜色变化
  888. }
  889. }
  890. span {
  891. transition: color 0.3s ease; // 文字颜色过渡
  892. }
  893. img {
  894. width: auto;
  895. height: 44px;
  896. object-fit: cover;
  897. transition: transform 0.3s ease; // 图片过渡效果
  898. }
  899. div {
  900. padding: 0;
  901. padding-top: 13px;
  902. }
  903. }
  904. .notice-item {
  905. padding: 12px;
  906. background: rgba(73, 120, 246, 0.05);
  907. border-radius: 4px;
  908. width: 100%;
  909. cursor: pointer;
  910. &:hover {
  911. background: rgba(73, 120, 246, 0.1); // 悬停时背景色加深
  912. transform: translateY(-2px); // 轻微上浮效果
  913. box-shadow: 0 2px 8px rgba(73, 120, 246, 0.1); // 添加阴影
  914. .title {
  915. color: #2c64ff; // 标题颜色变化
  916. }
  917. .sub-info {
  918. i {
  919. color: #4978f6; // 来源文字颜色变化
  920. }
  921. }
  922. }
  923. .title {
  924. font-family:
  925. PingFangSC,
  926. PingFang SC;
  927. font-weight: 500;
  928. font-size: 14px;
  929. color: rgba(0, 0, 0, 0.85);
  930. line-height: 22px;
  931. text-align: left;
  932. font-style: normal;
  933. }
  934. .sub-info {
  935. display: flex;
  936. justify-content: space-between;
  937. margin-top: 12px;
  938. font-size: 12px;
  939. color: rgba(0, 0, 0, 0.5);
  940. i {
  941. font-style: normal;
  942. color: #2c64ff;
  943. }
  944. }
  945. }
  946. }
  947. }
  948. }
  949. .card-header {
  950. display: flex;
  951. justify-content: space-between;
  952. span {
  953. display: flex;
  954. align-items: center;
  955. font-size: 18px;
  956. font-weight: 600;
  957. img {
  958. width: 24px;
  959. height: 24px;
  960. margin-right: 4px;
  961. }
  962. :deep(.el-button) {
  963. font-size: 14px;
  964. }
  965. }
  966. }
  967. .todo-title-row {
  968. display: flex !important;
  969. align-items: center;
  970. gap: 4px;
  971. }
  972. .equip-tag-boiler {
  973. color: #f56c6c !important;
  974. }
  975. .equip-tag-pipe {
  976. color: #67c23a !important;
  977. }
  978. .risk-alert-wrap {
  979. display: flex;
  980. flex-direction: column;
  981. gap: 16px;
  982. margin-bottom: 20px;
  983. }
  984. </style>