fix
This commit is contained in:
Generated
+286
@@ -10,6 +10,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^2",
|
"@tauri-apps/api": "^2",
|
||||||
"@tauri-apps/plugin-opener": "^2",
|
"@tauri-apps/plugin-opener": "^2",
|
||||||
|
"pdfjs-dist": "^5.6.205",
|
||||||
"vant": "^4.10.0",
|
"vant": "^4.10.0",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-router": "^4.6.4"
|
"vue-router": "^4.6.4"
|
||||||
@@ -516,6 +517,271 @@
|
|||||||
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@napi-rs/canvas": {
|
||||||
|
"version": "0.1.100",
|
||||||
|
"resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.100.tgz",
|
||||||
|
"integrity": "sha512-xglYA6q3XO5P3BNJYxVZ1IV7DLVjp1Py6nwag88YntrS+3vKHyYcMqXVS4ZztJmwz2uGvz1FWhI/4LgbR5uQDA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"workspaces": [
|
||||||
|
"e2e/*"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/Brooooooklyn"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@napi-rs/canvas-android-arm64": "0.1.100",
|
||||||
|
"@napi-rs/canvas-darwin-arm64": "0.1.100",
|
||||||
|
"@napi-rs/canvas-darwin-x64": "0.1.100",
|
||||||
|
"@napi-rs/canvas-linux-arm-gnueabihf": "0.1.100",
|
||||||
|
"@napi-rs/canvas-linux-arm64-gnu": "0.1.100",
|
||||||
|
"@napi-rs/canvas-linux-arm64-musl": "0.1.100",
|
||||||
|
"@napi-rs/canvas-linux-riscv64-gnu": "0.1.100",
|
||||||
|
"@napi-rs/canvas-linux-x64-gnu": "0.1.100",
|
||||||
|
"@napi-rs/canvas-linux-x64-musl": "0.1.100",
|
||||||
|
"@napi-rs/canvas-win32-arm64-msvc": "0.1.100",
|
||||||
|
"@napi-rs/canvas-win32-x64-msvc": "0.1.100"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@napi-rs/canvas-android-arm64": {
|
||||||
|
"version": "0.1.100",
|
||||||
|
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.100.tgz",
|
||||||
|
"integrity": "sha512-hjhCKhntPv9+t4ckHymdx0phYNcVW+GKQR6Lzw2zE+pOVjOplSmtx9nNNknTjbEDLcuLZqA1y8ufKg1XfgftzQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/Brooooooklyn"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@napi-rs/canvas-darwin-arm64": {
|
||||||
|
"version": "0.1.100",
|
||||||
|
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.100.tgz",
|
||||||
|
"integrity": "sha512-2PcswRaC7Ly645DGt88///zuFDhJxJYdKAs1uU3mfk1atYkXufgcgLfBpk6Tm12nCQBaNt1wpybuPZ4qOhTo8A==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/Brooooooklyn"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@napi-rs/canvas-darwin-x64": {
|
||||||
|
"version": "0.1.100",
|
||||||
|
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.100.tgz",
|
||||||
|
"integrity": "sha512-ePNZtj7pNIva/siZMg+HmbeozkIjqUIYdoymH8HaA3qK7LfzFN4WMBM8G6HQ9ZC+H3+Dnn5pqtiXpgLykaPOhw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/Brooooooklyn"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@napi-rs/canvas-linux-arm-gnueabihf": {
|
||||||
|
"version": "0.1.100",
|
||||||
|
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.100.tgz",
|
||||||
|
"integrity": "sha512-d5cDB48oWFGU8/XPhUOFAlySgb/VAu7D+s8fi55K1Pcfg8aPplHWqMgibhVLU8ky7Pyg/fuiVLz4Nf3JrSTuUA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/Brooooooklyn"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@napi-rs/canvas-linux-arm64-gnu": {
|
||||||
|
"version": "0.1.100",
|
||||||
|
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.100.tgz",
|
||||||
|
"integrity": "sha512-rDxgxRu69RvDlX/bh9o22DxLsGr8EqsNgotL9+RwQE1S0b0cqeatqsw6aW45mukm0B42DIAaAacKaYQ8cqS1nw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/Brooooooklyn"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@napi-rs/canvas-linux-arm64-musl": {
|
||||||
|
"version": "0.1.100",
|
||||||
|
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.100.tgz",
|
||||||
|
"integrity": "sha512-K3mDW66N+xT2/V439u1alFANiBUjdEx2gLiNYnCmUsva5jZMxWTjafBYwTzYK+EMFMHrUoabuU+T1BIP5CgbYQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/Brooooooklyn"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@napi-rs/canvas-linux-riscv64-gnu": {
|
||||||
|
"version": "0.1.100",
|
||||||
|
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.100.tgz",
|
||||||
|
"integrity": "sha512-mooqUBTIsccZpnoQC4NgrC1v6C1vof39etLNMnBwCY+p0gajWJvAHLGQ6g/gGyS5YrpDW+GefSN4+Cvcr08UWw==",
|
||||||
|
"cpu": [
|
||||||
|
"riscv64"
|
||||||
|
],
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/Brooooooklyn"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@napi-rs/canvas-linux-x64-gnu": {
|
||||||
|
"version": "0.1.100",
|
||||||
|
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.100.tgz",
|
||||||
|
"integrity": "sha512-1eCvkDCazm7FFhsT7DfGOdSaHgZVK3bt/dSBl5EWHOWmnz+I7j8tPseJqqD81NF+MH21jKUK4wQSDjN0mdhnTg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/Brooooooklyn"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@napi-rs/canvas-linux-x64-musl": {
|
||||||
|
"version": "0.1.100",
|
||||||
|
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.100.tgz",
|
||||||
|
"integrity": "sha512-20arT6lnI19S68qNlii73TSEDbECNgzMz2EpldC1V3mZFuRkeujXkcebRk0LRJe9SEUAooYiLokfMViY8IX7yA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/Brooooooklyn"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@napi-rs/canvas-win32-arm64-msvc": {
|
||||||
|
"version": "0.1.100",
|
||||||
|
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-arm64-msvc/-/canvas-win32-arm64-msvc-0.1.100.tgz",
|
||||||
|
"integrity": "sha512-DZFFT1wIAg37LJw37yhMRFfjATd3vTQzjZ1Yki8u2vhO6Hi5VE6BVaGQ1aaDu7xb4iMErz+9EOwjpS7xcxFeBw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/Brooooooklyn"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@napi-rs/canvas-win32-x64-msvc": {
|
||||||
|
"version": "0.1.100",
|
||||||
|
"resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.100.tgz",
|
||||||
|
"integrity": "sha512-MyT1j3mHC2+Lu4pBi9mKyMJhtP6U7k7EldY7sj/uS5gJA65gTXt8MefJQXLJo5d/vZbuWmfxzkEUNc/urV3pHA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/Brooooooklyn"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||||
"version": "4.62.2",
|
"version": "4.62.2",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz",
|
||||||
@@ -1551,6 +1817,13 @@
|
|||||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/node-readable-to-web-readable-stream": {
|
||||||
|
"version": "0.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-readable-to-web-readable-stream/-/node-readable-to-web-readable-stream-0.4.2.tgz",
|
||||||
|
"integrity": "sha512-/cMZNI34v//jUTrI+UIo4ieHAB5EZRY/+7OmXZgBxaWBMcW2tGdceIw06RFxWxrKZ5Jp3sI2i5TsRo+CBhtVLQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"node_modules/path-browserify": {
|
"node_modules/path-browserify": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
|
||||||
@@ -1558,6 +1831,19 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/pdfjs-dist": {
|
||||||
|
"version": "5.6.205",
|
||||||
|
"resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-5.6.205.tgz",
|
||||||
|
"integrity": "sha512-tlUj+2IDa7G1SbvBNN74UHRLJybZDWYom+k6p5KIZl7huBvsA4APi6mKL+zCxd3tLjN5hOOEE9Tv7VdzO88pfg==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20.19.0 || >=22.13.0 || >=24"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@napi-rs/canvas": "^0.1.96",
|
||||||
|
"node-readable-to-web-readable-stream": "^0.4.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/picocolors": {
|
"node_modules/picocolors": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^2",
|
"@tauri-apps/api": "^2",
|
||||||
"@tauri-apps/plugin-opener": "^2",
|
"@tauri-apps/plugin-opener": "^2",
|
||||||
|
"pdfjs-dist": "^5.6.205",
|
||||||
"vant": "^4.10.0",
|
"vant": "^4.10.0",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-router": "^4.6.4"
|
"vue-router": "^4.6.4"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
"windows": ["main"],
|
"windows": ["main"],
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"core:default",
|
"core:default",
|
||||||
"opener:default"
|
"opener:default",
|
||||||
|
"opener:allow-open-path"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-1
@@ -55,6 +55,39 @@ async fn sync_contracts(
|
|||||||
sync::sync_contracts(&api, app_data_dir).await
|
sync::sync_contracts(&api, app_data_dir).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
async fn load_application_file(local_path: String, scan_url: String) -> Result<Vec<u8>, ApiError> {
|
||||||
|
if !local_path.is_empty() {
|
||||||
|
match tokio::fs::metadata(&local_path).await {
|
||||||
|
Ok(metadata) if metadata.len() > 0 => {
|
||||||
|
return tokio::fs::read(&local_path)
|
||||||
|
.await
|
||||||
|
.map_err(|error| ApiError::new("file_error", error.to_string()));
|
||||||
|
}
|
||||||
|
Ok(_) | Err(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if scan_url.is_empty() {
|
||||||
|
return Err(ApiError::new("file_error", "Файл недоступен"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let response = reqwest::Client::new().get(&scan_url).send().await?;
|
||||||
|
if !response.status().is_success() {
|
||||||
|
return Err(ApiError::new(
|
||||||
|
"remote_error",
|
||||||
|
format!("file download failed with {}", response.status()),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let bytes = response.bytes().await?;
|
||||||
|
if bytes.is_empty() {
|
||||||
|
return Err(ApiError::new("file_error", "Файл пустой"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(bytes.to_vec())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
@@ -83,7 +116,8 @@ pub fn run() {
|
|||||||
auth_set_token,
|
auth_set_token,
|
||||||
auth_logout,
|
auth_logout,
|
||||||
auth_status,
|
auth_status,
|
||||||
sync_contracts
|
sync_contracts,
|
||||||
|
load_application_file
|
||||||
])
|
])
|
||||||
.run(tauri::generate_context!())
|
.run(tauri::generate_context!())
|
||||||
.expect("error while running tauri application");
|
.expect("error while running tauri application");
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
import { useAuth } from "./composables/useAuth";
|
import { useAuth } from "./shared/auth/useAuth";
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { createRouter, createWebHashHistory } from "vue-router";
|
||||||
|
import { isAuthenticated, useAuth } from "../../shared/auth/useAuth";
|
||||||
|
import { loginRoute } from "../../apps/auth/routes";
|
||||||
|
import { contractsRoutes } from "../../apps/contracts/routes";
|
||||||
|
import { tasksRoutes } from "../../apps/tasks/routes";
|
||||||
|
import { usersRoutes } from "../../apps/users/routes";
|
||||||
|
|
||||||
|
export const router = createRouter({
|
||||||
|
history: createWebHashHistory(),
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: "/",
|
||||||
|
redirect: "/tasks",
|
||||||
|
},
|
||||||
|
...tasksRoutes,
|
||||||
|
...usersRoutes,
|
||||||
|
...contractsRoutes,
|
||||||
|
loginRoute,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
router.beforeEach(async (to) => {
|
||||||
|
const { restoreToken } = useAuth();
|
||||||
|
await restoreToken();
|
||||||
|
|
||||||
|
if (to.meta.requiresAuth && !isAuthenticated()) {
|
||||||
|
return { path: "/login", query: { redirect: to.fullPath } };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to.path === "/login" && isAuthenticated()) {
|
||||||
|
return "/tasks";
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import LoginView from "./views/LoginView.vue";
|
||||||
|
|
||||||
|
export const loginRoute = {
|
||||||
|
path: "/login",
|
||||||
|
name: "login",
|
||||||
|
component: LoginView,
|
||||||
|
meta: { title: "Вход" },
|
||||||
|
};
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
import { showToast } from "vant";
|
import { showToast } from "vant";
|
||||||
import { useAuth } from "../composables/useAuth";
|
import { useAuth } from "../../../shared/auth/useAuth";
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref, watch } from "vue";
|
import { computed, ref, watch } from "vue";
|
||||||
import { contractCategoryApi } from "../generated/api";
|
import { contractCategoryApi } from "../../../generated/api";
|
||||||
import type { ContractCategoryListParams } from "../generated/models";
|
import type { ContractCategoryListParams } from "../../../generated/models";
|
||||||
import { useModelApi } from "../composables/useModelApi";
|
import { useModelApi } from "../../../shared/composables/useModelApi";
|
||||||
|
|
||||||
const PAGE_SIZE = 30;
|
const PAGE_SIZE = 30;
|
||||||
|
|
||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref, watch } from "vue";
|
import { computed, ref, watch } from "vue";
|
||||||
import { counterpartyApi } from "../generated/api";
|
import { counterpartyApi } from "../../../generated/api";
|
||||||
import type { CounterpartyListParams } from "../generated/models";
|
import type { CounterpartyListParams } from "../../../generated/models";
|
||||||
import { useModelApi } from "../composables/useModelApi";
|
import { useModelApi } from "../../../shared/composables/useModelApi";
|
||||||
|
|
||||||
const PAGE_SIZE = 20;
|
const PAGE_SIZE = 20;
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref, watch } from "vue";
|
import { computed, ref, watch } from "vue";
|
||||||
import { frcApi } from "../generated/api";
|
import { frcApi } from "../../../generated/api";
|
||||||
import type { FrcListParams } from "../generated/models";
|
import type { FrcListParams } from "../../../generated/models";
|
||||||
import { useModelApi } from "../composables/useModelApi";
|
import { useModelApi } from "../../../shared/composables/useModelApi";
|
||||||
|
|
||||||
const PAGE_SIZE = 20;
|
const PAGE_SIZE = 20;
|
||||||
|
|
||||||
@@ -0,0 +1,264 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
|
import {
|
||||||
|
GlobalWorkerOptions,
|
||||||
|
getDocument,
|
||||||
|
type PDFDocumentLoadingTask,
|
||||||
|
type PDFDocumentProxy,
|
||||||
|
type RenderTask,
|
||||||
|
} from "pdfjs-dist";
|
||||||
|
import { computed, nextTick, onBeforeUnmount, ref, watch } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
localPath: string;
|
||||||
|
scanUrl: string;
|
||||||
|
title: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const show = defineModel<boolean>("show", { required: true });
|
||||||
|
|
||||||
|
GlobalWorkerOptions.workerSrc = new URL(
|
||||||
|
"pdfjs-dist/build/pdf.worker.min.mjs",
|
||||||
|
import.meta.url,
|
||||||
|
).toString();
|
||||||
|
|
||||||
|
const canvasRef = ref<HTMLCanvasElement | null>(null);
|
||||||
|
const pdfDocument = ref<PDFDocumentProxy | null>(null);
|
||||||
|
const loading = ref(false);
|
||||||
|
const error = ref("");
|
||||||
|
const pageNumber = ref(1);
|
||||||
|
const pageCount = ref(0);
|
||||||
|
const scale = ref(1.1);
|
||||||
|
|
||||||
|
let loadingTask: PDFDocumentLoadingTask | null = null;
|
||||||
|
let renderTask: RenderTask | null = null;
|
||||||
|
const pageInfo = computed(() => `${pageNumber.value} / ${pageCount.value}`);
|
||||||
|
const canGoBack = computed(() => pageNumber.value > 1);
|
||||||
|
const canGoForward = computed(() => pageNumber.value < pageCount.value);
|
||||||
|
|
||||||
|
async function loadDocument() {
|
||||||
|
resetDocument();
|
||||||
|
|
||||||
|
loading.value = true;
|
||||||
|
error.value = "";
|
||||||
|
let task: PDFDocumentLoadingTask | null = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const bytes = await invoke<number[]>("load_application_file", {
|
||||||
|
localPath: props.localPath,
|
||||||
|
scanUrl: props.scanUrl,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!bytes.length) {
|
||||||
|
throw new Error("Файл пустой");
|
||||||
|
}
|
||||||
|
|
||||||
|
task = getDocument({ data: new Uint8Array(bytes) });
|
||||||
|
loadingTask = task;
|
||||||
|
|
||||||
|
const document = await task.promise;
|
||||||
|
if (loadingTask !== task) {
|
||||||
|
await document.destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdfDocument.value = document;
|
||||||
|
pageCount.value = document.numPages;
|
||||||
|
pageNumber.value = 1;
|
||||||
|
scale.value = 1.1;
|
||||||
|
await renderPage();
|
||||||
|
} catch (err) {
|
||||||
|
error.value = err instanceof Error ? err.message : "Не удалось открыть PDF";
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
if (task && loadingTask === task) {
|
||||||
|
loadingTask = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function renderPage() {
|
||||||
|
const document = pdfDocument.value;
|
||||||
|
const canvas = canvasRef.value;
|
||||||
|
|
||||||
|
if (!document || !canvas) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTask?.cancel();
|
||||||
|
|
||||||
|
const page = await document.getPage(pageNumber.value);
|
||||||
|
const viewport = page.getViewport({ scale: scale.value });
|
||||||
|
const context = canvas.getContext("2d");
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
error.value = "Не удалось создать canvas context";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const devicePixelRatio = window.devicePixelRatio || 1;
|
||||||
|
canvas.width = Math.floor(viewport.width * devicePixelRatio);
|
||||||
|
canvas.height = Math.floor(viewport.height * devicePixelRatio);
|
||||||
|
canvas.style.width = `${viewport.width}px`;
|
||||||
|
canvas.style.height = `${viewport.height}px`;
|
||||||
|
|
||||||
|
context.setTransform(devicePixelRatio, 0, 0, devicePixelRatio, 0, 0);
|
||||||
|
|
||||||
|
renderTask = page.render({ canvas: canvas, canvasContext: context, viewport });
|
||||||
|
|
||||||
|
try {
|
||||||
|
await renderTask.promise;
|
||||||
|
} catch (err) {
|
||||||
|
if (!(err instanceof Error) || err.name !== "RenderingCancelledException") {
|
||||||
|
error.value = err instanceof Error ? err.message : "Не удалось отрисовать PDF";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetDocument() {
|
||||||
|
renderTask?.cancel();
|
||||||
|
renderTask = null;
|
||||||
|
loadingTask?.destroy().catch(() => undefined);
|
||||||
|
loadingTask = null;
|
||||||
|
pdfDocument.value?.destroy().catch(() => undefined);
|
||||||
|
pdfDocument.value = null;
|
||||||
|
pageCount.value = 0;
|
||||||
|
pageNumber.value = 1;
|
||||||
|
loading.value = false;
|
||||||
|
error.value = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
async function goBack() {
|
||||||
|
if (canGoBack.value) {
|
||||||
|
pageNumber.value -= 1;
|
||||||
|
await nextTick();
|
||||||
|
await renderPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function goForward() {
|
||||||
|
if (canGoForward.value) {
|
||||||
|
pageNumber.value += 1;
|
||||||
|
await nextTick();
|
||||||
|
await renderPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function zoomIn() {
|
||||||
|
scale.value = Math.min(scale.value + 0.2, 3);
|
||||||
|
await nextTick();
|
||||||
|
await renderPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function zoomOut() {
|
||||||
|
scale.value = Math.max(scale.value - 0.2, 0.5);
|
||||||
|
await nextTick();
|
||||||
|
await renderPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
watch([show, () => props.localPath, () => props.scanUrl], async ([visible]) => {
|
||||||
|
if (visible) {
|
||||||
|
await nextTick();
|
||||||
|
await loadDocument();
|
||||||
|
} else {
|
||||||
|
resetDocument();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
resetDocument();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<van-popup v-model:show="show" round position="bottom" class="pdf-preview">
|
||||||
|
<div class="pdf-preview__header">
|
||||||
|
<div class="pdf-preview__title">{{ title }}</div>
|
||||||
|
<van-button size="small" plain @click="show = false">Закрыть</van-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pdf-preview__toolbar">
|
||||||
|
<van-button size="small" plain :disabled="!canGoBack" @click="goBack">
|
||||||
|
Назад
|
||||||
|
</van-button>
|
||||||
|
<div class="pdf-preview__page-info">{{ pageInfo }}</div>
|
||||||
|
<van-button size="small" plain :disabled="!canGoForward" @click="goForward">
|
||||||
|
Вперед
|
||||||
|
</van-button>
|
||||||
|
<van-button size="small" plain @click="zoomOut">-</van-button>
|
||||||
|
<van-button size="small" plain @click="zoomIn">+</van-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pdf-preview__body">
|
||||||
|
<van-loading v-if="loading">Загрузка PDF...</van-loading>
|
||||||
|
<van-empty v-else-if="error" :description="error" />
|
||||||
|
<div v-else class="pdf-preview__canvas-wrap">
|
||||||
|
<canvas ref="canvasRef" class="pdf-preview__canvas" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</van-popup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.pdf-preview {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 92vh;
|
||||||
|
background: #f5f7fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-preview__header,
|
||||||
|
.pdf-preview__toolbar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-preview__header {
|
||||||
|
justify-content: space-between;
|
||||||
|
border-bottom: 1px solid #eef0f4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-preview__title {
|
||||||
|
min-width: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-preview__toolbar {
|
||||||
|
justify-content: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
border-bottom: 1px solid #eef0f4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-preview__page-info {
|
||||||
|
min-width: 72px;
|
||||||
|
text-align: center;
|
||||||
|
color: #636b74;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-preview__body {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-preview__canvas-wrap {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-preview__canvas {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 8px 28px rgba(15, 23, 42, 0.16);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref, watch } from "vue";
|
import { computed, ref, watch } from "vue";
|
||||||
import { projectApi } from "../generated/api";
|
import { projectApi } from "../../../generated/api";
|
||||||
import type { ProjectListParams } from "../generated/models";
|
import type { ProjectListParams } from "../../../generated/models";
|
||||||
import { useModelApi } from "../composables/useModelApi";
|
import { useModelApi } from "../../../shared/composables/useModelApi";
|
||||||
|
|
||||||
const PAGE_SIZE = 20;
|
const PAGE_SIZE = 20;
|
||||||
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import ContractDetailView from "./views/ContractDetailView.vue";
|
||||||
|
import ContractsView from "./views/ContractsView.vue";
|
||||||
|
|
||||||
|
export const contractsRoutes = [
|
||||||
|
{
|
||||||
|
path: "/contracts",
|
||||||
|
name: "contracts",
|
||||||
|
component: ContractsView,
|
||||||
|
meta: { title: "Контракты", requiresAuth: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/contracts/:id",
|
||||||
|
name: "contract-detail",
|
||||||
|
component: ContractDetailView,
|
||||||
|
meta: { title: "Детали контракта", back: true, requiresAuth: true },
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -3,12 +3,14 @@ import { openPath, openUrl } from "@tauri-apps/plugin-opener";
|
|||||||
import { computed, onMounted, ref } from "vue";
|
import { computed, onMounted, ref } from "vue";
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
import { showToast } from "vant";
|
import { showToast } from "vant";
|
||||||
import { contractApi, contractApplicationFileApi } from "../generated/api";
|
import { contractApi, contractApplicationFileApi } from "../../../generated/api";
|
||||||
import type {
|
import type {
|
||||||
Contract,
|
Contract,
|
||||||
|
ContractApplicationFile,
|
||||||
ContractApplicationFileListParams,
|
ContractApplicationFileListParams,
|
||||||
} from "../generated/models";
|
} from "../../../generated/models";
|
||||||
import { useModelApi } from "../composables/useModelApi";
|
import { useModelApi } from "../../../shared/composables/useModelApi";
|
||||||
|
import PdfPreview from "../components/PdfPreview.vue";
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -117,6 +119,11 @@ const approvalFields = computed(() => {
|
|||||||
const templateUrl = computed(
|
const templateUrl = computed(
|
||||||
() => contract.value?.category_ref?.template ?? "",
|
() => contract.value?.category_ref?.template ?? "",
|
||||||
);
|
);
|
||||||
|
const pdfPreviewVisible = ref(false);
|
||||||
|
const pdfPreviewFile = ref<ContractApplicationFile | null>(null);
|
||||||
|
const pdfPreviewTitle = computed(
|
||||||
|
() => pdfPreviewFile.value?.name || pdfPreviewFile.value?.scan_name || "PDF",
|
||||||
|
);
|
||||||
|
|
||||||
const summaryStatus = computed(
|
const summaryStatus = computed(
|
||||||
() => contract.value?.status_name ?? "не указано",
|
() => contract.value?.status_name ?? "не указано",
|
||||||
@@ -192,6 +199,15 @@ async function openTemplateForm() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isPdfFile(file: ContractApplicationFile) {
|
||||||
|
return `${file.scan_name} ${file.name}`.toLowerCase().includes(".pdf");
|
||||||
|
}
|
||||||
|
|
||||||
|
function openPdfPreview(file: ContractApplicationFile) {
|
||||||
|
pdfPreviewFile.value = file;
|
||||||
|
pdfPreviewVisible.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
function errorMessage(err: unknown, fallback: string) {
|
function errorMessage(err: unknown, fallback: string) {
|
||||||
if (err instanceof Error) {
|
if (err instanceof Error) {
|
||||||
return err.message;
|
return err.message;
|
||||||
@@ -413,15 +429,26 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #value>
|
<template #value>
|
||||||
|
<div class="file-actions">
|
||||||
<van-button
|
<van-button
|
||||||
|
v-if="isPdfFile(file)"
|
||||||
size="small"
|
size="small"
|
||||||
type="primary"
|
type="primary"
|
||||||
plain
|
plain
|
||||||
:disabled="!file.local_path"
|
:disabled="!file.local_path"
|
||||||
|
@click="openPdfPreview(file)"
|
||||||
|
>
|
||||||
|
Просмотр
|
||||||
|
</van-button>
|
||||||
|
<van-button
|
||||||
|
size="small"
|
||||||
|
plain
|
||||||
|
:disabled="!file.local_path"
|
||||||
@click="openApplicationFile(file.local_path)"
|
@click="openApplicationFile(file.local_path)"
|
||||||
>
|
>
|
||||||
Открыть
|
Открыть
|
||||||
</van-button>
|
</van-button>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</van-cell>
|
</van-cell>
|
||||||
</van-cell-group>
|
</van-cell-group>
|
||||||
@@ -478,6 +505,13 @@ onMounted(() => {
|
|||||||
</van-tab>
|
</van-tab>
|
||||||
</van-tabs>
|
</van-tabs>
|
||||||
|
|
||||||
|
<PdfPreview
|
||||||
|
v-model:show="pdfPreviewVisible"
|
||||||
|
:local-path="pdfPreviewFile?.local_path ?? ''"
|
||||||
|
:scan-url="pdfPreviewFile?.scan_url ?? ''"
|
||||||
|
:title="pdfPreviewTitle"
|
||||||
|
/>
|
||||||
|
|
||||||
<div class="detail-actions">
|
<div class="detail-actions">
|
||||||
<van-button block round type="primary" plain @click="router.back()"
|
<van-button block round type="primary" plain @click="router.back()"
|
||||||
>Назад</van-button
|
>Назад</van-button
|
||||||
@@ -545,6 +579,13 @@ onMounted(() => {
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.file-actions {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
.detail-value--money {
|
.detail-value--money {
|
||||||
font-variant-numeric: tabular-nums;
|
font-variant-numeric: tabular-nums;
|
||||||
}
|
}
|
||||||
@@ -3,9 +3,9 @@ import { invoke } from "@tauri-apps/api/core";
|
|||||||
import { computed, ref, watch } from "vue";
|
import { computed, ref, watch } from "vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { showToast } from "vant";
|
import { showToast } from "vant";
|
||||||
import { contractApi } from "../generated/api";
|
import { contractApi } from "../../../generated/api";
|
||||||
import type { ContractListParams } from "../generated/models";
|
import type { ContractListParams } from "../../../generated/models";
|
||||||
import { useModelApi } from "../composables/useModelApi";
|
import { useModelApi } from "../../../shared/composables/useModelApi";
|
||||||
import ContractCategorySelect from "../components/ContractCategorySelect.vue";
|
import ContractCategorySelect from "../components/ContractCategorySelect.vue";
|
||||||
import CounterpartySelect from "../components/CounterpartySelect.vue";
|
import CounterpartySelect from "../components/CounterpartySelect.vue";
|
||||||
import FrcSelect from "../components/FrcSelect.vue";
|
import FrcSelect from "../components/FrcSelect.vue";
|
||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref, watch } from "vue";
|
import { computed, ref, watch } from "vue";
|
||||||
import { employeeApi } from "../generated/api";
|
import { employeeApi } from "../../../generated/api";
|
||||||
import type { EmployeeListParams } from "../generated/models";
|
import type { EmployeeListParams } from "../../../generated/models";
|
||||||
import { useModelApi } from "../composables/useModelApi";
|
import { useModelApi } from "../../../shared/composables/useModelApi";
|
||||||
|
|
||||||
const PAGE_SIZE = 20;
|
const PAGE_SIZE = 20;
|
||||||
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import TaskCreateView from "./views/TaskCreateView.vue";
|
||||||
|
import TaskDetailView from "./views/TaskDetailView.vue";
|
||||||
|
import TasksView from "./views/TasksView.vue";
|
||||||
|
|
||||||
|
export const tasksRoutes = [
|
||||||
|
{
|
||||||
|
path: "/tasks",
|
||||||
|
name: "tasks",
|
||||||
|
component: TasksView,
|
||||||
|
meta: { title: "Задачи", requiresAuth: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/tasks/new",
|
||||||
|
name: "task-create",
|
||||||
|
component: TaskCreateView,
|
||||||
|
meta: { title: "Новая задача", back: true, requiresAuth: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/tasks/:id",
|
||||||
|
name: "task-detail",
|
||||||
|
component: TaskDetailView,
|
||||||
|
meta: { title: "Детали задачи", back: true, requiresAuth: true },
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { showToast } from "vant";
|
import { showToast } from "vant";
|
||||||
import { taskApi } from "../generated/api";
|
import { taskApi } from "../../../generated/api";
|
||||||
import { useModelApi } from "../composables/useModelApi";
|
import { useModelApi } from "../../../shared/composables/useModelApi";
|
||||||
import EmployeeSelect from "../components/EmployeeSelect.vue";
|
import EmployeeSelect from "../../personnel/components/EmployeeSelect.vue";
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const newTaskName = ref("");
|
const newTaskName = ref("");
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
import { computed, onMounted, ref } from "vue";
|
import { computed, onMounted, ref } from "vue";
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
import { showToast } from "vant";
|
import { showToast } from "vant";
|
||||||
import { employeeApi, messageApi, taskApi } from "../generated/api";
|
import { employeeApi, messageApi, taskApi } from "../../../generated/api";
|
||||||
import { useModelApi } from "../composables/useModelApi";
|
import { useModelApi } from "../../../shared/composables/useModelApi";
|
||||||
import EmployeeSelect from "../components/EmployeeSelect.vue";
|
import EmployeeSelect from "../../personnel/components/EmployeeSelect.vue";
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { employeeApi, taskApi } from "../generated/api";
|
import { employeeApi, taskApi } from "../../../generated/api";
|
||||||
import { useModelApi } from "../composables/useModelApi";
|
import { useModelApi } from "../../../shared/composables/useModelApi";
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const {
|
const {
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import UsersView from "./views/UsersView.vue";
|
||||||
|
|
||||||
|
export const usersRoutes = [
|
||||||
|
{
|
||||||
|
path: "/users",
|
||||||
|
name: "users",
|
||||||
|
component: UsersView,
|
||||||
|
meta: { title: "Пользователи", requiresAuth: true },
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { userApi } from "../generated/api";
|
import { userApi } from "../../../generated/api";
|
||||||
import { useModelApi } from "../composables/useModelApi";
|
import { useModelApi } from "../../../shared/composables/useModelApi";
|
||||||
|
|
||||||
const {
|
const {
|
||||||
items: users,
|
items: users,
|
||||||
+1
-1
@@ -2,6 +2,6 @@ import { createApp } from "vue";
|
|||||||
import Vant from "vant";
|
import Vant from "vant";
|
||||||
import "vant/lib/index.css";
|
import "vant/lib/index.css";
|
||||||
import App from "./App.vue";
|
import App from "./App.vue";
|
||||||
import { router } from "./router";
|
import { router } from "./app/router";
|
||||||
|
|
||||||
createApp(App).use(router).use(Vant).mount("#app");
|
createApp(App).use(router).use(Vant).mount("#app");
|
||||||
|
|||||||
+1
-74
@@ -1,74 +1 @@
|
|||||||
import { createRouter, createWebHashHistory } from "vue-router";
|
export { router } from "../app/router";
|
||||||
import { isAuthenticated, useAuth } from "../composables/useAuth";
|
|
||||||
import ContractDetailView from "../views/ContractDetailView.vue";
|
|
||||||
import ContractsView from "../views/ContractsView.vue";
|
|
||||||
import LoginView from "../views/LoginView.vue";
|
|
||||||
import TaskCreateView from "../views/TaskCreateView.vue";
|
|
||||||
import TaskDetailView from "../views/TaskDetailView.vue";
|
|
||||||
import TasksView from "../views/TasksView.vue";
|
|
||||||
import UsersView from "../views/UsersView.vue";
|
|
||||||
|
|
||||||
export const router = createRouter({
|
|
||||||
history: createWebHashHistory(),
|
|
||||||
routes: [
|
|
||||||
{
|
|
||||||
path: "/",
|
|
||||||
redirect: "/tasks",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/tasks",
|
|
||||||
name: "tasks",
|
|
||||||
component: TasksView,
|
|
||||||
meta: { title: "Задачи", requiresAuth: true },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/tasks/new",
|
|
||||||
name: "task-create",
|
|
||||||
component: TaskCreateView,
|
|
||||||
meta: { title: "Новая задача", back: true, requiresAuth: true },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/tasks/:id",
|
|
||||||
name: "task-detail",
|
|
||||||
component: TaskDetailView,
|
|
||||||
meta: { title: "Детали задачи", back: true, requiresAuth: true },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/users",
|
|
||||||
name: "users",
|
|
||||||
component: UsersView,
|
|
||||||
meta: { title: "Пользователи", requiresAuth: true },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/contracts",
|
|
||||||
name: "contracts",
|
|
||||||
component: ContractsView,
|
|
||||||
meta: { title: "Контракты", requiresAuth: true },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/contracts/:id",
|
|
||||||
name: "contract-detail",
|
|
||||||
component: ContractDetailView,
|
|
||||||
meta: { title: "Детали контракта", back: true, requiresAuth: true },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/login",
|
|
||||||
name: "login",
|
|
||||||
component: LoginView,
|
|
||||||
meta: { title: "Вход" },
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
router.beforeEach(async (to) => {
|
|
||||||
const { restoreToken } = useAuth();
|
|
||||||
await restoreToken();
|
|
||||||
|
|
||||||
if (to.meta.requiresAuth && !isAuthenticated()) {
|
|
||||||
return { path: "/login", query: { redirect: to.fullPath } };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (to.path === "/login" && isAuthenticated()) {
|
|
||||||
return "/tasks";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { onMounted, reactive, ref, shallowRef, watch } from "vue";
|
import { onMounted, reactive, ref, shallowRef, watch } from "vue";
|
||||||
import { showToast } from "vant";
|
import { showToast } from "vant";
|
||||||
import type { BaseEntity, ListParams, ModelApi } from "../generated/api_client";
|
import type { BaseEntity, ListParams, ModelApi } from "../../generated/api_client";
|
||||||
|
|
||||||
interface UseModelApiOptions<Params> {
|
interface UseModelApiOptions<Params> {
|
||||||
defaultListParams?: Params;
|
defaultListParams?: Params;
|
||||||
Reference in New Issue
Block a user