Merge branch 'net-chat' into develop
This commit is contained in:
commit
bbb14c060f
16 changed files with 8159 additions and 70 deletions
249
package-lock.json
generated
249
package-lock.json
generated
|
|
@ -26,6 +26,7 @@
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
"pinia": "^2.0.29",
|
"pinia": "^2.0.29",
|
||||||
"quasar": "^2.11.1",
|
"quasar": "^2.11.1",
|
||||||
|
"socket.io-client": "^4.7.4",
|
||||||
"structure-chart": "^0.0.9",
|
"structure-chart": "^0.0.9",
|
||||||
"vue": "^3.4.15",
|
"vue": "^3.4.15",
|
||||||
"vue-currency-input": "^3.0.5",
|
"vue-currency-input": "^3.0.5",
|
||||||
|
|
@ -1493,6 +1494,11 @@
|
||||||
"integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==",
|
"integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@socket.io/component-emitter": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
|
||||||
|
},
|
||||||
"node_modules/@stencil/core": {
|
"node_modules/@stencil/core": {
|
||||||
"version": "2.22.3",
|
"version": "2.22.3",
|
||||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.22.3.tgz",
|
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.22.3.tgz",
|
||||||
|
|
@ -2644,30 +2650,6 @@
|
||||||
"integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==",
|
"integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/axios": {
|
|
||||||
"version": "0.27.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
|
|
||||||
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"follow-redirects": "^1.14.9",
|
|
||||||
"form-data": "^4.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/axios/node_modules/form-data": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
|
||||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"asynckit": "^0.4.0",
|
|
||||||
"combined-stream": "^1.0.8",
|
|
||||||
"mime-types": "^2.1.12"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/balanced-match": {
|
"node_modules/balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
|
|
@ -3712,7 +3694,6 @@
|
||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||||
"devOptional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ms": "2.1.2"
|
"ms": "2.1.2"
|
||||||
},
|
},
|
||||||
|
|
@ -4024,6 +4005,46 @@
|
||||||
"once": "^1.4.0"
|
"once": "^1.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/engine.io-client": {
|
||||||
|
"version": "6.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz",
|
||||||
|
"integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
|
"debug": "~4.3.1",
|
||||||
|
"engine.io-parser": "~5.2.1",
|
||||||
|
"ws": "~8.11.0",
|
||||||
|
"xmlhttprequest-ssl": "~2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/engine.io-client/node_modules/ws": {
|
||||||
|
"version": "8.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
|
||||||
|
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"bufferutil": "^4.0.1",
|
||||||
|
"utf-8-validate": "^5.0.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"bufferutil": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"utf-8-validate": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/engine.io-parser": {
|
||||||
|
"version": "5.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz",
|
||||||
|
"integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/enquirer": {
|
"node_modules/enquirer": {
|
||||||
"version": "2.4.1",
|
"version": "2.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz",
|
||||||
|
|
@ -4929,9 +4950,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/follow-redirects": {
|
"node_modules/follow-redirects": {
|
||||||
"version": "1.15.2",
|
"version": "1.15.5",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
|
||||||
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
|
"integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
|
@ -7217,8 +7238,7 @@
|
||||||
"node_modules/ms": {
|
"node_modules/ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
"devOptional": true
|
|
||||||
},
|
},
|
||||||
"node_modules/muggle-string": {
|
"node_modules/muggle-string": {
|
||||||
"version": "0.3.1",
|
"version": "0.3.1",
|
||||||
|
|
@ -9330,6 +9350,32 @@
|
||||||
"npm": ">= 3.0.0"
|
"npm": ">= 3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/socket.io-client": {
|
||||||
|
"version": "4.7.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.4.tgz",
|
||||||
|
"integrity": "sha512-wh+OkeF0rAVCrABWQBaEjLfb7DVPotMbu0cgWgyR0v6eA4EoVnAwcIeIbcdTE3GT/H3kbdLl7OoH2+asoDRIIg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
|
"debug": "~4.3.2",
|
||||||
|
"engine.io-client": "~6.5.2",
|
||||||
|
"socket.io-parser": "~4.2.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/socket.io-parser": {
|
||||||
|
"version": "4.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
|
||||||
|
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
|
||||||
|
"dependencies": {
|
||||||
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
|
"debug": "~4.3.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/socks": {
|
"node_modules/socks": {
|
||||||
"version": "2.7.1",
|
"version": "2.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz",
|
||||||
|
|
@ -10683,6 +10729,30 @@
|
||||||
"node": ">=12.0.0"
|
"node": ">=12.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/wait-on/node_modules/axios": {
|
||||||
|
"version": "0.27.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
|
||||||
|
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"follow-redirects": "^1.14.9",
|
||||||
|
"form-data": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/wait-on/node_modules/form-data": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"asynckit": "^0.4.0",
|
||||||
|
"combined-stream": "^1.0.8",
|
||||||
|
"mime-types": "^2.1.12"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/web-streams-polyfill": {
|
"node_modules/web-streams-polyfill": {
|
||||||
"version": "3.2.1",
|
"version": "3.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
|
||||||
|
|
@ -10890,6 +10960,14 @@
|
||||||
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
|
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/xmlhttprequest-ssl": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/xss": {
|
"node_modules/xss": {
|
||||||
"version": "1.0.13",
|
"version": "1.0.13",
|
||||||
"resolved": "https://registry.npmjs.org/xss/-/xss-1.0.13.tgz",
|
"resolved": "https://registry.npmjs.org/xss/-/xss-1.0.13.tgz",
|
||||||
|
|
@ -11969,6 +12047,11 @@
|
||||||
"integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==",
|
"integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@socket.io/component-emitter": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
|
||||||
|
},
|
||||||
"@stencil/core": {
|
"@stencil/core": {
|
||||||
"version": "2.22.3",
|
"version": "2.22.3",
|
||||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.22.3.tgz",
|
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.22.3.tgz",
|
||||||
|
|
@ -12818,29 +12901,6 @@
|
||||||
"integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==",
|
"integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"axios": {
|
|
||||||
"version": "0.27.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
|
|
||||||
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"follow-redirects": "^1.14.9",
|
|
||||||
"form-data": "^4.0.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"form-data": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
|
||||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"asynckit": "^0.4.0",
|
|
||||||
"combined-stream": "^1.0.8",
|
|
||||||
"mime-types": "^2.1.12"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
|
|
@ -13632,7 +13692,6 @@
|
||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||||
"devOptional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"ms": "2.1.2"
|
"ms": "2.1.2"
|
||||||
}
|
}
|
||||||
|
|
@ -13876,6 +13935,31 @@
|
||||||
"once": "^1.4.0"
|
"once": "^1.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"engine.io-client": {
|
||||||
|
"version": "6.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz",
|
||||||
|
"integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==",
|
||||||
|
"requires": {
|
||||||
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
|
"debug": "~4.3.1",
|
||||||
|
"engine.io-parser": "~5.2.1",
|
||||||
|
"ws": "~8.11.0",
|
||||||
|
"xmlhttprequest-ssl": "~2.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ws": {
|
||||||
|
"version": "8.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
|
||||||
|
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
|
||||||
|
"requires": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"engine.io-parser": {
|
||||||
|
"version": "5.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz",
|
||||||
|
"integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw=="
|
||||||
|
},
|
||||||
"enquirer": {
|
"enquirer": {
|
||||||
"version": "2.4.1",
|
"version": "2.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz",
|
||||||
|
|
@ -14552,9 +14636,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"follow-redirects": {
|
"follow-redirects": {
|
||||||
"version": "1.15.2",
|
"version": "1.15.5",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
|
||||||
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
|
"integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"for-each": {
|
"for-each": {
|
||||||
|
|
@ -16259,8 +16343,7 @@
|
||||||
"ms": {
|
"ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
"devOptional": true
|
|
||||||
},
|
},
|
||||||
"muggle-string": {
|
"muggle-string": {
|
||||||
"version": "0.3.1",
|
"version": "0.3.1",
|
||||||
|
|
@ -17794,6 +17877,26 @@
|
||||||
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
|
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"socket.io-client": {
|
||||||
|
"version": "4.7.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.4.tgz",
|
||||||
|
"integrity": "sha512-wh+OkeF0rAVCrABWQBaEjLfb7DVPotMbu0cgWgyR0v6eA4EoVnAwcIeIbcdTE3GT/H3kbdLl7OoH2+asoDRIIg==",
|
||||||
|
"requires": {
|
||||||
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
|
"debug": "~4.3.2",
|
||||||
|
"engine.io-client": "~6.5.2",
|
||||||
|
"socket.io-parser": "~4.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"socket.io-parser": {
|
||||||
|
"version": "4.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
|
||||||
|
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
|
||||||
|
"requires": {
|
||||||
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
|
"debug": "~4.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"socks": {
|
"socks": {
|
||||||
"version": "2.7.1",
|
"version": "2.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz",
|
||||||
|
|
@ -18773,6 +18876,29 @@
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"minimist": "^1.2.7",
|
"minimist": "^1.2.7",
|
||||||
"rxjs": "^7.8.0"
|
"rxjs": "^7.8.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": {
|
||||||
|
"version": "0.27.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
|
||||||
|
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"follow-redirects": "^1.14.9",
|
||||||
|
"form-data": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"form-data": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"asynckit": "^0.4.0",
|
||||||
|
"combined-stream": "^1.0.8",
|
||||||
|
"mime-types": "^2.1.12"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"web-streams-polyfill": {
|
"web-streams-polyfill": {
|
||||||
|
|
@ -18922,6 +19048,11 @@
|
||||||
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
|
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"xmlhttprequest-ssl": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A=="
|
||||||
|
},
|
||||||
"xss": {
|
"xss": {
|
||||||
"version": "1.0.13",
|
"version": "1.0.13",
|
||||||
"resolved": "https://registry.npmjs.org/xss/-/xss-1.0.13.tgz",
|
"resolved": "https://registry.npmjs.org/xss/-/xss-1.0.13.tgz",
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
"pinia": "^2.0.29",
|
"pinia": "^2.0.29",
|
||||||
"quasar": "^2.11.1",
|
"quasar": "^2.11.1",
|
||||||
|
"socket.io-client": "^4.7.4",
|
||||||
"structure-chart": "^0.0.9",
|
"structure-chart": "^0.0.9",
|
||||||
"vue": "^3.4.15",
|
"vue": "^3.4.15",
|
||||||
"vue-currency-input": "^3.0.5",
|
"vue-currency-input": "^3.0.5",
|
||||||
|
|
|
||||||
6498
pnpm-lock.yaml
generated
Normal file
6498
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load diff
28
src/api/00_support/api.support.ts
Normal file
28
src/api/00_support/api.support.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import env from "../index";
|
||||||
|
|
||||||
|
export const supportIssue = `${env.API_SUPPORT_URI}/issue`;
|
||||||
|
export const supportSearchIssue = (id: string) =>
|
||||||
|
`${env.API_SUPPORT_URI}/issue?search=${id}`;
|
||||||
|
export const supportCategory = `${env.API_SUPPORT_URI}/Issue-category`;
|
||||||
|
export const supportCategoryAction = (id: string) =>
|
||||||
|
`${env.API_SUPPORT_URI}/Issue-category/${id}`;
|
||||||
|
export const supportIssueChangeStatus = (id: string) =>
|
||||||
|
`${env.API_SUPPORT_URI}/issue/${id}`;
|
||||||
|
export const supportMessage = (id: string) =>
|
||||||
|
`${env.API_SUPPORT_URI}/issue/${id}/message`;
|
||||||
|
|
||||||
|
export const supportMessageStatus = (id: string) =>
|
||||||
|
`${env.API_SUPPORT_URI}/issue/${id}/message-status`;
|
||||||
|
|
||||||
|
export const supportSocket = `${env.API_SUPPORT_URI}`;
|
||||||
|
|
||||||
|
export default {
|
||||||
|
supportIssue,
|
||||||
|
supportCategory,
|
||||||
|
supportSocket,
|
||||||
|
supportMessage,
|
||||||
|
supportMessageStatus,
|
||||||
|
supportIssueChangeStatus,
|
||||||
|
supportCategoryAction,
|
||||||
|
supportSearchIssue,
|
||||||
|
};
|
||||||
|
|
@ -35,6 +35,7 @@ const config = ref<any>({
|
||||||
LINK_EVALUATE_PUBLISH: "https://bma-ehr-publish.frappet.synology.me",
|
LINK_EVALUATE_PUBLISH: "https://bma-ehr-publish.frappet.synology.me",
|
||||||
API_REPORT_TEMPLATE_URI:
|
API_REPORT_TEMPLATE_URI:
|
||||||
"https://report-server.frappet.synology.me/api/v1/report-template",
|
"https://report-server.frappet.synology.me/api/v1/report-template",
|
||||||
|
API_SUPPORT_URI: "https://bma-ehr.frappet.synology.me/api/v1/support",
|
||||||
},
|
},
|
||||||
test: {
|
test: {
|
||||||
API_URI: "http://localhost:5010/api/v1",
|
API_URI: "http://localhost:5010/api/v1",
|
||||||
|
|
@ -59,9 +60,11 @@ const config = ref<any>({
|
||||||
API_REPORT2_URI: `${window.location.protocol}//${window.location.host}/api/v2`,
|
API_REPORT2_URI: `${window.location.protocol}//${window.location.host}/api/v2`,
|
||||||
LINK_EVALUATE_PUBLISH: apiUrlConfigPublish,
|
LINK_EVALUATE_PUBLISH: apiUrlConfigPublish,
|
||||||
API_REPORT_TEMPLATE_URI: apiUrlConfigReport,
|
API_REPORT_TEMPLATE_URI: apiUrlConfigReport,
|
||||||
|
API_SUPPORT_URI: `${window.location.protocol}//${window.location.host}/api/v1/support`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const API_SUPPORT_URI = ref<string>(config.value[env.value].API_SUPPORT_URI);
|
||||||
const API_URI = ref<string>(config.value[env.value].API_URI);
|
const API_URI = ref<string>(config.value[env.value].API_URI);
|
||||||
const API_CANDIDATE_URI = ref<string>(
|
const API_CANDIDATE_URI = ref<string>(
|
||||||
config.value[env.value].API_CANDIDATE_URI
|
config.value[env.value].API_CANDIDATE_URI
|
||||||
|
|
@ -112,4 +115,5 @@ export default {
|
||||||
API_REPORT2_URI: API_REPORT2_URI.value,
|
API_REPORT2_URI: API_REPORT2_URI.value,
|
||||||
LINK_EVALUATE_PUBLISH: LINK_EVALUATE_PUBLISH.value,
|
LINK_EVALUATE_PUBLISH: LINK_EVALUATE_PUBLISH.value,
|
||||||
API_REPORT_TEMPLATE_URI: API_REPORT_TEMPLATE_URI.value,
|
API_REPORT_TEMPLATE_URI: API_REPORT_TEMPLATE_URI.value,
|
||||||
|
API_SUPPORT_URI: API_SUPPORT_URI.value,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,8 @@ import evaluate from "./api/12_evaluatePersonal/api.evaluate";
|
||||||
/** API โครงสร้างอัตรากำลัง*/
|
/** API โครงสร้างอัตรากำลัง*/
|
||||||
import organization from "./api/02_organizational/api.organization";
|
import organization from "./api/02_organizational/api.organization";
|
||||||
|
|
||||||
|
import support from "./api/00_support/api.support";
|
||||||
|
|
||||||
/** API เงินเดือน/ค่าจ้าง*/
|
/** API เงินเดือน/ค่าจ้าง*/
|
||||||
import salary from "./api/13_salary/api.salary";
|
import salary from "./api/13_salary/api.salary";
|
||||||
|
|
||||||
|
|
@ -120,6 +122,9 @@ const API = {
|
||||||
/**evaluate*/
|
/**evaluate*/
|
||||||
...evaluate,
|
...evaluate,
|
||||||
|
|
||||||
|
/** support */
|
||||||
|
...support,
|
||||||
|
|
||||||
...salary,
|
...salary,
|
||||||
...KPI,
|
...KPI,
|
||||||
...development,
|
...development,
|
||||||
|
|
|
||||||
133
src/modules/00_support/components/DialogStatus.vue
Normal file
133
src/modules/00_support/components/DialogStatus.vue
Normal file
|
|
@ -0,0 +1,133 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { useSupportStore } from "@/modules/00_support/store/Main";
|
||||||
|
import dialogHeader from "@/components/DialogHeader.vue";
|
||||||
|
const store = useSupportStore();
|
||||||
|
const open = ref<boolean>(false);
|
||||||
|
|
||||||
|
const statusIssue: ("ปัญหาใหม่" | "กำลังดำเนินการ" | "เสร็จสิ้น")[] = [
|
||||||
|
"ปัญหาใหม่",
|
||||||
|
"กำลังดำเนินการ",
|
||||||
|
"เสร็จสิ้น",
|
||||||
|
];
|
||||||
|
|
||||||
|
const status = ref<"ปัญหาใหม่" | "กำลังดำเนินการ" | "เสร็จสิ้น">(
|
||||||
|
store.correntStatusIssue == "new"
|
||||||
|
? "ปัญหาใหม่"
|
||||||
|
: store.correntStatusIssue == "ongoing"
|
||||||
|
? "กำลังดำเนินการ"
|
||||||
|
: "เสร็จสิ้น"
|
||||||
|
);
|
||||||
|
|
||||||
|
function saveData(inputStatus: "ปัญหาใหม่" | "กำลังดำเนินการ" | "เสร็จสิ้น") {
|
||||||
|
const statusEn: "new" | "ongoing" | "resolved" =
|
||||||
|
inputStatus == "ปัญหาใหม่"
|
||||||
|
? "new"
|
||||||
|
: inputStatus == "กำลังดำเนินการ"
|
||||||
|
? "ongoing"
|
||||||
|
: "resolved";
|
||||||
|
store.ChangeStatusIssue(
|
||||||
|
store.currentIssue,
|
||||||
|
store.currentTitle,
|
||||||
|
store.currentCategoryId,
|
||||||
|
statusEn
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
issueId: String,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<q-btn icon="more_vert" dense flat size="11px" @click.stop>
|
||||||
|
<q-menu transition-show="jump-down" transition-hide="jump-up">
|
||||||
|
<q-list style="min-width: 100px">
|
||||||
|
<q-item
|
||||||
|
clickable
|
||||||
|
v-close-popup
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
console.log('เเก้ไข ' + issueId);
|
||||||
|
open = true;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<q-item-section>
|
||||||
|
<div class="row items-center white">
|
||||||
|
<q-icon name="o_edit" color="positive" />
|
||||||
|
<span class="q-ml-sm">แก้ไขสถานะ</span>
|
||||||
|
</div></q-item-section
|
||||||
|
>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-menu>
|
||||||
|
</q-btn>
|
||||||
|
|
||||||
|
<q-dialog v-model="open" class="dialog" persistent>
|
||||||
|
<q-card style="min-width: 350px" class="bg-grey-11">
|
||||||
|
<q-card-section class="flex justify-between" style="padding: 0">
|
||||||
|
<dialog-header
|
||||||
|
tittle="แก้ไขสถานะ"
|
||||||
|
:close="
|
||||||
|
() => {
|
||||||
|
open = false;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-separator color="grey-4" />
|
||||||
|
<q-card-section class="q-pa-none align-center">
|
||||||
|
<div class="bg-white q-ma-sm border_black">
|
||||||
|
<q-select
|
||||||
|
class="q-my-sm q-mx-sm"
|
||||||
|
style="width: 280px"
|
||||||
|
borderless
|
||||||
|
dense
|
||||||
|
outlined
|
||||||
|
color="secondary"
|
||||||
|
v-model="status"
|
||||||
|
:options="statusIssue"
|
||||||
|
label="สถานะ"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</q-card-section>
|
||||||
|
<q-separator color="grey-4" />
|
||||||
|
<q-card-actions align="right">
|
||||||
|
<q-btn
|
||||||
|
id="onSubmit"
|
||||||
|
type="submit"
|
||||||
|
dense
|
||||||
|
unelevated
|
||||||
|
label="บันทึก"
|
||||||
|
color="public"
|
||||||
|
class="q-px-md"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
saveData(status);
|
||||||
|
open = false;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<q-tooltip>บันทึกข้อมูล</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
|
</q-card-actions>
|
||||||
|
</q-card>
|
||||||
|
</q-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.border_black {
|
||||||
|
border: solid 1px rgb(200, 211, 219);
|
||||||
|
padding: 2px;
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.align-center {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
466
src/modules/00_support/components/FormChat.vue
Normal file
466
src/modules/00_support/components/FormChat.vue
Normal file
|
|
@ -0,0 +1,466 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import "moment/dist/locale/th";
|
||||||
|
import moment from "moment";
|
||||||
|
import DialogStatus from "@/modules/00_support/components/DialogStatus.vue";
|
||||||
|
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
import { storeToRefs } from "pinia";
|
||||||
|
import { useSupportStore } from "@/modules/00_support/store/Main";
|
||||||
|
import type { QInfiniteScroll, QInfiniteScrollProps } from "quasar";
|
||||||
|
|
||||||
|
const store = useSupportStore();
|
||||||
|
const content = ref<string>("");
|
||||||
|
const searchInput = ref<string>("");
|
||||||
|
const currentIssuePage = ref<number>(1);
|
||||||
|
const totalPageIssue = ref<number>();
|
||||||
|
const iconAvatar = ref<string>(
|
||||||
|
"https://bma-ehr.frappet.synology.me/assets/avatar_user-8c8fe276.jpg"
|
||||||
|
);
|
||||||
|
|
||||||
|
const { scrollContainer } = storeToRefs(store);
|
||||||
|
function dateIssue(timestamp: string): string {
|
||||||
|
const parsedTimestamp = moment(timestamp);
|
||||||
|
const diff = moment().diff(parsedTimestamp);
|
||||||
|
|
||||||
|
if (diff < 1000) {
|
||||||
|
return "just now";
|
||||||
|
} else if (diff < 60000) {
|
||||||
|
return `${Math.floor(diff / 1000)}s`;
|
||||||
|
} else if (diff < 3600000) {
|
||||||
|
return `${Math.floor(diff / 60000)}m`;
|
||||||
|
} else if (diff < 86400000) {
|
||||||
|
return `${Math.floor(diff / 3600000)}h`;
|
||||||
|
} else {
|
||||||
|
const beYear = parsedTimestamp.year() + 543;
|
||||||
|
const formattedDate = parsedTimestamp.clone().year(beYear).format("DD MMM");
|
||||||
|
return formattedDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOnlineStatus(option: "icon" | "status", userId: string) {
|
||||||
|
const isOnline: boolean = store.userStatus.some((u) =>
|
||||||
|
u.userId.includes(userId)
|
||||||
|
);
|
||||||
|
if (option === "icon") return isOnline ? "green" : "grey";
|
||||||
|
if (option === "status") return isOnline ? "ออนไลน์" : "ออฟไลน์";
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateCategory(category: String | undefined) {
|
||||||
|
if (!!category) return category;
|
||||||
|
return "ระบุไม่ได้";
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
if (store.currentIssue) {
|
||||||
|
await store.fetchIssue();
|
||||||
|
}
|
||||||
|
await store.fetchIssue();
|
||||||
|
totalPageIssue.value = Math.ceil((store.currentTotalIssue || 0) / 30);
|
||||||
|
});
|
||||||
|
|
||||||
|
const onLoad = (async (_: any, done: any) => {
|
||||||
|
const totalPages = Math.ceil((store.currentTotalMessage || 1) / 30);
|
||||||
|
if (store.currentPage && totalPages > store.currentPage) {
|
||||||
|
await store.loadMessage(store.currentPage + 1);
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
}) satisfies QInfiniteScrollProps["onLoad"];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex">
|
||||||
|
<p class="text-h6 text-weight-medium align-center">ถาม - ตอบ</p>
|
||||||
|
<q-space />
|
||||||
|
<p>
|
||||||
|
<q-btn
|
||||||
|
dense
|
||||||
|
color="secondary"
|
||||||
|
class="button-link-no-deco q-px-md"
|
||||||
|
@click="$router.push('/support/category')"
|
||||||
|
>
|
||||||
|
จัดการประเภทของปัญหา
|
||||||
|
</q-btn>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="i1 bg-white align-center">
|
||||||
|
<q-toolbar>
|
||||||
|
<q-item-section>
|
||||||
|
<q-input
|
||||||
|
dense
|
||||||
|
rounded
|
||||||
|
outlined
|
||||||
|
label="ค้นหาข้อความ..."
|
||||||
|
v-model="searchInput"
|
||||||
|
@keydown.enter.prevent="
|
||||||
|
() => {
|
||||||
|
store.searchIssue(searchInput);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<q-icon name="search" />
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
</q-item-section>
|
||||||
|
</q-toolbar>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="i2 bg-white align-center">
|
||||||
|
<q-toolbar>
|
||||||
|
<q-avatar>
|
||||||
|
<img :src="iconAvatar" />
|
||||||
|
</q-avatar>
|
||||||
|
<q-item-section v-if="store.currentIssue" class="q-pl-sm">
|
||||||
|
<q-item-label>
|
||||||
|
<span class="tite-on-message-long">
|
||||||
|
<q-badge color="blue" outline>
|
||||||
|
{{ validateCategory(store.currentCategory) }}
|
||||||
|
</q-badge>
|
||||||
|
</span>
|
||||||
|
</q-item-label>
|
||||||
|
<span>
|
||||||
|
<q-icon
|
||||||
|
name="mdi-circle"
|
||||||
|
size="10px"
|
||||||
|
:color="getOnlineStatus('icon', store.createdByUserId)"
|
||||||
|
/>
|
||||||
|
{{ getOnlineStatus("status", store.createdByUserId) }}
|
||||||
|
</span>
|
||||||
|
</q-item-section>
|
||||||
|
|
||||||
|
<q-space />
|
||||||
|
|
||||||
|
<div v-if="store.currentIssue">
|
||||||
|
<q-badge
|
||||||
|
color="white"
|
||||||
|
text-color="black"
|
||||||
|
:label="
|
||||||
|
store.correntStatusIssue == 'new'
|
||||||
|
? 'ปัญหาใหม่'
|
||||||
|
: store.correntStatusIssue == 'ongoing'
|
||||||
|
? 'กำลังดำเนินการ'
|
||||||
|
: 'เสร็จสิ้น'
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<dialog-status />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<q-btn flat round dense icon="o_info" text-color="grey" />
|
||||||
|
</q-toolbar>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="i3 bg-white scroll">
|
||||||
|
<div v-for="(item, index) in store.issue?.result" :key="index">
|
||||||
|
<div
|
||||||
|
@click="
|
||||||
|
async () => {
|
||||||
|
store.currentIssue = item.id;
|
||||||
|
store.currentTitle = item.title;
|
||||||
|
store.correntStatusIssue = item.status;
|
||||||
|
store.currentCategory = item.category?.name;
|
||||||
|
store.createdByUserId = item.createdByUserId;
|
||||||
|
store.issue
|
||||||
|
? (store.issue.result = store.issue.result.map((v) => {
|
||||||
|
if (v.id === item.id) {
|
||||||
|
v.unreadCount = 0;
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}))
|
||||||
|
: '';
|
||||||
|
await store.fetchMessageStatus(item.id);
|
||||||
|
await store.fetchMessage(item.id);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
:class="{ active: store.currentIssue === item.id }"
|
||||||
|
class="noactive row q-py-sm justify-between items-center q-px-md"
|
||||||
|
>
|
||||||
|
<div class="col-10 row items-center">
|
||||||
|
<div class="noactive-avatar">
|
||||||
|
<q-avatar color="grey-2" text-color="white" size="40px">
|
||||||
|
<img :src="iconAvatar" />
|
||||||
|
</q-avatar>
|
||||||
|
</div>
|
||||||
|
<div class="col column q-ml-md">
|
||||||
|
<span> {{ item.createdByUserName }} </span>
|
||||||
|
<span class="col column">
|
||||||
|
<div>
|
||||||
|
<q-badge color="blue" outline>{{
|
||||||
|
validateCategory(item.category?.name)
|
||||||
|
}}</q-badge>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
<span class="tite-long text-weight-bold line-ellipsis">
|
||||||
|
{{ item.title }}</span
|
||||||
|
>
|
||||||
|
|
||||||
|
<span
|
||||||
|
class="col text-caption line-ellipsis"
|
||||||
|
:class="{
|
||||||
|
'text-weight-bold': item.unreadCount > 0,
|
||||||
|
'text-grey-8': item.unreadCount > 0,
|
||||||
|
'text-grey': item.unreadCount === 0,
|
||||||
|
}"
|
||||||
|
>{{ item.lastMessage }}</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-2 items-center text-right">
|
||||||
|
<q-icon
|
||||||
|
v-if="item.lastMessage?.length === 0"
|
||||||
|
name="mdi-send"
|
||||||
|
size="xs"
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div v-else class="column">
|
||||||
|
<span class="col text-caption text-grey">{{
|
||||||
|
dateIssue(item.updatedAt)
|
||||||
|
}}</span>
|
||||||
|
|
||||||
|
<div class="col">
|
||||||
|
<q-badge
|
||||||
|
v-if="item.unreadCount > 0"
|
||||||
|
rounded
|
||||||
|
color="negative"
|
||||||
|
text-color="white"
|
||||||
|
:label="item.unreadCount"
|
||||||
|
/>
|
||||||
|
<q-icon v-else name="mdi-check-all" size="xs" color="grey" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<q-separator inset />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="i4 bg-grey-3" v-if="store.currentIssue">
|
||||||
|
<q-scroll-area
|
||||||
|
ref="scrollContainer"
|
||||||
|
style="width: 100%; height: 100%"
|
||||||
|
v-if="store.message?.result.message.length || 0 > 0"
|
||||||
|
>
|
||||||
|
<q-infinite-scroll
|
||||||
|
@load="onLoad"
|
||||||
|
:offset="250"
|
||||||
|
reverse
|
||||||
|
:key="store.currentIssue"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in store.message?.result.message"
|
||||||
|
:key="index"
|
||||||
|
class="caption"
|
||||||
|
>
|
||||||
|
<q-item-section class="q-pr-md">
|
||||||
|
<q-item-label>
|
||||||
|
<q-chat-message
|
||||||
|
:key="index"
|
||||||
|
:id="item.id"
|
||||||
|
:avatar="iconAvatar"
|
||||||
|
:text="[item.content]"
|
||||||
|
:bg-color="
|
||||||
|
item.fromUserId === store.userId ? 'primary' : 'white'
|
||||||
|
"
|
||||||
|
:text-color="
|
||||||
|
item.fromUserId === store.userId ? 'white' : 'black'
|
||||||
|
"
|
||||||
|
:sent="item.fromUserId === store.userId"
|
||||||
|
:stamp="moment(item.createdAt).fromNow()"
|
||||||
|
/>
|
||||||
|
</q-item-label>
|
||||||
|
<q-item-label
|
||||||
|
v-if="item.fromUserId === store.userId"
|
||||||
|
class="flex"
|
||||||
|
caption
|
||||||
|
>
|
||||||
|
<q-space />
|
||||||
|
<div
|
||||||
|
v-if="
|
||||||
|
store.messageStatus?.result.some(
|
||||||
|
(v) =>
|
||||||
|
new Date(v.lastAccessDate).getTime() >=
|
||||||
|
new Date(item.createdAt).getTime() &&
|
||||||
|
index + 1 === store.message?.result.message.length
|
||||||
|
)
|
||||||
|
"
|
||||||
|
class="q-mr-xl"
|
||||||
|
>
|
||||||
|
<q-icon name="mdi-check-all" size="xs" />
|
||||||
|
<span class="text-caption q-ml-sm">อ่านแล้ว</span>
|
||||||
|
</div>
|
||||||
|
</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</div>
|
||||||
|
<template v-slot:loading>
|
||||||
|
<div class="row justify-center q-my-md">
|
||||||
|
<q-spinner-dots color="primary" size="40px" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</q-infinite-scroll>
|
||||||
|
</q-scroll-area>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid-manage bg-white align-center">
|
||||||
|
<q-pagination
|
||||||
|
v-model="currentIssuePage"
|
||||||
|
:max="totalPageIssue || 1"
|
||||||
|
:max-pages="6"
|
||||||
|
boundary-numbers
|
||||||
|
@update:model-value="
|
||||||
|
(value) => {
|
||||||
|
store.fetchIssue(value);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="i5 bg-white container-input align-center">
|
||||||
|
<!-- <div class="input-file">
|
||||||
|
<q-btn flat>
|
||||||
|
<q-icon name="attach_file" style="transform: rotate(-125deg)" />
|
||||||
|
</q-btn>
|
||||||
|
</div> -->
|
||||||
|
<div class="input-chat">
|
||||||
|
<q-input
|
||||||
|
@keydown.enter.prevent="
|
||||||
|
() => {
|
||||||
|
if (store.currentIssue) {
|
||||||
|
store.sendMessage(content, store.currentIssue);
|
||||||
|
content = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
placeholder="Aa"
|
||||||
|
v-model="content"
|
||||||
|
id="message"
|
||||||
|
:disable="store.currentIssue ? false : true"
|
||||||
|
>
|
||||||
|
</q-input>
|
||||||
|
</div>
|
||||||
|
<div class="btn-chat">
|
||||||
|
<q-btn
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
if (store.currentIssue) {
|
||||||
|
store.sendMessage(content, store.currentIssue);
|
||||||
|
content = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
:disable="store.currentIssue ? false : true"
|
||||||
|
flat
|
||||||
|
class="col-2"
|
||||||
|
style="color: #009789"
|
||||||
|
label="ส่งข้อความ"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tite-long {
|
||||||
|
width: 180px;
|
||||||
|
display: inline-block;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tite-on-message-long {
|
||||||
|
width: 250px;
|
||||||
|
display: inline-block;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.active {
|
||||||
|
background: #ebf9f7;
|
||||||
|
border-left: 5px solid #03a898;
|
||||||
|
& {
|
||||||
|
.noactive-avatar {
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 1px solid #03a898;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.align-center {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-areas:
|
||||||
|
"search toolbar"
|
||||||
|
"menu chat"
|
||||||
|
"manage input";
|
||||||
|
grid-template-rows: 60px 400px 60px;
|
||||||
|
grid-template-columns: 300px 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-input {
|
||||||
|
display: grid;
|
||||||
|
grid-template-areas: "input-chat btn";
|
||||||
|
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
grid-template-columns: 1fr 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-file {
|
||||||
|
grid-area: file;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-chat {
|
||||||
|
grid-area: input-chat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-chat {
|
||||||
|
grid-area: btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
.i1 {
|
||||||
|
grid-area: search;
|
||||||
|
}
|
||||||
|
|
||||||
|
.i2 {
|
||||||
|
grid-area: toolbar;
|
||||||
|
}
|
||||||
|
.i3 {
|
||||||
|
grid-area: menu;
|
||||||
|
}
|
||||||
|
.i4 {
|
||||||
|
grid-area: chat;
|
||||||
|
}
|
||||||
|
.i5 {
|
||||||
|
grid-area: input;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-manage {
|
||||||
|
grid-area: manage;
|
||||||
|
}
|
||||||
|
.container-1 {
|
||||||
|
display: grid;
|
||||||
|
/* grid-template-columns: 1fr 2fr; */
|
||||||
|
grid: 50px 450px / 1fr 2fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-2 {
|
||||||
|
display: grid;
|
||||||
|
/* grid-template-columns: 1fr 2fr; */
|
||||||
|
grid: 50px 450px / 1fr 2fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-link-no-deco >>> a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
122
src/modules/00_support/components/ItemAction.vue
Normal file
122
src/modules/00_support/components/ItemAction.vue
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { useSupportStore } from "@/modules/00_support/store/Main";
|
||||||
|
const store = useSupportStore();
|
||||||
|
const open = ref<boolean>(false);
|
||||||
|
const statusIssue: ("new" | "ongoing" | "resolved")[] = [
|
||||||
|
"new",
|
||||||
|
"ongoing",
|
||||||
|
"resolved",
|
||||||
|
];
|
||||||
|
|
||||||
|
const status = ref<"new" | "ongoing" | "resolved">(store.correntStatusIssue);
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
issueId: String,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<q-btn icon="more_vert" dense flat size="11px" @click.stop>
|
||||||
|
<q-menu transition-show="jump-down" transition-hide="jump-up">
|
||||||
|
<q-list style="min-width: 100px">
|
||||||
|
<q-item
|
||||||
|
clickable
|
||||||
|
v-close-popup
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
console.log('เเก้ไข ' + issueId);
|
||||||
|
open = true;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<q-item-section>
|
||||||
|
<div class="row items-center white">
|
||||||
|
<q-icon name="o_edit" color="positive" />
|
||||||
|
<span class="q-ml-sm">แก้ไขสถานะ</span>
|
||||||
|
</div></q-item-section
|
||||||
|
>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-menu>
|
||||||
|
</q-btn>
|
||||||
|
|
||||||
|
<q-dialog v-model="open" persistent>
|
||||||
|
<q-card>
|
||||||
|
<q-card-section class="row items-center">
|
||||||
|
<div class="flex items-center" style="flex-wrap: nowrap">
|
||||||
|
<div>
|
||||||
|
<h6 class="q-my-none">แก้ไขสถานะ</h6>
|
||||||
|
|
||||||
|
<q-btn-dropdown
|
||||||
|
v-if="store.currentIssue"
|
||||||
|
:label="
|
||||||
|
store.correntStatusIssue == 'new'
|
||||||
|
? 'ปัญหาใหม่'
|
||||||
|
: store.correntStatusIssue == 'ongoing'
|
||||||
|
? 'กำลังดำเนินการ'
|
||||||
|
: 'เสร็จสิ้น'
|
||||||
|
"
|
||||||
|
@click.stop
|
||||||
|
>
|
||||||
|
<q-list v-for="itemStatusIssue in statusIssue">
|
||||||
|
<q-item
|
||||||
|
clickable
|
||||||
|
v-close-popup
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
status = itemStatusIssue;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>{{
|
||||||
|
itemStatusIssue == "new"
|
||||||
|
? "ปัญหาใหม่"
|
||||||
|
: itemStatusIssue == "ongoing"
|
||||||
|
? "กำลังดำเนินการ"
|
||||||
|
: "เสร็จสิ้น"
|
||||||
|
}}</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-btn-dropdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-card-actions align="right">
|
||||||
|
<q-btn
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
console.log('ยกเลิกการลบ');
|
||||||
|
}
|
||||||
|
"
|
||||||
|
label="ยกเลิก"
|
||||||
|
flat
|
||||||
|
v-close-popup
|
||||||
|
id="dialogDeleteClose"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<q-btn
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
store.ChangeStatusIssue(
|
||||||
|
store.currentIssue,
|
||||||
|
store.currentTitle,
|
||||||
|
store.currentCategoryId,
|
||||||
|
status
|
||||||
|
);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
color="primary"
|
||||||
|
v-close-popup
|
||||||
|
label="ยืนยัน"
|
||||||
|
id="dialogDeleteConfirm"
|
||||||
|
/>
|
||||||
|
</q-card-actions>
|
||||||
|
</q-card>
|
||||||
|
</q-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useSupportStore } from "@/modules/00_support/store/Main";
|
||||||
|
import dialogHeader from "@/components/DialogHeader.vue";
|
||||||
|
const store = useSupportStore();
|
||||||
|
|
||||||
|
const [open] = defineModel<Boolean>();
|
||||||
|
const input = defineModel<string>("input");
|
||||||
|
const prop = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
open: boolean;
|
||||||
|
status: string;
|
||||||
|
category: string;
|
||||||
|
input: string;
|
||||||
|
}>(),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
function controlAction(
|
||||||
|
categoryId: string = "",
|
||||||
|
statusAction?: string,
|
||||||
|
name: string = ""
|
||||||
|
) {
|
||||||
|
if (statusAction == "add") {
|
||||||
|
store.newCategory(name);
|
||||||
|
}
|
||||||
|
if (statusAction == "edit") store.editCategory(categoryId, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkStatus(status: string) {
|
||||||
|
if (status == "add") return "เพิ่มประเภทของปัญหา";
|
||||||
|
if (status == "edit") return "แก้ไขประเภทของปัญหา";
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<q-dialog v-model="prop.open" class="dialog" persistent>
|
||||||
|
<q-card style="min-width: 350px" class="bg-grey-11">
|
||||||
|
<q-card-section class="flex justify-between" style="padding: 0">
|
||||||
|
<dialog-header
|
||||||
|
:tittle="checkStatus(prop.status)"
|
||||||
|
:close="
|
||||||
|
() => {
|
||||||
|
open = false;
|
||||||
|
if (status == 'add') input = '';
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-separator color="grey-4" />
|
||||||
|
<q-card-section class="q-pa-none align-center">
|
||||||
|
<div class="bg-white q-ma-sm border_black">
|
||||||
|
<q-input
|
||||||
|
hide-bottom-space
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
label="ประเภทของปัญหา"
|
||||||
|
lazy-rules
|
||||||
|
borderless
|
||||||
|
v-model="input"
|
||||||
|
@keyup.enter="
|
||||||
|
() => {
|
||||||
|
controlAction(prop.category, prop.status, input);
|
||||||
|
input = '';
|
||||||
|
open = false;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</q-card-section>
|
||||||
|
<q-separator color="grey-4" />
|
||||||
|
<q-card-actions align="right">
|
||||||
|
<q-btn
|
||||||
|
id="onSubmit"
|
||||||
|
type="submit"
|
||||||
|
dense
|
||||||
|
unelevated
|
||||||
|
label="บันทึก"
|
||||||
|
color="public"
|
||||||
|
class="q-px-md"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
controlAction(prop.category, prop.status, input);
|
||||||
|
input = '';
|
||||||
|
open = false;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<q-tooltip>บันทึกข้อมูล</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
|
</q-card-actions>
|
||||||
|
</q-card>
|
||||||
|
</q-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
168
src/modules/00_support/components/category/TableCategory.vue
Normal file
168
src/modules/00_support/components/category/TableCategory.vue
Normal file
|
|
@ -0,0 +1,168 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useSupportStore } from "@/modules/00_support/store/Main";
|
||||||
|
import DialogCategory from "@/modules/00_support/components/category/DialogCategory.vue";
|
||||||
|
import { onMounted, ref } from "vue";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
import type { QTableProps } from "quasar";
|
||||||
|
import { useQuasar } from "quasar";
|
||||||
|
const router = useRouter();
|
||||||
|
const store = useSupportStore();
|
||||||
|
const open = ref<boolean>(false);
|
||||||
|
const currentName = ref<string>("");
|
||||||
|
const status = ref<"add" | "edit" | "delete">("add");
|
||||||
|
const categoryId = ref<string>("");
|
||||||
|
import { useCounterMixin } from "@/stores/mixin";
|
||||||
|
const { dialogRemove, convertDateDisplay, date2Thai } = useCounterMixin();
|
||||||
|
|
||||||
|
const $q = useQuasar();
|
||||||
|
const columnsCategory = [
|
||||||
|
{
|
||||||
|
name: "name",
|
||||||
|
align: "left",
|
||||||
|
label: "ประเภทของปัญหา",
|
||||||
|
field: "name",
|
||||||
|
sortable: true,
|
||||||
|
headerStyle: "font-size: 14px",
|
||||||
|
style: "font-size: 14px",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "createdAt",
|
||||||
|
align: "left",
|
||||||
|
label: "วันที่สร้าง",
|
||||||
|
field: "createdAt",
|
||||||
|
sortable: true,
|
||||||
|
headerStyle: "font-size: 14px",
|
||||||
|
style: "font-size: 14px",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "actions",
|
||||||
|
align: "right",
|
||||||
|
label: "",
|
||||||
|
field: "",
|
||||||
|
headerStyle: "font-size: 14px",
|
||||||
|
style: "font-size: 14px",
|
||||||
|
},
|
||||||
|
] satisfies QTableProps["columns"];
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await store.fetchCategory();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex">
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
round
|
||||||
|
class="bg-teal-1 full-height q-mr-sm"
|
||||||
|
color="primary"
|
||||||
|
icon="mdi-arrow-left"
|
||||||
|
dense
|
||||||
|
@click="router.go(-1)"
|
||||||
|
>
|
||||||
|
</q-btn>
|
||||||
|
<p class="toptitle text-dark items-center">จัดการประเภทของปัญหา</p>
|
||||||
|
<q-space />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<q-card flat bordered class="col-12 q-mt-sm q-pt-sm q-pa-md">
|
||||||
|
<q-btn
|
||||||
|
class="q-mb-sm"
|
||||||
|
flat
|
||||||
|
round
|
||||||
|
color="primary"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
open = true;
|
||||||
|
status = 'add';
|
||||||
|
currentName = '';
|
||||||
|
}
|
||||||
|
"
|
||||||
|
icon="mdi-plus"
|
||||||
|
>
|
||||||
|
<q-tooltip>เพิ่มข้อมูล</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
|
<div>
|
||||||
|
<d-table
|
||||||
|
ref="table"
|
||||||
|
:columns="columnsCategory"
|
||||||
|
:rows="store.rowsCategory?.result"
|
||||||
|
flat
|
||||||
|
bordered
|
||||||
|
:paging="true"
|
||||||
|
dense
|
||||||
|
class="border_custom"
|
||||||
|
>
|
||||||
|
<template v-slot:body-cell-createdAt="data">
|
||||||
|
<q-td>
|
||||||
|
{{ date2Thai(data.row.createdAt) }}
|
||||||
|
</q-td>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:body-cell-actions="data">
|
||||||
|
<q-td>
|
||||||
|
<div class="align-right">
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
dense
|
||||||
|
id="listViewFolderEdit"
|
||||||
|
icon="edit"
|
||||||
|
color="edit"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
open = true;
|
||||||
|
status = 'edit';
|
||||||
|
categoryId = data.row.id;
|
||||||
|
currentName = data.row.name;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<q-tooltip>แก้ไขข้อมูล</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
|
|
||||||
|
<q-btn
|
||||||
|
class="q-ma-sm"
|
||||||
|
flat
|
||||||
|
dense
|
||||||
|
id="listViewFolderDelete"
|
||||||
|
color="red"
|
||||||
|
icon="mdi-delete"
|
||||||
|
:data-testid="data.row.name"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
dialogRemove($q, () => {
|
||||||
|
store.deleteCategory(data.row.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<q-tooltip>ลบข้อมูล</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
|
</div>
|
||||||
|
</q-td>
|
||||||
|
</template>
|
||||||
|
</d-table>
|
||||||
|
</div>
|
||||||
|
</q-card>
|
||||||
|
|
||||||
|
<dialog-category
|
||||||
|
v-model.open="open"
|
||||||
|
:open="open"
|
||||||
|
:status="status"
|
||||||
|
:category="categoryId"
|
||||||
|
:input="currentName"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.border_custom {
|
||||||
|
border-radius: 6px !important;
|
||||||
|
border: 1px solid #e1e1e1;
|
||||||
|
}
|
||||||
|
.align-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: right;
|
||||||
|
justify-content: right;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,8 +1,75 @@
|
||||||
interface DataOption {
|
export interface SupportMessageStatus {
|
||||||
|
result: SupportResult[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SupportResult {
|
||||||
|
fromUserId: string;
|
||||||
|
fromUserName: string;
|
||||||
|
lastAccessDate: string;
|
||||||
|
issueId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SupportStatusUser {
|
||||||
|
socketId: string;
|
||||||
|
userId: string;
|
||||||
|
name: string;
|
||||||
|
role: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SupportIssueResponse {
|
||||||
|
result: SupportIssue[];
|
||||||
|
page: number;
|
||||||
|
pageSize: number;
|
||||||
|
total: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SupportIssue {
|
||||||
|
id: string;
|
||||||
|
createdByUserId: string;
|
||||||
|
createdByUserName: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
title: string;
|
||||||
|
status: "new" | "ongoing" | "resolved";
|
||||||
|
category: SupportIssueCategory;
|
||||||
|
unreadCount: number;
|
||||||
|
lastMessage: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SupportIssueCategoryResponse {
|
||||||
|
result: SupportIssueCategory[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SupportIssueCategory {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type {
|
export interface SupportMessageResponse {
|
||||||
DataOption,
|
result: SupportIssueWithMessage;
|
||||||
};
|
page: number;
|
||||||
|
pageSize: number;
|
||||||
|
total: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SupportIssueWithMessage {
|
||||||
|
id: string;
|
||||||
|
createdByUserId: string;
|
||||||
|
createdByUserName: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
title: string;
|
||||||
|
status: string;
|
||||||
|
message: SupportIssueMessage[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SupportIssueMessage {
|
||||||
|
id: string;
|
||||||
|
fromUserId: string;
|
||||||
|
fromUserName: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
content: string;
|
||||||
|
read: boolean;
|
||||||
|
issueId: string;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,26 @@
|
||||||
const supportMain = () => import("@/modules/00_support/views/MainPage.vue");
|
const supportMain = () => import("@/modules/00_support/views/MainPage.vue");
|
||||||
|
const supportCategory = () =>
|
||||||
|
import("@/modules/00_support/views/ManageCategory.vue");
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
path: "/support",
|
path: "/support",
|
||||||
name: "supportMain",
|
name: "support",
|
||||||
component: supportMain,
|
component: supportMain,
|
||||||
meta: {
|
meta: {
|
||||||
Auth: true,
|
Auth: true,
|
||||||
Key: [1.1],
|
Key: [1.1],
|
||||||
Role: "evaluate",
|
Role: "support",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/support/category",
|
||||||
|
name: "supportCategory",
|
||||||
|
component: supportCategory,
|
||||||
|
meta: {
|
||||||
|
Auth: true,
|
||||||
|
Key: [1.1],
|
||||||
|
Role: "support",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,328 @@
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
|
import { io } from "socket.io-client";
|
||||||
|
import http from "@/plugins/http";
|
||||||
|
import config from "@/app.config";
|
||||||
|
|
||||||
export const useEvalutuonStore = defineStore("supportServiceStore", () => {
|
import { useCounterMixin } from "@/stores/mixin";
|
||||||
const index = ref<number>(0);
|
import type {
|
||||||
|
SupportMessageResponse,
|
||||||
|
SupportIssueResponse,
|
||||||
|
SupportStatusUser,
|
||||||
|
SupportMessageStatus,
|
||||||
|
SupportIssueCategoryResponse,
|
||||||
|
} from "@/modules/00_support/interface/index/Main";
|
||||||
|
import keycloak from "@/plugins/keycloak";
|
||||||
|
import { useQuasar } from "quasar";
|
||||||
|
|
||||||
|
export const useSupportStore = defineStore("supportServiceStore", () => {
|
||||||
|
const { showLoader, hideLoader, messageError } = useCounterMixin();
|
||||||
|
const $q = useQuasar();
|
||||||
|
const userId = ref<string | undefined>(keycloak.subject);
|
||||||
|
const issue = ref<SupportIssueResponse>();
|
||||||
|
const message = ref<SupportMessageResponse>();
|
||||||
|
const messageStatus = ref<SupportMessageStatus>();
|
||||||
|
const userStatus = ref<SupportStatusUser[]>([]);
|
||||||
|
const currentIssue = ref<string>("");
|
||||||
|
const currentTitle = ref<string>("");
|
||||||
|
const currentCategoryId = ref<string>("");
|
||||||
|
const correntStatusIssue = ref<"new" | "ongoing" | "resolved">("new");
|
||||||
|
const currentTotalMessage = ref<number>();
|
||||||
|
const currentPage = ref<number>();
|
||||||
|
const scrollContainer = ref();
|
||||||
|
const currentPageIssue = ref<number>();
|
||||||
|
const currentTotalIssue = ref<number>();
|
||||||
|
const currentCategory = ref<string>();
|
||||||
|
const createdByUserId = ref<string>("");
|
||||||
|
const createdByUserName = ref<string>("");
|
||||||
|
|
||||||
|
const rowsCategory = ref<SupportIssueCategoryResponse>();
|
||||||
|
|
||||||
|
function scrollToEnd(position: Number = 1) {
|
||||||
|
setTimeout(() => {
|
||||||
|
scrollContainer.value?.setScrollPercentage("vertical", position);
|
||||||
|
}, 150);
|
||||||
|
}
|
||||||
|
|
||||||
|
const socket = io(config.API.supportSocket, {
|
||||||
|
auth: { token: keycloak.token },
|
||||||
|
autoConnect: false,
|
||||||
|
path: "/api/v1/support/socket/",
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("users", (data: SupportStatusUser[]) => {
|
||||||
|
userStatus.value = data;
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("online", (r) => {
|
||||||
|
userStatus.value.push({
|
||||||
|
socketId: r.socketId,
|
||||||
|
userId: r.userId,
|
||||||
|
name: r.name,
|
||||||
|
role: r.role,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("offline", (socketId: string) => {
|
||||||
|
if (socketId === socket.id) return;
|
||||||
|
userStatus.value = userStatus.value.filter((v) => v.socketId !== socketId);
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("notify-message", (r) => {
|
||||||
|
if (issue.value) {
|
||||||
|
issue.value.result = issue.value.result.map((v) => {
|
||||||
|
if (v.id === r.issueId) {
|
||||||
|
v.unreadCount++;
|
||||||
|
v.lastMessage = r.content;
|
||||||
|
v.updatedAt = r.updatedAt;
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("read", (r) => {
|
||||||
|
if (messageStatus.value) {
|
||||||
|
messageStatus.value.result = messageStatus.value.result.map((v) => {
|
||||||
|
if (v.fromUserId !== r.fromUserId) return r;
|
||||||
|
return v;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("message", (r) => {
|
||||||
|
message.value?.result.message.push(r);
|
||||||
|
|
||||||
|
if (issue.value) {
|
||||||
|
issue.value.result = issue.value.result.map((v) => {
|
||||||
|
if (v.id === r.issueId) {
|
||||||
|
v.lastMessage = r.content;
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit("mark-read", { issueId: currentIssue.value });
|
||||||
|
scrollToEnd();
|
||||||
|
});
|
||||||
|
|
||||||
|
function sendMessage(content: string, to: string) {
|
||||||
|
socket.emit("message", { to, content });
|
||||||
|
scrollToEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchMessageStatus(issueId: string) {
|
||||||
|
const res = await http
|
||||||
|
.get(config.API.supportMessageStatus(issueId))
|
||||||
|
.catch((err) => {
|
||||||
|
messageError($q, err);
|
||||||
|
})
|
||||||
|
.finally(() => {});
|
||||||
|
|
||||||
|
if (res && res.data) {
|
||||||
|
messageStatus.value = res.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadMessage(page: number) {
|
||||||
|
const res = await http
|
||||||
|
.get(`${config.API.supportMessage(currentIssue.value)}?page=${page}`)
|
||||||
|
.catch((err) => {
|
||||||
|
messageError($q, err);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res && res.data) {
|
||||||
|
message.value?.result.message.unshift(...res.data.result.message);
|
||||||
|
currentPage.value = res.data.page;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchMessage(issueId: string) {
|
||||||
|
showLoader();
|
||||||
|
const res = await http
|
||||||
|
.get(config.API.supportMessage(issueId))
|
||||||
|
.catch((err) => {
|
||||||
|
messageError($q, err);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
hideLoader();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res && res.data) {
|
||||||
|
message.value = await res.data;
|
||||||
|
message.value?.result.message.reverse();
|
||||||
|
currentPage.value = res.data.page;
|
||||||
|
currentTotalMessage.value = res.data.total;
|
||||||
|
socket.emit("join-issue", { issueId });
|
||||||
|
socket.emit("mark-read", { issueId });
|
||||||
|
scrollToEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ChangeStatusIssue(
|
||||||
|
issueId: string,
|
||||||
|
title: string,
|
||||||
|
categoryId: string,
|
||||||
|
status: "new" | "ongoing" | "resolved"
|
||||||
|
) {
|
||||||
|
showLoader();
|
||||||
|
const requestBody = {
|
||||||
|
title: title,
|
||||||
|
categoryId: categoryId,
|
||||||
|
status: status,
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await http
|
||||||
|
.patch(config.API.supportIssueChangeStatus(issueId), requestBody)
|
||||||
|
.catch((err) => {
|
||||||
|
messageError($q, err);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
hideLoader();
|
||||||
|
});
|
||||||
|
if (res) {
|
||||||
|
fetchIssue();
|
||||||
|
correntStatusIssue.value = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchIssue(page: number = 1) {
|
||||||
|
showLoader();
|
||||||
|
const res = await http
|
||||||
|
.get(`${config.API.supportIssue}?page=${page}&pageSize=30`)
|
||||||
|
.catch((err) => {
|
||||||
|
messageError($q, err);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
hideLoader();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res && res.data) {
|
||||||
|
issue.value = res.data;
|
||||||
|
currentPageIssue.value = res.data.page;
|
||||||
|
currentTotalIssue.value = res.data.total;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function searchIssue(input: string) {
|
||||||
|
showLoader();
|
||||||
|
const res = await http
|
||||||
|
.get(config.API.supportSearchIssue(input))
|
||||||
|
.catch((err) => {
|
||||||
|
messageError($q, err);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
hideLoader();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res && res.data) {
|
||||||
|
issue.value = res.data;
|
||||||
|
currentPageIssue.value = res.data.page;
|
||||||
|
currentTotalIssue.value = res.data.total;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function newCategory(name: string) {
|
||||||
|
showLoader();
|
||||||
|
const res = await http
|
||||||
|
.post(config.API.supportCategory, {
|
||||||
|
name: name,
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
messageError($q, err);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
hideLoader();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
fetchCategory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchCategory() {
|
||||||
|
showLoader();
|
||||||
|
const res = await http
|
||||||
|
.get(config.API.supportCategory)
|
||||||
|
.catch((err) => {
|
||||||
|
messageError($q, err);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
messageError($q, err);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
hideLoader();
|
||||||
|
});
|
||||||
|
if (res && res.data) {
|
||||||
|
rowsCategory.value = res.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteCategory(CategoryId: string) {
|
||||||
|
showLoader();
|
||||||
|
const res = await http
|
||||||
|
.delete(config.API.supportCategoryAction(CategoryId))
|
||||||
|
.catch((err) => {
|
||||||
|
messageError($q, err);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
hideLoader();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
fetchCategory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function editCategory(CategoryId: string, name: string) {
|
||||||
|
showLoader();
|
||||||
|
const res = await http
|
||||||
|
.patch(config.API.supportCategoryAction(CategoryId), {
|
||||||
|
name: name,
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
messageError($q, err);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
hideLoader();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
fetchCategory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
index,
|
userId,
|
||||||
|
issue,
|
||||||
|
message,
|
||||||
|
scrollContainer,
|
||||||
|
currentIssue,
|
||||||
|
currentTitle,
|
||||||
|
socket,
|
||||||
|
messageStatus,
|
||||||
|
currentTotalMessage,
|
||||||
|
currentPage,
|
||||||
|
currentPageIssue,
|
||||||
|
currentTotalIssue,
|
||||||
|
currentCategoryId,
|
||||||
|
correntStatusIssue,
|
||||||
|
currentCategory,
|
||||||
|
rowsCategory,
|
||||||
|
userStatus,
|
||||||
|
createdByUserId,
|
||||||
|
createdByUserName,
|
||||||
|
fetchIssue,
|
||||||
|
fetchMessage,
|
||||||
|
fetchMessageStatus,
|
||||||
|
sendMessage,
|
||||||
|
scrollToEnd,
|
||||||
|
loadMessage,
|
||||||
|
ChangeStatusIssue,
|
||||||
|
newCategory,
|
||||||
|
fetchCategory,
|
||||||
|
deleteCategory,
|
||||||
|
editCategory,
|
||||||
|
searchIssue,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,26 @@
|
||||||
<script setup lang="ts"></script>
|
<script setup lang="ts">
|
||||||
|
import FormChat from "@/modules/00_support/components/FormChat.vue";
|
||||||
|
import { useSupportStore } from "@/modules/00_support/store/Main";
|
||||||
|
import { storeToRefs } from "pinia";
|
||||||
|
import { onMounted, onUnmounted, ref } from "vue";
|
||||||
|
const store = useSupportStore();
|
||||||
|
const { currentIssue } = storeToRefs(store);
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
store.socket.connect();
|
||||||
|
if (currentIssue.value) {
|
||||||
|
store.socket.emit("join-issue", { issueId: currentIssue.value });
|
||||||
|
store.socket.emit("mark-read", { issueId: currentIssue.value });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(async () => {
|
||||||
|
store.socket.disconnect();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>support user</div>
|
<form-chat />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|
|
||||||
21
src/modules/00_support/views/ManageCategory.vue
Normal file
21
src/modules/00_support/views/ManageCategory.vue
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useSupportStore } from "@/modules/00_support/store/Main";
|
||||||
|
import TableCategory from "@/modules/00_support/components/category/TableCategory.vue";
|
||||||
|
import { onMounted, onUnmounted, ref } from "vue";
|
||||||
|
|
||||||
|
const store = useSupportStore();
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
store.socket.connect();
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(async () => {
|
||||||
|
store.socket.disconnect();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<table-category />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue