Merge branch 'master' into jiangwu
17 files modified
16 files added
| | |
| | | |
| | | # 服务地址 |
| | | VITE_APP_URL = https://wrj.shuixiongit.com/api |
| | | # VITE_APP_URL= http://192.168.1.7 |
| | | # 域名 |
| | | VITE_APP_AREA_NAME = wss://wrj.shuixiongit.com |
| | | |
| | |
| | | # 服务地址 |
| | | VITE_APP_URL = http://192.168.253.121/api |
| | | # 域名 |
| | | VITE_APP_AREA_NAME = ws://192.168.253.121:8080 |
| | | VITE_APP_AREA_NAME = ws://192.168.253.121:8080 |
| | | |
| | | # 航线文件地址 |
| | | VITE_APP_AIRLINE_URL = https://wrj.shuixiongit.com/aiskyminio/cloud-bucket |
| | |
| | | VITE_APP_TERRAIN_URL = https://wrj.shuixiongit.com/aiskyminio/cloud-bucket |
| | | |
| | | # 是否在打包时开启压缩,支持 gzip 和 brotli |
| | | VITE_BUILD_COMPRESS = gzip |
| | | VITE_BUILD_COMPRESS = gzip |
| | |
| | | import request from '@/axios' |
| | | import request from '@/axios'; |
| | | // 事件概况总数 |
| | | export const getJobEventTotal = () => { |
| | | return request({ |
| | | url: '/drone-device-core/jobEvent/total', |
| | | method: 'get', |
| | | }) |
| | | } |
| | | return request({ |
| | | url: '/drone-device-core/jobEvent/total', |
| | | method: 'get', |
| | | }); |
| | | }; |
| | | // 事件概况分类数 |
| | | export const getJobEventByStatus = data => { |
| | | return request({ |
| | | url: '/drone-device-core/jobEvent/eventByStatus', |
| | | method: 'post', |
| | | data, |
| | | }) |
| | | } |
| | | return request({ |
| | | url: '/drone-device-core/jobEvent/eventByStatus', |
| | | method: 'post', |
| | | data, |
| | | }); |
| | | }; |
| | | // 行业任务统计 |
| | | export const industryJobNumPieChart = data => { |
| | | return request({ |
| | | url: '/drone-device-core/jobEvent/deviceEventList', |
| | | method: 'post', |
| | | data: data, |
| | | }) |
| | | } |
| | | return request({ |
| | | url: '/drone-device-core/jobEvent/deviceEventList', |
| | | method: 'post', |
| | | data: data, |
| | | }); |
| | | }; |
| | | // 事件任务统计 |
| | | export const jobEventBar = data => { |
| | | return request({ |
| | | url: '/drone-device-core/wayline/waylineJobInfo/jobEventBar', |
| | | method: 'post', |
| | | data: data, |
| | | }) |
| | | } |
| | | return request({ |
| | | url: '/drone-device-core/wayline/waylineJobInfo/jobEventBar', |
| | | method: 'post', |
| | | data: data, |
| | | }); |
| | | }; |
| | | // 设备统计 |
| | | export const getStatics = (areaCode) => { |
| | | return request({ |
| | | url: '/drone-device-core/manage/api/v1/devices/deviceStatistics', |
| | | method: 'post', |
| | | params: { |
| | | areaCode |
| | | }, |
| | | }); |
| | | }; |
| | | // 日历 |
| | | export const getStatics = areaCode => { |
| | | return request({ |
| | | url: '/drone-device-core/manage/api/v1/devices/deviceStatistics', |
| | | method: 'post', |
| | | params: { |
| | | areaCode, |
| | | }, |
| | | }); |
| | | }; |
| | | // 日历 |
| | | export const getCalen = data => { |
| | | return request({ |
| | | url: '/drone-device-core/wayline/waylineJobInfo/jobEventBar', |
| | | method: 'post', |
| | | data, |
| | | }) |
| | | } |
| | | return request({ |
| | | url: '/drone-device-core/wayline/waylineJobInfo/jobEventBarByMouth', |
| | | method: 'post', |
| | | data, |
| | | }); |
| | | }; |
| | | // 飞行统计 |
| | | export const getFly = data => { |
| | | return request({ |
| | | url: '/drone-device-core/manage/api/v1/devices/deviceFlyTimeAndDistance', |
| | | method: 'post', |
| | | data, |
| | | }); |
| | | }; |
| | | // 飞行时长 里程 任务数 |
| | | export const getFlyTime = data => { |
| | | return request({ |
| | | url: '/drone-device-core/manage/api/v1/devices/deviceFlyTimeAndDistanceBar', |
| | | method: 'post', |
| | | data, |
| | | }); |
| | | }; |
| | | |
| | | // 待办事项 |
| | | export const getdaiban = (type,areaCode) => { |
| | | return request({ |
| | | url: '/drone-device-core/jobEvent/getOrderOrEventFive', |
| | | method: 'get', |
| | | params: { |
| | | type, |
| | | areaCode |
| | | }, |
| | | }); |
| | | }; |
| New file |
| | |
| | | <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <g id="Frame" clip-path="url(#clip0_74_4839)"> |
| | | <path id="Vector" d="M2.57937 1.80809L14.3325 5.72559C14.3933 5.74575 14.4465 5.78414 14.4848 5.83553C14.5231 5.88692 14.5446 5.94885 14.5465 6.01291C14.5484 6.07697 14.5306 6.14007 14.4955 6.19365C14.4603 6.24723 14.4095 6.28871 14.35 6.31247L8.89187 8.49559L6.12624 14.0268C6.0981 14.0832 6.0536 14.1297 5.99857 14.1603C5.94354 14.1909 5.88056 14.2041 5.81786 14.1983C5.75517 14.1925 5.69569 14.1679 5.64722 14.1277C5.59875 14.0875 5.56356 14.0336 5.54624 13.9731L2.17999 2.19059C2.16438 2.13594 2.16396 2.07807 2.17879 2.02321C2.19362 1.96834 2.22313 1.91856 2.26414 1.87922C2.30516 1.83988 2.35612 1.81246 2.41156 1.79993C2.46699 1.7874 2.52479 1.79022 2.57874 1.80809H2.57937Z" fill="#F6A102"/> |
| | | </g> |
| | | <defs> |
| | | <clipPath id="clip0_74_4839"> |
| | | <rect width="15" height="15" fill="white" transform="translate(0.766602 0.370605)"/> |
| | | </clipPath> |
| | | </defs> |
| | | </svg> |
| New file |
| | |
| | | <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <g id="Frame" clip-path="url(#clip0_74_4842)"> |
| | | <path id="Vector" d="M9.67881 1.20398C12.5871 1.20398 15.0254 3.69561 15.0254 6.78639C15.0254 8.3547 14.4154 9.73884 13.4312 10.7538L9.96047 14.3529C9.86489 14.4417 9.73927 14.4911 9.60881 14.4911C9.47835 14.4911 9.35272 14.4417 9.25715 14.3529L5.78637 10.7538C4.76326 9.68674 4.1921 8.26555 4.19223 6.78723C4.28639 3.69477 6.72469 1.20398 9.67881 1.20398ZM9.67881 8.5397C10.8513 8.5397 11.7896 7.61721 11.7896 6.46306C11.7896 5.30975 10.8513 4.3881 9.67881 4.3881C8.50633 4.3881 7.56884 5.30975 7.56884 6.46306C7.56884 7.61721 8.50633 8.5397 9.67881 8.5397ZM4.75472 14.5371H8.50633L7.56884 13.6146H5.6922L4.75472 14.5371ZM0.0256252 9.71718C0.0256252 10.688 0.387288 11.5672 1.02061 12.2138L3.19058 14.4329C3.32641 14.5721 3.50724 14.5721 3.64307 14.4329L5.81387 12.168C5.85887 12.1205 5.85887 12.1205 5.85887 12.0755L4.95472 11.1047C4.72805 10.873 4.54722 10.6422 4.36639 10.4113C4.24505 10.5569 4.09298 10.6738 3.92108 10.7536C3.74919 10.8335 3.56176 10.8742 3.37224 10.873C2.64808 10.873 2.06059 10.273 2.06059 9.57885C2.06059 8.88553 2.64808 8.2847 3.37224 8.2847C3.23641 7.72971 3.14558 7.17472 3.14558 6.61973V6.2039C1.42727 6.34223 0.0256252 7.82221 0.0256252 9.71718Z" fill="#009666"/> |
| | | </g> |
| | | <defs> |
| | | <clipPath id="clip0_74_4842"> |
| | | <rect width="15" height="15" fill="white" transform="matrix(-1 0 0 1 15.0254 0.370605)"/> |
| | | </clipPath> |
| | | </defs> |
| | | </svg> |
| New file |
| | |
| | | <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <g id="Frame" clip-path="url(#clip0_74_4845)"> |
| | | <path id="Vector" d="M10.8271 1.30481H2.97832C2.15918 1.30481 1.49414 1.96985 1.49414 2.78899V11.4731C1.49414 13.3831 3.04726 14.9342 4.95521 14.9342H12.8039C13.6231 14.9342 14.2881 14.2691 14.2881 13.45V4.76588C14.2902 2.85793 12.737 1.30481 10.8271 1.30481ZM8.25407 10.6073H5.06064C4.69973 10.6073 4.40776 10.3153 4.40776 9.95443C4.40776 9.59353 4.69973 9.29953 5.06064 9.29953H8.25407C8.61498 9.29953 8.90695 9.5915 8.90695 9.95443C8.90897 10.3133 8.61498 10.6073 8.25407 10.6073ZM10.7216 6.85428H5.06064C4.69973 6.85428 4.40776 6.56231 4.40776 6.2014C4.40776 5.84049 4.69973 5.54852 5.06064 5.54852H10.7216C11.0825 5.54852 11.3745 5.84049 11.3745 6.2014C11.3745 6.56231 11.0825 6.85428 10.7216 6.85428Z" fill="#177BDF"/> |
| | | </g> |
| | | <defs> |
| | | <clipPath id="clip0_74_4845"> |
| | | <rect width="15" height="15" fill="white" transform="translate(0.402344 0.619629)"/> |
| | | </clipPath> |
| | | </defs> |
| | | </svg> |
| New file |
| | |
| | | <svg width="65" height="65" viewBox="0 0 65 65" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <g id="Group 1321315450"> |
| | | <circle id="Ellipse 2423" cx="32.4531" cy="32.8379" r="32" fill="url(#paint0_linear_75_7135)"/> |
| | | <g id="Frame"> |
| | | <path id="Vector" d="M25.0111 19.5042C24.1153 19.5042 23.2282 19.6766 22.4006 20.0116C21.5729 20.3467 20.8209 20.8377 20.1875 21.4568C19.554 22.0758 19.0515 22.8108 18.7087 23.6196C18.3659 24.4285 18.1894 25.2954 18.1895 26.1708V30.1708C18.1895 30.5245 18.3332 30.8636 18.5891 31.1136C18.8449 31.3637 19.1919 31.5041 19.5538 31.5042H23.6877L26.7193 27.0615C27.0232 26.6266 27.4903 26.3264 28.0192 26.226C28.5481 26.1256 29.0963 26.2331 29.5446 26.5252C29.9929 26.8173 30.3053 27.2704 30.4139 27.7862C30.5225 28.302 30.4186 28.8388 30.1247 29.2802L28.6075 31.5042H31.1507C31.5125 31.5042 31.8596 31.3637 32.1154 31.1136C32.3713 30.8636 32.515 30.5245 32.515 30.1708V20.8375C32.515 20.4839 32.3713 20.1447 32.1154 19.8947C31.8596 19.6446 31.5125 19.5042 31.1507 19.5042H25.0111ZM22.7791 32.8375L21.2619 35.0615C21.1093 35.2799 21.0025 35.5258 20.9478 35.7849C20.893 36.0439 20.8914 36.311 20.943 36.5707C20.9946 36.8303 21.0984 37.0774 21.2484 37.2976C21.3984 37.5178 21.5916 37.7067 21.8168 37.8534C22.042 38.0002 22.2948 38.1018 22.5604 38.1524C22.8261 38.203 23.0994 38.2016 23.3645 38.1483C23.6296 38.095 23.8813 37.9908 24.1049 37.8418C24.3286 37.6928 24.5197 37.5019 24.6673 37.2802L27.6989 32.8375H38.6955L41.7271 37.2802C41.8747 37.5019 42.0658 37.6928 42.2895 37.8418C42.5131 37.9908 42.7648 38.095 43.0299 38.1483C43.295 38.2016 43.5683 38.203 43.834 38.1524C44.0996 38.1018 44.3524 38.0002 44.5776 37.8534C44.8028 37.7067 44.996 37.5178 45.146 37.2976C45.296 37.0774 45.3997 36.8303 45.4514 36.5707C45.503 36.311 45.5013 36.0439 45.4466 35.7849C45.3919 35.5258 45.2851 35.2799 45.1325 35.0615L43.6153 32.8375H46.8406C47.2025 32.8375 47.5495 32.978 47.8053 33.228C48.0612 33.4781 48.2049 33.8172 48.2049 34.1708V38.6962C48.2051 39.3549 48.0388 40.0034 47.7209 40.5842C47.4029 41.165 46.943 41.6601 46.3822 42.0255L44.9032 42.9882C44.4094 43.3108 44.1119 43.8535 44.1119 44.4335C44.1119 45.3935 43.3165 46.1708 42.3342 46.1708H41.3832C41.0214 46.1708 40.6744 46.0304 40.4185 45.7803C40.1626 45.5303 40.0189 45.1911 40.0189 44.8375C40.0189 44.4839 39.8752 44.1447 39.6193 43.8947C39.3634 43.6446 39.0164 43.5042 38.6546 43.5042H27.7398C27.378 43.5042 27.031 43.6446 26.7751 43.8947C26.5192 44.1447 26.3755 44.4839 26.3755 44.8375C26.3755 45.1911 26.2318 45.5303 25.9759 45.7803C25.72 46.0304 25.373 46.1708 25.0111 46.1708H24.0602C23.0779 46.1708 22.2825 45.3935 22.2825 44.4335C22.2825 43.8535 21.985 43.3108 21.4911 42.9882L20.0122 42.0255C19.4514 41.6601 18.9915 41.1651 18.6736 40.5842C18.3556 40.0034 18.1893 39.3549 18.1895 38.6962V34.1708C18.1895 33.8172 18.3332 33.4781 18.5891 33.228C18.8449 32.978 19.1919 32.8375 19.5538 32.8375H22.7791ZM42.7067 31.5042H46.8406C47.2025 31.5041 47.5495 31.3637 47.8053 31.1136C48.0612 30.8636 48.2049 30.5245 48.2049 30.1708V24.8375C48.2049 23.423 47.63 22.0665 46.6065 21.0663C45.5831 20.0661 44.195 19.5042 42.7476 19.5042H35.2437C34.8819 19.5042 34.5348 19.6446 34.279 19.8947C34.0231 20.1447 33.8794 20.4839 33.8794 20.8375V30.1708C33.8794 30.5245 34.0231 30.8636 34.279 31.1136C34.5348 31.3637 34.8819 31.5042 35.2437 31.5042H37.7868L36.2697 29.2802C36.117 29.0617 36.0103 28.8158 35.9555 28.5568C35.9008 28.2977 35.8992 28.0307 35.9508 27.771C36.0024 27.5113 36.1062 27.2642 36.2562 27.0441C36.4062 26.8239 36.5993 26.6349 36.8246 26.4882C37.0498 26.3415 37.3025 26.2399 37.5682 26.1893C37.8339 26.1386 38.1072 26.14 38.3723 26.1934C38.6374 26.2467 38.889 26.3509 39.1127 26.4999C39.3363 26.6489 39.5275 26.8398 39.6751 27.0615L42.7067 31.5042Z" fill="url(#paint1_linear_75_7135)"/> |
| | | </g> |
| | | </g> |
| | | <defs> |
| | | <linearGradient id="paint0_linear_75_7135" x1="32.4531" y1="0.837891" x2="32.4531" y2="64.8379" gradientUnits="userSpaceOnUse"> |
| | | <stop stop-color="#F5F7F9"/> |
| | | <stop offset="1" stop-color="#F6FAFA"/> |
| | | </linearGradient> |
| | | <linearGradient id="paint1_linear_75_7135" x1="33.1972" y1="19.5042" x2="33.1972" y2="46.1708" gradientUnits="userSpaceOnUse"> |
| | | <stop stop-color="#65B2FF"/> |
| | | <stop offset="1" stop-color="#0166F5"/> |
| | | </linearGradient> |
| | | </defs> |
| | | </svg> |
| New file |
| | |
| | | <svg width="65" height="65" viewBox="0 0 65 65" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <g id="Group 1321315476"> |
| | | <circle id="Ellipse 2423" cx="32.9082" cy="32.0122" r="32" fill="url(#paint0_linear_75_7179)"/> |
| | | <g id="Frame" clip-path="url(#clip0_75_7179)"> |
| | | <path id="Vector" d="M28.8944 37.6504L25.4137 41.1311C25.2221 41.3229 24.9622 41.4307 24.6911 41.4309C24.42 41.431 24.1599 41.3234 23.9682 41.1319C23.7764 40.9403 23.6686 40.6803 23.6684 40.4093C23.6683 40.1382 23.7758 39.8781 23.9674 39.6864L27.4496 36.2056C26.6366 35.6676 25.6826 35.382 24.7077 35.3848C23.714 35.3848 22.7426 35.6795 21.9164 36.2315C21.0902 36.7836 20.4463 37.5682 20.066 38.4863C19.6858 39.4043 19.5863 40.4145 19.7801 41.389C19.974 42.3636 20.4525 43.2588 21.1551 43.9614C21.8577 44.6641 22.7529 45.1426 23.7275 45.3364C24.7021 45.5303 25.7123 45.4308 26.6303 45.0505C27.5483 44.6703 28.333 44.0263 28.885 43.2001C29.4371 42.3739 29.7317 41.4026 29.7317 40.4089C29.718 39.4289 29.4277 38.4727 28.8944 37.6504ZM23.9689 24.6637C23.8739 24.5688 23.7986 24.456 23.7472 24.332C23.6958 24.2079 23.6694 24.0749 23.6694 23.9406C23.6694 23.8063 23.6958 23.6733 23.7472 23.5493C23.7986 23.4252 23.8739 23.3125 23.9689 23.2175C24.0639 23.1225 24.1766 23.0472 24.3007 22.9958C24.4247 22.9444 24.5577 22.918 24.692 22.918C24.8263 22.918 24.9593 22.9444 25.0834 22.9958C25.2074 23.0472 25.3202 23.1225 25.4151 23.2175L28.8613 26.6666C29.5319 25.6348 29.7965 24.3912 29.6043 23.1758C29.412 21.9603 28.7765 20.8591 27.8202 20.0846C26.864 19.3101 25.6548 18.9172 24.4259 18.9816C23.1971 19.046 22.0356 19.5632 21.1655 20.4334C20.2955 21.3036 19.7785 22.4652 19.7144 23.6941C19.6502 24.923 20.0434 26.1321 20.8181 27.0882C21.5928 28.0442 22.6941 28.6796 23.9096 28.8716C25.1251 29.0636 26.3686 28.7987 27.4003 28.1279L23.9689 24.6637ZM41.1423 35.4176C40.18 35.4146 39.238 35.6943 38.4334 36.2222L41.8811 39.6698C41.976 39.7647 42.0514 39.8773 42.1028 40.0013C42.1542 40.1253 42.1807 40.2582 42.1808 40.3924C42.1809 40.5267 42.1545 40.6596 42.1032 40.7836C42.0519 40.9077 41.9767 41.0204 41.8818 41.1153C41.7869 41.2103 41.6743 41.2856 41.5503 41.3371C41.4263 41.3885 41.2934 41.415 41.1592 41.4151C41.025 41.4151 40.892 41.3888 40.768 41.3375C40.644 41.2862 40.5312 41.2109 40.4363 41.1161L36.9886 37.6657C36.463 38.4714 36.1834 39.4127 36.184 40.3746C36.184 43.1166 38.4169 45.3494 41.1588 45.3494C43.9008 45.3494 46.1333 43.1166 46.1333 40.3746C46.1333 37.6327 43.8842 35.4176 41.1423 35.4176ZM41.1423 18.9502C40.2437 18.9513 39.362 19.1948 38.5901 19.6548C37.8182 20.1149 37.1846 20.7746 36.7561 21.5644C36.3276 22.3542 36.1199 23.245 36.155 24.1429C36.1901 25.0408 36.4667 25.9127 36.9556 26.6666L40.4035 23.219C40.5953 23.0274 40.8553 22.9198 41.1264 22.92C41.3975 22.9201 41.6574 23.0279 41.849 23.2197C42.0406 23.4115 42.1482 23.6715 42.148 23.9426C42.1479 24.2137 42.0401 24.4736 41.8483 24.6652L38.4003 28.1114C39.1543 28.6004 40.0261 28.877 40.9241 28.9121C41.822 28.9473 42.7128 28.7397 43.5027 28.3112C44.2925 27.8826 44.9523 27.2491 45.4123 26.4772C45.8724 25.7053 46.1159 24.8236 46.1171 23.925C46.1333 21.183 43.9005 18.9502 41.1423 18.9502Z" fill="url(#paint1_linear_75_7179)"/> |
| | | <path id="Vector_2" d="M27.4166 36.1728C29.3705 33.8579 29.354 30.4265 27.4004 28.1113C28.0078 27.5532 28.2858 27.274 28.8779 26.6338C31.1928 28.6045 34.6416 28.6045 36.9556 26.6338C37.4482 27.1592 37.875 27.6025 38.4334 28.1113C37.4775 29.244 36.9545 30.6791 36.9573 32.1613C36.9602 33.6435 37.4888 35.0765 38.4491 36.2056C38.0557 36.6161 37.5303 37.0754 36.9733 37.6834C34.6585 35.7129 31.227 35.6967 28.9119 37.6503C28.2717 37.0101 27.8777 36.5668 27.4166 36.1728Z" fill="url(#paint2_linear_75_7179)"/> |
| | | </g> |
| | | </g> |
| | | <defs> |
| | | <linearGradient id="paint0_linear_75_7179" x1="32.9082" y1="0.012207" x2="32.9082" y2="64.0122" gradientUnits="userSpaceOnUse"> |
| | | <stop stop-color="#F5F7F9"/> |
| | | <stop offset="1" stop-color="#F6FAFA"/> |
| | | </linearGradient> |
| | | <linearGradient id="paint1_linear_75_7179" x1="32.9084" y1="18.9502" x2="32.9084" y2="45.433" gradientUnits="userSpaceOnUse"> |
| | | <stop stop-color="#00E2BC"/> |
| | | <stop offset="1" stop-color="#1FCBD0"/> |
| | | </linearGradient> |
| | | <linearGradient id="paint2_linear_75_7179" x1="32.9247" y1="26.6338" x2="32.9247" y2="37.6834" gradientUnits="userSpaceOnUse"> |
| | | <stop stop-color="#00E2BC"/> |
| | | <stop offset="1" stop-color="#1FCBD0"/> |
| | | </linearGradient> |
| | | <clipPath id="clip0_75_7179"> |
| | | <rect width="26.4828" height="26.4828" fill="white" transform="translate(19.667 18.9502)"/> |
| | | </clipPath> |
| | | </defs> |
| | | </svg> |
| New file |
| | |
| | | <svg width="65" height="65" viewBox="0 0 65 65" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <g id="Group 1321315477"> |
| | | <circle id="Ellipse 2423" cx="32.0977" cy="32.0688" r="32" fill="url(#paint0_linear_75_7156)"/> |
| | | <g id="Frame" clip-path="url(#clip0_75_7156)"> |
| | | <path id="Vector" d="M32.6496 42.3309C40.1751 42.3309 46.3323 36.3061 46.3323 28.8909C46.3323 21.5419 40.1751 15.5171 32.6496 15.5171C25.124 15.5171 18.9668 21.5419 18.9668 28.9571C18.9668 36.3061 25.124 42.3309 32.6496 42.3309ZM32.6496 23.3295C35.7966 23.3295 38.3963 25.8454 38.3963 28.9571C38.3963 32.0688 35.865 34.5847 32.6496 34.5847C29.5025 34.5847 26.9028 32.0688 26.9028 28.9571C26.9028 25.8454 29.5025 23.3295 32.6496 23.3295ZM26.9028 19.7543C27.7922 19.7543 28.5447 20.4826 28.5447 21.3433C28.5447 22.204 27.7922 22.9323 26.9028 22.9323C26.0134 22.9323 25.2609 22.204 25.2609 21.3433C25.3293 20.4826 26.0134 19.7543 26.9028 19.7543ZM42.8432 40.8081C40.3119 43.5888 36.686 45.3102 32.5811 45.3102C28.5447 45.3102 24.9872 43.5888 22.4559 40.9405L20.0614 46.6343C19.5825 47.6936 20.5403 48.6205 22.1138 48.6205H43.3905C45.0325 48.6205 45.9218 47.6936 45.4429 46.6343L42.8432 40.8081Z" fill="url(#paint1_linear_75_7156)"/> |
| | | </g> |
| | | </g> |
| | | <defs> |
| | | <linearGradient id="paint0_linear_75_7156" x1="32.0977" y1="0.0688477" x2="32.0977" y2="64.0688" gradientUnits="userSpaceOnUse"> |
| | | <stop stop-color="#F5F7F9"/> |
| | | <stop offset="1" stop-color="#F6FAFA"/> |
| | | </linearGradient> |
| | | <linearGradient id="paint1_linear_75_7156" x1="32.6496" y1="15.5171" x2="32.6496" y2="48.6205" gradientUnits="userSpaceOnUse"> |
| | | <stop stop-color="#60FE9D"/> |
| | | <stop offset="1" stop-color="#1FC37E"/> |
| | | </linearGradient> |
| | | <clipPath id="clip0_75_7156"> |
| | | <rect width="34.2069" height="33.1034" fill="white" transform="translate(15.5459 15.5171)"/> |
| | | </clipPath> |
| | | </defs> |
| | | </svg> |
| New file |
| | |
| | | <svg width="65" height="65" viewBox="0 0 65 65" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <g id="Group 1321315693"> |
| | | <g id="Group 1321315478"> |
| | | <circle id="Ellipse 2423" cx="32.123" cy="32.3198" r="32" fill="url(#paint0_linear_549_491)"/> |
| | | </g> |
| | | <g id="Frame"> |
| | | <path id="Vector" d="M30.1342 42.768C30.1342 40.4956 28.3596 38.6526 26.1689 38.6526C23.9801 38.6526 22.2055 40.4956 22.2055 42.768H19.5721C19.2227 42.7715 18.8862 42.6362 18.6365 42.3919C18.3868 42.1475 18.2442 41.814 18.2402 41.4646V22.1169C18.2402 21.3949 18.8349 20.8135 19.5702 20.8135H34.09C34.8253 20.8135 35.4219 21.3968 35.4219 22.1169V42.7699H30.1342V42.768ZM45.9954 42.768C45.9954 40.4956 44.2208 38.6526 42.0301 38.6526C39.8413 38.6526 38.0648 40.4956 38.0648 42.768H36.7443V23.559H40.7609C41.5247 23.559 42.2505 23.8763 42.7559 24.4368L47.9695 30.1995C48.4008 30.6764 48.6402 31.292 48.6402 31.9285V40.1612C48.6402 41.5957 47.4584 42.7585 45.9954 42.768ZM40.0522 26.3026C39.878 26.3011 39.7103 26.3685 39.5857 26.4903C39.4611 26.6121 39.3897 26.7782 39.3872 26.9524V29.7682C39.3872 30.1292 39.6855 30.4199 40.0522 30.4199H43.9472C44.1039 30.42 44.2557 30.3656 44.3766 30.266C44.4431 30.2115 44.4979 30.1444 44.5379 30.0684C44.5779 29.9924 44.6022 29.9091 44.6095 29.8236C44.6167 29.738 44.6068 29.6519 44.5802 29.5702C44.5535 29.4886 44.5108 29.4131 44.4545 29.3483L42.0187 26.5344C41.9553 26.4618 41.877 26.4037 41.7891 26.3641C41.7013 26.3244 41.6059 26.3041 41.5095 26.3045H40.0522V26.3026ZM26.1689 45.5116C24.7097 45.5116 23.5279 44.2842 23.5279 42.768C23.5279 41.2518 24.7097 40.0244 26.1689 40.0244C27.63 40.0244 28.8137 41.2518 28.8137 42.768C28.8137 44.2842 27.63 45.5135 26.1689 45.5135V45.5116ZM42.0301 45.5116C40.5709 45.5116 39.3872 44.2842 39.3872 42.768C39.3872 41.2518 40.5709 40.0244 42.0301 40.0244C43.4912 40.0244 44.6749 41.2518 44.6749 42.768C44.6749 44.2842 43.4912 45.5135 42.0301 45.5135V45.5116Z" fill="url(#paint1_linear_549_491)"/> |
| | | </g> |
| | | </g> |
| | | <defs> |
| | | <linearGradient id="paint0_linear_549_491" x1="32.123" y1="0.319824" x2="32.123" y2="64.3198" gradientUnits="userSpaceOnUse"> |
| | | <stop stop-color="#F5F7F9"/> |
| | | <stop offset="1" stop-color="#F6FAFA"/> |
| | | </linearGradient> |
| | | <linearGradient id="paint1_linear_549_491" x1="33.4402" y1="20.8135" x2="33.4402" y2="45.5135" gradientUnits="userSpaceOnUse"> |
| | | <stop stop-color="#966FF3"/> |
| | | <stop offset="1" stop-color="#3F2FCF"/> |
| | | </linearGradient> |
| | | </defs> |
| | | </svg> |
| New file |
| | |
| | | <svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <g id="Group 1321315493"> |
| | | <circle id="Ellipse 2423" cx="32" cy="32" r="32" fill="url(#paint0_linear_672_6139)"/> |
| | | <g id="Frame" clip-path="url(#clip0_672_6139)"> |
| | | <path id="Vector" d="M43.9078 18.1816H20.0939C19.5018 18.1816 18.9339 18.4115 18.5152 18.8207C18.0965 19.2299 17.8613 19.7848 17.8613 20.3635V43.6362C17.8613 44.2148 18.0965 44.7698 18.5152 45.179C18.9339 45.5881 19.5018 45.818 20.0939 45.818H43.9078C44.5 45.818 45.0678 45.5881 45.4865 45.179C45.9052 44.7698 46.1404 44.2148 46.1404 43.6362V20.3635C46.1404 19.7848 45.9052 19.2299 45.4865 18.8207C45.0678 18.4115 44.5 18.1816 43.9078 18.1816ZM25.3032 38.1816H23.0706V33.5466H25.3032V38.1816ZM30.5125 38.1816H28.2799V30.9693H30.5125V38.1816ZM35.7218 38.1816H33.4892V28.3935H35.7218V38.1816ZM40.9311 38.1816H38.6985V25.818H40.9311V38.1816Z" fill="url(#paint1_linear_672_6139)"/> |
| | | </g> |
| | | </g> |
| | | <defs> |
| | | <linearGradient id="paint0_linear_672_6139" x1="32" y1="0" x2="32" y2="64" gradientUnits="userSpaceOnUse"> |
| | | <stop stop-color="#F5F7F9"/> |
| | | <stop offset="1" stop-color="#F6FAFA"/> |
| | | </linearGradient> |
| | | <linearGradient id="paint1_linear_672_6139" x1="32.0009" y1="18.1816" x2="32.0009" y2="45.818" gradientUnits="userSpaceOnUse"> |
| | | <stop stop-color="#44C0ED"/> |
| | | <stop offset="1" stop-color="#3A8FFF"/> |
| | | </linearGradient> |
| | | <clipPath id="clip0_672_6139"> |
| | | <rect width="28.2791" height="27.6364" fill="white" transform="translate(17.8613 18.1816)"/> |
| | | </clipPath> |
| | | </defs> |
| | | </svg> |
| New file |
| | |
| | | <svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <g id="Group 1321315491"> |
| | | <circle id="Ellipse 2423" cx="32" cy="32" r="32" fill="url(#paint0_linear_672_6148)"/> |
| | | <g id="Frame"> |
| | | <path id="Vector" d="M16.6934 18.9328L31.9906 14.793L47.288 18.9328V31.2374C47.288 40.0922 40.816 47.682 31.9906 49.292C23.1653 47.5672 16.6934 39.9773 16.6934 31.2374V18.9328ZM26.5777 21.6929C25.4011 24.6827 23.5183 27.6726 21.4001 29.6274C21.7531 30.0875 22.3415 31.1225 22.4593 31.5826C23.1653 30.8924 23.7537 30.0875 24.4597 29.2825V40.5523H26.3425V26.5227C27.1661 25.1426 27.8721 23.7627 28.4605 22.2677L26.5777 21.6929ZM41.0514 33.3074V31.5826H35.2853V29.2825H39.8745V22.6127H28.9311V29.3976H33.2851V31.6975H27.4015V33.4223H32.2261C30.8138 35.4924 28.8135 37.3324 26.6955 38.3673C27.1661 38.7123 27.7545 39.4022 28.1074 39.8621C29.9902 38.7122 31.8728 36.8723 33.2851 34.8024V40.6672H35.2854V34.6873C36.5799 36.7574 38.4626 38.7123 40.2276 39.8622C40.5806 39.4023 41.1689 38.7123 41.6396 38.3673C39.757 37.3325 37.7564 35.3773 36.462 33.4224H41.0514V33.3074ZM30.8138 24.2228H37.9917V27.5576H30.8138V24.2228Z" fill="url(#paint1_linear_672_6148)"/> |
| | | </g> |
| | | </g> |
| | | <defs> |
| | | <linearGradient id="paint0_linear_672_6148" x1="32" y1="0" x2="32" y2="64" gradientUnits="userSpaceOnUse"> |
| | | <stop stop-color="#F5F7F9"/> |
| | | <stop offset="1" stop-color="#F6FAFA"/> |
| | | </linearGradient> |
| | | <linearGradient id="paint1_linear_672_6148" x1="31.9907" y1="14.793" x2="31.9907" y2="49.292" gradientUnits="userSpaceOnUse"> |
| | | <stop stop-color="#FF9358"/> |
| | | <stop offset="1" stop-color="#FF4D00"/> |
| | | </linearGradient> |
| | | </defs> |
| | | </svg> |
| New file |
| | |
| | | <svg width="37" height="40" viewBox="0 0 37 40" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <g id="1.1"> |
| | | <rect id="1.1_2" x="0.972656" y="0.30249" width="35.6948" height="39.5287"/> |
| | | </g> |
| | | </svg> |
| New file |
| | |
| | | <svg width="26" height="27" viewBox="0 0 26 27" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <g id="Group 1321315412"> |
| | | <circle id="Ellipse 2459" cx="13" cy="13.1533" r="13" fill="#FF6560" fill-opacity="0.14"/> |
| | | <g id="Frame" clip-path="url(#clip0_596_565)"> |
| | | <path id="Vector" d="M14.9618 16.1737H15.0997L15.6468 15.508C15.4362 15.295 15.2764 15.0335 15.182 14.7503C14.8383 13.7203 15.3926 12.6068 16.4226 12.2594C16.6236 12.1917 16.8342 12.1578 17.0472 12.1578C17.1029 12.1578 17.1585 12.1602 17.2142 12.165V8.37058C17.2142 7.8816 16.8172 7.4834 16.327 7.4834H8.3823C7.89211 7.4834 7.49512 7.8816 7.49512 8.37058V17.9396C7.49512 18.4286 7.89211 18.8268 8.3823 18.8268H13.7163C13.7284 18.8268 13.7405 18.8244 13.7526 18.8195C13.6146 18.5992 13.5348 18.3402 13.5348 18.0643V17.6019C13.5348 16.8152 14.1762 16.1737 14.9618 16.1737ZM9.64591 9.79032H11.908C12.1525 9.79032 12.351 9.98882 12.351 10.2333C12.351 10.4778 12.1525 10.6763 11.908 10.6763H9.64591C9.40141 10.6763 9.20292 10.4778 9.20292 10.2333C9.20292 9.98882 9.40384 9.79032 9.64591 9.79032ZM9.64591 12.4071H13.9487C14.1932 12.4071 14.3917 12.6056 14.3917 12.8501C14.3917 13.0946 14.1956 13.2931 13.9487 13.2931H9.64591C9.40141 13.2931 9.20292 13.0946 9.20292 12.8501C9.20292 12.6056 9.40384 12.4071 9.64591 12.4071ZM13.2854 15.9098H9.64591C9.40141 15.9098 9.20292 15.7113 9.20292 15.4669C9.20292 15.2224 9.40141 15.0239 9.64591 15.0239H13.2818C13.5263 15.0239 13.7248 15.2224 13.7248 15.4669C13.7284 15.7113 13.5299 15.9098 13.2854 15.9098Z" fill="#FF472F"/> |
| | | <path id="Vector_2" d="M19.1302 16.8389H18.6775L17.4563 15.3587C18.1365 15.1311 18.5056 14.3916 18.2781 13.7114C18.0965 13.1692 17.5882 12.8242 17.0447 12.8242C16.9068 12.8242 16.7688 12.846 16.6308 12.892C15.9506 13.1195 15.5814 13.8591 15.809 14.5393C15.9373 14.9242 16.2423 15.2292 16.6308 15.3611L15.412 16.8438H14.9593C14.5381 16.8438 14.1992 17.1851 14.1992 17.6039V18.0638C14.1992 18.485 14.5405 18.8239 14.9593 18.8239H19.129C19.5477 18.8239 19.8891 18.4826 19.8891 18.0638V17.6015C19.8915 17.1815 19.5502 16.8414 19.1302 16.8389Z" fill="#FF472F"/> |
| | | </g> |
| | | </g> |
| | | <defs> |
| | | <clipPath id="clip0_596_565"> |
| | | <rect width="12.394" height="12.394" fill="white" transform="translate(7.49512 6.95801)"/> |
| | | </clipPath> |
| | | </defs> |
| | | </svg> |
| New file |
| | |
| | | <svg width="27" height="27" viewBox="0 0 27 27" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <g id="Group 1321315413"> |
| | | <circle id="Ellipse 2460" cx="13.4912" cy="13.2656" r="13" fill="#FF7411" fill-opacity="0.15"/> |
| | | <g id="Frame" clip-path="url(#clip0_596_590)"> |
| | | <path id="Vector" d="M17.4019 7.90649C17.8313 7.90649 18.1172 8.26415 18.1172 8.76522V12.9836C16.329 12.9836 14.8992 14.4133 14.9709 16.2007C14.9709 17.7739 16.043 19.0611 17.4736 19.347H8.82175C8.39239 19.347 8.10645 18.9894 8.10645 18.4175V8.76522C8.10645 8.26503 8.39239 7.90738 8.82175 7.90738L17.4019 7.90649ZM17.9977 13.6272L18.1482 13.6316C19.4398 13.7078 20.5004 14.7657 20.5004 16.0927C20.5004 17.4711 19.3566 18.6317 17.9977 18.6317H17.9269C17.2819 18.6227 16.6658 18.3626 16.2094 17.9067C16.0678 17.7615 15.9961 17.6889 15.9244 17.5437C15.9245 17.5287 15.9205 17.514 15.9129 17.5012L15.8642 17.4419L15.8527 17.3985C15.8347 17.3794 15.8203 17.3572 15.8102 17.333L15.7517 17.1736L15.7093 17.109C15.7093 17.0364 15.6384 16.9638 15.6384 16.8912L15.6198 16.8186C15.5986 16.7699 15.5667 16.7213 15.5667 16.6735C15.4959 16.5283 15.4959 16.3105 15.4959 16.1653C15.4959 15.8023 15.5667 15.5128 15.7093 15.2225V15.1499C15.7093 15.0773 15.781 14.9321 15.8527 14.8604C15.8527 14.8418 15.8571 14.8285 15.8642 14.8161L15.9129 14.7577L15.9244 14.7152C16.3529 14.0619 17.0682 13.6263 17.9977 13.6263V13.6272ZM17.9977 14.3522C17.7835 14.3522 17.6401 14.4974 17.6401 14.7152V16.4557C17.6401 16.6735 17.7835 16.8186 17.9977 16.8186H19.5709C19.7143 16.8186 19.9285 16.6735 19.9285 16.4557C19.9285 16.2379 19.7851 16.0927 19.5709 16.0927H18.3554V14.7152C18.3554 14.4974 18.212 14.3522 17.9977 14.3522ZM12.6834 13.0544H9.96554C9.89007 13.0533 9.81514 13.0674 9.74521 13.0958C9.67528 13.1243 9.61177 13.1664 9.55844 13.2198C9.50511 13.2733 9.46304 13.3368 9.43473 13.4068C9.40643 13.4768 9.39245 13.5517 9.39365 13.6272C9.39365 13.9131 9.60789 14.1991 9.89383 14.1991H12.6117C12.9684 14.1991 13.2544 13.984 13.2544 13.6272C13.2556 13.5517 13.2416 13.4768 13.2133 13.4068C13.185 13.3368 13.1429 13.2733 13.0896 13.2198C13.0362 13.1664 12.9727 13.1243 12.9028 13.0958C12.8329 13.0674 12.7579 13.0533 12.6825 13.0544H12.6834ZM14.9718 10.195H9.96554C9.89014 10.1939 9.81529 10.2079 9.74542 10.2363C9.67555 10.2647 9.61208 10.3067 9.55876 10.3601C9.50544 10.4134 9.46335 10.4769 9.43499 10.5467C9.40663 10.6166 9.39257 10.6914 9.39365 10.7668C9.39365 11.0528 9.60789 11.3387 9.89383 11.3387H14.8992C14.9746 11.3398 15.0495 11.3258 15.1193 11.2974C15.1892 11.269 15.2527 11.2269 15.306 11.1736C15.3593 11.1203 15.4014 11.0568 15.4298 10.987C15.4581 10.9171 15.4722 10.8422 15.4711 10.7668C15.4711 10.4092 15.2569 10.195 14.9709 10.195H14.9718Z" fill="#FF7411"/> |
| | | </g> |
| | | </g> |
| | | <defs> |
| | | <clipPath id="clip0_596_590"> |
| | | <rect width="14.1645" height="14.1645" fill="white" transform="translate(6.57715 6.57861)"/> |
| | | </clipPath> |
| | | </defs> |
| | | </svg> |
| New file |
| | |
| | | <svg width="27" height="27" viewBox="0 0 27 27" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <g id="Group 1321315415"> |
| | | <circle id="Ellipse 2461" cx="13.8438" cy="13.8865" r="13" fill="#FFC300" fill-opacity="0.15"/> |
| | | <g id="Frame" clip-path="url(#clip0_596_578)"> |
| | | <path id="Vector" d="M9.37686 20.0792H18.3235C18.9836 20.0792 19.3574 19.7027 19.3574 18.9682V9.53491C19.3574 8.88991 18.899 8.42389 18.3235 8.42389H16.9502C16.9502 9.21275 16.7809 9.89423 15.9177 9.89423H11.782C10.9188 9.89423 10.7488 9.37383 10.7488 8.42389H9.37686C8.73324 8.42389 8.34294 8.81832 8.34294 9.53491V18.9675C8.34294 19.7206 8.81653 20.0792 9.37617 20.0792H9.37686ZM16.71 13.4482C17.2531 13.4482 17.6937 13.9108 17.6937 14.4808C17.6937 15.0514 17.2531 15.5133 16.7093 15.5133C16.1669 15.5133 15.727 15.0514 15.727 14.4808C15.727 13.9108 16.1676 13.4482 16.71 13.4482ZM13.9565 13.4482C14.5003 13.4482 14.9395 13.9108 14.9395 14.4808C14.9395 15.0514 14.4997 15.5133 13.9558 15.5133C13.4134 15.5133 12.9729 15.0514 12.9729 14.4808C12.9729 13.9108 13.4134 13.4482 13.9558 13.4482H13.9565ZM11.2024 13.4482C11.7462 13.4482 12.1861 13.9108 12.1861 14.4808C12.1861 15.0514 11.7455 15.5133 11.2017 15.5133C10.6593 15.5133 10.2194 15.0514 10.2194 14.4808C10.2194 13.9108 10.66 13.4482 11.2024 13.4482ZM12.3933 9.15906H15.2906C15.6465 9.15906 15.9184 8.83622 15.9184 8.42389C15.9184 8.01156 15.6465 7.68872 15.2906 7.68872H12.4105C12.0546 7.68872 11.7827 8.01087 11.7827 8.42389C11.7827 8.83622 12.0718 9.15906 12.3933 9.15906Z" fill="#FFC300"/> |
| | | </g> |
| | | </g> |
| | | <defs> |
| | | <clipPath id="clip0_596_578"> |
| | | <rect width="12.394" height="12.394" fill="white" transform="matrix(-1 0 0 1 20.041 7.68872)"/> |
| | | </clipPath> |
| | | </defs> |
| | | </svg> |
| New file |
| | |
| | | <svg width="27" height="27" viewBox="0 0 27 27" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <g id="Group 1321315414"> |
| | | <circle id="Ellipse 2462" cx="13.7402" cy="13.614" r="13" fill="#0291A1" fill-opacity="0.15"/> |
| | | <g id="Frame" clip-path="url(#clip0_596_602)"> |
| | | <path id="Vector" d="M19.9149 11.7499V10.3707C19.9149 9.62518 19.2191 9.02878 18.3494 9.02878H17.3274V8.73058C17.3274 8.52557 17.1317 8.37646 16.9143 8.37646C16.6751 8.37646 16.5011 8.5442 16.5011 8.73058V9.04742H11V8.73058C11 8.52557 10.8043 8.37646 10.5868 8.37646C10.3694 8.37646 10.1737 8.5442 10.1737 8.73058V9.04742H9.17349C8.30374 9.04742 7.60794 9.64382 7.60794 10.3893V11.7685H19.9149V11.7499ZM7.56445 12.4208V17.5089C7.56445 18.2544 8.26025 18.8508 9.13001 18.8508H18.3276C19.1974 18.8508 19.8932 18.2544 19.8932 17.5089V12.4208H7.56445ZM16.5881 14.2659L13.1744 17.2107L11.3044 15.6078C11.1739 15.496 11.1739 15.3283 11.3044 15.2164C11.4348 15.1046 11.6305 15.1046 11.761 15.2164L13.1309 16.3906L16.1098 13.8373C16.2402 13.7254 16.4359 13.7254 16.5664 13.8373L16.6316 13.8932C16.7403 13.9864 16.7403 14.1355 16.5881 14.2659Z" fill="#0291A1"/> |
| | | </g> |
| | | </g> |
| | | <defs> |
| | | <clipPath id="clip0_596_602"> |
| | | <rect width="12.394" height="10.6234" fill="white" transform="translate(7.54297 8.302)"/> |
| | | </clipPath> |
| | | </defs> |
| | | </svg> |
| | |
| | | * isSerialize是否开启form表单提交 |
| | | * isToken是否需要token |
| | | */ |
| | | |
| | | import axios from 'axios'; |
| | | import store from '@/store/'; |
| | | import router from '@/router/'; |
| | |
| | | config.url = baseUrl + config.url; |
| | | } |
| | | //安全请求header |
| | | console.log('selectedAreaCode',store.state.user.userInfo.detail.areaCode); |
| | | |
| | | config.headers['areaCode'] = store.state.user.userInfo.detail.areaCode |
| | | config.headers['Blade-Requested-With'] = 'BladeHttpRequest'; |
| | | //headers判断是否需要 |
| | | const authorization = config.authorization === false; |
| | |
| | | menu: true, |
| | | }, |
| | | fistPage: { |
| | | name: '事件工单', |
| | | name: '个人工作台', |
| | | path: '/wel/index', |
| | | // path: '/tickets/ticket', |
| | | |
| | | |
| | | }, |
| | | //配置菜单的属性 |
| | | menu: { |
| | |
| | | // 报表设计器地址(cloud端口为8108,boot端口为80) |
| | | reportUrl: 'http://localhost:8108/ureport', |
| | | }, |
| | | }; |
| | | } |
| | |
| | | import Store from '@/store/'; |
| | | import Store from '@/store/' |
| | | |
| | | export default [ |
| | | { |
| | |
| | | path: '/', |
| | | name: '主页', |
| | | redirect: '/wel', |
| | | |
| | | }, |
| | | // { |
| | | // path: '/', |
| | | // name: '主页', |
| | | // redirect: '/tickets/ticket', |
| | | // }, |
| | | ]; |
| | | ] |
| | |
| | | >远程调试 |
| | | </el-button> |
| | | </template> |
| | | <!-- 添加行政区划显示模板 --> |
| | | <template #area_code="{ row }"> |
| | | <span>{{ row.area_name }}</span> |
| | | </template> |
| | | </avue-crud> |
| | | |
| | | <el-dialog title="固件升级" append-to-body v-model="firmwareBox" width="455px"> |
| | |
| | | props: { |
| | | label: 'title', |
| | | value: 'value', |
| | | emitPath: false, |
| | | checkStrictly: true, |
| | | multiple: false, |
| | | expandTrigger: 'hover', |
| | | }, |
| | | dataType: 'string', |
| | | rules: [ |
| | | { |
| | | required: true, |
| | | message: '请选择所在省份', |
| | | trigger: 'blur', |
| | | message: '请选择行政区划', |
| | | trigger: 'change', |
| | | }, |
| | | ], |
| | | change: ({ value }) => { |
| | | if (!value) { |
| | | this.form.area_code = null; |
| | | } else { |
| | | if (typeof value === 'string' && value.includes(',')) { |
| | | const codes = value.split(','); |
| | | this.form.area_code = codes[codes.length - 1]; |
| | | } else { |
| | | this.form.area_code = value; |
| | | } |
| | | } |
| | | }, |
| | | lazy: true, |
| | | lazyLoad(node, resolve) { |
| | | let level = node.level; |
| | | let list = []; |
| | | let callback = () => { |
| | | resolve( |
| | | (list || []).map(ele => { |
| | | return Object.assign(ele, { |
| | | leaf: !ele.hasChildren, |
| | | }); |
| | | }) |
| | | (list || []).map(ele => ({ |
| | | ...ele, |
| | | value: ele.value, |
| | | leaf: level >= 2, |
| | | })) |
| | | ); |
| | | }; |
| | | if (level == 0) { |
| | | |
| | | if (level === 0) { |
| | | getLazyTree('000000000000').then(res => { |
| | | list = res.data.data; |
| | | callback(); |
| | | }); |
| | | } else if (level > 0 && level < 5) { |
| | | } else if (level === 1) { |
| | | getLazyTree(node.value).then(res => { |
| | | list = res.data.data; |
| | | callback(); |
| | | }); |
| | | } else if (level === 2) { |
| | | getLazyTree(node.value).then(res => { |
| | | list = res.data.data; |
| | | callback(); |
| | |
| | | this.ossSetBox = false; |
| | | }, |
| | | rowSave(row, done, loading) { |
| | | let areaCode = row.area_code; |
| | | if (Array.isArray(areaCode)) { |
| | | areaCode = areaCode[areaCode.length - 1]; |
| | | } else if (typeof areaCode === 'string' && areaCode.includes(',')) { |
| | | const codes = areaCode.split(','); |
| | | areaCode = codes[codes.length - 1]; |
| | | } |
| | | row.area_code = areaCode || null; |
| | | |
| | | add(row).then( |
| | | () => { |
| | | this.onLoad(this.page); |
| | |
| | | ); |
| | | }, |
| | | rowUpdate(row, index, done, loading) { |
| | | update(row).then( |
| | | const submitData = { |
| | | ...row, |
| | | area_code: row.area_code.split(',').pop(), |
| | | }; |
| | | |
| | | update(submitData).then( |
| | | () => { |
| | | this.onLoad(this.page); |
| | | this.$message({ |
| | |
| | | this.$refs.crud.toggleSelection(); |
| | | }); |
| | | }, |
| | | getFullAreaCode(areaCode) { |
| | | if (!areaCode) return ''; |
| | | |
| | | const code = areaCode.toString(); |
| | | |
| | | if (code.includes(',')) return code; |
| | | |
| | | if (code.endsWith('0000000000')) { |
| | | return code; |
| | | } else if (code.endsWith('00000000') && !code.endsWith('0000000000')) { |
| | | const provinceCode = code.substring(0, 2) + '0000000000'; |
| | | return `${provinceCode},${code}`; |
| | | } else { |
| | | const provinceCode = code.substring(0, 2) + '0000000000'; |
| | | const cityCode = code.substring(0, 4) + '00000000'; |
| | | return `${provinceCode},${cityCode},${code}`; |
| | | } |
| | | }, |
| | | beforeOpen(done, type) { |
| | | if (['edit', 'view'].includes(type)) { |
| | | getDetail(this.form.id).then(res => { |
| | | this.form = res.data.data; |
| | | const data = res.data.data; |
| | | this.form = { |
| | | ...data, |
| | | area_code: this.getFullAreaCode(data.area_code), |
| | | }; |
| | | }); |
| | | } |
| | | done(); |
| | |
| | | viewDisplay: false, |
| | | rules: [{ required: true, validator: validatePass2, trigger: 'blur' }], |
| | | }, |
| | | { |
| | | label: '到期时间', |
| | | prop: 'expireTime', |
| | | type: 'datetime', |
| | | format: 'YYYY-MM-DD HH:mm:ss', |
| | | valueFormat: 'YYYY-MM-DD HH:mm:ss', |
| | | }, |
| | | ], |
| | | }, |
| | | { |
| | |
| | | <template> |
| | | <basic-container> |
| | | <el-tabs v-model="activeTab" @tab-click="handleTabChange"> |
| | | <el-tab-pane v-for="tab in filteredTabs" :key="tab.name" :label="`${tab.label} (${tab.count})`" :name="tab.name"> |
| | | <el-tab-pane |
| | | v-for="tab in filteredTabs" |
| | | :key="tab.name" |
| | | :label="`${tab.label} (${tab.count})`" |
| | | :name="tab.name" |
| | | > |
| | | <div class="tab-content"> |
| | | <!-- 查询条件筛选栏 --> |
| | | <div class="filter-bar"> |
| | | <div class="search-bar-box"> |
| | | <div class="search-bar-box-item"> |
| | | <el-input v-model="filters.key_word" placeholder="输入工单编号/名称/内容/姓名" clearable |
| | | @keyup.enter="handleSearch" /> |
| | | <el-input |
| | | v-model="filters.key_word" |
| | | placeholder="输入工单编号/名称/内容/姓名" |
| | | clearable |
| | | @keyup.enter="handleSearch" |
| | | /> |
| | | </div> |
| | | |
| | | <div class="search-bar-box-item"> |
| | | <el-select placeholder="请选择所属单位" v-model="filters.create_dept" @change="handleDepartmentChange" |
| | | clearable> |
| | | <el-option v-for="dept in departments" :key="dept.value" :label="dept.label" :value="dept.value" /> |
| | | <el-select placeholder="请选择所属单位" v-model="filters.create_dept" clearable> |
| | | <el-option |
| | | v-for="dept in departments" |
| | | :key="dept.value" |
| | | :label="dept.label" |
| | | :value="dept.value" |
| | | /> |
| | | </el-select> |
| | | </div> |
| | | |
| | | <div class="search-bar-box-item"> |
| | | <el-date-picker v-model="filters.dateRange" type="daterange" range-separator="至" |
| | | start-placeholder="开始日期" end-placeholder="结束日期" :default-value="datePickerDefaultVal" /> |
| | | <el-date-picker |
| | | v-model="filters.dateRange" |
| | | type="daterange" |
| | | range-separator="至" |
| | | start-placeholder="开始日期" |
| | | end-placeholder="结束日期" |
| | | :default-value="datePickerDefaultVal" |
| | | /> |
| | | </div> |
| | | |
| | | <div class="search-bar-box-item"> |
| | | <el-select v-model="filters.file_id" placeholder="请选择关联航线" clearable> |
| | | <el-option v-for="item in wayLineList" :key="item.wayline_id" :label="item.name" |
| | | :value="item.wayline_id" /> |
| | | <el-option |
| | | v-for="item in wayLineList" |
| | | :key="item.wayline_id" |
| | | :label="item.name" |
| | | :value="item.wayline_id" |
| | | /> |
| | | </el-select> |
| | | </div> |
| | | |
| | | <div class="search-bar-box-item"> |
| | | <el-select v-model="filters.ai_types" placeholder="关联算法" clearable> |
| | | <el-option v-for="item in ai_types" :key="item.dictKey" :label="item.dictValue" |
| | | :value="item.dictKey" /> |
| | | <el-option |
| | | v-for="item in ai_types" |
| | | :key="item.dictKey" |
| | | :label="item.dictValue" |
| | | :value="item.dictKey" |
| | | /> |
| | | </el-select> |
| | | </div> |
| | | |
| | | <div class="search-bar-box-item"> |
| | | <el-select v-model="filters.type" placeholder="请选择工单类型" clearable> |
| | | <el-option v-for="item in types" :key="item.dictValue" :label="item.dictValue" |
| | | :value="item.dictKey" /> |
| | | <el-option |
| | | v-for="item in types" |
| | | :key="item.dictValue" |
| | | :label="item.dictValue" |
| | | :value="item.dictKey" |
| | | /> |
| | | </el-select> |
| | | </div> |
| | | |
| | | <div class="search-bar-box-item"> |
| | | <el-select v-model="filters.status" placeholder="请选择工单状态" clearable> |
| | | <el-option v-for="item in statuses" :key="item.value" :label="item.label" :value="item.value" /> |
| | | <el-option |
| | | v-for="item in statuses" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" |
| | | /> |
| | | </el-select> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="search-bar-box"> |
| | | <div class="search-bar-box-item flex-2"> |
| | | <el-date-picker v-model="filters.cycleDateRange" type="daterange" range-separator="至" |
| | | start-placeholder="工单周期开始日期" end-placeholder="工单周期结束日期" :default-value="datePickerDefaultVal" /> |
| | | <el-date-picker |
| | | v-model="filters.cycleDateRange" |
| | | type="daterange" |
| | | range-separator="至" |
| | | start-placeholder="工单周期开始日期" |
| | | end-placeholder="工单周期结束日期" |
| | | :default-value="datePickerDefaultVal" |
| | | /> |
| | | </div> |
| | | |
| | | <div class="search-bar-box-item"> |
| | |
| | | </div> |
| | | |
| | | <div class="search-bar-box-item"> |
| | | <el-time-picker v-model="filters.deal_time" placeholder="请选择执行时间" prop="deal_time" value-format="HH:mm" |
| | | <el-time-picker |
| | | v-model="filters.deal_time" |
| | | placeholder="请选择执行时间" |
| | | prop="deal_time" |
| | | value-format="HH:mm" |
| | | :picker-options="{ |
| | | selectableRange: '00:00 - 23:59', |
| | | }" /> |
| | | }" |
| | | /> |
| | | </div> |
| | | |
| | | <div class="search-bar-box-item"></div> |
| | | <div class="search-bar-box-item"></div> |
| | | |
| | | <div class="search-bar-box-item search-btn"> |
| | | <el-button type="primary" icon="el-icon-search" @click="handleSearch">搜索</el-button> |
| | | <el-button type="primary" icon="el-icon-search" @click="handleSearch" |
| | | >搜索</el-button |
| | | > |
| | | <el-button icon="el-icon-refresh" @click="handleReset">清空</el-button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 表格部分 --> |
| | | <avue-crud :data="tableData" :option="option" v-model:page="page" ref="crud" :table-loading="loading" |
| | | @current-change="currentChange" @refresh-change="refreshChange" @on-load="onLoad" |
| | | @search-change="searchChange" @size-change="sizeChange"> |
| | | <avue-crud |
| | | :data="tableData" |
| | | :option="option" |
| | | v-model:page="page" |
| | | ref="crud" |
| | | :table-loading="loading" |
| | | @current-change="currentChange" |
| | | @refresh-change="refreshChange" |
| | | @on-load="onLoad" |
| | | @search-change="searchChange" |
| | | @size-change="sizeChange" |
| | | > |
| | | <template #menu-left> |
| | | <el-button v-if="hasAddBtnPermission() && activeTab != 'WAIT_AUDIT'" type="primary" icon="el-icon-plus" |
| | | @click="handleAdd">新建工单</el-button> |
| | | <el-button type="success" plain icon="el-icon-download" @click="exportData">导出</el-button> |
| | | <el-button |
| | | v-if="hasAddBtnPermission() && activeTab != 'WAIT_AUDIT'" |
| | | type="primary" |
| | | icon="el-icon-plus" |
| | | @click="handleAdd" |
| | | >新建工单</el-button |
| | | > |
| | | <el-button type="success" plain icon="el-icon-download" @click="exportData" |
| | | >导出</el-button |
| | | > |
| | | </template> |
| | | |
| | | <template #menu="{ row }"> |
| | | <div class="menu-custom-box"> |
| | | <template v-if="row.status == 1"> |
| | | <el-button v-if="hasPaddingBtnPermission()" type="text" icon="el-icon-view" |
| | | @click="handleCheckDetail(row)">审核</el-button> |
| | | <el-button |
| | | v-if="hasPaddingBtnPermission()" |
| | | type="text" |
| | | icon="el-icon-view" |
| | | @click="handleCheckDetail(row)" |
| | | >审核</el-button |
| | | > |
| | | </template> |
| | | |
| | | <template v-if=" |
| | | (userInfo.user_id == row.create_user || hasRecallPaddingBtnPermission()) && |
| | | row.status == 1 |
| | | "> |
| | | <template |
| | | v-if=" |
| | | (userInfo.user_id == row.create_user || hasRecallPaddingBtnPermission()) && |
| | | row.status == 1 |
| | | " |
| | | > |
| | | <!--待审核状态--> |
| | | <el-button type="text" icon="el-icon-warning" @click="orderLogRecall(row.id)">撤回</el-button> |
| | | <el-button type="text" icon="el-icon-warning" @click="orderLogRecall(row.id)" |
| | | >撤回</el-button |
| | | > |
| | | </template> |
| | | <!--已驳回--> |
| | | <template v-if="row.status == 2"> |
| | | <el-button type="text" icon="el-icon-warning" @click="rejectDetail(row.id)">驳回原因</el-button> |
| | | <el-button type="text" icon="el-icon-warning" @click="rejectDetail(row.id)" |
| | | >驳回原因</el-button |
| | | > |
| | | <el-button type="text" icon="el-icon-view" @click="handleViewDetail(row)" |
| | | >详情</el-button |
| | | > |
| | | </template> |
| | | <!-- 已通过 --> |
| | | <template v-if="row.status == 3"> |
| | | <el-button type="text" icon="el-icon-view" @click="handleViewDetail(row)" |
| | | >详情</el-button |
| | | > |
| | | </template> |
| | | <!--草稿--> |
| | | <el-button type="text" icon="el-icon-edit" @click="handleViewDetail(row)">编辑</el-button> |
| | | <el-button type="text" icon="el-icon-position" @click="userPublishPush(row.id)">发起</el-button> |
| | | <el-button type="text" icon="el-icon-delete" @click="deleteOrderLog(row.id)">删除</el-button> |
| | | <template v-if="row.status == 3 || row.status == 1 || row.status == 2"> |
| | | <el-button type="text" icon="el-icon-view" @click="handleViewDetail(row)">详情</el-button> |
| | | <template v-if="row.status == 0"> |
| | | <el-button type="text" icon="el-icon-edit" @click="handleViewDetail(row)" |
| | | >编辑</el-button |
| | | > |
| | | <el-button type="text" icon="el-icon-position" @click="userPublishPush(row.id)" |
| | | >发布</el-button |
| | | > |
| | | <el-button type="text" icon="el-icon-delete" @click="deleteOrderLog(row.id)" |
| | | >删除</el-button |
| | | > |
| | | </template> |
| | | </div> |
| | | </template> |
| | |
| | | </el-tabs> |
| | | |
| | | <!-- 新建工单对话框 --> |
| | | <el-dialog v-model="dialogVisible" title="新建工单" width="70%" :close-on-click-modal="false" @close="resetForm"> |
| | | <el-dialog |
| | | v-model="dialogVisible" |
| | | title="新建工单" |
| | | width="70%" |
| | | :close-on-click-modal="false" |
| | | @close="resetForm" |
| | | > |
| | | <el-form :model="form" :rules="rules" ref="testform" label-width="100px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="工单名称" prop="name"> |
| | | <el-input v-model="form.name" placeholder="请输入工单名称" maxlength="100" show-word-limit></el-input> |
| | | <el-input |
| | | v-model="form.name" |
| | | placeholder="请输入工单名称" |
| | | maxlength="100" |
| | | show-word-limit |
| | | ></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="关联航线" prop="file_id"> |
| | | <el-select v-model="form.file_id" placeholder="请选择航线" @change="getFlyingNestBy"> |
| | | <el-option v-for="item in wayLineList" :key="item.wayline_id" :label="item.name" |
| | | :value="item.wayline_id" /> |
| | | <el-option |
| | | v-for="item in wayLineList" |
| | | :key="item.wayline_id" |
| | | :label="item.name" |
| | | :value="item.wayline_id" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | <el-col :span="12"> |
| | | <el-form-item label="关联机巢" prop="device_sns"> |
| | | <el-select v-model="form.device_sns" placeholder="请选择机巢" multiple> |
| | | <el-option v-for="item in device_sns" :key="item.device_sn" :label="item.nickname" |
| | | :value="item.device_sn" /> |
| | | <el-option |
| | | v-for="item in device_sns" |
| | | :key="item.device_sn" |
| | | :label="item.nickname" |
| | | :value="item.device_sn" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="关联算法" prop="ai_types"> |
| | | <el-select v-model="form.ai_types" placeholder="请选择关联算法" multiple> |
| | | <el-option v-for="item in ai_types" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" /> |
| | | <el-option |
| | | v-for="item in ai_types" |
| | | :key="item.dictKey" |
| | | :label="item.dictValue" |
| | | :value="item.dictKey" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="工单内容" prop="content"> |
| | | <el-input type="textarea" v-model="form.content" rows="4" placeholder="请输入工单内容" maxlength="255" |
| | | show-word-limit></el-input> |
| | | <el-input |
| | | type="textarea" |
| | | v-model="form.content" |
| | | rows="4" |
| | | placeholder="请输入工单内容" |
| | | maxlength="255" |
| | | show-word-limit |
| | | ></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="8"> |
| | | <el-form-item label="周期频次" prop="date_range"> |
| | | <el-date-picker v-model="form.date_range" type="daterange" range-separator="至" start-placeholder="开始日期" |
| | | end-placeholder="结束日期" /> |
| | | <el-date-picker |
| | | v-model="form.date_range" |
| | | type="daterange" |
| | | range-separator="至" |
| | | start-placeholder="开始日期" |
| | | end-placeholder="结束日期" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | |
| | | </el-select> |
| | | </div> |
| | | <div class="flex-1"> |
| | | <el-time-picker style="width: 100px" v-model="form.deal_time" prop="deal_time" value-format="HH:mm" |
| | | <el-time-picker |
| | | style="width: 100px" |
| | | v-model="form.deal_time" |
| | | prop="deal_time" |
| | | value-format="HH:mm" |
| | | :picker-options="{ |
| | | selectableRange: '00:00 - 23:59', |
| | | }" /> |
| | | }" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </el-col> |
| | |
| | | </el-dialog> |
| | | |
| | | <!-- 工单详情对话框 --> |
| | | <el-dialog v-model="detailVisible" :title="detailTitle" width="70%" :close-on-click-modal="false" |
| | | @close="resetForm"> |
| | | <el-dialog |
| | | v-model="detailVisible" |
| | | :title="detailTitle" |
| | | width="70%" |
| | | :close-on-click-modal="false" |
| | | @close="resetForm" |
| | | > |
| | | <div class="event-title-center">{{ form.name }}</div> |
| | | <el-form :model="form" ref="testform" label-width="100px"> |
| | | <div class="custom-steps-container"> |
| | | <!-- 标题行 --> |
| | | <div class="steps-titles"> |
| | | <div v-for="(record, index) in form.record_list" :class="{ active: record.user_id >= 0 }" :key="index" |
| | | class="step-title"> |
| | | <div |
| | | v-for="(record, index) in form.record_list" |
| | | :class="{ active: record.user_id >= 0 }" |
| | | :key="index" |
| | | class="step-title" |
| | | > |
| | | {{ record.status_str }} |
| | | </div> |
| | | </div> |
| | |
| | | <span class="step-description" style="position: relative; display: inline-block"> |
| | | {{ record.user_name }} |
| | | </span> |
| | | <span style=" |
| | | <span |
| | | style=" |
| | | position: absolute; |
| | | left: 80%; |
| | | top: 50%; |
| | |
| | | margin-left: 4px; |
| | | color: #666; |
| | | font-size: 12px; |
| | | "> |
| | | " |
| | | > |
| | | {{ record.interval_time_str }} |
| | | </span> |
| | | <div class="step-description"> |
| | |
| | | <el-col :span="12"> |
| | | <el-form-item label="关联航线" prop="file_id"> |
| | | <el-select v-model="form.file_id" placeholder="请选择航线" @change="getFlyingNestBy"> |
| | | <el-option v-for="item in wayLineList" :key="item.wayline_id" :label="item.name" |
| | | :value="item.wayline_id" /> |
| | | <el-option |
| | | v-for="item in wayLineList" |
| | | :key="item.wayline_id" |
| | | :label="item.name" |
| | | :value="item.wayline_id" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | <el-col :span="12"> |
| | | <el-form-item label="关联机巢" prop="device_sns"> |
| | | <el-select v-model="form.device_sns" placeholder="请选择机巢" multiple> |
| | | <el-option v-for="item in device_sns" :key="item.device_sn" :label="item.nickname" |
| | | :value="item.device_sn" /> |
| | | <el-option |
| | | v-for="item in device_sns" |
| | | :key="item.device_sn" |
| | | :label="item.nickname" |
| | | :value="item.device_sn" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="关联算法" prop="ai_types"> |
| | | <el-select v-model="form.ai_types" placeholder="请选择关联算法" multiple> |
| | | <el-option v-for="item in ai_types" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" /> |
| | | <el-option |
| | | v-for="item in ai_types" |
| | | :key="item.dictKey" |
| | | :label="item.dictValue" |
| | | :value="item.dictKey" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | |
| | | <el-col :span="6"> |
| | | <el-form-item label="周期频次" prop="date_range"> |
| | | <el-date-picker v-model="form.date_range" type="daterange" range-separator="至" start-placeholder="开始日期" |
| | | end-placeholder="结束日期" /> |
| | | <el-date-picker |
| | | v-model="form.date_range" |
| | | type="daterange" |
| | | range-separator="至" |
| | | start-placeholder="开始日期" |
| | | end-placeholder="结束日期" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | |
| | | </el-col> |
| | | |
| | | <el-col :span="3"> |
| | | <el-time-picker style="width: 100px" v-model="form.deal_time" prop="deal_time" value-format="HH:mm" |
| | | <el-time-picker |
| | | style="width: 100px" |
| | | v-model="form.deal_time" |
| | | prop="deal_time" |
| | | value-format="HH:mm" |
| | | :picker-options="{ |
| | | selectableRange: '00:00 - 23:59', |
| | | }" /> |
| | | }" |
| | | /> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="工单内容" prop="content"> |
| | | <el-input type="textarea" v-model="form.content" rows="4" placeholder="请输入工单内容" maxlength="255" |
| | | show-word-limit></el-input> |
| | | <el-input |
| | | type="textarea" |
| | | v-model="form.content" |
| | | rows="4" |
| | | placeholder="请输入工单内容" |
| | | maxlength="255" |
| | | show-word-limit |
| | | ></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | |
| | | <el-row> |
| | | <div class="add-box-btns"> |
| | | <el-button type="danger" |
| | | <el-button |
| | | type="danger" |
| | | v-if="form.status == 0 || (form.status == 2 && userInfo.user_id == form.create_user)" |
| | | @click="submitForm(1)">发布</el-button> |
| | | @click="submitForm(1)" |
| | | >发布</el-button |
| | | > |
| | | <!-- <el-button type="primary" v-if="form.status == 0 || userInfo.user_id == form.create_user" |
| | | @click="submitForm(0)">保存</el-button> --> |
| | | |
| | | <el-button type="primary" v-if="form.status == 1 && this.permission.orderLogpass" |
| | | @click="orderLogPass(form.id)">通过</el-button> |
| | | <el-button type="danger" v-if="form.status == 1 && hasRejectionBtnPermission()" |
| | | @click="orderLogReject(form.id)">驳回</el-button> |
| | | <el-button |
| | | type="primary" |
| | | v-if="form.status == 1 && this.permission.orderLogpass" |
| | | @click="orderLogPass(form.id)" |
| | | >通过</el-button |
| | | > |
| | | <el-button |
| | | type="danger" |
| | | v-if="form.status == 1 && hasRejectionBtnPermission()" |
| | | @click="orderLogReject(form.id)" |
| | | >驳回</el-button |
| | | > |
| | | </div> |
| | | </el-row> |
| | | </el-form> |
| | | </el-dialog> |
| | | |
| | | <!-- 工单详情 --> |
| | | <el-dialog v-model="detailVisibleCopy" title="工单详情" width="70%" :close-on-click-modal="false" @close="resetForm"> |
| | | <el-dialog |
| | | v-model="detailVisibleCopy" |
| | | title="工单详情" |
| | | width="70%" |
| | | :close-on-click-modal="false" |
| | | @close="resetForm" |
| | | > |
| | | <div class="event-title-center">{{ form.name }}</div> |
| | | <el-form :model="form" ref="testform" label-width="100px"> |
| | | <div class="custom-steps-container"> |
| | | <!-- 标题行 --> |
| | | <div class="steps-titles"> |
| | | <div v-for="(record, index) in form.record_list" :class="{ active: record.user_id >= 0 }" :key="index" |
| | | class="step-title"> |
| | | <div |
| | | v-for="(record, index) in form.record_list" |
| | | :class="{ active: record.user_id >= 0 }" |
| | | :key="index" |
| | | class="step-title" |
| | | > |
| | | {{ record.status_str }} |
| | | </div> |
| | | </div> |
| | |
| | | <span class="step-description" style="position: relative; display: inline-block"> |
| | | {{ record.user_name }} |
| | | </span> |
| | | <span style=" |
| | | <span |
| | | style=" |
| | | position: absolute; |
| | | left: 80%; |
| | | top: 50%; |
| | |
| | | margin-left: 4px; |
| | | color: #666; |
| | | font-size: 12px; |
| | | "> |
| | | " |
| | | > |
| | | {{ record.interval_time_str }} |
| | | </span> |
| | | <div class="step-description"> |
| | |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="工单名称" prop="name"> |
| | | <el-input v-model="form.name" placeholder="请输入工单名称" :disabled="true"></el-input> |
| | | <el-input |
| | | v-model="form.name" |
| | | placeholder="请输入工单名称" |
| | | :disabled="true" |
| | | ></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="关联航线" prop="file_id"> |
| | | <el-select v-model="form.file_id" placeholder="请选择航线" :disabled="true"> |
| | | <el-option v-for="item in wayLineList" :key="item.wayline_id" :label="item.name" |
| | | :value="item.wayline_id" /> |
| | | <el-option |
| | | v-for="item in wayLineList" |
| | | :key="item.wayline_id" |
| | | :label="item.name" |
| | | :value="item.wayline_id" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="关联机巢" prop="device_sns"> |
| | | <el-select v-model="form.device_sns" placeholder="请选择机巢" multiple :disabled="true"> |
| | | <el-option v-for="item in device_sns" :key="item.device_sn" :label="item.nickname" |
| | | :value="item.device_sn" /> |
| | | <el-select |
| | | v-model="form.device_sns" |
| | | placeholder="请选择机巢" |
| | | multiple |
| | | :disabled="true" |
| | | > |
| | | <el-option |
| | | v-for="item in device_sns" |
| | | :key="item.device_sn" |
| | | :label="item.nickname" |
| | | :value="item.device_sn" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="关联算法" prop="ai_types"> |
| | | <el-select v-model="form.ai_types" placeholder="请选择关联算法" multiple :disabled="true"> |
| | | <el-option v-for="item in ai_types" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" /> |
| | | <el-select |
| | | v-model="form.ai_types" |
| | | placeholder="请选择关联算法" |
| | | multiple |
| | | :disabled="true" |
| | | > |
| | | <el-option |
| | | v-for="item in ai_types" |
| | | :key="item.dictKey" |
| | | :label="item.dictValue" |
| | | :value="item.dictKey" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | |
| | | <el-col :span="6"> |
| | | <el-form-item label="周期频次" prop="date_range"> |
| | | <el-date-picker v-model="form.date_range" type="daterange" range-separator="至" start-placeholder="开始日期" |
| | | end-placeholder="结束日期" :disabled="true" /> |
| | | <el-date-picker |
| | | v-model="form.date_range" |
| | | type="daterange" |
| | | range-separator="至" |
| | | start-placeholder="开始日期" |
| | | end-placeholder="结束日期" |
| | | :disabled="true" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="3"> |
| | |
| | | </el-col> |
| | | |
| | | <el-col :span="3"> |
| | | <el-time-picker style="width: 100px" v-model="form.deal_time" prop="deal_time" :disabled="true" |
| | | value-format="HH:mm" :picker-options="{ |
| | | <el-time-picker |
| | | style="width: 100px" |
| | | v-model="form.deal_time" |
| | | prop="deal_time" |
| | | :disabled="true" |
| | | value-format="HH:mm" |
| | | :picker-options="{ |
| | | selectableRange: '00:00 - 23:59', |
| | | }" /> |
| | | }" |
| | | /> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="工单内容" prop="content"> |
| | | <el-input type="textarea" v-model="form.content" rows="2" placeholder="请输入工单内容" maxlength="255" |
| | | show-word-limit :readonly="true" :disabled="true"></el-input> |
| | | <el-input |
| | | type="textarea" |
| | | v-model="form.content" |
| | | rows="2" |
| | | placeholder="请输入工单内容" |
| | | maxlength="255" |
| | | show-word-limit |
| | | :readonly="true" |
| | | :disabled="true" |
| | | ></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | |
| | | <el-row> |
| | | <div class="add-box-btns"> |
| | | <el-button type="danger" |
| | | <el-button |
| | | type="danger" |
| | | v-if="form.status == 0 || (form.status == 2 && userInfo.user_id == form.create_user)" |
| | | @click="submitForm(1)">发布</el-button> |
| | | @click="submitForm(1)" |
| | | >发布</el-button |
| | | > |
| | | <!-- <el-button type="primary" v-if="form.status == 0 || userInfo.user_id == form.create_user" |
| | | @click="submitForm(0)">保存</el-button> --> |
| | | |
| | | <el-button type="primary" v-if="form.status == 1 && this.permission.orderLogpass" |
| | | @click="orderLogPass(form.id)">通过</el-button> |
| | | <el-button type="danger" v-if="form.status == 1 && hasRejectionBtnPermission()" |
| | | @click="orderLogReject(form.id)">驳回</el-button> |
| | | <el-button |
| | | type="primary" |
| | | v-if="form.status == 1 && this.permission.orderLogpass" |
| | | @click="orderLogPass(form.id)" |
| | | >通过</el-button |
| | | > |
| | | <el-button |
| | | type="danger" |
| | | v-if="form.status == 1 && hasRejectionBtnPermission()" |
| | | @click="orderLogReject(form.id)" |
| | | >驳回</el-button |
| | | > |
| | | <el-button @click="detailVisibleCopy = false">取消</el-button> |
| | | </div> |
| | | </el-row> |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import { calculateDefaultRange } from '@/utils/util' |
| | | import { calculateDefaultRange } from '@/utils/util'; |
| | | import { |
| | | getList, |
| | | saveUpdateOrderLog, |
| | |
| | | jobStatusNum, |
| | | userPublish, |
| | | deleteOrderLog, |
| | | } from '@/api/tickets/orderLog' |
| | | import { getTicketInfo } from '@/api/tickets/ticket' |
| | | import { getDictionaryByCode } from '@/api/system/dictbiz' |
| | | import { getWaylineFileListByArea } from '@/api/resource/wayline' |
| | | import { export_json_to_excel } from '@/utils/exportExcel' |
| | | import { getFlyingNestBy } from '@/api/device/device' |
| | | import { mapGetters } from 'vuex' |
| | | import NProgress from 'nprogress' |
| | | import { downloadXls } from '@/utils/util' |
| | | import 'nprogress/nprogress.css' |
| | | import { analyzeKmzFile, removeTextKey, XMLToJSON } from '@/utils/cesium/kmz' |
| | | } from '@/api/tickets/orderLog'; |
| | | import { getTicketInfo } from '@/api/tickets/ticket'; |
| | | import { getDictionaryByCode } from '@/api/system/dictbiz'; |
| | | import { getWaylineFileListByArea } from '@/api/resource/wayline'; |
| | | import { export_json_to_excel } from '@/utils/exportExcel'; |
| | | import { getFlyingNestBy } from '@/api/device/device'; |
| | | import { mapGetters } from 'vuex'; |
| | | import NProgress from 'nprogress'; |
| | | import { downloadXls } from '@/utils/util'; |
| | | import 'nprogress/nprogress.css'; |
| | | import { analyzeKmzFile, removeTextKey, XMLToJSON } from '@/utils/cesium/kmz'; |
| | | |
| | | export default { |
| | | name: 'TicketPage', |
| | | data () { |
| | | data() { |
| | | return { |
| | | activeTab: 'all', |
| | | |
| | |
| | | |
| | | // 配置时间选择器默认配置 |
| | | datePickerDefaultVal: calculateDefaultRange(), |
| | | } |
| | | }; |
| | | }, |
| | | async created () { |
| | | var response = await getDictionaryByCode('SF') |
| | | var word_order_typeResponse = await getDictionaryByCode('WORK_ORDER_TYPE') |
| | | this.ai_types = response.data.data['SF'] |
| | | this.types = word_order_typeResponse.data.data['WORK_ORDER_TYPE'] |
| | | async created() { |
| | | var response = await getDictionaryByCode('SF'); |
| | | var word_order_typeResponse = await getDictionaryByCode('WORK_ORDER_TYPE'); |
| | | this.ai_types = response.data.data['SF']; |
| | | this.types = word_order_typeResponse.data.data['WORK_ORDER_TYPE']; |
| | | //获取航线 |
| | | this.asyncgetWaylineFileListByArea() |
| | | const response2 = await getTicketInfo() |
| | | const { dept_data, event_type, ai_type } = response2.data.data |
| | | this.asyncgetWaylineFileListByArea(); |
| | | const response2 = await getTicketInfo(); |
| | | const { dept_data, event_type, ai_type } = response2.data.data; |
| | | this.departments = dept_data.map(item => ({ |
| | | label: item.dept_name, |
| | | value: item.id, |
| | | })) |
| | | })); |
| | | }, |
| | | mounted () { |
| | | this.fetchTableData() |
| | | mounted() { |
| | | this.fetchTableData(); |
| | | const id = this.$route.query.id; |
| | | if (id) { |
| | | // 确保 id 存在 |
| | | this.handleViewDetail({ id }); |
| | | } else { |
| | | console.error('工单ID不存在!'); |
| | | } |
| | | }, |
| | | computed: { |
| | | ...mapGetters(['userInfo', 'permission']), |
| | | filteredTabs () { |
| | | filteredTabs() { |
| | | // rejection_and_draft 权限控制“已驳回”和“草稿”tab |
| | | const canShowRejectAndDraft = this.permission?.rejection_and_draft === true |
| | | const canShowRejectAndDraft = this.permission?.rejection_and_draft === true; |
| | | return this.tabs |
| | | .map(tab => { |
| | | if (tab.name === 'DRAFT') { |
| | | return { ...tab, isShow: canShowRejectAndDraft } |
| | | return { ...tab, isShow: canShowRejectAndDraft }; |
| | | } |
| | | if (tab.name === 'REJECTED') { |
| | | return { ...tab, isShow: canShowRejectAndDraft } |
| | | return { ...tab, isShow: canShowRejectAndDraft }; |
| | | } |
| | | return { ...tab, isShow: true } |
| | | return { ...tab, isShow: true }; |
| | | }) |
| | | .filter(tab => tab.isShow) |
| | | .filter(tab => tab.isShow); |
| | | }, |
| | | }, |
| | | |
| | | methods: { |
| | | searchChange (params, done) { |
| | | console.log('searchChange') |
| | | this.query = params |
| | | this.parentId = '' |
| | | this.page.currentPage = 1 |
| | | this.onLoad(this.page, params) |
| | | done() |
| | | searchChange(params, done) { |
| | | // console.log('searchChange') |
| | | this.query = params; |
| | | this.parentId = ''; |
| | | this.page.currentPage = 1; |
| | | this.onLoad(this.page, params); |
| | | done(); |
| | | }, |
| | | async onLoad (page, params = {}) { |
| | | this.loading = true |
| | | async onLoad(page, params = {}) { |
| | | this.loading = true; |
| | | getList( |
| | | null, |
| | | this.page.currentPage, |
| | | this.page.pageSize, |
| | | Object.assign(params, this.query) |
| | | ).then(res => { |
| | | this.tableData = res.data.data |
| | | this.loading = false |
| | | this.selectionClear() |
| | | }) |
| | | this.tableData = res.data.data; |
| | | this.loading = false; |
| | | this.selectionClear(); |
| | | }); |
| | | }, |
| | | selectionClear () { |
| | | this.selectionList = [] |
| | | this.$refs.crud.toggleSelection() |
| | | selectionClear() { |
| | | this.selectionList = []; |
| | | this.$refs.crud.toggleSelection(); |
| | | }, |
| | | async loadAMapScripts () { |
| | | async loadAMapScripts() { |
| | | try { |
| | | // await loadAMap(); |
| | | // await loadAMapUI(); |
| | | this.mapLoaded = true |
| | | this.mapLoaded = true; |
| | | } catch (error) { |
| | | console.error('Failed to load AMap scripts:', error) |
| | | this.$message.error('地图加载失败,请检查网络或API Key配置') |
| | | console.error('Failed to load AMap scripts:', error); |
| | | this.$message.error('地图加载失败,请检查网络或API Key配置'); |
| | | } |
| | | }, |
| | | formatCycleTime (row) { |
| | | return `${row.cycle_time_value}` |
| | | formatCycleTime(row) { |
| | | return `${row.cycle_time_value}`; |
| | | }, |
| | | |
| | | async fetchTableData () { |
| | | this.loading = true |
| | | async fetchTableData() { |
| | | this.loading = true; |
| | | try { |
| | | let params = this.getQueryParam() |
| | | console.log('发送的参数:', params) |
| | | const response = await getList(params, this.page.currentPage, this.page.pageSize) |
| | | let params = this.getQueryParam(); |
| | | // console.log('发送的参数:', params) |
| | | const response = await getList(params, this.page.currentPage, this.page.pageSize); |
| | | if (!response?.data?.data?.records) { |
| | | throw new Error('接口返回数据格式不正确') |
| | | throw new Error('接口返回数据格式不正确'); |
| | | } |
| | | |
| | | const { total, records } = response.data.data |
| | | const { total, records } = response.data.data; |
| | | this.tableData = records.map(item => { |
| | | return item |
| | | }) |
| | | return item; |
| | | }); |
| | | |
| | | console.log('权限检查:', this.permission) |
| | | this.page.total = total || 0 |
| | | this.updateGlobalCounts() |
| | | // console.log('权限检查:', this.permission) |
| | | this.page.total = total || 0; |
| | | this.updateGlobalCounts(); |
| | | } catch (error) { |
| | | console.error('获取数据失败:', error) |
| | | this.$message.error(error.message || '获取数据失败') |
| | | this.tableData = [] |
| | | this.page.total = 0 |
| | | // console.error('获取数据失败:', error) |
| | | this.$message.error(error.message || '获取数据失败'); |
| | | this.tableData = []; |
| | | this.page.total = 0; |
| | | } finally { |
| | | this.loading = false |
| | | this.loading = false; |
| | | } |
| | | }, |
| | | |
| | | getQueryParam () { |
| | | const currentTab = this.tabs.find(tab => tab.name === this.activeTab) |
| | | getQueryParam() { |
| | | const currentTab = this.tabs.find(tab => tab.name === this.activeTab); |
| | | if (this.filters.dateRange) { |
| | | console.log( |
| | | 'this.formatDate(this.filters.dateRange[0])', |
| | | this.formatDate(this.filters.dateRange[0]) |
| | | ) |
| | | // console.log( |
| | | // 'this.formatDate(this.filters.dateRange[0])', |
| | | // this.formatDate(this.filters.dateRange[0]) |
| | | // ) |
| | | } |
| | | |
| | | const params = { |
| | |
| | | deal_time: this.filters.deal_time || undefined, |
| | | current: this.page.currentPage, |
| | | size: this.page.pageSize, |
| | | } |
| | | return params |
| | | }; |
| | | return params; |
| | | }, |
| | | sizeChange (pageSize) { |
| | | this.page.pageSize = pageSize |
| | | sizeChange(pageSize) { |
| | | this.page.pageSize = pageSize; |
| | | }, |
| | | async submitForm (status) { |
| | | async submitForm(status) { |
| | | this.$refs.testform.validate(async valid => { |
| | | if (valid) { |
| | | let dateRange = this.form.date_range |
| | | console.log('dateRange' + dateRange) |
| | | let dateRange = this.form.date_range; |
| | | // console.log('dateRange' + dateRange) |
| | | |
| | | this.form.begin_time = this.formatDate(dateRange[0]) |
| | | this.form.end_time = this.formatDate(dateRange[1]) |
| | | this.form.begin_time = this.formatDate(dateRange[0]); |
| | | this.form.end_time = this.formatDate(dateRange[1]); |
| | | |
| | | const submitData = { |
| | | ...this.form, |
| | | |
| | | status: status, |
| | | } |
| | | await saveUpdateOrderLog(submitData) |
| | | let id = this.form.id |
| | | }; |
| | | await saveUpdateOrderLog(submitData); |
| | | let id = this.form.id; |
| | | if (id) { |
| | | this.$message.success('工单发布成功') |
| | | this.$message.success('工单发布成功'); |
| | | } else { |
| | | this.$message.success('工单创建成功') |
| | | this.$message.success('工单创建成功'); |
| | | } |
| | | this.dialogVisible = false |
| | | this.dialogVisible = false; |
| | | this.detailVisible = false; |
| | | (this.device_sns = []), (this.wayLineList = []), this.fetchTableData() |
| | | (this.device_sns = []), (this.wayLineList = []), this.fetchTableData(); |
| | | } |
| | | }) |
| | | }); |
| | | }, |
| | | //驳回原因显示 |
| | | async rejectDetail (id) { |
| | | const response = await orderLogDetails(id) |
| | | let data = response.data.data |
| | | async rejectDetail(id) { |
| | | const response = await orderLogDetails(id); |
| | | let data = response.data.data; |
| | | this.$confirm(data.remark, '驳回原因', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | |
| | | }).then(() => { |
| | | this.form = { |
| | | ...response.data.data, |
| | | } |
| | | this.detailVisible = true |
| | | }) |
| | | }; |
| | | this.detailVisible = true; |
| | | }); |
| | | }, |
| | | formatDate (date) { |
| | | if (!date) return undefined |
| | | const d = new Date(date) |
| | | formatDate(date) { |
| | | if (!date) return undefined; |
| | | const d = new Date(date); |
| | | return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String( |
| | | d.getDate() |
| | | ).padStart(2, '0')} 00:00:00` |
| | | ).padStart(2, '0')} 00:00:00`; |
| | | }, |
| | | |
| | | mapStatus (status) { |
| | | mapStatus(status) { |
| | | const statusTextMap = { |
| | | 0: '草稿', |
| | | 1: '待审核', |
| | | 2: '已驳回', |
| | | 3: '已通过', |
| | | } |
| | | return statusTextMap[status] || '未知状态' |
| | | }; |
| | | return statusTextMap[status] || '未知状态'; |
| | | }, |
| | | |
| | | getStatusTagType (status) { |
| | | getStatusTagType(status) { |
| | | const statusMap = { |
| | | 1: 'warning', |
| | | 2: 'info', |
| | | 3: 'primary', |
| | | 4: 'success', |
| | | 5: 'danger', |
| | | } |
| | | return statusMap[status] || 'info' |
| | | }; |
| | | return statusMap[status] || 'info'; |
| | | }, |
| | | |
| | | handleTabChange (tab) { |
| | | this.activeTab = tab.props?.name || tab.name |
| | | this.filters.status = '' |
| | | this.page.currentPage = 1 |
| | | this.fetchTableData() |
| | | handleTabChange(tab) { |
| | | this.activeTab = tab.props?.name || tab.name; |
| | | this.filters.status = ''; |
| | | this.page.currentPage = 1; |
| | | this.fetchTableData(); |
| | | }, |
| | | |
| | | handleSearch () { |
| | | this.page.currentPage = 1 |
| | | this.fetchTableData() |
| | | handleSearch() { |
| | | this.page.currentPage = 1; |
| | | this.fetchTableData(); |
| | | }, |
| | | |
| | | handleReset () { |
| | | handleReset() { |
| | | this.filters = { |
| | | keyword: '', |
| | | department: '', |
| | | type: '', |
| | | dateRange: [], |
| | | status: '', |
| | | } |
| | | this.page.currentPage = 1 |
| | | this.fetchTableData() |
| | | }; |
| | | this.page.currentPage = 1; |
| | | this.fetchTableData(); |
| | | }, |
| | | |
| | | currentChange (currentPage) { |
| | | this.page.currentPage = currentPage |
| | | currentChange(currentPage) { |
| | | this.page.currentPage = currentPage; |
| | | }, |
| | | |
| | | async updateGlobalCounts () { |
| | | async updateGlobalCounts() { |
| | | const counts = { |
| | | all: 0, |
| | | DRAFT: 0, |
| | | WAIT_AUDIT: 0, |
| | | REJECTED: 0, |
| | | PASS: 0, |
| | | } |
| | | var reponse = await jobStatusNum() |
| | | console.log('统计' + reponse.data.data) |
| | | }; |
| | | var reponse = await jobStatusNum(); |
| | | // console.log('统计' + reponse.data.data) |
| | | reponse.data.data.forEach(item => { |
| | | const tab = this.tabs.find(t => t.name === item.dict_key) |
| | | const tab = this.tabs.find(t => t.name === item.dict_key); |
| | | if (tab) { |
| | | tab.count = item.num |
| | | tab.count = item.num; |
| | | } |
| | | }) |
| | | }); |
| | | }, |
| | | |
| | | handleAdd () { |
| | | this.form = {} |
| | | this.dialogVisible = true |
| | | handleAdd() { |
| | | this.form = {}; |
| | | this.dialogVisible = true; |
| | | //航线列表 |
| | | this.asyncgetWaylineFileListByArea() |
| | | this.asyncgetWaylineFileListByArea(); |
| | | }, |
| | | |
| | | resetForm () { |
| | | resetForm() { |
| | | this.form = { |
| | | name: '', |
| | | type: '', |
| | |
| | | address: '', |
| | | content: '', |
| | | photos: [], |
| | | } |
| | | }; |
| | | if (this.$refs.testform) { |
| | | this.$refs.testform.resetFields() |
| | | this.$refs.testform.resetFields(); |
| | | } |
| | | }, |
| | | |
| | | formatLocation (location) { |
| | | formatLocation(location) { |
| | | if (!Array.isArray(location)) { |
| | | return '未知位置' |
| | | return '未知位置'; |
| | | } |
| | | return `${location[0].toFixed(6)}, ${location[1].toFixed(6)}` |
| | | return `${location[0].toFixed(6)}, ${location[1].toFixed(6)}`; |
| | | }, |
| | | async handleViewDetail (row) { |
| | | const response = await orderLogDetails(row.id) |
| | | const data = response.data.data |
| | | |
| | | async handleViewDetail(row) { |
| | | const response = await orderLogDetails(row.id); |
| | | const data = response.data.data; |
| | | this.form = { |
| | | ...data, |
| | | } |
| | | }; |
| | | |
| | | // 更新机巢列表 |
| | | this.device_sns = data.device_list |
| | | this.device_sns = data.device_list; |
| | | this.permission && |
| | | (this.permission.order_log_review || this.permission.order_log_recall) && |
| | | (data.status == 1 || data.status == 3 || data.status == 2) |
| | | (this.permission.order_log_review || this.permission.order_log_recall) && |
| | | (data.status == 1 || data.status == 3 || data.status == 2) |
| | | ? (this.detailTitle = '工单详情') |
| | | : (this.detailTitle = '编辑工单') |
| | | : (this.detailTitle = '编辑工单'); |
| | | |
| | | this.detailVisible = true |
| | | this.detailVisible = true; |
| | | |
| | | this.initMapLine(data.device_map_infos) |
| | | this.initMapLine(data.device_map_infos); |
| | | }, |
| | | async handleCheckDetail (row) { |
| | | const response = await orderLogDetails(row.id) |
| | | const data = response.data.data |
| | | |
| | | async handleCheckDetail(row) { |
| | | const response = await orderLogDetails(row.id); |
| | | const data = response.data.data; |
| | | this.form = { |
| | | ...data, |
| | | } |
| | | }; |
| | | |
| | | // 更新机巢列表 |
| | | this.device_sns = data.device_list |
| | | this.detailVisibleCopy = true |
| | | this.initMapLine(data.device_map_infos) |
| | | this.device_sns = data.device_list; |
| | | this.detailVisibleCopy = true; |
| | | this.initMapLine(data.device_map_infos); |
| | | }, |
| | | //导出 |
| | | async exportData () { |
| | | async exportData() { |
| | | this.$confirm('是否智飞工单数据?', '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning', |
| | | }).then(() => { |
| | | NProgress.start() |
| | | let params = this.getQueryParam() |
| | | NProgress.start(); |
| | | let params = this.getQueryParam(); |
| | | orderLogExport(params).then(res => { |
| | | downloadXls(res.data, `智飞工单${this.$dayjs().format('YYYY-MM-DD')}.xlsx`) |
| | | NProgress.done() |
| | | }) |
| | | }) |
| | | downloadXls(res.data, `智飞工单${this.$dayjs().format('YYYY-MM-DD')}.xlsx`); |
| | | NProgress.done(); |
| | | }); |
| | | }); |
| | | }, |
| | | hasAddBtnPermission () { |
| | | hasAddBtnPermission() { |
| | | // undefined 或 false 都返回 false,只有 true 返回 true |
| | | console.log('this.permission.order_log_add :', this.permission.order_log_add) |
| | | return this.permission && this.permission.order_log_add === true |
| | | // console.log('this.permission.order_log_add :', this.permission.order_log_add) |
| | | return this.permission && this.permission.order_log_add === true; |
| | | }, |
| | | hasPaddingBtnPermission () { |
| | | hasPaddingBtnPermission() { |
| | | // undefined 或 false 都返回 false,只有 true 返回 true |
| | | console.log('权限检查:', this.permission) |
| | | return this.permission && this.permission.order_log_review === true |
| | | // console.log('权限检查:', this.permission) |
| | | return this.permission && this.permission.order_log_review === true; |
| | | }, |
| | | hasRecallPaddingBtnPermission () { |
| | | hasRecallPaddingBtnPermission() { |
| | | // undefined 或 false 都返回 false,只有 true 返回 true |
| | | console.log('权限检查:', this.permission) |
| | | return this.permission && this.permission.order_log_recall === true |
| | | // console.log('权限检查:', this.permission) |
| | | // 智飞工单撤回 |
| | | return this.permission && this.permission.order_log_recall === true; |
| | | }, |
| | | //驳回按钮权限 |
| | | hasRejectionBtnPermission () { |
| | | hasRejectionBtnPermission() { |
| | | // undefined 或 false 都返回 false,只有 true 返回 true |
| | | console.log('权限检查:', this.permission) |
| | | return this.permission && this.permission.rejection_btn === true |
| | | // console.log('权限检查:', this.permission) |
| | | return this.permission && this.permission.rejection_btn === true; |
| | | }, |
| | | //自己点发布 |
| | | userPublishPush (id) { |
| | | userPublishPush(id) { |
| | | this.$confirm('确定发布吗?', '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning', |
| | | }).then(() => { |
| | | let response = userPublish(id) |
| | | this.$message.success('发布成功') |
| | | this.fetchTableData() |
| | | }) |
| | | let response = userPublish(id); |
| | | this.$message.success('发布成功'); |
| | | this.fetchTableData(); |
| | | }); |
| | | }, |
| | | |
| | | //删除 |
| | | deleteOrderLog (id) { |
| | | deleteOrderLog(id) { |
| | | this.$confirm('确定删除吗?', '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning', |
| | | }).then(() => { |
| | | let response = deleteOrderLog(id) |
| | | this.$message.success('删除') |
| | | this.fetchTableData() |
| | | }) |
| | | let response = deleteOrderLog(id); |
| | | this.$message.success('删除'); |
| | | this.fetchTableData(); |
| | | }); |
| | | }, |
| | | refreshChange () { |
| | | this.fetchTableData() |
| | | refreshChange() { |
| | | this.fetchTableData(); |
| | | }, |
| | | //获取航线列表 |
| | | async asyncgetWaylineFileListByArea (name) { |
| | | var wayLineListResponse = await getWaylineFileListByArea(this.userInfo.detail.areaCode) |
| | | this.wayLineList = wayLineListResponse.data.data |
| | | async asyncgetWaylineFileListByArea(name) { |
| | | var wayLineListResponse = await getWaylineFileListByArea(this.userInfo.detail.areaCode); |
| | | this.wayLineList = wayLineListResponse.data.data; |
| | | |
| | | this.initMapLine() |
| | | this.initMapLine(); |
| | | }, |
| | | |
| | | initMapLine (infos = {}) { |
| | | let currentLine = this.wayLineList.find(item => item.wayline_id == this.form.file_id) |
| | | initMapLine(infos = {}) { |
| | | let currentLine = this.wayLineList.find(item => item.wayline_id == this.form.file_id); |
| | | |
| | | if (!currentLine) return |
| | | if (!currentLine) return; |
| | | |
| | | // 异步解析kmz文件 |
| | | const analysis = async url => { |
| | | return new Promise(async resolve => { |
| | | const res = await analyzeKmzFile(`${url}?_t=${new Date().getTime()}`) |
| | | const templateXML = await res.fileInfoObj['wpmz/template.kml'] |
| | | const templateXMLJSON = XMLToJSON(templateXML)?.['Document'] |
| | | const templateXMLObj = removeTextKey(templateXMLJSON.Folder) |
| | | resolve(templateXMLObj) |
| | | }) |
| | | } |
| | | const res = await analyzeKmzFile(`${url}?_t=${new Date().getTime()}`); |
| | | const templateXML = await res.fileInfoObj['wpmz/template.kml']; |
| | | const templateXMLJSON = XMLToJSON(templateXML)?.['Document']; |
| | | const templateXMLObj = removeTextKey(templateXMLJSON.Folder); |
| | | resolve(templateXMLObj); |
| | | }); |
| | | }; |
| | | |
| | | const drawLine = async () => { |
| | | let prexUrl = ref(import.meta.env.VITE_APP_AIRLINE_URL + currentLine.object_key) |
| | | const res = await analysis(prexUrl.value) |
| | | if (!res.Placemark.length) return |
| | | renderingLine(res) |
| | | } |
| | | let prexUrl = ref(import.meta.env.VITE_APP_AIRLINE_URL + currentLine.object_key); |
| | | const res = await analysis(prexUrl.value); |
| | | if (!res.Placemark.length) return; |
| | | renderingLine(res); |
| | | }; |
| | | |
| | | const renderingLine = lineObj => { |
| | | const positions = lineObj.Placemark.map(item => { |
| | | return item.Point.coordinates.split(',') |
| | | }) |
| | | return item.Point.coordinates.split(','); |
| | | }); |
| | | |
| | | if (JSON.stringify(infos) != '{}') positions.unshift([ |
| | | infos[0].longitude, |
| | | infos[0].latitude, |
| | | ]) |
| | | if (JSON.stringify(infos) != '{}') |
| | | positions.unshift([infos[0].longitude, infos[0].latitude]); |
| | | |
| | | this.$nextTick(() => { |
| | | if (this.$refs.MapContainer && this.$refs.MapContainer.initAddEntity) { |
| | | this.$refs.MapContainer.initAddEntity('polyline', positions) |
| | | this.$refs.MapContainer.initAddEntity('polyline', positions); |
| | | } |
| | | }) |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | drawLine() |
| | | drawLine(); |
| | | }, |
| | | |
| | | //可飞行机巢列表 |
| | | async getFlyingNestBy (waylineId) { |
| | | this.initMapLine() |
| | | async getFlyingNestBy(waylineId) { |
| | | this.initMapLine(); |
| | | |
| | | //按照航线来 |
| | | const params = { |
| | | type: 0, |
| | | waylineId: waylineId, |
| | | } |
| | | var wayLineListResponse = await getFlyingNestBy(params) |
| | | this.device_sns = wayLineListResponse.data.data |
| | | wayline_id: waylineId, |
| | | }; |
| | | var wayLineListResponse = await getFlyingNestBy(params); |
| | | this.device_sns = wayLineListResponse.data.data; |
| | | }, |
| | | |
| | | //撤回 |
| | | async orderLogRecall (id) { |
| | | async orderLogRecall(id) { |
| | | this.$confirm('确定撤回则到草稿箱。', '是否撤回?', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning', |
| | | }).then(async () => { |
| | | let reposne = await orderLogRecall(id) |
| | | this.handleSearch() |
| | | }) |
| | | let reposne = await orderLogRecall(id); |
| | | this.handleSearch(); |
| | | }); |
| | | }, |
| | | onLoad () { |
| | | this.fetchTableData() |
| | | onLoad() { |
| | | this.fetchTableData(); |
| | | }, |
| | | /** |
| | | * 通过 |
| | | */ |
| | | async orderLogPass (id) { |
| | | let response = await orderLogPass(id) |
| | | let data = response.data.data |
| | | this.$message.success('审核通过') |
| | | this.detailVisibleCopy = false |
| | | async orderLogPass(id) { |
| | | let response = await orderLogPass(id); |
| | | let data = response.data.data; |
| | | this.$message.success('审核通过'); |
| | | this.detailVisibleCopy = false; |
| | | }, |
| | | /** |
| | | * 驳回 |
| | | */ |
| | | async orderLogReject (id) { |
| | | async orderLogReject(id) { |
| | | this.$prompt('', '驳回原因', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | }).then(async ({ value }) => { |
| | | let response = await orderLogReject(id, value) |
| | | let data = response.data.data |
| | | this.$message.success('驳回成果') |
| | | this.detailVisibleCopy = false |
| | | }) |
| | | let response = await orderLogReject(id, value); |
| | | let data = response.data.data; |
| | | this.$message.success('驳回成果'); |
| | | this.detailVisibleCopy = false; |
| | | }); |
| | | }, |
| | | }, |
| | | |
| | | watch: { |
| | | tableData: { |
| | | handler () { |
| | | handler() { |
| | | // this.updateTabCounts() |
| | | }, |
| | | deep: true, |
| | | }, |
| | | }, |
| | | } |
| | | }; |
| | | </script> |
| | | <style></style> |
| | | <style lang="scss" scoped> |
| | |
| | | &-item { |
| | | flex: 1; |
| | | |
| | | &> ::v-deep(.el-date-editor) { |
| | | & > ::v-deep(.el-date-editor) { |
| | | width: 100%; |
| | | box-sizing: border-box; |
| | | } |
| | |
| | | justify-content: center; |
| | | flex-wrap: wrap; |
| | | |
| | | &> ::v-deep(.el-button) { |
| | | & > ::v-deep(.el-button) { |
| | | flex: 1; |
| | | max-width: 44px; |
| | | |
| | |
| | | .flex-1 { |
| | | flex: 1; |
| | | |
| | | &> ::v-deep(div) { |
| | | & > ::v-deep(div) { |
| | | width: 100% !important; |
| | | } |
| | | } |
| | |
| | | <div class="detail-container"> |
| | | <div class="event-title-center">{{ currentDetail.orderName || '事件名称' }}</div> |
| | | <div v-if="totalTime" class="event-total-time" |
| | | style="text-align:center;color:#666;font-size:15px;margin-bottom:12px;"> |
| | | style="text-align: center; color: #666; font-size: 15px; margin-bottom: 12px"> |
| | | 总耗时:{{ totalTime }} |
| | | </div> |
| | | <!-- 工单状态流程 --> |
| | |
| | | <div class="steps-titles"> |
| | | <div v-for="(status, index) in stepStatusList" :key="index" :class="{ |
| | | 'step-title': true, |
| | | 'active': index <= stepStatusList.indexOf(String(currentDetail.status)) |
| | | active: index <= stepStatusList.indexOf(String(currentDetail.status)), |
| | | }"> |
| | | {{ mapStatus(status) }} |
| | | </div> |
| | |
| | | {{ getStepHandler(status) }} |
| | | </span> |
| | | <div class="step-description" v-if="getStepTime(status)"> |
| | | <span |
| | | style="position: absolute; right: 80%; top: 50%; transform: translateY(-50%); width: 100px; margin-left: 4px; color: #666; font-size: 12px;"> |
| | | <span style=" |
| | | position: absolute; |
| | | right: 80%; |
| | | top: 50%; |
| | | transform: translateY(-50%); |
| | | width: 100px; |
| | | margin-left: 4px; |
| | | color: #666; |
| | | font-size: 12px; |
| | | "> |
| | | 耗时:{{ getStepTime(status) }} |
| | | </span> |
| | | </div> |
| | |
| | | </div> |
| | | |
| | | <!-- 基本信息表格 --> |
| | | <el-table :show-header="false" :data="formattedDetailFields" border style="width: 100%; margin-bottom: 20px;"> |
| | | <el-table :show-header="false" :data="formattedDetailFields" border style="width: 100%; margin-bottom: 20px"> |
| | | <el-table-column prop="label1" label="基本信息" width="150"> |
| | | <template #default="{ row }"> |
| | | <!-- 添加必填星号的标签 --> |
| | |
| | | </el-table-column> |
| | | <el-table-column> |
| | | <template #default="{ row }"> |
| | | <template v-if="currentDetail.status === 0 && row.label1 === '工单名称' && hasProcessingBtnPermission()"> |
| | | <template v-if=" |
| | | currentDetail.status === 0 && |
| | | row.label1 === '工单名称' && |
| | | hasProcessingBtnPermission() |
| | | "> |
| | | <el-input v-model="currentDetail.orderName" placeholder="请输入工单名称" class="required-input" /> |
| | | </template> |
| | | <template v-else>{{ row.value1 }}</template> |
| | |
| | | <el-table-column prop="label2" label="基本信息" width="150"> |
| | | <template #default="{ row }"> |
| | | <!-- 添加必填星号的标签 --> |
| | | <span v-if="currentDetail.status === 0 && (row.label2 === '工单类型' || row.label2 === '工单内容')" |
| | | class="required-label"> |
| | | <span v-if=" |
| | | currentDetail.status === 0 && |
| | | (row.label2 === '工单类型' || row.label2 === '工单内容') |
| | | " class="required-label"> |
| | | <span class="required-star">*</span>{{ row.label2 }} |
| | | </span> |
| | | <span v-else>{{ row.label2 }}</span> |
| | |
| | | <el-table-column> |
| | | <template #default="{ row }"> |
| | | <!-- 修改工单类型和工单内容的显示 --> |
| | | <template v-if="currentDetail.status === 0 && row.label2 === '工单类型' && hasProcessingBtnPermission()"> |
| | | <template v-if=" |
| | | currentDetail.status === 0 && |
| | | row.label2 === '工单类型' && |
| | | hasProcessingBtnPermission() |
| | | "> |
| | | <el-select v-model="currentDetail.type" placeholder="请选择工单类型" class="required-input"> |
| | | <el-option v-for="item in types" :key="item.value" :label="item.label" :value="item.value" /> |
| | | </el-select> |
| | | </template> |
| | | <template v-else-if="currentDetail.status === 0 && row.label2 === '工单内容' && hasProcessingBtnPermission()"> |
| | | <template v-else-if=" |
| | | currentDetail.status === 0 && |
| | | row.label2 === '工单内容' && |
| | | hasProcessingBtnPermission() |
| | | "> |
| | | <el-input type="textarea" v-model="currentDetail.content" placeholder="请输入工单内容" |
| | | class="required-input" /> |
| | | </template> |
| | |
| | | <div class="section-title"> |
| | | <!-- 处理中状态显示必填星号 --> |
| | | <template v-if="currentDetail.status === 3"> |
| | | <span class="required-label"> |
| | | <span class="required-star">*</span>事件处理详情 |
| | | </span> |
| | | <span class="required-label"> <span class="required-star">*</span>事件处理详情 </span> |
| | | </template> |
| | | <template v-else> |
| | | 事件处理详情 |
| | | </template> |
| | | <template v-else> 事件处理详情 </template> |
| | | </div> |
| | | <!-- 处理中状态显示输入框 --> |
| | | <template v-if="currentDetail.status === 3 && hasProcessedAndOverBtnPermission()"> |
| | | <el-input type="textarea" v-model="currentDetail.processingDetail" placeholder="请输入事件处理详情" :rows="4" |
| | | style="width: 100%; margin-bottom: 10px;" /> |
| | | style="width: 100%; margin-bottom: 10px" /> |
| | | </template> |
| | | <!-- 已完成和已完结状态显示只读文本 --> |
| | | <template v-else> |
| | |
| | | </div> |
| | | |
| | | <!-- 上传图片 --> |
| | | <div v-if="[3].includes(currentDetail.status)" class="form-section" style="margin-bottom: 32px;"> |
| | | <div v-if="[3].includes(currentDetail.status)" class="form-section" style="margin-bottom: 32px"> |
| | | <div class="section-title" v-if="hasProcessedAndOverBtnPermission()"> |
| | | <!-- 已完成状态显示必填星号 --> |
| | | <template v-if="currentDetail.status === 3"> |
| | | <span class="required-label"> |
| | | <span class="required-star">*</span>上传图片 |
| | | </span> |
| | | <span class="required-label"> <span class="required-star">*</span>上传图片 </span> |
| | | </template> |
| | | <template v-else> |
| | | 上传图片 |
| | | </template> |
| | | <template v-else> 上传图片 </template> |
| | | </div> |
| | | <el-upload v-if="hasProcessedAndOverBtnPermission()" ref="upload" :action="'#'" :auto-upload="false" |
| | | list-type="picture-card" :on-change="handleFileChange" :on-remove="handleUploadRemove" |
| | |
| | | <i class="el-icon-plus">+</i> |
| | | </template> |
| | | </el-upload> |
| | | <div class="el-upload__tip" style="margin-top: 12px;" v-if="hasProcessedAndOverBtnPermission()"> |
| | | <div class="el-upload__tip" style="margin-top: 12px" v-if="hasProcessedAndOverBtnPermission()"> |
| | | (上传照片即可完结工单,只能上传jpg、jpeg、png照片,且不超过5M) |
| | | </div> |
| | | </div> |
| | |
| | | <div class="media-content"> |
| | | <el-image v-if="currentDetail.mediaUrl" :src="getThumbUrl(currentDetail.mediaUrl)" |
| | | :preview-src-list="[getPreviewUrl(currentDetail.mediaUrl)]" fit="contain" |
| | | style="width: 700px; height: 520px; cursor: pointer;"> |
| | | style="width: 700px; height: 520px; cursor: pointer"> |
| | | <template #placeholder> |
| | | <div class="image-placeholder"> |
| | | <i class="el-icon-picture-outline"></i> |
| | |
| | | <template v-else> |
| | | <div class="media-title">地图标记事件点</div> |
| | | <div class="media-content"> |
| | | <map-container v-if='detailVisible' ref="MapContainer"></map-container> |
| | | <map-container v-if="detailVisible" ref="MapContainer"></map-container> |
| | | </div> |
| | | </template> |
| | | </div> |
| | |
| | | </el-dialog> |
| | | |
| | | <!-- 添加在其他 dialog 组件之后 --> |
| | | <el-dialog v-model="reviewDialogVisible" title="批量审核" width="70%" append-to-body custom-class="review-dialog" |
| | | <el-dialog v-model="reviewDialogVisible" title="批量审核" width="1100" append-to-body custom-class="review-dialog" |
| | | @close="cancleBatchReject"> |
| | | <div class="review-container"> |
| | | <div class="review-image-wrapper"> |
| | |
| | | </div> |
| | | |
| | | <div class="review-image-container"> |
| | | <el-image v-if="currentReviewImage" :src="getThumbUrl(currentReviewImage)" fit="fill" |
| | | <!-- <el-image v-if="currentReviewImage" :src="getThumbUrl(currentReviewImage)" fit="fill" |
| | | :preview-src-list="getImageList()" :initial-index="currentImageIndex - 1" class="preview-image" |
| | | style="cursor: pointer;"> |
| | | style="cursor: pointer"> --> |
| | | <el-image v-if="currentReviewImage" :src="getPreviewUrl(currentReviewImage)" fit="fill" |
| | | :initial-index="currentImageIndex - 1" class="preview-image" style="cursor: pointer"> |
| | | <template #error> |
| | | <div class="image-error"> |
| | | <i class="el-icon-picture-outline"></i> |
| | |
| | | getstatusCount, |
| | | getStepInfo, |
| | | getReviewById, |
| | | getCreateEventJob |
| | | getCreateEventJob, |
| | | } from '@/api/tickets/ticket' |
| | | import { export_json_to_excel } from '@/utils/exportExcel' |
| | | import geoJson from '@/assets/geoJson.json' |
| | |
| | | import { mapGetters } from 'vuex' |
| | | import { getAdcodeObj } from '@/utils/disposeData' |
| | | function regExp (label, name) { |
| | | var reg = new RegExp(label + "=([^&]*)(&|$)", "g") |
| | | return name.match(reg)[0].split("=")[1] |
| | | var reg = new RegExp(label + '=([^&]*)(&|$)', 'g') |
| | | return name.match(reg)[0].split('=')[1] |
| | | } |
| | | |
| | | export default { |
| | | name: "TicketPage", |
| | | name: 'TicketPage', |
| | | data () { |
| | | return { |
| | | submitLoading: false, // 新增loading状态 |
| | |
| | | dispatchLoading: false, |
| | | completeLoading: false, |
| | | finalizeLoading: false, |
| | | activeTab: "all", |
| | | activeTab: 'all', |
| | | // tabs 只保留静态结构,不做权限判断 |
| | | tabs: [ |
| | | { label: "全部工单", name: "all", value: null, count: 0 }, |
| | | { label: "待审核", name: "pending", value: 2, count: 0 }, |
| | | { label: "待处理", name: "processing", value: 0, count: 0 }, |
| | | { label: "处理中", name: "inProgress", value: 3, count: 0 }, |
| | | { label: "已完成", name: "completed", value: 4, count: 0 }, |
| | | { label: '全部工单', name: 'all', value: null, count: 0 }, |
| | | { label: '待审核', name: 'pending', value: 2, count: 0 }, |
| | | { label: '待处理', name: 'processing', value: 0, count: 0 }, |
| | | { label: '处理中', name: 'inProgress', value: 3, count: 0 }, |
| | | { label: '已完成', name: 'completed', value: 4, count: 0 }, |
| | | // { label: "已完结", name: "closed", value: 5, count: 0 }, |
| | | { label: "我发起的工单", name: "myTickets", value: null, count: 0 }, |
| | | { label: '我发起的工单', name: 'myTickets', value: null, count: 0 }, |
| | | ], |
| | | filters: { |
| | | keyword: "", |
| | | department: "", |
| | | type: "", |
| | | keyword: '', |
| | | department: '', |
| | | type: '', |
| | | dateRange: [], |
| | | status: "", |
| | | algorithm: "", // 新增算法筛选字段 |
| | | isReview: "", // 添加复核状态筛选字段 |
| | | status: '', |
| | | algorithm: '', // 新增算法筛选字段 |
| | | isReview: '', // 添加复核状态筛选字段 |
| | | }, |
| | | departments: [], |
| | | types: [], |
| | | handlers: [ |
| | | { label: "处理人A", value: "handlerA" }, |
| | | { label: "处理人B", value: "handlerB" }, |
| | | { label: '处理人A', value: 'handlerA' }, |
| | | { label: '处理人B', value: 'handlerB' }, |
| | | ], |
| | | |
| | | algorithms: [], |
| | | statuses: [ |
| | | { label: "待审核", value: "2" }, |
| | | { label: "待处理", value: "0" }, |
| | | { label: "处理中", value: "3" }, |
| | | { label: "已完成", value: "4" }, |
| | | { label: "已完结", value: "5" }, |
| | | { label: '待审核', value: '2' }, |
| | | { label: '待处理', value: '0' }, |
| | | { label: '处理中', value: '3' }, |
| | | { label: '已完成', value: '4' }, |
| | | ], |
| | | reviewStatuses: [ |
| | | { label: "否", value: 0 }, |
| | | { label: "是", value: 1 } |
| | | { label: '否', value: 0 }, |
| | | { label: '是', value: 1 }, |
| | | ], |
| | | tableData: [], |
| | | option: { |
| | | border: true, |
| | | stripe: true, |
| | | selection: true, // 添加多选功能 |
| | | index: true, // 保留序号功能 |
| | | index: true, // 保留序号功能 |
| | | indexLabel: '序号', |
| | | indexWidth: 60, |
| | | menuWidth: 150, |
| | |
| | | page: true, |
| | | column: [ |
| | | // { label: "序号", prop: "id", width: 70 }, |
| | | { label: "工单编号", prop: "orderNumber", width: 120, overHidden: true, tooltip: true }, |
| | | { label: "工单名称", prop: "orderName", width: 150, overHidden: true, tooltip: true }, |
| | | { label: "所属单位", prop: "department", overHidden: true, tooltip: true }, |
| | | { label: "发起时间", prop: "startTime", width: 160 }, |
| | | { label: "关联算法", prop: "aiType", width: 150, overHidden: true, tooltip: true }, |
| | | { label: "工单类型", prop: "type", width: 130, overHidden: true, tooltip: true }, |
| | | { label: '工单编号', prop: 'orderNumber', width: 120, overHidden: true, tooltip: true }, |
| | | { label: '工单名称', prop: 'orderName', width: 150, overHidden: true, tooltip: true }, |
| | | { label: '所属单位', prop: 'department', overHidden: true, tooltip: true }, |
| | | { label: '发起时间', prop: 'startTime', width: 160 }, |
| | | { label: '关联算法', prop: 'aiType', width: 150, overHidden: true, tooltip: true }, |
| | | { |
| | | label: "工单内容", |
| | | prop: "content", |
| | | label: '工单类型', |
| | | prop: 'type', |
| | | width: 130, |
| | | overHidden: true, |
| | | tooltip: true, |
| | | type: 'select', |
| | | dicData: [], |
| | | }, |
| | | { |
| | | label: '工单内容', |
| | | prop: 'content', |
| | | slot: true, |
| | | width: 152, |
| | | overHidden: true |
| | | overHidden: true, |
| | | }, |
| | | { label: "创建人", prop: "creator", width: 100 }, |
| | | { label: "处理人", prop: "handler", width: 100 }, |
| | | { label: '创建人', prop: 'creator', width: 100 }, |
| | | { label: '处理人', prop: 'handler', width: 100 }, |
| | | { |
| | | slot: true, |
| | | hide: false, |
| | | label: "复核状态", |
| | | prop: "isReview", |
| | | label: '复核状态', |
| | | prop: 'isReview', |
| | | width: 90, |
| | | }, |
| | | { label: "工单状态", prop: "status", slot: true, width: 90 }, |
| | | |
| | | { label: '工单状态', prop: 'status', slot: true, width: 90 }, |
| | | ], |
| | | }, |
| | | page: { |
| | | total: 0, |
| | | currentPage: 1, |
| | | pageSize: 10, |
| | | pageSizes: [10, 20, 30] |
| | | pageSizes: [10, 20, 30], |
| | | }, |
| | | dialogVisible: false, |
| | | detailVisible: false, |
| | |
| | | department: '', |
| | | handler: '', |
| | | algorithm: [], // 关联算法改为数组 |
| | | location: [], // 将存储为[经度, 纬度, 地址]格式 |
| | | location: [], // 将存储为[经度, 纬度, 地址]格式 |
| | | address: '', |
| | | photos: [], |
| | | content: '', // 新增字段,用于存储后端返回的 content |
| | |
| | | handler: [{ required: true, message: '请选择处理人员', trigger: 'change' }], |
| | | content: [{ required: true, message: '请输入工单内容', trigger: 'blur' }], |
| | | algorithm: [{ required: true, message: '请选择关联算法', trigger: 'change' }], |
| | | location: [{ |
| | | validator: (rule, value, callback) => { |
| | | if (!value || value.length < 2) { |
| | | callback(new Error('请选择位置信息')) |
| | | } else { |
| | | callback() |
| | | } |
| | | location: [ |
| | | { |
| | | validator: (rule, value, callback) => { |
| | | if (!value || value.length < 2) { |
| | | callback(new Error('请选择位置信息')) |
| | | } else { |
| | | callback() |
| | | } |
| | | }, |
| | | trigger: 'blur', |
| | | }, |
| | | trigger: 'blur' |
| | | }], |
| | | photos: [{ |
| | | validator: (rule, value, callback) => { |
| | | if (!this.form.photos || this.form.photos.length === 0) { |
| | | callback(new Error('请上传工单图片')) |
| | | } else { |
| | | callback() |
| | | } |
| | | ], |
| | | photos: [ |
| | | { |
| | | validator: (rule, value, callback) => { |
| | | if (!this.form.photos || this.form.photos.length === 0) { |
| | | callback(new Error('请上传工单图片')) |
| | | } else { |
| | | callback() |
| | | } |
| | | }, |
| | | trigger: 'change', |
| | | }, |
| | | trigger: 'change' |
| | | }], |
| | | ], |
| | | }, |
| | | departmentUsers: {}, |
| | | loading: false, |
| | |
| | | handler: [{ required: true, message: '请选择处理人', trigger: 'change' }], |
| | | }, // 新增:派发表单验证规则 |
| | | stepInfos: [], // 新增:存储步骤信息 |
| | | fixedStatuses: ["2", "0", "3", "4", "5"], // 固定的五个状态 |
| | | fixedStatuses: ['2', '0', '3', '4', '5'], // 固定的五个状态 |
| | | userNameToIdMap: {}, // 新增用户名到ID的映射 |
| | | workType: 0, // 新增:当前工单work_type |
| | | selections: [], // 添加选中行数据数组 |
| | |
| | | }, |
| | | mounted () { |
| | | const href = this.$route.href |
| | | let curQueryParams = {} |
| | | |
| | | if (href.split("?").length > 0) { |
| | | const [orderNumber] = href.split("?")[1].split("&") |
| | | if (href.indexOf('?') != -1 && href.split('?').length > 0) { |
| | | curQueryParams = (href.split('?')[1].split('&')).reduce((pre, cur) => { |
| | | let newArr = cur.split('=') |
| | | |
| | | const order = regExp('orderNumber', orderNumber) |
| | | if (order) { |
| | | this.filters.keyword = order |
| | | pre[newArr[0]] = newArr[1] |
| | | |
| | | return pre |
| | | }, {}) |
| | | |
| | | const { orderNumber = undefined, day = undefined } = curQueryParams |
| | | |
| | | // 日历传值 |
| | | if (day) { |
| | | const date = new Date(day + 'T00:00:00+08:00') |
| | | const dateArray = [date, date] |
| | | const handler = { |
| | | get (target, prop) { |
| | | if (typeof prop === 'string' && /^\d+$/.test(prop)) { |
| | | const index = parseInt(prop) |
| | | const dateObj = target[index] |
| | | return dateObj.toDateString() + ' 00:00:00 GMT+0800 (中国标准时间)' |
| | | } |
| | | return Reflect.get(target, prop) |
| | | }, |
| | | } |
| | | |
| | | const proxyArray = new Proxy(dateArray, handler) |
| | | this.filters.dateRange = proxyArray |
| | | } |
| | | |
| | | if (orderNumber) { |
| | | this.filters.keyword = orderNumber |
| | | |
| | | this.$nextTick(() => { |
| | | this.isShowInfo = true |
| | | }) |
| | | } |
| | | } |
| | | |
| | | |
| | | this.fetchTabCounts() // 新增:初始化时获取 tab 数据 |
| | | this.fetchTableData() |
| | |
| | | return this.tableData.length > 0 ? this.tableData[0] : null |
| | | }, |
| | | availableHandlers () { |
| | | return this.form.department ? (this.departmentUsers[this.form.department] || []) : [] |
| | | return this.form.department ? this.departmentUsers[this.form.department] || [] : [] |
| | | }, |
| | | availableDispatchHandlers () { |
| | | return this.dispatchForm.department ? (this.departmentUsers[this.dispatchForm.department] || []) : [] |
| | | return this.dispatchForm.department |
| | | ? this.departmentUsers[this.dispatchForm.department] || [] |
| | | : [] |
| | | }, |
| | | detailTableData () { |
| | | return [ |
| | | { |
| | | label: "工单名称", |
| | | label: '工单名称', |
| | | value: this.currentDetail.orderName, |
| | | editable: this.currentDetail.status === 0, |
| | | type: "input", |
| | | type: 'input', |
| | | }, |
| | | { |
| | | label: "关键任务", |
| | | label: '关键任务', |
| | | value: this.currentDetail.keyData, |
| | | editable: false, |
| | | }, |
| | | { |
| | | label: "任务发起人", |
| | | label: '任务发起人', |
| | | value: this.currentDetail.creator, |
| | | editable: false, |
| | | }, |
| | | { |
| | | label: "当前状态", |
| | | label: '当前状态', |
| | | value: this.mapStatus(this.currentDetail.status), |
| | | editable: false, |
| | | }, |
| | | { |
| | | label: "事件地址", |
| | | label: '事件地址', |
| | | value: this.currentDetail.address, |
| | | editable: false, |
| | | }, |
| | | { |
| | | label: "工单类型", |
| | | label: '工单类型', |
| | | value: this.currentDetail.type, |
| | | editable: this.currentDetail.status === 0, |
| | | type: "select", |
| | | type: 'select', |
| | | options: this.types, |
| | | }, |
| | | { |
| | | label: "关联算法", |
| | | label: '关联算法', |
| | | value: this.currentDetail.aiType, |
| | | editable: false, |
| | | }, |
| | | { |
| | | label: "发起单位", |
| | | label: '发起单位', |
| | | value: this.currentDetail.department, |
| | | editable: false, |
| | | }, |
| | | { |
| | | label: "发起任务时间", |
| | | label: '发起任务时间', |
| | | value: this.currentDetail.startTime, |
| | | editable: false, |
| | | }, |
| | | { |
| | | label: "工单内容", |
| | | label: '工单内容', |
| | | value: this.currentDetail.content, |
| | | editable: this.currentDetail.status === 0, |
| | | type: "textarea", |
| | | type: 'textarea', |
| | | }, |
| | | ] |
| | | }, |
| | | detailFields () { |
| | | return [ |
| | | { label: "工单名称", value: this.currentDetail.orderName, editable: this.currentDetail.status === 0, type: "input" }, |
| | | { label: "关键任务", value: this.currentDetail.keyData, editable: false }, |
| | | { label: "任务发起人", value: this.currentDetail.creator, editable: false }, |
| | | { label: "当前状态", value: this.mapStatus(this.currentDetail.status), editable: false }, |
| | | { label: "事件地址", value: this.currentDetail.address, editable: false }, |
| | | { label: "工单类型", value: this.currentDetail.type, editable: this.currentDetail.status === 0, type: "select", options: this.types }, |
| | | { label: "关联算法", value: this.currentDetail.aiType, editable: false }, |
| | | { label: "发起单位", value: this.currentDetail.department, editable: false }, |
| | | { label: "发起任务时间", value: this.currentDetail.startTime, editable: false }, |
| | | { label: "工单内容", value: this.currentDetail.content, editable: this.currentDetail.status === 0, type: "textarea" }, |
| | | { |
| | | label: '工单名称', |
| | | value: this.currentDetail.orderName, |
| | | editable: this.currentDetail.status === 0, |
| | | type: 'input', |
| | | }, |
| | | { label: '关键任务', value: this.currentDetail.keyData, editable: false }, |
| | | { label: '任务发起人', value: this.currentDetail.creator, editable: false }, |
| | | { label: '当前状态', value: this.mapStatus(this.currentDetail.status), editable: false }, |
| | | { label: '事件地址', value: this.currentDetail.address, editable: false }, |
| | | { |
| | | label: '工单类型', |
| | | value: this.currentDetail.type, |
| | | editable: this.currentDetail.status === 0, |
| | | type: 'select', |
| | | options: this.types, |
| | | }, |
| | | { label: '关联算法', value: this.currentDetail.aiType, editable: false }, |
| | | { label: '发起单位', value: this.currentDetail.department, editable: false }, |
| | | { label: '发起任务时间', value: this.currentDetail.startTime, editable: false }, |
| | | { |
| | | label: '工单内容', |
| | | value: this.currentDetail.content, |
| | | editable: this.currentDetail.status === 0, |
| | | type: 'textarea', |
| | | }, |
| | | ] |
| | | }, |
| | | formattedDetailFields () { |
| | | const fields = [ |
| | | { label: "工单名称", value: this.currentDetail.orderName }, |
| | | { label: "工单类型", value: this.currentDetail.type }, |
| | | { label: "关联任务", value: this.currentDetail.job_name || '/' }, |
| | | { label: "任务发起人", value: this.currentDetail.creator }, |
| | | { label: "当前状态", value: this.mapStatus(this.currentDetail.status) }, |
| | | { label: "事件地址", value: this.currentDetail.address }, // 包含经纬度信息 |
| | | { label: "关联算法", value: this.currentDetail.aiType }, |
| | | { label: "发起单位", value: this.currentDetail.department }, |
| | | { label: "发起任务时间", value: this.currentDetail.startTime }, |
| | | { label: "工单内容", value: this.currentDetail.content }, |
| | | { label: '工单名称', value: this.currentDetail.orderName }, |
| | | { |
| | | label: '工单类型', |
| | | // 修改这里:使用 types 数组查找对应的 label |
| | | value: this.types.find(t => t.value === this.currentDetail.type)?.label || this.currentDetail.type || '/' |
| | | }, |
| | | { label: '关联任务', value: this.currentDetail.job_name || '/' }, |
| | | { label: '任务发起人', value: this.currentDetail.creator }, |
| | | { label: '当前状态', value: this.mapStatus(this.currentDetail.status) }, |
| | | { label: '事件地址', value: this.currentDetail.address }, // 包含经纬度信息 |
| | | { label: '关联算法', value: this.currentDetail.aiType }, |
| | | { label: '发起单位', value: this.currentDetail.department }, |
| | | { label: '发起任务时间', value: this.currentDetail.startTime }, |
| | | { label: '工单内容', value: this.currentDetail.content }, |
| | | ] |
| | | |
| | | // 将字段分成两列 |
| | | const formattedFields = [] |
| | | for (let i = 0; i < fields.length; i += 2) { |
| | | formattedFields.push({ |
| | | label1: fields[i]?.label || "", |
| | | value1: fields[i]?.value || "暂无数据", |
| | | label2: fields[i + 1]?.label || "", |
| | | value2: fields[i + 1]?.value || "暂无数据", |
| | | label1: fields[i]?.label || '', |
| | | value1: fields[i]?.value || '暂无数据', |
| | | label2: fields[i + 1]?.label || '', |
| | | value2: fields[i + 1]?.value || '暂无数据', |
| | | }) |
| | | } |
| | | return formattedFields |
| | |
| | | const tabStatus = this.permission?.tickets_tab_status === true |
| | | const tabPending = this.permission?.tickets_tab_pending === true |
| | | const tabMyTickets = this.permission?.tickets_tab_mytickets === true |
| | | return this.tabs.map(tab => { |
| | | if (tab.name === 'all') { |
| | | return { ...tab, isShow: true } |
| | | } |
| | | if (tab.name === 'pending') { |
| | | return { ...tab, isShow: tabPending } |
| | | } |
| | | if (['processing', 'inProgress', 'completed', 'closed'].includes(tab.name)) { |
| | | return { ...tab, isShow: tabStatus } |
| | | } |
| | | if (tab.name === 'myTickets') { |
| | | return { ...tab, isShow: tabMyTickets } |
| | | } |
| | | return { ...tab, isShow: false } |
| | | }).filter(tab => tab.isShow) |
| | | return this.tabs |
| | | .map(tab => { |
| | | if (tab.name === 'all') { |
| | | return { ...tab, isShow: true } |
| | | } |
| | | if (tab.name === 'pending') { |
| | | return { ...tab, isShow: tabPending } |
| | | } |
| | | if (['processing', 'inProgress', 'completed', 'closed'].includes(tab.name)) { |
| | | return { ...tab, isShow: tabStatus } |
| | | } |
| | | if (tab.name === 'myTickets') { |
| | | return { ...tab, isShow: tabMyTickets } |
| | | } |
| | | return { ...tab, isShow: false } |
| | | }) |
| | | .filter(tab => tab.isShow) |
| | | }, |
| | | permissionList () { |
| | | // 可根据实际后端权限key调整 |
| | | return { |
| | | addBtn: this.validData(this.permission.tickets_add, false), |
| | | delBtn: this.validData(this.permission.tickets_delete, false), |
| | | exportBtn: this.validData(this.permission.tickets_export, false,), |
| | | exportBtn: this.validData(this.permission.tickets_export, false), |
| | | reviewBtn: this.validData(this.permission.tickets_review, false), |
| | | } |
| | | }, |
| | |
| | | // “我发起的工单”tab用默认流程,其它tab用接口返回的stepInfos |
| | | if (this.activeTab === 'myTickets') { |
| | | if (this.workType === 1) { |
| | | return ["3", "4", "5"] |
| | | return ['3', '4', '5'] |
| | | } |
| | | return this.fixedStatuses |
| | | } |
| | |
| | | }, |
| | | |
| | | showIsReviewText () { |
| | | return (row) => { |
| | | return row => { |
| | | if (['4', '5'].includes(String(row.status))) return row.isReview === 1 ? '是' : '否' |
| | | |
| | | return '/' |
| | | } |
| | | } |
| | | }, |
| | | }, |
| | | methods: { |
| | | async loadAMapScripts () { |
| | |
| | | await this.$confirm('确认审核通过当前工单?', '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning' |
| | | type: 'warning', |
| | | }) |
| | | |
| | | const data = { |
| | |
| | | value: key, |
| | | })) |
| | | |
| | | const columnType = this.findObject(this.option.column, 'type') |
| | | columnType.dicData = this.types |
| | | |
| | | // 确保算法数据的映射一致 |
| | | this.algorithms = ai_type.map(item => ({ |
| | | dict_key: item.dict_key, |
| | | dict_value: item.dict_value, |
| | | // 同时添加 label 和 value 以兼容两处使用 |
| | | label: item.dict_value, |
| | | value: item.dict_key |
| | | })) |
| | | this.algorithms = |
| | | ai_type?.map(item => ({ |
| | | dict_key: item.dict_key, |
| | | dict_value: item.dict_value, |
| | | // 同时添加 label 和 value 以兼容两处使用 |
| | | label: item.dict_value, |
| | | value: item.dict_key, |
| | | })) || [] |
| | | |
| | | // 构建用户ID和名称的映射关系 |
| | | this.userNameToIdMap = {} |
| | |
| | | const currentTab = this.tabs.find(tab => tab.name === this.activeTab) |
| | | const params = { |
| | | word_order_type: this.filters.type || undefined, |
| | | status: currentTab?.name === 'myTickets' ? undefined : |
| | | this.filters.status !== "" ? Number(this.filters.status) : |
| | | currentTab?.value, |
| | | status: |
| | | currentTab?.name === 'myTickets' |
| | | ? undefined |
| | | : this.filters.status !== '' |
| | | ? Number(this.filters.status) |
| | | : currentTab?.value, |
| | | event_name: this.filters.keyword || undefined, |
| | | dept_id: this.filters.department || undefined, |
| | | start_date: this.filters.dateRange?.[0] ? this.formatDate(this.filters.dateRange[0]) : undefined, |
| | | end_date: this.filters.dateRange?.[1] ? this.formatDate(this.filters.dateRange[1]).replace("00:00:00", "23:59:59") : undefined, |
| | | current: Number(this.page.currentPage), // 使用当前页码 |
| | | size: Number(this.page.pageSize), // 使用每页条数 |
| | | start_date: this.filters.dateRange?.[0] |
| | | ? this.formatDate(this.filters.dateRange[0]) |
| | | : undefined, |
| | | end_date: this.filters.dateRange?.[1] |
| | | ? this.formatDate(this.filters.dateRange[1]).replace('00:00:00', '23:59:59') |
| | | : undefined, |
| | | current: Number(this.page.currentPage), // 使用当前页码 |
| | | size: Number(this.page.pageSize), // 使用每页条数 |
| | | ai_type: this.filters.algorithm || undefined, // 添加算法参数 |
| | | // 添加 is_draft 参数,仅在"我发起的"标签页时设置为1 |
| | | is_draft: currentTab?.name === 'myTickets' ? 1 : undefined, |
| | |
| | | id: item.id, |
| | | orderNumber: item.event_num, // 修改这里:优先使用 event_num |
| | | orderName: item.event_name, |
| | | department: this.departments.find(d => d.value === item.dept_id)?.label || item.dept_name, |
| | | department: |
| | | this.departments.find(d => d.value === item.dept_id)?.label || item.dept_name, |
| | | startTime: item.create_time, |
| | | aiType: item.ai_types, |
| | | content: item.content, // 将后端返回的 content 映射为 content |
| | | type: this.types.find(t => t.value === item.work_order_type_dict_key)?.label, |
| | | keyData: (!isNaN(longitude) && !isNaN(latitude)) |
| | | ? `${longitude.toFixed(6)}, ${latitude.toFixed(6)}` |
| | | : '未知位置', |
| | | type: item.work_order_type_dict_key, |
| | | keyData: |
| | | !isNaN(longitude) && !isNaN(latitude) |
| | | ? `${longitude.toFixed(6)}, ${latitude.toFixed(6)}` |
| | | : '未知位置', |
| | | address: item.address, |
| | | creator: item.create_user, |
| | | handler: item.update_user || '未分配', |
| | | status: Number(item.status || 0), |
| | | // 保存原始字段 |
| | | photo_url: item.photo_url || '', // 保存原始 photo_url |
| | | video_url: item.video_url || '', // 保存原始 video_url |
| | | location: (!isNaN(longitude) && !isNaN(latitude)) ? [longitude, latitude] : null, |
| | | photo_url: item.photo_url || '', // 保存原始 photo_url |
| | | video_url: item.video_url || '', // 保存原始 video_url |
| | | location: !isNaN(longitude) && !isNaN(latitude) ? [longitude, latitude] : null, |
| | | processing_details: item.processing_details || '', // 添加处理详情字段 |
| | | update_photo_url: item.update_photo_url || '', // 添加处理图片字段 |
| | | work_type: item.work_type !== undefined ? Number(item.work_type) : 0, // 保留work_type字段并转为数字 |
| | |
| | | } |
| | | await this.fetchTabCounts() |
| | | } catch (error) { |
| | | this.$message.error(error.message || "获取数据失败") |
| | | this.$message.error(error.message || '获取数据失败') |
| | | this.tableData = [] |
| | | this.page.total = 0 |
| | | } finally { |
| | |
| | | const submitData = { |
| | | eventName: this.form.name, |
| | | content: this.form.content, |
| | | workType: "1", |
| | | workType: '1', |
| | | longitude: lng, |
| | | latitude: lat, |
| | | address: this.form.address, |
| | |
| | | aiType: Array.isArray(this.form.algorithm) ? this.form.algorithm : [this.form.algorithm], // 传数组 |
| | | updateUser: this.form.handler, |
| | | createDept: this.form.department, |
| | | isDraft: 0 |
| | | isDraft: 0, |
| | | } |
| | | |
| | | if (this.form.id) { |
| | |
| | | } else { |
| | | this.$message.error(error.message || '工单创建失败,请稍后重试') |
| | | } |
| | | } |
| | | finally { |
| | | } finally { |
| | | this.submitLoading = false |
| | | } |
| | | }, |
| | |
| | | id: this.form.id, |
| | | eventName: this.form.name || undefined, |
| | | content: this.form.content || undefined, |
| | | workType: "1", |
| | | workType: '1', |
| | | longitude: lng, |
| | | latitude: lat, |
| | | address: this.form.address || undefined, |
| | | workOrderTypeDictKey: this.form.type || undefined, |
| | | aiType: this.form.algorithm && this.form.algorithm.length > 0 |
| | | ? this.form.algorithm |
| | | : undefined, // 传数组 |
| | | aiType: |
| | | this.form.algorithm && this.form.algorithm.length > 0 ? this.form.algorithm : undefined, // 传数组 |
| | | updateUser: handlerValue, |
| | | createDept: this.form.department || undefined, |
| | | isDraft: 1 |
| | | isDraft: 1, |
| | | } |
| | | |
| | | // 草稿时也至少需要工单名称 |
| | |
| | | } |
| | | |
| | | // 过滤掉所有 undefined 的字段 |
| | | Object.keys(submitData).forEach(key => |
| | | submitData[key] === undefined && delete submitData[key] |
| | | Object.keys(submitData).forEach( |
| | | key => submitData[key] === undefined && delete submitData[key] |
| | | ) |
| | | |
| | | let file = null |
| | |
| | | } |
| | | } catch (error) { |
| | | this.$message.error(error.message || '保存草稿失败,请稍后重试') |
| | | } |
| | | finally { |
| | | } finally { |
| | | this.draftLoading = false |
| | | } |
| | | }, |
| | |
| | | this.form.location = [ |
| | | Number(locationValue[0]), |
| | | Number(locationValue[1]), |
| | | locationValue[2] || '' |
| | | locationValue[2] || '', |
| | | ] |
| | | this.form.address = locationValue[2] || '' |
| | | } else { |
| | |
| | | formatDate (date) { |
| | | if (!date) return undefined |
| | | const d = new Date(date) |
| | | return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')} 00:00:00` |
| | | return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String( |
| | | d.getDate() |
| | | ).padStart(2, '0')} 00:00:00` |
| | | }, |
| | | |
| | | mapStatus (status) { |
| | | const statusTextMap = { |
| | | "-1": "草稿", // 添加草稿状态 |
| | | "2": "待审核", |
| | | "0": "待处理", |
| | | "3": "处理中", |
| | | "4": "已完成", |
| | | "5": "已完结" |
| | | '-1': '草稿', // 添加草稿状态 |
| | | 2: '待审核', |
| | | 0: '待处理', |
| | | 3: '处理中', |
| | | 4: '已完成', |
| | | } |
| | | return statusTextMap[status] || "未知状态" |
| | | return statusTextMap[status] || '未知状态' |
| | | }, |
| | | |
| | | getStatusTagType (status) { |
| | | // 草稿不加颜色 |
| | | if (status === -1 || status === "-1") return '' |
| | | if (status === -1 || status === '-1') return '' |
| | | // 状态颜色映射 |
| | | const colorMap = { |
| | | "0": "#ffb6b6", // 待处理-淡红 |
| | | "3": "#e57373", // 处理中-更淡红 |
| | | "2": "#faad14", // 待审核-橙色 |
| | | "4": "#a0cfff", // 已完成-淡蓝 |
| | | "5": "#67c23a", // 已完结-绿色 |
| | | 0: '#ffb6b6', // 待处理-淡红 |
| | | 3: '#e57373', // 处理中-更淡红 |
| | | 2: '#faad14', // 待审核-橙色 |
| | | 4: '#a0cfff', // 已完成-淡蓝 |
| | | } |
| | | return colorMap[String(status)] || '' |
| | | }, |
| | |
| | | |
| | | handleReset () { |
| | | this.filters = { |
| | | keyword: "", |
| | | department: "", |
| | | type: "", |
| | | keyword: '', |
| | | department: '', |
| | | type: '', |
| | | dateRange: [], |
| | | status: "", |
| | | algorithm: "", // 重置时清空算法筛选 |
| | | isReview: "", // 重置时清空复核状态 |
| | | status: '', |
| | | algorithm: '', // 重置时清空算法筛选 |
| | | isReview: '', // 重置时清空复核状态 |
| | | } |
| | | this.page.currentPage = 1 |
| | | this.fetchTableData() |
| | |
| | | department: '', |
| | | handler: '', |
| | | algorithm: [], // 关联算法改为数组 |
| | | location: [], // 将存储为[经度, 纬度, 地址]格式 |
| | | location: [], // 将存储为[经度, 纬度, 地址]格式 |
| | | address: '', |
| | | content: '', |
| | | photos: [], |
| | |
| | | }, |
| | | |
| | | async handleViewDetail (row) { |
| | | |
| | | // 先设置workType,直接从row读取 |
| | | this.workType = row.work_type !== undefined ? Number(row.work_type) : 0 |
| | | |
| | |
| | | create_time: step.create_time, |
| | | })) |
| | | } else { |
| | | const statusArr = this.workType === 1 ? ["3", "4", "5"] : this.fixedStatuses |
| | | const statusArr = this.workType === 1 ? ['3', '4', '5'] : this.fixedStatuses |
| | | this.stepInfos = statusArr.map(status => { |
| | | const step = steps.find(s => String(s.status) === String(status)) |
| | | return { |
| | |
| | | this.currentDetail.status = row.status |
| | | } catch (error) { |
| | | if (this.activeTab === 'myTickets') { |
| | | const statusArr = this.workType === 1 ? ["3", "4", "5"] : this.fixedStatuses |
| | | const statusArr = this.workType === 1 ? ['3', '4', '5'] : this.fixedStatuses |
| | | this.stepInfos = statusArr.map(status => ({ |
| | | status, |
| | | name: status === row.status ? row.handler || '未分配' : '未处理', |
| | |
| | | const areaCode = this.userInfo.detail.areaCode |
| | | const subAreaCode = areaCode ? areaCode.substring(0, 6) : '' |
| | | getAdcodeObj(geoJson, 'adcode', subAreaCode) |
| | | this.$message.info("地图选址功能暂未实现") |
| | | this.$message.info('地图选址功能暂未实现') |
| | | }, |
| | | |
| | | handlePreview (file) { |
| | |
| | | 关联算法: item.aiType || '', |
| | | 工单内容: item.address || '', |
| | | 工单类型: item.type || '', |
| | | 经纬度: item.location ? `${item.location[0].toFixed(6)}, ${item.location[1].toFixed(6)}` : '', |
| | | 经纬度: item.location |
| | | ? `${item.location[0].toFixed(6)}, ${item.location[1].toFixed(6)}` |
| | | : '', |
| | | 创建人: item.creator || '', |
| | | 处理人: item.handler || '', |
| | | 工单状态: this.mapStatus(item.status) |
| | | 工单状态: this.mapStatus(item.status), |
| | | })) |
| | | } else { |
| | | // 原有的导出全部数据的逻辑 |
| | |
| | | // 使用与查询列表相同的参数构造逻辑 |
| | | const params = { |
| | | word_order_type: this.filters.type || undefined, |
| | | status: currentTab?.name === 'myTickets' ? undefined : |
| | | this.filters.status !== "" ? Number(this.filters.status) : |
| | | currentTab?.value, // 使用当前tab的状态值 |
| | | status: |
| | | currentTab?.name === 'myTickets' |
| | | ? undefined |
| | | : this.filters.status !== '' |
| | | ? Number(this.filters.status) |
| | | : currentTab?.value, // 使用当前tab的状态值 |
| | | keyword: this.filters.keyword || undefined, |
| | | dept_id: this.filters.department || undefined, |
| | | start_date: this.filters.dateRange?.[0] ? this.formatDate(this.filters.dateRange[0]) : undefined, |
| | | end_date: this.filters.dateRange?.[1] ? this.formatDate(this.filters.dateRange[1]) : undefined, |
| | | start_date: this.filters.dateRange?.[0] |
| | | ? this.formatDate(this.filters.dateRange[0]) |
| | | : undefined, |
| | | end_date: this.filters.dateRange?.[1] |
| | | ? this.formatDate(this.filters.dateRange[1]) |
| | | : undefined, |
| | | current: 1, |
| | | size: 10 |
| | | size: 10, |
| | | } |
| | | |
| | | const response = await getList(params) |
| | |
| | | // 使用与查询列表相同的过滤逻辑 |
| | | let filteredRecords = records |
| | | if (currentTab?.name === 'myTickets') { |
| | | filteredRecords = records.filter(item => |
| | | String(item.create_user_id) === String(item.user_id) |
| | | filteredRecords = records.filter( |
| | | item => String(item.create_user_id) === String(item.user_id) |
| | | ) |
| | | } |
| | | |
| | |
| | | 发起时间: item.create_time || '', |
| | | 关联算法: item.ai_types || '', |
| | | 工单内容: item.address || '', |
| | | 工单类型: this.types.find(t => t.value === item.work_order_type_dict_key)?.label || '', |
| | | 经纬度: (!isNaN(longitude) && !isNaN(latitude)) ? `${longitude.toFixed(6)}, ${latitude.toFixed(6)}` : '', |
| | | 工单类型: |
| | | this.types.find(t => t.value === item.work_order_type_dict_key)?.label || '', |
| | | 经纬度: |
| | | !isNaN(longitude) && !isNaN(latitude) |
| | | ? `${longitude.toFixed(6)}, ${latitude.toFixed(6)}` |
| | | : '', |
| | | 创建人: item.create_user || '', |
| | | 处理人: item.update_user || '', |
| | | 工单状态: this.mapStatus(Number(item.status || 0)) |
| | | 工单状态: this.mapStatus(Number(item.status || 0)), |
| | | } |
| | | }) |
| | | } |
| | |
| | | '经纬度', |
| | | '创建人', |
| | | '处理人', |
| | | '工单状态' |
| | | '工单状态', |
| | | ] |
| | | |
| | | export_json_to_excel(headers, exportData, '工单数据') |
| | |
| | | // 保持最新的文件列表 |
| | | this.form.photos = fileList.map(item => ({ |
| | | ...item, |
| | | existingUrl: item.url && !item.raw ? item.url : null // 标记已存在的图片URL |
| | | existingUrl: item.url && !item.raw ? item.url : null, // 标记已存在的图片URL |
| | | })) |
| | | this.currentDetail.photos = this.form.photos |
| | | }, |
| | |
| | | if (this.currentDetail.status !== 3) { |
| | | this.$message.warning('只有处理中状态的工单可以提交处理详情') |
| | | return |
| | | |
| | | } |
| | | |
| | | try { |
| | |
| | | } |
| | | }, |
| | | markAsCompleted () { |
| | | this.$message.success("工单已标记为完成") |
| | | this.$message.success('工单已标记为完成') |
| | | }, |
| | | async completeTicket () { |
| | | if (this.completeLoading) return |
| | |
| | | return |
| | | } |
| | | |
| | | |
| | | const data = { |
| | | id: this.currentDetail.id, |
| | | status: this.currentDetail.status, |
| | | processingDetails: this.currentDetail.processingDetail, |
| | | eventNum: this.currentDetail.orderNumber |
| | | eventNum: this.currentDetail.orderNumber, |
| | | } |
| | | |
| | | // 如果有上传的图片,添加到请求中 |
| | |
| | | return |
| | | } |
| | | this.dispatchLoading = true |
| | | this.$refs.dispatchForm.validate(async (valid) => { |
| | | this.$refs.dispatchForm.validate(async valid => { |
| | | if (valid) { |
| | | try { |
| | | const data = { |
| | |
| | | createDept: this.dispatchForm.department, // 派发部门 ID |
| | | updateUser: this.dispatchForm.handler, // 处理人 ID |
| | | } |
| | | |
| | | |
| | | const file = this.currentDetail.file || null // 如果没有文件,则为 null |
| | | |
| | |
| | | console.log('编辑原始数据:', row) |
| | | |
| | | // 尝试从row.dept_id或通过部门名称查找对应的部门ID |
| | | let deptId = row.dept_id // 优先使用原始数据中的dept_id |
| | | let deptId = row.dept_id // 优先使用原始数据中的dept_id |
| | | |
| | | // 如果没有dept_id,则通过部门名称查找 |
| | | if (!deptId) { |
| | |
| | | console.log('可用部门列表:', this.departments) |
| | | console.log('当前部门名称:', row.department) |
| | | |
| | | const deptInfo = this.departments.find(dept => |
| | | dept.label && dept.label.trim() === row.department.trim() |
| | | const deptInfo = this.departments.find( |
| | | dept => dept.label && dept.label.trim() === row.department.trim() |
| | | ) |
| | | deptId = deptInfo?.value |
| | | } |
| | | |
| | | // 获取工单类型值 - 从types中找到匹配的值 |
| | | const typeValue = this.types.find(t => t.label === row.type)?.value || row.work_order_type_dict_key |
| | | const typeValue = |
| | | this.types.find(t => t.label === row.type)?.value || row.work_order_type_dict_key |
| | | |
| | | // 获取处理人ID - 使用userNameToIdMap映射 |
| | | const handlerId = this.userNameToIdMap[row.handler] || row.handler |
| | |
| | | 原始处理人: row.handler, |
| | | 处理人ID: handlerId, |
| | | 原始工单类型: row.type, |
| | | 映射后类型值: typeValue |
| | | 映射后类型值: typeValue, |
| | | }) |
| | | |
| | | // 修改算法数组的处理逻辑 |
| | |
| | | } |
| | | |
| | | // 确保算法值与选项匹配 |
| | | algorithmArr = algorithmArr.map(item => { |
| | | // 如果是字符串值,尝试找到对应的 dict_key |
| | | if (typeof item === 'string') { |
| | | const matchedAlgorithm = this.algorithms.find( |
| | | algo => algo.dict_value === item || algo.dict_key === item |
| | | ) |
| | | return matchedAlgorithm ? matchedAlgorithm.dict_key : item |
| | | } |
| | | return item |
| | | }).filter(Boolean) // 过滤掉无效值 |
| | | algorithmArr = algorithmArr |
| | | .map(item => { |
| | | // 如果是字符串值,尝试找到对应的 dict_key |
| | | if (typeof item === 'string') { |
| | | const matchedAlgorithm = this.algorithms.find( |
| | | algo => algo.dict_value === item || algo.dict_key === item |
| | | ) |
| | | return matchedAlgorithm ? matchedAlgorithm.dict_key : item |
| | | } |
| | | return item |
| | | }) |
| | | .filter(Boolean) // 过滤掉无效值 |
| | | |
| | | console.log('算法处理:', { |
| | | 原始值: row.aiType, |
| | |
| | | department: deptId, |
| | | handler: handlerId, |
| | | algorithm: algorithmArr, |
| | | location: Array.isArray(row.location) && row.location.length >= 2 |
| | | ? [Number(row.location[0]), Number(row.location[1])] |
| | | : [], |
| | | location: |
| | | Array.isArray(row.location) && row.location.length >= 2 |
| | | ? [Number(row.location[0]), Number(row.location[1])] |
| | | : [], |
| | | address: row.address || '', |
| | | content: row.content, |
| | | photos: [], |
| | |
| | | if (Array.isArray(row.location) && row.location.length >= 2) { |
| | | let [lng, lat] = this.disposeLocation(false, row) |
| | | |
| | | curLocation = [ |
| | | lng, |
| | | lat, |
| | | row.location[2] || row.address || '' |
| | | ] |
| | | curLocation = [lng, lat, row.location[2] || row.address || ''] |
| | | } |
| | | |
| | | this.form.location = curLocation |
| | |
| | | // 如果有图片,添加到表单中 |
| | | if (row.photo_url) { |
| | | // 创建一个带有必要信息的文件对象 |
| | | this.form.photos = [{ |
| | | name: 'existing-photo.jpg', // 添加默认扩展名 |
| | | url: row.photo_url, // 用于预览的URL |
| | | status: 'success', // 标记为已上传成功 |
| | | raw: null, // 初始化为null |
| | | existingUrl: row.photo_url // 保存原始URL,用于区分是否为已存在的图片 |
| | | }] |
| | | this.form.photos = [ |
| | | { |
| | | name: 'existing-photo.jpg', // 添加默认扩展名 |
| | | url: row.photo_url, // 用于预览的URL |
| | | status: 'success', // 标记为已上传成功 |
| | | raw: null, // 初始化为null |
| | | existingUrl: row.photo_url, // 保存原始URL,用于区分是否为已存在的图片 |
| | | }, |
| | | ] |
| | | } |
| | | |
| | | // 调试输出 |
| | | console.log('编辑表单数据:', { |
| | | 原始算法值: row.aiType, |
| | | 处理后算法值: algorithmArr, |
| | | 表单数据: this.form |
| | | 表单数据: this.form, |
| | | }) |
| | | |
| | | this.dialogVisible = true |
| | |
| | | this.$confirm('确认删除该工单?', '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning' |
| | | }).then(async () => { |
| | | try { |
| | | const response = await flowEvent({ |
| | | id: row.id, |
| | | status: 0, |
| | | isDelete: 1 |
| | | }) |
| | | type: 'warning', |
| | | }) |
| | | .then(async () => { |
| | | try { |
| | | const response = await flowEvent({ |
| | | id: row.id, |
| | | status: 0, |
| | | isDelete: 1, |
| | | }) |
| | | |
| | | if (response.data.code === 0) { |
| | | this.$message.success('删除成功') |
| | | this.fetchTableData() |
| | | } else { |
| | | throw new Error(response.data.msg || '删除失败') |
| | | if (response.data.code === 0) { |
| | | this.$message.success('删除成功') |
| | | this.fetchTableData() |
| | | } else { |
| | | throw new Error(response.data.msg || '删除失败') |
| | | } |
| | | } catch (error) { |
| | | console.error('删除失败:', error) |
| | | this.$message.error(error.message || '删除失败,请稍后重试') |
| | | } |
| | | } catch (error) { |
| | | console.error('删除失败:', error) |
| | | this.$message.error(error.message || '删除失败,请稍后重试') |
| | | } |
| | | }).catch(() => { }) |
| | | }) |
| | | .catch(() => { }) |
| | | }, |
| | | |
| | | // 添加选择变化处理方法 |
| | |
| | | await this.$confirm('确认审核通过当前工单?', '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning' |
| | | type: 'warning', |
| | | }) |
| | | |
| | | const data = { |
| | |
| | | // 刷新表格数据 |
| | | // this.fetchTableData(); |
| | | this.selections = newSelections |
| | | |
| | | } else { |
| | | throw new Error(response.data.msg || '审核失败') |
| | | } |
| | |
| | | await this.$confirm('确认该工单审核不通过?', '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning' |
| | | type: 'warning', |
| | | }) |
| | | |
| | | const data = { |
| | |
| | | |
| | | // 获取所有图片列表用于预览 |
| | | getImageList () { |
| | | return this.selections |
| | | .map(item => this.getPreviewUrl(item.photo_url)) |
| | | .filter(url => url) // 过滤掉空值 |
| | | return this.selections.map(item => this.getPreviewUrl(item.photo_url)).filter(url => url) // 过滤掉空值 |
| | | }, |
| | | |
| | | // 处理图片点击 |
| | |
| | | reCheckConfirm (key) { |
| | | const that = this |
| | | if (key == 1) { |
| | | getReviewById(this.reCheckData.id).then(res => { |
| | | this.reCheckDialog = false |
| | | this.page.currentPage = 1 |
| | | this.fetchTableData() |
| | | this.fetchTabCounts() |
| | | getReviewById(that.reCheckData.id).then(res => { |
| | | that.reCheckDialog = false |
| | | that.page.currentPage = 1 |
| | | that.fetchTableData() |
| | | that.fetchTabCounts() |
| | | }) |
| | | } else { |
| | | |
| | | const loading = ElLoading.service({ |
| | | lock: true, |
| | | text: '复核任务创建中……', |
| | | background: 'rgba(0, 0, 0, 0.7)', |
| | | }) |
| | | |
| | | function closeConfirm () { |
| | | that.reCheckDialog = false |
| | | that.page.currentPage = 1 |
| | | that.fetchTableData() |
| | | that.fetchTabCounts() |
| | | loading.close() |
| | | } |
| | | |
| | | // 获取时间的接口 |
| | | getCreateEventJob(that.reCheckData.id).then(res => { |
| | | loading.close() |
| | | |
| | | ElMessageBox.confirm(`预计复核执行时间为${res.data.data}`, '提示', { |
| | | confirmButtonText: '确定', |
| | | showCancelButton: false, // 关键配置 |
| | | type: 'warning' |
| | | closeOnClickModal: false, |
| | | closeOnPressEscape: false, |
| | | type: 'warning', |
| | | }).then(() => { |
| | | this.reCheckDialog = false |
| | | this.page.currentPage = 1 |
| | | this.fetchTableData() |
| | | this.fetchTabCounts() |
| | | closeConfirm() |
| | | }).catch(() => { |
| | | closeConfirm() |
| | | }) |
| | | }).catch(() => { |
| | | closeConfirm() |
| | | }) |
| | | } |
| | | } |
| | | }, |
| | | }, |
| | | } |
| | | </script> |
| | |
| | | |
| | | // 添加删除按钮样式 |
| | | .danger-button { |
| | | color: #F56C6C; |
| | | color: #f56c6c; |
| | | } |
| | | |
| | | .danger-button:hover { |
| | |
| | | :deep(.el-dialog__body) { |
| | | padding: 0; |
| | | background-color: #f5f7fa; |
| | | |
| | | } |
| | | } |
| | | |
| | |
| | | display: inline-block; |
| | | |
| | | .required-star { |
| | | color: #F56C6C; |
| | | color: #f56c6c; |
| | | margin-right: 4px; |
| | | } |
| | | } |
| | |
| | | :deep(.el-input__inner), |
| | | :deep(.el-textarea__inner) { |
| | | &:focus { |
| | | border-color: #409EFF; |
| | | border-color: #409eff; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | | </style> |
| | |
| | | <div class="block"> |
| | | <div class="title">待办事项</div> |
| | | |
| | | <div class="todo-items"> |
| | | <div class="todo-items" v-if="todos.length>0"> |
| | | <div |
| | | v-for="(item, index) in todos" |
| | | :key="index" |
| | | class="todo-item" |
| | | :class="`status-${item.status}`" |
| | | :style="getStatusStyle(item.status)" |
| | | @click="jumporder(item)" |
| | | > |
| | | <div class="status-indicator"></div> |
| | | <div |
| | | class="status-indicator" |
| | | :style="{ backgroundColor: getStatusColor(item.status) }" |
| | | ></div> |
| | | |
| | | <div class="content-wrapper"> |
| | | <div class="main-content"> |
| | | <span class="status-tag">{{ statusMap[item.status] }}</span> |
| | | <span class="todo-text">{{ item.title }}</span> |
| | | <span class="status-tag" :style="{ color: getStatusColor(item.status) }">{{ |
| | | permission.o_and_m_p_jump === true |
| | | ? zfstatusMap[item.status] |
| | | : statusMap[item.status] |
| | | }}</span> |
| | | <span class="todo-text">{{ item.name }}</span> |
| | | </div> |
| | | |
| | | <div class="action-area"> |
| | | <img :src="st7" alt=""> |
| | | <span class="todo-date">{{ item.date }}</span> |
| | | <img :src="st7" alt="" /> |
| | | <span class="todo-date">{{ item.date?.slice(0, 10).replace(/-/g, '.') }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div v-else> |
| | | <el-empty > |
| | | <template #description> |
| | | <span class="custom-text">暂无数据</span> |
| | | </template> |
| | | </el-empty> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import st7 from '@/assets/images/workbench/st7.png' |
| | | // 状态显示映射 |
| | | import st7 from '@/assets/images/workbench/st7.png'; |
| | | import { getdaiban } from '@/api/home/index'; |
| | | import { onMounted } from 'vue'; |
| | | import { useRouter } from 'vue-router'; |
| | | import { useStore } from 'vuex'; |
| | | const router = useRouter(); |
| | | const store = useStore(); |
| | | const permission = computed(() => store.getters.permission); |
| | | const userInfo = computed(() => store.getters.userInfo); |
| | | const todos = ref([]); |
| | | const loading = ref(false); |
| | | const statusMap = { |
| | | pending: '待审核', |
| | | processing: '处理中', |
| | | todo: '待处理', |
| | | 0: '待处理', |
| | | 2: '待审核', |
| | | 3: '处理中', |
| | | }; |
| | | const statusMapColor = { |
| | | 0: { color: '#FF7411', background: '#FF7411', borderLeftColor: '#FF7411' }, |
| | | 2: { color: '#FF472F', background: '#FF472F', borderLeftColor: '#FF472F' }, |
| | | 3: { color: '#FFC300', background: '#FFC300', borderLeftColor: '#FFC300' }, |
| | | }; |
| | | const zfstatusMap = { |
| | | 1: '待审核', |
| | | }; |
| | | const zfstatusMapColor = { |
| | | 1: { color: '#FF472F', background: '#FF472F', borderLeftColor: '#FF472F' }, |
| | | }; |
| | | const getStatusStyle = statusIndex => { |
| | | if (permission.value.o_and_m_p_jump === true) { |
| | | const style = zfstatusMapColor[statusIndex] || { |
| | | color: '#999', |
| | | borderLeftColor: '#999', |
| | | }; |
| | | return { |
| | | color: style.color, |
| | | borderLeft: `3px solid ${style.borderLeftColor}`, |
| | | }; |
| | | } else { |
| | | const style = statusMapColor[statusIndex] || { |
| | | color: '#999', |
| | | borderLeftColor: '#999', |
| | | }; |
| | | return { |
| | | color: style.color, |
| | | borderLeft: `3px solid ${style.borderLeftColor}`, |
| | | }; |
| | | } |
| | | }; |
| | | // 获取状态对应的文字颜色 |
| | | const getStatusColor = statusIndex => { |
| | | if (permission.value.o_and_m_p_jump === true) { |
| | | return zfstatusMapColor[statusIndex]?.color || '#999'; |
| | | } else { |
| | | return statusMapColor[statusIndex]?.color || '#999'; |
| | | } |
| | | }; |
| | | const getListMatter = async () => { |
| | | loading.value = true; |
| | | try { |
| | | if (permission.value.o_and_m_p_jump === true) { |
| | | const res = await getdaiban(0, userInfo.value.detail.areaCode); |
| | | todos.value = res.data.data?.slice(0, 5) || []; |
| | | loading.value = false; |
| | | } else { |
| | | const res = await getdaiban(1, userInfo.value.detail.areaCode); |
| | | todos.value = res.data.data?.slice(0, 5) || []; |
| | | loading.value = false; |
| | | } |
| | | } catch (error) {} |
| | | }; |
| | | const isDataReady = computed(() => { |
| | | return userInfo.value.detail?.areaCode && permission.value.o_and_m_p_jump; |
| | | }); |
| | | const autoFetchData = () => { |
| | | if (isDataReady.value) { |
| | | getListMatter(); |
| | | } |
| | | }; |
| | | watch( |
| | | () => [userInfo.value.detail?.areaCode, permission.value.o_and_m_p_jump], |
| | | () => autoFetchData(), |
| | | { immediate: true } |
| | | ); |
| | | |
| | | // 待办事项数据 |
| | | const todos = ref([ |
| | | { |
| | | status: 'pending', |
| | | title: '发现暴露垃圾事件', |
| | | date: '2025.03.26', |
| | | }, |
| | | { |
| | | status: 'todo', |
| | | title: '发现暴露垃圾事件', |
| | | date: '2025.03.26', |
| | | }, |
| | | { |
| | | status: 'processing', |
| | | title: '发现暴露垃圾事件', |
| | | date: '2025.03.26', |
| | | }, |
| | | { |
| | | status: 'pending', |
| | | title: '发现暴露垃圾事件', |
| | | date: '2025.03.26', |
| | | }, |
| | | { |
| | | status: 'todo', |
| | | title: '发现暴露垃圾事件', |
| | | date: '2025.03.26', |
| | | }, |
| | | ]); |
| | | const jumporder = val => { |
| | | if (permission.value.o_and_m_p_jump === true) { |
| | | const id = val.id; |
| | | router.push({ |
| | | path: `/tickets/orderLog`, |
| | | query: { |
| | | id, |
| | | }, |
| | | }); |
| | | } else { |
| | | const orderNumber = val.event_num; |
| | | router.push({ |
| | | path: `/tickets/ticket`, |
| | | query: { |
| | | orderNumber, |
| | | }, |
| | | }); |
| | | } |
| | | }; |
| | | onMounted(() => { |
| | | autoFetchData(); |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | |
| | | .block { |
| | | margin: 11px 21px 13px 22px; |
| | | .title { |
| | | font-family: 'Source Han Sans CN'; |
| | | font-weight: bold; |
| | | font-size: 16px; |
| | | color: #363636; |
| | |
| | | |
| | | .todo-items { |
| | | display: grid; |
| | | gap: 0.8rem; |
| | | gap: 0.6rem; |
| | | margin-top: 10px; |
| | | } |
| | | |
| | | .todo-item { |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | background: #FFFFFF; |
| | | cursor: pointer; |
| | | background: #ffffff; |
| | | border-radius: 8px; |
| | | box-shadow: 0px 2px 4px 0px rgba(173, 173, 173, 0.18); |
| | | transition: all 0.2s ease; |
| | |
| | | .action-area { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-right: 42px; |
| | | margin-right: 42px; |
| | | |
| | | .todo-date { |
| | | color: #666; |
| | | font-size: 0.9rem; |
| | | } |
| | | |
| | | |
| | | } |
| | | } |
| | | |
| | | // 状态颜色方案 |
| | | .status-pending { |
| | | border-left-color: #FF6560; |
| | | color: #FF6560; |
| | | .status-0 { |
| | | border-left-color: #ff7411; |
| | | color: #ff7411; |
| | | .status-indicator { |
| | | background: #FF6560; |
| | | background: #ff7411; |
| | | } |
| | | } |
| | | |
| | | .status-todo { |
| | | border-left-color: #5D77FB; |
| | | color: #5D77FB; |
| | | .status-2 { |
| | | border-left-color: #ff472f; |
| | | color: #ff472f; |
| | | .status-indicator { |
| | | background: #5D77FB; |
| | | background: #ff472f; |
| | | } |
| | | } |
| | | |
| | | .status-processing { |
| | | border-left-color: #FF8B26; |
| | | color: #FF8B26; |
| | | .status-3 { |
| | | border-left-color: #ffc300; |
| | | color: #ffc300; |
| | | |
| | | .status-indicator { |
| | | background: #FF8B26; |
| | | background: #ffc300; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // @media (max-width: 768px) { |
| | | // .todo-list-container { |
| | | // padding: 1rem; |
| | | |
| | | // .content-wrapper { |
| | | // flex-direction: column; |
| | | // align-items: flex-start !important; |
| | | // gap: 0.5rem !important; |
| | | // } |
| | | |
| | | // .action-area { |
| | | // width: 100%; |
| | | // justify-content: space-between; |
| | | // } |
| | | // } |
| | | // } |
| | | |
| | | // @media (max-width: 480px) { |
| | | // .main-content { |
| | | // flex-direction: column; |
| | | // align-items: flex-start !important; |
| | | // } |
| | | |
| | | // .status-tag { |
| | | // margin-bottom: 0.3rem; |
| | | // } |
| | | // } |
| | | .custom-text { |
| | | font-size: 14px; |
| | | color: #7C8091; |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div class="calenBox"> |
| | | <el-calendar ref="calendar" v-model="leftValue" @change="handleMonthChange(date)"> |
| | | <el-calendar ref="calendar" v-model="leftValue"> |
| | | <template #date-cell="{ data }"> |
| | | <div> |
| | | <div :class="data.isSelected ? 'is-selected' : ''"> |
| | | <div class="date-number">{{ data.day.slice(8, 10) }}</div> |
| | | <div class="events"> |
| | | <div |
| | |
| | | :key="index" |
| | | class="event-item" |
| | | :class="event.type" |
| | | @click="jumpcalendar(event, data.day)" |
| | | > |
| | | <span></span> |
| | | {{ event.content }} |
| | | <img :src="getEventIcon(event.type)" alt="" /> |
| | | {{ event.name }}<span>{{ event.value }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | <script setup> |
| | | import dayjs from 'dayjs'; |
| | | import { jobEventBar, getCalen } from '@/api/home/index'; |
| | | // 日历事件数据 |
| | | // 格式: 'YYYY-MM-DD': [...events] |
| | | const events = ref({ |
| | | '2025-05-01': [ |
| | | { type: 'work-order', content: '工单26' }, |
| | | { type: 'task', content: '任务26' }, |
| | | ], |
| | | '2025-05-04': [ |
| | | { type: 'task', content: '任务26' }, |
| | | { type: 'work-order', content: '工单26' }, |
| | | ], |
| | | }); |
| | | import { useRouter } from 'vue-router'; |
| | | import ev1 from '@/assets/images/workbench/ev1.png'; |
| | | import ev2 from '@/assets/images/workbench/ev2.png'; |
| | | import { ElMessage } from 'element-plus' |
| | | const router = useRouter(); |
| | | const events = ref({}); |
| | | const params = ref({ |
| | | end_date: undefined, |
| | | start_date: undefined, |
| | | }); |
| | | |
| | | const eventIcons = ref({ |
| | | 'work-order': ev1, |
| | | task: ev2, |
| | | }); |
| | | const getEventIcon = type => { |
| | | return eventIcons.value[type] || eventIcons.value.default; |
| | | }; |
| | | function getCurrentMonthRange() { |
| | | return { |
| | | start_date: dayjs().startOf('month').format('YYYY-MM-DD HH:mm:ss'), |
| | |
| | | watch( |
| | | () => leftValue.value, |
| | | (newV, oldV) => { |
| | | if (newV && dayjs(newV).isSame(dayjs(), 'day')) { |
| | | console.log('点击了今天'); |
| | | } |
| | | |
| | | if (newV && oldV) { |
| | | const newDate = dayjs(newV); |
| | | const oldDate = dayjs(oldV); |
| | | |
| | | if (newDate.isBefore(oldDate, 'month')) { |
| | | console.log('点击了上个月'); |
| | | } else if (newDate.isAfter(oldDate, 'month')) { |
| | | console.log('点击了下个月'); |
| | | } |
| | | params.value = { |
| | | start_date: newDate.startOf('month').format('YYYY-MM-DD HH:mm:ss'), |
| | | end_date: newDate.endOf('month').format('YYYY-MM-DD HH:mm:ss'), |
| | | }; |
| | | getJobEventBar(); |
| | | } |
| | | }, |
| | | { deep: true } |
| | | { deep: true, immediate: true } |
| | | ); |
| | | const handleMonthChange = date => { |
| | | console.log('date', date); |
| | | |
| | | // 获取当前视图月份的第一天 |
| | | const firstDay = new Date(date.getFullYear(), date.getMonth(), 1); |
| | | |
| | | // 获取当前视图月份的最后一天 |
| | | const lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0); |
| | | |
| | | // 格式化为YYYY-MM-DD格式(可选) |
| | | const formatDate = d => d.toISOString().slice(0, 10); |
| | | |
| | | console.log('首日:', formatDate(firstDay)); |
| | | console.log('末日:', formatDate(lastDay)); |
| | | }; |
| | | // 获取日期数字 |
| | | const getDate = date => { |
| | | return date.getDate(); |
| | | }; |
| | | // 获取对应日期的事件 |
| | | const getEvents = dateString => { |
| | | // console.log('000',dateString); |
| | | |
| | | return events.value[dateString] || []; |
| | | }; |
| | | const monthRange = getCurrentMonthRange(); |
| | | params.value = monthRange; |
| | | const getJobEventBar = () => { |
| | | const monthRange = getCurrentMonthRange(); |
| | | params.value = monthRange; |
| | | console.log(monthRange); |
| | | getCalen(params.value).then(res => { |
| | | if (res.data.code !== 0) return; |
| | | // events.value = res.data.data |
| | | console.log('日历', res.data.data); |
| | | events.value = res.data.data; |
| | | }); |
| | | }; |
| | | const jumpcalendar = (event, day) => { |
| | | if (event.name === '工单') { |
| | | router.push({ |
| | | path: '/tickets/ticket', |
| | | query: { |
| | | day: day, |
| | | }, |
| | | }); |
| | | }else{ |
| | | ElMessage.warning('加急开发中...') |
| | | } |
| | | }; |
| | | onMounted(() => { |
| | | getJobEventBar(); |
| | | }); |
| | | </script> |
| | | <style lang="scss"> |
| | | .calenBox { |
| | | |
| | | .el-calendar-table td.is-selected { |
| | | background-color: #f0f7ff; |
| | | border: 2px solid #409eff; |
| | | border-radius: 4px; |
| | | } |
| | | .el-calendar-table td.is-selected .date-number { |
| | | font-weight: bold; |
| | | color: #409eff; |
| | | } |
| | | |
| | | .el-calendar-table td.is-selected .events { |
| | | // padding: 2px; |
| | | } |
| | | } |
| | | </style> |
| | | <style lang="scss" scoped> |
| | | .calenBox { |
| | | margin-top: 10px; |
| | |
| | | overflow: hidden; |
| | | .event-item { |
| | | font-size: 12px; |
| | | padding: 2px; |
| | | margin: 2px 0; |
| | | // padding: 2px; |
| | | |
| | | border-radius: 3px; |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | // overflow: hidden; |
| | | // text-overflow: ellipsis; |
| | | |
| | | &.work-order { |
| | | // background: #ecf5ff; |
| | | color: #409eff; |
| | | font-weight: 400; |
| | | font-size: 12px; |
| | | color: #7b7b7b; |
| | | span { |
| | | display: inline-block; |
| | | width: 7px; |
| | | height: 7px; |
| | | background: #1c5cff; |
| | | border-radius: 50%; |
| | | margin-right: 2px; |
| | | font-weight: 600; |
| | | font-size: 14px; |
| | | color: #1c5cff; |
| | | margin-left: 2px; |
| | | } |
| | | } |
| | | |
| | | &.task { |
| | | // background: #f0f9eb; |
| | | color: #67c23a; |
| | | font-weight: 400; |
| | | font-size: 12px; |
| | | color: #7b7b7b; |
| | | span { |
| | | display: inline-block; |
| | | width: 7px; |
| | | height: 7px; |
| | | background: #029d36; |
| | | border-radius: 50%; |
| | | margin-right: 2px; |
| | | font-weight: 600; |
| | | font-size: 14px; |
| | | color: #029d36; |
| | | margin-left: 2px; |
| | | } |
| | | } |
| | | } |
| | |
| | | <div class="card-title"> |
| | | <img :src="jc1" alt="" /> |
| | | <div class="cardtotal"> |
| | | <p>机巢事件数量排名</p> |
| | | <!-- <div class="total-number">111</div> |
| | | <span>个</span> --> |
| | | <p>机巢工单数量排名</p> |
| | | </div> |
| | | </div> |
| | | <!-- <div class="status-grid"> |
| | | <div v-for="(item, index) in jcOrder" :key="index" class="status-item"> |
| | | <img :src="jc2" alt="" /> |
| | | <div> |
| | | <div class="status-label">{{ item.name }}</div> |
| | | <div :style="{ color: '#387FC8' }" class="status-value"> |
| | | {{ item.value }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> --> |
| | | </div> |
| | | <div class="nestCenter"> |
| | | <div class="chart" ref="echartsRef"></div> |
| | | <div class="chart" ref="echartsRef" ></div> |
| | | |
| | | </div> |
| | | </div> |
| | | </template> |
| | |
| | | const echartsRef = ref(null); |
| | | let { chart: jcchart } = useEchartsResize(echartsRef); |
| | | const jcOrder = ref([]); |
| | | const props = defineProps({ |
| | | dateSelect: { |
| | | type: String, |
| | | }, |
| | | }); |
| | | const params = reactive({ |
| | | date_enum: props.dateSelect, |
| | | }); |
| | | // 获取机巢事件数据 |
| | | const getIndustryJobNumPieChart = value => { |
| | | industryJobNumPieChart(value).then(res => { |
| | | console.log('ppp', res); |
| | | |
| | | const getIndustryJobNumPieChart = () => { |
| | | industryJobNumPieChart(params).then(res => { |
| | | const resList = res?.data?.data || []; |
| | | jcOrder.value = resList; |
| | | pieInit(resList); |
| | | }); |
| | | }; |
| | | watch( |
| | | () => props.dateSelect, |
| | | newVal => { |
| | | params.date_enum = newVal; |
| | | getIndustryJobNumPieChart(); |
| | | }, |
| | | { immediate: true } |
| | | ); |
| | | const pieInit = resList => { |
| | | // 处理数据,过滤掉没有name的项 |
| | | const validData = resList.filter(item => item.name); |
| | | const validData = resList.filter(item => item.name).sort((a, b) => b.value - a.value); // 从大到小排序 |
| | | const colors = [ |
| | | '#F87E04', // 橙色 |
| | | '#FFC400', // 黄色 |
| | | '#08BC44', // 绿色 |
| | | '#07B5FF', // 蓝色 |
| | | '#A98DFF', // 紫色 |
| | | '#9ABFFF', // 浅蓝 |
| | | ]; |
| | | |
| | | // 准备图表数据 |
| | | const optionData = { |
| | | yAxisData: validData.map(item => item.name), |
| | | seriesData: validData.map(item => item.value), |
| | | }; |
| | | |
| | | const option = { |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | axisPointer: { |
| | | type: 'shadow', |
| | | }, |
| | | axisPointer: { type: 'shadow' }, |
| | | formatter: '{b}: {c}', |
| | | }, |
| | | grid: { |
| | |
| | | }, |
| | | xAxis: { |
| | | type: 'value', |
| | | splitLine: { |
| | | lineStyle: { |
| | | color: '#E5E5E5', |
| | | }, |
| | | }, |
| | | axisLabel: { |
| | | color: '#35455aa6', |
| | | }, |
| | | splitLine: { lineStyle: { color: '#E5E5E5' } }, |
| | | axisLabel: { color: '#7C8091' }, |
| | | boundaryGap: [0, 0.01], |
| | | }, |
| | | yAxis: { |
| | | type: 'category', |
| | | data: optionData.yAxisData, // 使用处理后的分类数据 |
| | | axisLabel: { |
| | | color: '#35455aa6', |
| | | }, |
| | | axisLine: { |
| | | lineStyle: { |
| | | color: '#D1D1D1', |
| | | }, |
| | | }, |
| | | axisTick: { |
| | | show: false, |
| | | }, |
| | | data: optionData.yAxisData, |
| | | axisLabel: { color: '#7C8091' }, |
| | | axisLine: { lineStyle: { color: '#D1D1D1' } }, |
| | | axisTick: { show: false }, |
| | | // 4. 确保排序后的数据从上到下显示(最大值在顶部) |
| | | inverse: true, |
| | | }, |
| | | series: [ |
| | | { |
| | | type: 'bar', |
| | | data: optionData.seriesData, // 使用处理后的数值数据 |
| | | data: optionData.seriesData, |
| | | itemStyle: { |
| | | color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [ |
| | | { offset: 0, color: '#93BAFF' }, |
| | | { offset: 1, color: '#C5DEFF' }, |
| | | ]), |
| | | color: params => { |
| | | // 前6项使用固定颜色循环,之后使用渐变 |
| | | return params.dataIndex < colors.length |
| | | ? colors[params.dataIndex] |
| | | : new echarts.graphic.LinearGradient(0, 0, 1, 0, [ |
| | | { offset: 0, color: '#93BAFF' }, |
| | | { offset: 1, color: '#C5DEFF' }, |
| | | ]); |
| | | }, |
| | | }, |
| | | barWidth: '30%', |
| | | label: { |
| | |
| | | ], |
| | | }; |
| | | |
| | | jcchart.value.setOption(option); |
| | | // 5. 设置图表选项 |
| | | jcchart.value.setOption(option, true); |
| | | }; |
| | | onMounted(() => { |
| | | getIndustryJobNumPieChart({ date_enum: 'CURRENT_WEEK' }); |
| | | getIndustryJobNumPieChart(); |
| | | |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .machineNest { |
| | | width: 100%; |
| | | .custom-text { |
| | | font-size: 14px; |
| | | color: #7C8091; |
| | | } |
| | | .nestTop { |
| | | .card-title { |
| | | display: flex; |
| | |
| | | color: #7c8091; |
| | | } |
| | | .total-number { |
| | | font-family: 'YouSheBiaoTiHei'; |
| | | font-family: 'Source Han Sans CN'; |
| | | font-weight: bold; |
| | | font-size: 32px; |
| | | color: #2a54ff; |
| | |
| | | color: #383838; |
| | | } |
| | | .status-value { |
| | | font-family: 'YouSheBiaoTiHei'; |
| | | font-family: 'Source Han Sans CN'; |
| | | font-weight: bold; |
| | | font-size: 20px; |
| | | } |
| | |
| | | <div class="title"> |
| | | <div class="name"> |
| | | <span> 设备统计</span> |
| | | <img src="/src/assets/images/workbench/st1.png" alt="" /> |
| | | <img @click="refresh" src="/src/assets/images/workbench/st1.png" alt="" /> |
| | | </div> |
| | | <div class="arrow"> |
| | | <div class="arrow" @click="jumppage"> |
| | | <img src="/src/assets/images/workbench/st2.png" alt="" /> |
| | | </div> |
| | | </div> |
| | | <!-- <div class="grid-container"> |
| | | |
| | | <div class="grid-container"> |
| | | <div v-for="(item, index) in Object.keys(newtitleData)" :key="index" class="device-card"> |
| | | <div class="device-title"> |
| | | <img :src="test[item].img" :alt="newtitleData[item].name" /> |
| | | <div class="itemcenter"> |
| | | <div>{{ test[item]?.name || '--' }}</div> |
| | | <span class="shu">{{ newtitleData[item].total_num }}</span> |
| | | <span>个</span> |
| | | <span>{{unitMap[test[item]?.name]}}</span> |
| | | </div> |
| | | </div> |
| | | <div class="status-list"> |
| | | |
| | | <div |
| | | v-for="(status, statusIndex) in newtitleData[item].status_map" |
| | | :key="statusIndex" |
| | | class="status-item" |
| | | :class="getStatusStyle(test[item]?.name, statusIndex)" |
| | | :style="{ color: getStatusColor(test[item]?.name, statusIndex) }" |
| | | > |
| | | <span class="indicator"></span> |
| | | <span class="label">{{ getStatusLabel(test[item]?.name, statusIndex) }}</span> |
| | | <span class="count" |
| | | >{{ status }} {{ test[item]?.name === '无人机' ? '架' : '个' }}</span |
| | | <template v-if="test[item]?.name == '机巢' || test[item]?.name == '无人机'"> |
| | | <div |
| | | v-for="statusKey in [4, 0, -1]" |
| | | :key="statusKey" |
| | | class="status-item" |
| | | :class="getStatusStyle(test[item]?.name, statusKey)" |
| | | :style="{ color: getStatusColor(test[item]?.name, statusKey) }" |
| | | > |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> --> |
| | | <div class="grid-container1"> |
| | | <div v-for="(item, index) in Object.keys(newtitleData)" :key="index" class="device-card"> |
| | | <div class="device-title"> |
| | | <img :src="test[item].img" :alt="newtitleData[item].name" /> |
| | | <div class="itemcenter"> |
| | | <div>{{ test[item]?.name || '--' }}</div> |
| | | <span class="shu">{{ newtitleData[item].total_num }}</span> |
| | | <span>个</span> |
| | | </div> |
| | | </div> |
| | | <div class="status-list"> |
| | | <!-- :class="`status-${statusIndex}`" --> |
| | | <div |
| | | v-for="(status, statusIndex) in newtitleData[item].status_map" |
| | | :key="statusIndex" |
| | | class="status-item" |
| | | :class="getStatusStyle(test[item]?.name, statusIndex)" |
| | | :style="{ color: getStatusColor(test[item]?.name, statusIndex) }" |
| | | > |
| | | <span |
| | | class="indicator" |
| | | :style="{ |
| | | backgroundColor: getStatusBackground(test[item]?.name, statusIndex), |
| | | color: getStatusColor(test[item]?.name, statusIndex), |
| | | }" |
| | | ></span> |
| | | <span class="label">{{ getStatusLabel(test[item]?.name, statusIndex) }}</span> |
| | | <span class="count" |
| | | >{{ status }} {{ test[item]?.name === '无人机' ? '架' : '个' }}</span |
| | | <span |
| | | class="indicator" |
| | | :style="{ |
| | | backgroundColor: getStatusBackground(test[item]?.name, statusKey), |
| | | color: getStatusColor(test[item]?.name, statusKey), |
| | | }" |
| | | ></span> |
| | | <span class="label">{{ getStatusLabel(test[item]?.name, statusKey) }}</span> |
| | | <span class="count"> |
| | | {{ newtitleData[item].status_map[statusKey] }} |
| | | {{ unitMap[test[item]?.name]}} |
| | | </span> |
| | | </div> |
| | | </template> |
| | | <template v-else-if="test[item]?.name == '监控设备'"> |
| | | <div |
| | | v-for="statusKey in [1, 0]" |
| | | :key="statusKey" |
| | | class="status-item" |
| | | :class="getStatusStyle(test[item]?.name, statusKey)" |
| | | :style="{ color: getStatusColor(test[item]?.name, statusKey) }" |
| | | > |
| | | </div> |
| | | <span |
| | | class="indicator" |
| | | :style="{ |
| | | backgroundColor: getStatusBackground(test[item]?.name, statusKey), |
| | | color: getStatusColor(test[item]?.name, statusKey), |
| | | }" |
| | | ></span> |
| | | <span class="label">{{ getStatusLabel(test[item]?.name, statusKey) }}</span> |
| | | <span class="count"> |
| | | {{ newtitleData[item].status_map[statusKey] }} |
| | | {{ unitMap[test[item]?.name]}} |
| | | </span> |
| | | </div> |
| | | </template> |
| | | <template v-else-if="test[item]?.name == '机巢保险'"> |
| | | <div |
| | | v-for="statusKey in [1, 0]" |
| | | :key="statusKey" |
| | | class="status-item" |
| | | :class="getStatusStyle(test[item]?.name, statusKey)" |
| | | :style="{ color: getStatusColor(test[item]?.name, statusKey) }" |
| | | > |
| | | <span |
| | | class="indicator" |
| | | :style="{ |
| | | backgroundColor: getStatusBackground(test[item]?.name, statusKey), |
| | | color: getStatusColor(test[item]?.name, statusKey), |
| | | }" |
| | | ></span> |
| | | <span class="label">{{ getStatusLabel(test[item]?.name, statusKey) }}</span> |
| | | <span class="count"> |
| | | {{ newtitleData[item].status_map[statusKey] }} |
| | | {{ test[item]?.name === '无人机' ? '架' : '个' }} |
| | | </span> |
| | | </div> |
| | | </template> |
| | | <template v-else> |
| | | <div |
| | | v-for="(status, statusIndex) in newtitleData[item].status_map" |
| | | :key="statusIndex" |
| | | class="status-item" |
| | | :class="getStatusStyle(test[item]?.name, statusIndex)" |
| | | :style="{ color: getStatusColor(test[item]?.name, statusIndex) }" |
| | | > |
| | | <span |
| | | class="indicator" |
| | | :style="{ |
| | | backgroundColor: getStatusBackground(test[item]?.name, statusIndex), |
| | | color: getStatusColor(test[item]?.name, statusIndex), |
| | | }" |
| | | ></span> |
| | | <span class="label">{{ getStatusLabel(test[item]?.name, statusIndex) }}</span> |
| | | <span class="count" |
| | | >{{ status }} {{ unitMap[test[item]?.name]}}</span |
| | | > |
| | | </div> |
| | | </template> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | <script setup> |
| | | import { useStore } from 'vuex'; |
| | | import { computed } from 'vue'; |
| | | import titleImg1 from '@/assets/images/workbench/st3.png'; |
| | | import titleImg2 from '@/assets/images/workbench/st4.png'; |
| | | import titleImg3 from '@/assets/images/workbench/st5.png'; |
| | | import titleImg4 from '@/assets/images/workbench/st6.png'; |
| | | import titleImg5 from '@/assets/images/workbench/st8.png'; |
| | | import titleImg6 from '@/assets/images/workbench/st9.png'; |
| | | import titleImg1 from '@/assets/images/workbench/st3.svg'; |
| | | import titleImg2 from '@/assets/images/workbench/st4.svg'; |
| | | import titleImg3 from '@/assets/images/workbench/st8.svg'; |
| | | import titleImg4 from '@/assets/images/workbench/st5.svg'; |
| | | import titleImg5 from '@/assets/images/workbench/st6.svg'; |
| | | import titleImg6 from '@/assets/images/workbench/st9.svg'; |
| | | import { getStatics } from '@/api/home/index'; |
| | | import { useRouter } from 'vue-router'; |
| | | const router = useRouter(); |
| | | const store = useStore(); |
| | | Object.key; |
| | | const refresh = () => { |
| | | getStaticsList(); |
| | | }; |
| | | const jumppage = () => { |
| | | router.push({ |
| | | path: '/device/index', |
| | | }); |
| | | }; |
| | | const userInfo = computed(() => store.getters.userInfo); |
| | | const permission = computed(() => store.getters.permission); |
| | | |
| | | const newtitleData = ref({}); |
| | | |
| | | const test = { |
| | | no_move_list: { |
| | | name: '机巢', |
| | |
| | | img: titleImg2, |
| | | }, |
| | | flow_type_list: { |
| | | name: '机巢流量', |
| | | name: '无人机流量', |
| | | img: titleImg3, |
| | | }, |
| | | monitor_list: { |
| | |
| | | }, |
| | | }; |
| | | const statusSelect = { |
| | | 0: '空闲中', |
| | | 4: '作业中', |
| | | 0: '空闲中', |
| | | '-1': '离线中', |
| | | }; |
| | | // 流量 状态 0充足,1=流量到期,2=不足 |
| | | const flowStatus = { |
| | | 0: '流量无忧', |
| | | 1: '流量到期', |
| | | 2: '流量不足', |
| | | 0: '无忧', |
| | | 1: '到期', |
| | | 2: '不足', |
| | | }; |
| | | // "监控状态 1=在线,0=离线" |
| | | const monitorStatus = { |
| | | 0: '离线中', |
| | | 1: '在线中', |
| | | }; |
| | | // 机巢保险 1=保险,0=未保险 |
| | | |
| | | const insureStatus = { |
| | | 0: '临近到期', |
| | | 1: '正常期限', |
| | | }; |
| | | const moveListStatus = { |
| | | '-1': '离线中', |
| | | 4: '在线中', |
| | | }; |
| | | // 样式配置对象 |
| | | const statusStyles = { |
| | |
| | | 1: { class: 'normal', color: '#1B94FF', background: '#1B94FF' }, |
| | | }, |
| | | |
| | | 机巢流量: { |
| | | 无人机流量: { |
| | | 0: { class: 'offline', color: '#11CE3E', background: '#11CE3E' }, |
| | | 1: { class: 'flying', color: '#1B94FF', background: '#1B94FF' }, |
| | | 2: { class: 'flying', color: '#7C8091', background: '#7C8091' }, |
| | |
| | | 0: { class: 'offline', color: '#bababa', background: '#bababa' }, |
| | | 1: { class: 'flying', color: '#1B94FF', background: '#1B94FF' }, |
| | | }, |
| | | 移动机巢: { |
| | | '-1': { class: 'offline', color: '#bababa', background: '#bababa' }, |
| | | 4: { class: 'flying', color: '#1B94FF', background: '#1B94FF' }, |
| | | }, |
| | | // 默认样式配置 |
| | | default: { |
| | | 0: { class: 'warning', color: '#1b94ff', background: '#1b94ff' }, |
| | |
| | | '-1': { class: 'success', color: '#bababa', background: '#bababa' }, |
| | | }, |
| | | }; |
| | | |
| | | const getStatusStyle = (name, statusIndex) => { |
| | | // 获取样式配置,优先使用名称专属配置 |
| | | const styleConfig = statusStyles[name] || statusStyles.default; |
| | | return styleConfig[statusIndex]?.class || ''; |
| | | }; |
| | | |
| | | const getStatusColor = (name, statusIndex) => { |
| | | // 获取颜色配置,优先使用名称专属配置 |
| | | const styleConfig = statusStyles[name] || statusStyles.default; |
| | | return styleConfig[statusIndex]?.color || '#333'; |
| | | }; |
| | | // 新增背景颜色获取方法 |
| | | //背景颜色获取方法 |
| | | const getStatusBackground = (name, statusIndex) => { |
| | | const styleConfig = statusStyles[name] || statusStyles.default; |
| | | return ( |
| | | styleConfig[statusIndex]?.background || |
| | | styleConfig[statusIndex]?.color || // 降级使用字体颜色 |
| | | '#F0F0F0' |
| | | ); // 最终默认颜色 |
| | | return styleConfig[statusIndex]?.background || styleConfig[statusIndex]?.color || '#F0F0F0'; |
| | | }; |
| | | const getStatusLabel = (itemName, statusCode) => { |
| | | switch (itemName) { |
| | | case '机巢流量': |
| | | case '无人机流量': |
| | | return flowStatus[statusCode] || statusSelect[statusCode]; |
| | | case '监控设备': |
| | | return monitorStatus[statusCode] || statusSelect[statusCode]; |
| | | case '机巢保险': |
| | | return insureStatus[statusCode] || statusSelect[statusCode]; |
| | | case '移动机巢': |
| | | return moveListStatus[statusCode] || statusSelect[statusCode]; |
| | | default: |
| | | return statusSelect[statusCode] || `未知状态(${statusCode})`; |
| | | } |
| | | }; |
| | | |
| | | const getStaticsList = () => { |
| | | getStatics(userInfo.value.detail.areaCode).then(res => { |
| | | newtitleData.value = res.data.data; |
| | | console.log('设备', newtitleData.value); |
| | | console.log('permission.value', permission.value); |
| | | // console.log('设备', res.data.data); |
| | | if (permission.value?.device_statistics_six) { |
| | | const { move_list, monitor_list, ...filteredData } = res.data.data; |
| | | newtitleData.value = filteredData; |
| | | return; |
| | | } |
| | | |
| | | for (let key in res.data.data) { |
| | | if (permission.value?.device_statistics_four) { |
| | | const { flow_type_list, insure_list, ...filteredData } = res.data.data; |
| | | newtitleData.value = filteredData; |
| | | return; |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | const unitMap = { |
| | | drone: '架', |
| | | nest: '个', |
| | | monitor: '个', |
| | | mobile: '个', |
| | | '无人机流量': '架', |
| | | '无人机': '架', |
| | | '机巢': '个', |
| | | '机巢保险': '个', |
| | | '监控设备': '个', |
| | | '移动机巢': '个', |
| | | }; |
| | | const titleData = ref([ |
| | | { |
| | | img: titleImg1, |
| | | name: '机巢', |
| | | type: 'nest', |
| | | data: 52, |
| | | statuses: [ |
| | | { type: 'working', label: '作业中', count: 20 }, |
| | | { type: 'idle', label: '空间中', count: 20 }, |
| | | { type: 'offline', label: '离线中', count: 20 }, |
| | | ], |
| | | }, |
| | | { |
| | | img: titleImg2, |
| | | name: '无人机', |
| | | data: 52, |
| | | type: 'drone', |
| | | statuses: [ |
| | | { type: 'working', label: '作业中', count: 20 }, |
| | | { type: 'idle', label: '空间中', count: 20 }, |
| | | { type: 'offline', label: '离线中', count: 20 }, |
| | | ], |
| | | }, |
| | | { |
| | | img: titleImg3, |
| | | name: '监控设备', |
| | | type: 'monitor', |
| | | data: 52, |
| | | statuses: [ |
| | | { type: 'working', label: '作业中', count: 20 }, |
| | | { type: 'idle', label: '空间中', count: 20 }, |
| | | { type: 'offline', label: '离线中', count: 20 }, |
| | | ], |
| | | }, |
| | | { |
| | | img: titleImg4, |
| | | name: '移动机巢', |
| | | type: 'mobile', |
| | | data: 52, |
| | | statuses: [ |
| | | { type: 'working', label: '作业中', count: 20 }, |
| | | { type: 'idle', label: '空间中', count: 20 }, |
| | | { type: 'offline', label: '离线中', count: 20 }, |
| | | ], |
| | | }, |
| | | ]); |
| | | watch( |
| | | () => [ |
| | | userInfo.value.detail?.areaCode, |
| | | permission.value.device_statistics_six, |
| | | permission.value?.device_statistics_four, |
| | | ], |
| | | () => getStaticsList(), |
| | | { immediate: true } |
| | | ); |
| | | onMounted(() => { |
| | | getStaticsList(); |
| | | }); |
| | |
| | | |
| | | <style scoped lang="scss"> |
| | | .statistics { |
| | | // height: 174px; |
| | | min-height: 174px; |
| | | background: #ffffff; |
| | | border-radius: 8px 8px 8px 8px; |
| | | margin-bottom: 10px; |
| | | font-size: clamp(12px, 2vw, 24px); |
| | | .title { |
| | | padding: 14px 14px 0 21px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | |
| | | .name { |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | span { |
| | | margin-right: 4px; |
| | | font-weight: bold; |
| | | font-size: 16px; |
| | | color: #363636; |
| | | font-family: 'Source Han Sans CN'; |
| | | } |
| | | |
| | | img { |
| | | cursor: pointer; |
| | | } |
| | | } |
| | | |
| | | .arrow { |
| | | cursor: pointer; |
| | | } |
| | | } |
| | | |
| | | .grid-container { |
| | | padding: 0 14px 0 21px; |
| | | display: grid; |
| | | grid-template-columns: repeat(6, 1fr); |
| | | // display: grid; |
| | | // grid-template-columns: repeat(4, 1fr); |
| | | display: flex; |
| | | justify-content: space-around; |
| | | .device-card { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | margin-top: 30px; |
| | | |
| | | .device-title { |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | img { |
| | | width: 43px; |
| | | height: 44px; |
| | | width: 64px; |
| | | height: 64px; |
| | | } |
| | | } |
| | | |
| | | .itemcenter { |
| | | margin-left: 14px; |
| | | margin-left: 5px; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #343434; |
| | | div{ |
| | | margin-top: 5px; |
| | | } |
| | | .shu { |
| | | font-weight: bold; |
| | | font-size: 36px; |
| | | color: #363636; |
| | | display: inline-block; |
| | | transform: skewX(-5deg); |
| | | font-family: 'Source Han Sans CN'; |
| | | // font-size: calc(12px + 0.5vw); |
| | | margin-right: 2px; |
| | | } |
| | | |
| | | span { |
| | | font-weight: 400; |
| | | font-size: 12px; |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | .status-list { |
| | | display: grid; |
| | | |
| | | margin-left: 5px; |
| | | .status-item { |
| | | display: flex; |
| | | align-items: center; |
| | |
| | | // font-size: clamp(14px, 1.1vw, 16px); |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | } |
| | | |
| | | &.status-4 .indicator { |
| | | background: #11ce3e; |
| | | } |
| | | &.status-4 { |
| | | color: #11ce3e; |
| | | } |
| | | &.status-0 .indicator { |
| | | background: #1b94ff; |
| | | } |
| | | &.status-0 { |
| | | color: #1b94ff; |
| | | } |
| | | |
| | | &.status--1 .indicator { |
| | | background: #bababa; |
| | | } |
| | | &.status--1 { |
| | | color: #bababa; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .grid-container1 { |
| | | padding: 0 14px 0 21px; |
| | | // padding: 0 14px 0 21px; |
| | | display: grid; |
| | | grid-template-columns: repeat(6, 1fr); |
| | | |
| | | .device-card { |
| | | display: flex; |
| | | flex-direction: column; |
| | |
| | | .device-title { |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | img { |
| | | width: 43px; |
| | | height: 44px; |
| | | width: 64px; |
| | | height: 64px; |
| | | } |
| | | } |
| | | |
| | | .itemcenter { |
| | | margin-left: 14px; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #343434; |
| | | |
| | | .shu { |
| | | font-weight: bold; |
| | | font-size: 36px; |
| | | color: #363636; |
| | | display: inline-block; |
| | | transform: skewX(-5deg); |
| | | font-family: 'Source Han Sans CN'; |
| | | margin-right: 2px; |
| | | } |
| | | |
| | | span { |
| | | font-weight: 400; |
| | | font-size: 12px; |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | .status-list { |
| | | display: grid; |
| | | |
| | |
| | | font-size: 12px; |
| | | gap: 10px; |
| | | margin-bottom: 5px; |
| | | |
| | | .indicator { |
| | | width: 6px; |
| | | height: 6px; |
| | | border-radius: 50%; |
| | | } |
| | | |
| | | .label { |
| | | flex: 1; |
| | | // font-size: clamp(12px, 1vw, 14px); |
| | | font-size: clamp(12px, 1vw, 14px); |
| | | } |
| | | |
| | | .count { |
| | | // font-size: clamp(14px, 1.1vw, 16px); |
| | | font-size: clamp(12px, 1.1vw, 16px); |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | } |
| | | |
| | | &.status-4 .indicator { |
| | | background: #11ce3e; |
| | | } |
| | | &.status-4 { |
| | | color: #11ce3e; |
| | | } |
| | | &.status-0 .indicator { |
| | | background: #1b94ff; |
| | | } |
| | | &.status-0 { |
| | | color: #1b94ff; |
| | | } |
| | | |
| | | &.status--1 .indicator { |
| | | background: #bababa; |
| | | } |
| | | &.status--1 { |
| | | color: #bababa; |
| | | } |
| | | } |
| | | } |
| | |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="arrow"> |
| | | <div class="arrow" @click="jumpshebei"> |
| | | <img src="/src/assets/images/workbench/st2.png" alt="" /> |
| | | </div> |
| | | </div> |
| | |
| | | <div class="status-item" v-for="(item, index) in eventTypeList" :key="index"> |
| | | <div class="statusCon"> |
| | | <div class="status-label">{{ item.name }}</div> |
| | | <div :style="{ color: item.color }" class="status-value"> |
| | | <!-- <div :style="{ color: item.color }" class="status-value"> |
| | | {{ item.value }}<span>个</span> |
| | | </div> |
| | | </div> --> |
| | | <div class="status-value">{{ item.value }}<span>个</span></div> |
| | | <div class="ratio"> |
| | | 占比 |
| | | <span :style="{ color: item.color }" |
| | | >{{ (item.rate / 100) * 100 }}%</span |
| | | >{{ ((item.rate * 100) / 100).toFixed(2) }}%</span |
| | | > |
| | | </div> |
| | | </div> |
| | |
| | | </div> |
| | | <div class="flycenter"> |
| | | <div class="centerBox"> |
| | | <div class="centerItem" v-for="(item, index) in 3" :key="index"> |
| | | <div><img src="@/assets/images/workbench/fy2.png" alt="" />飞行时长</div> |
| | | <div class="flydata"><span>5421.56</span>时</div> |
| | | <div class="centerItem" v-for="(itemfly, index) in flyTypeList" :key="index"> |
| | | <div class="flyimg"><img :src="itemfly.img" alt="" />{{ itemfly.name }}</div> |
| | | <div class="flydata"> |
| | | <span>{{ itemfly.value }}</span |
| | | >{{ unitMap[itemfly.name] }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="lineChart"> |
| | |
| | | </div> |
| | | </div> |
| | | <div class="centerRight"> |
| | | <flyratio></flyratio> |
| | | <flyratio :dateSelect="dateSelect"></flyratio> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | import * as echarts from 'echarts'; |
| | | import useEchartsResize from '@/hooks/useEchartsResize'; |
| | | import { mapGetters } from 'vuex'; |
| | | import { ref } from 'vue'; |
| | | import { getJobEventByStatus, getJobEventTotal, getFly, getFlyTime } from '@/api/home/index'; |
| | | import overviewImg1 from '@/assets/images/workbench/tc1.png'; |
| | | import overviewImg2 from '@/assets/images/workbench/tc2.png'; |
| | | import overviewImg3 from '@/assets/images/workbench/tc3.png'; |
| | | import overviewImg4 from '@/assets/images/workbench/tc4.png'; |
| | | import overviewImg5 from '@/assets/images/workbench/tc5.png'; |
| | | import overviewImg6 from '@/assets/images/workbench/tc6.png'; |
| | | import flyImg1 from '@/assets/images/workbench/fy2.png'; |
| | | import overviewImg2 from '@/assets/images/workbench/tc2.svg'; |
| | | import overviewImg3 from '@/assets/images/workbench/tc3.svg'; |
| | | import overviewImg4 from '@/assets/images/workbench/tc4.svg'; |
| | | import overviewImg5 from '@/assets/images/workbench/tc5.svg'; |
| | | |
| | | import flyImg1 from '@/assets/images/workbench/fy2.svg'; |
| | | import flyImg2 from '@/assets/images/workbench/fy3.svg'; |
| | | import flyImg3 from '@/assets/images/workbench/fy4.svg'; |
| | | import statistics from './components/statistics.vue'; |
| | | import { getJobEventByStatus, getJobEventTotal } from '@/api/home/index'; |
| | | // const value = ref(new Date()); |
| | | let checked = ref('CURRENT_WEEK'); |
| | | import { ElMessage } from 'element-plus'; |
| | | let checked = ref('CURRENT_YEAR'); |
| | | let timeListStr = ['本周', '本月', '本年']; |
| | | let timeListEnum = ['CURRENT_WEEK', 'CURRENT_MONTH', 'CURRENT_YEAR']; |
| | | let timeClick = (item, index) => { |
| | | checked.value = item; |
| | | params.value.date_enum = item; |
| | | console.log('日期选择', params.value.date_enum); |
| | | getTypeData(); |
| | | }; |
| | | const eventTypeList = ref([ |
| | | { name: '待审核', value: 0, img: overviewImg2, color: '#FF6560', status: '2', rate: 0 }, |
| | | { name: '待处理', value: 0, img: overviewImg3, color: '#5D77FB', status: '0', rate: 0 }, |
| | | { name: '处理中', value: 0, img: overviewImg4, color: '#FF8B26', status: '3', rate: 0 }, |
| | | { name: '已完成', value: 0, img: overviewImg5, color: '#0291A1', status: '4', rate: 0 }, |
| | | ]); |
| | | const flyTypeList = ref([ |
| | | { name: '飞行时长', value: 0, img: overviewImg2 }, |
| | | { name: '飞行里程', value: 0, img: overviewImg3 }, |
| | | { name: '任务成功', value: 0, img: overviewImg4 }, |
| | | ]); |
| | | const params = ref({ |
| | | date_enum: 'CURRENT_WEEK', |
| | | date_enum: 'CURRENT_YEAR', |
| | | device_sn: '', |
| | | end_date: undefined, |
| | | start_date: undefined, |
| | | }); |
| | | const dateSelect = ref('CURRENT_YEAR'); |
| | | let timeClick = (item, index) => { |
| | | checked.value = item; |
| | | params.value.date_enum = item; |
| | | dateSelect.value = item; |
| | | getTypeData(); |
| | | getFlyList(); |
| | | getFlyTimeList(); |
| | | }; |
| | | // 跳转 |
| | | const jumpshebei = () => { |
| | | ElMessage.warning('加急开发中...'); |
| | | }; |
| | | |
| | | const eventTypeList = ref([ |
| | | { name: '待审核', value: 0, img: overviewImg2, color: '#FF472F', status: '2', rate: 0 }, |
| | | { name: '待处理', value: 0, img: overviewImg3, color: '#FF7411', status: '0', rate: 0 }, |
| | | { name: '处理中', value: 0, img: overviewImg4, color: '#FFC300', status: '3', rate: 0 }, |
| | | { name: '已完成', value: 0, img: overviewImg5, color: '#0291A1', status: '4', rate: 0 }, |
| | | ]); |
| | | const keyMapping = { |
| | | 飞行时长: 'total_flight_time', |
| | | 飞行里程: 'total_flight_distance', |
| | | 任务成果: 'event_num', |
| | | }; |
| | | const unitMap = { |
| | | 飞行时长: '时', |
| | | 飞行里程: '千米', |
| | | 任务成果: '个', |
| | | }; |
| | | const flyTypeList = ref([ |
| | | { name: '飞行时长', value: 0, img: flyImg1 }, |
| | | { name: '飞行里程', value: 0, img: flyImg2 }, |
| | | { name: '任务成果', value: 0, img: flyImg3 }, |
| | | ]); |
| | | |
| | | const eventTotal = ref(0); |
| | | const data = ref([]); |
| | | // 工单统计 |
| | | const getTypeData = () => { |
| | | getJobEventByStatus(params.value).then(res => { |
| | | const resList = res?.data?.data || []; |
| | | console.log('工单统计', res.data.data); |
| | | |
| | | resList.forEach(item => { |
| | | eventTypeList.value.forEach(item1 => { |
| | | if (item1.name === item.name) { |
| | |
| | | initChart(resList); |
| | | }); |
| | | }; |
| | | // 飞行统计 |
| | | |
| | | const getFlyList = () => { |
| | | getFly(params.value).then(res => { |
| | | flyTypeList.value = flyTypeList.value.map(item => ({ |
| | | ...item, |
| | | value: res.data.data[keyMapping[item.name]] || 0, |
| | | })); |
| | | }); |
| | | }; |
| | | const getFlyTimeList = () => { |
| | | getFlyTime(params.value).then(res => { |
| | | const resList = res?.data?.data || []; |
| | | lineCharts(resList); |
| | | }); |
| | | }; |
| | | // 图表 |
| | | const echartsRef = ref(null); |
| | | let { chart } = useEchartsResize(echartsRef); |
| | | const chartRef = ref(null); |
| | | let { chart: lineChart } = useEchartsResize(chartRef); |
| | | const initChart = val => { |
| | | // 转换数据格式并计算总数 |
| | | const totalNum = val.reduce((sum, item) => sum + item.num, 0); |
| | | const data = { |
| | | total: { |
| | | title: '总计', |
| | | |
| | | figure: totalNum.toString(), // 动态计算总数 |
| | | }, |
| | | data: val.map(item => ({ |
| | |
| | | }; |
| | | |
| | | const echartsOption = { |
| | | color: ['#FF6560', '#5D77FB', '#FF8B26', '#0291A1'], |
| | | color: ['#FF472F', '#FF7411', '#FFC300', '#0291A1'], |
| | | tooltip: { |
| | | trigger: 'item', |
| | | padding: 0, |
| | |
| | | textStyle: { |
| | | color: 'rgba(28, 31, 35, 0.80)', |
| | | fontSize: '12px', |
| | | fontWeight: 'normal', |
| | | fontWeight: 'bold', |
| | | }, |
| | | subtext: data.total.figure, |
| | | subtextStyle: { |
| | |
| | | fontWeight: '600', |
| | | }, |
| | | top: '40%', |
| | | left: 'center', |
| | | left: '48%', |
| | | textAlign: 'center', // 文本对齐 |
| | | }, |
| | | series: [ |
| | | { |
| | | name: '', |
| | | type: 'pie', |
| | | radius: ['30%', '45%'], |
| | | radius: ['43%', '63%'], |
| | | avoidLabelOverlap: true, |
| | | // avoidLabelOverlap: false, |
| | | left: '-2%', |
| | | label: { |
| | | formatter: `{a|{b}}: {b|{d}%}`, |
| | | formatter: params => { |
| | | // 使用 b 样式标记包裹百分比数值 |
| | | return `{a|${params.name}}: {b|${params.data.rate}%}`; |
| | | }, |
| | | alignTo: 'labelLine', |
| | | overflow: 'truncate', |
| | | rich: { |
| | | a: { |
| | | color: 'rgba(28, 31, 35, 0.80)', |
| | | fontSize: '12px', |
| | | fontSize: 12, // 建议去掉引号使用数字 |
| | | }, |
| | | b: { |
| | | color: '#1C1F23', |
| | | fontSize: '14px', |
| | | fontWeight: '600', |
| | | fontSize: 14, |
| | | fontWeight: 'bold', // 确保加粗 |
| | | }, |
| | | }, |
| | | }, |
| | | labelLine: { |
| | | show: true, |
| | | length: 5, // 调整引导线长度 |
| | | length2: 15, |
| | | lineStyle: { |
| | | cap: 'round', |
| | | }, |
| | |
| | | }; |
| | | |
| | | // 柱状图 |
| | | const lineCharts = () => { |
| | | const lineCharts = bardata => { |
| | | const categories = bardata?.map(item => item.name); // x轴类别 |
| | | const flight_distance = []; |
| | | const flight_time = []; |
| | | const event_num = []; |
| | | // /遍历数据填充各系列 |
| | | bardata?.forEach(period => { |
| | | let hasDuration = false, |
| | | hasDistance = false, |
| | | hasResult = false; |
| | | |
| | | period.data?.forEach(item => { |
| | | switch (item.name) { |
| | | case '飞行时长': |
| | | flight_time.push(parseFloat(item.value) || 0); |
| | | hasDuration = true; |
| | | break; |
| | | case '飞行里程': |
| | | // 转换为万公 (假设原始单位是米) |
| | | // flight_distance.push((parseFloat(item.value) / 10 || 0)); |
| | | flight_distance.push(parseFloat(item.value) || 0); |
| | | hasDistance = true; |
| | | break; |
| | | case '任务成果': |
| | | event_num.push(Number(item.value) || 0); |
| | | hasResult = true; |
| | | break; |
| | | } |
| | | }); |
| | | |
| | | // 处理可能缺失的数据项 |
| | | if (!hasDuration) flight_time.push(0); |
| | | if (!hasDistance) flight_distance.push(0); |
| | | if (!hasResult) event_num.push(0); |
| | | }); |
| | | var option = { |
| | | tooltip: { |
| | | trigger: 'item', |
| | |
| | | data: ['飞行时长', '飞行里程', '任务成果'], |
| | | left: 'center', |
| | | top: '5%', |
| | | textStyle: { |
| | | color: '#666666', |
| | | }, |
| | | color: '#383838', // 直接配置颜色 |
| | | itemWidth: 15, |
| | | itemHeight: 10, |
| | | itemGap: 25, |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'], |
| | | data: categories, |
| | | axisLine: { |
| | | lineStyle: { |
| | | color: '#cdd5e2', |
| | | }, |
| | | }, |
| | | |
| | | axisLabel: { |
| | | interval: 0, |
| | | textStyle: { |
| | | color: '#666666', |
| | | }, |
| | | color: '#383838', // 直接配置颜色 |
| | | }, |
| | | }, |
| | | yAxis: [ |
| | | // 只保留第一个y轴 |
| | | { |
| | | type: 'log', |
| | | name: '单位:万套', |
| | | nameTextStyle: { |
| | | color: '#666666', |
| | | color: '#383838', |
| | | }, |
| | | min: 1, |
| | | logBase: 3, |
| | |
| | | color: '#cdd5e2', |
| | | }, |
| | | }, |
| | | |
| | | splitLine: { |
| | | show: true, // 显示分割线 |
| | | show: true, |
| | | lineStyle: { |
| | | type: 'dashed', // 设置为虚线 |
| | | color: '#cdd5e2', // 颜色与轴线一致 |
| | | width: 1, // 线宽 |
| | | opacity: 0.5, // 透明度 |
| | | type: 'dashed', |
| | | color: '#cdd5e2', |
| | | width: 1, |
| | | opacity: 0.5, |
| | | }, |
| | | }, |
| | | axisLabel: { |
| | | textStyle: { |
| | | color: '#666666', |
| | | }, |
| | | color: '#666666', // 直接配置颜色 |
| | | }, |
| | | }, |
| | | { |
| | | type: 'log', |
| | | name: '', |
| | | nameTextStyle: { |
| | | color: '#383838', |
| | | }, |
| | | min: 1, |
| | | logBase: 3, |
| | | axisLine: { |
| | | show: false, |
| | | lineStyle: { |
| | | color: '#cdd5e2', |
| | | }, |
| | | }, |
| | | splitLine: { |
| | | show: true, |
| | | lineStyle: { |
| | | type: 'dashed', |
| | | color: '#cdd5e2', |
| | | width: 1, |
| | | opacity: 0.5, |
| | | }, |
| | | }, |
| | | axisLabel: { |
| | | color: '#383838', // 直接配置颜色 |
| | | }, |
| | | }, |
| | | // 移除第二个y轴配置 |
| | | ], |
| | | series: [ |
| | | { |
| | |
| | | type: 'bar', |
| | | barWidth: '12px', |
| | | itemStyle: { |
| | | normal: { |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { |
| | | offset: 0, |
| | | color: '#29acff', |
| | | }, |
| | | { |
| | | offset: 1, |
| | | color: '#4bdfff', |
| | | }, |
| | | ]), |
| | | barBorderRadius: 6, |
| | | }, |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { offset: 0, color: '#29acff' }, |
| | | { offset: 1, color: '#4bdfff' }, |
| | | ]), |
| | | borderRadius: 6, |
| | | }, |
| | | data: [11, 14, 133, 4, 10, 14, 116, 12, 12, 58, 15, 12], |
| | | data: flight_time, |
| | | }, |
| | | { |
| | | name: '飞行里程', |
| | | type: 'bar', |
| | | barWidth: '12px', |
| | | itemStyle: { |
| | | normal: { |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { |
| | | offset: 0, |
| | | color: '#01c871', |
| | | }, |
| | | { |
| | | offset: 1, |
| | | color: '#55f49c', |
| | | }, |
| | | ]), |
| | | barBorderRadius: 6, |
| | | }, |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { offset: 0, color: '#01c871' }, |
| | | { offset: 1, color: '#55f49c' }, |
| | | ]), |
| | | borderRadius: 6, |
| | | }, |
| | | data: [0, 1, 9, 0, 5, 3, 0, 2, 0, 0, 1, 0], |
| | | data: flight_distance, |
| | | }, |
| | | |
| | | { |
| | | name: '任务成果', |
| | | type: 'line', |
| | | yAxisIndex: 0, // 改为使用第一个y轴 |
| | | yAxisIndex: 1, |
| | | smooth: true, |
| | | // symbol: 'circle', |
| | | // symbolSize: 8, |
| | | // itemStyle: { |
| | | // normal: { |
| | | // color: '#ffa43a', |
| | | // borderColor: 'rgba(255, 234, 0, 0.5)', |
| | | // borderWidth: 5, |
| | | // color: '#ffa43a', // 默认状态颜色 |
| | | // borderColor: 'rgba(255, 234, 0, 0.5)', |
| | | // borderWidth: 5, |
| | | // }, |
| | | // emphasis: { |
| | | // // 悬停状态 |
| | | // itemStyle: { |
| | | // color: '#ff8c00', // 悬停时颜色变深 |
| | | // borderWidth: 6, |
| | | // }, |
| | | // }, |
| | | lineStyle: { |
| | | color: 'rgba(52, 146, 242, 1)', |
| | | }, |
| | | data: [1, 7, 6, 30, 20, 21.43, 11, 16.67, 22, 88, 6.67, 10], |
| | | data: event_num, |
| | | }, |
| | | ], |
| | | }; |
| | |
| | | |
| | | getTypeData(); |
| | | lineCharts(); |
| | | getFlyList(); |
| | | getFlyTimeList(); |
| | | }); |
| | | </script> |
| | | |
| | |
| | | } |
| | | </style> |
| | | <style scoped lang="scss"> |
| | | // 开始 |
| | | .workbench { |
| | | padding: 0px 20px 0 20px; |
| | | display: flex; |
| | |
| | | .workleft { |
| | | width: 68%; |
| | | margin-right: 10px; |
| | | // 综合 |
| | | .comprehensiveCon { |
| | | // height: 736px; |
| | | background: #ffffff; |
| | |
| | | .name { |
| | | display: flex; |
| | | align-items: center; |
| | | font-weight: bold; |
| | | font-size: 16px; |
| | | color: #363636; |
| | | font-family: 'Source Han Sans CN'; |
| | | span { |
| | | margin-right: 4px; |
| | | } |
| | |
| | | height: 100%; |
| | | line-height: 32px; |
| | | cursor: pointer; |
| | | font-family: 'Source Han Sans CN'; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #1441FF; |
| | | } |
| | | .card-item:first-child { |
| | | border-right: 1px solid #e5e5e5; |
| | |
| | | .card-item:nth-child(2) { |
| | | border-right: 1px solid #e5e5e5; |
| | | } |
| | | .active { |
| | | .card-item.active { |
| | | color: #1441ff; |
| | | border: 1px solid #1c5cff; |
| | | } |
| | | } |
| | | } |
| | |
| | | .workOrder { |
| | | margin-top: 21px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | border-bottom: 1px solid #dfdfdf; |
| | | .card-group { |
| | | width: 40%; |
| | |
| | | color: #7c8091; |
| | | } |
| | | .total-number { |
| | | font-family: 'YouSheBiaoTiHei'; |
| | | font-family: 'Source Han Sans CN'; |
| | | |
| | | font-weight: bold; |
| | | font-size: 32px; |
| | | color: #2a54ff; |
| | |
| | | .status-item { |
| | | display: flex; |
| | | text-align: center; |
| | | justify-content: space-between; |
| | | height: 97px; |
| | | max-width: 148px; |
| | | background: #f6f8fe; |
| | | border-radius: 8px 8px 8px 8px; |
| | | img { |
| | | width: 26px; |
| | | height: 26px; |
| | | padding: 9px 2px; |
| | | padding: 9px 10px 9px 2px; |
| | | } |
| | | .statusCon { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | padding: 9px 4px 0 4px; |
| | | // align-items: center; |
| | | padding: 9px 4px 7px 10px; |
| | | text-align: left; |
| | | .status-label { |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | text-align: left; |
| | | color: #383838; |
| | | } |
| | | .ratio { |
| | |
| | | font-size: 12px; |
| | | color: #363636; |
| | | white-space: nowrap; |
| | | text-align: left; |
| | | } |
| | | .status-value { |
| | | font-family: 'YouSheBiaoTiHei'; |
| | | font-family: 'Source Han Sans CN'; |
| | | font-weight: bold; |
| | | font-size: 24px; |
| | | font-size: 30px; |
| | | color: #363636; |
| | | margin: 5px 0; |
| | | // font-style: italic; |
| | | display: inline-block; |
| | | transform: skewX(-5deg); |
| | | |
| | | span { |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | |
| | | } |
| | | .flycenter { |
| | | margin-top: 13px; |
| | | |
| | | .centerBox { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | margin-bottom: 10px; |
| | | .centerItem { |
| | | padding: 7px 7px 0 15px; |
| | | // width: 196px; |
| | |
| | | border-radius: 8px 8px 8px 8px; |
| | | border: 1px solid #ffffff; |
| | | margin-right: 16px; |
| | | img { |
| | | width: 15px; |
| | | height: 15px; |
| | | margin-right: 5px; |
| | | } |
| | | .flyimg { |
| | | display: flex; |
| | | align-items: center; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #7c8091; |
| | | } |
| | | .flydata { |
| | | margin-top: 15px; |
| | | text-align: right; |
| | |
| | | } |
| | | } |
| | | } |
| | | .centerRight { |
| | | width: 40%; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .workright { |
| | | width: 32%; |
| | | } |