feat: 优化模板代码,增加服务端模板
This commit is contained in:
+1
-1
@@ -21,4 +21,4 @@ dist-ssr
|
|||||||
*.ntvs*
|
*.ntvs*
|
||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
Vendored
+2
@@ -23,6 +23,8 @@ declare module '@vue/runtime-core' {
|
|||||||
ElLink: typeof import('element-plus/es')['ElLink']
|
ElLink: typeof import('element-plus/es')['ElLink']
|
||||||
ElMenu: typeof import('element-plus/es')['ElMenu']
|
ElMenu: typeof import('element-plus/es')['ElMenu']
|
||||||
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
|
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
|
||||||
|
ElRadio: typeof import('element-plus/es')['ElRadio']
|
||||||
|
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
||||||
ElRow: typeof import('element-plus/es')['ElRow']
|
ElRow: typeof import('element-plus/es')['ElRow']
|
||||||
ElTag: typeof import('element-plus/es')['ElTag']
|
ElTag: typeof import('element-plus/es')['ElTag']
|
||||||
ImgPreview: typeof import('./src/components/ImgPreview.vue')['default']
|
ImgPreview: typeof import('./src/components/ImgPreview.vue')['default']
|
||||||
|
|||||||
+2
-1
@@ -18,7 +18,8 @@
|
|||||||
"dayjs": "^1.10.7",
|
"dayjs": "^1.10.7",
|
||||||
"element-plus": "2.1.10",
|
"element-plus": "2.1.10",
|
||||||
"funjialib": "git+http://git.funjia.top/funjia/FunJiaLib_Package.git",
|
"funjialib": "git+http://git.funjia.top/funjia/FunJiaLib_Package.git",
|
||||||
"funjiaui": "git+http://git.funjia.top/funjia/FunjiaUI_Vue.git#v1.1.2",
|
"funjiaui": "git+http://git.funjia.top/funjia/FunjiaUI_Vue.git#v1.1.2",
|
||||||
|
"funjia-axios": "git+http://git.funjia.top/funjia/funjia-axios.git",
|
||||||
"html-print-element": "^0.0.5",
|
"html-print-element": "^0.0.5",
|
||||||
"html2pdf.js": "^0.10.2",
|
"html2pdf.js": "^0.10.2",
|
||||||
"js-cookie": "^3.0.1",
|
"js-cookie": "^3.0.1",
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 7.0 KiB |
@@ -0,0 +1,2 @@
|
|||||||
|
static/*
|
||||||
|
config.yml
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
db: # 数据库配置
|
||||||
|
db: &db E:\sourceCode\2025\funjia-admin-template-vue\server\db\db.json
|
||||||
|
resourceDB: &resourceDB E:\sourceCode\2025\funjia-admin-template-vue\server\db\resourceDB.json
|
||||||
|
backupDB: &backupDB E:\sourceCode\2025\funjia-admin-template-vue\server\db\backupDB.json
|
||||||
|
logDB: &logDB E:\sourceCode\2025\funjia-admin-template-vue\server\db\logDB.json
|
||||||
|
dbBak: # 数据库备份配置
|
||||||
|
- #
|
||||||
|
original: *db
|
||||||
|
dest: F:/sourceCode/2022/compute-cms/bak/db
|
||||||
|
category: db
|
||||||
|
- #
|
||||||
|
original: *resourceDB
|
||||||
|
dest: F:/sourceCode/2022/compute-cms/bak/resourceDB
|
||||||
|
category: resourceDB
|
||||||
|
- #
|
||||||
|
original: *backupDB
|
||||||
|
dest: F:/sourceCode/2022/compute-cms/bak/backupDB
|
||||||
|
category: backupDB
|
||||||
|
- #
|
||||||
|
original: *logDB
|
||||||
|
dest: F:/sourceCode/2022/compute-cms/bak/logDB
|
||||||
|
category: logDB
|
||||||
@@ -0,0 +1,346 @@
|
|||||||
|
{
|
||||||
|
"backupHistory": [
|
||||||
|
{
|
||||||
|
"name": "db20220701112510.json",
|
||||||
|
"category": "db",
|
||||||
|
"id": "cl51w799y00003cny7rm01lx4",
|
||||||
|
"createTime": "2022-07-01T03:25:10.198Z",
|
||||||
|
"status": "1,2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "resourceDB20220701112510.json",
|
||||||
|
"category": "resourceDB",
|
||||||
|
"id": "cl51w79f900033cnyd44c044t",
|
||||||
|
"createTime": "2022-07-01T03:25:10.389Z",
|
||||||
|
"status": "1,2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "backupDB20220701112510.json",
|
||||||
|
"category": "backupDB",
|
||||||
|
"id": "cl51w79ia00063cny0hty82gs",
|
||||||
|
"createTime": "2022-07-01T03:25:10.499Z",
|
||||||
|
"status": "1,2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "logDB20220701112510.json",
|
||||||
|
"category": "logDB",
|
||||||
|
"id": "cl51w79lc00093cny9oiz4tlh",
|
||||||
|
"createTime": "2022-07-01T03:25:10.608Z",
|
||||||
|
"status": "1,2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "db20220701112520.json",
|
||||||
|
"category": "db",
|
||||||
|
"id": "cl51w7h1n000c3cnyhpfjbrpj",
|
||||||
|
"createTime": "2022-07-01T03:25:20.267Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "resourceDB20220701112520.json",
|
||||||
|
"category": "resourceDB",
|
||||||
|
"id": "cl51w7h4o000f3cnybldh5115",
|
||||||
|
"createTime": "2022-07-01T03:25:20.376Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "backupDB20220701112520.json",
|
||||||
|
"category": "backupDB",
|
||||||
|
"id": "cl51w7h7w000i3cnyafqk3p1o",
|
||||||
|
"createTime": "2022-07-01T03:25:20.492Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "logDB20220701112520.json",
|
||||||
|
"category": "logDB",
|
||||||
|
"id": "cl51w7haw000l3cny4nv48t44",
|
||||||
|
"createTime": "2022-07-01T03:25:20.600Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "db20220701112530.json",
|
||||||
|
"category": "db",
|
||||||
|
"id": "cl51w7oty000o3cny5v281zy3",
|
||||||
|
"createTime": "2022-07-01T03:25:30.358Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "resourceDB20220701112530.json",
|
||||||
|
"category": "resourceDB",
|
||||||
|
"id": "cl51w7owz000r3cnybuil0qm8",
|
||||||
|
"createTime": "2022-07-01T03:25:30.467Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "backupDB20220701112530.json",
|
||||||
|
"category": "backupDB",
|
||||||
|
"id": "cl51w7p0e000u3cnyg8r9by1q",
|
||||||
|
"createTime": "2022-07-01T03:25:30.590Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "logDB20220701112530.json",
|
||||||
|
"category": "logDB",
|
||||||
|
"id": "cl51w7p37000x3cny9be2eh4h",
|
||||||
|
"createTime": "2022-07-01T03:25:30.691Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "db20220701112540.json",
|
||||||
|
"category": "db",
|
||||||
|
"id": "cl51w7wlu00103cny65nw72bm",
|
||||||
|
"createTime": "2022-07-01T03:25:40.434Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "resourceDB20220701112540.json",
|
||||||
|
"category": "resourceDB",
|
||||||
|
"id": "cl51w7wom00133cnyg0nqc9w3",
|
||||||
|
"createTime": "2022-07-01T03:25:40.534Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "backupDB20220701112540.json",
|
||||||
|
"category": "backupDB",
|
||||||
|
"id": "cl51w7wrd00163cnydmnjcgw7",
|
||||||
|
"createTime": "2022-07-01T03:25:40.633Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "logDB20220701112540.json",
|
||||||
|
"category": "logDB",
|
||||||
|
"id": "cl51w7wuk00193cny8hwlcc89",
|
||||||
|
"createTime": "2022-07-01T03:25:40.748Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "db20220701112550.json",
|
||||||
|
"category": "db",
|
||||||
|
"id": "cl51w84dz001c3cnygo6oeal7",
|
||||||
|
"createTime": "2022-07-01T03:25:50.519Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "resourceDB20220701112550.json",
|
||||||
|
"category": "resourceDB",
|
||||||
|
"id": "cl51w84h0001f3cnyfahs5q4c",
|
||||||
|
"createTime": "2022-07-01T03:25:50.628Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "backupDB20220701112550.json",
|
||||||
|
"category": "backupDB",
|
||||||
|
"id": "cl51w84jm001i3cny2tpqcjjp",
|
||||||
|
"createTime": "2022-07-01T03:25:50.722Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "logDB20220701112550.json",
|
||||||
|
"category": "logDB",
|
||||||
|
"id": "cl51w84ml001l3cnygzl3hjod",
|
||||||
|
"createTime": "2022-07-01T03:25:50.829Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "db20220701112600.json",
|
||||||
|
"category": "db",
|
||||||
|
"id": "cl51w8c63001o3cnyfevk3kyp",
|
||||||
|
"createTime": "2022-07-01T03:26:00.603Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "resourceDB20220701112600.json",
|
||||||
|
"category": "resourceDB",
|
||||||
|
"id": "cl51w8c8m001r3cny9zryh2pe",
|
||||||
|
"createTime": "2022-07-01T03:26:00.694Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "backupDB20220701112600.json",
|
||||||
|
"category": "backupDB",
|
||||||
|
"id": "cl51w8cbo001u3cnya2bw2bsi",
|
||||||
|
"createTime": "2022-07-01T03:26:00.804Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "logDB20220701112600.json",
|
||||||
|
"category": "logDB",
|
||||||
|
"id": "cl51w8ce8001x3cny1cltcbdh",
|
||||||
|
"createTime": "2022-07-01T03:26:00.896Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "db20220701112610.json",
|
||||||
|
"category": "db",
|
||||||
|
"id": "cl51w8jxq00203cny392bhx57",
|
||||||
|
"createTime": "2022-07-01T03:26:10.670Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "resourceDB20220701112610.json",
|
||||||
|
"category": "resourceDB",
|
||||||
|
"id": "cl51w8k0n00233cny37f0cx5j",
|
||||||
|
"createTime": "2022-07-01T03:26:10.775Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "backupDB20220701112610.json",
|
||||||
|
"category": "backupDB",
|
||||||
|
"id": "cl51w8k3h00263cnydfiu8inf",
|
||||||
|
"createTime": "2022-07-01T03:26:10.877Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "logDB20220701112610.json",
|
||||||
|
"category": "logDB",
|
||||||
|
"id": "cl51w8k6n00293cny0j395r0p",
|
||||||
|
"createTime": "2022-07-01T03:26:10.991Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "db20220701112620.json",
|
||||||
|
"category": "db",
|
||||||
|
"id": "cl51w8rq0002c3cny2tih0ehp",
|
||||||
|
"createTime": "2022-07-01T03:26:20.760Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "resourceDB20220701112620.json",
|
||||||
|
"category": "resourceDB",
|
||||||
|
"id": "cl51w8rv2002f3cnyddcya1y9",
|
||||||
|
"createTime": "2022-07-01T03:26:20.942Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "backupDB20220701112621.json",
|
||||||
|
"category": "backupDB",
|
||||||
|
"id": "cl51w8rz2002i3cnyhsiihd6x",
|
||||||
|
"createTime": "2022-07-01T03:26:21.086Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "logDB20220701112621.json",
|
||||||
|
"category": "logDB",
|
||||||
|
"id": "cl51w8s5u002l3cny2o7m161c",
|
||||||
|
"createTime": "2022-07-01T03:26:21.330Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "F:\\sourceCode\\2022\\compute-cms\\db20220703182610.json",
|
||||||
|
"category": "db",
|
||||||
|
"id": "cl5564dxd0000sonyakfraso1",
|
||||||
|
"createTime": "2022-07-03T10:26:10.945Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "db20220703182700.json",
|
||||||
|
"category": "db",
|
||||||
|
"id": "cl5565fxt0000s0ny94tvajvl",
|
||||||
|
"createTime": "2022-07-03T10:27:00.209Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "resourceDB20220703182700.json",
|
||||||
|
"category": "resourceDB",
|
||||||
|
"id": "cl5565g3o0003s0nyhl4m51nu",
|
||||||
|
"createTime": "2022-07-03T10:27:00.420Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "backupDB20220703182700.json",
|
||||||
|
"category": "backupDB",
|
||||||
|
"id": "cl5565g7t0006s0ny2juo1ve3",
|
||||||
|
"createTime": "2022-07-03T10:27:00.570Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "logDB20220703182700.json",
|
||||||
|
"category": "logDB",
|
||||||
|
"id": "cl5565gas0009s0nyfyi71i0a",
|
||||||
|
"createTime": "2022-07-03T10:27:00.676Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "db20220703182710.json",
|
||||||
|
"category": "db",
|
||||||
|
"id": "cl5565npe000cs0ny4jmk13uj",
|
||||||
|
"createTime": "2022-07-03T10:27:10.274Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "resourceDB20220703182710.json",
|
||||||
|
"category": "resourceDB",
|
||||||
|
"id": "cl5565num000fs0nyfuynhsvn",
|
||||||
|
"createTime": "2022-07-03T10:27:10.462Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "backupDB20220703182710.json",
|
||||||
|
"category": "backupDB",
|
||||||
|
"id": "cl5565nxt000is0nyfaw54i99",
|
||||||
|
"createTime": "2022-07-03T10:27:10.578Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "logDB20220703182710.json",
|
||||||
|
"category": "logDB",
|
||||||
|
"id": "cl5565o0q000ls0ny49na7htm",
|
||||||
|
"createTime": "2022-07-03T10:27:10.682Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "db20220703182720.json",
|
||||||
|
"category": "db",
|
||||||
|
"id": "cl5565vh5000os0ny8q5l2dhe",
|
||||||
|
"createTime": "2022-07-03T10:27:20.346Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "resourceDB20220703182720.json",
|
||||||
|
"category": "resourceDB",
|
||||||
|
"id": "cl5565vlh000rs0ny6nvm1t28",
|
||||||
|
"createTime": "2022-07-03T10:27:20.501Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "backupDB20220703182720.json",
|
||||||
|
"category": "backupDB",
|
||||||
|
"id": "cl5565vpg000us0nyhchjafdx",
|
||||||
|
"createTime": "2022-07-03T10:27:20.644Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "logDB20220703182720.json",
|
||||||
|
"category": "logDB",
|
||||||
|
"id": "cl5565vs9000xs0nybt568rnh",
|
||||||
|
"createTime": "2022-07-03T10:27:20.745Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "db20220703182730.json",
|
||||||
|
"category": "db",
|
||||||
|
"id": "cl556638l0010s0ny42h7beca",
|
||||||
|
"createTime": "2022-07-03T10:27:30.405Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "resourceDB20220703182730.json",
|
||||||
|
"category": "resourceDB",
|
||||||
|
"id": "cl55663c00013s0nyefkb8ozn",
|
||||||
|
"createTime": "2022-07-03T10:27:30.528Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "backupDB20220703182730.json",
|
||||||
|
"category": "backupDB",
|
||||||
|
"id": "cl55663f50016s0nyhmal0v7o",
|
||||||
|
"createTime": "2022-07-03T10:27:30.641Z",
|
||||||
|
"status": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "logDB20220703182730.json",
|
||||||
|
"category": "logDB",
|
||||||
|
"id": "cl55663i50019s0nydmqjhwqr",
|
||||||
|
"createTime": "2022-07-03T10:27:30.749Z",
|
||||||
|
"status": "1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
+21146
File diff suppressed because one or more lines are too long
+72195
File diff suppressed because one or more lines are too long
@@ -0,0 +1,190 @@
|
|||||||
|
{
|
||||||
|
"img": [
|
||||||
|
{
|
||||||
|
"id": "cl4u5pghi0001wgny53o32aq4",
|
||||||
|
"filename": "cl4u5pgh40000wgnya0lp59uc.jpg",
|
||||||
|
"path": "static\\cl4u5pgh40000wgnya0lp59uc.jpg",
|
||||||
|
"createTime": "2022-06-25T17:29:06.486Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4u68rlb0001qcnygmv39izm",
|
||||||
|
"filename": "cl4u68rl60000qcny6npk19d3.jpg",
|
||||||
|
"path": "static\\cl4u68rl60000qcny6npk19d3.jpg",
|
||||||
|
"createTime": "2022-06-25T17:44:07.343Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4u692vx0003qcnyaiip9dnn",
|
||||||
|
"filename": "cl4u692vq0002qcny9bmj3q30.jpg",
|
||||||
|
"path": "static\\cl4u692vq0002qcny9bmj3q30.jpg",
|
||||||
|
"createTime": "2022-06-25T17:44:21.981Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4u6agif0005qcny0kd1659n",
|
||||||
|
"filename": "cl4u6agib0004qcnyexnb9xzz.jpg",
|
||||||
|
"path": "static\\cl4u6agib0004qcnyexnb9xzz.jpg",
|
||||||
|
"createTime": "2022-06-25T17:45:26.295Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4u6ls550001ucnyhy6ghpwy",
|
||||||
|
"filename": "cl4u6ls4r0000ucny86k414pr.jpg",
|
||||||
|
"path": "static\\cl4u6ls4r0000ucny86k414pr.jpg",
|
||||||
|
"createTime": "2022-06-25T17:54:14.585Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4u6mmog0003ucnyato6b8qd",
|
||||||
|
"filename": "cl4u6mmoc0002ucny0eaa8t7f.jpg",
|
||||||
|
"path": "static\\cl4u6mmoc0002ucny0eaa8t7f.jpg",
|
||||||
|
"createTime": "2022-06-25T17:54:54.160Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4u7huus0001x4nyalm386vp",
|
||||||
|
"filename": "cl4u7huui0000x4ny1rd095z4.jpg",
|
||||||
|
"path": "static\\cl4u7huui0000x4ny1rd095z4.jpg",
|
||||||
|
"createTime": "2022-06-25T18:19:11.092Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4u7jyqy0003x4nyaa2mhk1a",
|
||||||
|
"filename": "cl4u7jyqv0002x4ny27cb0zyt.jpg",
|
||||||
|
"path": "static\\cl4u7jyqv0002x4ny27cb0zyt.jpg",
|
||||||
|
"createTime": "2022-06-25T18:20:49.450Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4uycgv80005x4nycnn4ahui",
|
||||||
|
"filename": "cl4uycgv30004x4ny4k9a0987.jpg",
|
||||||
|
"path": "static\\cl4uycgv30004x4ny4k9a0987.jpg",
|
||||||
|
"createTime": "2022-06-26T06:50:49.316Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4v0kl5h000rx4nydmi0gnhl",
|
||||||
|
"filename": "cl4v0kl59000qx4ny0xsx9j2n.jpg",
|
||||||
|
"path": "static\\cl4v0kl59000qx4ny0xsx9j2n.jpg",
|
||||||
|
"createTime": "2022-06-26T07:53:07.349Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4v0lgm3000tx4ny7i4xdeq4",
|
||||||
|
"filename": "cl4v0lglz000sx4ny17in7q6a.jpg",
|
||||||
|
"path": "static\\cl4v0lglz000sx4ny17in7q6a.jpg",
|
||||||
|
"createTime": "2022-06-26T07:53:48.123Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4v0m2wm000vx4nye3kl2794",
|
||||||
|
"filename": "cl4v0m2wi000ux4nyhb7xaykl.jpg",
|
||||||
|
"path": "static\\cl4v0m2wi000ux4nyhb7xaykl.jpg",
|
||||||
|
"createTime": "2022-06-26T07:54:17.014Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4v0mdjv000xx4nycqqngyjr",
|
||||||
|
"filename": "cl4v0mdjl000wx4ny6d4acii7.jpg",
|
||||||
|
"path": "static\\cl4v0mdjl000wx4ny6d4acii7.jpg",
|
||||||
|
"createTime": "2022-06-26T07:54:30.811Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4v0mzlq000zx4ny37649xm3",
|
||||||
|
"filename": "cl4v0mzlm000yx4nyhjcwdmwb.jpg",
|
||||||
|
"path": "static\\cl4v0mzlm000yx4nyhjcwdmwb.jpg",
|
||||||
|
"createTime": "2022-06-26T07:54:59.390Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4v0nf8t0011x4ny3vgb0njg",
|
||||||
|
"filename": "cl4v0nf8p0010x4ny1q8o96bb.jpg",
|
||||||
|
"path": "static\\cl4v0nf8p0010x4ny1q8o96bb.jpg",
|
||||||
|
"createTime": "2022-06-26T07:55:19.661Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4v0q7mv0013x4nybkoy3z9b",
|
||||||
|
"filename": "cl4v0q7ms0012x4ny29i1hy0d.jpg",
|
||||||
|
"path": "static\\cl4v0q7ms0012x4ny29i1hy0d.jpg",
|
||||||
|
"createTime": "2022-06-26T07:57:29.767Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4v0qaxk0015x4nyc61xhnsk",
|
||||||
|
"filename": "cl4v0qaxi0014x4nyd02n1y0s.jpg",
|
||||||
|
"path": "static\\cl4v0qaxi0014x4nyd02n1y0s.jpg",
|
||||||
|
"createTime": "2022-06-26T07:57:34.040Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4v0qrtf0017x4ny1y0t0wam",
|
||||||
|
"filename": "cl4v0qrtc0016x4ny1bxh12e8.jpg",
|
||||||
|
"path": "static\\cl4v0qrtc0016x4ny1bxh12e8.jpg",
|
||||||
|
"createTime": "2022-06-26T07:57:55.923Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4v0s7m10019x4ny5zta50b4",
|
||||||
|
"filename": "cl4v0s7lv0018x4nybu4u9qrp.jpg",
|
||||||
|
"path": "static\\cl4v0s7lv0018x4nybu4u9qrp.jpg",
|
||||||
|
"createTime": "2022-06-26T07:59:03.049Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4v0uvxk001bx4ny2qe0c22r",
|
||||||
|
"filename": "cl4v0uvxi001ax4ny0itgd8j9.jpg",
|
||||||
|
"path": "static\\cl4v0uvxi001ax4ny0itgd8j9.jpg",
|
||||||
|
"createTime": "2022-06-26T08:01:07.880Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4v18kp9001dx4nya6yhb8yy",
|
||||||
|
"filename": "cl4v18kp6001cx4nyg3xoh7kn.jpg",
|
||||||
|
"path": "static\\cl4v18kp6001cx4nyg3xoh7kn.jpg",
|
||||||
|
"createTime": "2022-06-26T08:11:46.509Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4v18mxi001fx4nyc6h2fozb",
|
||||||
|
"filename": "cl4v18mxe001ex4ny8147ehkt.jpg",
|
||||||
|
"path": "static\\cl4v18mxe001ex4ny8147ehkt.jpg",
|
||||||
|
"createTime": "2022-06-26T08:11:49.398Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4v18pi9001hx4ny7idea4m5",
|
||||||
|
"filename": "cl4v18pi3001gx4nyazt40dus.jpg",
|
||||||
|
"path": "static\\cl4v18pi3001gx4nyazt40dus.jpg",
|
||||||
|
"createTime": "2022-06-26T08:11:52.737Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4wq1ywm0001a0ny38cmcwa2",
|
||||||
|
"filename": "cl4wq1ywc0000a0ny2y25e0fa.jpg",
|
||||||
|
"path": "static\\cl4wq1ywc0000a0ny2y25e0fa.jpg",
|
||||||
|
"createTime": "2022-06-27T12:34:14.902Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4wq21w30003a0ny9xpd62rv",
|
||||||
|
"filename": "cl4wq21vu0002a0ny07359nx6.jpg",
|
||||||
|
"path": "static\\cl4wq21vu0002a0ny07359nx6.jpg",
|
||||||
|
"createTime": "2022-06-27T12:34:18.771Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl4wq28rv0005a0nycf7k2a34",
|
||||||
|
"filename": "cl4wq28rt0004a0ny5nj4gbe2.jpg",
|
||||||
|
"path": "static\\cl4wq28rt0004a0ny5nj4gbe2.jpg",
|
||||||
|
"createTime": "2022-06-27T12:34:27.691Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl550ghgz0009lsnycaace5r1",
|
||||||
|
"filename": "cl550ghgt0008lsnyc7jl7rhw.jpg",
|
||||||
|
"path": "static\\cl550ghgt0008lsnyc7jl7rhw.jpg",
|
||||||
|
"createTime": "2022-07-03T07:47:37.715Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl550gk3n000blsnybbxz3rru",
|
||||||
|
"filename": "cl550gk3e000alsnyafhcc8b2.jpg",
|
||||||
|
"path": "static\\cl550gk3e000alsnyafhcc8b2.jpg",
|
||||||
|
"createTime": "2022-07-03T07:47:41.123Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cl550gmhr000dlsny9oxxex2y",
|
||||||
|
"filename": "cl550gmhf000clsny2c4h5a33.jpg",
|
||||||
|
"path": "static\\cl550gmhf000clsny2c4h5a33.jpg",
|
||||||
|
"createTime": "2022-07-03T07:47:44.223Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "clzwtwwmp00029grb63lr3hcq",
|
||||||
|
"filename": "clzwtwwml00019grbfbsf6r72.viminfo",
|
||||||
|
"path": "static\\clzwtwwml00019grbfbsf6r72.viminfo",
|
||||||
|
"createTime": "2024-08-16T14:53:09.553Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "clzwuyxln00049grb4ng91xik",
|
||||||
|
"filename": "clzwuyxlf00039grb80upct14.yarnrc",
|
||||||
|
"path": "static\\clzwuyxlf00039grb80upct14.yarnrc",
|
||||||
|
"createTime": "2024-08-16T15:22:43.739Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
import { CreateServer } from "funjia-server";
|
||||||
|
const app = await CreateServer(4873);
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"name": "server",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@koa/multer": "^3.0.0",
|
||||||
|
"@types/yaml": "^1.9.7",
|
||||||
|
"cuid": "^2.1.8",
|
||||||
|
"dayjs": "^1.11.3",
|
||||||
|
"koa": "^2.13.4",
|
||||||
|
"koa-body": "^4.2.0",
|
||||||
|
"koa-mount": "^4.0.0",
|
||||||
|
"koa-router": "^10.1.1",
|
||||||
|
"koa-static": "^5.0.0",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"lowdb": "^3.0.0",
|
||||||
|
"multer": "^1.4.5-lts.1",
|
||||||
|
"node-cron": "^3.0.1",
|
||||||
|
"uuid": "^8.3.2",
|
||||||
|
"yaml": "^2.1.1",
|
||||||
|
"funjia-server":"git+http://git.funjia.top/funjia/funjia-server.git"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"vite": "^6.0.7"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// import RouterFactor from "../RouterFactory.mjs";
|
||||||
|
// import DBHelper from "../DBHelper.mjs";
|
||||||
|
import {RouterFactor,DBHelper} from "funjia-server/lib/funjia-server.mjs";
|
||||||
|
|
||||||
|
const getDataLog = (router) => {
|
||||||
|
const rF = new RouterFactor({
|
||||||
|
router,
|
||||||
|
db: DBHelper.logDB,
|
||||||
|
name: "dataLog"
|
||||||
|
});
|
||||||
|
|
||||||
|
rF.creaetBaseRouter();
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getDataLog;
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
import cuid from "cuid";
|
||||||
|
// import getDb from "../dbServer.mjs";
|
||||||
|
import _ from "lodash";
|
||||||
|
|
||||||
|
import { getDb } from "funjia-server/lib/funjia-server.mjs";
|
||||||
|
const getEmployee = (router) => {
|
||||||
|
|
||||||
|
router.post('/api/employee/list', async (ctx) => {
|
||||||
|
// 设置头类型, 如果不设置,会直接下载该页面
|
||||||
|
ctx.type = 'application/json';
|
||||||
|
const db = await getDb();
|
||||||
|
const body = ctx.request.body;
|
||||||
|
const data = db.data?.employee?.filter((item) => {
|
||||||
|
let isMatch = true;
|
||||||
|
for (let field in body) {
|
||||||
|
if (["page", "pageSize"].includes(field)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof (item[field]) == "string") {
|
||||||
|
isMatch = item[field]?.indexOf?.(body[field]) > -1;
|
||||||
|
} else if (typeof (item[field]) == "number") {
|
||||||
|
isMatch = item[field] == body[field];
|
||||||
|
}
|
||||||
|
if (!isMatch)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return isMatch;
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
page,
|
||||||
|
pageSize
|
||||||
|
} = body;
|
||||||
|
let batchData = data;
|
||||||
|
if (page && pageSize) {
|
||||||
|
batchData = data.slice((page - 1) * pageSize, page * pageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
code: 0,
|
||||||
|
data: batchData || [],
|
||||||
|
total: data.length
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/api/employee', async (ctx) => {
|
||||||
|
// 设置头类型, 如果不设置,会直接下载该页面
|
||||||
|
ctx.type = 'application/json';
|
||||||
|
const db = await getDb();
|
||||||
|
const data = db.data.employee;
|
||||||
|
const query = ctx.request.query;
|
||||||
|
console.log("参数:", query, ctx.request.body, ctx.query);
|
||||||
|
let detail = {};
|
||||||
|
if (query.id && data) {
|
||||||
|
detail = data.find((item) => {
|
||||||
|
return item.id == query.id;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
code: 0,
|
||||||
|
data: detail || {}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/api/employee/add', async (ctx) => {
|
||||||
|
ctx.type = 'application/json';
|
||||||
|
const db = await getDb();
|
||||||
|
|
||||||
|
// You can also use this syntax if you prefer
|
||||||
|
if (!db.data?.employee)
|
||||||
|
db.data.employee = [];
|
||||||
|
const {
|
||||||
|
employee
|
||||||
|
} = db.data;
|
||||||
|
const data = ctx.request.body;
|
||||||
|
console.log("add:", data);
|
||||||
|
data.id = cuid();
|
||||||
|
data.createTime = new Date();
|
||||||
|
employee.push(data)
|
||||||
|
// Write db.data content to db.json
|
||||||
|
await db.write()
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
code: 0,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/api/employee/upd', async (ctx) => {
|
||||||
|
ctx.type = 'application/json';
|
||||||
|
const db = await getDb();
|
||||||
|
|
||||||
|
// You can also use this syntax if you prefer
|
||||||
|
if (!db.data?.employee)
|
||||||
|
db.data = {
|
||||||
|
employee: []
|
||||||
|
}
|
||||||
|
const {
|
||||||
|
employee
|
||||||
|
} = db.data;
|
||||||
|
const data = ctx.request.body;
|
||||||
|
const id = data.id;
|
||||||
|
console.log("数据Id:", id);
|
||||||
|
if (id && employee) {
|
||||||
|
const currentDetail = employee.find(item => item.id == id);
|
||||||
|
if (currentDetail) {
|
||||||
|
_.merge(currentDetail, data);
|
||||||
|
}
|
||||||
|
// Write db.data content to db.json
|
||||||
|
await db.write()
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
code: 0,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/api/employee/delete', async (ctx) => {
|
||||||
|
ctx.type = 'application/json';
|
||||||
|
const db = await getDb();
|
||||||
|
|
||||||
|
// You can also use this syntax if you prefer
|
||||||
|
if (!db.data?.employee)
|
||||||
|
db.data = {
|
||||||
|
employee: []
|
||||||
|
}
|
||||||
|
let {
|
||||||
|
employee
|
||||||
|
} = db.data;
|
||||||
|
const data = ctx.request.body;
|
||||||
|
const ids = data.ids;
|
||||||
|
if (ids?.length > 0 && employee) {
|
||||||
|
let id = null;
|
||||||
|
for (let i = 0; i < ids.length; i++) {
|
||||||
|
id = ids[i];
|
||||||
|
const idx = employee.findIndex(item => item.id == id);
|
||||||
|
if (idx != -1) {
|
||||||
|
employee.splice(idx, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Write db.data content to db.json
|
||||||
|
await db.write()
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
code: 0,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/api/employee/login', async (ctx) => {
|
||||||
|
// 设置头类型, 如果不设置,会直接下载该页面
|
||||||
|
ctx.type = 'application/json';
|
||||||
|
const db = await getDb();
|
||||||
|
const data = db.data.employee;
|
||||||
|
const params = ctx.request.body;
|
||||||
|
let detail = {};
|
||||||
|
if (data) {
|
||||||
|
detail = data.find((item) => {
|
||||||
|
return item.userName == params.userName && item.pwd == params.pwd;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const code = detail ? 0 : 1;
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
code,
|
||||||
|
data: detail || {}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getEmployee;
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
import cuid from "cuid";
|
||||||
|
// import getDb from "../dbServer.mjs";
|
||||||
|
import {getDb} from "funjia-server/lib/funjia-server.mjs";
|
||||||
|
import _ from "lodash";
|
||||||
|
|
||||||
|
const getNotice = (router) => {
|
||||||
|
|
||||||
|
router.post('/api/Notice/list', async (ctx) => {
|
||||||
|
// 设置头类型, 如果不设置,会直接下载该页面
|
||||||
|
ctx.type = 'application/json';
|
||||||
|
const db = await getDb();
|
||||||
|
const body = ctx.request.body;
|
||||||
|
const data = db.data?.Notice?.filter((item) => {
|
||||||
|
let isMatch = true;
|
||||||
|
for (let field in body) {
|
||||||
|
if (["page", "pageSize"].includes(field)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof (item[field]) == "string") {
|
||||||
|
isMatch = item[field]?.indexOf?.(body[field]) > -1;
|
||||||
|
} else if (typeof (item[field]) == "number") {
|
||||||
|
isMatch = item[field] == body[field];
|
||||||
|
}
|
||||||
|
if (!isMatch)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return isMatch;
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
page,
|
||||||
|
pageSize
|
||||||
|
} = body;
|
||||||
|
let batchData = data;
|
||||||
|
if (page && pageSize) {
|
||||||
|
batchData = data.slice((page - 1) * pageSize, page * pageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
code: 0,
|
||||||
|
data: batchData.sort((a, b) => {
|
||||||
|
return a.sort - b.sort;
|
||||||
|
}) || [],
|
||||||
|
total: data.length
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/api/Notice', async (ctx) => {
|
||||||
|
// 设置头类型, 如果不设置,会直接下载该页面
|
||||||
|
ctx.type = 'application/json';
|
||||||
|
const db = await getDb();
|
||||||
|
const data = db.data.Notice;
|
||||||
|
const query = ctx.request.query;
|
||||||
|
console.log("参数:", query, ctx.request.body, ctx.query);
|
||||||
|
let detail = {};
|
||||||
|
if (query.id && data) {
|
||||||
|
detail = data.find((item) => {
|
||||||
|
return item.id == query.id;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
code: 0,
|
||||||
|
data: detail || {}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/api/Notice/add', async (ctx) => {
|
||||||
|
ctx.type = 'application/json';
|
||||||
|
const db = await getDb();
|
||||||
|
|
||||||
|
// You can also use this syntax if you prefer
|
||||||
|
if (!db.data?.Notice)
|
||||||
|
db.data.Notice = [];
|
||||||
|
const {
|
||||||
|
Notice
|
||||||
|
} = db.data;
|
||||||
|
const data = ctx.request.body;
|
||||||
|
console.log("add:", data);
|
||||||
|
data.id = cuid();
|
||||||
|
data.createTime = new Date();
|
||||||
|
Notice.push(data)
|
||||||
|
// Write db.data content to db.json
|
||||||
|
await db.write()
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
code: 0,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/api/Notice/upd', async (ctx) => {
|
||||||
|
ctx.type = 'application/json';
|
||||||
|
const db = await getDb();
|
||||||
|
|
||||||
|
// You can also use this syntax if you prefer
|
||||||
|
if (!db.data?.Notice)
|
||||||
|
db.data = {
|
||||||
|
Notice: []
|
||||||
|
}
|
||||||
|
const {
|
||||||
|
Notice
|
||||||
|
} = db.data;
|
||||||
|
const data = ctx.request.body;
|
||||||
|
const id = data.id;
|
||||||
|
console.log("数据Id:", id);
|
||||||
|
if (id && Notice) {
|
||||||
|
const currentDetail = Notice.find(item => item.id == id);
|
||||||
|
if (currentDetail) {
|
||||||
|
_.merge(currentDetail, data);
|
||||||
|
}
|
||||||
|
// Write db.data content to db.json
|
||||||
|
await db.write()
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
code: 0,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/api/Notice/delete', async (ctx) => {
|
||||||
|
ctx.type = 'application/json';
|
||||||
|
const db = await getDb();
|
||||||
|
|
||||||
|
// You can also use this syntax if you prefer
|
||||||
|
if (!db.data?.Notice)
|
||||||
|
db.data = {
|
||||||
|
Notice: []
|
||||||
|
}
|
||||||
|
let {
|
||||||
|
Notice
|
||||||
|
} = db.data;
|
||||||
|
const data = ctx.request.body;
|
||||||
|
const ids = data.ids;
|
||||||
|
if (ids?.length > 0 && Notice) {
|
||||||
|
let id = null;
|
||||||
|
for (let i = 0; i < ids.length; i++) {
|
||||||
|
id = ids[i];
|
||||||
|
const idx = Notice.findIndex(item => item.id == id);
|
||||||
|
if (idx != -1) {
|
||||||
|
Notice.splice(idx, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Write db.data content to db.json
|
||||||
|
await db.write()
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
code: 0,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getNotice;
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// import RouterFactor from "../RouterFactory.mjs";
|
||||||
|
// import DBHelper from "../DBHelper.mjs";
|
||||||
|
import {RouterFactor,DBHelper} from "funjia-server/lib/funjia-server.mjs";
|
||||||
|
|
||||||
|
|
||||||
|
const getQA = (router) => {
|
||||||
|
const rF = new RouterFactor({
|
||||||
|
router,
|
||||||
|
db: DBHelper.baseDB,
|
||||||
|
name: "qa"
|
||||||
|
});
|
||||||
|
|
||||||
|
rF.creaetBaseRouter();
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getQA;
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
import _ from "lodash";
|
||||||
|
// import RouterFactor from "../RouterFactory.mjs";
|
||||||
|
// import DBHelper from "../DBHelper.mjs";
|
||||||
|
import {RouterFactor,DBHelper} from "funjia-server/lib/funjia-server.mjs";
|
||||||
|
|
||||||
|
const getBackupHistory = (router) => {
|
||||||
|
const rF = new RouterFactor({
|
||||||
|
router,
|
||||||
|
db: DBHelper.backupDB,
|
||||||
|
name: "backupHistory"
|
||||||
|
});
|
||||||
|
|
||||||
|
rF.createGetList();
|
||||||
|
|
||||||
|
rF.createGetDetail();
|
||||||
|
|
||||||
|
rF.createAdd();
|
||||||
|
|
||||||
|
rF.createUpdate();
|
||||||
|
|
||||||
|
rF.createDelete();
|
||||||
|
|
||||||
|
// router.post('/api/backupHistory/add', async (ctx) => {
|
||||||
|
// ctx.type = 'application/json';
|
||||||
|
// const db = await getBackupDb();
|
||||||
|
|
||||||
|
// // You can also use this syntax if you prefer
|
||||||
|
// if (!db.data.backupHistory)
|
||||||
|
// db.data.backupHistory = [];
|
||||||
|
// const {
|
||||||
|
// backupHistory
|
||||||
|
// } = db.data;
|
||||||
|
// const data = ctx.request.body;
|
||||||
|
// console.log("add:", data);
|
||||||
|
// data.id = cuid();
|
||||||
|
// data.createTime = new Date();
|
||||||
|
// backupHistory.push(data)
|
||||||
|
// // Write db.data content to db.json
|
||||||
|
// await db.write()
|
||||||
|
|
||||||
|
// ctx.body = {
|
||||||
|
// code: 0,
|
||||||
|
// };
|
||||||
|
// });
|
||||||
|
|
||||||
|
// router.post('/api/backupHistory/upd', async (ctx) => {
|
||||||
|
// ctx.type = 'application/json';
|
||||||
|
// const db = await getBackupDb();
|
||||||
|
|
||||||
|
// // You can also use this syntax if you prefer
|
||||||
|
// if (!db.data.backupHistory)
|
||||||
|
// db.data = {
|
||||||
|
// backupHistory: []
|
||||||
|
// }
|
||||||
|
// const {
|
||||||
|
// backupHistory
|
||||||
|
// } = db.data;
|
||||||
|
// const data = ctx.request.body;
|
||||||
|
// const id = data.id;
|
||||||
|
// console.log("数据Id:", id);
|
||||||
|
// if (id && backupHistory) {
|
||||||
|
// const currentDetail = backupHistory.find(item => item.id == id);
|
||||||
|
// if (currentDetail) {
|
||||||
|
// _.merge(currentDetail, data);
|
||||||
|
// }
|
||||||
|
// // Write db.data content to db.json
|
||||||
|
// await db.write()
|
||||||
|
// }
|
||||||
|
|
||||||
|
// ctx.body = {
|
||||||
|
// code: 0,
|
||||||
|
// };
|
||||||
|
// });
|
||||||
|
|
||||||
|
// router.post('/api/backupHistory/delete', async (ctx) => {
|
||||||
|
// ctx.type = 'application/json';
|
||||||
|
// const db = await getBackupDb();
|
||||||
|
|
||||||
|
// // You can also use this syntax if you prefer
|
||||||
|
// if (!db.data.backupHistory)
|
||||||
|
// db.data = {
|
||||||
|
// backupHistory: []
|
||||||
|
// }
|
||||||
|
// let {
|
||||||
|
// backupHistory
|
||||||
|
// } = db.data;
|
||||||
|
// const data = ctx.request.body;
|
||||||
|
// const ids = data.ids;
|
||||||
|
// if (ids.length > 0 && backupHistory) {
|
||||||
|
// let id = null;
|
||||||
|
// for (let i = 0; i < ids.length; i++) {
|
||||||
|
// id = ids[i];
|
||||||
|
// const idx = backupHistory.findIndex(item => item.id == id);
|
||||||
|
// if (idx != -1) {
|
||||||
|
// backupHistory.splice(idx, 1);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// // Write db.data content to db.json
|
||||||
|
// await db.write()
|
||||||
|
// }
|
||||||
|
|
||||||
|
// ctx.body = {
|
||||||
|
// code: 0,
|
||||||
|
// };
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getBackupHistory;
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
import cuid from "cuid";
|
||||||
|
// import getDb from "../dbServer.mjs";
|
||||||
|
import {getDb} from "funjia-server/lib/funjia-server.mjs";
|
||||||
|
import _ from "lodash";
|
||||||
|
|
||||||
|
const getDynamic = (router) => {
|
||||||
|
|
||||||
|
router.post('/api/dynamic/list/:tableName', async (ctx) => {
|
||||||
|
// 设置头类型, 如果不设置,会直接下载该页面
|
||||||
|
ctx.type = 'application/json';
|
||||||
|
const db = await getDb();
|
||||||
|
const body = ctx.request.body;
|
||||||
|
const data = db.data[ctx.params.tableName]?.filter((item) => {
|
||||||
|
let isMatch = true;
|
||||||
|
for (let field in body) {
|
||||||
|
if (["page", "pageSize"].includes(field)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof (item[field]) == "string") {
|
||||||
|
isMatch = item[field]?.indexOf?.(body[field]) > -1;
|
||||||
|
} else if (typeof (item[field]) == "number") {
|
||||||
|
isMatch = item[field] == body[field];
|
||||||
|
}
|
||||||
|
if (!isMatch)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return isMatch;
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
page,
|
||||||
|
pageSize
|
||||||
|
} = body;
|
||||||
|
let batchData = data;
|
||||||
|
if (page && pageSize) {
|
||||||
|
batchData = data.slice((page - 1) * pageSize, page * pageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
code: 0,
|
||||||
|
data: batchData || [],
|
||||||
|
total: data.length
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/api/dynamic/:tableName', async (ctx) => {
|
||||||
|
// 设置头类型, 如果不设置,会直接下载该页面
|
||||||
|
ctx.type = 'application/json';
|
||||||
|
const db = await getDb();
|
||||||
|
const data = db.data[ctx.params.tableName];
|
||||||
|
const query = ctx.request.query;
|
||||||
|
console.log("参数:", query, ctx.request.body, ctx.query);
|
||||||
|
let detail = {};
|
||||||
|
if (query.id && data) {
|
||||||
|
detail = data.find((item) => {
|
||||||
|
return item.id == query.id;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
code: 0,
|
||||||
|
data: detail || {}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/api/dynamic/add/:tableName', async (ctx) => {
|
||||||
|
ctx.type = 'application/json';
|
||||||
|
const tableName=ctx.params.tableName;
|
||||||
|
|
||||||
|
const db = await getDb();
|
||||||
|
|
||||||
|
// You can also use this syntax if you prefer
|
||||||
|
if (!db.data[tableName])
|
||||||
|
db.data[tableName] = [];
|
||||||
|
|
||||||
|
const dynamic = db.data[tableName];
|
||||||
|
const data = ctx.request.body;
|
||||||
|
console.log("add:", data);
|
||||||
|
data.id = cuid();
|
||||||
|
data.createTime = new Date();
|
||||||
|
dynamic.push(data)
|
||||||
|
// Write db.data content to db.json
|
||||||
|
await db.write()
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
code: 0,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/api/dynamic/upd/:tableName', async (ctx) => {
|
||||||
|
ctx.type = 'application/json';
|
||||||
|
const tableName=ctx.params.tableName;
|
||||||
|
|
||||||
|
const db = await getDb();
|
||||||
|
|
||||||
|
// You can also use this syntax if you prefer
|
||||||
|
if (!db.data[tableName])
|
||||||
|
db.data = {
|
||||||
|
dynamic: []
|
||||||
|
}
|
||||||
|
|
||||||
|
const dynamic = db.data[tableName];
|
||||||
|
|
||||||
|
const data = ctx.request.body;
|
||||||
|
const id = data.id;
|
||||||
|
console.log("数据Id:", id);
|
||||||
|
if (id && dynamic) {
|
||||||
|
const currentDetail = dynamic.find(item => item.id == id);
|
||||||
|
if (currentDetail) {
|
||||||
|
_.merge(currentDetail, data);
|
||||||
|
}
|
||||||
|
// Write db.data content to db.json
|
||||||
|
await db.write()
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
code: 0,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/api/dynamic/delete/:tableName', async (ctx) => {
|
||||||
|
ctx.type = 'application/json';
|
||||||
|
const tableName=ctx.params.tableName;
|
||||||
|
|
||||||
|
const db = await getDb();
|
||||||
|
|
||||||
|
// You can also use this syntax if you prefer
|
||||||
|
if (!db.data[tableName])
|
||||||
|
db.data = {
|
||||||
|
[tableName]: []
|
||||||
|
}
|
||||||
|
|
||||||
|
const dynamic = db.data[tableName];
|
||||||
|
|
||||||
|
const data = ctx.request.body;
|
||||||
|
const ids = data.ids;
|
||||||
|
if (ids?.length > 0 && dynamic) {
|
||||||
|
let id = null;
|
||||||
|
for (let i = 0; i < ids.length; i++) {
|
||||||
|
id = ids[i];
|
||||||
|
const idx = dynamic.findIndex(item => item.id == id);
|
||||||
|
if (idx != -1) {
|
||||||
|
dynamic.splice(idx, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Write db.data content to db.json
|
||||||
|
await db.write()
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
code: 0,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getDynamic;
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
import cuid from "cuid";
|
||||||
|
// import getDb, {
|
||||||
|
// getResourceDb
|
||||||
|
// } from "../dbServer.mjs";
|
||||||
|
import {getDb,getResourceDb} from "funjia-server/lib/funjia-server.mjs";
|
||||||
|
import _ from "lodash";
|
||||||
|
import multer from '@koa/multer';
|
||||||
|
|
||||||
|
//配置
|
||||||
|
var storage = multer.diskStorage({
|
||||||
|
//文件保存路径
|
||||||
|
destination: function (req, file, cb) {
|
||||||
|
cb(null, 'static') //注意路径必须存最后面在不用加斜杠
|
||||||
|
},
|
||||||
|
//修改文件名称
|
||||||
|
filename: function (req, file, cb) {
|
||||||
|
var fileFormat = (file.originalname).split(".");
|
||||||
|
const filename = cuid() + "." + fileFormat[fileFormat.length - 1];
|
||||||
|
req.filename = filename;
|
||||||
|
cb(null, filename);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
//加载配置
|
||||||
|
var upload = multer({
|
||||||
|
storage: storage
|
||||||
|
})
|
||||||
|
|
||||||
|
// const upload = multer({ dest: 'static/' })
|
||||||
|
|
||||||
|
const getUpload = (router) => {
|
||||||
|
router.post('/api/leaseRecords/list', async (ctx) => {
|
||||||
|
// 设置头类型, 如果不设置,会直接下载该页面
|
||||||
|
ctx.type = 'application/json';
|
||||||
|
const db = await getDb();
|
||||||
|
const body = ctx.request.body;
|
||||||
|
const data = db.data.leaseRecords.filter((item) => {
|
||||||
|
let isMatch = true;
|
||||||
|
for (let field in body) {
|
||||||
|
if (["page", "pageSize"].includes(field)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof (item[field]) == "string") {
|
||||||
|
isMatch = item[field].indexOf(body[field]) > -1;
|
||||||
|
} else if (typeof (item[field]) == "number") {
|
||||||
|
isMatch = item[field] == body[field];
|
||||||
|
}
|
||||||
|
if (!isMatch)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return isMatch;
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
page,
|
||||||
|
pageSize
|
||||||
|
} = body;
|
||||||
|
let batchData = data;
|
||||||
|
if (page && pageSize) {
|
||||||
|
batchData = data.slice((page - 1) * pageSize, page * pageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
code: 0,
|
||||||
|
data: batchData.sort((a, b) => {
|
||||||
|
return a.sort - b.sort;
|
||||||
|
}) || [],
|
||||||
|
total: data.length
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/api/img', async (ctx) => {
|
||||||
|
// 设置头类型, 如果不设置,会直接下载该页面
|
||||||
|
ctx.type = 'application/json';
|
||||||
|
const db = await getDb();
|
||||||
|
const data = db.data.leaseRecords;
|
||||||
|
const query = ctx.request.query;
|
||||||
|
console.log("参数:", query, ctx.request.body, ctx.query);
|
||||||
|
let detail = {};
|
||||||
|
if (query.id && data) {
|
||||||
|
detail = data.find((item) => {
|
||||||
|
return item.id == query.id;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
code: 0,
|
||||||
|
data: detail || {}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加图片记录
|
||||||
|
* @param {*} path
|
||||||
|
*/
|
||||||
|
const addImg = async (filename, path) => {
|
||||||
|
const data = {};
|
||||||
|
try {
|
||||||
|
const db = await getResourceDb();
|
||||||
|
|
||||||
|
// You can also use this syntax if you prefer
|
||||||
|
if (!db.data.img)
|
||||||
|
db.data.img = [];
|
||||||
|
|
||||||
|
const {
|
||||||
|
img
|
||||||
|
} = db.data;
|
||||||
|
|
||||||
|
data.id = cuid();
|
||||||
|
data.filename = filename;
|
||||||
|
data.path = path;
|
||||||
|
data.createTime = new Date();
|
||||||
|
img.push(data)
|
||||||
|
// Write db.data content to db.json
|
||||||
|
await db.write()
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return data.id;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加单个文件上传的路由
|
||||||
|
router.post(
|
||||||
|
'/api/upload/img',
|
||||||
|
upload.single('file'),
|
||||||
|
async (ctx) => {
|
||||||
|
const {
|
||||||
|
filename,
|
||||||
|
path
|
||||||
|
} = ctx.file;
|
||||||
|
const res = await addImg(filename, path);
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
code: res ? 0 : 1,
|
||||||
|
data: {
|
||||||
|
id: res,
|
||||||
|
url: path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 添加单个文件上传的路由
|
||||||
|
router.post(
|
||||||
|
'/api/upload/file',
|
||||||
|
upload.single('file'),
|
||||||
|
async (ctx) => {
|
||||||
|
const {
|
||||||
|
filename,
|
||||||
|
path
|
||||||
|
} = ctx.file;
|
||||||
|
// const res = await addImg(filename, path);
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
code: 0,
|
||||||
|
data: {
|
||||||
|
url: "/resource/static/"+filename
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getUpload;
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { defineConfig } from 'vite';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
build: {
|
||||||
|
lib: {
|
||||||
|
entry: './src/main.mjs', // 你的库的入口文件,这里假设是 src/main.mjs
|
||||||
|
name: 'YourLibraryName', // 库的全局名称,将在浏览器环境中使用
|
||||||
|
formats: ['es', 'umd'], // 输出的模块格式,这里包含 ES 模块和 UMD 模块
|
||||||
|
fileName: (format) => `your-library-name.${format}.js` // 输出的文件名,根据不同的格式生成不同的文件名
|
||||||
|
},
|
||||||
|
rollupOptions: {
|
||||||
|
// 确保外部化处理那些你不想打包进库中的依赖
|
||||||
|
external: [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
+1596
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,11 @@ import SystemMenu from './components/SystemMenu.vue';
|
|||||||
import SystemLayout from './components/SystemLayout.vue';
|
import SystemLayout from './components/SystemLayout.vue';
|
||||||
import "element-plus/dist/index.css";
|
import "element-plus/dist/index.css";
|
||||||
import "funjiaui/dist/style.css";
|
import "funjiaui/dist/style.css";
|
||||||
|
import * as funjiaui from "funjiaui";
|
||||||
|
import axios from "funjia-axios";
|
||||||
|
|
||||||
|
window.funjiaui = funjiaui;
|
||||||
|
window.axios = axios;
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 6.7 KiB |
@@ -1,4 +0,0 @@
|
|||||||
import { createApp } from 'vue'
|
|
||||||
import CaptureObjectList from '@/views/CaptureObjectList.vue'
|
|
||||||
|
|
||||||
createApp(CaptureObjectList).mount('#app')
|
|
||||||
+37
-30
@@ -1,4 +1,4 @@
|
|||||||
import axios from "../axios";
|
import axios from "funjia-axios";
|
||||||
// import imgList from "../../../public/data/image_cache.json";
|
// import imgList from "../../../public/data/image_cache.json";
|
||||||
// import serviceInfo from "../../../public/data/get_service_info.json";
|
// import serviceInfo from "../../../public/data/get_service_info.json";
|
||||||
|
|
||||||
@@ -25,34 +25,6 @@ export const getSytemInfo = (): Promise<any> => {
|
|||||||
return axios.get("/api/get/system");
|
return axios.get("/api/get/system");
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取ipc列表
|
|
||||||
*/
|
|
||||||
export const getIpcList = (params: any): Promise<any> => {
|
|
||||||
return axios.post("/api/manager/device/list");
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加ipc
|
|
||||||
*/
|
|
||||||
export const addIpc = (params: any): Promise<any> => {
|
|
||||||
return axios.post("/api/manager/device/add", params);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改ipc
|
|
||||||
*/
|
|
||||||
export const updateIpc = (params: any): Promise<any> => {
|
|
||||||
return axios.post("/api/manager/device/update", params);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除ipc
|
|
||||||
*/
|
|
||||||
export const deleteIpc = (params: any): Promise<any> => {
|
|
||||||
return axios.post("/api/manager/device/delete", params);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据ipcId获取抓拍图片列表
|
* 根据ipcId获取抓拍图片列表
|
||||||
*/
|
*/
|
||||||
@@ -268,4 +240,39 @@ export const updateQA = (params: any): Promise<any> => {
|
|||||||
*/
|
*/
|
||||||
export const deleteQA = (params: any): Promise<any> => {
|
export const deleteQA = (params: any): Promise<any> => {
|
||||||
return axios.post("/api/QA/delete", params);
|
return axios.post("/api/QA/delete", params);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Dynamic列表
|
||||||
|
*/
|
||||||
|
export const getDynamicList = (params: any, tableName: string): Promise<any> => {
|
||||||
|
return axios.post("/api/dynamic/list/" + tableName, params);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Dynamic详情
|
||||||
|
*/
|
||||||
|
export const getDynamic = (params: any, tableName: string): Promise<any> => {
|
||||||
|
return axios.get("/api/dynamic/" + tableName, { params });
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加Dynamic
|
||||||
|
*/
|
||||||
|
export const addDynamic = (params: any, tableName: string): Promise<any> => {
|
||||||
|
return axios.post("/api/dynamic/add/" + tableName, params);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改Dynamic
|
||||||
|
*/
|
||||||
|
export const updateDynamic = (params: any, tableName: string): Promise<any> => {
|
||||||
|
return axios.post("/api/dynamic/upd/" + tableName, params);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除Dynamic
|
||||||
|
*/
|
||||||
|
export const deleteDynamic = (params: any, tableName: string): Promise<any> => {
|
||||||
|
return axios.post("/api/dynamic/delete/" + tableName, params);
|
||||||
|
};
|
||||||
|
|||||||
@@ -7,18 +7,16 @@
|
|||||||
<el-menu :default-active="activeIndex" :default-openeds="openeds" :router="true" class="el-menu-vertical-demo"
|
<el-menu :default-active="activeIndex" :default-openeds="openeds" :router="true" class="el-menu-vertical-demo"
|
||||||
:collapse="isCollapse" active-text-color="#409eff" background-color="#001529" text-color="#fff"
|
:collapse="isCollapse" active-text-color="#409eff" background-color="#001529" text-color="#fff"
|
||||||
:style="{ border: 0 }" @open="handleOpen" @close="handleClose">
|
:style="{ border: 0 }" @open="handleOpen" @close="handleClose">
|
||||||
<el-menu-item index="/app/Employee">
|
<template v-if="menuJson.length == 0">
|
||||||
用戶列表
|
<el-menu-item index="/app/Employee">
|
||||||
</el-menu-item>
|
用戶列表
|
||||||
<el-menu-item index="/app/TravelInformation">
|
</el-menu-item>
|
||||||
出行记录
|
</template>
|
||||||
</el-menu-item>
|
<template v-else>
|
||||||
<el-menu-item index="/app/Notice">
|
<el-menu-item v-for="(item, index) in menuJson" :key="item.name" :index="item.route">
|
||||||
通知列表
|
{{ item.name }}
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
<el-menu-item index="/app/QA">
|
</template>
|
||||||
问答列表
|
|
||||||
</el-menu-item>
|
|
||||||
</el-menu>
|
</el-menu>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -30,6 +28,8 @@ import {
|
|||||||
Setting,
|
Setting,
|
||||||
} from '@element-plus/icons-vue'
|
} from '@element-plus/icons-vue'
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
|
import * as api from "@/common/api";
|
||||||
|
import { MENU_JSON } from "@/consts/dataDict";
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
menuIdx: string,
|
menuIdx: string,
|
||||||
@@ -42,6 +42,7 @@ const props = withDefaults(defineProps<{
|
|||||||
const activeIndex = ref();
|
const activeIndex = ref();
|
||||||
const openeds = ref<string[]>([]);
|
const openeds = ref<string[]>([]);
|
||||||
const router = useRoute();
|
const router = useRoute();
|
||||||
|
const menuJson = ref<any>([]);
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
activeIndex.value = router.path;
|
activeIndex.value = router.path;
|
||||||
@@ -54,6 +55,7 @@ onBeforeMount(() => {
|
|||||||
openeds.value = ['/app/system/info'];
|
openeds.value = ['/app/system/info'];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
getMenuJson();
|
||||||
})
|
})
|
||||||
|
|
||||||
const isCollapse = ref(false)
|
const isCollapse = ref(false)
|
||||||
@@ -66,6 +68,18 @@ const goTo = (url) => {
|
|||||||
document.location.href = url;
|
document.location.href = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getMenuJson = async () => {
|
||||||
|
const { data: dataDict } = await api.getDynamic({ id: MENU_JSON }, "dataDict");
|
||||||
|
|
||||||
|
if (dataDict?.value) {
|
||||||
|
try {
|
||||||
|
menuJson.value = JSON.parse(dataDict.value);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style module lang="scss">
|
<style module lang="scss">
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// 接口地址
|
||||||
|
export const RECORD_URL = "clyx9ba3a0000qwrb2mjd25sd"
|
||||||
|
// 菜单项
|
||||||
|
export const MENU_JSON = "clyzxul91000mqorb1w503q2o"
|
||||||
|
// 系统名称
|
||||||
|
export const SYSTEM_TITLE = "cm64rpfik0000egrb3x33hbhj"
|
||||||
@@ -1,176 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div :class="$style['device-list']">
|
|
||||||
<div :class="$style['form-search']">
|
|
||||||
<label>类型:</label>
|
|
||||||
<el-radio-group v-model="objectType" size="large">
|
|
||||||
<el-radio :label="-1">全部</el-radio>
|
|
||||||
<el-radio :label="0">人脸</el-radio>
|
|
||||||
<el-radio :label="5">人体</el-radio>
|
|
||||||
<el-radio :label="3">车</el-radio>
|
|
||||||
<el-radio :label="4">电动车</el-radio>
|
|
||||||
<el-radio :label="8">车牌</el-radio>
|
|
||||||
<el-radio :label="11">猫</el-radio>
|
|
||||||
<el-radio :label="12">狗</el-radio>
|
|
||||||
</el-radio-group>
|
|
||||||
</div>
|
|
||||||
<image-list :data="ipcImgList" :containerHeight="imgListContainerHeight" @show="onShow"></image-list>
|
|
||||||
<um-dialog v-model="visible" :custom-class="$style['img-preview-dialog']" title="" width="1100px"
|
|
||||||
:footer="false">
|
|
||||||
<div :style="{ height: '650px' }">
|
|
||||||
<img-preview :id="imgPreviewInfo.id" :img-url="imgPreviewInfo.imgUrl"
|
|
||||||
:position="imgPreviewInfo.position" @img-idx-change="onImgIdxChange">
|
|
||||||
</img-preview>
|
|
||||||
<div :class="$style['footer']">
|
|
||||||
<div><span>抓拍时间:</span><span>{{ fDT(imgPreviewInfo.time) }}</span></div>
|
|
||||||
<div><span>相机名称:</span><span>{{ imgPreviewInfo.deviceName }}</span></div>
|
|
||||||
<div><span>类型:</span><span>{{ getObjectTypeName(imgPreviewInfo?.objectType) }}</span></div>
|
|
||||||
<div><span>置信度:</span><span>{{ toFixed((imgPreviewInfo?.confidence || 0) / 100) }}</span></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</um-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
|
||||||
// import UmTableClassEnhance from "@/components/UmTable/UmByClassEnhance.vue";
|
|
||||||
// import UmDialog from "@/components/UmDialog/index.vue";
|
|
||||||
import { UmByClassEnhance as UmTableClassEnhance,UmDialog } from "funjiaui";
|
|
||||||
// import CaptureObjectList from "@/containers/viewModel/CaptureObjectList";
|
|
||||||
import ImgPreview from "@/components/ImgPreview.vue";
|
|
||||||
import { ref, reactive, watch, onBeforeMount } from "vue";
|
|
||||||
import * as api from "@/common/api";
|
|
||||||
import { fDT } from "funjialib";
|
|
||||||
import ImageList from "./ImageList.vue";
|
|
||||||
import { toFixed, getObjectTypeName } from "@/common/tool"
|
|
||||||
|
|
||||||
const visible = ref(false);
|
|
||||||
const imgIndex = ref(0);
|
|
||||||
const ipcImgList = ref([]);
|
|
||||||
const imgPreviewInfo = reactive({
|
|
||||||
id: "",
|
|
||||||
imgUrl: "",
|
|
||||||
position: "",
|
|
||||||
time: "",
|
|
||||||
deviceName: "",
|
|
||||||
confidence: "",
|
|
||||||
objectType: ""
|
|
||||||
})
|
|
||||||
const objectType = ref<undefined | TObjectType>(-1);
|
|
||||||
|
|
||||||
const props = defineProps<{ deviceIds: [], imgListContainerHeight: number }>();
|
|
||||||
|
|
||||||
// CaptureObjectList.singleListen = (rowData) => {
|
|
||||||
// initImgPreviewInfo(rowData);
|
|
||||||
// imgIndex.value = (ipcImgList.value || []).findIndex(item => rowData.id == item.id) || 0;
|
|
||||||
// visible.value = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
onBeforeMount(() => {
|
|
||||||
getData();
|
|
||||||
})
|
|
||||||
|
|
||||||
watch(objectType, () => {
|
|
||||||
getData();
|
|
||||||
})
|
|
||||||
|
|
||||||
const getData = async () => {
|
|
||||||
const { data } = await api.getCaputreImgListByIpcId({
|
|
||||||
deviceIds: props?.deviceIds || undefined, objectType: objectType.value
|
|
||||||
});
|
|
||||||
ipcImgList.value = [];
|
|
||||||
if (data && data.objectList) {
|
|
||||||
ipcImgList.value = (data.objectList || []).sort((a, b) => {
|
|
||||||
return new Date(b.time) - new Date(a.time);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const initImgPreviewInfo = (data) => {
|
|
||||||
imgPreviewInfo.id = data?.["id"];
|
|
||||||
imgPreviewInfo.imgUrl = data?.["imgUrl"];
|
|
||||||
imgPreviewInfo.position = data?.["position"];
|
|
||||||
imgPreviewInfo.time = data?.["time"];
|
|
||||||
imgPreviewInfo.deviceName = data?.["deviceName"];
|
|
||||||
imgPreviewInfo.confidence = data?.["confidence"];
|
|
||||||
imgPreviewInfo.objectType = data?.["objectType"];
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(imgIndex, (i) => {
|
|
||||||
initImgPreviewInfo(ipcImgList.value?.[i]);
|
|
||||||
})
|
|
||||||
|
|
||||||
watch(visible, () => {
|
|
||||||
if (!visible) {
|
|
||||||
imgIndex.value = 0;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
const onDataChange = (data) => {
|
|
||||||
ipcImgList.value = data || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const onImgIdxChange = (idx: TImgPreviewIdx) => {
|
|
||||||
let tempIdx = imgIndex.value;
|
|
||||||
tempIdx += idx;
|
|
||||||
|
|
||||||
if (tempIdx >= 0 && tempIdx < ipcImgList.value?.length) {
|
|
||||||
imgIndex.value = tempIdx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const onShow = (id) => {
|
|
||||||
const rowData = (ipcImgList.value || []).find(item => id == item.id);
|
|
||||||
if (rowData) {
|
|
||||||
initImgPreviewInfo(rowData);
|
|
||||||
imgIndex.value = (ipcImgList.value || []).findIndex(item => rowData.id == item.id) || 0;
|
|
||||||
visible.value = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const onFire = async (key: string, data: any) => {
|
|
||||||
imgIndex.value = 0;
|
|
||||||
const resData = await api.getCaputreImgListByIpcId({ id: data })
|
|
||||||
ipcImgList.value = resData.data?.objectList || [];
|
|
||||||
initImgPreviewInfo(ipcImgList.value?.[0]);
|
|
||||||
visible.value = true;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style module lang="scss">
|
|
||||||
:global {
|
|
||||||
:local(.device-list) {
|
|
||||||
padding: 20px;
|
|
||||||
height: calc(100% - 40px);
|
|
||||||
overflow: auto;
|
|
||||||
|
|
||||||
:local(.form-search) {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.el-radio-group {
|
|
||||||
.el-radio__inner {
|
|
||||||
height: 24px;
|
|
||||||
width: 24px;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
width: 8px;
|
|
||||||
height: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:local(.img-preview-dialog) {
|
|
||||||
:local(.footer) {
|
|
||||||
margin-top: 20px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
|
|
||||||
>div {
|
|
||||||
margin-left: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<el-row :style="{ width: '100%' }">
|
<el-row :style="{ width: '100%' }">
|
||||||
<el-col :span="3">
|
<el-col :span="3">
|
||||||
<div class="system-name">
|
<div class="system-name">
|
||||||
出行管理
|
{{systemTitle||'...'}}
|
||||||
<!-- <img src="/logo.png" height="60"> -->
|
<!-- <img src="/logo.png" height="60"> -->
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
@@ -43,10 +43,19 @@ import {
|
|||||||
ArrowDown
|
ArrowDown
|
||||||
} from "@element-plus/icons-vue";
|
} from "@element-plus/icons-vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
|
import { SYSTEM_TITLE } from "@/consts/dataDict";
|
||||||
|
import * as api from "@/common/api";
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const pwdRef = ref<any>();
|
const pwdRef = ref<any>();
|
||||||
const router=useRouter();
|
const router=useRouter();
|
||||||
|
const systemTitle = ref();
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const { data: dataDict } = await api.getDynamic({ id: SYSTEM_TITLE }, "dataDict");
|
||||||
|
systemTitle.value = dataDict?.value;
|
||||||
|
}
|
||||||
|
)();
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
const userInfo = Cookies.get("UserInfo");
|
const userInfo = Cookies.get("UserInfo");
|
||||||
|
|||||||
@@ -1,117 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div :class="$style['license-update']">
|
|
||||||
<single-upload @file-change="onFileChange" />
|
|
||||||
<el-button :class="$style['submit']" :disabled="!enableSubmit" @click="onSubmit">更新</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ElMessage } from "element-plus";
|
|
||||||
import { decode } from "@/common/tool";
|
|
||||||
import SingleUpload from '@/components/SingleUpload.vue';
|
|
||||||
import { ref } from "vue";
|
|
||||||
|
|
||||||
const enableSubmit = ref(false);
|
|
||||||
// 当前浏览的文件
|
|
||||||
const currentFile = ref();
|
|
||||||
|
|
||||||
const verifyFileSize = (size: number) => {
|
|
||||||
const maxKb = 1;
|
|
||||||
const minB = 300;
|
|
||||||
const fileMaxSize = maxKb * 1024;
|
|
||||||
const fileMinSize = minB;
|
|
||||||
|
|
||||||
if (size > fileMaxSize) {
|
|
||||||
ElMessage.warning("附件大小不能大于" + maxKb + "KB!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (size < fileMinSize) {
|
|
||||||
ElMessage.warning("附件大小不能小于" + minB + "B!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const verifyUploadFile = (file: File) => {
|
|
||||||
const //fileName = rawFile.name,
|
|
||||||
fileSize = file.size;
|
|
||||||
const methodMap = [[verifyFileSize], [fileSize]];
|
|
||||||
let result = true;
|
|
||||||
let method: any, params;
|
|
||||||
for (let i = 0; i < methodMap[0].length; i++) {
|
|
||||||
method = methodMap[0][i];
|
|
||||||
params = methodMap[1][i];
|
|
||||||
|
|
||||||
if (result && method) {
|
|
||||||
result = method?.(params);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const onFileChange = (file: File) => {
|
|
||||||
currentFile.value = null;
|
|
||||||
enableSubmit.value = verifyUploadFile(file);
|
|
||||||
if (enableSubmit.value) {
|
|
||||||
currentFile.value = file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const onSubmit = async () => {
|
|
||||||
const file = currentFile.value;
|
|
||||||
const p = new Promise((resolve, reject) => {
|
|
||||||
// 获取文件内容
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.readAsDataURL(file);//发起异步请求
|
|
||||||
reader.onload = function () {
|
|
||||||
try {
|
|
||||||
let value: any = this.result?.split?.('base64,')?.slice(1);
|
|
||||||
// base64转文本
|
|
||||||
value = decode(value.join(""));
|
|
||||||
|
|
||||||
resolve([true, value]);
|
|
||||||
} catch (error) {
|
|
||||||
resolve([false]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const [result, value] = await p;
|
|
||||||
if (result) {
|
|
||||||
try {
|
|
||||||
const { status, reason } = await (await fetch('/api/system/license/update', {
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify({ license: value })
|
|
||||||
})).json()
|
|
||||||
|
|
||||||
if (status == "200") {
|
|
||||||
ElMessage.success("更新成功");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ElMessage.error(reason || "更新失败");
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
ElMessage.error("更新失败");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ElMessage.error("文件格式不正确");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style module lang="scss">
|
|
||||||
:global {
|
|
||||||
:local(.license-update) {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
:local(.submit) {
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
<template>
|
|
||||||
<el-form :inline="true" :model="form">
|
|
||||||
<el-form-item prop="autoRefersh" label="自动刷新">
|
|
||||||
<el-checkbox v-model="form.autoRefersh"></el-checkbox>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item prop="level" label="日志级别">
|
|
||||||
<el-select v-model="form.level">
|
|
||||||
<el-option v-for="item of levelList" :value="item.name">
|
|
||||||
{{ item.name }}
|
|
||||||
</el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item>
|
|
||||||
<el-button type="primary" @click="setLogLevel">设置日志级别</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<variable-size-list :class="$style['log-list']" :height="800" :itemCount="logData.length" :itemSize="getItemSize"
|
|
||||||
width="100%">
|
|
||||||
<template v-slot:default="slotProps">
|
|
||||||
<div :key="slotProps.key" :style="slotProps.style" class="log-row">
|
|
||||||
{{ logData[slotProps.index]?.info }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</variable-size-list>
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { reactive, ref, onBeforeMount, watch, onBeforeUnmount } from "vue";
|
|
||||||
import * as api from "@/common/api";
|
|
||||||
import { ElMessage } from "element-plus";
|
|
||||||
import { VariableSizeList } from '@kousum/vue3-window';
|
|
||||||
|
|
||||||
const levelList = ref([]);
|
|
||||||
const form = reactive({
|
|
||||||
level: "info",
|
|
||||||
autoRefersh: true
|
|
||||||
})
|
|
||||||
const props = {
|
|
||||||
value: 'id',
|
|
||||||
label: 'info',
|
|
||||||
}
|
|
||||||
const logData = ref([]);
|
|
||||||
// 读取日志行索引
|
|
||||||
const logIdx = ref(0);
|
|
||||||
const loopToken = ref(-1);
|
|
||||||
|
|
||||||
watch(() => form.autoRefersh, (v) => {
|
|
||||||
if (v) {
|
|
||||||
enableLoopLog();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
noEnableLoopLog();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
onBeforeMount(() => {
|
|
||||||
getLevelList();
|
|
||||||
getLogList();
|
|
||||||
|
|
||||||
if (form.autoRefersh) {
|
|
||||||
enableLoopLog();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
noEnableLoopLog();
|
|
||||||
})
|
|
||||||
|
|
||||||
// These row heights are arbitrary.
|
|
||||||
// Yours should be based on the content of the row.
|
|
||||||
const rowHeights = new Array(1000)
|
|
||||||
.fill(true)
|
|
||||||
.map(() => 25 + Math.round(Math.random() * 50));
|
|
||||||
|
|
||||||
const getItemSize = index => {
|
|
||||||
const len = logData.value?.[index]?.info?.length;
|
|
||||||
let row = logData.value?.[index].info.length / 200
|
|
||||||
if (len % 200 > 0) {
|
|
||||||
row += 1;
|
|
||||||
}
|
|
||||||
return row * 30;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getLevelList = async () => {
|
|
||||||
const data = await api.getLevelList();
|
|
||||||
if (data) {
|
|
||||||
form.level = data?.level_name;
|
|
||||||
levelList.value = data?.levels || [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getLogList = async () => {
|
|
||||||
const data = await api.getLogList({ index: logIdx.value });
|
|
||||||
if (logIdx.value != 0) {
|
|
||||||
logData.value = (data?.logs || []).sort((a, b) => {
|
|
||||||
return new Date(b.time) - new Date(a.time);
|
|
||||||
}).concat(logData.value);
|
|
||||||
} else {
|
|
||||||
logData.value = (data?.logs || []).sort((a, b) => {
|
|
||||||
return new Date(b.time) - new Date(a.time);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
logIdx.value = data?.max_index || 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const enableLoopLog = () => {
|
|
||||||
clearTimeout(loopToken.value);
|
|
||||||
|
|
||||||
loopToken.value = setTimeout(async () => {
|
|
||||||
await getLogList();
|
|
||||||
if (form.autoRefersh) {
|
|
||||||
enableLoopLog();
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
const noEnableLoopLog = () => {
|
|
||||||
clearTimeout(loopToken.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
const setLogLevel = async () => {
|
|
||||||
logData.value = [];
|
|
||||||
const data = await api.setLogLevel({ level: form.level })
|
|
||||||
if (data) {
|
|
||||||
logIdx.value = 0;
|
|
||||||
clearTimeout();
|
|
||||||
getLogList();
|
|
||||||
if (form.autoRefersh) {
|
|
||||||
enableLoopLog();
|
|
||||||
}
|
|
||||||
ElMessage.success("设置成功")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
<style module lang="scss">
|
|
||||||
:global {
|
|
||||||
:local(.log-list) {
|
|
||||||
.log-row {
|
|
||||||
// line-height: 60px;
|
|
||||||
// padding: 0 20px;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
align-items: center;
|
|
||||||
line-height: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.log-row:hover {
|
|
||||||
background-color: #d5d5d5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div :class="$style['system-info']">
|
|
||||||
<h2>系统信息</h2>
|
|
||||||
<div :class="$style['content']">
|
|
||||||
<div class="info" v-for="item in data">
|
|
||||||
<span>{{ item.name }}:</span>
|
|
||||||
<span>{{ item.value }}</span>
|
|
||||||
<!-- <el-divider border-style="dotted" /> -->
|
|
||||||
</div>
|
|
||||||
<div class="info">
|
|
||||||
<span>授权状态:</span>
|
|
||||||
<div :class="[$style['license-status'], license.valid ? '' : 'no-valid']">
|
|
||||||
<span>{{ license.valid ? "有效" : "无效" }}</span>
|
|
||||||
<span>{{ license.errorReason }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="info">
|
|
||||||
<span>授权有效期:</span>
|
|
||||||
<span>{{ license.expire ?? '--' }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
|
||||||
import * as api from "@/common/api";
|
|
||||||
import { onBeforeMount, reactive, onBeforeUnmount, ref } from "vue";
|
|
||||||
class v {
|
|
||||||
name: any = ""
|
|
||||||
value: any = ""
|
|
||||||
VFormat: any = null;
|
|
||||||
constructor(arg: any = null) {
|
|
||||||
this.name = arg?.name;
|
|
||||||
this.VFormat = arg?.vFormat;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const format = (v) => {
|
|
||||||
return parseFloat(v).toFixed(2) + "%";
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = reactive({
|
|
||||||
"cpu": new v({ name: "CPU", vFormat: format }),
|
|
||||||
"memory": new v({ name: "Memory", vFormat: format }),
|
|
||||||
"tup_util": new v({ name: "TPU", vFormat: format }),
|
|
||||||
"tup_memory": new v({ name: "TPU memory" }),
|
|
||||||
"sn": new v({ name: "SN" }),
|
|
||||||
"commit_id": new v({ name: "Commit id" }),
|
|
||||||
"commit_time": new v({ name: "Commit time" }),
|
|
||||||
"version": new v({ name: "版本" }),
|
|
||||||
"run_time": new v({ name: "启动时间" }),
|
|
||||||
"task_sum": new v({ name: "设备数" }),
|
|
||||||
"snap_count": new v({ name: "抓拍图片总数" }),
|
|
||||||
});
|
|
||||||
const license = reactive({
|
|
||||||
expire: null,
|
|
||||||
errorReason: "",
|
|
||||||
valid: true
|
|
||||||
})
|
|
||||||
|
|
||||||
const loopToken = ref(-1);
|
|
||||||
|
|
||||||
onBeforeMount(() => {
|
|
||||||
getData();
|
|
||||||
enableLoop();
|
|
||||||
})
|
|
||||||
|
|
||||||
onBeforeUnmount(() => { noEnableLoop() })
|
|
||||||
|
|
||||||
const enableLoop = () => {
|
|
||||||
clearTimeout(loopToken.value)
|
|
||||||
loopToken.value = setTimeout(() => {
|
|
||||||
getData();
|
|
||||||
enableLoop();
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
const noEnableLoop = () => {
|
|
||||||
clearTimeout(loopToken.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const getData = async () => {
|
|
||||||
const resData = await api.getSytemInfo();
|
|
||||||
if (resData) {
|
|
||||||
let item = null;
|
|
||||||
for (const key in resData) {
|
|
||||||
item = data?.[key];
|
|
||||||
if (item) {
|
|
||||||
if (item.VFormat) {
|
|
||||||
item.value = item.VFormat(resData[key])
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
item.value = resData[key]
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!item.name) {
|
|
||||||
// 如果未设置名称则以该字段作为name
|
|
||||||
item.name = key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
license.expire = resData?.license?.expire;
|
|
||||||
license.errorReason = resData?.license?.error_reason;
|
|
||||||
license.valid = resData?.license?.valid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style module lang="scss">
|
|
||||||
:global {
|
|
||||||
:local(.system-info) {
|
|
||||||
padding: 20px;
|
|
||||||
background-color: #FFF;
|
|
||||||
|
|
||||||
:local(.content) {
|
|
||||||
padding: 20px;
|
|
||||||
|
|
||||||
.info {
|
|
||||||
margin-bottom: 18px;
|
|
||||||
|
|
||||||
span {
|
|
||||||
font-size: 18px;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
display: inline-block;
|
|
||||||
width: 180px;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-divider {
|
|
||||||
margin: 12px 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:local(.license-status) {
|
|
||||||
display: inline-flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: flex-start;
|
|
||||||
|
|
||||||
span {
|
|
||||||
text-align: left !important;
|
|
||||||
width: auto !important;
|
|
||||||
margin-right: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
// align-items: center;
|
|
||||||
|
|
||||||
&.no-valid {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div :class="$style['up-server']">
|
|
||||||
<h2>平台注册配置</h2>
|
|
||||||
<um-table-form :key="formKey" ref="formRef" :target="UpServer" :data="formData" :is-show-default-submit="false"
|
|
||||||
@ok="onResetSubmit">
|
|
||||||
</um-table-form>
|
|
||||||
<div :style="{ textAlign: 'center', width: '500px' }">
|
|
||||||
<el-button @click="onSave">保存</el-button>
|
|
||||||
<el-button @click="onRefreshStatus">刷新状态</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
|
||||||
import UpServer from '@/containers/viewModel/UpServer';
|
|
||||||
import { reactive, ref, onBeforeMount } from 'vue';
|
|
||||||
import * as api from "@/common/api";
|
|
||||||
import { ElMessage } from 'element-plus';
|
|
||||||
|
|
||||||
const formData = reactive(new UpServer());
|
|
||||||
const formRef = ref();
|
|
||||||
const formKey = ref(-1);
|
|
||||||
|
|
||||||
onBeforeMount(() => {
|
|
||||||
onRefreshStatus();
|
|
||||||
})
|
|
||||||
|
|
||||||
const onSave = () => {
|
|
||||||
formRef?.value.onSubmit?.();
|
|
||||||
}
|
|
||||||
|
|
||||||
const onRefreshStatus = async () => {
|
|
||||||
const data = await api.getServiceStatus();
|
|
||||||
if (data) {
|
|
||||||
formData.id = data?.id;
|
|
||||||
formData.ip = data?.manage?.ip;
|
|
||||||
formData.port = data?.manage?.port;
|
|
||||||
formData.manage_status = data?.manage?.status;
|
|
||||||
formData.kafka_ip = data?.kafka?.ip;
|
|
||||||
formData.kafka_port = data?.kafka?.port;
|
|
||||||
formData.kafka_status = data?.kafka?.status;
|
|
||||||
if (data?.manage?.enable) {
|
|
||||||
formData.type = 1;
|
|
||||||
} else {
|
|
||||||
formData.type = 0;
|
|
||||||
}
|
|
||||||
formKey.value = new Date().getTime();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const onResetSubmit = async (params) => {
|
|
||||||
const data = await api.setService(params);
|
|
||||||
if (data) {
|
|
||||||
onRefreshStatus();
|
|
||||||
ElMessage.success('提交成功');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style module lang="scss">
|
|
||||||
:global {
|
|
||||||
:local(.up-server) {
|
|
||||||
padding: 20px;
|
|
||||||
background-color: #FFF;
|
|
||||||
|
|
||||||
.el-form {
|
|
||||||
width: 500px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,371 +0,0 @@
|
|||||||
<template>
|
|
||||||
<el-upload v-if="false" class="upload-demo" drag action="/api/system/update" accept=".zip,.bin,.gz"
|
|
||||||
:multiple="false" :limit="1" :auto-upload="true" @progress="onProgress" @error="onError" @success="onSuccess">
|
|
||||||
<el-icon class="el-icon--upload">
|
|
||||||
<upload-filled />
|
|
||||||
</el-icon>
|
|
||||||
<div class="el-upload__text">
|
|
||||||
可拖动文件到这里 <em>点击上传文件</em>
|
|
||||||
</div>
|
|
||||||
<template #tip>
|
|
||||||
<div class="el-upload__tip">
|
|
||||||
支持[.zip,.bin,.gz]文件类型,文件需小于1GB
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-upload>
|
|
||||||
<div :class="$style['upgrade-system']">
|
|
||||||
<single-upload accept=".zip,.bin,.gz" @file-change="onFileChange" />
|
|
||||||
<el-button :class="$style['submit']" :disabled="!enableSubmit" @click="onSubmit">升级</el-button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<um-dialog v-model="visible" title="提示" :footer="null" :show-close="showDialogClose" :close-on-press-escape="false"
|
|
||||||
width="640px" @update:model-value="onModelValueChange">
|
|
||||||
<div :style="{ height: '120px' }">
|
|
||||||
<div class="upload-file-progress">
|
|
||||||
<label>文件上传进度:</label>
|
|
||||||
<el-progress :text-inside="true" :stroke-width="18" :percentage="percentage"></el-progress>
|
|
||||||
</div>
|
|
||||||
<div class="ugrade-system-progress">
|
|
||||||
<label>系统升级进度:</label>
|
|
||||||
<el-progress :text-inside="true" :stroke-width="18" :percentage="upgradeProgressParams.percentage">
|
|
||||||
</el-progress>
|
|
||||||
</div>
|
|
||||||
<div class="tip">
|
|
||||||
{{ msg }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</um-dialog>
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ElMessage, ElProgress, UploadFiles, UploadProgressEvent, UploadRawFile } from "element-plus";
|
|
||||||
import {
|
|
||||||
UploadFilled
|
|
||||||
} from '@element-plus/icons-vue';
|
|
||||||
import { reactive, ref, h, watch, onBeforeUnmount } from "vue";
|
|
||||||
import { toFixed } from "@/common/tool";
|
|
||||||
import { useRouter, onBeforeRouteLeave } from "vue-router";
|
|
||||||
import CountDownMessage from "@/components/CountDownMessage.vue";
|
|
||||||
import { merge } from "lodash-es";
|
|
||||||
import SingleUpload from '@/components/SingleUpload.vue';
|
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
const PINGURL = "/api/login/ping";
|
|
||||||
// 请求成功时得到的步长,基本上4次请求就可以确定程序重启成功了
|
|
||||||
const PONGSTEP = 1 / 4;
|
|
||||||
|
|
||||||
const showDialogClose = ref(false);
|
|
||||||
const percentage = ref(0);
|
|
||||||
const upgradeProgressParams = reactive({
|
|
||||||
percentage: 0,
|
|
||||||
startTime: null,
|
|
||||||
maxTimeSpan: 60,// 单位:秒
|
|
||||||
});
|
|
||||||
const visible = ref(false);
|
|
||||||
const msg = ref();
|
|
||||||
const coutDownTOV = ref(-1);
|
|
||||||
const router = useRouter();
|
|
||||||
const enableSubmit = ref(false);
|
|
||||||
const isStop = ref(false);
|
|
||||||
// 当前浏览的文件
|
|
||||||
const currentFile = ref();
|
|
||||||
|
|
||||||
watch(visible, (v) => {
|
|
||||||
if (!v) {
|
|
||||||
msg.value = "";
|
|
||||||
showDialogClose.value = false;
|
|
||||||
percentage.value = 0;
|
|
||||||
upgradeProgressParams.percentage = 0;
|
|
||||||
upgradeProgressParams.startTime = null;
|
|
||||||
coutDownTOV.value = -1;
|
|
||||||
enableSubmit.value = false;
|
|
||||||
isStop.value = false;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
window.removeEventListener('beforeunload', closeWindow);
|
|
||||||
clearTimeout(coutDownTOV.value);
|
|
||||||
})
|
|
||||||
|
|
||||||
onBeforeRouteLeave(() => {
|
|
||||||
if (!upgradeProgressParams.startTime) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ElMessage.warning('任务进行中,请不要操作系统');
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
})
|
|
||||||
|
|
||||||
const verifyFileType = (fileName: string) => {
|
|
||||||
const fileTypes = [".bin", ".zip", ".gz"];
|
|
||||||
const fileEnd = fileName.substring(fileName.lastIndexOf("."));
|
|
||||||
if (!fileTypes.includes(fileEnd)) {
|
|
||||||
ElMessage.warning("不支持该类型文件");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const verifyFileSize = (size: number) => {
|
|
||||||
const maxMb = 1;
|
|
||||||
const minKb = 14;
|
|
||||||
const fileMaxSize = 1024 * 1024 * 1024 * maxMb;//300M
|
|
||||||
const fileMinSize = 1024 * 14;
|
|
||||||
|
|
||||||
if (size > fileMaxSize) {
|
|
||||||
ElMessage.warning("附件大小不能大于" + maxMb + "GB!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (size < fileMinSize) {
|
|
||||||
ElMessage.warning("附件大小不能小于" + minKb + "KB!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const verifyUploadFile = (file: File) => {
|
|
||||||
const fileName = file.name, fileSize = file.size;
|
|
||||||
const methodMap = [[verifyFileType, verifyFileSize], [fileName, fileSize]];
|
|
||||||
let result = true;
|
|
||||||
let method: any, params;
|
|
||||||
for (let i = 0; i < methodMap[0].length; i++) {
|
|
||||||
method = methodMap[0][i];
|
|
||||||
params = methodMap[1][i];
|
|
||||||
|
|
||||||
if (result && method) {
|
|
||||||
result = method?.(params);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// // 隐藏弹出框右上角关闭按钮
|
|
||||||
// if (result) {
|
|
||||||
// // showDialogClose.value = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const onError = (response: any) => {
|
|
||||||
console.log("response:", response);
|
|
||||||
msg.value = response;
|
|
||||||
ElMessage.error("文件上传失败");
|
|
||||||
}
|
|
||||||
|
|
||||||
const onSuccess = (response: any) => {
|
|
||||||
if (response.status == "200") {
|
|
||||||
enableProgress('');
|
|
||||||
msg.value = "文件上传成功";
|
|
||||||
ElMessage.success("文件上传成功");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ElMessage.error(response.reason || "文件上传失败");
|
|
||||||
msg.value = response?.reason
|
|
||||||
showDialogClose.value = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const onModelValueChange = (value: boolean) => {
|
|
||||||
visible.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
const onProgress = (evt: UploadProgressEvent) => {
|
|
||||||
visible.value = true;
|
|
||||||
percentage.value = toFixed(evt.percent / 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
const closeWindow = (event) => {
|
|
||||||
// Cancel the event as stated by the standard.
|
|
||||||
event.preventDefault();
|
|
||||||
// Chrome requires returnValue to be set.
|
|
||||||
event.returnValue = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 启用进度条
|
|
||||||
*/
|
|
||||||
const enableProgress = (succMsg) => {
|
|
||||||
window.removeEventListener('beforeunload', closeWindow);
|
|
||||||
window.addEventListener('beforeunload', closeWindow);
|
|
||||||
|
|
||||||
upgradeProgressParams.startTime = new Date();
|
|
||||||
enableCountDown(succMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
const enableCountDown = (succMsg) => {
|
|
||||||
clearTimeout(coutDownTOV.value);
|
|
||||||
const uPP = upgradeProgressParams;
|
|
||||||
coutDownTOV.value = setTimeout(async () => {
|
|
||||||
msg.value = "系统升级中...";
|
|
||||||
const timeSpan = new Date().getTime() - (uPP.startTime || new Date())?.getTime();
|
|
||||||
if ((timeSpan / uPP.maxTimeSpan / 1000) > 4 / 5) {
|
|
||||||
uPP.percentage = uPP.percentage < 80 ? 80 : uPP.percentage;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const percentage = toFixed(timeSpan / 1000 / uPP.maxTimeSpan);
|
|
||||||
uPP.percentage = uPP.percentage < percentage ? percentage : uPP.percentage;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pong = await pingService();
|
|
||||||
// console.log("pong:", pong)
|
|
||||||
if (pong && isStop.value) {
|
|
||||||
// 只要能正确获取返回值,一般4秒内就可以判定服务已经启动成功
|
|
||||||
uPP.percentage = toFixed((parseFloat(uPP.percentage) / 100 + PONGSTEP));
|
|
||||||
}
|
|
||||||
else if (!pong) {
|
|
||||||
// 先验证是否停止了服务,再验证服务是否启动了
|
|
||||||
isStop.value = true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uPP.percentage < 100) {
|
|
||||||
enableCountDown(succMsg);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
uPP.percentage = 100;
|
|
||||||
showMsg();
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** ping接口服务,如果ping通代表服务当前是启动状态 */
|
|
||||||
const pingService = async (): Promise<boolean> => {
|
|
||||||
try {
|
|
||||||
// 用于终止Fetch请求的控制器。
|
|
||||||
const controller = new AbortController();
|
|
||||||
const { signal } = controller;
|
|
||||||
|
|
||||||
// Promise.race 可以处理异步请求的先后问题,这里用于
|
|
||||||
// 处理接口是否按预期请求完成
|
|
||||||
const data = await Promise.race([
|
|
||||||
fetch(PINGURL, { signal }),
|
|
||||||
new Promise((resolve) => {
|
|
||||||
setTimeout(() => {
|
|
||||||
// 终止目标请求
|
|
||||||
controller.abort();
|
|
||||||
resolve({ error: true });
|
|
||||||
}, 2000)
|
|
||||||
})
|
|
||||||
]).catch((err) => {
|
|
||||||
return { error: true };
|
|
||||||
})
|
|
||||||
|
|
||||||
console.log("ping-log:", data);
|
|
||||||
// 数据中未返回error字段或字段不为true时,
|
|
||||||
// 或者接口返回值中status是200|401 则表明请求是成功的
|
|
||||||
// return !!!data?.error || [200, 401].includes(data?.status);
|
|
||||||
return data?.error !== true || data?.statusText == "Not Found"; //data?.includes?.("File not found") || false
|
|
||||||
} catch (error) {
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const showMsg = () => {
|
|
||||||
msg.value = "系统升级成功";
|
|
||||||
const msgInstance = ElMessage({
|
|
||||||
type: "success",
|
|
||||||
message: h(CountDownMessage, {
|
|
||||||
getMsgTempalte(value: number) {
|
|
||||||
return `操作成功,${value}秒倒计时后将跳转到登录页!`
|
|
||||||
},
|
|
||||||
onNext() {
|
|
||||||
msgInstance.close();
|
|
||||||
clear();
|
|
||||||
router.push('/login');
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
duration: 10 * 1000
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const clear = () => {
|
|
||||||
merge(upgradeProgressParams, {
|
|
||||||
percentage: 0,
|
|
||||||
startTime: null,
|
|
||||||
maxTimeSpan: 30,// 单位:秒
|
|
||||||
});
|
|
||||||
|
|
||||||
clearTimeout(coutDownTOV.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
const onFileChange = (file: File) => {
|
|
||||||
currentFile.value = null;
|
|
||||||
enableSubmit.value = verifyUploadFile(file);
|
|
||||||
if (enableSubmit.value) {
|
|
||||||
currentFile.value = file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const onSubmit = async () => {
|
|
||||||
const file = currentFile.value;
|
|
||||||
visible.value = true;
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append('file', file);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const { status, reason } = await axios.post('/api/system/update', formData,
|
|
||||||
{
|
|
||||||
//获取上传进度
|
|
||||||
onUploadProgress: function (pE) {
|
|
||||||
// console.log('进度', progressEvent)
|
|
||||||
percentage.value = Math.round(pE.loaded / pE.total * 100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
).catch(error => {
|
|
||||||
// _this.$Message.error(error)
|
|
||||||
})
|
|
||||||
|
|
||||||
if (status == "200") {
|
|
||||||
enableProgress('');
|
|
||||||
msg.value = "文件上传成功";
|
|
||||||
ElMessage.success("文件上传成功");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ElMessage.error(reason || "文件上传失败");
|
|
||||||
msg.value = reason
|
|
||||||
showDialogClose.value = true;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
msg.value = "文件上传失败";
|
|
||||||
showDialogClose.value = true;
|
|
||||||
// ElMessage.error("文件上传失败");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
<style module lang="scss">
|
|
||||||
:global {
|
|
||||||
|
|
||||||
.upload-file-progress,
|
|
||||||
.ugrade-system-progress {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.el-progress {
|
|
||||||
width: 500px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ugrade-system-progress {
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tip {
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:local(.upgrade-system) {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
:local(.submit) {
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
import 'reflect-metadata';
|
|
||||||
import {
|
|
||||||
TableColumnPropertyDecorator as tcpd,
|
|
||||||
TableFormColumnPropertyDecorator as tfcpd,
|
|
||||||
TableColumnMethodDecorator as tcmd, TOperateType,
|
|
||||||
TableSearchFormPropertyDecorator as tsfpd,
|
|
||||||
UmTableForm
|
|
||||||
} from "funjiaui";
|
|
||||||
import * as api from "@/common/api"
|
|
||||||
import { h } from "vue";
|
|
||||||
import { getObjectTypeName } from "@/common/tool";
|
|
||||||
|
|
||||||
export default class CaptureObjectList {
|
|
||||||
|
|
||||||
static singleListen = null;
|
|
||||||
|
|
||||||
@tcpd({ "lang": "", "def": "设备名称", minWidth: 120 })
|
|
||||||
deviceName: string = "";
|
|
||||||
|
|
||||||
@tcpd({
|
|
||||||
"lang": "", "def": "置信度", minWidth: 120, columnRender2(value) {
|
|
||||||
try {
|
|
||||||
return (parseFloat(value).toFixed(2) * 100) + "%";
|
|
||||||
} catch (error) {
|
|
||||||
}
|
|
||||||
return '--';
|
|
||||||
}
|
|
||||||
})
|
|
||||||
confidence: number = 0;
|
|
||||||
|
|
||||||
@tcpd({
|
|
||||||
"lang": "", "def": "目标类型", minWidth: 120, columnRender(value) {
|
|
||||||
return getObjectTypeName(value);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@tsfpd({
|
|
||||||
lang: "", "def": "目标类型", fieldType: "select", async getData() {
|
|
||||||
return {
|
|
||||||
data: Array.from({ length: 7 }).map((item, index) => {
|
|
||||||
return {
|
|
||||||
label: getObjectTypeName(index),
|
|
||||||
value: index
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
multiple: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
objectType: string = "";
|
|
||||||
|
|
||||||
@tcpd({
|
|
||||||
"lang": "", "def": "抓拍照片", columnRender(value, f, rowData) {
|
|
||||||
return h('img', {
|
|
||||||
src: value,
|
|
||||||
style: { width: '100px', height: '100px' },
|
|
||||||
'onClick': (e) => {
|
|
||||||
CaptureObjectList.singleListen?.(rowData)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
width: 220
|
|
||||||
})
|
|
||||||
objectUrl: string = "";
|
|
||||||
|
|
||||||
@tcpd({ "lang": "", "def": "抓拍时间", minWidth: 120, "fieldType": "date" })
|
|
||||||
time: string = "";
|
|
||||||
|
|
||||||
@tcmd({ "key": "table:searchFormMethod", "value": { "type": "getList", "es": "onAfter" } })
|
|
||||||
getList = async (params: any) => {
|
|
||||||
const key = "captureObjectList";
|
|
||||||
let ipcListCache: string | null = sessionStorage.getItem(key);
|
|
||||||
try {
|
|
||||||
ipcListCache = ipcListCache ? JSON.parse(ipcListCache) : null;
|
|
||||||
} catch (error) {
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params.page == 1 || !ipcListCache) {
|
|
||||||
const { data } = await api.getCaputreImgListByIpcId(params);
|
|
||||||
let listData: any = null;
|
|
||||||
if (data?.objectList?.length > 0) {
|
|
||||||
listData = {
|
|
||||||
data: data?.objectList.sort((a, b) => {
|
|
||||||
return new Date(b.time) - new Date(a.time);
|
|
||||||
}), code: 0, total: data.total
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
listData = { data: [], code: 0, total: 0 }
|
|
||||||
}
|
|
||||||
sessionStorage.setItem(key, JSON.stringify(listData));
|
|
||||||
return { data: listData.data.slice(0, params.pageSize), code: 0, total: listData.total }
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const startIndex = (params.page - 1) * params.pageSize,
|
|
||||||
endIndex = startIndex + params.pageSize;
|
|
||||||
|
|
||||||
return { data: (ipcListCache?.data || []).slice(startIndex, endIndex), code: 0, total: ipcListCache?.total || 0 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
|
||||||
|
import 'reflect-metadata';
|
||||||
|
import { UmTableForm,
|
||||||
|
TableColumnPropertyDecorator as tcpd,
|
||||||
|
TableFormColumnPropertyDecorator as tfcpd,
|
||||||
|
TableColumnMethodDecorator as tcmd,
|
||||||
|
TableSearchFormPropertyDecorator as tsfpd
|
||||||
|
} from "funjiaui";
|
||||||
|
import * as api from "@/common/api"
|
||||||
|
// 数据字典
|
||||||
|
const tableName = "dataDict";
|
||||||
|
|
||||||
|
const isShow = (rowData: any) => {
|
||||||
|
if (rowData?.source_add_type == "1") {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 数据字典
|
||||||
|
export default class DataDict {
|
||||||
|
// 侵入性事件注入
|
||||||
|
static singleListen: any = null
|
||||||
|
|
||||||
|
static isEdit = false;
|
||||||
|
|
||||||
|
// 操作列宽度
|
||||||
|
static operateWidth = "140px";
|
||||||
|
|
||||||
|
@tcpd({ "lang": "", "def": "数据", minWidth: 120 })
|
||||||
|
@tfcpd({ "lang": "", "def": "id", fieldType: "primaryKey" })
|
||||||
|
id: number = 0;
|
||||||
|
|
||||||
|
@tcpd({ "lang": "", "def": "唯一标识", minWidth: 120 })
|
||||||
|
@tfcpd({ "lang": "", "def": "唯一标识", fieldType: "string", rule: [{ "type": "require", message: "不能为空" }] })
|
||||||
|
unionKey: string = ""
|
||||||
|
|
||||||
|
@tcpd({ "lang": "", "def": "数据", minWidth: 120 })
|
||||||
|
@tfcpd({ "lang": "", "def": "数据", fieldType: "string", rule: [{ "type": "require", message: "不能为空" }] })
|
||||||
|
value: string = ""
|
||||||
|
|
||||||
|
@tcpd({ "lang": "", "def": "描述", minWidth: 120 })
|
||||||
|
@tfcpd({ "lang": "", "def": "描述", fieldType: "string", rule: [{ "type": "require", message: "不能为空" }] })
|
||||||
|
desc: string = ""
|
||||||
|
|
||||||
|
@tcmd({ "key": "table:searchFormMethod", "value": { "type": "getList", "es": "onAfter" } })
|
||||||
|
getList = async (params: any) => {
|
||||||
|
return await api.getDynamicList(params, tableName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@tcmd({
|
||||||
|
"key": "table:toolbar", "value": {
|
||||||
|
"type": "添加", "priority": 1, "es": "onAfter", "dialogContent": UmTableForm, "dialogTitle": "增加", "dialogWidth": 650
|
||||||
|
}
|
||||||
|
})
|
||||||
|
onAdd = async (data: any) => {
|
||||||
|
const { code, msg } = await api.addDynamic({ ...data, unionKey: data.unionKey.toUpperCase() }, tableName);
|
||||||
|
if (code != 0) {
|
||||||
|
return { code: 1, message: msg };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return { code: 0 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取详情数据
|
||||||
|
*/
|
||||||
|
@tcmd({ "value": { "type": "edit", "es": "onBefore", "dialogContent": UmTableForm, "dialogTitle": "编辑" } })
|
||||||
|
getDetail = async (rowId: number, r, meta) => {
|
||||||
|
const { data } = await api.getDynamic({ id: rowId }, tableName);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@tcmd({
|
||||||
|
"value": {
|
||||||
|
"type": "edit", "es": "onAfter",
|
||||||
|
sort: 2,
|
||||||
|
// isShow
|
||||||
|
}
|
||||||
|
})
|
||||||
|
onEdit = async (params: any) => {
|
||||||
|
const { code, msg } = await api.updateDynamic({ ...params, unionKey: params.unionKey.toUpperCase() }, tableName);
|
||||||
|
if (code != 0) {
|
||||||
|
return { code: 1, message: msg };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return { code: 0 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@tcmd({
|
||||||
|
"value": {
|
||||||
|
"type": "del", "es": "onAfter", "dialogContent": "确定要删除该条数据吗?",
|
||||||
|
sort: 3,
|
||||||
|
// isShow
|
||||||
|
}
|
||||||
|
})
|
||||||
|
delByIds = async (rowId: number) => {
|
||||||
|
const { code, msg } = await api.deleteDynamic({ ids: [rowId] }, tableName);
|
||||||
|
if (code != 0) {
|
||||||
|
return { code: 1, message: msg };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return { code: 0 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@tcmd({ "key": "table:toolbar", "value": { "type": "批量删除", "priority": 5, "es": "onAfter", "dialogContent": "确定要删除选择的数据吗?" } })
|
||||||
|
onMutilDel = async (ids: any[]) => {
|
||||||
|
const { code, msg } = await api.deleteDynamic({ ids }, tableName);
|
||||||
|
if (code != 0) {
|
||||||
|
return { code: 1, message: msg };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return { code: 0 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exportText(filename, text) {
|
||||||
|
var element = document.createElement('a');
|
||||||
|
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
|
||||||
|
element.setAttribute('download', filename);
|
||||||
|
|
||||||
|
element.style.display = 'none';
|
||||||
|
document.body.appendChild(element);
|
||||||
|
|
||||||
|
element.click();
|
||||||
|
|
||||||
|
document.body.removeChild(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
@tcmd({
|
||||||
|
"key": "table:toolbar", "value": {
|
||||||
|
"type": "自定义", id: "anki", "priority": 1, "es": "onAfter", title: "导出字典常量表"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
onExport = async (params: any) => {
|
||||||
|
const { data } = await api.getDynamicList({ ...params, page: 1, pageSize: 10000 }, tableName);
|
||||||
|
|
||||||
|
const content = data.map(item => {
|
||||||
|
return `export const ${item.unionKey} = "${item.id}"`;
|
||||||
|
}).join("\n")
|
||||||
|
|
||||||
|
this.exportText("dataDict.ts", content);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,216 +0,0 @@
|
|||||||
|
|
||||||
import 'reflect-metadata';
|
|
||||||
import {
|
|
||||||
TableColumnPropertyDecorator as tcpd,
|
|
||||||
TableFormColumnPropertyDecorator as tfcpd,
|
|
||||||
TableColumnMethodDecorator as tcmd, TOperateType,
|
|
||||||
TableSearchFormPropertyDecorator as tsfpd,
|
|
||||||
UmTableForm
|
|
||||||
} from "funjiaui";
|
|
||||||
import * as api from "@/common/api"
|
|
||||||
import { ElMessage } from 'element-plus'
|
|
||||||
import { isEmpty } from 'funjialib';
|
|
||||||
|
|
||||||
const isShow = (rowData: any) => {
|
|
||||||
if (rowData?.source_add_type == "1") {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class Ipc {
|
|
||||||
// 侵入性事件注入
|
|
||||||
static singleListen: any = null
|
|
||||||
|
|
||||||
static isEdit = false;
|
|
||||||
|
|
||||||
// 操作列宽度
|
|
||||||
static operateWidth = "140px";
|
|
||||||
|
|
||||||
@tcpd({ "lang": "", "def": "设备ID", width: 200 })
|
|
||||||
@tfcpd({
|
|
||||||
"lang": "", "def": "ID", fieldType: 'number', rule: [{ "type": "require", message: "不能为空" }],
|
|
||||||
isDisabled(rowData) {
|
|
||||||
return rowData?.['$ref:birthday'];
|
|
||||||
}
|
|
||||||
})
|
|
||||||
id: number = 0;
|
|
||||||
|
|
||||||
@tcpd({ "lang": "", "def": "名称", minWidth: 120 })
|
|
||||||
@tfcpd({ "lang": "", "def": "名称", rule: [{ "type": "require", message: "不能为空" }] })
|
|
||||||
name: string = "";
|
|
||||||
|
|
||||||
@tcpd({ "lang": "", "def": "视频流地址", minWidth: 120 })
|
|
||||||
@tfcpd({
|
|
||||||
"lang": "", "def": "流地址", fieldType: 'string', placeholder: "rtsp://admin:admin1234@192.168.1.108", rule: [{ "type": "require", message: "不能为空" }]
|
|
||||||
})
|
|
||||||
url: string = "";
|
|
||||||
|
|
||||||
@tfcpd({
|
|
||||||
"lang": "", "def": "算法", fieldType: "select", getData() {
|
|
||||||
return {
|
|
||||||
data: [{ label: "人脸", value: "face" },
|
|
||||||
{ label: "人车非", value: "person" }
|
|
||||||
],
|
|
||||||
multiple: true
|
|
||||||
}
|
|
||||||
}, rule: [{ "type": "require", message: "不能为空" }]
|
|
||||||
})
|
|
||||||
type: string[] = [];
|
|
||||||
|
|
||||||
@tfcpd({ "lang": "", "def": "", isShow: async () => false })
|
|
||||||
source_type = "IPC";
|
|
||||||
|
|
||||||
@tfcpd({ "lang": "", "def": "", isShow: async () => false })
|
|
||||||
forever = true;
|
|
||||||
|
|
||||||
@tfcpd({ "lang": "", "def": "", isShow: async () => false })
|
|
||||||
birthday: any;
|
|
||||||
|
|
||||||
@tcpd({
|
|
||||||
"lang": "", "def": "最后抓拍时间", columnRender(v, f, rowData) {
|
|
||||||
return rowData?.time?.last_image;
|
|
||||||
}, width: 220
|
|
||||||
})
|
|
||||||
last_image: string = "";
|
|
||||||
|
|
||||||
|
|
||||||
// @tcpd({
|
|
||||||
// "lang": "", "def": "最后抓拍照片", columnRender(value, f, rowData) {
|
|
||||||
// return h('img', {
|
|
||||||
// src: value,
|
|
||||||
// style: { width: '100px', height: '100px' },
|
|
||||||
// 'onClick': (e) => {
|
|
||||||
// Ipc.singleListen?.(rowData)
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// },
|
|
||||||
// width: 220
|
|
||||||
// })
|
|
||||||
// objectUrl: string = "";
|
|
||||||
|
|
||||||
@tcpd({
|
|
||||||
"lang": "", "def": "状态", columnRender(v, f, rowData) {
|
|
||||||
let statusinfo = "在线";
|
|
||||||
if (rowData.status != "6") {
|
|
||||||
statusinfo = rowData.status_info;
|
|
||||||
}
|
|
||||||
return statusinfo;
|
|
||||||
}, width: 80
|
|
||||||
})
|
|
||||||
status: string = "";
|
|
||||||
|
|
||||||
@tcpd({ "lang": "", "def": "抓拍数", width: 80 })
|
|
||||||
snaper_image: string = "";
|
|
||||||
|
|
||||||
@tcmd({ "key": "table:searchFormMethod", "value": { "type": "getList", "es": "onAfter" } })
|
|
||||||
getList = async (params: any) => {
|
|
||||||
let ipcListCache: string | null = sessionStorage.getItem("ipcList");
|
|
||||||
try {
|
|
||||||
ipcListCache = ipcListCache ? JSON.parse(ipcListCache) : null;
|
|
||||||
} catch (error) {
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params.page == 1 || !ipcListCache) {
|
|
||||||
const data = await api.getIpcList(params);
|
|
||||||
let listData: any = null;
|
|
||||||
if (data?.devices?.length > 0) {
|
|
||||||
listData = {
|
|
||||||
data: data?.devices.sort((a, b) => {
|
|
||||||
return new Date(b.time) - new Date(a.time);
|
|
||||||
}), code: 0, total: data.size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
listData = { data: [], code: 0, total: 0 }
|
|
||||||
}
|
|
||||||
sessionStorage.setItem("ipcList", JSON.stringify(listData));
|
|
||||||
return { data: listData.data.slice(0, params.pageSize), code: 0, total: listData.total }
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const startIndex = (params.page - 1) * params.pageSize,
|
|
||||||
endIndex = startIndex + params.pageSize;
|
|
||||||
|
|
||||||
return { data: (ipcListCache?.data || []).slice(startIndex, endIndex), code: 0, total: ipcListCache?.total || 0 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@tcmd({
|
|
||||||
"key": "table:toolbar", "value": {
|
|
||||||
"type": "添加", "priority": 1, "es": "onAfter", "dialogContent": UmTableForm, "dialogTitle": "增加视频分析相机", "dialogWidth": 650
|
|
||||||
}
|
|
||||||
})
|
|
||||||
onAdd = async (data: any) => {
|
|
||||||
const { status, reason } = await api.addIpc(data);
|
|
||||||
if (status != 200) {
|
|
||||||
return { code: 1, message: reason };
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return { code: 0 };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取详情数据
|
|
||||||
*/
|
|
||||||
@tcmd({ "value": { "type": "edit", "es": "onBefore", "dialogContent": UmTableForm, "dialogTitle": "编辑视频分析相机" } })
|
|
||||||
getDetail = async (rowId: number, r, meta, data) => {
|
|
||||||
return data.find(item => rowId == item.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@tcmd({
|
|
||||||
"value": {
|
|
||||||
"type": "edit", "es": "onAfter",
|
|
||||||
sort: 2,
|
|
||||||
isShow
|
|
||||||
}
|
|
||||||
})
|
|
||||||
onEdit = async (params: any) => {
|
|
||||||
params.source_type = "IPC";
|
|
||||||
params.forever = true;
|
|
||||||
|
|
||||||
const { status, reason } = await api.updateIpc(params);
|
|
||||||
if (status != 200) {
|
|
||||||
return { code: 1, message: reason };
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return { code: 0 };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@tcmd({
|
|
||||||
"value": {
|
|
||||||
"type": "del", "es": "onAfter", "dialogContent": "确定要删除该条数据吗?",
|
|
||||||
sort: 3,
|
|
||||||
isShow
|
|
||||||
}
|
|
||||||
})
|
|
||||||
delByIds = async (rowId: number) => {
|
|
||||||
const { status, reason } = await api.deleteIpc({ id: rowId });
|
|
||||||
if (status != 200) {
|
|
||||||
return { code: 1, message: reason };
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return { code: 0 };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@tcmd({
|
|
||||||
"value": {
|
|
||||||
"id": 1, "type": "customOperateEvent", "title": "详情",
|
|
||||||
sort: 1,
|
|
||||||
isShow: (rowData) => {
|
|
||||||
if (rowData?.snaper_image > 0) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
jumpEmployee = (rowId: number) => {
|
|
||||||
return rowId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
|
||||||
|
import 'reflect-metadata';
|
||||||
|
import {
|
||||||
|
TableColumnPropertyDecorator as tcpd,
|
||||||
|
TableFormColumnPropertyDecorator as tfcpd,
|
||||||
|
TableColumnMethodDecorator as tcmd,
|
||||||
|
TableSearchFormPropertyDecorator as tsfpd,
|
||||||
|
UmTableForm
|
||||||
|
} from "funjiaui";
|
||||||
|
import * as api from "@/common/api"
|
||||||
|
import { h, ref } from 'vue';
|
||||||
|
import SingleUpload from '@/components/SingleUpload.vue';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
// 插件模块
|
||||||
|
const tableName = "plugin";
|
||||||
|
|
||||||
|
const isShow = (rowData: any) => {
|
||||||
|
if (rowData?.source_add_type == "1") {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Plugin2 {
|
||||||
|
// 侵入性事件注入
|
||||||
|
static singleListen: any = null
|
||||||
|
|
||||||
|
static isEdit = false;
|
||||||
|
|
||||||
|
// 操作列宽度
|
||||||
|
static operateWidth = "140px";
|
||||||
|
|
||||||
|
@tfcpd({ "lang": "", "def": "id", fieldType: "primaryKey" })
|
||||||
|
id: number = 0;
|
||||||
|
|
||||||
|
questionId: string = ""
|
||||||
|
|
||||||
|
@tcpd({ "lang": "", "def": "名称", minWidth: 120 })
|
||||||
|
@tfcpd({ "lang": "", "def": "名称", fieldType: "string", rule: [{ "type": "require", message: "不能为空" }] })
|
||||||
|
name: string = ""
|
||||||
|
|
||||||
|
@tcpd({ "lang": "", "def": "描述", minWidth: 120 })
|
||||||
|
@tfcpd({ "lang": "", "def": "描述", fieldType: "string", rule: [{ "type": "require", message: "不能为空" }] })
|
||||||
|
desc: string = ""
|
||||||
|
|
||||||
|
@tcpd({ "lang": "", "def": "插件脚本绝对地址", minWidth: 120 })
|
||||||
|
@tfcpd({
|
||||||
|
"lang": "", "def": "插件脚本绝对地址", component: function (props) {
|
||||||
|
const value = ref<any>();
|
||||||
|
const that = this;
|
||||||
|
return h(SingleUpload, {
|
||||||
|
modelValue: value,
|
||||||
|
"onFileChange": async (data) => {
|
||||||
|
const fdata = new FormData();
|
||||||
|
fdata.append("file", data);
|
||||||
|
const res = await axios.post('/api/upload/file', fdata);
|
||||||
|
value.value = res.data?.url
|
||||||
|
// this.$emit("");
|
||||||
|
// debugger;
|
||||||
|
// console.log(res.data?.url,props);
|
||||||
|
props['onUpdate:modelValue']?.(res.data?.url);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
rule: [{ "type": "require", message: "不能为空" }]
|
||||||
|
})
|
||||||
|
pluginUrl: string = ""
|
||||||
|
|
||||||
|
@tcmd({ "key": "table:searchFormMethod", "value": { "type": "getList", "es": "onAfter" } })
|
||||||
|
getList = async (params: any) => {
|
||||||
|
return await api.getDynamicList(params, tableName);
|
||||||
|
// return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
@tcmd({
|
||||||
|
"key": "table:toolbar", "value": {
|
||||||
|
"type": "添加", "priority": 1, "es": "onAfter", "dialogContent": UmTableForm, "dialogTitle": "增加", "dialogWidth": 650
|
||||||
|
}
|
||||||
|
})
|
||||||
|
onAdd = async (data: any) => {
|
||||||
|
const { code, msg } = await api.addDynamic({ ...data }, tableName);
|
||||||
|
if (code != 0) {
|
||||||
|
return { code: 1, message: msg };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return { code: 0 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取详情数据
|
||||||
|
*/
|
||||||
|
@tcmd({ "value": { "type": "edit", "es": "onBefore", "dialogContent": UmTableForm, "dialogTitle": "编辑" } })
|
||||||
|
getDetail = async (rowId: number, r, meta) => {
|
||||||
|
const { data } = await api.getDynamic({ id: rowId }, tableName);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@tcmd({
|
||||||
|
"value": {
|
||||||
|
"type": "edit", "es": "onAfter",
|
||||||
|
sort: 2,
|
||||||
|
// isShow
|
||||||
|
}
|
||||||
|
})
|
||||||
|
onEdit = async (params: any) => {
|
||||||
|
const { code, msg } = await api.updateDynamic({ ...params }, tableName);
|
||||||
|
if (code != 0) {
|
||||||
|
return { code: 1, message: msg };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return { code: 0 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@tcmd({
|
||||||
|
"value": {
|
||||||
|
"type": "del", "es": "onAfter", "dialogContent": "确定要删除该条数据吗?",
|
||||||
|
sort: 3,
|
||||||
|
// isShow
|
||||||
|
}
|
||||||
|
})
|
||||||
|
delByIds = async (rowId: number) => {
|
||||||
|
const { code, msg } = await api.deleteDynamic({ ids: [rowId] }, tableName);
|
||||||
|
if (code != 0) {
|
||||||
|
return { code: 1, message: msg };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return { code: 0 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@tcmd({ "key": "table:toolbar", "value": { "type": "批量删除", "priority": 5, "es": "onAfter", "dialogContent": "确定要删除选择的数据吗?" } })
|
||||||
|
onMutilDel = async (ids: any[]) => {
|
||||||
|
const { code, msg } = await api.deleteDynamic({ ids }, tableName);
|
||||||
|
if (code != 0) {
|
||||||
|
return { code: 1, message: msg };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return { code: 0 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,214 +0,0 @@
|
|||||||
|
|
||||||
import 'reflect-metadata';
|
|
||||||
import {
|
|
||||||
TableColumnPropertyDecorator as tcpd,
|
|
||||||
TableFormColumnPropertyDecorator as tfcpd,
|
|
||||||
TableColumnMethodDecorator as tcmd, TOperateType,
|
|
||||||
TableSearchFormPropertyDecorator as tsfpd,
|
|
||||||
UmTableForm
|
|
||||||
} from "funjiaui";
|
|
||||||
import * as api from "@/common/api"
|
|
||||||
// import UmTableForm from '@/components/UmTable/UmTableForm.vue';
|
|
||||||
import { ElMessage } from 'element-plus'
|
|
||||||
// import { isEmpty } from 'marsLib/is';
|
|
||||||
import { fDT } from 'funjialib';
|
|
||||||
import { h } from 'vue';
|
|
||||||
|
|
||||||
const isShow = (rowData: any) => {
|
|
||||||
if (rowData?.source_add_type == "1") {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class TravelInformation {
|
|
||||||
// 侵入性事件注入
|
|
||||||
static singleListen: any = null
|
|
||||||
|
|
||||||
static isEdit = false;
|
|
||||||
|
|
||||||
// 操作列宽度
|
|
||||||
static operateWidth = "140px";
|
|
||||||
|
|
||||||
@tfcpd({ "lang": "", "def": "id", fieldType: "primaryKey" })
|
|
||||||
id: number = 0;
|
|
||||||
|
|
||||||
@tcpd({ "lang": "", "def": "用车时间", minWidth: 120 })
|
|
||||||
@tfcpd({ "lang": "", "def": "用车时间", fieldType: "date", rule: [{ "type": "require", message: "不能为空" }] })
|
|
||||||
useDateTime: string = fDT(new Date(), "YYYY-MM-DD HH:mm:ss");
|
|
||||||
|
|
||||||
@tcpd({ "lang": "", "def": "联系手机", minWidth: 120 })
|
|
||||||
@tfcpd({
|
|
||||||
"lang": "", "def": "联系手机", fieldType: 'string', rule: [{ "type": "require", message: "不能为空" }]
|
|
||||||
})
|
|
||||||
contactPhone: string = "";
|
|
||||||
|
|
||||||
@tcpd({ "lang": "", "def": "起点", minWidth: 120 })
|
|
||||||
@tfcpd({
|
|
||||||
"lang": "", "def": "起点", fieldType: 'string', rule: [{ "type": "require", message: "不能为空" }]
|
|
||||||
})
|
|
||||||
beginLocation: string = "";
|
|
||||||
|
|
||||||
@tcpd({ "lang": "", "def": "终点", minWidth: 120 })
|
|
||||||
@tfcpd({
|
|
||||||
"lang": "", "def": "终点", fieldType: 'string', rule: [{ "type": "require", message: "不能为空" }]
|
|
||||||
})
|
|
||||||
endLocation: string = "";
|
|
||||||
|
|
||||||
@tcpd({ "lang": "", "def": "人数", minWidth: 120 })
|
|
||||||
@tfcpd({
|
|
||||||
"lang": "", "def": "人数", fieldType: 'number', rule: [{ "type": "require", message: "不能为空" }],
|
|
||||||
cascadeFiled: ['sum']
|
|
||||||
})
|
|
||||||
total: number = 1;
|
|
||||||
|
|
||||||
@tcpd({ "lang": "", "def": "单价", minWidth: 120 })
|
|
||||||
@tfcpd({
|
|
||||||
"lang": "", "def": "单价", fieldType: 'number', rule: [{ "type": "require", message: "不能为空" }],
|
|
||||||
cascadeFiled: ['sum']
|
|
||||||
})
|
|
||||||
price: number = 100;
|
|
||||||
|
|
||||||
@tcpd({ "lang": "", "def": "总价", minWidth: 120 })
|
|
||||||
@tfcpd({
|
|
||||||
"lang": "", "def": "总价", fieldType: "string",
|
|
||||||
disabled: true,
|
|
||||||
getData(formModel) {
|
|
||||||
return Number(formModel.total) * Number(formModel.price);
|
|
||||||
},
|
|
||||||
isCascade: true
|
|
||||||
})
|
|
||||||
sum: number = 0;
|
|
||||||
|
|
||||||
@tcpd({
|
|
||||||
"lang": "", "def": "状态", minWidth: 120, columnRender(value) {
|
|
||||||
let content = "";
|
|
||||||
switch (value) {
|
|
||||||
case 0:
|
|
||||||
content = "待完成";
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
content = "已完成";
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
content = "已取消";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return h("div", content);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@tfcpd({
|
|
||||||
"lang": "", "def": "状态", fieldType: "select",
|
|
||||||
disabled: true,
|
|
||||||
getData() {
|
|
||||||
return {
|
|
||||||
data: [
|
|
||||||
{ label: "待完成", value: 0 },
|
|
||||||
{ label: "已完成", value: 1 },
|
|
||||||
{ label: "已取消", value: 2 }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@tsfpd({
|
|
||||||
lang: "", "def": "订单状态", fieldType: "select", async getData() {
|
|
||||||
return {
|
|
||||||
data: [{
|
|
||||||
label: "待完成",
|
|
||||||
value: 0
|
|
||||||
}, {
|
|
||||||
label: "已完成",
|
|
||||||
value: 1
|
|
||||||
}, {
|
|
||||||
label: "已取消",
|
|
||||||
value: 2
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
status: TStatus = 0;
|
|
||||||
|
|
||||||
static userId: any;
|
|
||||||
|
|
||||||
@tcmd({ "key": "table:searchFormMethod", "value": { "type": "getList", "es": "onAfter" } })
|
|
||||||
getList = async (params: any) => {
|
|
||||||
return await api.getTravelInformationList(params);
|
|
||||||
}
|
|
||||||
|
|
||||||
@tcmd({
|
|
||||||
"key": "table:toolbar", "value": {
|
|
||||||
"type": "添加", "priority": 1, "es": "onAfter", "dialogContent": UmTableForm, "dialogTitle": "增加", "dialogWidth": 650
|
|
||||||
}
|
|
||||||
})
|
|
||||||
onAdd = async (data: any) => {
|
|
||||||
const { code, msg } = await api.addTravelInformation({ ...data, userId: TravelInformation.userId });
|
|
||||||
if (code != 0) {
|
|
||||||
return { code: 1, message: msg };
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return { code: 0 };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取详情数据
|
|
||||||
*/
|
|
||||||
@tcmd({ "value": { "type": "edit", "es": "onBefore", "dialogContent": UmTableForm, "dialogTitle": "编辑" } })
|
|
||||||
getDetail = async (rowId: number, r, meta) => {
|
|
||||||
const { data } = await api.getTravelInformation({ id: rowId });
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@tcmd({
|
|
||||||
"value": {
|
|
||||||
"type": "edit", "es": "onAfter",
|
|
||||||
sort: 2,
|
|
||||||
// isShow
|
|
||||||
}
|
|
||||||
})
|
|
||||||
onEdit = async (params: any) => {
|
|
||||||
const { code, msg } = await api.updateTravelInformation({ ...params, userId: TravelInformation.userId });
|
|
||||||
if (code != 0) {
|
|
||||||
return { code: 1, message: msg };
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return { code: 0 };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// @tcmd({
|
|
||||||
// "value": {
|
|
||||||
// "type": "del", "es": "onAfter", "dialogContent": "确定要删除该条数据吗?",
|
|
||||||
// sort: 3,
|
|
||||||
// // isShow
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
delByIds = async (rowId: number) => {
|
|
||||||
const { code, msg } = await api.deleteTravelInformation({ ids: [rowId] });
|
|
||||||
if (code != 0) {
|
|
||||||
return { code: 1, message: msg };
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return { code: 0 };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// @tcmd({
|
|
||||||
// "value": {
|
|
||||||
// "id": 1, "type": "customOperateEvent", "title": "详情",
|
|
||||||
// sort: 1,
|
|
||||||
// isShow: (rowData) => {
|
|
||||||
// if (rowData?.snaper_image > 0) {
|
|
||||||
// return true;
|
|
||||||
// } else {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// jumpEmployee = (rowId: number) => {
|
|
||||||
// return rowId;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
|
|
||||||
import 'reflect-metadata';
|
|
||||||
import {
|
|
||||||
TableColumnPropertyDecorator as tcpd,
|
|
||||||
TableFormColumnPropertyDecorator as tfcpd,
|
|
||||||
TableColumnMethodDecorator as tcmd, TOperateType,
|
|
||||||
TableSearchFormPropertyDecorator as tsfpd,
|
|
||||||
UmTableForm
|
|
||||||
} from "funjiaui";
|
|
||||||
import { h } from 'vue';
|
|
||||||
|
|
||||||
export default class UpServer {
|
|
||||||
@tfcpd({
|
|
||||||
"lang": "", "def": "平台注册", "fieldType": "select",
|
|
||||||
getData: () => {
|
|
||||||
return {
|
|
||||||
data: [{ label: "不启用", value: 0 },
|
|
||||||
{ label: "", value: 1 }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
rule: [{ "type": "require", message: "不能为空" }]
|
|
||||||
})
|
|
||||||
type: number = 0;
|
|
||||||
|
|
||||||
@tfcpd({ "lang": "", "def": "注册id", rule: [{ "type": "require", message: "不能为空" }] })
|
|
||||||
id: string = "";
|
|
||||||
|
|
||||||
@tfcpd({ "lang": "", "def": "服务器地址", rule: [{ "type": "require", message: "不能为空" }, { "type": "ip" }] })
|
|
||||||
ip: string = "";
|
|
||||||
|
|
||||||
@tfcpd({ "lang": "", "def": "服务器端口", rule: [{ "type": "require", message: "不能为空" }, { "type": "port" }] })
|
|
||||||
port: string = "";
|
|
||||||
|
|
||||||
@tfcpd({
|
|
||||||
"lang": "", "def": "服务状态", component: (props) => {
|
|
||||||
return props?.modelValue;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
manage_status: string = "Success";
|
|
||||||
|
|
||||||
@tfcpd({ "lang": "", "def": "Kafka服务地址", rule: [{ "type": "require", message: "不能为空" }, { "type": "ip" }] })
|
|
||||||
kafka_ip: string = "";
|
|
||||||
|
|
||||||
@tfcpd({ "lang": "", "def": "Kafka端口", rule: [{ "type": "require", message: "不能为空" }, { "type": "port" }] })
|
|
||||||
kafka_port: string = "";
|
|
||||||
|
|
||||||
@tfcpd({
|
|
||||||
"lang": "", "def": "Kafka状态", component: (props) => {
|
|
||||||
return props?.modelValue;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
kafka_status: string = "Success";
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
import { createApp } from 'vue'
|
|
||||||
import DeviceList from '@/views/DeviceList.vue'
|
|
||||||
|
|
||||||
createApp(DeviceList).mount('#app')
|
|
||||||
+22
-13
@@ -1,15 +1,10 @@
|
|||||||
import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
|
import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
|
||||||
// import { ManageRouterFuncIds } from "@/utils/constant";
|
|
||||||
// import SystemInfo from "@/views/SystemInfo.vue";
|
|
||||||
// import SystemLog from "@/views/SystemLog.vue";
|
|
||||||
// import UpServer from "@/views/UpServer.vue";
|
|
||||||
// import Sett from "@/views/Sett.vue";
|
|
||||||
// import DeviceList from "@/views/DeviceList.vue";
|
|
||||||
// import CaptureObjectList from "@/views/CaptureObjectList.vue";
|
|
||||||
import TravelInformation from "@/views/TravelInformation.vue";
|
|
||||||
import Employee from "@/views/Employee.vue";
|
import Employee from "@/views/Employee.vue";
|
||||||
import Notice from "@/views/Notice.vue";
|
import Notice from "@/views/Notice.vue";
|
||||||
import QA from "@/views/QA.vue";
|
import QA from "@/views/QA.vue";
|
||||||
|
import DataDict from "@/views/DataDict.vue";
|
||||||
|
import DynamicTable from "@/views/DynamicTable.vue";
|
||||||
|
import Plugin from "@/views/Plugin.vue";
|
||||||
|
|
||||||
const routes: Array<RouteRecordRaw | any> = [
|
const routes: Array<RouteRecordRaw | any> = [
|
||||||
{
|
{
|
||||||
@@ -23,11 +18,7 @@ const routes: Array<RouteRecordRaw | any> = [
|
|||||||
{
|
{
|
||||||
path: "/app",
|
path: "/app",
|
||||||
component: () => import("@/components/Layout.vue"),
|
component: () => import("@/components/Layout.vue"),
|
||||||
children: [
|
children: [
|
||||||
{
|
|
||||||
path: "/app/TravelInformation",
|
|
||||||
component: TravelInformation,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: "/app/Employee",
|
path: "/app/Employee",
|
||||||
component: Employee,
|
component: Employee,
|
||||||
@@ -39,6 +30,24 @@ const routes: Array<RouteRecordRaw | any> = [
|
|||||||
{
|
{
|
||||||
path: "/app/QA",
|
path: "/app/QA",
|
||||||
component: QA,
|
component: QA,
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// path: "/app/tag",
|
||||||
|
// component: Tag,
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
path: "/app/dynamicTable/:name/:path/:title?",
|
||||||
|
// component: Record,
|
||||||
|
component: DynamicTable,
|
||||||
|
// 动态表格
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/app/dataDict",
|
||||||
|
component: DataDict,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/app/plugin",
|
||||||
|
component: Plugin,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
import { createApp } from 'vue'
|
|
||||||
import Sett from '@/views/Sett.vue'
|
|
||||||
|
|
||||||
createApp(Sett).mount('#app')
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
import { createApp } from 'vue'
|
|
||||||
import SystemInfo from '@/views/SystemInfo.vue'
|
|
||||||
|
|
||||||
createApp(SystemInfo).mount('#app')
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
import { createApp } from 'vue'
|
|
||||||
import SystemLog from '@/views/SystemLog.vue'
|
|
||||||
|
|
||||||
createApp(SystemLog).mount('#app')
|
|
||||||
-50
@@ -1,50 +0,0 @@
|
|||||||
function countSquaresInContainer(x, y, objList) {
|
|
||||||
const containerEffectiveArea = x * y;
|
|
||||||
let currentArea = { count: 0 };
|
|
||||||
const innerObj = [];
|
|
||||||
let count = 0;
|
|
||||||
while (true) {
|
|
||||||
count = 0;
|
|
||||||
objList.forEach(obj => {
|
|
||||||
if (calcSquare(obj, containerEffectiveArea, currentArea)) {
|
|
||||||
innerObj.push(obj);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (count == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return innerObj
|
|
||||||
}
|
|
||||||
|
|
||||||
const calcSquare = (obj, containerEffectiveArea, currentArea) => {
|
|
||||||
const totalArea = obj.width * obj.height + currentArea.count;
|
|
||||||
if (totalArea < containerEffectiveArea) {
|
|
||||||
currentArea.count = totalArea;
|
|
||||||
// console.log(totalArea);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const containerWidth = 793.7,
|
|
||||||
containerHeight = 1122.5,
|
|
||||||
|
|
||||||
square1Width = 100,
|
|
||||||
square1Height = 100,
|
|
||||||
|
|
||||||
square2Width = 200,
|
|
||||||
square2Height = 100,
|
|
||||||
|
|
||||||
square3Width = 160,
|
|
||||||
square3Height = 40;
|
|
||||||
|
|
||||||
const value = countSquaresInContainer(containerWidth, containerHeight, [{ width: square1Width, height: square1Height, type: 1 }, {
|
|
||||||
width: square3Width, height: square3Width, type: 3
|
|
||||||
},{
|
|
||||||
width: square2Width, height: square2Width, type: 2
|
|
||||||
}]);
|
|
||||||
|
|
||||||
console.log(value.sort((a, b) => a.type -b.type ));
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
import { createApp } from 'vue'
|
|
||||||
import UpServer from '@/views/UpServer.vue'
|
|
||||||
|
|
||||||
createApp(UpServer).mount('#app')
|
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="$style['device-list']">
|
||||||
|
<h2>数据字典列表</h2>
|
||||||
|
<um-table-class-enhance class="role-right" :target="Record" :data="[]"
|
||||||
|
:other-params="{ userId: appStore.userInfo?.id }" @data-change="onDataChange"
|
||||||
|
@fire="onFire">
|
||||||
|
</um-table-class-enhance>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
// import UmTableClassEnhance from "@/components/UmTable/UmByClassEnhance.vue";
|
||||||
|
import { UmByClassEnhance as UmTableClassEnhance } from "funjiaui";
|
||||||
|
import Record from "@/containers/viewModel/DataDict";
|
||||||
|
import ImgPreview from "@/components/ImgPreview.vue";
|
||||||
|
import { ref, reactive, watch } from "vue";
|
||||||
|
import CaptureList from "@/containers/CaptureList.vue";
|
||||||
|
import { useAppStore } from "@/store/app";
|
||||||
|
|
||||||
|
const visible = ref(false);
|
||||||
|
const imgIndex = ref(0);
|
||||||
|
const ipcImgList = ref([]);
|
||||||
|
const imgPreviewInfo = reactive({
|
||||||
|
id: "",
|
||||||
|
imgUrl: "",
|
||||||
|
position: "",
|
||||||
|
time: "",
|
||||||
|
deviceName: ""
|
||||||
|
});
|
||||||
|
const currentDeviceId = ref(null);
|
||||||
|
const appStore = useAppStore();
|
||||||
|
// const formData = reactive<Notice>(traveInfomation)
|
||||||
|
|
||||||
|
|
||||||
|
const onDataChange = (data) => {
|
||||||
|
// ipcImgList.value = data || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const onFire = async (key: string, value, data: any) => {
|
||||||
|
// imgIndex.value = 0;
|
||||||
|
// const resData = await api.getCaputreImgListByIpcId({ id: data })
|
||||||
|
// ipcImgList.value = resData.data?.objectList || [];
|
||||||
|
// initImgPreviewInfo(ipcImgList.value?.[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style module lang="scss">
|
||||||
|
:global {
|
||||||
|
:local(.device-list) {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local(.img-preview-dialog) {
|
||||||
|
:local(.footer) {
|
||||||
|
margin-top: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
>div {
|
||||||
|
margin-left: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div :class="$style['device-list']">
|
|
||||||
<h2>摄像机列表</h2>
|
|
||||||
<um-table-class-enhance class="role-right" :target="Ipc" :data="[]" @data-change="onDataChange" @fire="onFire">
|
|
||||||
</um-table-class-enhance>
|
|
||||||
<um-dialog v-model="visible" top="60px" :custom-class="$style['img-preview-dialog']" title="" width="1700px"
|
|
||||||
:footer="false">
|
|
||||||
<div :style="{ height: '660px' }">
|
|
||||||
<capture-list :device-ids="[currentDeviceId]" :imgListContainerHeight="580"></capture-list>
|
|
||||||
</div>
|
|
||||||
</um-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
|
||||||
// import UmTableClassEnhance from "@/components/UmTable/UmByClassEnhance.vue";
|
|
||||||
// import UmDialog from "@/components/UmDialog/index.vue";
|
|
||||||
import { UmByClassEnhance as UmTableClassEnhance,UmDialog } from "funjiaui";
|
|
||||||
import Ipc from "@/containers/viewModel/Ipc";
|
|
||||||
import ImgPreview from "@/components/ImgPreview.vue";
|
|
||||||
import { ref, reactive, watch } from "vue";
|
|
||||||
import * as api from "@/common/api";
|
|
||||||
// import { fDT } from "marsLib/date";
|
|
||||||
import CaptureList from "@/containers/CaptureList.vue";
|
|
||||||
|
|
||||||
const visible = ref(false);
|
|
||||||
const imgIndex = ref(0);
|
|
||||||
const ipcImgList = ref([]);
|
|
||||||
const imgPreviewInfo = reactive({
|
|
||||||
id: "",
|
|
||||||
imgUrl: "",
|
|
||||||
position: "",
|
|
||||||
time: "",
|
|
||||||
deviceName: ""
|
|
||||||
});
|
|
||||||
const currentDeviceId = ref(null);
|
|
||||||
|
|
||||||
Ipc.singleListen = (rowData) => {
|
|
||||||
initImgPreviewInfo(rowData);
|
|
||||||
imgIndex.value = (ipcImgList.value || []).findIndex(item => rowData.id == item.id) || 0;
|
|
||||||
visible.value = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const initImgPreviewInfo = (data) => {
|
|
||||||
imgPreviewInfo.id = data?.["id"];
|
|
||||||
imgPreviewInfo.imgUrl = data?.["imgUrl"];
|
|
||||||
imgPreviewInfo.position = data?.["position"];
|
|
||||||
imgPreviewInfo.time = data?.["time"];
|
|
||||||
imgPreviewInfo.deviceName = data?.["deviceName"];
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(imgIndex, (i) => {
|
|
||||||
initImgPreviewInfo(ipcImgList.value?.[i]);
|
|
||||||
})
|
|
||||||
|
|
||||||
watch(visible, () => {
|
|
||||||
if (!visible) {
|
|
||||||
imgIndex.value = 0;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
const onDataChange = (data) => {
|
|
||||||
// ipcImgList.value = data || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const onImgIdxChange = (idx: TImgPreviewIdx) => {
|
|
||||||
let tempIdx = imgIndex.value;
|
|
||||||
tempIdx += idx;
|
|
||||||
|
|
||||||
if (tempIdx >= 0 && tempIdx < ipcImgList.value?.length) {
|
|
||||||
imgIndex.value = tempIdx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const onFire = async (key: string, value, data: any) => {
|
|
||||||
// imgIndex.value = 0;
|
|
||||||
// const resData = await api.getCaputreImgListByIpcId({ id: data })
|
|
||||||
// ipcImgList.value = resData.data?.objectList || [];
|
|
||||||
// initImgPreviewInfo(ipcImgList.value?.[0]);
|
|
||||||
currentDeviceId.value = value;
|
|
||||||
visible.value = true;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style module lang="scss">
|
|
||||||
:global {
|
|
||||||
:local(.device-list) {
|
|
||||||
padding: 20px;
|
|
||||||
background-color: #FFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
:local(.img-preview-dialog) {
|
|
||||||
:local(.footer) {
|
|
||||||
margin-top: 20px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
|
|
||||||
>div {
|
|
||||||
margin-left: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="$style['device-list']">
|
||||||
|
<h2>{{ router.params?.title || router.params?.name }}</h2>
|
||||||
|
<um-table-class-enhance v-if="obj" class="role-right" :target="obj" :data="[]"
|
||||||
|
:other-params="{ userId: appStore.userInfo?.id }" @data-change="onDataChange" @fire="onFire">
|
||||||
|
</um-table-class-enhance>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
// import UmTableClassEnhance from "@/components/UmTable/UmByClassEnhance.vue";
|
||||||
|
import { UmByClassEnhance as UmTableClassEnhance } from "funjiaui";
|
||||||
|
// import UmDialog from "@/components/UmDialog/index.vue";
|
||||||
|
// import RecordUser from "@/containers/viewModel/RecordUser";
|
||||||
|
// import ImgPreview from "@/components/ImgPreview.vue";
|
||||||
|
import { ref, reactive, watch, onMounted } from "vue";
|
||||||
|
import { useAppStore } from "@/store/app";
|
||||||
|
// import ThirdPartyLoader from "@/common/ThirdPartyLoader"
|
||||||
|
import { useRoute, onBeforeRouteUpdate } from "vue-router";
|
||||||
|
|
||||||
|
// async function loadModuleFromUrl(url) {
|
||||||
|
// const response = await fetch(url);
|
||||||
|
// const moduleCode = await response.text();
|
||||||
|
|
||||||
|
// // 创建一个新的模块
|
||||||
|
// const module = new Function('module', 'exports', moduleCode);
|
||||||
|
|
||||||
|
// // 执行模块
|
||||||
|
// const exports = {};
|
||||||
|
// module({ exports });
|
||||||
|
|
||||||
|
// return exports;
|
||||||
|
// }
|
||||||
|
|
||||||
|
class ThirdPartyLoader {
|
||||||
|
loadedModules: any = {};
|
||||||
|
constructor() {
|
||||||
|
this.loadedModules = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
loadModule(moduleName, url) {
|
||||||
|
if (!this.loadedModules[moduleName]) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.src = url;
|
||||||
|
script.onload = () => {
|
||||||
|
this.loadedModules[moduleName] = true;
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
script.onerror = (error) => {
|
||||||
|
reject(error);
|
||||||
|
};
|
||||||
|
document.body.appendChild(script);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const visible = ref(false);
|
||||||
|
const imgIndex = ref(0);
|
||||||
|
const ipcImgList = ref([]);
|
||||||
|
const imgPreviewInfo = reactive({
|
||||||
|
id: "",
|
||||||
|
imgUrl: "",
|
||||||
|
position: "",
|
||||||
|
time: "",
|
||||||
|
deviceName: ""
|
||||||
|
});
|
||||||
|
const currentDeviceId = ref(null);
|
||||||
|
const appStore = useAppStore();
|
||||||
|
const obj = ref(null);
|
||||||
|
const router = useRoute();
|
||||||
|
|
||||||
|
// const formData = reactive<Notice>(traveInfomation)
|
||||||
|
|
||||||
|
function capitalizeFirstLetter(str) {
|
||||||
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const { name, path } = router.params;
|
||||||
|
await new ThirdPartyLoader().loadModule(name, "/static/" + path + ".js")
|
||||||
|
// console.log(window[capitalizeFirstLetter(name)]);
|
||||||
|
obj.value = window[capitalizeFirstLetter(name)];
|
||||||
|
// 使用示例
|
||||||
|
// loadModuleFromUrl('/box-admin.iife.js').then(module => {
|
||||||
|
// // 在这里使用导入的模块
|
||||||
|
// // const t=new module;
|
||||||
|
// console.log(module);
|
||||||
|
// });
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(() => router.params.name, async () => {
|
||||||
|
const { name, path } = router.params;
|
||||||
|
await new ThirdPartyLoader().loadModule(name, "/static/" + path + ".js")
|
||||||
|
// console.log(window[capitalizeFirstLetter(name)]);
|
||||||
|
obj.value = window[capitalizeFirstLetter(name)];
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
onBeforeRouteUpdate((to, from) => {
|
||||||
|
// 在此处执行刷新相关的操作
|
||||||
|
debugger;
|
||||||
|
});
|
||||||
|
|
||||||
|
const onDataChange = (data) => {
|
||||||
|
// ipcImgList.value = data || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const onFire = async (key: string, value, data: any) => {
|
||||||
|
// imgIndex.value = 0;
|
||||||
|
// const resData = await api.getCaputreImgListByIpcId({ id: data })
|
||||||
|
// ipcImgList.value = resData.data?.objectList || [];
|
||||||
|
// initImgPreviewInfo(ipcImgList.value?.[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style module lang="scss">
|
||||||
|
:global {
|
||||||
|
:local(.device-list) {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local(.img-preview-dialog) {
|
||||||
|
:local(.footer) {
|
||||||
|
margin-top: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
>div {
|
||||||
|
margin-left: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
+5
-329
@@ -1,317 +1,22 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :class="$style['device-list']">
|
<div :class="$style['device-list']">
|
||||||
<h2>用戶列表</h2>
|
<h2>用戶列表</h2>
|
||||||
<!-- <um-table-class-enhance class="role-right" :target="Employee" :data="[]" @data-change="onDataChange"
|
<um-table-class-enhance class="role-right" :target="Employee" :data="[]" @data-change="onDataChange" @fire="onFire">
|
||||||
@fire="onFire">
|
</um-table-class-enhance>
|
||||||
</um-table-class-enhance>
|
|
||||||
<um-table-class-enhance2 class="role-right" :target="Employee" :data="[]" @data-change="onDataChange"
|
|
||||||
@fire="onFire">
|
|
||||||
</um-table-class-enhance2>
|
|
||||||
<um-dialog v-model="visible" top="60px" :custom-class="$style['img-preview-dialog']" title="" width="1700px"
|
|
||||||
:footer="false">
|
|
||||||
<div :style="{ height: '660px' }">
|
|
||||||
<capture-list :device-ids="[currentDeviceId]" :imgListContainerHeight="580"></capture-list>
|
|
||||||
</div>
|
|
||||||
</um-dialog> -->
|
|
||||||
<div :class="$style['params-field']"><label>宽度:</label><div><el-input v-model="widthHeigth.width"/></div></div>
|
|
||||||
<div :class="$style['params-field']"><label>高度:</label><div><el-input v-model="widthHeigth.height"/></div></div>
|
|
||||||
<div :class="$style['params-field']"><label>内边距:</label><div><el-input v-model="widthHeigth.padding"/></div></div>
|
|
||||||
<div :class="$style['params-field']"><label>字号:</label><div><el-input v-model="widthHeigth.fontSize"/></div></div>
|
|
||||||
<div :class="$style['params-field']"><label>字色:</label><div><el-input v-model="widthHeigth.fontColor"/></div></div>
|
|
||||||
<div :class="$style['params-field']"><label>itemMargin:</label><div><el-input v-model="itemMargin"/></div></div>
|
|
||||||
<div :class="$style['params-field']"><label>gridWidth:</label><div><el-input v-model="gridWidth"/></div></div>
|
|
||||||
<div :class="$style['params-field']"><el-button @click="onFreeLayout">自由排版</el-button></div>
|
|
||||||
<div :class="$style['params-field']"><el-button @click="print">打印</el-button></div>
|
|
||||||
<DndProvider :backend="HTML5Backend">
|
|
||||||
<Box2 id="111" :index="1" v-bind="box1Data"/>
|
|
||||||
<Box3 id="112" :index="2" v-bind="box2Data"/>
|
|
||||||
<Box4 id="112" :index="2" v-bind="box3Data"/>
|
|
||||||
<div ref="a4ContainerRef" :class="$style['a4']" id="a4">
|
|
||||||
<Container ref="a4Ref" :item-margin="itemMargin" :grid-width="gridWidth"></Container>
|
|
||||||
</div>
|
|
||||||
</DndProvider>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// import { UmByClassEnhance as UmTableClassEnhance2 } from "funjiaui/um_table.es.js";
|
import { UmByClassEnhance as UmTableClassEnhance,UmDialog } from "funjiaui";
|
||||||
import { Printd } from 'printd'
|
|
||||||
import html2pdf from "html2pdf.js";
|
|
||||||
// import { UmByClassEnhance as UmTableClassEnhance2 } from "../../lib/funjiaui.es.js";
|
|
||||||
// import UmTableClassEnhance from "@/components/UmTable/UmByClassEnhance.vue";
|
|
||||||
// import "funjiaui/style.css";
|
|
||||||
import UmDialog from "funjiaui";
|
|
||||||
import Employee from "@/containers/viewModel/Employee";
|
import Employee from "@/containers/viewModel/Employee";
|
||||||
|
import { ref, reactive, watch } from "vue";
|
||||||
import { ref, reactive, watch,onMounted,onUnmounted, computed } from "vue";
|
|
||||||
import * as api from "@/common/api";
|
|
||||||
// import { fDT } from "marsLib/date";
|
|
||||||
import CaptureList from "@/containers/CaptureList.vue";
|
|
||||||
import { DndProvider } from 'vue3-dnd'
|
|
||||||
import { HTML5Backend } from 'react-dnd-html5-backend'
|
|
||||||
import Container from "@/views/Employee/A4.vue";
|
|
||||||
import Box2 from "./Employee/Box2.vue";
|
|
||||||
import { Box } from "./Employee/boxType.js";
|
|
||||||
import Box3 from "./Employee/Box3.vue";
|
|
||||||
import Box4 from "./Employee/Box4.vue";
|
|
||||||
|
|
||||||
|
|
||||||
const containerWidth=793.7;
|
|
||||||
const containerHeight=ref(1100);
|
|
||||||
|
|
||||||
const visible = ref(false);
|
const visible = ref(false);
|
||||||
const imgIndex = ref(0);
|
|
||||||
const ipcImgList = ref([]);
|
|
||||||
const imgPreviewInfo = reactive({
|
|
||||||
id: "",
|
|
||||||
imgUrl: "",
|
|
||||||
position: "",
|
|
||||||
time: "",
|
|
||||||
deviceName: ""
|
|
||||||
});
|
|
||||||
const currentTemplateType = ref("Box1");
|
|
||||||
const widthHeigth=reactive({
|
|
||||||
width:74,
|
|
||||||
height:46,
|
|
||||||
padding:0,
|
|
||||||
fontSize:12,
|
|
||||||
fontColor:"black"
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
const templateOption:ITemplate[]=reactive([
|
|
||||||
{
|
|
||||||
type:"Box1",
|
|
||||||
width:74,
|
|
||||||
height:66,
|
|
||||||
padding:0,
|
|
||||||
fontSize:12,
|
|
||||||
fontColor:"red"
|
|
||||||
}
|
|
||||||
// ,{
|
|
||||||
// type:"Box2",
|
|
||||||
// width:48,
|
|
||||||
// height:18,
|
|
||||||
// padding:1,
|
|
||||||
// fontSize:12,
|
|
||||||
// fontColor:"black"
|
|
||||||
// },{
|
|
||||||
// type:"Box3",
|
|
||||||
// width:14,
|
|
||||||
// height:62,
|
|
||||||
// padding:1,
|
|
||||||
// fontSize:12,
|
|
||||||
// fontColor:"black"
|
|
||||||
// }
|
|
||||||
]);
|
|
||||||
|
|
||||||
const a4ContainerRef =ref();
|
|
||||||
const a4Ref =ref();
|
|
||||||
const observerRef=ref();
|
|
||||||
const itemMargin=ref(1);
|
|
||||||
const gridWidth=ref(1);
|
|
||||||
|
|
||||||
// Ipc.singleListen = (rowData) => {
|
|
||||||
// initImgPreviewInfo(rowData);
|
|
||||||
// imgIndex.value = (ipcImgList.value || []).findIndex(item => rowData.id == item.id) || 0;
|
|
||||||
// visible.value = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
watch([widthHeigth,currentTemplateType,templateOption],([_widthHeigth,_currentTemplateType,_templateOption])=>{
|
|
||||||
const data=_templateOption.find(item=>item.type==_currentTemplateType);
|
|
||||||
if(data)
|
|
||||||
{
|
|
||||||
data.width=_widthHeigth.width;
|
|
||||||
data.height=_widthHeigth.height;
|
|
||||||
data.padding=_widthHeigth.padding;
|
|
||||||
data.fontSize=_widthHeigth.fontSize;
|
|
||||||
data.fontColor=_widthHeigth.fontColor;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
onMounted(()=>{
|
|
||||||
const targetNode:any=a4ContainerRef.value;
|
|
||||||
|
|
||||||
const config={attribute:true,childList:true,subtree:true,attributeFilter:['class','style'],attributeOldValue:true,characterDataOldValue:true};
|
|
||||||
|
|
||||||
const callback=function(mutationsList,observer){
|
|
||||||
console.log(mutationsList);
|
|
||||||
for(let mutation of mutationsList){
|
|
||||||
if(mutation.type=="attributes"&&mutation.target.className=="column"){
|
|
||||||
const column=mutation.target;
|
|
||||||
// if()
|
|
||||||
console.log(column.style.transform);
|
|
||||||
const matrix3dRegex = /translate3d\((.+)\)/,
|
|
||||||
match=column.style.transform.match(matrix3dRegex);
|
|
||||||
if(match&&column.children.length>0){
|
|
||||||
const values=match[1].split(',');
|
|
||||||
const y=parseFloat(values[1]);
|
|
||||||
// 元素偏移高度加自身高度超过容器本身高度时需移除当前元素
|
|
||||||
if( y+column.children[0].offsetHeight>containerHeight.value){
|
|
||||||
// observerRef.value.disconnect();
|
|
||||||
a4Ref.value.removeLastNode();
|
|
||||||
console.log('remove');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
observerRef.value=new MutationObserver(callback);
|
|
||||||
observerRef.value.observe(targetNode,config);
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
onUnmounted(()=>{
|
|
||||||
if( observerRef.value){
|
|
||||||
observerRef.value.disconnect();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// 自由排版
|
|
||||||
const onFreeLayout=async ()=>{
|
|
||||||
a4Ref.value.clearNode();
|
|
||||||
|
|
||||||
const x=containerWidth,y=containerHeight.value;
|
|
||||||
|
|
||||||
const boxList=templateOption.map(item=>{
|
|
||||||
const box=new Box(item.width,item.height,item.padding,item.type);
|
|
||||||
box.fontSize=item.fontSize;
|
|
||||||
box.fontColor=item.fontColor;
|
|
||||||
return {width:box.getOffsetWidth(),height:box.getOffsetHeight(),origin:box};
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const value=countSquaresInContainer(x,y,boxList).sort((a,b)=>
|
|
||||||
{
|
|
||||||
return a.origin.type.localeCompare(b.origin.type);
|
|
||||||
|
|
||||||
});
|
|
||||||
console.log(value,value.length);
|
|
||||||
|
|
||||||
for(const item of value){
|
|
||||||
|
|
||||||
console.log(item.origin);
|
|
||||||
a4Ref.value.addLastNode({
|
|
||||||
...item.origin,
|
|
||||||
id: new Date().getTime()
|
|
||||||
})
|
|
||||||
await waitFor(2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function waitFor(ms){
|
|
||||||
return new Promise((resolve)=>{
|
|
||||||
setTimeout(resolve, ms);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function countSquaresInContainer(x, y, objList) {
|
|
||||||
const containerEffectiveArea = x * y;
|
|
||||||
let currentArea = { count: 0 };
|
|
||||||
const innerObj = [];
|
|
||||||
let count = 0;
|
|
||||||
while (true) {
|
|
||||||
count = 0;
|
|
||||||
objList.forEach(obj => {
|
|
||||||
if (calcSquare(obj, containerEffectiveArea, currentArea)) {
|
|
||||||
innerObj.push(obj);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (count == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return innerObj
|
|
||||||
}
|
|
||||||
|
|
||||||
const calcSquare = (obj, containerEffectiveArea, currentArea) => {
|
|
||||||
const totalArea = obj.width * obj.height + currentArea.count;
|
|
||||||
if (totalArea < containerEffectiveArea) {
|
|
||||||
currentArea.count = totalArea;
|
|
||||||
// console.log(totalArea);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const initImgPreviewInfo = (data) => {
|
|
||||||
imgPreviewInfo.id = data?.["id"];
|
|
||||||
imgPreviewInfo.imgUrl = data?.["imgUrl"];
|
|
||||||
imgPreviewInfo.position = data?.["position"];
|
|
||||||
imgPreviewInfo.time = data?.["time"];
|
|
||||||
imgPreviewInfo.deviceName = data?.["deviceName"];
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(imgIndex, (i) => {
|
|
||||||
initImgPreviewInfo(ipcImgList.value?.[i]);
|
|
||||||
})
|
|
||||||
|
|
||||||
watch(visible, () => {
|
|
||||||
if (!visible) {
|
|
||||||
imgIndex.value = 0;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
const onDataChange = (data) => {
|
const onDataChange = (data) => {
|
||||||
// ipcImgList.value = data || [];
|
// ipcImgList.value = data || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const onImgIdxChange = (idx: TImgPreviewIdx) => {
|
const onFire = async (key: string, value, data: any) => {
|
||||||
let tempIdx = imgIndex.value;
|
|
||||||
tempIdx += idx;
|
|
||||||
|
|
||||||
if (tempIdx >= 0 && tempIdx < ipcImgList.value?.length) {
|
|
||||||
imgIndex.value = tempIdx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const onFire = async (key: string, value, data: any) => {
|
|
||||||
// imgIndex.value = 0;
|
|
||||||
// const resData = await api.getCaputreImgListByIpcId({ id: data })
|
|
||||||
// ipcImgList.value = resData.data?.objectList || [];
|
|
||||||
// initImgPreviewInfo(ipcImgList.value?.[0]);
|
|
||||||
currentDeviceId.value = value;
|
|
||||||
visible.value = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const box1Data=computed(()=>{
|
|
||||||
return templateOption.find(item=>item.type=="Box1");
|
|
||||||
});
|
|
||||||
|
|
||||||
const box2Data=computed(()=>{
|
|
||||||
return templateOption.find(item=>item.type=="Box2");
|
|
||||||
});
|
|
||||||
|
|
||||||
const box3Data=computed(()=>{
|
|
||||||
return templateOption.find(item=>item.type=="Box3");
|
|
||||||
});
|
|
||||||
|
|
||||||
const containerHeightValue=computed(()=>{
|
|
||||||
return containerHeight;
|
|
||||||
});
|
|
||||||
|
|
||||||
const print=()=>{
|
|
||||||
var element = document.getElementById('a4');
|
|
||||||
var opt = {
|
|
||||||
margin: 0,
|
|
||||||
filename: 'myfile.pdf',
|
|
||||||
image: { type: 'jpeg', quality:1 },
|
|
||||||
html2canvas: { scale: 1 },
|
|
||||||
jsPDF: { unit: 'in', format: 'letter', orientation: 'portrait' }
|
|
||||||
};
|
|
||||||
|
|
||||||
// New Promise-based usage:
|
|
||||||
html2pdf().set(opt).from(element).save();
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style module lang="scss">
|
<style module lang="scss">
|
||||||
@@ -320,34 +25,5 @@ html2pdf().set(opt).from(element).save();
|
|||||||
padding: 20px;
|
padding: 20px;
|
||||||
background-color: #FFF;
|
background-color: #FFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
:local(.img-preview-dialog) {
|
|
||||||
:local(.footer) {
|
|
||||||
margin-top: 20px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
|
|
||||||
>div {
|
|
||||||
margin-left: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:local(.a4) {
|
|
||||||
width: 793.7px;
|
|
||||||
height: v-bind(containerHeightValue)+"px";
|
|
||||||
// border: 1px solid black;
|
|
||||||
}
|
|
||||||
|
|
||||||
:local(.params-field){
|
|
||||||
display:flex;
|
|
||||||
flex-direction:row;
|
|
||||||
align-items:center;
|
|
||||||
label{
|
|
||||||
// width:100px;
|
|
||||||
// flex:1;
|
|
||||||
// flex-wrap:nowrap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -1,142 +0,0 @@
|
|||||||
<template>
|
|
||||||
<!-- <el-watermark :font="font" :content="['加零', '+0']" :gap="[20,20]"> -->
|
|
||||||
<div :ref="drop" class="target-box" :class="$style['a4']">
|
|
||||||
<!-- {{ isActive ? 'Release to drop' : 'Drag item here' }} -->
|
|
||||||
<!-- <Card v-for="(card, index) in cards" :id="card.id" :key="card.id" :text="card.text" :index="index"
|
|
||||||
:move-card="moveCard" /> -->
|
|
||||||
<auto-responsive v-bind="options" :itemMargin="itemMargin" :gridWidth="gridWidth" >
|
|
||||||
<div class="column" v-for="(card, index) in cardList" :style="{height:card.getOffsetHeight()+'px',width:card.getOffsetWidth()+'px'}">
|
|
||||||
<component :is="switchCom(card)" v-bind="card" :index="index"
|
|
||||||
:moveCard="moveCard"></component>
|
|
||||||
</div>
|
|
||||||
</auto-responsive>
|
|
||||||
</div>
|
|
||||||
<!-- </el-watermark> -->
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { computed, ref, unref, h, reactive } from 'vue'
|
|
||||||
import Card from './Box1.vue'
|
|
||||||
import { useDrop } from 'vue3-dnd'
|
|
||||||
import { toRefs } from '@vueuse/core'
|
|
||||||
import Box2 from './Box2.vue';
|
|
||||||
import AutoResponsive from "../../components/autoresponsive.vue";
|
|
||||||
import { Box } from './boxType';
|
|
||||||
import Box3 from './Box3.vue';
|
|
||||||
import Box4 from './Box4.vue';
|
|
||||||
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
itemMargin: 1,
|
|
||||||
containerWidth: 793.7,
|
|
||||||
itemClassName: 'column',
|
|
||||||
gridWidth: 1,
|
|
||||||
transitionDuration: '.5'
|
|
||||||
};
|
|
||||||
|
|
||||||
const font = reactive({
|
|
||||||
color: 'rgba(0, 0, 0, .45)',
|
|
||||||
})
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
|
||||||
itemMargin: number
|
|
||||||
gridWidth: number
|
|
||||||
}>(), {
|
|
||||||
itemMargin:1,
|
|
||||||
gridWidth: 1
|
|
||||||
})
|
|
||||||
|
|
||||||
defineExpose({
|
|
||||||
addLastNode:(data)=>{
|
|
||||||
const box=new Box(data.width,data.height,data.padding,data.type);
|
|
||||||
box.fontSize=data.fontSize;
|
|
||||||
box.fontColor=data.fontColor;
|
|
||||||
cardList.value.push(box);
|
|
||||||
},
|
|
||||||
removeLastNode:()=>{
|
|
||||||
cardList.value.splice(cardList.value.length-1);
|
|
||||||
},
|
|
||||||
clearNode:()=>{
|
|
||||||
cardList.value.splice(0);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
const cards = ref<Item[]>()
|
|
||||||
|
|
||||||
const cardList = ref<IBox[]>([]);
|
|
||||||
|
|
||||||
const [collect, drop] = useDrop(() => ({
|
|
||||||
accept: 'card',
|
|
||||||
collect: (monitor) => {
|
|
||||||
return { isActive: monitor.canDrop() && monitor.isOver() }
|
|
||||||
},
|
|
||||||
drop: (item: any, monitor) => {
|
|
||||||
// console.log(monitor.canDrop(), monitor.didDrop(), monitor.getDropResult(), monitor.getItem(), item, monitor.isOver({ shallow: true }));
|
|
||||||
const boxItem:IBox=monitor.getItem() as IBox;
|
|
||||||
if (monitor.canDrop() && !monitor.didDrop() && monitor.isOver({ shallow: true })) {
|
|
||||||
const box=new Box(boxItem.width.toString(),boxItem.height.toString(),boxItem.padding.toString(),boxItem.type);
|
|
||||||
box.fontSize=boxItem.fontSize;
|
|
||||||
box.fontColor=boxItem.fontColor;
|
|
||||||
cardList.value.push(box);
|
|
||||||
console.log('add', cardList.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
const { isActive } = toRefs(collect)
|
|
||||||
|
|
||||||
interface Item {
|
|
||||||
id: number
|
|
||||||
text: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const switchCom = (item) => {
|
|
||||||
switch (item.type) {
|
|
||||||
case "Box1":
|
|
||||||
return Box2;
|
|
||||||
case "Box2":
|
|
||||||
return Box3;
|
|
||||||
case "Box3":
|
|
||||||
return Box4;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const moveCard = (dragIndex: number, hoverIndex: number) => {
|
|
||||||
const item = cards.value[dragIndex]
|
|
||||||
cards.value.splice(dragIndex, 1)
|
|
||||||
cards.value.splice(hoverIndex, 0, item)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style module lang="scss">
|
|
||||||
:global {
|
|
||||||
:local(.device-list) {
|
|
||||||
padding: 20px;
|
|
||||||
background-color: #FFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
:local(.img-preview-dialog) {
|
|
||||||
:local(.footer) {
|
|
||||||
margin-top: 20px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
|
|
||||||
>div {
|
|
||||||
margin-left: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:local(.a4) {
|
|
||||||
width: 793.7px;
|
|
||||||
// height: 1122.5px;
|
|
||||||
border: 1px solid black;
|
|
||||||
|
|
||||||
|
|
||||||
.column {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
import { computed, ref, unref } from 'vue'
|
|
||||||
import { useDrag, useDrop } from 'vue3-dnd'
|
|
||||||
// import { ItemTypes } from './ItemTypes'
|
|
||||||
import type { XYCoord, Identifier } from 'dnd-core'
|
|
||||||
import { toRefs } from '@vueuse/core'
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
id: any
|
|
||||||
text: string
|
|
||||||
index: number
|
|
||||||
moveCard: (dragIndex: number, hoverIndex: number) => void
|
|
||||||
}>()
|
|
||||||
|
|
||||||
interface DragItem {
|
|
||||||
index: number
|
|
||||||
id: string
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const card = ref<HTMLDivElement>()
|
|
||||||
const [dropCollect, drop] = useDrop<
|
|
||||||
DragItem,
|
|
||||||
void,
|
|
||||||
{ handlerId: Identifier | null }
|
|
||||||
>({
|
|
||||||
accept: 'card',
|
|
||||||
collect(monitor) {
|
|
||||||
return {
|
|
||||||
handlerId: monitor.getHandlerId(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
hover(item: DragItem, monitor) {
|
|
||||||
if (!card.value) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const dragIndex = item.index
|
|
||||||
const hoverIndex = props.index
|
|
||||||
// Don't replace items with themselves
|
|
||||||
if (dragIndex === hoverIndex) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine rectangle on screen
|
|
||||||
const hoverBoundingRect = card.value?.getBoundingClientRect()
|
|
||||||
|
|
||||||
// Get vertical middle
|
|
||||||
const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2
|
|
||||||
|
|
||||||
// Determine mouse position
|
|
||||||
const clientOffset = monitor.getClientOffset()
|
|
||||||
|
|
||||||
// Get pixels to the top
|
|
||||||
const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top
|
|
||||||
|
|
||||||
// Only perform the move when the mouse has crossed half of the items height
|
|
||||||
// When dragging downwards, only move when the cursor is below 50%
|
|
||||||
// When dragging upwards, only move when the cursor is above 50%
|
|
||||||
|
|
||||||
// Dragging downwards
|
|
||||||
if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dragging upwards
|
|
||||||
if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Time to actually perform the action
|
|
||||||
props.moveCard(dragIndex, hoverIndex)
|
|
||||||
|
|
||||||
// Note: we're mutating the monitor item here!
|
|
||||||
// Generally it's better to avoid mutations,
|
|
||||||
// but it's good here for the sake of performance
|
|
||||||
// to avoid expensive index searches.
|
|
||||||
item.index = hoverIndex
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const dragId = ref();
|
|
||||||
|
|
||||||
const [collect, drag] = useDrag({
|
|
||||||
type: 'card',
|
|
||||||
item: () => {
|
|
||||||
return { id: props.id, index: props.index, dragId: dragId.value }
|
|
||||||
},
|
|
||||||
collect: (monitor: any) => {
|
|
||||||
return ({
|
|
||||||
isDragging: monitor.isDragging(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const { handlerId } = toRefs(dropCollect)
|
|
||||||
const { isDragging } = toRefs(collect)
|
|
||||||
const opacity = computed(() => (unref(isDragging) ? 0 : 1))
|
|
||||||
|
|
||||||
const setRef = (el: HTMLDivElement) => {
|
|
||||||
card.value = drag(drop(el)) as HTMLDivElement
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div :ref="setRef" class="card" :style="{ opacity }" :data-handler-id="handlerId">
|
|
||||||
{{ text }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.card {
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
background-color: white;
|
|
||||||
border: 1px dashed gray;
|
|
||||||
cursor: move;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,166 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div :ref="setRef" class="card" :style="{ opacity }" :data-handler-id="handlerId">
|
|
||||||
<div>i5 10代</div>
|
|
||||||
<div>16g 256g</div>
|
|
||||||
<div>显卡:2060</div>
|
|
||||||
<div>加零租赁</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { computed, ref, unref, useCssVars } from 'vue'
|
|
||||||
import { useDrag, useDrop } from 'vue3-dnd'
|
|
||||||
// import { ItemTypes } from './ItemTypes'
|
|
||||||
import type { XYCoord, Identifier } from 'dnd-core'
|
|
||||||
import { toRefs } from '@vueuse/core'
|
|
||||||
import {Box} from "./boxType";
|
|
||||||
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
|
||||||
id: any
|
|
||||||
index: number
|
|
||||||
width: number
|
|
||||||
height: number
|
|
||||||
padding:number
|
|
||||||
fontSize:number
|
|
||||||
fontColor:string
|
|
||||||
moveCard?: (dragIndex: number, hoverIndex: number) => void
|
|
||||||
}>(), {
|
|
||||||
width: 100,
|
|
||||||
height: 100,
|
|
||||||
padding:10,
|
|
||||||
fontSize:18,
|
|
||||||
fontColor:"black"
|
|
||||||
})
|
|
||||||
|
|
||||||
interface DragItem {
|
|
||||||
index: number
|
|
||||||
id: string
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const BOXTYPE:TBoxType = "Box1"
|
|
||||||
const card = ref<HTMLDivElement>()
|
|
||||||
const [dropCollect, drop] = useDrop<
|
|
||||||
DragItem,
|
|
||||||
void,
|
|
||||||
{ handlerId: Identifier | null }
|
|
||||||
>({
|
|
||||||
accept: 'card',
|
|
||||||
collect(monitor) {
|
|
||||||
return {
|
|
||||||
handlerId: monitor.getHandlerId(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
hover(item: DragItem, monitor) {
|
|
||||||
if (!card.value) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const dragIndex = item.index
|
|
||||||
const hoverIndex = props.index
|
|
||||||
// Don't replace items with themselves
|
|
||||||
if (dragIndex === hoverIndex) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine rectangle on screen
|
|
||||||
const hoverBoundingRect = card.value?.getBoundingClientRect()
|
|
||||||
|
|
||||||
// Get vertical middle
|
|
||||||
const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2
|
|
||||||
|
|
||||||
// Determine mouse position
|
|
||||||
const clientOffset = monitor.getClientOffset()
|
|
||||||
|
|
||||||
// Get pixels to the top
|
|
||||||
const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top
|
|
||||||
|
|
||||||
// Only perform the move when the mouse has crossed half of the items height
|
|
||||||
// When dragging downwards, only move when the cursor is below 50%
|
|
||||||
// When dragging upwards, only move when the cursor is above 50%
|
|
||||||
|
|
||||||
// Dragging downwards
|
|
||||||
if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dragging upwards
|
|
||||||
if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Time to actually perform the action
|
|
||||||
props.moveCard(dragIndex, hoverIndex)
|
|
||||||
|
|
||||||
// Note: we're mutating the monitor item here!
|
|
||||||
// Generally it's better to avoid mutations,
|
|
||||||
// but it's good here for the sake of performance
|
|
||||||
// to avoid expensive index searches.
|
|
||||||
item.index = hoverIndex
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const dragId = ref();
|
|
||||||
|
|
||||||
const [collect, drag] = useDrag({
|
|
||||||
type: 'card',
|
|
||||||
item: ():IBox => {
|
|
||||||
const {width,height,padding,index,fontColor,fontSize}=props;
|
|
||||||
const box=new Box(width,height,padding,BOXTYPE);
|
|
||||||
box.fontSize=fontSize;
|
|
||||||
box.fontColor=fontColor;
|
|
||||||
box.index=index;
|
|
||||||
return box;
|
|
||||||
},
|
|
||||||
collect: (monitor: any) => {
|
|
||||||
return ({
|
|
||||||
isDragging: monitor.isDragging(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const { handlerId } = toRefs(dropCollect)
|
|
||||||
const { isDragging } = toRefs(collect)
|
|
||||||
const opacity = computed(() => (unref(isDragging) ? 0 : 1))
|
|
||||||
|
|
||||||
const setRef = (el: HTMLDivElement) => {
|
|
||||||
// card.value = drag(drop(el)) as HTMLDivElement
|
|
||||||
card.value = drag(el) as HTMLDivElement
|
|
||||||
}
|
|
||||||
|
|
||||||
const widthValue = computed(() => {
|
|
||||||
return props.width + "px";
|
|
||||||
})
|
|
||||||
|
|
||||||
const heightValue = computed(() => {
|
|
||||||
return props.height + "px";
|
|
||||||
})
|
|
||||||
|
|
||||||
const paddingValue=computed(()=>{
|
|
||||||
console.log("padding:",props.padding)
|
|
||||||
return props.padding+"px";
|
|
||||||
})
|
|
||||||
|
|
||||||
const fontSizeValue=computed(()=>{
|
|
||||||
console.log("padding:",props.padding)
|
|
||||||
return props.fontSize+"px";
|
|
||||||
})
|
|
||||||
|
|
||||||
const fontColorValue=computed(()=>{
|
|
||||||
console.log("padding:",props.padding)
|
|
||||||
return props.fontColor;
|
|
||||||
})
|
|
||||||
|
|
||||||
</script>
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.card {
|
|
||||||
width: v-bind(widthValue);
|
|
||||||
height:v-bind(heightValue);
|
|
||||||
// margin-bottom: 8px;
|
|
||||||
padding: v-bind(paddingValue);
|
|
||||||
font-size: v-bind(fontSizeValue);
|
|
||||||
color:v-bind(fontColorValue);
|
|
||||||
background-color: white;
|
|
||||||
border: 1px dashed gray;
|
|
||||||
cursor: move;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,163 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div :ref="setRef" class="card" :style="{ opacity }" :data-handler-id="handlerId">
|
|
||||||
加零租赁
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { computed, ref, unref, useCssVars } from 'vue'
|
|
||||||
import { useDrag, useDrop } from 'vue3-dnd'
|
|
||||||
// import { ItemTypes } from './ItemTypes'
|
|
||||||
import type { XYCoord, Identifier } from 'dnd-core'
|
|
||||||
import { toRefs } from '@vueuse/core'
|
|
||||||
import {Box} from "./boxType";
|
|
||||||
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
|
||||||
id: any
|
|
||||||
index: number
|
|
||||||
width: number
|
|
||||||
height: number
|
|
||||||
padding:number
|
|
||||||
fontSize:number
|
|
||||||
fontColor:string
|
|
||||||
moveCard?: (dragIndex: number, hoverIndex: number) => void
|
|
||||||
}>(), {
|
|
||||||
width: 60,
|
|
||||||
height: 40,
|
|
||||||
padding:2,
|
|
||||||
fontSize:12,
|
|
||||||
fontColor:"black"
|
|
||||||
})
|
|
||||||
|
|
||||||
interface DragItem {
|
|
||||||
index: number
|
|
||||||
id: string
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const BOXTYPE:TBoxType = "Box2"
|
|
||||||
const card = ref<HTMLDivElement>()
|
|
||||||
const [dropCollect, drop] = useDrop<
|
|
||||||
DragItem,
|
|
||||||
void,
|
|
||||||
{ handlerId: Identifier | null }
|
|
||||||
>({
|
|
||||||
accept: 'card',
|
|
||||||
collect(monitor) {
|
|
||||||
return {
|
|
||||||
handlerId: monitor.getHandlerId(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
hover(item: DragItem, monitor) {
|
|
||||||
if (!card.value) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const dragIndex = item.index
|
|
||||||
const hoverIndex = props.index
|
|
||||||
// Don't replace items with themselves
|
|
||||||
if (dragIndex === hoverIndex) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine rectangle on screen
|
|
||||||
const hoverBoundingRect = card.value?.getBoundingClientRect()
|
|
||||||
|
|
||||||
// Get vertical middle
|
|
||||||
const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2
|
|
||||||
|
|
||||||
// Determine mouse position
|
|
||||||
const clientOffset = monitor.getClientOffset()
|
|
||||||
|
|
||||||
// Get pixels to the top
|
|
||||||
const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top
|
|
||||||
|
|
||||||
// Only perform the move when the mouse has crossed half of the items height
|
|
||||||
// When dragging downwards, only move when the cursor is below 50%
|
|
||||||
// When dragging upwards, only move when the cursor is above 50%
|
|
||||||
|
|
||||||
// Dragging downwards
|
|
||||||
if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dragging upwards
|
|
||||||
if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Time to actually perform the action
|
|
||||||
props.moveCard(dragIndex, hoverIndex)
|
|
||||||
|
|
||||||
// Note: we're mutating the monitor item here!
|
|
||||||
// Generally it's better to avoid mutations,
|
|
||||||
// but it's good here for the sake of performance
|
|
||||||
// to avoid expensive index searches.
|
|
||||||
item.index = hoverIndex
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const dragId = ref();
|
|
||||||
|
|
||||||
const [collect, drag] = useDrag({
|
|
||||||
type: 'card',
|
|
||||||
item: ():IBox => {
|
|
||||||
const {width,height,padding,index,fontColor,fontSize}=props;
|
|
||||||
const box=new Box(width,height,padding,BOXTYPE);
|
|
||||||
box.fontSize=fontSize;
|
|
||||||
box.fontColor=fontColor;
|
|
||||||
box.index=index;
|
|
||||||
return box;
|
|
||||||
},
|
|
||||||
collect: (monitor: any) => {
|
|
||||||
return ({
|
|
||||||
isDragging: monitor.isDragging(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const { handlerId } = toRefs(dropCollect)
|
|
||||||
const { isDragging } = toRefs(collect)
|
|
||||||
const opacity = computed(() => (unref(isDragging) ? 0 : 1))
|
|
||||||
|
|
||||||
const setRef = (el: HTMLDivElement) => {
|
|
||||||
// card.value = drag(drop(el)) as HTMLDivElement
|
|
||||||
card.value = drag(el) as HTMLDivElement
|
|
||||||
}
|
|
||||||
|
|
||||||
const widthValue = computed(() => {
|
|
||||||
return props.width + "px";
|
|
||||||
})
|
|
||||||
|
|
||||||
const heightValue = computed(() => {
|
|
||||||
return props.height + "px";
|
|
||||||
})
|
|
||||||
|
|
||||||
const paddingValue=computed(()=>{
|
|
||||||
console.log("padding:",props.padding)
|
|
||||||
return props.padding+"px";
|
|
||||||
})
|
|
||||||
|
|
||||||
const fontSizeValue=computed(()=>{
|
|
||||||
console.log("padding:",props.padding)
|
|
||||||
return props.fontSize+"px";
|
|
||||||
})
|
|
||||||
|
|
||||||
const fontColorValue=computed(()=>{
|
|
||||||
console.log("padding:",props.padding)
|
|
||||||
return props.fontColor;
|
|
||||||
})
|
|
||||||
|
|
||||||
</script>
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.card {
|
|
||||||
width: v-bind(widthValue);
|
|
||||||
height:v-bind(heightValue);
|
|
||||||
// margin-bottom: 8px;
|
|
||||||
padding: v-bind(paddingValue);
|
|
||||||
font-size: v-bind(fontSizeValue);
|
|
||||||
color:v-bind(fontColorValue);
|
|
||||||
background-color: white;
|
|
||||||
border: 1px dashed gray;
|
|
||||||
cursor: move;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,166 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div :ref="setRef" class="card" :style="{ opacity }" :data-handler-id="handlerId">
|
|
||||||
<span>加</span><span>零</span><span>租</span><span>赁</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { computed, ref, unref, useCssVars } from 'vue'
|
|
||||||
import { useDrag, useDrop } from 'vue3-dnd'
|
|
||||||
// import { ItemTypes } from './ItemTypes'
|
|
||||||
import type { XYCoord, Identifier } from 'dnd-core'
|
|
||||||
import { toRefs } from '@vueuse/core'
|
|
||||||
import {Box} from "./boxType";
|
|
||||||
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
|
||||||
id: any
|
|
||||||
index: number
|
|
||||||
width: number
|
|
||||||
height: number
|
|
||||||
padding:number
|
|
||||||
fontSize:number
|
|
||||||
fontColor:string
|
|
||||||
moveCard?: (dragIndex: number, hoverIndex: number) => void
|
|
||||||
}>(), {
|
|
||||||
width: 60,
|
|
||||||
height: 40,
|
|
||||||
padding:2,
|
|
||||||
fontSize:12,
|
|
||||||
fontColor:"black"
|
|
||||||
})
|
|
||||||
|
|
||||||
interface DragItem {
|
|
||||||
index: number
|
|
||||||
id: string
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const BOXTYPE:TBoxType = "Box3"
|
|
||||||
const card = ref<HTMLDivElement>()
|
|
||||||
const [dropCollect, drop] = useDrop<
|
|
||||||
DragItem,
|
|
||||||
void,
|
|
||||||
{ handlerId: Identifier | null }
|
|
||||||
>({
|
|
||||||
accept: 'card',
|
|
||||||
collect(monitor) {
|
|
||||||
return {
|
|
||||||
handlerId: monitor.getHandlerId(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
hover(item: DragItem, monitor) {
|
|
||||||
if (!card.value) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const dragIndex = item.index
|
|
||||||
const hoverIndex = props.index
|
|
||||||
// Don't replace items with themselves
|
|
||||||
if (dragIndex === hoverIndex) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine rectangle on screen
|
|
||||||
const hoverBoundingRect = card.value?.getBoundingClientRect()
|
|
||||||
|
|
||||||
// Get vertical middle
|
|
||||||
const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2
|
|
||||||
|
|
||||||
// Determine mouse position
|
|
||||||
const clientOffset = monitor.getClientOffset()
|
|
||||||
|
|
||||||
// Get pixels to the top
|
|
||||||
const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top
|
|
||||||
|
|
||||||
// Only perform the move when the mouse has crossed half of the items height
|
|
||||||
// When dragging downwards, only move when the cursor is below 50%
|
|
||||||
// When dragging upwards, only move when the cursor is above 50%
|
|
||||||
|
|
||||||
// Dragging downwards
|
|
||||||
if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dragging upwards
|
|
||||||
if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Time to actually perform the action
|
|
||||||
props.moveCard(dragIndex, hoverIndex)
|
|
||||||
|
|
||||||
// Note: we're mutating the monitor item here!
|
|
||||||
// Generally it's better to avoid mutations,
|
|
||||||
// but it's good here for the sake of performance
|
|
||||||
// to avoid expensive index searches.
|
|
||||||
item.index = hoverIndex
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const dragId = ref();
|
|
||||||
|
|
||||||
const [collect, drag] = useDrag({
|
|
||||||
type: 'card',
|
|
||||||
item: ():IBox => {
|
|
||||||
const {width,height,padding,index,fontColor,fontSize}=props;
|
|
||||||
const box=new Box(width,height,padding,BOXTYPE);
|
|
||||||
box.fontSize=fontSize;
|
|
||||||
box.fontColor=fontColor;
|
|
||||||
box.index=index;
|
|
||||||
return box;
|
|
||||||
},
|
|
||||||
collect: (monitor: any) => {
|
|
||||||
return ({
|
|
||||||
isDragging: monitor.isDragging(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const { handlerId } = toRefs(dropCollect)
|
|
||||||
const { isDragging } = toRefs(collect)
|
|
||||||
const opacity = computed(() => (unref(isDragging) ? 0 : 1))
|
|
||||||
|
|
||||||
const setRef = (el: HTMLDivElement) => {
|
|
||||||
// card.value = drag(drop(el)) as HTMLDivElement
|
|
||||||
card.value = drag(el) as HTMLDivElement
|
|
||||||
}
|
|
||||||
|
|
||||||
const widthValue = computed(() => {
|
|
||||||
return props.width + "px";
|
|
||||||
})
|
|
||||||
|
|
||||||
const heightValue = computed(() => {
|
|
||||||
return props.height + "px";
|
|
||||||
})
|
|
||||||
|
|
||||||
const paddingValue=computed(()=>{
|
|
||||||
console.log("padding:",props.padding)
|
|
||||||
return props.padding+"px";
|
|
||||||
})
|
|
||||||
|
|
||||||
const fontSizeValue=computed(()=>{
|
|
||||||
console.log("padding:",props.padding)
|
|
||||||
return props.fontSize+"px";
|
|
||||||
})
|
|
||||||
|
|
||||||
const fontColorValue=computed(()=>{
|
|
||||||
console.log("padding:",props.padding)
|
|
||||||
return props.fontColor;
|
|
||||||
})
|
|
||||||
|
|
||||||
</script>
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.card {
|
|
||||||
width: v-bind(widthValue);
|
|
||||||
height:v-bind(heightValue);
|
|
||||||
// margin-bottom: 8px;
|
|
||||||
padding: v-bind(paddingValue);
|
|
||||||
font-size: v-bind(fontSizeValue);
|
|
||||||
color:v-bind(fontColorValue);
|
|
||||||
background-color: white;
|
|
||||||
border: 1px dashed gray;
|
|
||||||
cursor: move;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div ref="watermarkContainer" class="watermark-container"></div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import { onMounted,onUnmounted,ref } from 'vue';
|
|
||||||
|
|
||||||
export default{
|
|
||||||
name:'Watermark',
|
|
||||||
setup(){
|
|
||||||
const watermarkContainer=ref(null);
|
|
||||||
|
|
||||||
const createWatermark=()=>{
|
|
||||||
if(!watermarkContainer.value)return;
|
|
||||||
|
|
||||||
const canvas=document.createElement('canvas');
|
|
||||||
const ctx=canvas.getContext('2d');
|
|
||||||
|
|
||||||
const text='Your watermark'
|
|
||||||
|
|
||||||
const fontSize=4;
|
|
||||||
ctx.font=`${fontSize}px sans-serif`;
|
|
||||||
ctx.fillStyle='rgba(128,128,128,0.3)';
|
|
||||||
ctx.textAlign='center';
|
|
||||||
ctx.textBaseline='middle';
|
|
||||||
|
|
||||||
const width=watermarkContainer.value.clientWidth;
|
|
||||||
const heigth=watermarkContainer.value.clientHeight;
|
|
||||||
|
|
||||||
const padding=20;
|
|
||||||
const lineHeight=fontSize+padding;
|
|
||||||
const columns=Math.ceil(width/lineHeight);
|
|
||||||
const rows=Math.ceil(height/lineHeight);
|
|
||||||
|
|
||||||
canvas.width=width;
|
|
||||||
canvas.height=height;
|
|
||||||
|
|
||||||
for(let i=0;i<rows;i++){
|
|
||||||
for(let j=0;j<columns;j++){
|
|
||||||
ctx.fillText(text,j*lineHeight+lineHeight/2,i*lineHeight+lineHeight/2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const watermarkImage=new Image();
|
|
||||||
watermarkImage.src=canvas.toDataURL();
|
|
||||||
watermarkImage.onload=()=>{
|
|
||||||
const watermarkDiv=document.createElement('div');
|
|
||||||
watermarkDiv.style.backgroundImage=`url(${watermarkImage.src})`;
|
|
||||||
watermarkDiv.style.backgroundRepeat='repeat';
|
|
||||||
watermarkDiv.style.position='absolute';
|
|
||||||
watermarkDiv.style.top=0;
|
|
||||||
watermarkDiv.style.left=0;
|
|
||||||
watermarkDiv.style.width='100%';
|
|
||||||
watermarkDiv.style.height='100%';
|
|
||||||
|
|
||||||
watermarkContainer.value.appendChild(watermarkDiv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(()=>{
|
|
||||||
createWatermark();
|
|
||||||
window.addEventListener('resize',createWatermark);
|
|
||||||
})
|
|
||||||
|
|
||||||
onUnmounted(()=>{
|
|
||||||
window.removeEventListener('resize',createWatermark)
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
|
||||||
watermarkContainer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.watermark-container{
|
|
||||||
position:relative;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
export class Box implements IBox {
|
|
||||||
type: TBoxType = "Box1";
|
|
||||||
width: number = 0;
|
|
||||||
height: number = 0;
|
|
||||||
padding: number = 10;
|
|
||||||
borderWidth: number = 1;
|
|
||||||
fontSize:number=18;
|
|
||||||
fontColor:string="black";
|
|
||||||
sort: number = 1;
|
|
||||||
index: number = 1
|
|
||||||
|
|
||||||
constructor(_width: string, _height: string, _padding: string | number = 10, type: TBoxType = "Box1") {
|
|
||||||
this.type = type;
|
|
||||||
this.width = parseFloat(_width);
|
|
||||||
this.height = parseFloat(_height);
|
|
||||||
this.padding = parseFloat(_padding.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
getOffsetWidth() {
|
|
||||||
return this.width + this.padding * 2 + this.borderWidth * 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
getOffsetHeight() {
|
|
||||||
return this.height + this.padding * 2 + this.borderWidth * 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export class Template implements ITemplate {
|
|
||||||
id: string = "";
|
|
||||||
width: number = 100;
|
|
||||||
height: number = 100;
|
|
||||||
padding: number = 10;
|
|
||||||
fontSize: number = 18;
|
|
||||||
fontColor: string = "#000000";
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
declare type TBoxType = "Box1" | "Box2" | "Box3" | "Box4";
|
|
||||||
|
|
||||||
declare interface IBox {
|
|
||||||
type: TBoxType;
|
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
padding: number;
|
|
||||||
fontSize:number;
|
|
||||||
fontColor:string;
|
|
||||||
sort: number;
|
|
||||||
index: number;
|
|
||||||
getOffsetWidth: () => number;
|
|
||||||
getOffsetHeight: () => number;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare interface ITemplate {
|
|
||||||
type:TBoxType;
|
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
padding: number;
|
|
||||||
fontSize: number;
|
|
||||||
fontColor: string;
|
|
||||||
}
|
|
||||||
+9
-2
@@ -2,7 +2,7 @@
|
|||||||
<div :class="$style['login']">
|
<div :class="$style['login']">
|
||||||
<div class="login-form">
|
<div class="login-form">
|
||||||
<!-- <img src="/logo.png" :style="{ marginLeft: '45px', marginBottom: '20px' }"> -->
|
<!-- <img src="/logo.png" :style="{ marginLeft: '45px', marginBottom: '20px' }"> -->
|
||||||
<h1>出行管理</h1>
|
<h1>{{systemTitle||'...'}}</h1>
|
||||||
<el-form ref="formRef" :model="form" :rules="rules">
|
<el-form ref="formRef" :model="form" :rules="rules">
|
||||||
<el-form-item prop="user">
|
<el-form-item prop="user">
|
||||||
<el-input placeholder="请输入用户名" :prefix-icon="User" size="large" v-model.trim="form.user" />
|
<el-input placeholder="请输入用户名" :prefix-icon="User" size="large" v-model.trim="form.user" />
|
||||||
@@ -23,12 +23,12 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive, ref, onBeforeMount, onBeforeUnmount, computed } from "vue";
|
import { reactive, ref, onBeforeMount, onBeforeUnmount, computed } from "vue";
|
||||||
import { ElMessage, FormItemRule } from "element-plus";
|
import { ElMessage, FormItemRule } from "element-plus";
|
||||||
import md5 from "md5";
|
|
||||||
import * as api from "@/common/api";
|
import * as api from "@/common/api";
|
||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
import { User, Lock } from "@element-plus/icons-vue";
|
import { User, Lock } from "@element-plus/icons-vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { useAppStore } from "@/store/app";
|
import { useAppStore } from "@/store/app";
|
||||||
|
import { SYSTEM_TITLE } from "@/consts/dataDict";
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const formRef = ref();
|
const formRef = ref();
|
||||||
@@ -37,6 +37,13 @@ const form = reactive({
|
|||||||
password: ""
|
password: ""
|
||||||
});
|
});
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
|
const systemTitle = ref();
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const { data: dataDict } = await api.getDynamic({ id: SYSTEM_TITLE }, "dataDict");
|
||||||
|
systemTitle.value = dataDict?.value;
|
||||||
|
}
|
||||||
|
)();
|
||||||
|
|
||||||
const rules = ref<Record<string, FormItemRule | FormItemRule[]>>({
|
const rules = ref<Record<string, FormItemRule | FormItemRule[]>>({
|
||||||
user: {
|
user: {
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :class="$style['device-list']">
|
<div :class="$style['device-list']">
|
||||||
<h2>抓拍列表</h2>
|
<h2>插件列表</h2>
|
||||||
<capture-list></capture-list>
|
<um-table-class-enhance class="role-right" :target="Plugin2" :data="[]"
|
||||||
|
:other-params="{ userId: appStore?.userInfo?.id }">
|
||||||
|
</um-table-class-enhance>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import CaptureList from '@/containers/CaptureList.vue';
|
import { UmByClassEnhance as UmTableClassEnhance } from "funjiaui";
|
||||||
|
import Plugin2 from "@/containers/viewModel/Plugin";
|
||||||
|
import { useAppStore } from "@/store/app";
|
||||||
|
|
||||||
|
const appStore = useAppStore();
|
||||||
</script>
|
</script>
|
||||||
<style module lang="scss">
|
<style module lang="scss">
|
||||||
:global {
|
:global {
|
||||||
@@ -1,311 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div :class="$style['sett']">
|
|
||||||
<h2>重启</h2>
|
|
||||||
<div>
|
|
||||||
<el-button @click="onRestartSystemConfirm">重启系统</el-button>
|
|
||||||
<el-button @click="onRestartAppConfirm">重启程序</el-button>
|
|
||||||
</div>
|
|
||||||
<h2>系统升级</h2>
|
|
||||||
<upgrade-system></upgrade-system>
|
|
||||||
<um-dialog :model-value="confirmDialog.visible" :title="confirmDialog.title" width="500px"
|
|
||||||
:show-close="confirmDialog.showClose" @on-ok="confirmMethod" :footer="confirmDialog.showFooter"
|
|
||||||
:close-on-press-escape="false" @update:model-value="onModelValueChange">
|
|
||||||
<div>{{ confirmDialog.content }}</div>
|
|
||||||
<component :is="confirmDialog.progress" :text-inside="progressParams.textInside"
|
|
||||||
:stroke-width="progressParams.strokeWidth" :percentage="progressParams.percentage"></component>
|
|
||||||
</um-dialog>
|
|
||||||
<h2>机器码</h2>
|
|
||||||
<el-link v-if="downloadFileName" type="primary" :icon="Download" href="/api/system/license/download/hostid.conf"
|
|
||||||
:download="downloadFileName">下载机器码</el-link>
|
|
||||||
<h2>更新授权信息</h2>
|
|
||||||
<license-update />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
|
||||||
import * as api from "@/common/api";
|
|
||||||
import { ElMessage, ElProgress, UploadFiles, UploadProgressEvent, UploadRawFile } from "element-plus";
|
|
||||||
import {
|
|
||||||
UploadFilled
|
|
||||||
} from '@element-plus/icons-vue'
|
|
||||||
import { UmDialog } from "funjiaui";
|
|
||||||
import { h, reactive, ref, onBeforeUnmount, onBeforeMount } from "vue";
|
|
||||||
import { toFixed } from "@/common/tool";
|
|
||||||
import { merge } from "lodash-es";
|
|
||||||
import CountDownMessage from "@/components/CountDownMessage.vue";
|
|
||||||
import { useRouter, onBeforeRouteLeave } from "vue-router";
|
|
||||||
import UpgradeSystem from "@/containers/UpgradeSystem.vue";
|
|
||||||
import LicenseUpdate from "@/containers/LicenseUpdate.vue";
|
|
||||||
import { Download } from '@element-plus/icons-vue';
|
|
||||||
|
|
||||||
const PINGURL = "/api/get/system";
|
|
||||||
// 请求成功时得到的步长,基本上4次请求就可以确定程序重启成功了
|
|
||||||
const PONGSTEP = 1 / 4;
|
|
||||||
|
|
||||||
const confirmDialog = reactive({
|
|
||||||
visible: false,
|
|
||||||
content: "",
|
|
||||||
progress: null,
|
|
||||||
showClose: true,
|
|
||||||
title: "提示",
|
|
||||||
showFooter: true
|
|
||||||
});
|
|
||||||
const progressParams = reactive({
|
|
||||||
textInside: true,
|
|
||||||
strokeWidth: 26,
|
|
||||||
percentage: 0,
|
|
||||||
maxTimeSpan: 30,// 单位:秒
|
|
||||||
startTime: null
|
|
||||||
});
|
|
||||||
// 二次确认框回调事件
|
|
||||||
const confirmMethod = ref<any>(null);
|
|
||||||
const coutDownTOV = ref();
|
|
||||||
const router = useRouter();
|
|
||||||
const downloadFileName = ref();
|
|
||||||
|
|
||||||
const closeWindow = (event) => {
|
|
||||||
// Cancel the event as stated by the standard.
|
|
||||||
event.preventDefault();
|
|
||||||
// Chrome requires returnValue to be set.
|
|
||||||
event.returnValue = '12313';
|
|
||||||
}
|
|
||||||
|
|
||||||
onBeforeMount(() => {
|
|
||||||
api.getSytemInfo().then((res) => {
|
|
||||||
downloadFileName.value = res?.sn + ".conf";
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
// 程序关闭前,清除定时器
|
|
||||||
clearTimeout(coutDownTOV.value);
|
|
||||||
window.removeEventListener('beforeunload', closeWindow);
|
|
||||||
})
|
|
||||||
|
|
||||||
onBeforeRouteLeave(() => {
|
|
||||||
if (!confirmDialog.progress) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ElMessage.warning('任务进行中,请不要操作系统');
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
})
|
|
||||||
|
|
||||||
const clear = () => {
|
|
||||||
merge(confirmDialog, {
|
|
||||||
visible: false,
|
|
||||||
content: "",
|
|
||||||
progress: null,
|
|
||||||
showClose: true
|
|
||||||
});
|
|
||||||
merge(progressParams, {
|
|
||||||
textInside: true,
|
|
||||||
strokeWidth: 26,
|
|
||||||
percentage: 0,
|
|
||||||
maxTimeSpan: 30,// 单位:秒
|
|
||||||
startTime: null
|
|
||||||
});
|
|
||||||
confirmMethod.value = null;
|
|
||||||
clearTimeout(coutDownTOV.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
const onRestartSystemConfirm = () => {
|
|
||||||
confirmDialog.visible = true;
|
|
||||||
confirmDialog.content = "确定要重启系统吗!";
|
|
||||||
|
|
||||||
confirmMethod.value = onRestartSystem;
|
|
||||||
}
|
|
||||||
|
|
||||||
const onRestartSystem = async () => {
|
|
||||||
const data = await api.restartSystem();
|
|
||||||
if (data) {
|
|
||||||
confirmDialog.title = "重启系统中...";
|
|
||||||
confirmDialog.showFooter = false;
|
|
||||||
enableProgress('重启系统程序成功');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const onRestartAppConfirm = () => {
|
|
||||||
confirmDialog.visible = true;
|
|
||||||
confirmDialog.content = "确定要重启程序吗!";
|
|
||||||
|
|
||||||
confirmMethod.value = onRestartApp;
|
|
||||||
}
|
|
||||||
|
|
||||||
const onRestartApp = async () => {
|
|
||||||
const data = await api.restartApp();
|
|
||||||
if (data) {
|
|
||||||
confirmDialog.title = "重启系统程序中...";
|
|
||||||
confirmDialog.showFooter = false;
|
|
||||||
enableProgress('重启系统程序成功');
|
|
||||||
// ElMessage.success("操作成功");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 启用进度条
|
|
||||||
*/
|
|
||||||
const enableProgress = (succMsg) => {
|
|
||||||
window.removeEventListener('beforeunload', closeWindow);
|
|
||||||
window.addEventListener('beforeunload', closeWindow);
|
|
||||||
|
|
||||||
// let total=30;
|
|
||||||
confirmDialog.content = "";
|
|
||||||
confirmDialog.progress = ElProgress;
|
|
||||||
confirmDialog.showClose = false;
|
|
||||||
|
|
||||||
progressParams.startTime = new Date();
|
|
||||||
enableCountDown(succMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
const enableCountDown = (succMsg) => {
|
|
||||||
clearTimeout(coutDownTOV.value);
|
|
||||||
coutDownTOV.value = setTimeout(async () => {
|
|
||||||
const timeSpan = new Date().getTime() - (progressParams.startTime || new Date())?.getTime();
|
|
||||||
if ((timeSpan / progressParams.maxTimeSpan / 1000) > 4 / 5) {
|
|
||||||
progressParams.percentage = progressParams.percentage < 80 ? 80 : progressParams.percentage;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const percentage = toFixed(timeSpan / 1000 / progressParams.maxTimeSpan);
|
|
||||||
progressParams.percentage = progressParams.percentage < percentage ? percentage : progressParams.percentage;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pong = await pingService();
|
|
||||||
if (pong) {
|
|
||||||
// 只要能正确获取返回值,一般4秒内就可以判定服务已经启动成功
|
|
||||||
progressParams.percentage = toFixed((parseFloat(progressParams.percentage) / 100 + PONGSTEP));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (progressParams.percentage < 100) {
|
|
||||||
enableCountDown(succMsg);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
progressParams.percentage = 100;
|
|
||||||
showMsg();
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** ping接口服务,如果ping通代表服务当前是启动状态 */
|
|
||||||
const pingService = async (): Promise<boolean> => {
|
|
||||||
try {
|
|
||||||
// 用于终止Fetch请求的控制器。
|
|
||||||
const controller = new AbortController();
|
|
||||||
const { signal } = controller;
|
|
||||||
|
|
||||||
// Promise.race 可以处理异步请求的先后问题,这里用于
|
|
||||||
// 处理接口是否按预期请求完成
|
|
||||||
const data = await Promise.race([
|
|
||||||
fetch(PINGURL, { signal }),
|
|
||||||
new Promise((resolve) => {
|
|
||||||
setTimeout(() => {
|
|
||||||
// 终止目标请求
|
|
||||||
controller.abort();
|
|
||||||
resolve({ error: true });
|
|
||||||
}, 2000)
|
|
||||||
})
|
|
||||||
]).catch((err) => {
|
|
||||||
return { error: true };
|
|
||||||
})
|
|
||||||
|
|
||||||
// 数据中未返回error字段或字段不为true时,
|
|
||||||
// 或者接口返回值中status是200|401 则表明请求是成功的
|
|
||||||
return !!!data?.error || [200, 401].includes(data?.status);
|
|
||||||
} catch (error) {
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const verifyFileType = (fileName: string) => {
|
|
||||||
const fileTypes = [".bin", ".zip", ".gz"];
|
|
||||||
const fileEnd = fileName.substring(fileName.lastIndexOf("."));
|
|
||||||
if (!fileTypes.includes(fileEnd)) {
|
|
||||||
ElMessage.warning("不支持该类型文件");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const verifyFileSize = (size: number) => {
|
|
||||||
const maxMb = 1024;
|
|
||||||
const minKb = 14;
|
|
||||||
const fileMaxSize = 1024 * maxMb;//300M
|
|
||||||
const fileMinSize = 14;
|
|
||||||
if (size > fileMaxSize) {
|
|
||||||
ElMessage.warning("附件大小不能大于" + maxMb + "GB!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (size < fileMinSize) {
|
|
||||||
ElMessage.warning("附件大小不能小于" + minKb + "KB!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const onBeforeUpload = (rawFile: UploadRawFile) => {
|
|
||||||
const fileName = rawFile.name, fileSize = rawFile.size;
|
|
||||||
const methodMap = [[verifyFileType, verifyFileSize], [fileName, fileSize]];
|
|
||||||
let result = true;
|
|
||||||
let method: any, params;
|
|
||||||
for (let i = 0; i < methodMap[0].length; i++) {
|
|
||||||
method = methodMap[0][i];
|
|
||||||
params = methodMap[1][i];
|
|
||||||
|
|
||||||
if (result && method) {
|
|
||||||
result = method?.(params);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const onError = () => {
|
|
||||||
ElMessage.error("文件上传失败");
|
|
||||||
}
|
|
||||||
|
|
||||||
const onSuccess = (response: any) => {
|
|
||||||
if (response.status == "200") {
|
|
||||||
ElMessage.success("系统升级成功");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ElMessage.error(response.reason || "文件上传失败");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const showMsg = () => {
|
|
||||||
const msgInstance = ElMessage({
|
|
||||||
type: "success",
|
|
||||||
message: h(CountDownMessage, {
|
|
||||||
getMsgTempalte(value: number) {
|
|
||||||
return `操作成功,${value}秒倒计时后将跳转到登录页!`
|
|
||||||
},
|
|
||||||
onNext() {
|
|
||||||
msgInstance.close();
|
|
||||||
clear();
|
|
||||||
router.push('/login');
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
duration: 10 * 1000
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const onModelValueChange = (value) => {
|
|
||||||
if (!confirmDialog.progress) {
|
|
||||||
confirmDialog.visible = value;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ElMessage.warning('任务进行中,请不要操作系统');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
<style module lang="scss">
|
|
||||||
:global {
|
|
||||||
:local(.sett) {
|
|
||||||
padding: 20px;
|
|
||||||
background-color: #FFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<template>
|
|
||||||
<SystemInfoFormDetail></SystemInfoFormDetail>
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
|
||||||
import SystemInfoFormDetail from "@/containers/SystemInfoFormDetail.vue"
|
|
||||||
</script>
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div :class="$style['system-log']">
|
|
||||||
<h2>系统日志</h2>
|
|
||||||
<log-info></log-info>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
|
||||||
import LogInfo from "@/containers/LogInfo.vue";
|
|
||||||
</script>
|
|
||||||
<style module lang="scss">
|
|
||||||
:global {
|
|
||||||
:local(.system-log) {
|
|
||||||
padding: 20px;
|
|
||||||
background-color: #FFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div :class="$style['device-list']">
|
|
||||||
<h2>出行列表</h2>
|
|
||||||
<um-table-class-enhance class="role-right" :target="TravelInformation" :data="[]"
|
|
||||||
:other-params="{ userId: appStore.userInfo?.id }" @data-change="onDataChange"
|
|
||||||
@fire="onFire">
|
|
||||||
</um-table-class-enhance>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { UmByClassEnhance as UmTableClassEnhance } from "funjiaui";
|
|
||||||
// import UmDialog from "@/components/UmDialog/index.vue";
|
|
||||||
import TravelInformation from "@/containers/viewModel/TravelInformation";
|
|
||||||
import ImgPreview from "@/components/ImgPreview.vue";
|
|
||||||
import { ref, reactive, watch } from "vue";
|
|
||||||
import * as api from "@/common/api";
|
|
||||||
// import { fDT } from "marsLib/date";
|
|
||||||
import CaptureList from "@/containers/CaptureList.vue";
|
|
||||||
import { useAppStore } from "@/store/app";
|
|
||||||
|
|
||||||
const visible = ref(false);
|
|
||||||
const imgIndex = ref(0);
|
|
||||||
const ipcImgList = ref([]);
|
|
||||||
const imgPreviewInfo = reactive({
|
|
||||||
id: "",
|
|
||||||
imgUrl: "",
|
|
||||||
position: "",
|
|
||||||
time: "",
|
|
||||||
deviceName: ""
|
|
||||||
});
|
|
||||||
const currentDeviceId = ref(null);
|
|
||||||
const appStore = useAppStore();
|
|
||||||
const traveInfomation = new TravelInformation();
|
|
||||||
const formData = reactive<TravelInformation>(traveInfomation)
|
|
||||||
// debugger;
|
|
||||||
TravelInformation.userId = appStore.userInfo?.id;
|
|
||||||
|
|
||||||
watch(() => appStore.userInfo, (uI) => {
|
|
||||||
// TravelInformation.userId
|
|
||||||
TravelInformation.userId = uI?.id;
|
|
||||||
})
|
|
||||||
|
|
||||||
// Ipc.singleListen = (rowData) => {
|
|
||||||
// initImgPreviewInfo(rowData);
|
|
||||||
// imgIndex.value = (ipcImgList.value || []).findIndex(item => rowData.id == item.id) || 0;
|
|
||||||
// visible.value = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
const initImgPreviewInfo = (data) => {
|
|
||||||
imgPreviewInfo.id = data?.["id"];
|
|
||||||
imgPreviewInfo.imgUrl = data?.["imgUrl"];
|
|
||||||
imgPreviewInfo.position = data?.["position"];
|
|
||||||
imgPreviewInfo.time = data?.["time"];
|
|
||||||
imgPreviewInfo.deviceName = data?.["deviceName"];
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(imgIndex, (i) => {
|
|
||||||
initImgPreviewInfo(ipcImgList.value?.[i]);
|
|
||||||
})
|
|
||||||
|
|
||||||
watch(visible, () => {
|
|
||||||
if (!visible) {
|
|
||||||
imgIndex.value = 0;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
const onDataChange = (data) => {
|
|
||||||
// ipcImgList.value = data || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const onImgIdxChange = (idx: TImgPreviewIdx) => {
|
|
||||||
let tempIdx = imgIndex.value;
|
|
||||||
tempIdx += idx;
|
|
||||||
|
|
||||||
if (tempIdx >= 0 && tempIdx < ipcImgList.value?.length) {
|
|
||||||
imgIndex.value = tempIdx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const onFire = async (key: string, value, data: any) => {
|
|
||||||
// imgIndex.value = 0;
|
|
||||||
// const resData = await api.getCaputreImgListByIpcId({ id: data })
|
|
||||||
// ipcImgList.value = resData.data?.objectList || [];
|
|
||||||
// initImgPreviewInfo(ipcImgList.value?.[0]);
|
|
||||||
currentDeviceId.value = value;
|
|
||||||
visible.value = true;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style module lang="scss">
|
|
||||||
:global {
|
|
||||||
:local(.device-list) {
|
|
||||||
padding: 20px;
|
|
||||||
background-color: #FFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
:local(.img-preview-dialog) {
|
|
||||||
:local(.footer) {
|
|
||||||
margin-top: 20px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
|
|
||||||
>div {
|
|
||||||
margin-left: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<template>
|
|
||||||
<up-server />
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
|
||||||
import UpServer from "@/containers/UpServer.vue"
|
|
||||||
</script>
|
|
||||||
@@ -26,6 +26,10 @@ export default defineConfig({
|
|||||||
target: "http://localhost:4873/",
|
target: "http://localhost:4873/",
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
},
|
},
|
||||||
|
"^/static": {
|
||||||
|
target: "http://localhost:4873/resource/",
|
||||||
|
changeOrigin: true,
|
||||||
|
},
|
||||||
"^/set/log/level": {
|
"^/set/log/level": {
|
||||||
target: "http://192.168.1.89:4873/",
|
target: "http://192.168.1.89:4873/",
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
|
|||||||
@@ -1273,6 +1273,13 @@ function-bind@^1.1.2:
|
|||||||
resolved "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
|
resolved "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
|
||||||
integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
|
integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
|
||||||
|
|
||||||
|
"funjia-axios@git+http://git.funjia.top/funjia/funjia-axios.git":
|
||||||
|
version "0.0.1"
|
||||||
|
resolved "git+http://git.funjia.top/funjia/funjia-axios.git#b76323800995e88c6fcd3ede5a87ff62f0ff0a9d"
|
||||||
|
dependencies:
|
||||||
|
axios "^0.26.1"
|
||||||
|
js-cookie "^3.0.1"
|
||||||
|
|
||||||
"funjialib@git+http://git.funjia.top/funjia/FunJiaLib_Package.git":
|
"funjialib@git+http://git.funjia.top/funjia/FunJiaLib_Package.git":
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "git+http://git.funjia.top/funjia/FunJiaLib_Package.git#07908bb596bb21750d0298460df12ba963a70fa6"
|
resolved "git+http://git.funjia.top/funjia/FunJiaLib_Package.git#07908bb596bb21750d0298460df12ba963a70fa6"
|
||||||
|
|||||||
Reference in New Issue
Block a user