Compare commits
2 Commits
32e97a7591
...
6510432f41
| Author | SHA1 | Date | |
|---|---|---|---|
| 6510432f41 | |||
| 8fefb4568b |
Generated
+241
@@ -13,6 +13,7 @@
|
|||||||
"@tanstack/vue-query-devtools": "^5.62.2",
|
"@tanstack/vue-query-devtools": "^5.62.2",
|
||||||
"@tinymce/tinymce-vue": "^4.0.7",
|
"@tinymce/tinymce-vue": "^4.0.7",
|
||||||
"axios": "^1.12.2",
|
"axios": "^1.12.2",
|
||||||
|
"html2pdf.js": "^0.14.0",
|
||||||
"husky": "^8.0.0",
|
"husky": "^8.0.0",
|
||||||
"jalaali-js": "^1.2.8",
|
"jalaali-js": "^1.2.8",
|
||||||
"lodash": "^4.18.1",
|
"lodash": "^4.18.1",
|
||||||
@@ -102,6 +103,15 @@
|
|||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@babel/runtime": {
|
||||||
|
"version": "7.29.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz",
|
||||||
|
"integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@babel/types": {
|
"node_modules/@babel/types": {
|
||||||
"version": "7.29.0",
|
"version": "7.29.0",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
|
||||||
@@ -1722,6 +1732,26 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/pako": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@types/raf": {
|
||||||
|
"version": "3.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz",
|
||||||
|
"integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"node_modules/@types/trusted-types": {
|
||||||
|
"version": "2.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
|
||||||
|
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"node_modules/@ungap/structured-clone": {
|
"node_modules/@ungap/structured-clone": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz",
|
||||||
@@ -2168,6 +2198,15 @@
|
|||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/base64-arraybuffer": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/baseline-browser-mapping": {
|
"node_modules/baseline-browser-mapping": {
|
||||||
"version": "2.10.29",
|
"version": "2.10.29",
|
||||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.29.tgz",
|
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.29.tgz",
|
||||||
@@ -2371,6 +2410,26 @@
|
|||||||
],
|
],
|
||||||
"license": "CC-BY-4.0"
|
"license": "CC-BY-4.0"
|
||||||
},
|
},
|
||||||
|
"node_modules/canvg": {
|
||||||
|
"version": "3.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.11.tgz",
|
||||||
|
"integrity": "sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.12.5",
|
||||||
|
"@types/raf": "^3.4.0",
|
||||||
|
"core-js": "^3.8.3",
|
||||||
|
"raf": "^3.4.1",
|
||||||
|
"regenerator-runtime": "^0.13.7",
|
||||||
|
"rgbcolor": "^1.0.1",
|
||||||
|
"stackblur-canvas": "^2.0.0",
|
||||||
|
"svg-pathdata": "^6.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/chalk": {
|
"node_modules/chalk": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||||
@@ -2656,6 +2715,18 @@
|
|||||||
"url": "https://github.com/sponsors/mesqueeb"
|
"url": "https://github.com/sponsors/mesqueeb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/core-js": {
|
||||||
|
"version": "3.49.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.49.0.tgz",
|
||||||
|
"integrity": "sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/core-js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/core-js-compat": {
|
"node_modules/core-js-compat": {
|
||||||
"version": "3.49.0",
|
"version": "3.49.0",
|
||||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz",
|
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz",
|
||||||
@@ -2722,6 +2793,15 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/css-line-break": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"utrie": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/css-select": {
|
"node_modules/css-select": {
|
||||||
"version": "5.2.2",
|
"version": "5.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
|
||||||
@@ -3032,6 +3112,15 @@
|
|||||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dompurify": {
|
||||||
|
"version": "3.4.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.12.tgz",
|
||||||
|
"integrity": "sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg==",
|
||||||
|
"license": "(MPL-2.0 OR Apache-2.0)",
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@types/trusted-types": "^2.0.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/domutils": {
|
"node_modules/domutils": {
|
||||||
"version": "3.2.2",
|
"version": "3.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
|
||||||
@@ -3853,6 +3942,17 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/fast-png": {
|
||||||
|
"version": "6.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-png/-/fast-png-6.4.0.tgz",
|
||||||
|
"integrity": "sha512-kAqZq1TlgBjZcLr5mcN6NP5Rv4V2f22z00c3g8vRrwkcqjerx7BEhPbOnWCPqaHUl2XWQBJQvOT/FQhdMT7X/Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/pako": "^2.0.3",
|
||||||
|
"iobuffer": "^5.3.2",
|
||||||
|
"pako": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/fast-uri": {
|
"node_modules/fast-uri": {
|
||||||
"version": "3.1.2",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz",
|
||||||
@@ -3908,6 +4008,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fflate": {
|
||||||
|
"version": "0.8.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.3.tgz",
|
||||||
|
"integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/file-entry-cache": {
|
"node_modules/file-entry-cache": {
|
||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
||||||
@@ -4469,6 +4575,30 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/html2canvas": {
|
||||||
|
"version": "1.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
|
||||||
|
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"css-line-break": "^2.1.0",
|
||||||
|
"text-segmentation": "^1.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/html2pdf.js": {
|
||||||
|
"version": "0.14.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/html2pdf.js/-/html2pdf.js-0.14.0.tgz",
|
||||||
|
"integrity": "sha512-yvNJgE/8yru2UeGflkPdjW8YEY+nDH5X7/2WG4uiuSCwYiCp8PZ8EKNiTAa6HxJ1NjC51fZSIEq6xld5CADKBQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"dompurify": "^3.3.1",
|
||||||
|
"html2canvas": "^1.0.0",
|
||||||
|
"jspdf": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/htmlparser2": {
|
"node_modules/htmlparser2": {
|
||||||
"version": "8.0.2",
|
"version": "8.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
|
||||||
@@ -4607,6 +4737,12 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/iobuffer": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/iobuffer/-/iobuffer-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-DRebOWuqDvxunfkNJAlc3IzWIPD5xVxwUNbHr7xKB8E6aLJxIPfNX3CoMJghcFjpv6RWQsrcJbghtEwSPoJqMA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/is-array-buffer": {
|
"node_modules/is-array-buffer": {
|
||||||
"version": "3.0.5",
|
"version": "3.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
|
||||||
@@ -5171,6 +5307,23 @@
|
|||||||
"json5": "lib/cli.js"
|
"json5": "lib/cli.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jspdf": {
|
||||||
|
"version": "4.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jspdf/-/jspdf-4.2.1.tgz",
|
||||||
|
"integrity": "sha512-YyAXyvnmjTbR4bHQRLzex3CuINCDlQnBqoSYyjJwTP2x9jDLuKDzy7aKUl0hgx3uhcl7xzg32agn5vlie6HIlQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.28.6",
|
||||||
|
"fast-png": "^6.2.0",
|
||||||
|
"fflate": "^0.8.1"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"canvg": "^3.0.11",
|
||||||
|
"core-js": "^3.6.0",
|
||||||
|
"dompurify": "^3.3.1",
|
||||||
|
"html2canvas": "^1.0.0-rc.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/keyv": {
|
"node_modules/keyv": {
|
||||||
"version": "4.5.4",
|
"version": "4.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||||
@@ -6022,6 +6175,22 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/pako": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pako/-/pako-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-zJq6RP/5q+TO2OpFV3FHzlPnFjmkb7Nc99a5SNjJE+uu/PkpChs+NIZSSzbBoD+6kjiISXjfYdwj1ZRQ81dz/w==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/puzrin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/nodeca"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "(MIT AND Zlib)"
|
||||||
|
},
|
||||||
"node_modules/parent-module": {
|
"node_modules/parent-module": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||||
@@ -6106,6 +6275,13 @@
|
|||||||
"integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==",
|
"integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/performance-now": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"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",
|
||||||
@@ -6416,6 +6592,16 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/raf": {
|
||||||
|
"version": "3.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
|
||||||
|
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"performance-now": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/read-pkg": {
|
"node_modules/read-pkg": {
|
||||||
"version": "5.2.0",
|
"version": "5.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
|
||||||
@@ -6563,6 +6749,13 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/regenerator-runtime": {
|
||||||
|
"version": "0.13.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
|
||||||
|
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"node_modules/regexp-tree": {
|
"node_modules/regexp-tree": {
|
||||||
"version": "0.1.27",
|
"version": "0.1.27",
|
||||||
"resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz",
|
"resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz",
|
||||||
@@ -6716,6 +6909,16 @@
|
|||||||
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
|
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/rgbcolor": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
|
||||||
|
"license": "MIT OR SEE LICENSE IN FEEL-FREE.md",
|
||||||
|
"optional": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.15"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/rimraf": {
|
"node_modules/rimraf": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||||
@@ -7140,6 +7343,16 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/stackblur-canvas": {
|
||||||
|
"version": "2.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz",
|
||||||
|
"integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.1.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/stop-iteration-iterator": {
|
"node_modules/stop-iteration-iterator": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
|
||||||
@@ -7685,6 +7898,16 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/svg-pathdata": {
|
||||||
|
"version": "6.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
|
||||||
|
"integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/svg-tags": {
|
"node_modules/svg-tags": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz",
|
||||||
@@ -7779,6 +8002,15 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/text-segmentation": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"utrie": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/text-table": {
|
"node_modules/text-table": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
||||||
@@ -8018,6 +8250,15 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/utrie": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"base64-arraybuffer": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/validate-npm-package-license": {
|
"node_modules/validate-npm-package-license": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
"@tanstack/vue-query-devtools": "^5.62.2",
|
"@tanstack/vue-query-devtools": "^5.62.2",
|
||||||
"@tinymce/tinymce-vue": "^4.0.7",
|
"@tinymce/tinymce-vue": "^4.0.7",
|
||||||
"axios": "^1.12.2",
|
"axios": "^1.12.2",
|
||||||
|
"html2pdf.js": "^0.14.0",
|
||||||
"husky": "^8.0.0",
|
"husky": "^8.0.0",
|
||||||
"jalaali-js": "^1.2.8",
|
"jalaali-js": "^1.2.8",
|
||||||
"lodash": "^4.18.1",
|
"lodash": "^4.18.1",
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="stat-card">
|
<component
|
||||||
|
:is="to ? RouterLink : 'div'"
|
||||||
|
:to="to || undefined"
|
||||||
|
class="stat-card"
|
||||||
|
:class="{ 'stat-card--linked': to }"
|
||||||
|
>
|
||||||
<SvgIcon name="card-corner-arrow" :size="'1.5rem'" class="stat-card__corner" />
|
<SvgIcon name="card-corner-arrow" :size="'1.5rem'" class="stat-card__corner" />
|
||||||
|
|
||||||
<div class="stat-card__head">
|
<div class="stat-card__head">
|
||||||
@@ -14,10 +19,11 @@
|
|||||||
<span class="stat-card__subtitle">{{ subtitle }}</span>
|
<span class="stat-card__subtitle">{{ subtitle }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</component>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { RouterLink } from 'vue-router'
|
||||||
import SvgIcon from '@/components/icons/SvgIcon.vue'
|
import SvgIcon from '@/components/icons/SvgIcon.vue'
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
@@ -27,6 +33,7 @@ defineProps({
|
|||||||
value: { type: [String, Number], default: '' },
|
value: { type: [String, Number], default: '' },
|
||||||
unit: { type: String, default: '' },
|
unit: { type: String, default: '' },
|
||||||
subtitle: { type: String, default: '' },
|
subtitle: { type: String, default: '' },
|
||||||
|
to: { type: [String, Object], default: null },
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -41,6 +48,23 @@ defineProps({
|
|||||||
background: rgba(255, 255, 255, 58%);
|
background: rgba(255, 255, 255, 58%);
|
||||||
box-shadow: 0 6.75px 19.425px rgba(0, 0, 0, 4%);
|
box-shadow: 0 6.75px 19.425px rgba(0, 0, 0, 4%);
|
||||||
border-radius: 0.9375rem;
|
border-radius: 0.9375rem;
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
|
||||||
|
&--linked {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 9px 24px rgba(0, 0, 0, 7%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
outline: 2px solid var(--color-primary);
|
||||||
|
outline-offset: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&__corner {
|
&__corner {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</BoxedIconTitleBlock>
|
</BoxedIconTitleBlock>
|
||||||
|
|
||||||
<SkeletonLoaderBlock v-if="isLoading" :rows="1" :cols-per-row="3" />
|
<SkeletonLoaderBlock v-if="isLoading" :rows="2" :cols-per-row="3" />
|
||||||
<div v-else class="dashboard__stats">
|
<div v-else class="dashboard__stats">
|
||||||
<DashboardStatCard
|
<DashboardStatCard
|
||||||
v-for="(stat, i) in institutionStats"
|
v-for="(stat, i) in institutionStats"
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
:value="stat.value"
|
:value="stat.value"
|
||||||
:unit="stat.unit"
|
:unit="stat.unit"
|
||||||
:subtitle="stat.subtitle"
|
:subtitle="stat.subtitle"
|
||||||
|
:to="stat.to"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -95,37 +96,56 @@ const ACCESS_LABELS = {
|
|||||||
limited: 'محدود',
|
limited: 'محدود',
|
||||||
}
|
}
|
||||||
|
|
||||||
const formatThousands = (value) => {
|
|
||||||
const n = Number(value ?? 0)
|
|
||||||
return n >= 1000
|
|
||||||
? { value: toFaDigits(Math.round(n / 1000)), unit: 'هزار' }
|
|
||||||
: { value: toFaDigits(n), unit: 'نفر' }
|
|
||||||
}
|
|
||||||
|
|
||||||
const institutionStats = computed(() => {
|
const institutionStats = computed(() => {
|
||||||
const stats = dashboard.value.stats ?? {}
|
const stats = dashboard.value.stats ?? {}
|
||||||
const users = formatThousands(stats.activeUsers)
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
icon: 'user',
|
icon: 'users-three',
|
||||||
label: 'آمار کلی کاربران',
|
label: 'مجموع کل متقاضیان',
|
||||||
value: users.value,
|
value: toFaDigits(stats.totalApplicants ?? 0),
|
||||||
unit: users.unit,
|
unit: 'نفر',
|
||||||
subtitle: 'کاربر فعال',
|
subtitle: 'احراز شده و نشده',
|
||||||
|
to: { name: 'admin-users' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'video',
|
icon: 'clock',
|
||||||
label: 'دوره های ایجاد شده',
|
label: 'تعداد کاربران در انتظار ارزیابی',
|
||||||
value: toFaDigits(stats.coursesCreated ?? 0),
|
value: toFaDigits(stats.awaitingEvaluation ?? 0),
|
||||||
unit: 'دوره',
|
unit: 'نفر',
|
||||||
subtitle: 'ایجاد شده',
|
subtitle: 'در انتظار ارزیابی',
|
||||||
|
to: { name: 'admin-user-verification' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'shopping-bag',
|
icon: 'book',
|
||||||
label: 'دوره های فروش رفته',
|
label: 'آمار طلبههای ترم ۱',
|
||||||
value: toFaDigits(stats.coursesSold ?? 0),
|
value: toFaDigits(stats.term1Students ?? 0),
|
||||||
unit: 'عدد',
|
unit: 'نفر',
|
||||||
subtitle: 'دوره فروش رفته',
|
subtitle: 'ترم اول',
|
||||||
|
to: { name: 'admin-terms' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'book',
|
||||||
|
label: 'آمار طلبههای ترم ۲',
|
||||||
|
value: toFaDigits(stats.term2Students ?? 0),
|
||||||
|
unit: 'نفر',
|
||||||
|
subtitle: 'ترم دوم',
|
||||||
|
to: { name: 'admin-terms' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'book',
|
||||||
|
label: 'آمار طلبههای ترم ۳',
|
||||||
|
value: toFaDigits(stats.term3Students ?? 0),
|
||||||
|
unit: 'نفر',
|
||||||
|
subtitle: 'ترم سوم',
|
||||||
|
to: { name: 'admin-terms' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'graduation-cap',
|
||||||
|
label: 'آمار فارغالتحصیلان',
|
||||||
|
value: toFaDigits(stats.graduates ?? 0),
|
||||||
|
unit: 'نفر',
|
||||||
|
subtitle: 'فارغالتحصیل',
|
||||||
|
to: { name: 'admin-users' },
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|||||||
+137
-7
@@ -8,10 +8,15 @@
|
|||||||
:show-close-button="true"
|
:show-close-button="true"
|
||||||
>
|
>
|
||||||
<template #default>
|
<template #default>
|
||||||
<div v-if="!user" class="user-verification-details">
|
<div v-if="detailsLoading || !user" class="user-verification-details">
|
||||||
<p class="user-verification-details__loading">در حال بارگذاری…</p>
|
<p class="user-verification-details__loading">در حال بارگذاری…</p>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="user-verification-details">
|
<div v-else ref="pdfContent" class="user-verification-details">
|
||||||
|
<header class="user-verification-details__pdf-header">
|
||||||
|
<h1>اطلاعات احراز هویت کاربر</h1>
|
||||||
|
<p>{{ fullName }}</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
<section class="user-verification-details__section">
|
<section class="user-verification-details__section">
|
||||||
<div class="user-verification-details__grid user-verification-details__grid--6">
|
<div class="user-verification-details__grid user-verification-details__grid--6">
|
||||||
<LineInfoBlock title="نام و نام خانوادگی" :numeric-desc="fullName" />
|
<LineInfoBlock title="نام و نام خانوادگی" :numeric-desc="fullName" />
|
||||||
@@ -178,15 +183,33 @@
|
|||||||
class="user-verification-details__video"
|
class="user-verification-details__video"
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<div class="user-verification-details__divider" />
|
||||||
|
|
||||||
|
<div class="user-verification-details__actions" data-pdf-ignore>
|
||||||
|
<BaseButton
|
||||||
|
text="ذخیره به صورت PDF"
|
||||||
|
:loading="pdfLoading"
|
||||||
|
custom-class="user-verification-details__pdf-btn"
|
||||||
|
@click="onSaveAsPdf"
|
||||||
|
>
|
||||||
|
<template #appendIcon>
|
||||||
|
<SvgIcon name="arrow-left" :size="18" color="#fff" />
|
||||||
|
</template>
|
||||||
|
</BaseButton>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</BasicModal>
|
</BasicModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
|
import { toast } from 'vue3-toastify'
|
||||||
import useModal from '@/composables/useModal'
|
import useModal from '@/composables/useModal'
|
||||||
import BasicModal from '@/components/BasicModal.vue'
|
import BasicModal from '@/components/BasicModal.vue'
|
||||||
|
import BaseButton from '@/components/BaseButton.vue'
|
||||||
|
import SvgIcon from '@/components/icons/SvgIcon.vue'
|
||||||
import { formatJalaaliDate } from '@/utils/date-utils'
|
import { formatJalaaliDate } from '@/utils/date-utils'
|
||||||
import LineTitleBlock from '@/components/LineTitleBlock.vue'
|
import LineTitleBlock from '@/components/LineTitleBlock.vue'
|
||||||
import VoiceRecorder from '@/components/form/VoiceRecorder.vue'
|
import VoiceRecorder from '@/components/form/VoiceRecorder.vue'
|
||||||
@@ -213,15 +236,19 @@ const modalData = computed(() => getModal('UserVerificationDetailsModal')?.data
|
|||||||
const userId = computed(() => modalData.value.id ?? null)
|
const userId = computed(() => modalData.value.id ?? null)
|
||||||
const userIdRef = computed(() => userId.value)
|
const userIdRef = computed(() => userId.value)
|
||||||
|
|
||||||
const { data: fetched } = useAdminUserQuery(userIdRef, {
|
const { data: fetched, isLoading: userLoading } = useAdminUserQuery(userIdRef, {
|
||||||
enabled: () => !!userIdRef.value,
|
enabled: () => !!userIdRef.value,
|
||||||
})
|
})
|
||||||
|
|
||||||
const { data: registerData } = useAdminUserRegisterDataQuery(userIdRef, {
|
const { data: registerData, isLoading: registerDataLoading } = useAdminUserRegisterDataQuery(
|
||||||
enabled: () => !!userIdRef.value,
|
userIdRef,
|
||||||
})
|
{
|
||||||
|
enabled: () => !!userIdRef.value,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const user = computed(() => modalData.value.user || fetched.value || null)
|
const user = computed(() => modalData.value.user || fetched.value || null)
|
||||||
|
const detailsLoading = computed(() => userLoading.value || registerDataLoading.value)
|
||||||
|
|
||||||
const profile = computed(() => ({ ...user.value?.profile, ...registerData.value }))
|
const profile = computed(() => ({ ...user.value?.profile, ...registerData.value }))
|
||||||
|
|
||||||
@@ -263,6 +290,49 @@ const onlinePlatformDetails = computed(
|
|||||||
// `faithProductionAudio` / `leaderMessageVideo` (each carries a `url`).
|
// `faithProductionAudio` / `leaderMessageVideo` (each carries a `url`).
|
||||||
const faithProduction = computed(() => profile.value.faithProductionAudio || null)
|
const faithProduction = computed(() => profile.value.faithProductionAudio || null)
|
||||||
const leaderMessage = computed(() => profile.value.leaderMessageVideo || null)
|
const leaderMessage = computed(() => profile.value.leaderMessageVideo || null)
|
||||||
|
|
||||||
|
const pdfContent = ref(null)
|
||||||
|
const pdfLoading = ref(false)
|
||||||
|
|
||||||
|
const onSaveAsPdf = async () => {
|
||||||
|
if (!pdfContent.value || !userId.value || detailsLoading.value || pdfLoading.value) return
|
||||||
|
|
||||||
|
pdfLoading.value = true
|
||||||
|
try {
|
||||||
|
await document.fonts?.ready
|
||||||
|
|
||||||
|
const pdfSource = pdfContent.value.cloneNode(true)
|
||||||
|
pdfSource.classList.add('user-verification-details--pdf')
|
||||||
|
pdfSource.querySelectorAll('[data-pdf-ignore]').forEach((element) => element.remove())
|
||||||
|
|
||||||
|
const html2pdfModule = await import('html2pdf.js')
|
||||||
|
const html2pdf = html2pdfModule.default || html2pdfModule
|
||||||
|
|
||||||
|
await html2pdf()
|
||||||
|
.set({
|
||||||
|
margin: [8, 8, 8, 8],
|
||||||
|
filename: `user-verification-${userId.value}.pdf`,
|
||||||
|
image: { type: 'jpeg', quality: 0.98 },
|
||||||
|
html2canvas: {
|
||||||
|
scale: 2,
|
||||||
|
useCORS: true,
|
||||||
|
backgroundColor: '#ffffff',
|
||||||
|
logging: false,
|
||||||
|
},
|
||||||
|
jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' },
|
||||||
|
pagebreak: {
|
||||||
|
mode: ['css', 'legacy'],
|
||||||
|
avoid: ['.user-verification-details__section'],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.from(pdfSource)
|
||||||
|
.save()
|
||||||
|
} catch {
|
||||||
|
toast.error('ساخت فایل PDF با خطا مواجه شد.')
|
||||||
|
} finally {
|
||||||
|
pdfLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -270,6 +340,10 @@ const leaderMessage = computed(() => profile.value.leaderMessageVideo || null)
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: start;
|
text-align: start;
|
||||||
|
|
||||||
|
&__pdf-header {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
&__loading {
|
&__loading {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
@@ -439,5 +513,61 @@ const leaderMessage = computed(() => profile.value.leaderMessageVideo || null)
|
|||||||
&__pdf-btn {
|
&__pdf-btn {
|
||||||
min-width: 12rem;
|
min-width: 12rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--pdf {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.25rem;
|
||||||
|
background: #fff;
|
||||||
|
box-sizing: border-box;
|
||||||
|
direction: rtl;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--pdf &__pdf-header {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
padding-bottom: 0.75rem;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
text-align: right;
|
||||||
|
break-after: avoid;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-family: var(--font-family-fa);
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #4b4b4b;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0.25rem 0 0;
|
||||||
|
font-family: var(--font-family-fa);
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: #808080;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--pdf &__section {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
break-inside: avoid;
|
||||||
|
page-break-inside: avoid;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--pdf &__grid--4 {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
&--pdf &__grid--6 {
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
&--pdf &__cell--span-3 {
|
||||||
|
grid-column: span 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--pdf :deep(.line-info__title) {
|
||||||
|
overflow: visible;
|
||||||
|
text-overflow: initial;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
:value="stat.value"
|
:value="stat.value"
|
||||||
:unit="stat.unit"
|
:unit="stat.unit"
|
||||||
:subtitle="stat.subtitle"
|
:subtitle="stat.subtitle"
|
||||||
|
:to="stat.to"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -91,6 +92,7 @@ const ticketStats = computed(() => {
|
|||||||
value: toFaDigits(stats.openTickets ?? 0),
|
value: toFaDigits(stats.openTickets ?? 0),
|
||||||
unit: 'تیکت',
|
unit: 'تیکت',
|
||||||
subtitle: 'در انتظار پاسخ',
|
subtitle: 'در انتظار پاسخ',
|
||||||
|
to: { name: 'counselor-consultations' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'check-circle',
|
icon: 'check-circle',
|
||||||
@@ -98,6 +100,7 @@ const ticketStats = computed(() => {
|
|||||||
value: toFaDigits(stats.answeredTickets ?? 0),
|
value: toFaDigits(stats.answeredTickets ?? 0),
|
||||||
unit: 'تیکت',
|
unit: 'تیکت',
|
||||||
subtitle: 'پاسخ داده شده',
|
subtitle: 'پاسخ داده شده',
|
||||||
|
to: { name: 'counselor-consultations' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'check',
|
icon: 'check',
|
||||||
@@ -105,6 +108,7 @@ const ticketStats = computed(() => {
|
|||||||
value: toFaDigits(stats.closedTickets ?? 0),
|
value: toFaDigits(stats.closedTickets ?? 0),
|
||||||
unit: 'تیکت',
|
unit: 'تیکت',
|
||||||
subtitle: 'بسته شده',
|
subtitle: 'بسته شده',
|
||||||
|
to: { name: 'counselor-consultations' },
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
:value="stat.value"
|
:value="stat.value"
|
||||||
:unit="stat.unit"
|
:unit="stat.unit"
|
||||||
:subtitle="stat.subtitle"
|
:subtitle="stat.subtitle"
|
||||||
|
:to="stat.to"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -91,6 +92,7 @@ const requestStats = computed(() => {
|
|||||||
value: toFaDigits(stats.totalRequests ?? 0),
|
value: toFaDigits(stats.totalRequests ?? 0),
|
||||||
unit: 'درخواست',
|
unit: 'درخواست',
|
||||||
subtitle: 'ثبت شده',
|
subtitle: 'ثبت شده',
|
||||||
|
to: { name: 'missionary-requests' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'check-circle',
|
icon: 'check-circle',
|
||||||
@@ -98,6 +100,7 @@ const requestStats = computed(() => {
|
|||||||
value: toFaDigits(stats.acceptedRequests ?? 0),
|
value: toFaDigits(stats.acceptedRequests ?? 0),
|
||||||
unit: 'درخواست',
|
unit: 'درخواست',
|
||||||
subtitle: 'پذیرفته شده',
|
subtitle: 'پذیرفته شده',
|
||||||
|
to: { name: 'missionary-requests' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'clock',
|
icon: 'clock',
|
||||||
@@ -105,6 +108,7 @@ const requestStats = computed(() => {
|
|||||||
value: toFaDigits(stats.pendingRequests ?? 0),
|
value: toFaDigits(stats.pendingRequests ?? 0),
|
||||||
unit: 'درخواست',
|
unit: 'درخواست',
|
||||||
subtitle: 'در انتظار',
|
subtitle: 'در انتظار',
|
||||||
|
to: { name: 'missionary-requests' },
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
:value="stat.value"
|
:value="stat.value"
|
||||||
:unit="stat.unit"
|
:unit="stat.unit"
|
||||||
:subtitle="stat.subtitle"
|
:subtitle="stat.subtitle"
|
||||||
|
:to="stat.to"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -95,6 +96,7 @@ const performanceStats = computed(() => {
|
|||||||
value: toFaDigits(stats.attendedSessions ?? 0),
|
value: toFaDigits(stats.attendedSessions ?? 0),
|
||||||
unit: 'جلسه',
|
unit: 'جلسه',
|
||||||
subtitle: 'اعزام شده است',
|
subtitle: 'اعزام شده است',
|
||||||
|
to: { name: 'student-terms' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'video',
|
icon: 'video',
|
||||||
@@ -102,6 +104,7 @@ const performanceStats = computed(() => {
|
|||||||
value: toFaDigits(stats.enrolledTerms ?? 0),
|
value: toFaDigits(stats.enrolledTerms ?? 0),
|
||||||
unit: 'دوره',
|
unit: 'دوره',
|
||||||
subtitle: 'خریداری شده',
|
subtitle: 'خریداری شده',
|
||||||
|
to: { name: 'student-terms' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'clock',
|
icon: 'clock',
|
||||||
@@ -109,6 +112,7 @@ const performanceStats = computed(() => {
|
|||||||
value: toFaDigits(stats.hoursSpent ?? 0),
|
value: toFaDigits(stats.hoursSpent ?? 0),
|
||||||
unit: 'ساعت',
|
unit: 'ساعت',
|
||||||
subtitle: 'گذرانده شده',
|
subtitle: 'گذرانده شده',
|
||||||
|
to: { name: 'student-terms' },
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="stat-card">
|
<component
|
||||||
|
:is="to ? RouterLink : 'div'"
|
||||||
|
:to="to || undefined"
|
||||||
|
class="stat-card"
|
||||||
|
:class="{ 'stat-card--linked': to }"
|
||||||
|
>
|
||||||
<SvgIcon name="card-corner-arrow" :size="'1.5rem'" class="stat-card__corner" />
|
<SvgIcon name="card-corner-arrow" :size="'1.5rem'" class="stat-card__corner" />
|
||||||
|
|
||||||
<div class="stat-card__head">
|
<div class="stat-card__head">
|
||||||
@@ -14,10 +19,11 @@
|
|||||||
<span class="stat-card__subtitle">{{ subtitle }}</span>
|
<span class="stat-card__subtitle">{{ subtitle }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</component>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { RouterLink } from 'vue-router'
|
||||||
import SvgIcon from '@/components/icons/SvgIcon.vue'
|
import SvgIcon from '@/components/icons/SvgIcon.vue'
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
@@ -27,6 +33,7 @@ defineProps({
|
|||||||
value: { type: [String, Number], default: '' },
|
value: { type: [String, Number], default: '' },
|
||||||
unit: { type: String, default: '' },
|
unit: { type: String, default: '' },
|
||||||
subtitle: { type: String, default: '' },
|
subtitle: { type: String, default: '' },
|
||||||
|
to: { type: [String, Object], default: null },
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -41,6 +48,23 @@ defineProps({
|
|||||||
background: rgba(255, 255, 255, 58%);
|
background: rgba(255, 255, 255, 58%);
|
||||||
box-shadow: 0 6.75px 19.425px rgba(0, 0, 0, 4%);
|
box-shadow: 0 6.75px 19.425px rgba(0, 0, 0, 4%);
|
||||||
border-radius: 0.9375rem;
|
border-radius: 0.9375rem;
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
|
||||||
|
&--linked {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 9px 24px rgba(0, 0, 0, 7%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
outline: 2px solid var(--color-primary);
|
||||||
|
outline-offset: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&__corner {
|
&__corner {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|||||||
@@ -3,11 +3,14 @@
|
|||||||
<form class="csf__form" @submit.prevent="onSubmit">
|
<form class="csf__form" @submit.prevent="onSubmit">
|
||||||
<div class="csf__row">
|
<div class="csf__row">
|
||||||
<div class="csf__cell">
|
<div class="csf__cell">
|
||||||
<TextField
|
<SelectField
|
||||||
v-model="form.category"
|
v-model="form.category"
|
||||||
name="category"
|
name="category"
|
||||||
label="نوع خدمت"
|
label="نوع خدمت"
|
||||||
placeholder="نوع خدمت را وارد کنید"
|
placeholder="نوع خدمت را انتخاب کنید"
|
||||||
|
:options="serviceTypeOptions"
|
||||||
|
option-label="label"
|
||||||
|
option-value="value"
|
||||||
:error="errors.category"
|
:error="errors.category"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -71,6 +74,7 @@ import useYup from '@/composables/useYup'
|
|||||||
import BaseButton from '@/components/BaseButton.vue'
|
import BaseButton from '@/components/BaseButton.vue'
|
||||||
import SvgIcon from '@/components/icons/SvgIcon.vue'
|
import SvgIcon from '@/components/icons/SvgIcon.vue'
|
||||||
import TextField from '@/components/form/TextField.vue'
|
import TextField from '@/components/form/TextField.vue'
|
||||||
|
import SelectField from '@/components/form/SelectField.vue'
|
||||||
import FileUploader from '@/components/form/FileUploader.vue'
|
import FileUploader from '@/components/form/FileUploader.vue'
|
||||||
import { objectToFormData } from '@/utils/object-to-formdata'
|
import { objectToFormData } from '@/utils/object-to-formdata'
|
||||||
import { useUploadMediaMutation } from '@/services/query/auth'
|
import { useUploadMediaMutation } from '@/services/query/auth'
|
||||||
@@ -82,6 +86,11 @@ defineProps({
|
|||||||
|
|
||||||
const emit = defineEmits(['submit', 'file-error'])
|
const emit = defineEmits(['submit', 'file-error'])
|
||||||
|
|
||||||
|
const serviceTypeOptions = [
|
||||||
|
{ value: 'خدمات رفاهی', label: 'خدمات رفاهی' },
|
||||||
|
{ value: 'خدمات آموزشی', label: 'خدمات آموزشی' },
|
||||||
|
]
|
||||||
|
|
||||||
const form = ref({
|
const form = ref({
|
||||||
category: '',
|
category: '',
|
||||||
subject: '',
|
subject: '',
|
||||||
@@ -94,7 +103,7 @@ const form = ref({
|
|||||||
const files = ref([])
|
const files = ref([])
|
||||||
|
|
||||||
const schema = yup.object({
|
const schema = yup.object({
|
||||||
category: yup.string().trim().required('نوع خدمت را وارد کنید'),
|
category: yup.string().trim().required('نوع خدمت را انتخاب کنید'),
|
||||||
subject: yup.string().trim().required('عنوان خدمت را وارد کنید'),
|
subject: yup.string().trim().required('عنوان خدمت را وارد کنید'),
|
||||||
message: yup
|
message: yup
|
||||||
.string()
|
.string()
|
||||||
|
|||||||
@@ -84,12 +84,6 @@ const menuItems = computed(() => [
|
|||||||
to: { name: 'student-services' },
|
to: { name: 'student-services' },
|
||||||
active: route.name === 'student-services',
|
active: route.name === 'student-services',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: 'مشاوره',
|
|
||||||
icon: 'chat-teardrop-text',
|
|
||||||
to: { name: 'student-consultants' },
|
|
||||||
active: route.name === 'student-consultants',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: 'گواهینامه',
|
title: 'گواهینامه',
|
||||||
icon: 'certificate',
|
icon: 'certificate',
|
||||||
|
|||||||
@@ -11,10 +11,16 @@ export const adminDashboard = {
|
|||||||
openTickets: 32,
|
openTickets: 32,
|
||||||
},
|
},
|
||||||
stats: {
|
stats: {
|
||||||
activeUsers: 11_000,
|
totalApplicants: 18,
|
||||||
totalUsers: 11_540,
|
awaitingEvaluation: 1,
|
||||||
coursesCreated: 6,
|
term1Students: 2,
|
||||||
coursesSold: 12,
|
term2Students: 0,
|
||||||
|
term3Students: 1,
|
||||||
|
graduates: 0,
|
||||||
|
activeUsers: 11,
|
||||||
|
totalUsers: 24,
|
||||||
|
coursesCreated: 4,
|
||||||
|
coursesSold: 3,
|
||||||
},
|
},
|
||||||
recentRegistrations: [
|
recentRegistrations: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,4 +2,8 @@ import { register } from '@/services/mock/registry'
|
|||||||
import { endpoints } from '@/services/api/endpoints'
|
import { endpoints } from '@/services/api/endpoints'
|
||||||
import { adminDashboard } from '@/services/mock/fixtures/admin-dashboard'
|
import { adminDashboard } from '@/services/mock/fixtures/admin-dashboard'
|
||||||
|
|
||||||
register('GET', endpoints.getAdminDashboard, () => ({ data: adminDashboard }))
|
register('GET', endpoints.getAdminDashboard, () => ({
|
||||||
|
success: true,
|
||||||
|
message: 'انجام شد.',
|
||||||
|
data: adminDashboard,
|
||||||
|
}))
|
||||||
|
|||||||
@@ -2,4 +2,8 @@ import { register } from '@/services/mock/registry'
|
|||||||
import { endpoints } from '@/services/api/endpoints'
|
import { endpoints } from '@/services/api/endpoints'
|
||||||
import { counselorDashboard } from '@/services/mock/fixtures/counselor-dashboard'
|
import { counselorDashboard } from '@/services/mock/fixtures/counselor-dashboard'
|
||||||
|
|
||||||
register('GET', endpoints.getCounselorDashboard, () => ({ data: counselorDashboard }))
|
register('GET', endpoints.getCounselorDashboard, () => ({
|
||||||
|
success: true,
|
||||||
|
message: 'انجام شد.',
|
||||||
|
data: counselorDashboard,
|
||||||
|
}))
|
||||||
|
|||||||
@@ -2,4 +2,8 @@ import { register } from '@/services/mock/registry'
|
|||||||
import { endpoints } from '@/services/api/endpoints'
|
import { endpoints } from '@/services/api/endpoints'
|
||||||
import { missionaryDashboard } from '@/services/mock/fixtures/missionary-dashboard'
|
import { missionaryDashboard } from '@/services/mock/fixtures/missionary-dashboard'
|
||||||
|
|
||||||
register('GET', endpoints.getMissionaryDashboard, () => ({ data: missionaryDashboard }))
|
register('GET', endpoints.getMissionaryDashboard, () => ({
|
||||||
|
success: true,
|
||||||
|
message: 'انجام شد.',
|
||||||
|
data: missionaryDashboard,
|
||||||
|
}))
|
||||||
|
|||||||
@@ -2,4 +2,8 @@ import { register } from '@/services/mock/registry'
|
|||||||
import { endpoints } from '@/services/api/endpoints'
|
import { endpoints } from '@/services/api/endpoints'
|
||||||
import { studentDashboard } from '@/services/mock/fixtures/student-dashboard'
|
import { studentDashboard } from '@/services/mock/fixtures/student-dashboard'
|
||||||
|
|
||||||
register('GET', endpoints.getStudentDashboard, () => ({ data: studentDashboard }))
|
register('GET', endpoints.getStudentDashboard, () => ({
|
||||||
|
success: true,
|
||||||
|
message: 'انجام شد.',
|
||||||
|
data: studentDashboard,
|
||||||
|
}))
|
||||||
|
|||||||
Reference in New Issue
Block a user