Compare commits
61 Commits
3606ab7cf8
...
dhr
| Author | SHA1 | Date | |
|---|---|---|---|
| b6fabc0c4c | |||
| 0022ca0d01 | |||
| fe0ffbdf11 | |||
| 7645cba791 | |||
| f58efb0e08 | |||
| db9e2e55ea | |||
| 6079814962 | |||
| fd4e05a802 | |||
| af65455d33 | |||
| d1c090b855 | |||
| ed25998d61 | |||
| 6003bcbe32 | |||
| 8cd3ed3f8c | |||
| 16003cff02 | |||
| e9a60e978f | |||
| 63d17eea3c | |||
| 9407ad5446 | |||
| 11f9433ba7 | |||
| b6ec72acee | |||
| 3fa5b39fc3 | |||
| 744b7a6d97 | |||
| 086b52f88f | |||
| dd32d930d7 | |||
| d626d72d43 | |||
| 33831ecad3 | |||
| d68f537537 | |||
| b7c716509d | |||
| 64c538775f | |||
| bab5b8a856 | |||
| 4163b11d3d | |||
| 30f5941202 | |||
| f79eecd247 | |||
| bbca5c8961 | |||
| 033c6bcbfa | |||
| 31c1732af5 | |||
| 07c5dcde11 | |||
| 6d960a1fc7 | |||
| bc158f9bd5 | |||
| 84b2a05e3c | |||
| c027533d4f | |||
| bf44c0c34d | |||
| f0609716bc | |||
| 31cf862392 | |||
| 29be0d8e51 | |||
| e6aa2cb5a0 | |||
| f84503b620 | |||
| 55f2aeea39 | |||
| 7eabcd203f | |||
| 0521eb62ee | |||
| 938f8ad026 | |||
| 3445e54da0 | |||
| eb3e1326ca | |||
| d67b16d0b6 | |||
| 3c989db422 | |||
| 7ef7e48e83 | |||
| 504e1760d7 | |||
| 16b7bd4240 | |||
| 63167f66e7 | |||
| a32d382865 | |||
| f28a617bb3 | |||
| 93d6da6169 |
@ -29,8 +29,10 @@
|
||||
"axios": "1.8.4",
|
||||
"crypto-js": "4.2.0",
|
||||
"echarts": "5.6.0",
|
||||
"echarts-gl": "^2.0.9",
|
||||
"echarts-liquidfill": "^3.1.0",
|
||||
"element-plus": "2.9.8",
|
||||
"ezuikit-js": "^8.1.10",
|
||||
"file-saver": "2.0.5",
|
||||
"highlight.js": "11.9.0",
|
||||
"image-conversion": "2.1.1",
|
||||
@ -94,4 +96,4 @@
|
||||
"Safari >= 14",
|
||||
"Firefox >= 78"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
BIN
public/assets/caigou.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
public/assets/dialog1.png
Normal file
|
After Width: | Height: | Size: 411 KiB |
BIN
public/assets/dialog2.png
Normal file
|
After Width: | Height: | Size: 685 KiB |
BIN
public/assets/jkcckj.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
public/assets/jkfdl.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
public/assets/jkjrbjcs.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
public/assets/jklxsc.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
public/assets/no.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
public/assets/play.png
Normal file
|
After Width: | Height: | Size: 303 B |
BIN
public/assets/qian.jpg
Normal file
|
After Width: | Height: | Size: 827 B |
BIN
public/assets/re.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
1
public/assets/svg/delete.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12" height="12" viewBox="0 0 12 12" fill="none"><path d="M10.0923 2.25614C10.3323 2.25614 10.5303 2.29614 10.6863 2.37614C10.8423 2.45614 10.9663 2.55614 11.0583 2.67614C11.1503 2.79614 11.2143 2.92614 11.2503 3.06614C11.2863 3.20614 11.3043 3.33614 11.3043 3.45614C11.3043 3.51214 11.3023 3.55614 11.2983 3.58814C11.2943 3.62014 11.2923 3.64814 11.2923 3.67214L11.2923 3.74414L10.5003 3.74414L10.5003 10.0441C10.5003 10.2041 10.4683 10.3581 10.4043 10.5061C10.3403 10.6541 10.2483 10.7841 10.1283 10.8961C10.0083 11.0081 9.86228 11.0981 9.69028 11.1661C9.51828 11.2341 9.32028 11.2681 9.09628 11.2681L3.74428 11.2681C3.53628 11.2681 3.34028 11.2361 3.15628 11.1721C2.97229 11.1081 2.81428 11.0181 2.68228 10.9021C2.55028 10.7861 2.44628 10.6461 2.37028 10.4821C2.29428 10.3181 2.25628 10.1321 2.25628 9.92414L2.25628 3.74414L1.51228 3.74414C1.50428 3.73614 1.50028 3.71614 1.50028 3.68414C1.49228 3.64414 1.48828 3.52014 1.48828 3.31214C1.48828 3.20814 1.51228 3.09214 1.56028 2.96414C1.60828 2.83614 1.68028 2.71814 1.77628 2.61014C1.87228 2.50214 1.99628 2.41214 2.14828 2.34014C2.30028 2.26814 2.48028 2.23214 2.68828 2.23214L3.75628 2.23214L3.75628 1.50014C3.75628 1.29214 3.82828 1.11414 3.97228 0.966141C4.11628 0.818141 4.29228 0.744141 4.50028 0.744141L8.25628 0.744141C8.53628 0.744141 8.73028 0.818141 8.83828 0.966141C8.94628 1.11414 9.00028 1.29214 9.00028 1.50014L9.00028 2.24414C9.16828 2.25214 9.34828 2.25614 9.54028 2.25614L10.0923 2.25614ZM4.50028 2.25614L8.25628 2.25614L8.25628 1.50014L4.50028 1.50014L4.50028 2.25614ZM4.12828 9.85214C4.38428 9.85214 4.51228 9.68814 4.51228 9.36014L4.51228 3.79214L3.76828 3.79214L3.76828 9.36014C3.76828 9.52814 3.79429 9.65214 3.84628 9.73214C3.89828 9.81214 3.99229 9.85214 4.12828 9.85214ZM6.39628 9.84014C6.53228 9.84014 6.62428 9.80214 6.67228 9.72614C6.72028 9.65014 6.74428 9.52814 6.74428 9.36014L6.74428 3.79214L6.00028 3.79214L6.00028 9.36014C6.00028 9.68014 6.13228 9.84014 6.39628 9.84014ZM8.65228 9.81614C8.79628 9.81614 8.89228 9.77814 8.94028 9.70214C8.98828 9.62614 9.01228 9.50414 9.01228 9.33614L9.01228 3.79214L8.25628 3.79214L8.25628 9.33614C8.25628 9.65614 8.38828 9.81614 8.65228 9.81614Z" fill="#186DF5" ></path></svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
1
public/assets/svg/download.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12" height="12" viewBox="0 0 12 12" fill="none"><path d="M9.71435 10.4777L2.22855 10.4777C1.40179 10.4777 0.731445 9.80755 0.731445 8.98058L0.731445 7.10912C0.731445 6.90247 0.899128 6.7349 1.10565 6.7349L1.85435 6.7349C2.06101 6.7349 2.22855 6.90247 2.22855 7.10912L2.22855 8.23203C2.22855 8.64549 2.56367 8.98059 2.97711 8.98059L8.96579 8.98059C9.37924 8.98059 9.71435 8.64549 9.71435 8.23203L9.71435 7.10912C9.71435 6.90247 9.8819 6.7349 10.0887 6.7349L10.8372 6.7349C11.0439 6.7349 11.2115 6.90247 11.2115 7.10912L11.2115 8.98059C11.2115 9.80755 10.5413 10.4777 9.71435 10.4777ZM2.92875 3.13454C3.08016 2.98313 3.32585 2.98313 3.47728 3.13454L5.22302 4.8803L5.22302 1.11169C5.22302 0.905035 5.39062 0.737305 5.59723 0.737305L6.34579 0.737305C6.55249 0.737305 6.72015 0.905035 6.72015 1.11169L6.72015 4.8803L8.4659 3.13454C8.61733 2.98313 8.86289 2.98313 9.01431 3.13454L9.56289 3.68319C9.71432 3.83462 9.71432 4.08015 9.56289 4.23171L6.47159 7.32305C6.45822 7.33639 6.21771 7.48341 5.9757 7.48352C5.73105 7.48364 5.48493 7.33654 5.47156 7.32305L2.38011 4.23171C2.22868 4.08014 2.22868 3.83462 2.38011 3.68319L2.92875 3.13454Z" fill="#186DF5" ></path></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
1
public/assets/svg/huanyuan.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32" fill="none"><path d="M17.9776 16.1268L21.269 12.8125L21.269 13.6583C21.269 14.4614 21.9287 15.1097 22.7318 15.1097C23.535 15.1097 24.1833 14.4614 24.1833 13.6583L24.1833 9.26969C24.1833 8.46651 23.535 7.81826 22.7318 7.81826L18.3433 7.81826C17.5401 7.81826 16.8918 8.46651 16.8918 9.26969C16.8918 10.0728 17.5401 10.7325 18.3433 10.7325L19.189 10.7325L15.8747 14.024C15.8578 14.0412 15.845 14.0631 15.829 14.0811C15.8129 14.0991 15.7984 14.1195 15.7833 14.1383C15.7681 14.157 15.7518 14.1759 15.7376 14.1954C15.7233 14.2149 15.7165 14.2324 15.7033 14.2525C15.69 14.2727 15.6813 14.3003 15.669 14.3211C15.6567 14.3419 15.6233 14.3684 15.6233 14.3897C15.6233 14.411 15.6004 14.425 15.6004 14.4468C15.6004 14.4687 15.5661 14.4817 15.5661 14.504C15.5661 14.5263 15.5433 14.5612 15.5433 14.584C15.5433 14.6067 15.509 14.6295 15.509 14.6525C15.509 14.6756 15.4976 14.6863 15.4976 14.7097C15.4976 14.7331 15.4861 14.766 15.4861 14.7897C15.4861 14.8134 15.4633 14.8458 15.4633 14.8697C15.4633 14.8935 15.4518 14.9028 15.4518 14.9268C15.4518 14.9508 15.4518 14.9828 15.4518 15.0068C15.4518 15.0309 15.4518 15.0513 15.4518 15.0754C15.4518 15.0995 15.4518 15.1199 15.4518 15.144C15.4518 15.1681 15.4518 15.2 15.4518 15.224C15.4518 15.248 15.4633 15.2687 15.4633 15.2925C15.4633 15.3164 15.4861 15.3374 15.4861 15.3611C15.4861 15.3848 15.4976 15.4177 15.4976 15.4411C15.4976 15.4645 15.509 15.4752 15.509 15.4983C15.509 15.5214 15.5433 15.5441 15.5433 15.5668C15.5433 15.5895 15.5661 15.6245 15.5661 15.6468C15.5661 15.6691 15.6004 15.6821 15.6004 15.704C15.6004 15.7258 15.6233 15.7512 15.6233 15.7725C15.6233 15.7939 15.6567 15.8089 15.669 15.8297C15.6813 15.8505 15.69 15.8781 15.7033 15.8983C15.7165 15.9184 15.7233 15.9359 15.7376 15.9554C15.7518 15.9749 15.7681 15.9938 15.7833 16.0125C15.7984 16.0313 15.8129 16.0517 15.829 16.0697C15.845 16.0877 15.8578 16.1097 15.8747 16.1268C16.4588 16.6964 17.408 16.6964 17.9776 16.1268ZM8.12613 25.3268L12.5147 25.3268C13.3179 25.3268 13.9661 24.6786 13.9661 23.8754C13.9661 23.0722 13.3179 22.4125 12.5147 22.4125L11.669 22.4125L15.0176 19.0754C15.5871 18.5059 15.5871 17.5681 15.0176 16.984C15.0004 16.9671 14.9898 16.9429 14.9718 16.9268C14.9539 16.9108 14.9334 16.8963 14.9147 16.8811C14.8959 16.866 14.877 16.8611 14.8576 16.8468C14.8381 16.8326 14.8205 16.8144 14.8004 16.8011C14.7803 16.7878 14.7526 16.7677 14.7318 16.7554C14.7111 16.7431 14.6846 16.7211 14.6633 16.7211C14.6419 16.7211 14.628 16.6983 14.6061 16.6983C14.5843 16.6983 14.5599 16.664 14.5376 16.664C14.5153 16.664 14.4917 16.6411 14.469 16.6411C14.4463 16.6411 14.4235 16.6183 14.4004 16.6183C14.3773 16.6183 14.3553 16.5954 14.3318 16.5954C14.3085 16.5954 14.2869 16.584 14.2633 16.584C14.2396 16.584 14.2186 16.5725 14.1947 16.5725C14.1709 16.5725 14.1501 16.5611 14.1261 16.5611C14.1021 16.5611 14.0702 16.5497 14.0461 16.5497C14.022 16.5497 14.0017 16.5497 13.9776 16.5497C13.9535 16.5497 13.9331 16.5497 13.909 16.5497C13.8849 16.5497 13.853 16.5611 13.829 16.5611C13.805 16.5611 13.7843 16.5725 13.7604 16.5725C13.7366 16.5725 13.7155 16.584 13.6918 16.584C13.6682 16.584 13.6352 16.5954 13.6118 16.5954C13.5885 16.5954 13.5778 16.6183 13.5547 16.6183C13.5316 16.6183 13.4974 16.6411 13.4747 16.6411C13.452 16.6411 13.4284 16.664 13.4061 16.664C13.3838 16.664 13.3708 16.6983 13.349 16.6983C13.3271 16.6983 13.3018 16.7211 13.2804 16.7211C13.2591 16.7211 13.2326 16.7431 13.2118 16.7554C13.1911 16.7677 13.1749 16.7878 13.1547 16.8011C13.1346 16.8144 13.117 16.8326 13.0976 16.8468C13.0781 16.8611 13.0592 16.866 13.0404 16.8811C13.0217 16.8963 13.0013 16.9108 12.9833 16.9268C12.9653 16.9429 12.9548 16.9671 12.9376 16.984L9.58899 20.3325L9.58899 19.4868C9.58899 18.6837 8.92929 18.0354 8.12613 18.0354C7.32296 18.0354 6.6747 18.6837 6.6747 19.4868L6.6747 23.8754C6.6747 24.6786 7.32296 25.3268 8.12613 25.3268ZM25.6576 3.42969L5.20042 3.42969C3.59406 3.42969 2.28613 4.73762 2.28613 6.34397L2.28613 26.8011C2.28613 28.4075 3.59406 29.7154 5.20042 29.7154L25.6576 29.7154C27.2639 29.7154 28.5718 28.4075 28.5718 26.8011L28.5718 6.34397C28.5718 4.73762 27.2639 3.42969 25.6576 3.42969ZM25.6576 26.8011L5.20042 26.8011L5.20042 6.34397L25.6576 6.34397L25.6576 26.8011Z" fill="#FFFFFF" ></path></svg>
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
1
public/assets/svg/jietu.svg
Normal file
|
After Width: | Height: | Size: 16 KiB |
1
public/assets/svg/play.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12" height="12" viewBox="0 0 12 12" fill="none"><path d="M9.1496 5.57504L3.34961 1.97504C3.0246 1.77505 2.59961 2.02504 2.59961 2.40004L2.59961 9.60005C2.59961 9.97505 3.0246 10.225 3.34961 10.0251L9.12461 6.42505C9.4746 6.25004 9.4746 5.75005 9.1496 5.57504Z" fill="#186DF5" ></path></svg>
|
||||
|
After Width: | Height: | Size: 382 B |
1
public/assets/svg/quanpin.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32" fill="none"><path d="M11.9501 11.3874L11.9501 8.01232C11.9501 7.4532 11.4799 7 10.9 7C10.3199 7 9.84997 7.4532 9.84997 8.01232L9.84997 10.7125L7.05011 10.7125C6.46998 10.7125 6 11.1657 6 11.7248C6 12.2842 6.46998 12.7373 7.05011 12.7373L10.5499 12.7373C11.3231 12.7373 11.9501 12.133 11.9501 11.3874ZM11.9501 21.5125L11.9501 24.8873C11.9501 25.4467 11.4799 25.8999 10.9 25.8999C10.3199 25.8999 9.84997 25.4467 9.84997 24.8873L9.84997 22.1874L7.05011 22.1874C6.46998 22.1874 6 21.7342 6 21.1748C6 20.6157 6.46998 20.1622 7.05011 20.1622L10.5499 20.1622C11.3231 20.1622 11.9501 20.7668 11.9501 21.5125ZM19.65 21.5125L19.65 24.8873C19.65 25.4467 20.12 25.8999 20.7001 25.8999C21.2799 25.8999 21.7499 25.4467 21.7499 24.8873L21.7499 22.1874L24.55 22.1874C25.1298 22.1874 25.6001 21.7342 25.6001 21.1748C25.6001 20.6157 25.1299 20.1622 24.55 20.1622L21.0499 20.1622C20.2767 20.1622 19.65 20.7668 19.65 21.5125ZM19.65 11.3874L19.65 8.01232C19.65 7.4532 20.12 7 20.7001 7C21.2799 7 21.7499 7.4532 21.7499 8.01232L21.7499 10.7125L24.55 10.7125C25.1298 10.7125 25.6001 11.1657 25.6001 11.7248C25.6001 12.2842 25.1299 12.7373 24.55 12.7373L21.0499 12.7373C20.2767 12.7373 19.65 12.133 19.65 11.3874Z" stroke="rgba(255, 255, 255, 1)" stroke-width="0.8" fill="#FFFFFF" ></path><path d="M2 27.2998L2 5.69984C2 4.20862 3.25368 3 4.80014 3L27.2001 3C28.7465 3 30 4.20862 30 5.69984L30 27.2998C30 28.791 28.7465 30 27.2001 30L4.80014 30C3.25368 30 2 28.791 2 27.2998ZM27.2001 5.02491L4.80014 5.02491C4.30497 5.02491 4.10016 5.22265 4.10016 5.69984L4.10016 27.2998C4.10016 27.7773 4.30497 27.9751 4.80014 27.9751L27.9 27.9751L27.9 5.69984C27.9 5.22265 27.695 5.02491 27.2001 5.02491Z" stroke="rgba(255, 255, 255, 1)" stroke-width="0.8" fill="#FFFFFF" ></path></svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
BIN
public/assets/yes.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
75
src/api/devicePreset/index.ts
Normal file
@ -0,0 +1,75 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { DevicePresetVO, DevicePresetForm, DevicePresetQuery } from '@/api/camera/devicePreset/types';
|
||||
|
||||
/**
|
||||
* 查询摄像头预置位列表
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const listDevicePreset = (query?: DevicePresetQuery): AxiosPromise<DevicePresetVO[]> => {
|
||||
return request({
|
||||
url: '/ops/devicePreset/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询摄像头预置位详细
|
||||
* @param id
|
||||
*/
|
||||
export const getDevicePreset = (id: string | number): AxiosPromise<DevicePresetVO> => {
|
||||
return request({
|
||||
url: '/ops/devicePreset/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 新增摄像头预置位
|
||||
* @param data
|
||||
*/
|
||||
export const addDevicePreset = (data: DevicePresetForm) => {
|
||||
return request({
|
||||
url: '/ops/devicePreset',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 修改摄像头预置位
|
||||
* @param data
|
||||
*/
|
||||
export const updateDevicePreset = (data: DevicePresetForm) => {
|
||||
return request({
|
||||
url: '/ops/devicePreset',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除摄像头预置位
|
||||
* @param id
|
||||
*/
|
||||
export const delDevicePreset = (data: any) => {
|
||||
return request({
|
||||
url: '/ops/devicePreset/delYzd',
|
||||
method: 'delete',
|
||||
data: [data]
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 调用摄像头预置位
|
||||
* @param data
|
||||
*/
|
||||
export const callDevicePreset = (data: DevicePresetForm) => {
|
||||
return request({
|
||||
url: '/ops/devicePreset/callYzd',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
86
src/api/devicePreset/types.ts
Normal file
@ -0,0 +1,86 @@
|
||||
export interface DevicePresetVO {
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 设备序列号
|
||||
*/
|
||||
deviceSerial: string;
|
||||
|
||||
/**
|
||||
* 通道号
|
||||
*/
|
||||
channelNo: number;
|
||||
|
||||
/**
|
||||
* 预置点序号
|
||||
*/
|
||||
presetIndex: number;
|
||||
|
||||
/**
|
||||
* 预置点
|
||||
*/
|
||||
presetName: string;
|
||||
|
||||
}
|
||||
|
||||
export interface DevicePresetForm extends BaseEntity {
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 设备序列号
|
||||
*/
|
||||
deviceSerial?: string;
|
||||
|
||||
/**
|
||||
* 通道号
|
||||
*/
|
||||
channelNo?: number;
|
||||
|
||||
/**
|
||||
* 预置点序号
|
||||
*/
|
||||
presetIndex?: number;
|
||||
|
||||
/**
|
||||
* 预置点
|
||||
*/
|
||||
presetName?: string;
|
||||
|
||||
}
|
||||
|
||||
export interface DevicePresetQuery extends PageQuery {
|
||||
|
||||
/**
|
||||
* 设备序列号
|
||||
*/
|
||||
deviceSerial?: string;
|
||||
|
||||
/**
|
||||
* 通道号
|
||||
*/
|
||||
channelNo?: number;
|
||||
|
||||
/**
|
||||
* 预置点序号
|
||||
*/
|
||||
presetIndex?: number;
|
||||
|
||||
/**
|
||||
* 预置点
|
||||
*/
|
||||
presetName?: string;
|
||||
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
params?: any;
|
||||
}
|
||||
|
||||
|
||||
|
||||
33
src/api/large/index.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import request from '@/utils/request';
|
||||
|
||||
// 查询图表总数据
|
||||
export function getPowerStationOverview() {
|
||||
return request({
|
||||
url: '/ops/ginlong/api/getPowerStationOverview',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
//能源收益
|
||||
export function getStationMonthOverview(params: any) {
|
||||
return request({
|
||||
url: '/ops/ginlong/api/getStationMonthOverview',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
//能源收益
|
||||
export function getInverterListOverview(params: any) {
|
||||
return request({
|
||||
url: '/ops/ginlong/api/getInverterListOverview',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
//警告
|
||||
export function getAlarmListOverview(params?: any) {
|
||||
return request({
|
||||
url: '/ops/ginlong/api/getAlarmListOverview',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
79
src/api/renyuan/paiban/index.ts
Normal file
@ -0,0 +1,79 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { SchedulingVO } from './types';
|
||||
|
||||
|
||||
/**
|
||||
* 查询排班人员列表
|
||||
* @param deptId
|
||||
*/
|
||||
export function getPaibanRenYuanList(deptId:string | number): AxiosPromise<any> {
|
||||
return request({
|
||||
url: `/system/user/list/dept/`+deptId,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询运维-人员排班列表
|
||||
*/
|
||||
export function getPaibanRiLiList(query?: SchedulingVO): AxiosPromise<SchedulingVO[]> {
|
||||
return request({
|
||||
url: `/ops/personnel/scheduling/getRiLiList`,
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 运维-人员排班-查询排班列表
|
||||
*/
|
||||
export function getPaibanListPage(query?: SchedulingVO): AxiosPromise<SchedulingVO[]> {
|
||||
return request({
|
||||
url: `/ops/personnel/scheduling/list`,
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 运维-人员排班-安排排班
|
||||
*/
|
||||
export function savePaiban(data: any): AxiosPromise<any> {
|
||||
return request({
|
||||
url: `/ops/personnel/scheduling/all`,
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 运维-人员排班-修改排班
|
||||
*/
|
||||
export function updatePaiban(data:any): AxiosPromise<any> {
|
||||
return request({
|
||||
url: `/ops/personnel/scheduling`,
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 运维-人员排班-批量修改排班
|
||||
*/
|
||||
// export function updateAllPaiban(): AxiosPromise<any> {
|
||||
// return request({
|
||||
// url: `/ops/personnel/scheduling/all`,
|
||||
// method: 'put',
|
||||
// });
|
||||
// }
|
||||
|
||||
/**
|
||||
* 运维-人员排班-删除排班
|
||||
*/
|
||||
export function deletePaiban(ids: string): AxiosPromise<any> {
|
||||
return request({
|
||||
url: `/ops/personnel/scheduling/${ids}`,
|
||||
method: 'delete',
|
||||
});
|
||||
}
|
||||
39
src/api/renyuan/paiban/types.ts
Normal file
@ -0,0 +1,39 @@
|
||||
export interface SchedulingVO {
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
schedulingStartDate: string;
|
||||
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
schedulingEndDate: string;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
projectId?: string | number;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// export interface SchedulingQuery extends PageQuery {
|
||||
|
||||
// /**
|
||||
// * 开始时间
|
||||
// */
|
||||
// schedulingStartDate: string;
|
||||
|
||||
// /**
|
||||
// * 结束时间
|
||||
// */
|
||||
// schedulingEndDate: string;
|
||||
|
||||
// /**
|
||||
// * 部门ID
|
||||
// */
|
||||
// projectId?: string | number;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
63
src/api/renyuan/schedulingDate/index.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { SchedulingDateVO, SchedulingDateForm, SchedulingDateQuery } from '@/api/renyuan/schedulingDate/types';
|
||||
|
||||
/**
|
||||
* 查询运维-排班时间类型列表
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const listSchedulingDate = (query?: SchedulingDateQuery): AxiosPromise<SchedulingDateVO[]> => {
|
||||
return request({
|
||||
url: '/ops/personnel/schedulingDate/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询运维-排班时间类型详细
|
||||
* @param id
|
||||
*/
|
||||
export const getSchedulingDate = (id: string | number): AxiosPromise<SchedulingDateVO> => {
|
||||
return request({
|
||||
url: '/ops/personnel/schedulingDate/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 新增运维-排班时间类型
|
||||
* @param data
|
||||
*/
|
||||
export const addSchedulingDate = (data: SchedulingDateForm) => {
|
||||
return request({
|
||||
url: '/ops/personnel/schedulingDate',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 修改运维-排班时间类型
|
||||
* @param data
|
||||
*/
|
||||
export const updateSchedulingDate = (data: SchedulingDateForm) => {
|
||||
return request({
|
||||
url: '/ops/personnel/schedulingDate',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除运维-排班时间类型
|
||||
* @param id
|
||||
*/
|
||||
export const delSchedulingDate = (id: string | number | Array<string | number>) => {
|
||||
return request({
|
||||
url: '/ops/personnel/schedulingDate/' + id,
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
86
src/api/renyuan/schedulingDate/types.ts
Normal file
@ -0,0 +1,86 @@
|
||||
export interface SchedulingDateVO {
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 排班名称
|
||||
*/
|
||||
schedulingName: string;
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
startTime: string;
|
||||
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
endTime: string;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
projectId?: string | number;
|
||||
|
||||
}
|
||||
|
||||
export interface SchedulingDateForm extends BaseEntity {
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 排班名称
|
||||
*/
|
||||
schedulingName?: string;
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
startTime?: string;
|
||||
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
endTime?: string;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
projectId?: string | number;
|
||||
|
||||
}
|
||||
|
||||
export interface SchedulingDateQuery extends PageQuery {
|
||||
|
||||
/**
|
||||
* 排班名称
|
||||
*/
|
||||
schedulingName?: string;
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
startTime?: string;
|
||||
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
endTime?: string;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
projectId?: string | number;
|
||||
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
params?: any;
|
||||
}
|
||||
|
||||
|
||||
|
||||
23
src/api/securitySurveillance/index.js
Normal file
@ -0,0 +1,23 @@
|
||||
import request from '@/utils/request';
|
||||
// 获取萤石云Token
|
||||
export function getToken() {
|
||||
return request({
|
||||
url: '/ops/monitoriing/getToken',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
// 获取摄像头列表
|
||||
export function getMonitoringList(data) {
|
||||
return request({
|
||||
url: '/ops/monitoriing/getMonitoringList',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
// 获取首页大屏数据
|
||||
export function getHomeScreenData() {
|
||||
return request({
|
||||
url: '/ops/monitoriing/getMonitoringDp',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
@ -20,18 +20,20 @@ export const getMenu = (menuId: string | number): AxiosPromise<MenuVO> => {
|
||||
};
|
||||
|
||||
// 查询菜单下拉树结构
|
||||
export const treeselect = (): AxiosPromise<MenuTreeOption[]> => {
|
||||
export const treeselect = (params?: any): AxiosPromise<MenuTreeOption[]> => {
|
||||
return request({
|
||||
url: '/system/menu/treeselect',
|
||||
method: 'get'
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
};
|
||||
|
||||
// 根据角色ID查询菜单下拉树结构
|
||||
export const roleMenuTreeselect = (roleId: string | number): AxiosPromise<RoleMenuTree> => {
|
||||
export const roleMenuTreeselect = (roleId: string | number, params?: any): AxiosPromise<RoleMenuTree> => {
|
||||
return request({
|
||||
url: '/system/menu/roleMenuTreeselect/' + roleId,
|
||||
method: 'get'
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -147,10 +147,11 @@ export const authUserSelectAll = (data: any) => {
|
||||
});
|
||||
};
|
||||
// 根据角色ID查询部门树结构
|
||||
export const deptTreeSelect = (roleId: string | number): AxiosPromise<RoleDeptTree> => {
|
||||
export const deptTreeSelect = (roleId: string | number, params?) => {
|
||||
return request({
|
||||
url: '/system/role/deptTree/' + roleId,
|
||||
method: 'get'
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -39,6 +39,7 @@ export interface RoleQuery extends PageQuery {
|
||||
|
||||
export interface RoleForm {
|
||||
roleName: string;
|
||||
deptId: string | undefined;
|
||||
roleKey: string;
|
||||
roleSort: number;
|
||||
status: string;
|
||||
|
||||
@ -202,10 +202,11 @@ export const listUserByDeptId = (deptId: string | number): AxiosPromise<UserVO[]
|
||||
/**
|
||||
* 查询部门下拉树结构
|
||||
*/
|
||||
export const deptTreeSelect = (): AxiosPromise<DeptTreeVO[]> => {
|
||||
export const deptTreeSelect = (data?: { isShow: string }): AxiosPromise<DeptTreeVO[]> => {
|
||||
return request({
|
||||
url: '/system/user/deptTree',
|
||||
method: 'get'
|
||||
method: 'get',
|
||||
params: data
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
63
src/api/wuziguanli/beijian/index.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { BeipinBeijianVO, BeipinBeijianForm, BeipinBeijianQuery } from '@/api/wuziguanli/beijian/types';
|
||||
|
||||
/**
|
||||
* 查询运维-物资-备品配件列表
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const listBeipinBeijian = (query?: BeipinBeijianQuery): AxiosPromise<BeipinBeijianVO[]> => {
|
||||
return request({
|
||||
url: '/ops/beipinBeijian/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询运维-物资-备品配件详细
|
||||
* @param id
|
||||
*/
|
||||
export const getBeipinBeijian = (id: string | number): AxiosPromise<BeipinBeijianVO> => {
|
||||
return request({
|
||||
url: '/ops/beipinBeijian/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 新增运维-物资-备品配件
|
||||
* @param data
|
||||
*/
|
||||
export const addBeipinBeijian = (data: BeipinBeijianForm) => {
|
||||
return request({
|
||||
url: '/ops/beipinBeijian',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 修改运维-物资-备品配件
|
||||
* @param data
|
||||
*/
|
||||
export const updateBeipinBeijian = (data: BeipinBeijianForm) => {
|
||||
return request({
|
||||
url: '/ops/beipinBeijian',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除运维-物资-备品配件
|
||||
* @param id
|
||||
*/
|
||||
export const delBeipinBeijian = (id: string | number | Array<string | number>) => {
|
||||
return request({
|
||||
url: '/ops/beipinBeijian/' + id,
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
131
src/api/wuziguanli/beijian/types.ts
Normal file
@ -0,0 +1,131 @@
|
||||
export interface BeipinBeijianVO {
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 项目id
|
||||
*/
|
||||
projectId: string | number;
|
||||
|
||||
/**
|
||||
* 备件编号
|
||||
*/
|
||||
beijianNumber: string;
|
||||
|
||||
/**
|
||||
* 备件名称
|
||||
*/
|
||||
beijianName: string;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
shebeiType: string;
|
||||
|
||||
/**
|
||||
* 规格型号
|
||||
*/
|
||||
guigexinghao: string;
|
||||
|
||||
/**
|
||||
* 库存状态(待定)
|
||||
*/
|
||||
kucunStatus: string;
|
||||
|
||||
/**
|
||||
* 库存数量
|
||||
*/
|
||||
kucunCount: number;
|
||||
|
||||
}
|
||||
|
||||
export interface BeipinBeijianForm extends BaseEntity {
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 项目id
|
||||
*/
|
||||
projectId?: string | number;
|
||||
|
||||
/**
|
||||
* 备件编号
|
||||
*/
|
||||
beijianNumber?: string;
|
||||
|
||||
/**
|
||||
* 备件名称
|
||||
*/
|
||||
beijianName?: string;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
shebeiType?: string;
|
||||
|
||||
/**
|
||||
* 规格型号
|
||||
*/
|
||||
guigexinghao?: string;
|
||||
|
||||
/**
|
||||
* 库存状态(待定)
|
||||
*/
|
||||
kucunStatus?: string;
|
||||
|
||||
/**
|
||||
* 库存数量
|
||||
*/
|
||||
kucunCount?: number;
|
||||
|
||||
}
|
||||
|
||||
export interface BeipinBeijianQuery extends PageQuery {
|
||||
|
||||
/**
|
||||
* 项目id
|
||||
*/
|
||||
projectId?: string | number;
|
||||
|
||||
/**
|
||||
* 备件编号
|
||||
*/
|
||||
beijianNumber?: string;
|
||||
|
||||
/**
|
||||
* 备件名称
|
||||
*/
|
||||
beijianName?: string;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
shebeiType?: string;
|
||||
|
||||
/**
|
||||
* 规格型号
|
||||
*/
|
||||
guigexinghao?: string;
|
||||
|
||||
/**
|
||||
* 库存状态(待定)
|
||||
*/
|
||||
kucunStatus?: string;
|
||||
|
||||
/**
|
||||
* 库存数量
|
||||
*/
|
||||
kucunCount?: number;
|
||||
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
params?: any;
|
||||
}
|
||||
|
||||
|
||||
|
||||
56
src/api/wuziguanli/caigouPlan/index.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { CaigouPlanVO, CaigouPlanForm, CaigouPlanQuery } from '@/api/wuziguanli/caigouPlan/types';
|
||||
|
||||
/**
|
||||
* 查询运维-物资-采购计划单列表
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const listCaigouPlan = (query?: CaigouPlanQuery): AxiosPromise<CaigouPlanVO[]> => {
|
||||
return request({
|
||||
url: '/ops/caigouPlan/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询采购商列表
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const getSupplierList = (data:any): AxiosPromise<any> => {
|
||||
return request({
|
||||
url: '/ops/tenderSupplierInput/getList',
|
||||
method: 'get',
|
||||
params: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 新增运维-物资-采购计划单
|
||||
* @param data
|
||||
* @returns {*}
|
||||
*/
|
||||
export const addCaigouPlan = (data: CaigouPlanForm): AxiosPromise<CaigouPlanVO> => {
|
||||
return request({
|
||||
url: '/ops/caigouPlan',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询运维-物资-采购计划单详情
|
||||
* @param id
|
||||
* @returns {*}
|
||||
*/
|
||||
export const caigouPlanDetail = (id: string | number): AxiosPromise<CaigouPlanVO> => {
|
||||
return request({
|
||||
url: `/ops/caigouPlan/`+id,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
558
src/api/wuziguanli/caigouPlan/types.ts
Normal file
@ -0,0 +1,558 @@
|
||||
export interface CaigouPlanVO {
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 项目id
|
||||
*/
|
||||
projectId: string | number;
|
||||
|
||||
/**
|
||||
* 计划名称
|
||||
*/
|
||||
jihuaName: string;
|
||||
|
||||
/**
|
||||
* 计划编号
|
||||
*/
|
||||
jihuaBianhao: string;
|
||||
|
||||
/**
|
||||
* 采购单位(当前登录人部门)
|
||||
*/
|
||||
caigouDanwei: number;
|
||||
|
||||
/**
|
||||
* 采购单位名称
|
||||
*/
|
||||
caigouDanweiName: string;
|
||||
|
||||
/**
|
||||
* 经办人
|
||||
*/
|
||||
jingbanren: number;
|
||||
|
||||
/**
|
||||
* 经办人名称
|
||||
*/
|
||||
jingbanrenName: string;
|
||||
|
||||
/**
|
||||
* 合同类型
|
||||
*/
|
||||
hetonType: string;
|
||||
|
||||
/**
|
||||
* 采购类型
|
||||
*/
|
||||
caigouType: string;
|
||||
|
||||
/**
|
||||
* 仓库地址
|
||||
*/
|
||||
cangkuUrl: string;
|
||||
|
||||
/**
|
||||
* 合同名称
|
||||
*/
|
||||
hetonName: string;
|
||||
|
||||
/**
|
||||
* 供应商id
|
||||
*/
|
||||
gonyingshangId: string | number;
|
||||
|
||||
/**
|
||||
* 出货时间
|
||||
*/
|
||||
chuhuoTime: string;
|
||||
|
||||
/**
|
||||
* 付款条件
|
||||
*/
|
||||
fukuantiaojian: string;
|
||||
|
||||
/**
|
||||
* 发票开具方式
|
||||
*/
|
||||
fapiaoKjfs: string;
|
||||
|
||||
/**
|
||||
* 计划状态
|
||||
*/
|
||||
status: string;
|
||||
|
||||
/**
|
||||
* 审核状态
|
||||
*/
|
||||
shenheStatus: string;
|
||||
|
||||
/**
|
||||
* 预计金额
|
||||
*/
|
||||
yujiJine: number;
|
||||
|
||||
/**
|
||||
* 实际采购金额
|
||||
*/
|
||||
shijiJine: number;
|
||||
/**
|
||||
* 文件id
|
||||
*/
|
||||
fileId: string | number;
|
||||
|
||||
/**
|
||||
* 文件地址
|
||||
*/
|
||||
fileUrl: string;
|
||||
|
||||
/**
|
||||
* 文件名称
|
||||
*/
|
||||
fileName: string;
|
||||
|
||||
/**
|
||||
* 采购申请计划id
|
||||
*/
|
||||
caigouPlanId: string | number;
|
||||
|
||||
/**
|
||||
* 产品名称
|
||||
*/
|
||||
chanpinName: string;
|
||||
|
||||
/**
|
||||
* 产品型号
|
||||
*/
|
||||
chanpinType: string;
|
||||
|
||||
/**
|
||||
* 产品单价
|
||||
*/
|
||||
chanpinMonovalent: number;
|
||||
|
||||
/**
|
||||
* 购买数量
|
||||
*/
|
||||
goumaiNumber: number;
|
||||
|
||||
/**
|
||||
* 单位
|
||||
*/
|
||||
danwei: string;
|
||||
|
||||
/**
|
||||
* 用途
|
||||
*/
|
||||
yontu: string;
|
||||
|
||||
/**
|
||||
* 总价
|
||||
*/
|
||||
totalPrice: number;
|
||||
/**
|
||||
* 申请时间
|
||||
*/
|
||||
createTime?: string;
|
||||
/**
|
||||
* 出货时间
|
||||
*/
|
||||
chouhuoTime?: string;
|
||||
/**
|
||||
* 采购申请计划文件 新增
|
||||
*/
|
||||
opsCaigouPlanFilesBos?: Array<any>;
|
||||
/**
|
||||
* 采购申请计划产品 新增
|
||||
*/
|
||||
opsCaigouPlanChanpinBos?:Array<any>;
|
||||
|
||||
/**
|
||||
* 采购申请计划产品 查询
|
||||
*/
|
||||
opsCaigouPlanChanpinVos?: Array<any>;
|
||||
|
||||
/**
|
||||
* 采购申请计划文件 查询
|
||||
*/
|
||||
opsCaigouPlanFilesVos?: Array<any>;
|
||||
|
||||
}
|
||||
|
||||
export interface CaigouPlanForm extends BaseEntity {
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 项目id
|
||||
*/
|
||||
projectId?: string | number;
|
||||
|
||||
/**
|
||||
* 计划名称
|
||||
*/
|
||||
jihuaName?: string;
|
||||
|
||||
/**
|
||||
* 计划编号
|
||||
*/
|
||||
jihuaBianhao?: string;
|
||||
|
||||
/**
|
||||
* 采购单位(当前登录人部门)
|
||||
*/
|
||||
caigouDanwei?: number;
|
||||
|
||||
/**
|
||||
* 采购单位名称
|
||||
*/
|
||||
caigouDanweiName?: string;
|
||||
|
||||
/**
|
||||
* 经办人
|
||||
*/
|
||||
jingbanren?: number;
|
||||
|
||||
/**
|
||||
* 经办人名称
|
||||
*/
|
||||
jingbanrenName?: string;
|
||||
|
||||
/**
|
||||
* 合同类型
|
||||
*/
|
||||
hetonType?: string;
|
||||
|
||||
/**
|
||||
* 采购类型
|
||||
*/
|
||||
caigouType?: string;
|
||||
|
||||
/**
|
||||
* 仓库地址
|
||||
*/
|
||||
cangkuUrl?: string;
|
||||
|
||||
/**
|
||||
* 合同名称
|
||||
*/
|
||||
hetonName?: string;
|
||||
|
||||
/**
|
||||
* 供应商id
|
||||
*/
|
||||
gonyingshangId?: string | number;
|
||||
|
||||
/**
|
||||
* 出货时间
|
||||
*/
|
||||
chuhuoTime?: string;
|
||||
|
||||
/**
|
||||
* 付款条件
|
||||
*/
|
||||
fukuantiaojian?: string;
|
||||
|
||||
/**
|
||||
* 发票开具方式
|
||||
*/
|
||||
fapiaoKjfs?: string;
|
||||
|
||||
/**
|
||||
* 计划状态
|
||||
*/
|
||||
status?: string;
|
||||
|
||||
/**
|
||||
* 审核状态
|
||||
*/
|
||||
shenheStatus?: string;
|
||||
|
||||
/**
|
||||
* 预计金额
|
||||
*/
|
||||
yujiJine?: number;
|
||||
|
||||
/**
|
||||
* 实际采购金额
|
||||
*/
|
||||
shijiJine?: number;
|
||||
/**
|
||||
* 采购申请计划id
|
||||
*/
|
||||
caigouPlanId?: string | number;
|
||||
|
||||
/**
|
||||
* 文件id
|
||||
*/
|
||||
fileId?: string | number;
|
||||
|
||||
/**
|
||||
* 文件地址
|
||||
*/
|
||||
fileUrl?: string;
|
||||
|
||||
/**
|
||||
* 文件名称
|
||||
*/
|
||||
fileName?: string;
|
||||
/**
|
||||
* 产品名称
|
||||
*/
|
||||
chanpinName?: string;
|
||||
|
||||
/**
|
||||
* 产品型号
|
||||
*/
|
||||
chanpinType?: string;
|
||||
|
||||
/**
|
||||
* 产品单价
|
||||
*/
|
||||
chanpinMonovalent?: number;
|
||||
|
||||
/**
|
||||
* 购买数量
|
||||
*/
|
||||
goumaiNumber?: number;
|
||||
|
||||
/**
|
||||
* 单位
|
||||
*/
|
||||
danwei?: string;
|
||||
|
||||
/**
|
||||
* 用途
|
||||
*/
|
||||
yontu?: string;
|
||||
|
||||
/**
|
||||
* 总价
|
||||
*/
|
||||
totalPrice?: number;
|
||||
/**
|
||||
* 采购申请计划文件 新增
|
||||
*/
|
||||
opsCaigouPlanFilesBos?: Array<any>;
|
||||
/**
|
||||
* 采购申请计划产品 新增
|
||||
*/
|
||||
opsCaigouPlanChanpinBos?:Array<any>;
|
||||
|
||||
/**
|
||||
* 采购申请计划产品 查询
|
||||
*/
|
||||
opsCaigouPlanChanpinVos?: Array<any>;
|
||||
|
||||
/**
|
||||
* 采购申请计划文件 查询
|
||||
*/
|
||||
opsCaigouPlanFilesVos?: Array<any>;
|
||||
/**
|
||||
* 申请时间
|
||||
*/
|
||||
createTime?: string;
|
||||
/**
|
||||
* 出货时间
|
||||
*/
|
||||
chouhuoTime?: string;
|
||||
|
||||
|
||||
}
|
||||
|
||||
export interface CaigouPlanQuery extends PageQuery {
|
||||
|
||||
/**
|
||||
* 项目id
|
||||
*/
|
||||
projectId?: string | number;
|
||||
|
||||
/**
|
||||
* 计划名称
|
||||
*/
|
||||
jihuaName?: string;
|
||||
|
||||
/**
|
||||
* 计划编号
|
||||
*/
|
||||
jihuaBianhao?: string;
|
||||
|
||||
/**
|
||||
* 采购单位(当前登录人部门)
|
||||
*/
|
||||
caigouDanwei?: number;
|
||||
|
||||
/**
|
||||
* 采购单位名称
|
||||
*/
|
||||
caigouDanweiName?: string;
|
||||
|
||||
/**
|
||||
* 经办人
|
||||
*/
|
||||
jingbanren?: number;
|
||||
|
||||
/**
|
||||
* 经办人名称
|
||||
*/
|
||||
jingbanrenName?: string;
|
||||
|
||||
/**
|
||||
* 合同类型
|
||||
*/
|
||||
hetonType?: string;
|
||||
|
||||
/**
|
||||
* 采购类型
|
||||
*/
|
||||
caigouType?: string;
|
||||
|
||||
/**
|
||||
* 仓库地址
|
||||
*/
|
||||
cangkuUrl?: string;
|
||||
|
||||
/**
|
||||
* 合同名称
|
||||
*/
|
||||
hetonName?: string;
|
||||
|
||||
/**
|
||||
* 供应商id
|
||||
*/
|
||||
gonyingshangId?: string | number;
|
||||
|
||||
/**
|
||||
* 出货时间
|
||||
*/
|
||||
chuhuoTime?: string;
|
||||
|
||||
/**
|
||||
* 付款条件
|
||||
*/
|
||||
fukuantiaojian?: string;
|
||||
|
||||
/**
|
||||
* 发票开具方式
|
||||
*/
|
||||
fapiaoKjfs?: string;
|
||||
|
||||
/**
|
||||
* 计划状态
|
||||
*/
|
||||
status?: string;
|
||||
|
||||
/**
|
||||
* 审核状态
|
||||
*/
|
||||
shenheStatus?: string;
|
||||
|
||||
/**
|
||||
* 预计金额
|
||||
*/
|
||||
yujiJine?: number;
|
||||
|
||||
/**
|
||||
* 实际采购金额
|
||||
*/
|
||||
shijiJine?: number;
|
||||
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
params?: any;
|
||||
/**
|
||||
* 采购申请计划id
|
||||
*/
|
||||
caigouPlanId?: string | number;
|
||||
|
||||
/**
|
||||
* 文件id
|
||||
*/
|
||||
fileId?: string | number;
|
||||
|
||||
/**
|
||||
* 文件地址
|
||||
*/
|
||||
fileUrl?: string;
|
||||
|
||||
/**
|
||||
* 文件名称
|
||||
*/
|
||||
fileName?: string;
|
||||
|
||||
/**
|
||||
* 产品名称
|
||||
*/
|
||||
chanpinName?: string;
|
||||
|
||||
/**
|
||||
* 产品型号
|
||||
*/
|
||||
chanpinType?: string;
|
||||
|
||||
/**
|
||||
* 产品单价
|
||||
*/
|
||||
chanpinMonovalent?: number;
|
||||
|
||||
/**
|
||||
* 购买数量
|
||||
*/
|
||||
goumaiNumber?: number;
|
||||
|
||||
/**
|
||||
* 单位
|
||||
*/
|
||||
danwei?: string;
|
||||
|
||||
/**
|
||||
* 用途
|
||||
*/
|
||||
yontu?: string;
|
||||
|
||||
/**
|
||||
* 总价
|
||||
*/
|
||||
totalPrice?: number;
|
||||
/**
|
||||
* 采购申请计划文件 新增
|
||||
*/
|
||||
opsCaigouPlanFilesBos?: Array<any>;
|
||||
/**
|
||||
* 采购申请计划产品 新增
|
||||
*/
|
||||
opsCaigouPlanChanpinBos?:Array<any>;
|
||||
|
||||
/**
|
||||
* 采购申请计划产品 查询
|
||||
*/
|
||||
opsCaigouPlanChanpinVos?: Array<any>;
|
||||
|
||||
/**
|
||||
* 采购申请计划文件 查询
|
||||
*/
|
||||
opsCaigouPlanFilesVos?: Array<any>;
|
||||
/**
|
||||
* 申请时间
|
||||
*/
|
||||
createTime?: string;
|
||||
/**
|
||||
* 出货时间
|
||||
*/
|
||||
chouhuoTime?: string;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
76
src/api/wuziguanli/churuku/index.ts
Normal file
@ -0,0 +1,76 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { ChurukudanVO, ChurukudanForm, ChurukudanQuery } from '@/api/wuziguanli/churuku/types';
|
||||
|
||||
/**
|
||||
* 查询运维-物资-出入库单管理列表
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const listChurukudan = (query?: ChurukudanQuery): AxiosPromise<ChurukudanVO[]> => {
|
||||
return request({
|
||||
url: '/ops/churukudan/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询运维-物资-出入库单管理详细
|
||||
* @param id
|
||||
*/
|
||||
export const getChurukudan = (id: string | number): AxiosPromise<ChurukudanVO> => {
|
||||
return request({
|
||||
url: '/ops/churukudan/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 新增运维-物资-出入库单管理
|
||||
* @param data
|
||||
*/
|
||||
export const addChurukudan = (data: ChurukudanForm) => {
|
||||
return request({
|
||||
url: '/ops/churukudan',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 修改运维-物资-出入库单管理
|
||||
* @param data
|
||||
*/
|
||||
export const updateChurukudan = (data: ChurukudanForm) => {
|
||||
return request({
|
||||
url: '/ops/churukudan',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除运维-物资-出入库单管理
|
||||
* @param id
|
||||
*/
|
||||
export const delChurukudan = (id: string | number | Array<string | number>) => {
|
||||
return request({
|
||||
url: '/ops/churukudan/' + id,
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 运维-物资-出入库单柱状图
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
export const getChuRuKuCountBar = (data:any): AxiosPromise<any> => {
|
||||
return request({
|
||||
url: '/ops/churukudan/getChuRuKuCount',
|
||||
method: 'get',
|
||||
params: data
|
||||
});
|
||||
};
|
||||
154
src/api/wuziguanli/churuku/types.ts
Normal file
@ -0,0 +1,154 @@
|
||||
export interface ChurukudanVO {
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
id: string | number;
|
||||
/**
|
||||
* 项目id
|
||||
*/
|
||||
projectId: string | number;
|
||||
/**
|
||||
* 单据编号
|
||||
*/
|
||||
danjvNumber: string;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
shebeiType: string;
|
||||
|
||||
/**
|
||||
* 经手人id
|
||||
*/
|
||||
jingshourenId: string | number;
|
||||
|
||||
/**
|
||||
* 经手人
|
||||
*/
|
||||
jingshourenName: string;
|
||||
|
||||
/**
|
||||
* 联系电话
|
||||
*/
|
||||
contactNumber: string;
|
||||
|
||||
/**
|
||||
* 总数量
|
||||
*/
|
||||
zonNumber: number;
|
||||
|
||||
/**
|
||||
* 审核状态
|
||||
*/
|
||||
shenheStatus: string;
|
||||
|
||||
/**
|
||||
* 单据状态(1、出库单,2入库单)
|
||||
*/
|
||||
danjvType: string;
|
||||
|
||||
}
|
||||
|
||||
export interface ChurukudanForm extends BaseEntity {
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
id?: string | number;
|
||||
/**
|
||||
* 项目id
|
||||
*/
|
||||
projectId: string | number;
|
||||
/**
|
||||
* 单据编号
|
||||
*/
|
||||
danjvNumber?: string;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
shebeiType?: string;
|
||||
|
||||
/**
|
||||
* 经手人id
|
||||
*/
|
||||
jingshourenId?: string | number;
|
||||
|
||||
/**
|
||||
* 经手人
|
||||
*/
|
||||
jingshourenName?: string;
|
||||
|
||||
/**
|
||||
* 联系电话
|
||||
*/
|
||||
contactNumber?: string;
|
||||
|
||||
/**
|
||||
* 总数量
|
||||
*/
|
||||
zonNumber?: number;
|
||||
|
||||
/**
|
||||
* 审核状态
|
||||
*/
|
||||
shenheStatus?: string;
|
||||
|
||||
/**
|
||||
* 单据状态(1、出库单,2入库单)
|
||||
*/
|
||||
danjvType?: string;
|
||||
|
||||
/**
|
||||
* 审核状态
|
||||
*/
|
||||
auditStatus?: string;
|
||||
|
||||
}
|
||||
|
||||
export interface ChurukudanQuery extends PageQuery {
|
||||
/**
|
||||
* 项目id
|
||||
*/
|
||||
projectId?: string | number;
|
||||
/**
|
||||
* 单据编号
|
||||
*/
|
||||
danjvNumber?: string;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
shebeiType?: string;
|
||||
|
||||
/**
|
||||
* 审核状态
|
||||
*/
|
||||
shenheStatus?: string;
|
||||
|
||||
/**
|
||||
* 单据状态(1、出库单,2入库单)
|
||||
*/
|
||||
danjvType?: string;
|
||||
|
||||
/**
|
||||
* 审核状态
|
||||
*/
|
||||
auditStatus?: string;
|
||||
|
||||
/**
|
||||
* 开始日期
|
||||
*/
|
||||
startDate?: string;
|
||||
|
||||
/**
|
||||
* 结束日期
|
||||
*/
|
||||
endDate?: string;
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
params?: any;
|
||||
}
|
||||
|
||||
|
||||
|
||||
27252
src/assets/china.json
Normal file
7522
src/assets/cq.json
Normal file
BIN
src/assets/demo/approval.png
Normal file
|
After Width: | Height: | Size: 507 B |
BIN
src/assets/demo/archive.png
Normal file
|
After Width: | Height: | Size: 353 B |
BIN
src/assets/demo/chi.png
Normal file
|
After Width: | Height: | Size: 604 B |
BIN
src/assets/demo/down.png
Normal file
|
After Width: | Height: | Size: 195 B |
BIN
src/assets/demo/health.png
Normal file
|
After Width: | Height: | Size: 415 B |
BIN
src/assets/demo/icTicket.png
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
src/assets/demo/mouse-square.png
Normal file
|
After Width: | Height: | Size: 405 B |
BIN
src/assets/demo/nowifi.png
Normal file
|
After Width: | Height: | Size: 348 B |
BIN
src/assets/demo/people.png
Normal file
|
After Width: | Height: | Size: 208 B |
BIN
src/assets/demo/qin.png
Normal file
|
After Width: | Height: | Size: 544 B |
BIN
src/assets/demo/que.png
Normal file
|
After Width: | Height: | Size: 660 B |
BIN
src/assets/demo/rebot.png
Normal file
|
After Width: | Height: | Size: 384 B |
BIN
src/assets/demo/sms-tracking.png
Normal file
|
After Width: | Height: | Size: 432 B |
BIN
src/assets/demo/time.png
Normal file
|
After Width: | Height: | Size: 253 B |
BIN
src/assets/demo/tui.png
Normal file
|
After Width: | Height: | Size: 613 B |
BIN
src/assets/demo/up.png
Normal file
|
After Width: | Height: | Size: 193 B |
BIN
src/assets/demo/wifi.png
Normal file
|
After Width: | Height: | Size: 312 B |
BIN
src/assets/demo/wifiwarn.png
Normal file
|
After Width: | Height: | Size: 424 B |
@ -11,6 +11,7 @@
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
// 思源字体
|
||||
// @font-face {
|
||||
// font-family: 'SourceHanSansCN-Bold';
|
||||
@ -56,6 +57,7 @@
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
// @font-face {
|
||||
// font-family: 'SourceHanSansCN-Bold';
|
||||
// src: url('./ReflectTi/SourceHanSerifCN-Bold.otf');//暂时没用
|
||||
@ -110,6 +112,8 @@
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
|
||||
//阿里黑体
|
||||
@font-face {
|
||||
font-family: 'AlimamaShuHeiTi-Bold';
|
||||
@ -117,6 +121,7 @@
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
// @font-face {
|
||||
// font-family: 'Alibaba-PuHuiTi-Heavy';
|
||||
// src: url('./Alibaba/Alibaba-PuHuiTi-Heavy.otf');//暂时没用
|
||||
@ -135,6 +140,7 @@
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
// @font-face {
|
||||
// font-family: 'Alibaba-PuHuiTi-Regular';
|
||||
// src: url('./Alibaba/Alibaba-PuHuiTi-Regular.otf');//暂时没用
|
||||
@ -148,18 +154,19 @@
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'D-Din';
|
||||
font-family: 'D-Din';
|
||||
src: url('./D-Din//D-DIN.ttf');
|
||||
font-weight: normal;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Roboto-Regular'; //Roboto
|
||||
src: url('./Roboto//Roboto-Regular.ttf');
|
||||
font-weight: normal;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
}
|
||||
BIN
src/assets/large/Inversion.png
Normal file
|
After Width: | Height: | Size: 361 B |
BIN
src/assets/large/bg.png
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
src/assets/large/center1.png
Normal file
|
After Width: | Height: | Size: 399 B |
BIN
src/assets/large/center2.png
Normal file
|
After Width: | Height: | Size: 597 B |
BIN
src/assets/large/center3.png
Normal file
|
After Width: | Height: | Size: 541 B |
BIN
src/assets/large/center4.png
Normal file
|
After Width: | Height: | Size: 457 B |
BIN
src/assets/large/center5.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
src/assets/large/income.png
Normal file
|
After Width: | Height: | Size: 568 B |
BIN
src/assets/large/monitor.png
Normal file
|
After Width: | Height: | Size: 793 B |
BIN
src/assets/large/power.png
Normal file
|
After Width: | Height: | Size: 671 B |
BIN
src/assets/large/right1.png
Normal file
|
After Width: | Height: | Size: 464 B |
BIN
src/assets/large/right2.png
Normal file
|
After Width: | Height: | Size: 425 B |
BIN
src/assets/large/right3.png
Normal file
|
After Width: | Height: | Size: 492 B |
BIN
src/assets/large/right4.png
Normal file
|
After Width: | Height: | Size: 368 B |
BIN
src/assets/large/right5.png
Normal file
|
After Width: | Height: | Size: 487 B |
BIN
src/assets/large/right6.png
Normal file
|
After Width: | Height: | Size: 758 B |
BIN
src/assets/large/right7.png
Normal file
|
After Width: | Height: | Size: 478 B |
BIN
src/assets/large/right8.png
Normal file
|
After Width: | Height: | Size: 491 B |
BIN
src/assets/large/right9.png
Normal file
|
After Width: | Height: | Size: 534 B |
BIN
src/assets/large/secure.png
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
src/assets/large/setting.png
Normal file
|
After Width: | Height: | Size: 760 B |
BIN
src/assets/large/weather.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
16
src/assets/styles/1.html
Normal file
@ -0,0 +1,16 @@
|
||||
<div class="card">
|
||||
<div id="content">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
// 定义每个状态对应的图片URL
|
||||
const titleList = ['运行正常', '运行异常', '未运行']
|
||||
let titleHtml = ""
|
||||
titleList.forEach((title, index) => {
|
||||
titleHtml += `我是标题${title}<br>`
|
||||
})
|
||||
document.getElementById('content').innerHTML = titleHtml
|
||||
|
||||
</script>
|
||||
230
src/assets/styles/dialog.scss
Normal file
@ -0,0 +1,230 @@
|
||||
.no-header-dialog {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#custom-dialog {
|
||||
padding: 0;
|
||||
top: 0;
|
||||
|
||||
.el-dialog__header {
|
||||
// display: none;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
padding: 0 !important;
|
||||
// height: auto !important;
|
||||
max-height: none !important;
|
||||
}
|
||||
|
||||
.status-alert-content {
|
||||
background: linear-gradient(180deg, rgba(0, 119, 255, 0.23) 0%, rgba(255, 255, 255, 0) 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-left: 20px;
|
||||
padding-right: 50px;
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
|
||||
.title {
|
||||
color: rgba(0, 30, 59, 1);
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.name {
|
||||
color: rgba(0, 30, 59, 1);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
|
||||
.last-update {
|
||||
// font-size: ;
|
||||
color: rgba(113, 128, 150, 1);
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
.text {
|
||||
font-size: 12px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.img {
|
||||
width: 240px;
|
||||
height: 240px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.info-box {
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
gap: 40px;
|
||||
margin-left: 30px;
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.title {
|
||||
color: rgba(113, 128, 150, 1);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.text {
|
||||
font-weight: bold;
|
||||
color: rgba(0, 30, 59, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.status-alert-content .success {
|
||||
color: rgba(0, 184, 122, 1) !important;
|
||||
}
|
||||
|
||||
.status-alert-content .orange {
|
||||
color: rgba(255, 153, 0, 1) !important;
|
||||
}
|
||||
|
||||
.status-alert-content .red {
|
||||
color: rgba(227, 39, 39, 1) !important;
|
||||
}
|
||||
|
||||
.back {
|
||||
background-image: url("/assets/dialog2.png");
|
||||
background-size: 455px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 780px -65px;
|
||||
}
|
||||
|
||||
.alarm-alert-content {
|
||||
background: linear-gradient(180deg, rgba(255, 87, 51, 0.23) 0%, rgba(255, 219, 219, 0) 100%);
|
||||
padding-left: 50px;
|
||||
padding-right: 50px;
|
||||
padding-bottom: 50px;
|
||||
|
||||
.top {
|
||||
display: flex;
|
||||
gap: 50px;
|
||||
align-items: center;
|
||||
padding: 50px 0;
|
||||
padding-bottom: 20px;
|
||||
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
|
||||
.title {
|
||||
color: rgba(227, 39, 39, 1);
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.alarm-id {
|
||||
color: rgba(0, 30, 59, 1);
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.status-box {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
|
||||
.status {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.last-update {
|
||||
color: rgba(113, 128, 150, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.info-box {
|
||||
.list {
|
||||
display: flex;
|
||||
gap: 90px;
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 30px;
|
||||
|
||||
.title {
|
||||
color: rgba(113, 128, 150, 1);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.text {
|
||||
color: rgba(0, 30, 59, 1);
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.progress-box {
|
||||
.title {
|
||||
color: rgba(0, 30, 59, 1);
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.notice-box {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
color: rgba(113, 128, 150, 1);
|
||||
|
||||
.time {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.title.active {
|
||||
color: rgba(247, 89, 10, 1);
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.alarm-alert-content .red {
|
||||
color: rgba(227, 39, 39, 1) !important;
|
||||
}
|
||||
}
|
||||
86
src/assets/styles/element.scss
Normal file
@ -0,0 +1,86 @@
|
||||
// 选择框样式
|
||||
.el-select {
|
||||
.el-select__wrapper {
|
||||
background: transparent !important;
|
||||
box-shadow: none !important;
|
||||
border: 0.1px solid rgba(24, 177, 219, 0.3) !important;
|
||||
}
|
||||
|
||||
.el-select__placeholder {
|
||||
color: rgba(255, 255, 255, 0.9) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.el-popper {
|
||||
background: transparent !important;
|
||||
border: 1px solid rgba(24, 177, 219, 0.3) !important;
|
||||
|
||||
.el-popper__arrow:before {
|
||||
background: rgba(10, 79, 84, 0.5) !important;
|
||||
border: 1px solid rgba(10, 79, 84, 1) !important;
|
||||
right: 0;
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.el-select-dropdown__item {
|
||||
color: rgba(255, 255, 255, 0.9) !important;
|
||||
}
|
||||
|
||||
.is-hovering {
|
||||
background: rgba(10, 79, 84, 1) !important;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// 日期组件样式
|
||||
.el-input__wrapper {
|
||||
display: inline-flex;
|
||||
flex-grow: 1;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 1px 11px;
|
||||
background-color: transparent !important;
|
||||
background-image: none;
|
||||
// border-radius: var(--el-input-border-radius, var(--el-border-radius-base));
|
||||
// cursor: text;
|
||||
// transition: var(--el-transition-box-shadow);
|
||||
// transform: translate3d(0, 0, 0);
|
||||
box-shadow: none !important;
|
||||
border: 0.1px solid rgba(24, 177, 219, 0.3) !important;
|
||||
}
|
||||
|
||||
.el-input__inner {
|
||||
color: #fff !important;
|
||||
|
||||
}
|
||||
|
||||
.el-date-table-cell__text {
|
||||
color: #fff !important;
|
||||
|
||||
}
|
||||
|
||||
.el-date-picker {
|
||||
/* --el-datepicker-text-color: var(--el-text-color-regular); */
|
||||
--el-datepicker-off-text-color: var(--el-text-color-placeholder);
|
||||
--el-datepicker-header-text-color: #fff !important;
|
||||
--el-datepicker-icon-color: #fff !important;
|
||||
/* --el-datepicker-border-color: var(--el-disabled-border-color); */
|
||||
/* --el-datepicker-inner-border-color: var(--el-border-color-light); */
|
||||
/* --el-datepicker-inrange-bg-color: var(--el-border-color-extra-light); */
|
||||
/* --el-datepicker-inrange-hover-bg-color: var(--el-border-color-extra-light); */
|
||||
/* --el-datepicker-active-color: var(--el-color-primary); */
|
||||
--el-datepicker-hover-text-color: #fff !important;
|
||||
}
|
||||
|
||||
.el-date-picker__header-label {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.el-picker-panel {
|
||||
color: #fff !important;
|
||||
background: rgba(10, 79, 84, 0.85) !important;
|
||||
|
||||
// border-radius: var(--el-border-radius-base);
|
||||
// line-height: 30px;
|
||||
}
|
||||
@ -7,6 +7,8 @@
|
||||
@use './ruoyi.scss';
|
||||
@use 'animate.css';
|
||||
@use 'element-plus/dist/index.css';
|
||||
@use './dialog.scss';
|
||||
|
||||
|
||||
body {
|
||||
height: 100%;
|
||||
@ -208,4 +210,4 @@ aside {
|
||||
vertical-align: middle;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
169
src/components/EchartBox/index.vue
Normal file
@ -0,0 +1,169 @@
|
||||
<template>
|
||||
<div ref="echartBox" class="echarts"></div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import china from '@/assets/china.json';
|
||||
import cq from '@/assets/cq.json';
|
||||
import { ref, onMounted, watchEffect, onBeforeUnmount } from 'vue';
|
||||
import * as echarts from 'echarts/core';
|
||||
import {
|
||||
BarChart, // 柱状图
|
||||
// 系列类型的定义后缀都为 SeriesOption
|
||||
BarSeriesOption,
|
||||
LineChart, // 折线图
|
||||
LineSeriesOption,
|
||||
PieChart, // 饼图
|
||||
PieSeriesOption,
|
||||
PictorialBarChart,
|
||||
MapChart,
|
||||
ScatterChart,
|
||||
EffectScatterChart,
|
||||
LinesChart
|
||||
} from 'echarts/charts';
|
||||
import {
|
||||
// 组件类型的定义后缀都为 ComponentOption
|
||||
// 标题
|
||||
TitleComponent,
|
||||
TitleComponentOption,
|
||||
// 提示框
|
||||
TooltipComponent,
|
||||
TooltipComponentOption,
|
||||
// 直角坐标系
|
||||
GridComponent,
|
||||
GridComponentOption,
|
||||
// 图例
|
||||
LegendComponent,
|
||||
LegendComponentOption,
|
||||
// 数据集组件
|
||||
DatasetComponent,
|
||||
DatasetComponentOption,
|
||||
// 内置数据转换器组件 (filter, sort)
|
||||
TransformComponent,
|
||||
DataZoomComponent,
|
||||
DataZoomComponentOption,
|
||||
// 极坐标
|
||||
PolarComponent,
|
||||
PolarComponentOption,
|
||||
MarkLineComponentOption,
|
||||
MarkLineComponent,
|
||||
// MarkPoint
|
||||
MarkPointComponent,
|
||||
MarkPointComponentOption,
|
||||
// VisualMap
|
||||
VisualMapComponent,
|
||||
VisualMapComponentOption,
|
||||
// GeoComponent
|
||||
GeoComponent,
|
||||
GeoComponentOption
|
||||
} from 'echarts/components';
|
||||
import { LabelLayout, UniversalTransition } from 'echarts/features';
|
||||
import { CanvasRenderer } from 'echarts/renderers';
|
||||
import 'echarts-gl';
|
||||
|
||||
// 通过 ComposeOption 来组合出一个只有必须组件和图表的 Option 类型
|
||||
type ECOption = echarts.ComposeOption<
|
||||
| BarSeriesOption
|
||||
| LineSeriesOption
|
||||
| PieSeriesOption
|
||||
| TitleComponentOption
|
||||
| TooltipComponentOption
|
||||
| GridComponentOption
|
||||
| DatasetComponentOption
|
||||
| LegendComponentOption
|
||||
| DataZoomComponentOption
|
||||
| PolarComponentOption
|
||||
| MarkLineComponentOption
|
||||
| MarkPointComponentOption
|
||||
| VisualMapComponentOption
|
||||
| GeoComponentOption
|
||||
>;
|
||||
|
||||
// 注册必须的组件
|
||||
echarts.use([
|
||||
TitleComponent,
|
||||
TooltipComponent,
|
||||
GridComponent,
|
||||
DatasetComponent,
|
||||
TransformComponent,
|
||||
LegendComponent,
|
||||
DataZoomComponent,
|
||||
PolarComponent,
|
||||
MarkLineComponent,
|
||||
MarkPointComponent,
|
||||
LabelLayout,
|
||||
UniversalTransition,
|
||||
CanvasRenderer,
|
||||
BarChart,
|
||||
LineChart,
|
||||
PieChart,
|
||||
VisualMapComponent,
|
||||
PictorialBarChart,
|
||||
GeoComponent,
|
||||
MapChart,
|
||||
ScatterChart,
|
||||
EffectScatterChart,
|
||||
LinesChart
|
||||
]);
|
||||
const props = defineProps({
|
||||
option: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
});
|
||||
const emit = defineEmits(['echartsEvent']);
|
||||
const echartBox = ref(null);
|
||||
let chart!: echarts.ECharts;
|
||||
|
||||
const setChart = (option: ECOption): void => {
|
||||
if (!props.option || !echartBox.value) {
|
||||
return;
|
||||
}
|
||||
chart.resize();
|
||||
chart.setOption(option);
|
||||
};
|
||||
|
||||
const resetChart = (): void => {
|
||||
const option = chart.getOption();
|
||||
if (!option || !echartBox.value) {
|
||||
return;
|
||||
}
|
||||
chart.resize();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
(echarts as any).registerMap('china', { geoJSON: china });
|
||||
(echarts as any).registerMap('cq', { geoJSON: cq });
|
||||
chart = echarts.init(echartBox.value as any);
|
||||
|
||||
emit('echartsEvent', chart);
|
||||
setChart(props.option);
|
||||
// 界面拉伸后重设
|
||||
window.addEventListener('resize', () => {
|
||||
resetChart();
|
||||
});
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
if (chart) {
|
||||
chart.clear();
|
||||
}
|
||||
setChart(props.option);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (chart) {
|
||||
chart.dispose();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.echarts {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: all;
|
||||
}
|
||||
</style>
|
||||
@ -3,6 +3,7 @@
|
||||
<el-upload
|
||||
ref="fileUploadRef"
|
||||
multiple
|
||||
:drag="isDrag"
|
||||
:action="uploadFileUrl"
|
||||
:before-upload="handleBeforeUpload"
|
||||
:file-list="fileList"
|
||||
@ -17,7 +18,13 @@
|
||||
v-if="!disabled"
|
||||
>
|
||||
<!-- 上传按钮 -->
|
||||
<el-button type="primary">选取文件</el-button>
|
||||
<el-button type="primary" v-if="!isDrag">选取文件</el-button>
|
||||
<div v-else>
|
||||
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
|
||||
<div class="el-upload__text">
|
||||
拖拽文件到此处,或 <em>点击上传</em>
|
||||
</div>
|
||||
</div>
|
||||
</el-upload>
|
||||
<!-- 上传提示 -->
|
||||
<div v-if="showTip && !disabled" class="el-upload__tip">
|
||||
@ -63,11 +70,13 @@ const props = defineProps({
|
||||
// 是否显示提示
|
||||
isShowTip: propTypes.bool.def(true),
|
||||
// 禁用组件(仅查看文件)
|
||||
disabled: propTypes.bool.def(false)
|
||||
disabled: propTypes.bool.def(false),
|
||||
// 是否开启拖拽上传
|
||||
isDrag: propTypes.bool.def(false)
|
||||
});
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const emit = defineEmits(['update:modelValue']);
|
||||
const emit = defineEmits(['update:modelValue', 'update:fileList']);
|
||||
const number = ref(0);
|
||||
const uploadList = ref<any[]>([]);
|
||||
|
||||
@ -80,6 +89,7 @@ const showTip = computed(() => props.isShowTip && (props.fileType || props.fileS
|
||||
|
||||
const fileUploadRef = ref<ElUploadInstance>();
|
||||
|
||||
|
||||
// 监听 fileType 变化,更新 fileAccept
|
||||
const fileAccept = computed(() => props.fileType.map((type) => `.${type}`).join(','));
|
||||
|
||||
@ -164,6 +174,7 @@ const handleUploadSuccess = (res: any, file: UploadFile) => {
|
||||
url: res.data.url,
|
||||
ossId: res.data.ossId
|
||||
});
|
||||
|
||||
uploadedSuccessfully();
|
||||
} else {
|
||||
number.value--;
|
||||
@ -189,6 +200,7 @@ const uploadedSuccessfully = () => {
|
||||
uploadList.value = [];
|
||||
number.value = 0;
|
||||
emit('update:modelValue', listToString(fileList.value));
|
||||
emit('update:fileList', fileList.value);
|
||||
proxy?.$modal.closeLoading();
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-row>
|
||||
<el-row v-if="titleStatus">
|
||||
<el-col>
|
||||
<div style="color: rgba(0, 30, 59, 1);font-family: 'Alibaba-PuHuiTi-Bold';margin: 10px 0 0 0;"
|
||||
:style="{ fontSize: fontLevelMap[props.fontLevel] }">
|
||||
@ -11,10 +11,10 @@
|
||||
{{ props.subtitle }}
|
||||
</p>
|
||||
</el-col>
|
||||
|
||||
</el-row>
|
||||
</template>
|
||||
<script setup>
|
||||
const titleStatus = ref(false)
|
||||
const props = defineProps({
|
||||
title: String,
|
||||
subtitle: String,
|
||||
|
||||
@ -42,6 +42,8 @@ export default {
|
||||
responseType: 'blob',
|
||||
headers: globalHeaders()
|
||||
});
|
||||
console.log('🚀 ~ zip ~ res:', res);
|
||||
|
||||
const isBlob = blobValidate(res.data);
|
||||
if (isBlob) {
|
||||
const blob = new Blob([res.data], { type: 'application/zip' });
|
||||
|
||||
@ -62,6 +62,11 @@ export const constantRoutes: RouteRecordRaw[] = [
|
||||
component: () => import('@/views/error/401.vue'),
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: '/largeScreen',
|
||||
component: () => import('@/views/largeScreen/index.vue'),
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
component: Layout,
|
||||
@ -92,9 +97,7 @@ export const constantRoutes: RouteRecordRaw[] = [
|
||||
];
|
||||
|
||||
// 动态路由,基于用户权限动态去加载
|
||||
export const dynamicRoutes: RouteRecordRaw[] = [
|
||||
|
||||
];
|
||||
export const dynamicRoutes: RouteRecordRaw[] = [];
|
||||
|
||||
/**
|
||||
* 创建路由
|
||||
|
||||
80
src/store/modules/procurementDraft.ts
Normal file
@ -0,0 +1,80 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { ref } from 'vue';
|
||||
import $cache from '@/plugins/cache';
|
||||
|
||||
// 草稿数据类型
|
||||
export interface ProcurementDraft {
|
||||
id: string;
|
||||
draftNumber: string;
|
||||
planName: string;
|
||||
saveTime: string;
|
||||
content: any;
|
||||
}
|
||||
|
||||
// 保存草稿到本地存储
|
||||
const saveDraftsToStorage = (drafts: ProcurementDraft[]) => {
|
||||
$cache.local.setJSON('procurementDrafts', drafts);
|
||||
};
|
||||
|
||||
// 从本地存储获取草稿
|
||||
const getDraftsFromStorage = (): ProcurementDraft[] => {
|
||||
const stored = $cache.local.getJSON('procurementDrafts');
|
||||
return stored && Array.isArray(stored) ? stored : [];
|
||||
};
|
||||
|
||||
export const useProcurementDraftStore = defineStore('procurementDraft', () => {
|
||||
const draftList = ref<ProcurementDraft[]>(getDraftsFromStorage());
|
||||
|
||||
// 保存草稿
|
||||
const saveDraft = (planName: string, content: any): ProcurementDraft => {
|
||||
const today = new Date();
|
||||
const dateStr = today.getFullYear() + '-' +
|
||||
String(today.getMonth() + 1).padStart(2, '0') + '-' +
|
||||
String(today.getDate()).padStart(2, '0');
|
||||
const randomNum = Math.floor(100 + Math.random() * 900);
|
||||
const draftNumber = `DRAFT-${dateStr}-${randomNum}`;
|
||||
|
||||
const newDraft: ProcurementDraft = {
|
||||
id: `draft_${Date.now()}_${randomNum}`,
|
||||
draftNumber,
|
||||
planName,
|
||||
saveTime: new Date().toLocaleString(),
|
||||
content: JSON.parse(JSON.stringify(content)) // 深拷贝内容
|
||||
};
|
||||
|
||||
// 添加到草稿列表并保存到本地存储
|
||||
draftList.value.unshift(newDraft);
|
||||
saveDraftsToStorage(draftList.value);
|
||||
|
||||
return newDraft;
|
||||
};
|
||||
|
||||
// 获取草稿列表
|
||||
const getDraftList = (): ProcurementDraft[] => {
|
||||
return draftList.value;
|
||||
};
|
||||
|
||||
// 获取单个草稿
|
||||
const getDraft = (draftId: string): ProcurementDraft | undefined => {
|
||||
return draftList.value.find(draft => draft.id === draftId);
|
||||
};
|
||||
|
||||
// 删除草稿
|
||||
const deleteDraft = (draftId: string): boolean => {
|
||||
const index = draftList.value.findIndex(draft => draft.id === draftId);
|
||||
if (index !== -1) {
|
||||
draftList.value.splice(index, 1);
|
||||
saveDraftsToStorage(draftList.value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
return {
|
||||
draftList,
|
||||
saveDraft,
|
||||
getDraftList,
|
||||
getDraft,
|
||||
deleteDraft
|
||||
};
|
||||
});
|
||||
70
src/utils/getDate.ts
Normal file
@ -0,0 +1,70 @@
|
||||
// 获取指定月份的日期信息
|
||||
export interface DateInfo {
|
||||
date: number;
|
||||
weekDay: string;
|
||||
fullDate: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前月份的日期信息
|
||||
* @returns 包含当月所有日期信息的数组
|
||||
*/
|
||||
export const getCurrentMonthDates = (): DateInfo[] => {
|
||||
const today = new Date();
|
||||
const year = today.getFullYear();
|
||||
const month = today.getMonth(); // 0-11
|
||||
|
||||
// 获取当月第一天
|
||||
const firstDay = new Date(year, month, 1);
|
||||
// 获取当月最后一天
|
||||
const lastDay = new Date(year, month + 1, 0);
|
||||
// 当月总天数
|
||||
const daysInMonth = lastDay.getDate();
|
||||
|
||||
const weekdays = ['日', '一', '二', '三', '四', '五', '六'];
|
||||
const dates: DateInfo[] = [];
|
||||
|
||||
// 生成当月所有日期信息
|
||||
for (let i = 1; i <= daysInMonth; i++) {
|
||||
const date = new Date(year, month, i);
|
||||
const weekDayIndex = date.getDay(); // 0-6,0表示星期日
|
||||
dates.push({
|
||||
date: i,
|
||||
weekDay: weekdays[weekDayIndex],
|
||||
fullDate: `${year}-${String(month + 1).padStart(2, '0')}-${String(i).padStart(2, '0')}`
|
||||
});
|
||||
}
|
||||
|
||||
return dates;
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取指定月份的日期信息
|
||||
* @param year 年份
|
||||
* @param month 月份(0-11)
|
||||
* @returns 包含指定月份所有日期信息的数组
|
||||
*/
|
||||
export const getMonthDates = (year: number, month: number): DateInfo[] => {
|
||||
// 获取当月第一天
|
||||
const firstDay = new Date(year, month, 1);
|
||||
// 获取当月最后一天
|
||||
const lastDay = new Date(year, month + 1, 0);
|
||||
// 当月总天数
|
||||
const daysInMonth = lastDay.getDate();
|
||||
|
||||
const weekdays = ['日', '一', '二', '三', '四', '五', '六'];
|
||||
const dates: DateInfo[] = [];
|
||||
|
||||
// 生成当月所有日期信息
|
||||
for (let i = 1; i <= daysInMonth; i++) {
|
||||
const date = new Date(year, month, i);
|
||||
const weekDayIndex = date.getDay(); // 0-6,0表示星期日
|
||||
dates.push({
|
||||
date: i,
|
||||
weekDay: weekdays[weekDayIndex],
|
||||
fullDate: `${year}-${String(month + 1).padStart(2, '0')}-${String(i).padStart(2, '0')}`
|
||||
});
|
||||
}
|
||||
|
||||
return dates;
|
||||
};
|
||||
@ -365,9 +365,9 @@ export const getStepStatusText = (status: string | number): string => {
|
||||
const statusMap: Record<string, string> = {
|
||||
'1': '待执行',
|
||||
'2': '执行中',
|
||||
'3': '已完成',
|
||||
'3': '失败',
|
||||
'4': '已延期',
|
||||
'5': '失败'
|
||||
'5': '已完成'
|
||||
};
|
||||
return statusMap[statusStr] || '未知状态';
|
||||
};
|
||||
|
||||
309
src/views/camera/components/presetAdd.vue
Normal file
@ -0,0 +1,309 @@
|
||||
<template>
|
||||
<div class="system-busPresettingBit-add">
|
||||
<el-dialog v-model="isShowDialog" width="1250px" :close-on-click-modal="false" :destroy-on-close="true"
|
||||
@close="closeDialog">
|
||||
<template #header>
|
||||
<div
|
||||
v-drag="['.system-busPresettingBit-add .el-dialog', '.system-busPresettingBit-add .el-dialog__header']">
|
||||
{{ title }}:添加摄像头预置位
|
||||
</div>
|
||||
</template>
|
||||
<div class="info_list">
|
||||
<div class="video_box">
|
||||
<div class="video-container" id="video-container" style="width: 870px; height: 600px"></div>
|
||||
</div>
|
||||
<div>
|
||||
<el-button type="primary" style="margin: 0 20px 10px" @click="addPre">
|
||||
<el-icon>
|
||||
<Plus />
|
||||
</el-icon>
|
||||
添加预置点
|
||||
</el-button>
|
||||
<el-table v-loading="loading" :data="tableData.data" border>
|
||||
<el-table-column label="序号" align="center" type="index" width="55" />
|
||||
<el-table-column label="名称" align="center" prop="presetName" width="120px"
|
||||
show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.presetName" placeholder="请输入内容"
|
||||
@change="handleEdit(scope.row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="135px">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" link @click="handleDebug(scope.row)">
|
||||
<el-icon>
|
||||
<View />
|
||||
</el-icon>调用
|
||||
</el-button>
|
||||
<el-button type="danger" link @click="handleDelete(scope.row)">
|
||||
<el-icon>
|
||||
<DeleteFilled />
|
||||
</el-icon>删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination style="padding: 5px 16px" v-show="tableData.total > 0" :total="tableData.total"
|
||||
v-model:page="tableData.param.pageNum" v-model:limit="tableData.param.pageSize"
|
||||
@pagination="busPresettingBitList" :layout="layout" />
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onBeforeUnmount, getCurrentInstance, nextTick } from 'vue';
|
||||
import { ElMessageBox, ElMessage } from 'element-plus';
|
||||
import { listDevicePreset, addDevicePreset, updateDevicePreset, delDevicePreset, callDevicePreset } from '@/api/devicePreset';
|
||||
import { getToken } from '@/api/securitySurveillance/index.js';
|
||||
|
||||
import EZUIKit from 'ezuikit-js';
|
||||
import { ca } from 'element-plus/es/locale/index.mjs';
|
||||
const emit = defineEmits(['update']);
|
||||
const { proxy } = getCurrentInstance() as any;
|
||||
|
||||
const formRef = ref<HTMLElement | null>(null);
|
||||
const menuRef = ref();
|
||||
const loading = ref(false);
|
||||
|
||||
const isShowDialog = ref(false);
|
||||
const layout = ref('total, prev, pager, next');
|
||||
const title = ref('');
|
||||
const updateRow = ref<any>(null);
|
||||
const src = ref(null);
|
||||
const flvPlayer = ref<any>(null);
|
||||
|
||||
const formData = ref({
|
||||
deviceSerial: undefined,
|
||||
channelNo: '1',
|
||||
presetName: undefined
|
||||
});
|
||||
|
||||
const tableData = ref({
|
||||
data: [],
|
||||
total: 0,
|
||||
loading: false,
|
||||
param: {
|
||||
pageNum: 1,
|
||||
pageSize: 15,
|
||||
deviceSerial: ''
|
||||
}
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
function openDialog(row: any) {
|
||||
resetForm();
|
||||
updateRow.value = row;
|
||||
title.value = row.deviceName;
|
||||
formData.value.deviceSerial = row.deviceSerial;
|
||||
tableData.value.param.deviceSerial = row.deviceSerial;
|
||||
isShowDialog.value = true;
|
||||
busPresettingBitList();
|
||||
nextTick(() => {
|
||||
videoPlay(row);
|
||||
});
|
||||
}
|
||||
|
||||
// 添加预置点
|
||||
function addPre() {
|
||||
ElMessageBox.prompt('请输入预置点名称', '添加预置点', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
inputErrorMessage: '请输入预置点名称'
|
||||
})
|
||||
.then(({ value }) => {
|
||||
// 加载动画
|
||||
const loading = ElLoading.service({
|
||||
lock: true,
|
||||
text: '添加中',
|
||||
background: 'rgba(0, 0, 0, 0.7)',
|
||||
})
|
||||
formData.value.presetName = value;
|
||||
addDevicePreset(formData.value)
|
||||
.then(() => {
|
||||
ElMessage.success('添加成功');
|
||||
busPresettingBitList();
|
||||
})
|
||||
.finally(() => {
|
||||
// loading.value = false;
|
||||
loading.close();
|
||||
});
|
||||
})
|
||||
.catch(() => { });
|
||||
}
|
||||
|
||||
// 视频播放
|
||||
function videoPlay(obj: any) {
|
||||
console.log('objobjobj', obj);
|
||||
|
||||
getToken().then((res: any) => {
|
||||
if (res.msg == "ok" && obj.deviceSerial) {
|
||||
flvPlayer.value = new EZUIKit.EZUIKitPlayer({
|
||||
audio: '0',
|
||||
id: 'video-container',
|
||||
accessToken: res.data,
|
||||
url: `ezopen://open.ys7.com/${obj.deviceSerial}/1.hd.live`,
|
||||
template: 'pcLive',
|
||||
width: 870,
|
||||
height: 600,
|
||||
plugin: ['talk'],
|
||||
handleError: function (err: any) {
|
||||
console.log(err);
|
||||
|
||||
if (err?.data?.ret === 20020) {
|
||||
// 20020 是并发连接限制的错误码
|
||||
ElMessage.error('当前观看人数已达上限,请稍后再试');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 关闭弹窗
|
||||
function closeDialog() {
|
||||
if (flvPlayer.value) {
|
||||
flvPlayer.value.destroy().then((data: any) => {
|
||||
console.log('promise 获取 数据', data);
|
||||
});
|
||||
flvPlayer.value = null;
|
||||
}
|
||||
isShowDialog.value = false;
|
||||
}
|
||||
|
||||
// 获取列表
|
||||
function busPresettingBitList() {
|
||||
loading.value = true;
|
||||
listDevicePreset(tableData.value.param).then((res: any) => {
|
||||
tableData.value.data = res.rows ?? [];
|
||||
tableData.value.total = res.total;
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
// 取消
|
||||
function onCancel() {
|
||||
closeDialog();
|
||||
}
|
||||
|
||||
// 删除
|
||||
function handleDelete(row: any) {
|
||||
let msg = '你确定要删除所选数据?';
|
||||
let id: number[] = [];
|
||||
if (row) {
|
||||
msg = '此操作将永久删除数据,是否继续?';
|
||||
id = [row.id];
|
||||
}
|
||||
if (id.length === 0) {
|
||||
ElMessage.error('请选择要删除的数据。');
|
||||
return;
|
||||
}
|
||||
ElMessageBox.confirm(msg, '提示', {
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
const obj = {
|
||||
deviceSerial: row.deviceSerial,
|
||||
ids: id
|
||||
};
|
||||
delDevicePreset({
|
||||
id: row.id,
|
||||
deviceSerial: row.deviceSerial,
|
||||
channelNo: "1",
|
||||
presetIndex: row.presetIndex
|
||||
}).then((res: any) => {
|
||||
if (res.code === 200) {
|
||||
ElMessage.success('删除成功');
|
||||
busPresettingBitList();
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(() => { });
|
||||
}
|
||||
|
||||
// 调用
|
||||
function handleDebug(row: any) {
|
||||
callDevicePreset([{
|
||||
deviceSerial: row.deviceSerial,
|
||||
presetIndex: row.presetIndex,
|
||||
channelNo: "1",
|
||||
id: row.id
|
||||
}]).then((res: any) => {
|
||||
if (res.code === 200) {
|
||||
ElMessage.success('调用成功');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 修改
|
||||
function handleEdit(row: any) {
|
||||
const param = {
|
||||
id: row.id,
|
||||
deviceSerial: row.deviceSerial,
|
||||
presetName: row.presetName
|
||||
};
|
||||
updateDevicePreset(param)
|
||||
.then(() => {
|
||||
ElMessage.success('修改成功');
|
||||
busPresettingBitList();
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
// 重置表单
|
||||
function resetForm() {
|
||||
formData.value = {
|
||||
deviceSerial: undefined,
|
||||
channelNo: '1',
|
||||
presetName: undefined
|
||||
};
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
|
||||
if (flvPlayer.value) {
|
||||
flvPlayer.value.destroy().then((data: any) => {
|
||||
console.log('promise 获取 数据', data);
|
||||
});
|
||||
flvPlayer.value = null;
|
||||
}
|
||||
});
|
||||
|
||||
// ✅ 关键:暴露方法给父组件调用
|
||||
defineExpose({
|
||||
openDialog,
|
||||
closeDialog
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.system-busPresettingBit-add {
|
||||
.info_list {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
|
||||
.video_box {
|
||||
width: 75%;
|
||||
height: 600px;
|
||||
margin-right: 10px;
|
||||
|
||||
.iframe {
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.video_air {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: fill;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
374
src/views/camera/index.vue
Normal file
@ -0,0 +1,374 @@
|
||||
<template>
|
||||
<div class="system-ys7Devices-container">
|
||||
<el-card shadow="hover">
|
||||
<div class="system-ys7Devices-search mb8">
|
||||
<el-form :model="tableData.param" ref="queryRef" :inline="true" label-width="100px">
|
||||
<el-row>
|
||||
<el-col :span="8" class="colBlock">
|
||||
<el-form-item label="设备名称" prop="deviceName">
|
||||
<el-input v-model="tableData.param.deviceName" placeholder="请输入设备名称" clearable
|
||||
@keyup.enter.native="ys7DevicesList" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" class="colBlock">
|
||||
<el-form-item label="设备类型" prop="deviceType">
|
||||
<el-input v-model="tableData.param.deviceType" placeholder="请输入设备类型" clearable
|
||||
@keyup.enter.native="ys7DevicesList" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" :class="!showAll ? 'colBlock' : 'colNone'">
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="ys7DevicesList"><el-icon>
|
||||
<Search />
|
||||
</el-icon>搜索</el-button>
|
||||
<el-button @click="resetQuery(queryRef)"><el-icon>
|
||||
<Refresh />
|
||||
</el-icon>重置</el-button>
|
||||
<el-button type="primary" link @click="toggleSearch">
|
||||
{{ word }}
|
||||
<el-icon v-show="showAll">
|
||||
<ArrowUp />
|
||||
</el-icon>
|
||||
<el-icon v-show="!showAll">
|
||||
<ArrowDown />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" :class="showAll ? 'colBlock' : 'colNone'">
|
||||
<el-form-item label="设备序列号" prop="deviceSerial">
|
||||
<el-input v-model="tableData.param.deviceSerial" placeholder="请输入设备串号" clearable
|
||||
@keyup.enter.native="ys7DevicesList" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" :class="showAll ? 'colBlock' : 'colNone'">
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="tableData.param.status" placeholder="请选择设备状态" clearable>
|
||||
<el-option label="在线" :value="1" />
|
||||
<el-option label="离线" :value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" :class="showAll ? 'colBlock' : 'colNone'">
|
||||
<el-form-item label="设备版本" prop="deviceVersion">
|
||||
<el-input v-model="tableData.param.deviceVersion" placeholder="请输入设备版本" clearable
|
||||
@keyup.enter.native="ys7DevicesList" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" :class="showAll ? 'colBlock' : 'colNone'">
|
||||
<el-form-item label="所属项目" prop="projectId">
|
||||
<el-select v-model="tableData.param.projectId" placeholder="请选择所属项目" clearable
|
||||
filterable>
|
||||
<el-option v-for="item in projectList" class="device_row" :key="item.id"
|
||||
:label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" :class="showAll ? 'colBlock' : 'colNone'">
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="ys7DevicesList"><el-icon>
|
||||
<Search />
|
||||
</el-icon>搜索</el-button>
|
||||
<el-button @click="resetQuery(queryRef)"><el-icon>
|
||||
<Refresh />
|
||||
</el-icon>重置</el-button>
|
||||
<el-button type="primary" link @click="toggleSearch">
|
||||
{{ word }}
|
||||
<el-icon v-show="showAll">
|
||||
<ArrowUp />
|
||||
</el-icon>
|
||||
<el-icon v-show="!showAll">
|
||||
<ArrowDown />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<!-- <el-col :span="1.5">
|
||||
<el-button type="primary" @click="handleAdd" v-auth="'api/v1/system/ys7Devices/add'"
|
||||
><el-icon><Plus /></el-icon>新增</el-button
|
||||
>
|
||||
</el-col> -->
|
||||
<!-- <el-col :span="1.5">
|
||||
<el-button type="success" :disabled="single" @click="handleUpdate(null)"
|
||||
v-auth="'api/v1/system/ys7Devices/edit'"><el-icon>
|
||||
<Edit />
|
||||
</el-icon>修改</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" :disabled="multiple" @click="handleDelete(null)"
|
||||
v-auth="'api/v1/system/ys7Devices/delete'"><el-icon>
|
||||
<Delete />
|
||||
</el-icon>删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="warning" :disabled="multiple" @click="onLinkProject(null)"
|
||||
v-auth="'api/v1/system/ys7Devices/add'"><el-icon>
|
||||
<Link />
|
||||
</el-icon>设备分配</el-button>
|
||||
</el-col>-->
|
||||
</el-row>
|
||||
</div>
|
||||
<el-table v-loading="loading" :data="tableData.data" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="设备序列号" align="center" prop="deviceSerial" min-width="100px" />
|
||||
<el-table-column label="设备名称" align="center" prop="deviceName" min-width="100px" />
|
||||
<el-table-column label="设备类型" align="center" prop="deviceType" min-width="100px" />
|
||||
<el-table-column label="状态" align="center" prop="status" min-width="100px">
|
||||
<template #default="scope">
|
||||
<el-tag type="success" v-if="scope.row.status === 1">在线</el-tag>
|
||||
<el-tag type="danger" v-if="scope.row.status === 0">离线</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- <el-table-column label="视频加密" align="center" prop="videoEncrypted" min-width="100px">
|
||||
<template #default="scope">
|
||||
<el-switch v-model="scope.row.videoEncrypted" class="ml-2" :active-value="1" :inactive-value="0"
|
||||
:loading="scope.row.enctyptLoading" @change="encryptChange(scope.row)" inline-prompt
|
||||
active-text="开启" inactive-text="关闭"
|
||||
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949" />
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
<!-- <el-table-column label="" align="center" prop="defence" min-width="100px" /> -->
|
||||
<el-table-column label="设备版本" align="center" prop="deviceVersion" min-width="100px" />
|
||||
<!-- <el-table-column label="所属项目" align="center" prop="projectId" min-width="100px">
|
||||
<template #default="scope">
|
||||
{{ scope.row.projectName ? scope.row.projectName : '未分配' }}
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
<!-- <el-table-column label="备注" align="center" prop="remark" min-width="100px" /> -->
|
||||
<!-- <el-table-column label="创建时间" align="center" prop="deviceCreateTime" min-width="100px">
|
||||
<template #default="scope">
|
||||
<span>{{ proxy.parseTime(scope.row.deviceCreateTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
<el-table-column label="操作" align="center" class-name="small-padding" min-width="160px" fixed="right">
|
||||
<template #default="scope">
|
||||
<!-- <el-button type="primary" link @click="handleUpdate(scope.row)"
|
||||
v-auth="'api/v1/system/ys7Devices/edit'"><el-icon>
|
||||
<EditPen />
|
||||
</el-icon>修改</el-button>
|
||||
<el-button type="primary" link @click="handleDelete(scope.row)"
|
||||
v-auth="'api/v1/system/ys7Devices/delete'"><el-icon>
|
||||
<DeleteFilled />
|
||||
</el-icon>删除</el-button>
|
||||
<el-button type="primary" link @click="onLinkProject(scope.row)"
|
||||
v-auth="'api/v1/system/ys7Devices/delete'"><el-icon>
|
||||
<Link />
|
||||
</el-icon>设备分配</el-button> -->
|
||||
<el-button type="primary" link @click="addPreset(scope.row)"><el-icon>
|
||||
<Plus />
|
||||
</el-icon>添加预置位</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination v-show="tableData.total > 0" :total="tableData.total" v-model:page="tableData.param.pageNum"
|
||||
v-model:limit="tableData.param.pageSize" @pagination="ys7DevicesList" />
|
||||
</el-card>
|
||||
<presetAdd ref="presetAddRef"></presetAdd>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ElMessageBox, ElMessage, FormInstance } from 'element-plus';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { getMonitoringList } from '@/api/securitySurveillance/index.js';
|
||||
import presetAdd from './components/presetAdd.vue';
|
||||
// proxy 获取
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
// ref 定义
|
||||
const loading = ref(false);
|
||||
const queryRef = ref<FormInstance>();
|
||||
const addRef = ref();
|
||||
const editRef = ref();
|
||||
const detailRef = ref();
|
||||
const bindProRef = ref();
|
||||
const presetAddRef = ref();
|
||||
|
||||
// 展开/收起搜索项
|
||||
const showAll = ref(false);
|
||||
const word = computed(() => (showAll.value ? '收起搜索' : '展开搜索'));
|
||||
|
||||
// 多选控制
|
||||
const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const projects = computed(() => userStore.projects);
|
||||
|
||||
// 状态管理
|
||||
const state = reactive<any>({
|
||||
ids: [],
|
||||
serials: [],
|
||||
tableData: {
|
||||
data: [],
|
||||
total: 0,
|
||||
loading: false,
|
||||
param: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
id: undefined,
|
||||
createdAt: undefined,
|
||||
deviceSerial: undefined,
|
||||
deviceName: undefined,
|
||||
deviceType: undefined,
|
||||
status: undefined,
|
||||
defence: undefined,
|
||||
deviceVersion: undefined,
|
||||
projectId: currentProject.value?.id,
|
||||
dateRange: [],
|
||||
isFront: false
|
||||
}
|
||||
},
|
||||
projectList: projects.value
|
||||
});
|
||||
|
||||
// 初始化
|
||||
const initTableData = () => {
|
||||
ys7DevicesList();
|
||||
// sysProjectList();
|
||||
};
|
||||
|
||||
// 搜索重置
|
||||
const resetQuery = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.resetFields();
|
||||
ys7DevicesList();
|
||||
};
|
||||
|
||||
// 获取设备列表
|
||||
const ys7DevicesList = () => {
|
||||
loading.value = true;
|
||||
getMonitoringList({
|
||||
pageStart: state.tableData.param.pageNum,
|
||||
pageSize: state.tableData.param.pageSize,
|
||||
isflow: false
|
||||
}).then((res: any) => {
|
||||
let list = res.data.object ?? [];
|
||||
state.tableData.data = list.map((item) => {
|
||||
item.enctyptLoading = false;
|
||||
return item;
|
||||
});
|
||||
state.tableData.total = Number(res.data.sum);
|
||||
console.log(state.tableData);
|
||||
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
// 展开/收起搜索项
|
||||
const toggleSearch = () => {
|
||||
showAll.value = !showAll.value;
|
||||
};
|
||||
|
||||
// 多选事件
|
||||
const handleSelectionChange = (selection: any[]) => {
|
||||
state.ids = selection.map((item) => item.id);
|
||||
state.serials = selection.map((item) => item.deviceSerial);
|
||||
single.value = selection.length !== 1;
|
||||
multiple.value = !selection.length;
|
||||
};
|
||||
|
||||
// 新增
|
||||
// const handleAdd = () => {
|
||||
// addRef.value.openDialog();
|
||||
// };
|
||||
|
||||
// // 编辑
|
||||
// const handleUpdate = (row?: Ys7DeviceVO) => {
|
||||
// if (!row) {
|
||||
// row = state.tableData.data.find((item) => item.id === state.ids[0])!;
|
||||
// }
|
||||
// editRef.value.openDialog(toRaw(row));
|
||||
// };
|
||||
|
||||
// 删除
|
||||
// const handleDelete = (row?: any) => {
|
||||
// let msg = row ? `此操作将永久删除数据,是否继续?` : '你确定要删除所选数据?';
|
||||
// let id = row ? [row.id] : state.ids;
|
||||
|
||||
// if (id.length === 0) {
|
||||
// ElMessage.error('请选择要删除的数据。');
|
||||
// return;
|
||||
// }
|
||||
|
||||
// ElMessageBox.confirm(msg, '提示', {
|
||||
// confirmButtonText: '确认',
|
||||
// cancelButtonText: '取消',
|
||||
// type: 'warning'
|
||||
// })
|
||||
// .then(() => {
|
||||
// delYs7Device(id).then(() => {
|
||||
// ElMessage.success('删除成功');
|
||||
// ys7DevicesList();
|
||||
// });
|
||||
// })
|
||||
// .catch(() => { });
|
||||
// };
|
||||
|
||||
// 绑定项目
|
||||
// const onLinkProject = (row?: Ys7DeviceVO) => {
|
||||
// let serials = row ? [row.deviceSerial] : state.ids;
|
||||
|
||||
// if (serials.length === 0) {
|
||||
// ElMessage.error('请选择要绑定项目的设备');
|
||||
// return;
|
||||
// }
|
||||
// let info = { serials, row };
|
||||
// bindProRef.value.openDialog(toRaw(info));
|
||||
// };
|
||||
|
||||
// 添加预置位
|
||||
const addPreset = (row: any) => {
|
||||
presetAddRef.value.openDialog(row);
|
||||
};
|
||||
|
||||
// 开关加密
|
||||
// const encryptChange = (row: any) => {
|
||||
// row.enctyptLoading = true;
|
||||
// // const action = row.videoEncrypted === 0 ? 1 : 0;
|
||||
// console.log(row.videoEncrypted);
|
||||
|
||||
// toggleEncrypt({ videoEncrypted: row.videoEncrypted, id: row.id })
|
||||
// .then(() => {
|
||||
// proxy?.$modal.msgSuccess(row.videoEncrypted === 0 ? '关闭成功' : '开启成功');
|
||||
// })
|
||||
// .finally(() => {
|
||||
// row.enctyptLoading = false;
|
||||
// ys7DevicesList();
|
||||
// });
|
||||
// };
|
||||
|
||||
//监听项目id刷新数据
|
||||
// const listeningProject = watch(
|
||||
// () => currentProject.value?.id,
|
||||
// (nid, oid) => {
|
||||
// tableData.value.param.projectId = nid;
|
||||
// initTableData();
|
||||
// }
|
||||
// );
|
||||
|
||||
// 页面加载
|
||||
onMounted(() => {
|
||||
initTableData();
|
||||
});
|
||||
|
||||
// onUnmounted(() => {
|
||||
// listeningProject();
|
||||
// });
|
||||
|
||||
// 暴露变量
|
||||
const { tableData, projectList } = toRefs(state);
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.colBlock {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.colNone {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
185
src/views/integratedManage/alarmManage/components/fenxiBar.vue
Normal file
@ -0,0 +1,185 @@
|
||||
<template>
|
||||
<div class="chart-container">
|
||||
<!--组件温度(℃) 图表内容区域 -->
|
||||
<div ref="chartRef" class="chart-content"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, watch } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
|
||||
// 定义props类型
|
||||
interface TrendSeriesItem {
|
||||
name: string;
|
||||
data: number[];
|
||||
color: string;
|
||||
}
|
||||
|
||||
interface TrendData {
|
||||
dates: string[];
|
||||
series: TrendSeriesItem[];
|
||||
}
|
||||
|
||||
// 定义props
|
||||
const props = defineProps<{
|
||||
trendData: TrendData;
|
||||
}>();
|
||||
|
||||
// 图表DOM引用
|
||||
const chartRef = ref(null);
|
||||
// 图表实例
|
||||
let chartInstance = null;
|
||||
|
||||
// 初始化图表
|
||||
const initChart = () => {
|
||||
if (chartRef.value && !chartInstance) {
|
||||
chartInstance = echarts.init(chartRef.value);
|
||||
}
|
||||
const option = {
|
||||
xAxis: {
|
||||
type: "category",
|
||||
data: props.trendData.dates,
|
||||
axisTick: {
|
||||
show: false // 去除刻度线
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#f0f0f0',
|
||||
type: 'dashed'
|
||||
}
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
show: true,
|
||||
icon: 'square',
|
||||
left: '2%',
|
||||
itemWidth: 10,
|
||||
itemHeight: 10,
|
||||
itemAlign: 'middle', // 设置图例项垂直居中
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
series: props.trendData.series.map((item, index) => ({
|
||||
name: item.name,
|
||||
data: item.data,
|
||||
type: "bar",
|
||||
barWidth: '10%' ,
|
||||
itemStyle: {
|
||||
color: item.color,
|
||||
},
|
||||
})),
|
||||
};
|
||||
|
||||
chartInstance.setOption(option);
|
||||
};
|
||||
|
||||
// 响应窗口大小变化
|
||||
const handleResize = () => {
|
||||
if (chartInstance) {
|
||||
chartInstance.resize();
|
||||
}
|
||||
};
|
||||
|
||||
// 监听props变化
|
||||
watch(() => props.trendData, () => {
|
||||
if (chartInstance) {
|
||||
initChart();
|
||||
}
|
||||
}, { deep: true });
|
||||
|
||||
// 生命周期钩子
|
||||
onMounted(() => {
|
||||
initChart();
|
||||
window.addEventListener('resize', handleResize);
|
||||
|
||||
// 清理函数
|
||||
return () => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
if (chartInstance) {
|
||||
chartInstance.dispose();
|
||||
chartInstance = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.chart-container {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
height: 400px;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.chart-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15px 20px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.chart-header h2 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.chart-content {
|
||||
width: 100%;
|
||||
height: calc(100% - 54px);
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.chart-container {
|
||||
height: 350px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.chart-container {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.chart-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.chart-actions {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.chart-actions button {
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.chart-actions button:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.model {
|
||||
padding: 20px;
|
||||
background-color: rgba(242, 248, 252, 1);
|
||||
}
|
||||
</style>
|
||||
219
src/views/integratedManage/alarmManage/components/levelPie.vue
Normal file
@ -0,0 +1,219 @@
|
||||
<template>
|
||||
<div class="chart-container">
|
||||
<!--组件温度(℃) 图表内容区域 -->
|
||||
<div ref="chartRef" class="chart-content"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, watch } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
|
||||
// 定义props类型
|
||||
interface PieItem {
|
||||
value: number;
|
||||
name: string;
|
||||
displayName: string;
|
||||
color: string;
|
||||
}
|
||||
|
||||
interface PieData {
|
||||
normal: PieItem;
|
||||
interrupt: PieItem;
|
||||
abnormal: PieItem;
|
||||
serious: PieItem;
|
||||
}
|
||||
|
||||
// 定义props
|
||||
const props = defineProps<{
|
||||
pieData: PieData;
|
||||
}>();
|
||||
|
||||
// 图表DOM引用
|
||||
const chartRef = ref(null);
|
||||
// 图表实例
|
||||
let chartInstance = null;
|
||||
|
||||
// 初始化图表
|
||||
const initChart = () => {
|
||||
if (chartRef.value && !chartInstance) {
|
||||
chartInstance = echarts.init(chartRef.value);
|
||||
}
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: (params: any) => {
|
||||
return `${params.data.displayName}: ${params.value}`;
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '0%',
|
||||
right: '20%',
|
||||
bottom: '0%',
|
||||
top: '0%',
|
||||
containLabel: true
|
||||
},
|
||||
legend: {
|
||||
top: 'middle',
|
||||
orient: 'vertical',
|
||||
right: '5%', // 调整图例位置,使其更靠近左侧
|
||||
itemWidth: 15,
|
||||
itemHeight: 15,
|
||||
formatter: (name: string) => {
|
||||
const item = Object.values(props.pieData).find(item => item.name === name);
|
||||
return item?.displayName || name;
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: '80%',
|
||||
label: {
|
||||
show: false
|
||||
},
|
||||
color: [
|
||||
props.pieData.normal.color,
|
||||
props.pieData.interrupt.color,
|
||||
props.pieData.abnormal.color,
|
||||
props.pieData.serious.color
|
||||
],
|
||||
data: [
|
||||
{
|
||||
value: props.pieData.normal.value,
|
||||
name: props.pieData.normal.name,
|
||||
displayName: props.pieData.normal.displayName
|
||||
},
|
||||
{
|
||||
value: props.pieData.interrupt.value,
|
||||
name: props.pieData.interrupt.name,
|
||||
displayName: props.pieData.interrupt.displayName
|
||||
},
|
||||
{
|
||||
value: props.pieData.abnormal.value,
|
||||
name: props.pieData.abnormal.name,
|
||||
displayName: props.pieData.abnormal.displayName
|
||||
},
|
||||
{
|
||||
value: props.pieData.serious.value,
|
||||
name: props.pieData.serious.name,
|
||||
displayName: props.pieData.serious.displayName
|
||||
}
|
||||
],
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
chartInstance.setOption(option);
|
||||
};
|
||||
|
||||
// 响应窗口大小变化
|
||||
const handleResize = () => {
|
||||
if (chartInstance) {
|
||||
chartInstance.resize();
|
||||
}
|
||||
};
|
||||
|
||||
// 监听props变化
|
||||
watch(() => props.pieData, () => {
|
||||
if (chartInstance) {
|
||||
initChart();
|
||||
}
|
||||
}, { deep: true });
|
||||
|
||||
// 生命周期钩子
|
||||
onMounted(() => {
|
||||
initChart();
|
||||
window.addEventListener('resize', handleResize);
|
||||
|
||||
// 清理函数
|
||||
return () => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
if (chartInstance) {
|
||||
chartInstance.dispose();
|
||||
chartInstance = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.chart-container {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
height: 150px;
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.chart-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15px 20px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.chart-header h2 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.chart-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 5px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.chart-container {
|
||||
height: 350px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.chart-container {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.chart-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.chart-actions {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.chart-actions button {
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.chart-actions button:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.model {
|
||||
padding: 20px;
|
||||
background-color: rgba(242, 248, 252, 1);
|
||||
}
|
||||
</style>
|
||||
352
src/views/integratedManage/alarmManage/components/levelSet.vue
Normal file
@ -0,0 +1,352 @@
|
||||
<template>
|
||||
<el-table :data="localAlarmLevels" :border="false" style="width: 100%">
|
||||
<el-table-column prop="levelName" label="级别名称" align="center">
|
||||
<template #default="scope">
|
||||
<span :class="['level-name', `level-${scope.row.level}`]">{{ scope.row.levelName }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="description" label="标识含义" align="center"></el-table-column>
|
||||
<el-table-column prop="priority" label="优先级" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag :type="getPriorityType(scope.row.priority)">{{ scope.row.priority }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="responseTime" label="响应时间" align="center">
|
||||
<template #default="scope">
|
||||
<span style="color: #186DF5;">{{ scope.row.responseTime }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="processingMethod" label="处理方式" align="center">
|
||||
<template #default="scope">
|
||||
<div class="process-methods">
|
||||
<el-tag size="small" v-for="method in scope.row.processingMethod" :key="method" :type="getMethodType(method)">{{ method }}</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="enabled" label="是否启用" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<el-switch v-model="scope.row.enabled" active-color="#13ce66" inactive-color="#ff4949" @change="handleEnabledChange(scope.row)"></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="120" fixed="right" align="center">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" @click="handleConfig(scope.row)">配置</el-button>
|
||||
<el-button link type="danger" @click="handleDelete(scope.row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
|
||||
|
||||
<!-- 配置对话框 -->
|
||||
<el-dialog v-model="configDialogVisible" title="告警配置" width="600px">
|
||||
<div v-if="currentConfigData">
|
||||
<h3 class="config-title">{{ currentConfigData.levelName }} - 详细配置</h3>
|
||||
<el-form ref="configFormRef" :model="currentConfigData" label-width="120px">
|
||||
<el-form-item label="告警声音">
|
||||
<el-select v-model="currentConfigData.alarmSound" placeholder="请选择告警声音">
|
||||
<el-option label="默认声音" value="default" />
|
||||
<el-option label="紧急声音" value="urgent" />
|
||||
<el-option label="普通声音" value="normal" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="通知方式">
|
||||
<el-checkbox-group v-model="currentConfigData.notificationMethods">
|
||||
<el-checkbox label="短信" />
|
||||
<el-checkbox label="邮件" />
|
||||
<el-checkbox label="站内信" />
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="告警持续时间">
|
||||
<el-input-number v-model="currentConfigData.duration" :min="1" :max="60" label="分钟" />
|
||||
</el-form-item>
|
||||
<el-form-item label="自动处理">
|
||||
<el-switch v-model="currentConfigData.autoProcess" />
|
||||
</el-form-item>
|
||||
<el-form-item label="处理说明" v-if="currentConfigData.autoProcess">
|
||||
<el-input v-model="currentConfigData.processDescription" type="textarea" placeholder="请输入自动处理说明" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="configDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleConfigSave">保存配置</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
|
||||
// 定义告警等级类型
|
||||
interface AlarmLevel {
|
||||
id: number;
|
||||
levelName: string;
|
||||
description: string;
|
||||
priority: string;
|
||||
responseTime: string;
|
||||
processingMethod: string[];
|
||||
enabled: boolean;
|
||||
level: number; // 用于样式区分
|
||||
}
|
||||
|
||||
// 定义配置数据类型
|
||||
interface ConfigData extends AlarmLevel {
|
||||
alarmSound: string;
|
||||
notificationMethods: string[];
|
||||
duration: number;
|
||||
autoProcess: boolean;
|
||||
processDescription: string;
|
||||
}
|
||||
|
||||
// 定义props
|
||||
const props = defineProps<{
|
||||
alarmLevels: AlarmLevel[];
|
||||
}>();
|
||||
|
||||
// 本地数据副本
|
||||
const localAlarmLevels = ref<AlarmLevel[]>([]);
|
||||
|
||||
// 初始化本地数据
|
||||
watch(() => props.alarmLevels, (newVal) => {
|
||||
// 深拷贝以避免直接修改props
|
||||
localAlarmLevels.value = JSON.parse(JSON.stringify(newVal));
|
||||
}, { immediate: true, deep: true });
|
||||
|
||||
// 对话框相关状态
|
||||
const configDialogVisible = ref(false);
|
||||
const configFormRef = ref<any>();
|
||||
const currentConfigData = ref<ConfigData | null>(null);
|
||||
|
||||
// 获取优先级对应的标签类型
|
||||
const getPriorityType = (priority: string) => {
|
||||
const priorityMap: Record<string, string> = {
|
||||
'一级': 'danger',
|
||||
'二级': 'warning',
|
||||
'三级': 'success',
|
||||
'四级': 'primary'
|
||||
};
|
||||
return priorityMap[priority] || 'default';
|
||||
};
|
||||
|
||||
// 获取处理方式对应的标签类型
|
||||
const getMethodType = (method: string) => {
|
||||
const methodMap: Record<string, string> = {
|
||||
'系统锁定': 'danger',
|
||||
'声光报警': 'warning',
|
||||
'短信通知': 'primary',
|
||||
'邮件通知': 'info',
|
||||
'系统记录': 'success'
|
||||
};
|
||||
return methodMap[method] || 'info';
|
||||
};
|
||||
|
||||
// 处理启用状态变更
|
||||
const handleEnabledChange = (row: AlarmLevel) => {
|
||||
ElMessage.success(`${row.levelName} ${row.enabled ? '已启用' : '已禁用'}`);
|
||||
// 这里可以添加保存到后端的逻辑
|
||||
};
|
||||
|
||||
// 打开配置对话框
|
||||
const handleConfig = (row: AlarmLevel) => {
|
||||
// 构建配置数据
|
||||
currentConfigData.value = {
|
||||
...row,
|
||||
alarmSound: 'default',
|
||||
notificationMethods: ['短信'],
|
||||
duration: 30,
|
||||
autoProcess: false,
|
||||
processDescription: ''
|
||||
};
|
||||
configDialogVisible.value = true;
|
||||
};
|
||||
|
||||
// 保存配置
|
||||
const handleConfigSave = () => {
|
||||
if (currentConfigData.value) {
|
||||
// 找到对应的告警等级并更新
|
||||
const index = localAlarmLevels.value.findIndex(item => item.id === currentConfigData.value!.id);
|
||||
if (index !== -1) {
|
||||
localAlarmLevels.value[index] = {
|
||||
...localAlarmLevels.value[index],
|
||||
enabled: currentConfigData.value!.enabled
|
||||
};
|
||||
}
|
||||
ElMessage.success('配置保存成功');
|
||||
configDialogVisible.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 删除告警等级
|
||||
const handleDelete = (id: number) => {
|
||||
ElMessageBox.confirm('确定要删除该告警等级吗?', '确认删除', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
const index = localAlarmLevels.value.findIndex(item => item.id === id);
|
||||
if (index !== -1) {
|
||||
localAlarmLevels.value.splice(index, 1);
|
||||
ElMessage.success('删除成功');
|
||||
}
|
||||
}).catch(() => {
|
||||
// 用户取消删除
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.level-set-container {
|
||||
padding: 20px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.level-name {
|
||||
font-weight: 500;
|
||||
padding: 2px 6px 2px 18px;
|
||||
border-radius: 3px;
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.level-name::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 4px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.level-1::before {
|
||||
background-color: #ff4949;
|
||||
}
|
||||
|
||||
.level-2::before {
|
||||
background-color: #f7ba1e;
|
||||
}
|
||||
|
||||
.level-3::before {
|
||||
background-color: #13ce66;
|
||||
}
|
||||
|
||||
.level-4::before {
|
||||
background-color: #1890ff;
|
||||
}
|
||||
|
||||
.level-name:hover {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.level-1 {
|
||||
color: #ff4949;
|
||||
}
|
||||
|
||||
.level-2 {
|
||||
color: #f7ba1e;
|
||||
}
|
||||
|
||||
.level-3 {
|
||||
color: #13ce66;
|
||||
}
|
||||
|
||||
.level-4 {
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.process-methods {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
flex-wrap: wrap;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
/* 优化表格样式 */
|
||||
:deep(.el-table) {
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
:deep(.el-table th) {
|
||||
background-color: #fafafa;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
:deep(.el-table tr:hover > td) {
|
||||
background-color: #f0f9ff !important;
|
||||
}
|
||||
|
||||
:deep(.el-table__row:nth-child(even)) {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
/* 优化按钮和操作列 */
|
||||
:deep(.el-button--text) {
|
||||
transition: all 0.3s ease;
|
||||
padding: 4px 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
:deep(.el-button--text:hover) {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
/* 优化对话框样式 */
|
||||
.config-title {
|
||||
margin-bottom: 20px;
|
||||
color: #303133;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
/* 优化表单样式 */
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
:deep(.el-form-item__label) {
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
:deep(.el-select),
|
||||
:deep(.el-input),
|
||||
:deep(.el-input-number) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 响应式调整 */
|
||||
@media (max-width: 768px) {
|
||||
.level-set-container {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
:deep(.el-table) {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
339
src/views/integratedManage/alarmManage/components/totalView.vue
Normal file
@ -0,0 +1,339 @@
|
||||
<template>
|
||||
<div class="total-view-dashboard">
|
||||
<!-- 今日报警总数 -->
|
||||
<div class="total-view-card blue-border">
|
||||
<div class="total-content">
|
||||
<div class="content-row">
|
||||
<div class="left-section">
|
||||
<div class="total-header">
|
||||
<span class="total-title">今日报警总数</span>
|
||||
</div>
|
||||
<div class="total-number">{{ totalData.totalAlarm }}</div>
|
||||
</div>
|
||||
<div class="icon-section">
|
||||
<el-icon class="total-icon blue">
|
||||
<img src="@/assets/demo/health.png" alt="">
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="total-comparison">
|
||||
<el-icon class="trend-icon green">
|
||||
<img src="/src/assets/demo/up.png" alt="上升">
|
||||
</el-icon>
|
||||
<span class="comparison-text green">+{{ totalData.totalIncrease }}台</span>
|
||||
<span class="period-text">较上月同期</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 未处理报警 -->
|
||||
<div class="total-view-card purple-border">
|
||||
<div class="total-content">
|
||||
<div class="content-row">
|
||||
<div class="left-section">
|
||||
<div class="total-header">
|
||||
<span class="total-title">未处理报警</span>
|
||||
</div>
|
||||
<div class="total-number">{{ totalData.unprocessedAlarm }}</div>
|
||||
</div>
|
||||
<div class="icon-section">
|
||||
<el-icon class="total-icon purple">
|
||||
<img src="@/assets/demo/sms-tracking.png" alt="">
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="total-comparison">
|
||||
<el-icon class="trend-icon green">
|
||||
<img src="/src/assets/demo/up.png" alt="上升">
|
||||
</el-icon>
|
||||
<span class="comparison-text green">+{{ totalData.unprocessedIncrease }}台</span>
|
||||
<span class="period-text">较上月同期</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 已处理报警 -->
|
||||
<div class="total-view-card green-border">
|
||||
<div class="total-content">
|
||||
<div class="content-row">
|
||||
<div class="left-section">
|
||||
<div class="total-header">
|
||||
<span class="total-title">已处理报警</span>
|
||||
</div>
|
||||
<div class="total-number">{{ totalData.processedAlarm }}</div>
|
||||
</div>
|
||||
<div class="icon-section">
|
||||
<el-icon class="total-icon green">
|
||||
<img src="@/assets/demo/archive.png" alt="">
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="total-comparison">
|
||||
<el-icon class="trend-icon green">
|
||||
<img src="/src/assets/demo/up.png" alt="上升">
|
||||
</el-icon>
|
||||
<span class="comparison-text green">+{{ totalData.processedIncrease }}台</span>
|
||||
<span class="period-text">较上月同期</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 严重报警 -->
|
||||
<div class="total-view-card orange-border">
|
||||
<div class="total-content">
|
||||
<div class="content-row">
|
||||
<div class="left-section">
|
||||
<div class="total-header">
|
||||
<span class="total-title">严重报警</span>
|
||||
</div>
|
||||
<div class="total-number">{{ totalData.seriousAlarm }}</div>
|
||||
</div>
|
||||
<div class="icon-section">
|
||||
<el-icon class="total-icon orange">
|
||||
<img src="@/assets/demo/mouse-square.png" alt="">
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="total-comparison">
|
||||
<el-icon class="trend-icon green">
|
||||
<img src="/src/assets/demo/up.png" alt="上升">
|
||||
</el-icon>
|
||||
<span class="comparison-text green">+{{ totalData.seriousIncrease }}台</span>
|
||||
<span class="period-text">较上月同期</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineProps } from 'vue';
|
||||
|
||||
// 定义props类型
|
||||
interface TotalData {
|
||||
totalAlarm: number;
|
||||
unprocessedAlarm: number;
|
||||
processedAlarm: number;
|
||||
seriousAlarm: number;
|
||||
totalIncrease: number;
|
||||
unprocessedIncrease: number;
|
||||
processedIncrease: number;
|
||||
seriousIncrease: number;
|
||||
}
|
||||
|
||||
// 定义props
|
||||
const props = defineProps<{
|
||||
totalData: TotalData;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.total-view-dashboard {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
width: 100%;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.total-view-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20px 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
position: relative;
|
||||
flex: 1;
|
||||
min-width: 200px;
|
||||
height: 150px;
|
||||
transition: all 0.3s ease;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.total-view-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* 左侧边框样式 - 使用伪元素创建与指定内容高度一致的边框 */
|
||||
.total-view-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 42px;
|
||||
width: 4px;
|
||||
height: 45px;
|
||||
border-radius: 0 2px 2px 0;
|
||||
transition: height 0.3s ease;
|
||||
}
|
||||
|
||||
.total-view-card:hover::before {
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.blue-border::before {
|
||||
background-color: #0080FC;
|
||||
}
|
||||
|
||||
.blue-border {
|
||||
background-color: #EAF5FF;
|
||||
}
|
||||
|
||||
/* 添加卡片背景渐变效果 */
|
||||
.total-view-card::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.3) 100%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.purple-border::before {
|
||||
background-color: #722ed1;
|
||||
}
|
||||
|
||||
.purple-border {
|
||||
background-color: #F3EDFF;
|
||||
}
|
||||
|
||||
.green-border::before {
|
||||
background-color: #009B72;
|
||||
}
|
||||
|
||||
.green-border {
|
||||
background-color: #E8FFF9;
|
||||
}
|
||||
|
||||
.orange-border::before {
|
||||
background-color: #fa8c16;
|
||||
}
|
||||
|
||||
.orange-border {
|
||||
background-color: #FFF6EC;
|
||||
}
|
||||
|
||||
.total-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.content-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.left-section {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.icon-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.total-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.total-title {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.total-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.total-icon.blue {
|
||||
background-color: #DBEEFF;
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.total-icon.purple {
|
||||
background-color: #E9DEFF;
|
||||
color: #722ed1;
|
||||
}
|
||||
|
||||
.total-icon.green {
|
||||
background-color: #CEFFF2;
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.total-icon.orange {
|
||||
background-color: #FFEBD3;
|
||||
color: #fa8c16;
|
||||
}
|
||||
|
||||
.total-number {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.total-comparison {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.trend-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.trend-icon.green {
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.comparison-text {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.comparison-text.green {
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.period-text {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1200px) {
|
||||
.total-view-dashboard {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.total-view-card {
|
||||
flex: 0 0 calc(50% - 8px);
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.total-view-card {
|
||||
flex: 0 0 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
210
src/views/integratedManage/alarmManage/index.vue
Normal file
@ -0,0 +1,210 @@
|
||||
<template>
|
||||
<div class="model">
|
||||
<!-- 标题栏 -->
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<TitleComponent title="报警管理" subtitle="配置新能源厂站的报警级别、类型及相关规则" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 第一行:报警管理和报警级别分布 -->
|
||||
<el-row :gutter="20" class="content-row">
|
||||
<el-col :span="16">
|
||||
<el-card shadow="hover" class="custom-card">
|
||||
<TitleComponent title="报警管理" :font-level="2" />
|
||||
<totalView :totalData="totalData" />
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<!-- 报警级别分布 -->
|
||||
<el-card shadow="hover" class="custom-card">
|
||||
<TitleComponent title="报警级别分布" :font-level="2" />
|
||||
<levelPie :pieData="pieData" />
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 第二行:报警趋势分析 -->
|
||||
<el-row :gutter="20" class="content-row">
|
||||
<el-col :span="24">
|
||||
<el-card shadow="hover" class="custom-card">
|
||||
<TitleComponent title="报警趋势分析" :font-level="2" />
|
||||
<fenxiBar :trendData="trendData" />
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 第三行:报警级别设置 -->
|
||||
<el-row :gutter="20" class="content-row">
|
||||
<el-col :span="24">
|
||||
<el-card shadow="hover" class="custom-card">
|
||||
<TitleComponent title="报警级别设置" :font-level="2" />
|
||||
<levelSet :alarmLevels="alarmLevelsData" />
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import TitleComponent from '@/components/TitleComponent/index.vue';
|
||||
import levelPie from '@/views/integratedManage/alarmManage/components/levelPie.vue'
|
||||
import fenxiBar from '@/views/integratedManage/alarmManage/components/fenxiBar.vue'
|
||||
import totalView from '@/views/integratedManage/alarmManage/components/totalView.vue';
|
||||
import levelSet from '@/views/integratedManage/alarmManage/components/levelSet.vue';
|
||||
|
||||
// 模拟报警总数数据
|
||||
const totalData = ref({
|
||||
totalAlarm: 28,
|
||||
unprocessedAlarm: 8,
|
||||
processedAlarm: 20,
|
||||
seriousAlarm: 3,
|
||||
totalIncrease: 8,
|
||||
unprocessedIncrease: 3,
|
||||
processedIncrease: 5,
|
||||
seriousIncrease: 1
|
||||
});
|
||||
|
||||
// 模拟报警级别分布数据
|
||||
const pieData = ref({
|
||||
normal: {
|
||||
value: 1048,
|
||||
name: '提示信息',
|
||||
displayName: '提示信息',
|
||||
color: 'rgb(0, 179, 255)'
|
||||
},
|
||||
interrupt: {
|
||||
value: 735,
|
||||
name: '一般告警',
|
||||
displayName: '一般告警',
|
||||
color: 'rgb(45, 214, 131)'
|
||||
},
|
||||
abnormal: {
|
||||
value: 580,
|
||||
name: '重要告警',
|
||||
displayName: '重要告警',
|
||||
color: 'rgb(255, 208, 35)'
|
||||
},
|
||||
serious: {
|
||||
value: 484,
|
||||
name: '严重告警',
|
||||
displayName: '严重告警',
|
||||
color: 'rgb(227, 39, 39)'
|
||||
}
|
||||
});
|
||||
|
||||
// 模拟报警趋势数据
|
||||
const trendData = ref({
|
||||
dates: ['09-04', '09-05', '09-06', '09-07', '09-08', '09-09', '09-10'],
|
||||
series: [
|
||||
{
|
||||
name: '维护提醒',
|
||||
data: [120, 200, 150, 80, 70, 110, 130],
|
||||
color: 'rgb(0, 179, 255)'
|
||||
},
|
||||
{
|
||||
name: '数据异常',
|
||||
data: [80, 170, 100, 50, 90, 140, 170],
|
||||
color: 'rgb(22, 93, 255)'
|
||||
},
|
||||
{
|
||||
name: '信号减弱',
|
||||
data: [60, 140, 100, 120, 110, 100, 130],
|
||||
color: 'rgb(255, 153, 0)'
|
||||
},
|
||||
{
|
||||
name: '温度过高',
|
||||
data: [60, 140, 100, 120, 110, 100, 130],
|
||||
color: 'rgb(250, 220, 25)'
|
||||
},
|
||||
{
|
||||
name: '通讯中断',
|
||||
data: [60, 140, 100, 120, 110, 100, 130],
|
||||
color: 'rgb(251, 62, 122)'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// 模拟告警级别设置数据
|
||||
const alarmLevelsData = ref([
|
||||
{
|
||||
id: 1,
|
||||
levelName: '严重告警',
|
||||
description: '系统或应用出现严重故障',
|
||||
priority: '一级',
|
||||
responseTime: '15分钟以内',
|
||||
processingMethod: ['系统锁定', '声光报警', '短信通知'],
|
||||
enabled: true,
|
||||
level: 1
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
levelName: '重要告警',
|
||||
description: '系统或应用出现严重故障',
|
||||
priority: '二级',
|
||||
responseTime: '30分钟以内',
|
||||
processingMethod: ['声光报警', '短信通知', '系统记录'],
|
||||
enabled: true,
|
||||
level: 2
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
levelName: '一般告警',
|
||||
description: '非关键性故障或潜在风险',
|
||||
priority: '三级',
|
||||
responseTime: '120分钟以内',
|
||||
processingMethod: ['短信通知', '系统记录'],
|
||||
enabled: true,
|
||||
level: 3
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
levelName: '提示信息',
|
||||
description: '系统或应用非关键性变化或即将达到阈值的状态',
|
||||
priority: '四级',
|
||||
responseTime: '24小时以内',
|
||||
processingMethod: ['短信通知'],
|
||||
enabled: false,
|
||||
level: 4
|
||||
}
|
||||
]);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.model {
|
||||
padding: 20px 15px;
|
||||
background-color: rgba(242, 248, 252, 1);
|
||||
}
|
||||
|
||||
.content-row {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.custom-card {
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s ease;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.custom-card:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* 响应式布局调整 */
|
||||
@media (max-width: 1200px) {
|
||||
.content-row {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.model {
|
||||
padding: 15px 10px;
|
||||
}
|
||||
|
||||
.content-row {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,327 @@
|
||||
<template>
|
||||
<div class="chart-container">
|
||||
<!-- 图表标题和时间范围选择器 -->
|
||||
<div class="chart-header">
|
||||
<h2>出勤趋势分析</h2>
|
||||
<div class="chart-actions">
|
||||
<button @click="timeRange = 'week'" :class="{ active: timeRange === 'week' }">每周</button>
|
||||
<button @click="timeRange = 'month'" :class="{ active: timeRange === 'month' }">每月</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 图表内容区域 -->
|
||||
<div ref="chartRef" class="chart-content"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, computed, watch } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
|
||||
// 接收从父组件传入的数据
|
||||
const props = defineProps({
|
||||
attendData: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
week: {
|
||||
xAxis: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
|
||||
actualCount: [40, 20, 30, 15, 22, 63, 58],
|
||||
expectedCount: [100, 556, 413, 115, 510, 115, 317]
|
||||
},
|
||||
month: {
|
||||
xAxis: ['第1周', '第2周', '第3周', '第4周'],
|
||||
actualData: [280, 360, 320, 400],
|
||||
theoreticalData: [300, 400, 350, 450]
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
// 图表DOM引用
|
||||
const chartRef = ref(null);
|
||||
// 图表实例
|
||||
let chartInstance = null;
|
||||
|
||||
// 时间范围状态
|
||||
const timeRange = ref('week');
|
||||
|
||||
// 根据时间范围计算当前显示的数据
|
||||
const chartData = computed(() => {
|
||||
const dataForRange = props.attendData[timeRange.value] || props.attendData.week;
|
||||
|
||||
// 处理字段名称差异
|
||||
if (timeRange.value === 'week') {
|
||||
return {
|
||||
xAxis: dataForRange.xAxis || [],
|
||||
actualCount: dataForRange.actualCount || [],
|
||||
expectedCount: dataForRange.expectedCount || []
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
xAxis: dataForRange.xAxis || [],
|
||||
actualCount: dataForRange.actualData || [],
|
||||
expectedCount: dataForRange.theoreticalData || []
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// 定义颜色常量
|
||||
const ACTUAL_COUNT_COLOR = '#029CD4'; // 蓝色 - 实际人数
|
||||
const EXPECTED_COUNT_COLOR = '#0052D9'; // 蓝色 - 应出勤人数
|
||||
|
||||
// 初始化图表
|
||||
const initChart = () => {
|
||||
if (chartRef.value && !chartInstance) {
|
||||
chartInstance = echarts.init(chartRef.value);
|
||||
}
|
||||
|
||||
// 使用计算后的数据
|
||||
const { xAxis, actualCount, expectedCount } = chartData.value;
|
||||
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
backgroundColor: 'rgba(255,255,255,1)',
|
||||
borderColor: '#ddd',
|
||||
borderWidth: 1,
|
||||
textStyle: {
|
||||
color: '#333',
|
||||
fontSize: 14
|
||||
},
|
||||
formatter: function(params) {
|
||||
const actualCount = params[0].value;
|
||||
const expectedCount = params[1].value;
|
||||
return `
|
||||
<div style="padding: 5px;">
|
||||
<div style="color: ${params[0].color};">实际人数: ${actualCount}</div>
|
||||
<div style="color: ${params[1].color};">应出勤人数: ${expectedCount}</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
top: 30,
|
||||
left: 'center',
|
||||
itemWidth: 10,
|
||||
itemHeight: 10,
|
||||
itemGap: 25,
|
||||
data: ['实际人数', '应出勤人数'],
|
||||
textStyle: {
|
||||
color: '#666',
|
||||
fontSize: 12
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
top: '30%',
|
||||
right: '10%',
|
||||
bottom: '10%',
|
||||
left: '6%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
data: xAxis,
|
||||
type: 'category',
|
||||
boundaryGap: true,
|
||||
axisLabel: {
|
||||
textStyle: {
|
||||
color: '#666',
|
||||
fontSize: 12
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#ddd'
|
||||
}
|
||||
}
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '人数',
|
||||
nameTextStyle: {
|
||||
color: '#666',
|
||||
fontSize: 12
|
||||
},
|
||||
interval: 100,
|
||||
axisLabel: {
|
||||
textStyle: {
|
||||
color: '#666',
|
||||
fontSize: 12
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLine: {
|
||||
show: false
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#f0f0f0',
|
||||
type: 'dashed'
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '实际人数',
|
||||
type: 'bar',
|
||||
barWidth: '40%',
|
||||
itemStyle: {
|
||||
color: ACTUAL_COUNT_COLOR
|
||||
},
|
||||
data: actualCount
|
||||
},
|
||||
{
|
||||
name: '应出勤人数',
|
||||
type: 'line',
|
||||
showSymbol: false,
|
||||
symbol: 'circle',
|
||||
symbolSize: 6,
|
||||
emphasis: {
|
||||
showSymbol: true,
|
||||
symbolSize: 10
|
||||
},
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
color: EXPECTED_COUNT_COLOR
|
||||
},
|
||||
itemStyle: {
|
||||
color: EXPECTED_COUNT_COLOR,
|
||||
borderColor: '#fff',
|
||||
borderWidth: 2
|
||||
},
|
||||
data: expectedCount
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
chartInstance.setOption(option);
|
||||
};
|
||||
|
||||
// 响应窗口大小变化
|
||||
const handleResize = () => {
|
||||
if (chartInstance) {
|
||||
chartInstance.resize();
|
||||
}
|
||||
};
|
||||
|
||||
// 监听时间范围变化,更新图表
|
||||
watch(timeRange, () => {
|
||||
initChart();
|
||||
});
|
||||
|
||||
// 监听数据变化,更新图表
|
||||
watch(() => props.attendData, () => {
|
||||
initChart();
|
||||
}, { deep: true });
|
||||
|
||||
// 生命周期钩子
|
||||
onMounted(() => {
|
||||
initChart();
|
||||
window.addEventListener('resize', handleResize);
|
||||
|
||||
// 清理函数
|
||||
return () => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
if (chartInstance) {
|
||||
chartInstance.dispose();
|
||||
chartInstance = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.chart-container {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
height: 435px;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.chart-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15px 20px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.chart-header h2 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.chart-actions button {
|
||||
background: none;
|
||||
border: 1px solid #e0e0e0;
|
||||
padding: 5px 12px;
|
||||
border-radius: 4px;
|
||||
margin-left: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.chart-actions button.active {
|
||||
background-color: #1890ff;
|
||||
color: white;
|
||||
border-color: #1890ff;
|
||||
}
|
||||
|
||||
.chart-content {
|
||||
width: 100%;
|
||||
height: calc(100% - 54px);
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.chart-container {
|
||||
height: 435px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.chart-container {
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.chart-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.chart-actions {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.chart-actions button {
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.chart-actions button:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.model {
|
||||
padding: 20px;
|
||||
background-color: rgba(242, 248, 252, 1);
|
||||
}
|
||||
</style>
|
||||