Merge branch 'develop'
Some checks failed
Spell Check / Spell Check with Typos (push) Failing after 9s
Some checks failed
Spell Check / Spell Check with Typos (push) Failing after 9s
This commit is contained in:
commit
71c1f9c770
42 changed files with 1733 additions and 14298 deletions
|
|
@ -1,9 +0,0 @@
|
||||||
/dist
|
|
||||||
/src-capacitor
|
|
||||||
/src-cordova
|
|
||||||
/.quasar
|
|
||||||
/node_modules
|
|
||||||
.eslintrc.cjs
|
|
||||||
/src-ssr
|
|
||||||
/quasar.config.*.temporary.compiled*
|
|
||||||
/tests
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
root: true,
|
|
||||||
|
|
||||||
parserOptions: {
|
|
||||||
parser: require.resolve('@typescript-eslint/parser'),
|
|
||||||
extraFileExtensions: ['.vue'],
|
|
||||||
},
|
|
||||||
|
|
||||||
env: {
|
|
||||||
browser: true,
|
|
||||||
es2021: true,
|
|
||||||
node: true,
|
|
||||||
'vue/setup-compiler-macros': true,
|
|
||||||
},
|
|
||||||
|
|
||||||
extends: [
|
|
||||||
// https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#usage
|
|
||||||
// ESLint typescript rules
|
|
||||||
'plugin:@typescript-eslint/recommended',
|
|
||||||
|
|
||||||
// Uncomment any of the lines below to choose desired strictness,
|
|
||||||
// but leave only one uncommented!
|
|
||||||
// See https://eslint.vuejs.org/rules/#available-rules
|
|
||||||
'plugin:vue/vue3-essential',
|
|
||||||
|
|
||||||
// https://github.com/prettier/eslint-config-prettier#installation
|
|
||||||
// usage with Prettier, provided by 'eslint-config-prettier'.
|
|
||||||
'prettier',
|
|
||||||
],
|
|
||||||
|
|
||||||
plugins: [
|
|
||||||
// required to apply rules which need type information
|
|
||||||
'@typescript-eslint',
|
|
||||||
|
|
||||||
// https://eslint.vuejs.org/user-guide/#why-doesn-t-it-work-on-vue-files
|
|
||||||
// required to lint *.vue files
|
|
||||||
'vue',
|
|
||||||
],
|
|
||||||
|
|
||||||
globals: {
|
|
||||||
ga: 'readonly', // Google Analytics
|
|
||||||
cordova: 'readonly',
|
|
||||||
__statics: 'readonly',
|
|
||||||
__QUASAR_SSR__: 'readonly',
|
|
||||||
__QUASAR_SSR_SERVER__: 'readonly',
|
|
||||||
__QUASAR_SSR_CLIENT__: 'readonly',
|
|
||||||
__QUASAR_SSR_PWA__: 'readonly',
|
|
||||||
process: 'readonly',
|
|
||||||
Capacitor: 'readonly',
|
|
||||||
chrome: 'readonly',
|
|
||||||
},
|
|
||||||
|
|
||||||
// add your custom rules here
|
|
||||||
rules: {
|
|
||||||
quotes: ['warn', 'single', { avoidEscape: true }],
|
|
||||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
||||||
'@typescript-eslint/no-unused-vars': 'warn',
|
|
||||||
'prefer-promise-reject-errors': 'off',
|
|
||||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
12398
package-lock.json
generated
12398
package-lock.json
generated
File diff suppressed because it is too large
Load diff
22
package.json
22
package.json
|
|
@ -7,16 +7,16 @@
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "eslint --ext .js,.ts,.vue ./",
|
|
||||||
"format": "prettier --write \"**/*.{js,ts,vue,scss,html,md,json}\" --ignore-path .gitignore",
|
"format": "prettier --write \"**/*.{js,ts,vue,scss,html,md,json}\" --ignore-path .gitignore",
|
||||||
"test": "echo \"No test specified\" && exit 0",
|
"test": "echo \"No test specified\" && exit 0",
|
||||||
"dev": "quasar dev",
|
"dev": "quasar dev",
|
||||||
"build": "quasar build",
|
"build": "quasar build",
|
||||||
|
"postinstall": "quasar prepare",
|
||||||
"changelog:generate": "git-cliff -o CHANGELOG.md"
|
"changelog:generate": "git-cliff -o CHANGELOG.md"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@peaceroad/markdown-it-figure-with-p-caption": "^0.11.0",
|
"@peaceroad/markdown-it-figure-with-p-caption": "^0.11.0",
|
||||||
"@quasar/extras": "^1.16.12",
|
"@quasar/extras": "^1.16.17",
|
||||||
"@tato30/vue-pdf": "^1.11.0",
|
"@tato30/vue-pdf": "^1.11.0",
|
||||||
"@vuepic/vue-datepicker": "^8.8.1",
|
"@vuepic/vue-datepicker": "^8.8.1",
|
||||||
"apexcharts": "^4.5.0",
|
"apexcharts": "^4.5.0",
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
"number-to-words": "^1.2.4",
|
"number-to-words": "^1.2.4",
|
||||||
"open-props": "^1.7.5",
|
"open-props": "^1.7.5",
|
||||||
"pinia": "^2.2.2",
|
"pinia": "^2.2.2",
|
||||||
"quasar": "^2.16.9",
|
"quasar": "^2.18.1",
|
||||||
"signature_pad": "^5.0.2",
|
"signature_pad": "^5.0.2",
|
||||||
"socket.io-client": "^4.7.5",
|
"socket.io-client": "^4.7.5",
|
||||||
"tesseract.js": "^5.1.1",
|
"tesseract.js": "^5.1.1",
|
||||||
|
|
@ -45,35 +45,31 @@
|
||||||
"uuid": "^10.0.0",
|
"uuid": "^10.0.0",
|
||||||
"vue": "^3.4.38",
|
"vue": "^3.4.38",
|
||||||
"vue-dragscroll": "^4.0.6",
|
"vue-dragscroll": "^4.0.6",
|
||||||
"vue-i18n": "^9.14.0",
|
"vue-i18n": "^11.1.2",
|
||||||
"vue-pdf": "^4.3.0",
|
"vue-pdf": "^4.3.0",
|
||||||
"vue-router": "^4.4.3",
|
"vue-router": "^4.4.3",
|
||||||
"vue3-apexcharts": "^1.7.0"
|
"vue-tsc": "^2.2.8",
|
||||||
|
"vue3-apexcharts": "^1.8.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@faker-js/faker": "^9.3.0",
|
"@faker-js/faker": "^9.3.0",
|
||||||
"@iconify/vue": "^4.1.2",
|
"@iconify/vue": "^4.1.2",
|
||||||
"@intlify/unplugin-vue-i18n": "^4.0.0",
|
"@intlify/unplugin-vue-i18n": "^6.0.5",
|
||||||
"@playwright/test": "^1.46.1",
|
"@playwright/test": "^1.46.1",
|
||||||
"@quasar/app-vite": "2.0.0-beta.19",
|
"@quasar/app-vite": "^2.2.0",
|
||||||
"@types/markdown-it": "^14.1.2",
|
"@types/markdown-it": "^14.1.2",
|
||||||
"@types/markdown-it-highlightjs": "^3.3.4",
|
"@types/markdown-it-highlightjs": "^3.3.4",
|
||||||
"@types/node": "^20.16.1",
|
"@types/node": "^20.16.1",
|
||||||
"@types/number-to-words": "^1.2.3",
|
"@types/number-to-words": "^1.2.3",
|
||||||
"@types/uuid": "^10.0.0",
|
"@types/uuid": "^10.0.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
|
||||||
"@typescript-eslint/parser": "^7.18.0",
|
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
"dotenv": "^16.4.7",
|
"dotenv": "^16.4.7",
|
||||||
"eslint": "^8.57.0",
|
|
||||||
"eslint-config-prettier": "^9.1.0",
|
|
||||||
"eslint-plugin-vue": "^9.27.0",
|
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.3.3",
|
||||||
"typescript": "^5.5.4",
|
"typescript": "^5.5.4",
|
||||||
"vue-component-type-helpers": "^2.1.10"
|
"vue-component-type-helpers": "^2.1.10"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^24 || ^22 || ^20 || ^18",
|
"node": "^28 || ^26 || ^24 || ^22 || ^20 || ^18",
|
||||||
"npm": ">= 6.13.4",
|
"npm": ">= 6.13.4",
|
||||||
"yarn": ">= 1.21.1"
|
"yarn": ">= 1.21.1"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2712
pnpm-lock.yaml
generated
2712
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
18
postcss.config.js
Normal file
18
postcss.config.js
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
import autoprefixer from 'autoprefixer';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
plugins: [
|
||||||
|
autoprefixer({
|
||||||
|
overrideBrowserslist: [
|
||||||
|
'last 4 Chrome versions',
|
||||||
|
'last 4 Firefox versions',
|
||||||
|
'last 4 Edge versions',
|
||||||
|
'last 4 Safari versions',
|
||||||
|
'last 4 Android versions',
|
||||||
|
'last 4 ChromeAndroid versions',
|
||||||
|
'last 4 FirefoxAndroid versions',
|
||||||
|
'last 4 iOS versions',
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
@ -1,26 +1,22 @@
|
||||||
/* eslint-env node */
|
|
||||||
|
|
||||||
// Configuration for your app
|
// Configuration for your app
|
||||||
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js
|
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js
|
||||||
|
|
||||||
import { configure } from 'quasar/wrappers';
|
import { defineConfig } from '#q-app/wrappers';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
export default configure((ctx) => {
|
export default defineConfig((ctx) => {
|
||||||
return {
|
return {
|
||||||
eslint: {
|
|
||||||
fix: true,
|
|
||||||
warnings: true,
|
|
||||||
errors: true,
|
|
||||||
},
|
|
||||||
boot: ['i18n', 'axios', 'components'],
|
boot: ['i18n', 'axios', 'components'],
|
||||||
css: ['app.scss'],
|
css: ['app.scss'],
|
||||||
extras: ['mdi-v7'],
|
extras: ['mdi-v7'],
|
||||||
build: {
|
build: {
|
||||||
target: {
|
target: {
|
||||||
browser: ['es2019', 'edge88', 'firefox78', 'chrome87', 'safari13.1'],
|
browser: ['es2022', 'firefox115', 'chrome115', 'safari14'],
|
||||||
node: 'node20',
|
node: 'node20',
|
||||||
},
|
},
|
||||||
|
typescript: {
|
||||||
|
vueShim: true,
|
||||||
|
},
|
||||||
vueRouterMode: 'history',
|
vueRouterMode: 'history',
|
||||||
vitePlugins: [
|
vitePlugins: [
|
||||||
[
|
[
|
||||||
|
|
|
||||||
167
reports.json
167
reports.json
|
|
@ -1,167 +0,0 @@
|
||||||
{
|
|
||||||
"config": {
|
|
||||||
"configFile": "/Users/linping/Desktop/Chamomind&FrappeT/JWS_TestScript/playwright.config.ts",
|
|
||||||
"rootDir": "/Users/linping/Desktop/Chamomind&FrappeT/JWS_TestScript/tests",
|
|
||||||
"forbidOnly": false,
|
|
||||||
"fullyParallel": true,
|
|
||||||
"globalSetup": null,
|
|
||||||
"globalTeardown": null,
|
|
||||||
"globalTimeout": 0,
|
|
||||||
"grep": {},
|
|
||||||
"grepInvert": null,
|
|
||||||
"maxFailures": 0,
|
|
||||||
"metadata": {
|
|
||||||
"actualWorkers": 1
|
|
||||||
},
|
|
||||||
"preserveOutput": "always",
|
|
||||||
"reporter": [
|
|
||||||
[
|
|
||||||
"json",
|
|
||||||
{
|
|
||||||
"outputFile": "reports.json"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"reportSlowTests": {
|
|
||||||
"max": 5,
|
|
||||||
"threshold": 15000
|
|
||||||
},
|
|
||||||
"quiet": false,
|
|
||||||
"projects": [
|
|
||||||
{
|
|
||||||
"outputDir": "/Users/linping/Desktop/Chamomind&FrappeT/JWS_TestScript/test-results",
|
|
||||||
"repeatEach": 1,
|
|
||||||
"retries": 0,
|
|
||||||
"metadata": {},
|
|
||||||
"id": "chromium",
|
|
||||||
"name": "chromium",
|
|
||||||
"testDir": "/Users/linping/Desktop/Chamomind&FrappeT/JWS_TestScript/tests",
|
|
||||||
"testIgnore": [],
|
|
||||||
"testMatch": [
|
|
||||||
"**/*.@(spec|test).?(c|m)[jt]s?(x)"
|
|
||||||
],
|
|
||||||
"timeout": 30000
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"shard": null,
|
|
||||||
"updateSnapshots": "missing",
|
|
||||||
"version": "1.44.1",
|
|
||||||
"workers": 1,
|
|
||||||
"webServer": null
|
|
||||||
},
|
|
||||||
"suites": [
|
|
||||||
{
|
|
||||||
"title": "01-Admin-BranchManagement/JWS_BM_001_CreateHeadquarters.spec.ts",
|
|
||||||
"file": "01-Admin-BranchManagement/JWS_BM_001_CreateHeadquarters.spec.ts",
|
|
||||||
"column": 0,
|
|
||||||
"line": 0,
|
|
||||||
"specs": [
|
|
||||||
{
|
|
||||||
"title": "Login",
|
|
||||||
"ok": true,
|
|
||||||
"tags": [],
|
|
||||||
"tests": [
|
|
||||||
{
|
|
||||||
"timeout": 30000,
|
|
||||||
"annotations": [],
|
|
||||||
"expectedStatus": "passed",
|
|
||||||
"projectId": "chromium",
|
|
||||||
"projectName": "chromium",
|
|
||||||
"results": [
|
|
||||||
{
|
|
||||||
"workerIndex": 4,
|
|
||||||
"status": "passed",
|
|
||||||
"duration": 3024,
|
|
||||||
"errors": [],
|
|
||||||
"stdout": [],
|
|
||||||
"stderr": [],
|
|
||||||
"retry": 0,
|
|
||||||
"startTime": "2024-07-30T02:59:00.817Z",
|
|
||||||
"attachments": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"status": "expected"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"id": "8c5091bd59605f227965-8109f0f4a59e27330a76",
|
|
||||||
"file": "01-Admin-BranchManagement/JWS_BM_001_CreateHeadquarters.spec.ts",
|
|
||||||
"line": 16,
|
|
||||||
"column": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Create Branch Managenment",
|
|
||||||
"ok": true,
|
|
||||||
"tags": [],
|
|
||||||
"tests": [
|
|
||||||
{
|
|
||||||
"timeout": 30000,
|
|
||||||
"annotations": [],
|
|
||||||
"expectedStatus": "passed",
|
|
||||||
"projectId": "chromium",
|
|
||||||
"projectName": "chromium",
|
|
||||||
"results": [
|
|
||||||
{
|
|
||||||
"workerIndex": 4,
|
|
||||||
"status": "passed",
|
|
||||||
"duration": 5091,
|
|
||||||
"errors": [],
|
|
||||||
"stdout": [],
|
|
||||||
"stderr": [],
|
|
||||||
"retry": 0,
|
|
||||||
"startTime": "2024-07-30T02:59:05.659Z",
|
|
||||||
"attachments": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"status": "expected"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"id": "8c5091bd59605f227965-5a0d70f27623401a3479",
|
|
||||||
"file": "01-Admin-BranchManagement/JWS_BM_001_CreateHeadquarters.spec.ts",
|
|
||||||
"line": 27,
|
|
||||||
"column": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Create Branch Managenment Second",
|
|
||||||
"ok": true,
|
|
||||||
"tags": [],
|
|
||||||
"tests": [
|
|
||||||
{
|
|
||||||
"timeout": 30000,
|
|
||||||
"annotations": [],
|
|
||||||
"expectedStatus": "passed",
|
|
||||||
"projectId": "chromium",
|
|
||||||
"projectName": "chromium",
|
|
||||||
"results": [
|
|
||||||
{
|
|
||||||
"workerIndex": 4,
|
|
||||||
"status": "passed",
|
|
||||||
"duration": 5029,
|
|
||||||
"errors": [],
|
|
||||||
"stdout": [],
|
|
||||||
"stderr": [],
|
|
||||||
"retry": 0,
|
|
||||||
"startTime": "2024-07-30T02:59:10.755Z",
|
|
||||||
"attachments": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"status": "expected"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"id": "8c5091bd59605f227965-d619bd2184e7f07d4970",
|
|
||||||
"file": "01-Admin-BranchManagement/JWS_BM_001_CreateHeadquarters.spec.ts",
|
|
||||||
"line": 52,
|
|
||||||
"column": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"errors": [],
|
|
||||||
"stats": {
|
|
||||||
"startTime": "2024-07-30T02:59:00.334Z",
|
|
||||||
"duration": 15556.794999999925,
|
|
||||||
"expected": 3,
|
|
||||||
"skipped": 0,
|
|
||||||
"unexpected": 0,
|
|
||||||
"flaky": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import axios, { AxiosInstance } from 'axios';
|
import axios, { AxiosInstance } from 'axios';
|
||||||
import { boot } from 'quasar/wrappers';
|
import { defineBoot } from '#q-app/wrappers';
|
||||||
import { getToken } from 'src/services/keycloak';
|
import { getToken } from 'src/services/keycloak';
|
||||||
import { dialog } from 'stores/utils';
|
import { dialog } from 'stores/utils';
|
||||||
import useLoader from 'stores/loader';
|
import useLoader from 'stores/loader';
|
||||||
import useFlowStore from 'src/stores/flow';
|
import useFlowStore from 'src/stores/flow';
|
||||||
|
|
||||||
declare module '@vue/runtime-core' {
|
declare module 'vue' {
|
||||||
interface ComponentCustomProperties {
|
interface ComponentCustomProperties {
|
||||||
$axios: AxiosInstance;
|
$axios: AxiosInstance;
|
||||||
$api: AxiosInstance;
|
$api: AxiosInstance;
|
||||||
|
|
@ -24,10 +24,10 @@ function parseError(
|
||||||
status: number,
|
status: number,
|
||||||
body?: { status: number; message: string; code: string },
|
body?: { status: number; message: string; code: string },
|
||||||
) {
|
) {
|
||||||
if (status === 422) return 'invalideData';
|
if (status === 422) return 'invalidData';
|
||||||
if (body && body.code) return body.code;
|
if (body && body.code) return body.code;
|
||||||
|
|
||||||
return 'errorOccure';
|
return 'errorOccurred';
|
||||||
}
|
}
|
||||||
|
|
||||||
api.interceptors.request.use(async (config) => {
|
api.interceptors.request.use(async (config) => {
|
||||||
|
|
@ -64,7 +64,7 @@ api.interceptors.response.use(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export default boot(({ app }) => {
|
export default defineBoot(({ app }) => {
|
||||||
// for use inside Vue files (Options API) through this.$axios and this.$api
|
// for use inside Vue files (Options API) through this.$axios and this.$api
|
||||||
|
|
||||||
app.config.globalProperties.$axios = axios;
|
app.config.globalProperties.$axios = axios;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { boot } from 'quasar/wrappers';
|
import { defineBoot } from '#q-app/wrappers';
|
||||||
import VueDatePicker from '@vuepic/vue-datepicker';
|
import VueDatePicker from '@vuepic/vue-datepicker';
|
||||||
import '@vuepic/vue-datepicker/dist/main.css';
|
import '@vuepic/vue-datepicker/dist/main.css';
|
||||||
import GlobalDialog from 'components/GlobalDialog.vue';
|
import GlobalDialog from 'components/GlobalDialog.vue';
|
||||||
|
|
@ -6,7 +6,7 @@ import GlobalLoading from 'components/GlobalLoading.vue';
|
||||||
import VueDragscroll from 'vue-dragscroll';
|
import VueDragscroll from 'vue-dragscroll';
|
||||||
import VueApexCharts from 'vue3-apexcharts';
|
import VueApexCharts from 'vue3-apexcharts';
|
||||||
|
|
||||||
export default boot(({ app }) => {
|
export default defineBoot(({ app }) => {
|
||||||
app.component('global-dialog', GlobalDialog);
|
app.component('global-dialog', GlobalDialog);
|
||||||
app.component('global-loading', GlobalLoading);
|
app.component('global-loading', GlobalLoading);
|
||||||
app.component('VueDatePicker', VueDatePicker);
|
app.component('VueDatePicker', VueDatePicker);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { boot } from 'quasar/wrappers';
|
import { defineBoot } from '#q-app/wrappers';
|
||||||
import { createI18n } from 'vue-i18n';
|
import { createI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import messages from 'src/i18n';
|
import messages from 'src/i18n';
|
||||||
|
|
@ -21,16 +21,17 @@ declare module 'vue-i18n' {
|
||||||
}
|
}
|
||||||
/* eslint-enable @typescript-eslint/no-empty-interface */
|
/* eslint-enable @typescript-eslint/no-empty-interface */
|
||||||
|
|
||||||
export const i18n = createI18n({
|
export const i18n = createI18n<
|
||||||
locale: 'tha',
|
{ message: MessageSchema },
|
||||||
|
MessageLanguages,
|
||||||
|
false
|
||||||
|
>({
|
||||||
|
locale: 'en-US',
|
||||||
legacy: false,
|
legacy: false,
|
||||||
messages: {
|
messages,
|
||||||
'en-US': {},
|
|
||||||
...messages,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default boot(({ app }) => {
|
export default defineBoot(({ app }) => {
|
||||||
// Set i18n instance on app
|
// Set i18n instance on app
|
||||||
app.use(i18n);
|
app.use(i18n);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { useQuasar } from 'quasar';
|
||||||
import SignaturePad from 'signature_pad';
|
import SignaturePad from 'signature_pad';
|
||||||
import Cropper from 'cropperjs';
|
import Cropper from 'cropperjs';
|
||||||
|
|
||||||
defineExpose({ clearCanvas, clearUpload });
|
defineExpose({ setCanvas, getCanvas, clearCanvas, clearUpload });
|
||||||
|
|
||||||
const $q = useQuasar();
|
const $q = useQuasar();
|
||||||
const isDarkActive = computed(() => $q.dark.isActive);
|
const isDarkActive = computed(() => $q.dark.isActive);
|
||||||
|
|
@ -18,7 +18,7 @@ const cropper = ref();
|
||||||
|
|
||||||
const tab = ref('draw');
|
const tab = ref('draw');
|
||||||
const uploadFile = ref<File | undefined>(undefined);
|
const uploadFile = ref<File | undefined>(undefined);
|
||||||
const profileUrl = ref<string | null>('');
|
const imgUrl = ref<string | null>('');
|
||||||
const inputFile = (() => {
|
const inputFile = (() => {
|
||||||
const element = document.createElement('input');
|
const element = document.createElement('input');
|
||||||
element.type = 'file';
|
element.type = 'file';
|
||||||
|
|
@ -26,7 +26,7 @@ const inputFile = (() => {
|
||||||
|
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.addEventListener('load', () => {
|
reader.addEventListener('load', () => {
|
||||||
if (typeof reader.result === 'string') profileUrl.value = reader.result;
|
if (typeof reader.result === 'string') imgUrl.value = reader.result;
|
||||||
});
|
});
|
||||||
|
|
||||||
element.addEventListener('change', () => {
|
element.addEventListener('change', () => {
|
||||||
|
|
@ -39,12 +39,11 @@ const inputFile = (() => {
|
||||||
return element;
|
return element;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
async function initializeSignaturePad(canva?: HTMLCanvasElement) {
|
async function initializeSignaturePad() {
|
||||||
if (canva) {
|
const canvas = canvasRef.value;
|
||||||
signaturePad.value = new SignaturePad(canva, {
|
|
||||||
backgroundColor: isDarkActive.value
|
if (canvas) {
|
||||||
? 'rgb(21,25,29)'
|
signaturePad.value = new SignaturePad(canvas, {
|
||||||
: 'rgb(248,249,250)',
|
|
||||||
penColor: 'blue',
|
penColor: 'blue',
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -77,34 +76,41 @@ function changeColor(color: string) {
|
||||||
currentColor.value = color;
|
currentColor.value = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setCanvas() {
|
||||||
|
const data = signaturePad.value.toDataURL('image/png');
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCanvas(signature: string) {
|
||||||
|
signaturePad.value.fromDataURL(signature);
|
||||||
|
}
|
||||||
|
|
||||||
function clearCanvas() {
|
function clearCanvas() {
|
||||||
signaturePad.value.clear();
|
signaturePad.value.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearUpload() {
|
function clearUpload() {
|
||||||
profileUrl.value = '';
|
imgUrl.value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => tab.value,
|
() => tab.value,
|
||||||
async () => {
|
async () => {
|
||||||
await initializeSignaturePad(canvasRef.value);
|
await initializeSignaturePad();
|
||||||
await initializeCropper(imageRef.value);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await initializeSignaturePad(canvasRef.value);
|
await initializeSignaturePad();
|
||||||
await initializeCropper(imageRef.value);
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="surface-1 bordered rounded full-width">
|
<div class="surface-1 column full-width full-height">
|
||||||
<q-tabs
|
<q-tabs
|
||||||
v-model="tab"
|
v-model="tab"
|
||||||
dense
|
dense
|
||||||
align="left"
|
align="left"
|
||||||
class="text-grey"
|
class="text-grey surface-2"
|
||||||
active-color="primary"
|
active-color="primary"
|
||||||
indicator-color="primary"
|
indicator-color="primary"
|
||||||
>
|
>
|
||||||
|
|
@ -112,18 +118,18 @@ onMounted(async () => {
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<q-tab
|
<q-tab
|
||||||
name="draw"
|
name="draw"
|
||||||
label="Draw"
|
:label="$t('general.draw')"
|
||||||
style="border-top-left-radius: var(--radius-2)"
|
style="border-top-left-radius: var(--radius-2)"
|
||||||
/>
|
/>
|
||||||
<q-tab name="upload" label="Upload" />
|
<q-tab name="upload" :label="$t('general.upload')" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="q-pr-md">
|
<div class="q-pr-md">
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="tab === 'upload'"
|
||||||
dense
|
dense
|
||||||
flat
|
flat
|
||||||
v-if="tab === 'upload'"
|
:label="$t('general.newUpload')"
|
||||||
:label="$t('newUpload')"
|
|
||||||
color="info"
|
color="info"
|
||||||
@click="inputFile.click()"
|
@click="inputFile.click()"
|
||||||
/>
|
/>
|
||||||
|
|
@ -132,89 +138,66 @@ onMounted(async () => {
|
||||||
</q-tabs>
|
</q-tabs>
|
||||||
<q-separator />
|
<q-separator />
|
||||||
|
|
||||||
<div v-show="tab === 'draw'" class="q-pa-md">
|
<section v-show="tab === 'draw'" class="q-pa-md col">
|
||||||
<div class="column relative-position">
|
<div class="column relative-position">
|
||||||
<div class="absolute-top-right q-ma-md q-gutter-x-md row items-center">
|
<article
|
||||||
|
class="absolute-top-right q-ma-md q-gutter-x-md row items-center"
|
||||||
|
>
|
||||||
<span
|
<span
|
||||||
|
v-for="color in ['black', 'red', 'blue']"
|
||||||
|
:key="color"
|
||||||
|
:class="{ active: currentColor === color }"
|
||||||
class="dot"
|
class="dot"
|
||||||
:class="{ active: currentColor === 'black' }"
|
:style="`background-color: ${color}`"
|
||||||
style="background-color: black"
|
@click="changeColor(color)"
|
||||||
@click="changeColor('black')"
|
|
||||||
>
|
>
|
||||||
<q-icon
|
<q-icon
|
||||||
v-if="currentColor === 'black'"
|
v-if="currentColor === color"
|
||||||
name="mdi-check"
|
name="mdi-check"
|
||||||
color="white"
|
color="white"
|
||||||
size="sm"
|
size="sm"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span
|
</article>
|
||||||
:class="{ active: currentColor === 'red' }"
|
|
||||||
class="dot"
|
|
||||||
style="background-color: red"
|
|
||||||
@click="changeColor('red')"
|
|
||||||
>
|
|
||||||
<q-icon
|
|
||||||
v-if="currentColor === 'red'"
|
|
||||||
name="mdi-check"
|
|
||||||
color="white"
|
|
||||||
size="sm"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
:class="{ active: currentColor === 'blue' }"
|
|
||||||
class="dot"
|
|
||||||
style="background-color: blue"
|
|
||||||
@click="changeColor('blue')"
|
|
||||||
>
|
|
||||||
<q-icon
|
|
||||||
v-if="currentColor === 'blue'"
|
|
||||||
name="mdi-check"
|
|
||||||
color="white"
|
|
||||||
size="sm"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<canvas
|
<canvas
|
||||||
class="signature-canvas"
|
class="signature-canvas"
|
||||||
ref="canvasRef"
|
ref="canvasRef"
|
||||||
id="signature-pad"
|
id="signature-pad"
|
||||||
width="700"
|
width="766"
|
||||||
height="310"
|
height="364"
|
||||||
></canvas>
|
></canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
|
|
||||||
<div v-show="tab === 'upload'" class="q-pa-md">
|
<section v-show="tab === 'upload'" class="q-pa-md col">
|
||||||
<div
|
<div
|
||||||
class="bordered upload-border rounded column items-center justify-center"
|
class="bordered upload-border rounded column items-center justify-center full-height"
|
||||||
style="height: 312px"
|
|
||||||
>
|
>
|
||||||
<q-img
|
<q-img
|
||||||
v-show="profileUrl"
|
v-show="imgUrl"
|
||||||
ref="imageRef"
|
ref="imageRef"
|
||||||
:src="profileUrl ?? ''"
|
:src="imgUrl ?? ''"
|
||||||
style="object-fit: cover; width: 100%; height: 100%"
|
style="object-fit: cover; width: 100%; height: 100%"
|
||||||
/>
|
/>
|
||||||
<div v-if="!profileUrl">
|
<div v-if="!imgUrl">
|
||||||
<q-icon
|
<q-icon
|
||||||
name="mdi-cloud-upload"
|
name="mdi-cloud-upload"
|
||||||
size="10rem"
|
size="10rem"
|
||||||
style="color: hsla(var(--text-mute) / 0.2)"
|
style="color: hsla(var(--text-mute) / 0.2)"
|
||||||
/>
|
/>
|
||||||
<div>
|
<div class="text-center">
|
||||||
<q-btn
|
<q-btn
|
||||||
unelevated
|
unelevated
|
||||||
color="info"
|
color="info"
|
||||||
:label="$t('uploadFile')"
|
:label="$t('general.upload')"
|
||||||
icon="mdi-plus"
|
icon="mdi-plus"
|
||||||
@click="inputFile.click()"
|
@click="inputFile.click()"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|
|
||||||
2
src/env.d.ts
vendored
2
src/env.d.ts
vendored
|
|
@ -1,5 +1,3 @@
|
||||||
/* eslint-disable */
|
|
||||||
|
|
||||||
declare namespace NodeJS {
|
declare namespace NodeJS {
|
||||||
interface ProcessEnv {
|
interface ProcessEnv {
|
||||||
NODE_ENV: string;
|
NODE_ENV: string;
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,8 @@ export default {
|
||||||
dueDate: 'Due date',
|
dueDate: 'Due date',
|
||||||
year: 'year',
|
year: 'year',
|
||||||
tableOfContent: 'Table of Contents',
|
tableOfContent: 'Table of Contents',
|
||||||
|
draw: 'Draw',
|
||||||
|
newUpload: 'New Upload',
|
||||||
},
|
},
|
||||||
|
|
||||||
menu: {
|
menu: {
|
||||||
|
|
@ -874,7 +876,7 @@ export default {
|
||||||
SplitCustom: 'Custom Installments Bill',
|
SplitCustom: 'Custom Installments Bill',
|
||||||
BillFull: 'Full Amount Bill',
|
BillFull: 'Full Amount Bill',
|
||||||
BillSplit: 'Installments Bill',
|
BillSplit: 'Installments Bill',
|
||||||
BillCustomSplit: 'Custom Installments Bill',
|
BillSplitCustom: 'Custom Installments Bill',
|
||||||
},
|
},
|
||||||
|
|
||||||
status: {
|
status: {
|
||||||
|
|
@ -1072,10 +1074,8 @@ export default {
|
||||||
confirmSavingStatus:
|
confirmSavingStatus:
|
||||||
'Do you want to confirm the saving of the status change data?',
|
'Do you want to confirm the saving of the status change data?',
|
||||||
confirmSending: 'Do you confirm the submission of the task?',
|
confirmSending: 'Do you confirm the submission of the task?',
|
||||||
confirmValidate: 'Do you confirm the validation?',
|
|
||||||
warningSelectDeliveryStaff:
|
warningSelectDeliveryStaff:
|
||||||
'You have not yet selected a document delivery staff.',
|
'You have not yet selected a document delivery staff.',
|
||||||
|
|
||||||
confirmEndWorkWarning:
|
confirmEndWorkWarning:
|
||||||
"Do you want to end the work now? The current statuses 'Pending', 'In Progress', 'To Be Reprocessed' will be changed to 'Redo All'.",
|
"Do you want to end the work now? The current statuses 'Pending', 'In Progress', 'To Be Reprocessed' will be changed to 'Redo All'.",
|
||||||
confirmEndWork: 'Do you want to end the work?',
|
confirmEndWork: 'Do you want to end the work?',
|
||||||
|
|
@ -1187,9 +1187,9 @@ export default {
|
||||||
validateError: 'Validate Error',
|
validateError: 'Validate Error',
|
||||||
codeMisMatch: 'Code Mismatch',
|
codeMisMatch: 'Code Mismatch',
|
||||||
crossCompanyNotPermit: 'Cannot move between different headoffice',
|
crossCompanyNotPermit: 'Cannot move between different headoffice',
|
||||||
errorOccure:
|
errorOccurred:
|
||||||
'An error has occurred, causing the system to be unable to function. Please try again later.',
|
'An error has occurred, causing the system to be unable to function. Please try again later.',
|
||||||
invalideData: 'The information is incorrect. Please try again later.',
|
invalidData: 'The information is incorrect. Please try again later.',
|
||||||
authFailed: 'Authentication Failed. Please try again later. ',
|
authFailed: 'Authentication Failed. Please try again later. ',
|
||||||
installmentsValidateFailed:
|
installmentsValidateFailed:
|
||||||
'Validation failed. Each installment must include at least one product. Please review and update the installments accordingly.',
|
'Validation failed. Each installment must include at least one product. Please review and update the installments accordingly.',
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,8 @@ export default {
|
||||||
dueDate: 'วันครบกำหนด',
|
dueDate: 'วันครบกำหนด',
|
||||||
year: 'ปี',
|
year: 'ปี',
|
||||||
tableOfContent: 'สารบัญ',
|
tableOfContent: 'สารบัญ',
|
||||||
|
draw: 'วาด',
|
||||||
|
newUpload: 'อัปโหลดใหม่',
|
||||||
},
|
},
|
||||||
|
|
||||||
menu: {
|
menu: {
|
||||||
|
|
@ -1165,9 +1167,9 @@ export default {
|
||||||
validateError: 'เกิดข้อผิดพลาดจากการตรวจสอบ',
|
validateError: 'เกิดข้อผิดพลาดจากการตรวจสอบ',
|
||||||
codeMisMatch: 'รหัสไม่ตรงกัน',
|
codeMisMatch: 'รหัสไม่ตรงกัน',
|
||||||
crossCompanyNotPermit: 'ไม่สามารถดำเนินการระหว่างสำนักงานใหญ่อื่นได้',
|
crossCompanyNotPermit: 'ไม่สามารถดำเนินการระหว่างสำนักงานใหญ่อื่นได้',
|
||||||
errorOccure:
|
errorOccurred:
|
||||||
'เกิดข้อผิดพลาดทำให้ระบบไม่สามารถทำงานได้ กรุณาลองใหม่ในภายหลัง',
|
'เกิดข้อผิดพลาดทำให้ระบบไม่สามารถทำงานได้ กรุณาลองใหม่ในภายหลัง',
|
||||||
invalideData: 'ข้อมูลไม่ถูกต้อง กรุณาตรวจสอบใหม่อีกครั้ง',
|
invalidData: 'ข้อมูลไม่ถูกต้อง กรุณาตรวจสอบใหม่อีกครั้ง',
|
||||||
authFailed: 'การยืนยันตัวตนล้มเหลว กรุณาลองใหม่ในภายหลัง',
|
authFailed: 'การยืนยันตัวตนล้มเหลว กรุณาลองใหม่ในภายหลัง',
|
||||||
installmentsValidateFailed:
|
installmentsValidateFailed:
|
||||||
'ข้อมูลงวดไม่ถูกต้อง กรุณาตรวจสอบและยืนยันว่าแต่ละงวดมีสินค้าอย่างน้อยหนึ่งรายการ',
|
'ข้อมูลงวดไม่ถูกต้อง กรุณาตรวจสอบและยืนยันว่าแต่ละงวดมีสินค้าอย่างน้อยหนึ่งรายการ',
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,6 @@ const leftDrawerMini = ref(false);
|
||||||
const unread = computed<number>(
|
const unread = computed<number>(
|
||||||
() => notificationData.value.filter((v) => !v.read).length || 0,
|
() => notificationData.value.filter((v) => !v.read).length || 0,
|
||||||
);
|
);
|
||||||
// const filterRole = ref<string[]>();
|
|
||||||
const userImage = ref<string>();
|
const userImage = ref<string>();
|
||||||
const userGender = ref('');
|
const userGender = ref('');
|
||||||
const canvasRef = ref();
|
const canvasRef = ref();
|
||||||
|
|
@ -124,6 +123,17 @@ function readNoti(id: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function signatureSubmit() {
|
||||||
|
const signature = canvasRef.value.setCanvas();
|
||||||
|
userStore.setSignature(signature);
|
||||||
|
canvasModal.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function signatureFetch() {
|
||||||
|
const ret = await userStore.getSignature();
|
||||||
|
if (ret) canvasRef.value.getCanvas(ret);
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
initTheme();
|
initTheme();
|
||||||
initLang();
|
initLang();
|
||||||
|
|
@ -367,12 +377,28 @@ onMounted(async () => {
|
||||||
<div class="col column text-caption q-pl-md ellipsis">
|
<div class="col column text-caption q-pl-md ellipsis">
|
||||||
<span class="block ellipsis full-width text-weight-bold">
|
<span class="block ellipsis full-width text-weight-bold">
|
||||||
{{ item.title }}
|
{{ item.title }}
|
||||||
|
<q-tooltip
|
||||||
|
anchor="top middle"
|
||||||
|
self="bottom middle"
|
||||||
|
:delay="300"
|
||||||
|
:offset="[10, 10]"
|
||||||
|
>
|
||||||
|
{{ item.title }}
|
||||||
|
</q-tooltip>
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
class="block ellipsis full-width text-stone"
|
class="block ellipsis full-width text-stone"
|
||||||
:class="{ 'text-weight-medium': !item.read }"
|
:class="{ 'text-weight-medium': !item.read }"
|
||||||
>
|
>
|
||||||
{{ item.detail }}
|
{{ item.detail }}
|
||||||
|
<q-tooltip
|
||||||
|
anchor="top middle"
|
||||||
|
self="bottom middle"
|
||||||
|
:delay="300"
|
||||||
|
:offset="[10, 10]"
|
||||||
|
>
|
||||||
|
{{ item.detail }}
|
||||||
|
</q-tooltip>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
|
|
@ -382,15 +408,6 @@ onMounted(async () => {
|
||||||
>
|
>
|
||||||
{{ moment(item.createdAt).fromNow() }}
|
{{ moment(item.createdAt).fromNow() }}
|
||||||
</span>
|
</span>
|
||||||
<q-tooltip
|
|
||||||
anchor="top middle"
|
|
||||||
self="bottom middle"
|
|
||||||
:delay="1000"
|
|
||||||
:offset="[10, 10]"
|
|
||||||
>
|
|
||||||
{{ item.title }}
|
|
||||||
{{ item.detail }}
|
|
||||||
</q-tooltip>
|
|
||||||
</q-item>
|
</q-item>
|
||||||
</section>
|
</section>
|
||||||
<section
|
<section
|
||||||
|
|
@ -495,13 +512,15 @@ onMounted(async () => {
|
||||||
no-app-box
|
no-app-box
|
||||||
:title="$t('menu.profile.addSignature')"
|
:title="$t('menu.profile.addSignature')"
|
||||||
:close="() => (canvasModal = false)"
|
:close="() => (canvasModal = false)"
|
||||||
|
:submit="signatureSubmit"
|
||||||
|
:show="signatureFetch"
|
||||||
>
|
>
|
||||||
<CanvasComponent ref="canvasRef" v-model:modal="canvasModal" />
|
<CanvasComponent ref="canvasRef" v-model:modal="canvasModal" />
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<q-btn
|
<q-btn
|
||||||
flat
|
flat
|
||||||
dense
|
dense
|
||||||
:label="$t('clear')"
|
:label="$t('general.clear')"
|
||||||
@click="
|
@click="
|
||||||
() => {
|
() => {
|
||||||
canvasRef.clearCanvas(), canvasRef.clearUpload();
|
canvasRef.clearCanvas(), canvasRef.clearUpload();
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ const options = [
|
||||||
label: 'menu.profile.signature',
|
label: 'menu.profile.signature',
|
||||||
value: 'signature',
|
value: 'signature',
|
||||||
color: 'grey',
|
color: 'grey',
|
||||||
disabled: true,
|
disabled: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'mdi-brightness-6',
|
icon: 'mdi-brightness-6',
|
||||||
|
|
|
||||||
2
src/markdown-it.d.ts
vendored
Normal file
2
src/markdown-it.d.ts
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
declare module 'markdown-it-image-figures';
|
||||||
|
declare module 'markdown-it-html5-media';
|
||||||
|
|
@ -5,9 +5,7 @@ import hljs from 'highlight.js';
|
||||||
import { nextTick, onMounted, onUnmounted, ref } from 'vue';
|
import { nextTick, onMounted, onUnmounted, ref } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
// @ts-expect-error
|
|
||||||
import mditFigureWithPCaption from 'markdown-it-image-figures';
|
import mditFigureWithPCaption from 'markdown-it-image-figures';
|
||||||
// @ts-expect-error
|
|
||||||
import mditMedia from 'markdown-it-html5-media';
|
import mditMedia from 'markdown-it-html5-media';
|
||||||
import mditAnchor from 'markdown-it-anchor';
|
import mditAnchor from 'markdown-it-anchor';
|
||||||
import mditHighlight from 'markdown-it-highlightjs';
|
import mditHighlight from 'markdown-it-highlightjs';
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import { deleteItem } from 'stores/utils';
|
||||||
|
|
||||||
// NOTE Import Types
|
// NOTE Import Types
|
||||||
import { RequestData, RequestDataStatus } from 'src/stores/request-list/types';
|
import { RequestData, RequestDataStatus } from 'src/stores/request-list/types';
|
||||||
import { View } from './types.ts';
|
import { View } from './types';
|
||||||
import {
|
import {
|
||||||
PayCondition,
|
PayCondition,
|
||||||
ProductRelation,
|
ProductRelation,
|
||||||
|
|
@ -76,6 +76,7 @@ import { api } from 'src/boot/axios';
|
||||||
import { RouterLink, useRoute } from 'vue-router';
|
import { RouterLink, useRoute } from 'vue-router';
|
||||||
import { initLang, initTheme, Lang } from 'src/utils/ui';
|
import { initLang, initTheme, Lang } from 'src/utils/ui';
|
||||||
import { convertTemplate } from 'src/utils/string-template';
|
import { convertTemplate } from 'src/utils/string-template';
|
||||||
|
import { getRole } from 'src/services/keycloak';
|
||||||
|
|
||||||
type Node = {
|
type Node = {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
|
|
@ -211,6 +212,17 @@ const attachmentData = ref<
|
||||||
url?: string;
|
url?: string;
|
||||||
}[]
|
}[]
|
||||||
>([]);
|
>([]);
|
||||||
|
const hideBtnApproveInvoice = computed(() => {
|
||||||
|
const role = getRole();
|
||||||
|
const allowedRoles = [
|
||||||
|
'system',
|
||||||
|
'head_of_admin',
|
||||||
|
'admin',
|
||||||
|
'head_of_accountant',
|
||||||
|
'accountant',
|
||||||
|
];
|
||||||
|
return !role || !role.some((r) => allowedRoles.includes(r));
|
||||||
|
});
|
||||||
|
|
||||||
const getToolbarConfig = computed(() => {
|
const getToolbarConfig = computed(() => {
|
||||||
const toolbar = [['left', 'center', 'justify'], ['toggle'], ['clip']];
|
const toolbar = [['left', 'center', 'justify'], ['toggle'], ['clip']];
|
||||||
|
|
@ -2317,6 +2329,7 @@ function covertToNode() {
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<MainButton
|
<MainButton
|
||||||
|
v-if="!hideBtnApproveInvoice"
|
||||||
solid
|
solid
|
||||||
icon="mdi-account-multiple-check-outline"
|
icon="mdi-account-multiple-check-outline"
|
||||||
color="207 96% 32%"
|
color="207 96% 32%"
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { Icon } from '@iconify/vue';
|
||||||
import { ref, watch, computed } from 'vue';
|
import { ref, watch, computed } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { View } from './types.ts';
|
import { View } from './types';
|
||||||
|
|
||||||
import { formatNumberDecimal, commaInput } from 'stores/utils';
|
import { formatNumberDecimal, commaInput } from 'stores/utils';
|
||||||
|
|
||||||
|
|
@ -14,7 +14,7 @@ import SelectInput from 'src/components/shared/SelectInput.vue';
|
||||||
|
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { precisionRound } from 'src/utils/arithmetic';
|
import { precisionRound } from 'src/utils/arithmetic';
|
||||||
import { PayCondition } from 'src/stores/quotations/types.ts';
|
import { PayCondition } from 'src/stores/quotations/types';
|
||||||
|
|
||||||
defineEmits<{
|
defineEmits<{
|
||||||
(e: 'changePayType', type: PayCondition): void;
|
(e: 'changePayType', type: PayCondition): void;
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import { useRequestList } from 'src/stores/request-list';
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
step: Step;
|
step: Step;
|
||||||
|
requestWorkId: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const requestListStore = useRequestList();
|
const requestListStore = useRequestList();
|
||||||
|
|
@ -116,7 +117,7 @@ function assignToForm() {
|
||||||
<FormGroupHead>
|
<FormGroupHead>
|
||||||
{{ $t('quotation.templateForm') }}
|
{{ $t('quotation.templateForm') }}
|
||||||
</FormGroupHead>
|
</FormGroupHead>
|
||||||
<FormIssue :readonly="!state.isEdit" />
|
<FormIssue :request-work-id="requestWorkId" :readonly="!state.isEdit" />
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
</q-expansion-item>
|
</q-expansion-item>
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,49 @@
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { MainButton } from 'components/button';
|
import { MainButton } from 'components/button';
|
||||||
import SelectInput from 'src/components/shared/SelectInput.vue';
|
import SelectInput from 'src/components/shared/SelectInput.vue';
|
||||||
|
import { onMounted } from 'vue';
|
||||||
|
import { api } from 'src/boot/axios';
|
||||||
|
import { baseUrl } from 'src/stores/utils';
|
||||||
|
|
||||||
defineProps<{
|
const prop = defineProps<{
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
|
requestWorkId: string;
|
||||||
}>();
|
}>();
|
||||||
const templateForm = defineModel<string>();
|
const templateForm = defineModel<string>();
|
||||||
const templateFormOption = ref<
|
const templateFormOption = ref<
|
||||||
{ label: string; labelEN: string; value: string }[]
|
{ label: string; labelEN: string; value: string }[]
|
||||||
>([]);
|
>([]);
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const { data: docTemplate, status } = await api.get<string[]>(
|
||||||
|
'/doc-template',
|
||||||
|
{ params: { templateGroup: 'Request' } },
|
||||||
|
);
|
||||||
|
|
||||||
|
if (status < 400) {
|
||||||
|
templateFormOption.value = docTemplate.map((v) => ({
|
||||||
|
label: v,
|
||||||
|
labelEN: v,
|
||||||
|
value: v,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function formDownload() {
|
||||||
|
const res = await fetch(
|
||||||
|
baseUrl +
|
||||||
|
'/doc-template/' +
|
||||||
|
templateForm.value +
|
||||||
|
`?templateGroup=Request&data=request-work&dataId=${prop.requestWorkId}`,
|
||||||
|
);
|
||||||
|
const blob = await res.blob();
|
||||||
|
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.download = templateForm.value;
|
||||||
|
a.href = window.URL.createObjectURL(blob);
|
||||||
|
a.click();
|
||||||
|
a.remove();
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -24,7 +59,6 @@ const templateFormOption = ref<
|
||||||
<SelectInput
|
<SelectInput
|
||||||
id="quotation-branch"
|
id="quotation-branch"
|
||||||
style="grid-column: span 2"
|
style="grid-column: span 2"
|
||||||
incremental
|
|
||||||
v-model="templateForm"
|
v-model="templateForm"
|
||||||
class="full-width"
|
class="full-width"
|
||||||
:readonly
|
:readonly
|
||||||
|
|
@ -32,21 +66,13 @@ const templateFormOption = ref<
|
||||||
:label="$t('quotation.templateForm')"
|
:label="$t('quotation.templateForm')"
|
||||||
:option-label="$i18n.locale === 'eng' ? 'labelEN' : 'label'"
|
:option-label="$i18n.locale === 'eng' ? 'labelEN' : 'label'"
|
||||||
/>
|
/>
|
||||||
<MainButton
|
|
||||||
outlined
|
|
||||||
icon="mdi-play-box-outline"
|
|
||||||
color="207 96% 32%"
|
|
||||||
class="full-width"
|
|
||||||
style="grid-column: span 1"
|
|
||||||
>
|
|
||||||
{{ $t('general.view', { msg: $t('general.example') }) }}
|
|
||||||
</MainButton>
|
|
||||||
<MainButton
|
<MainButton
|
||||||
solid
|
solid
|
||||||
icon="mdi-pencil-outline"
|
icon="mdi-pencil-outline"
|
||||||
color="207 96% 32%"
|
color="207 96% 32%"
|
||||||
class="full-width"
|
class="full-width"
|
||||||
style="grid-column: span 1"
|
style="grid-column: span 1"
|
||||||
|
@click="formDownload"
|
||||||
>
|
>
|
||||||
{{ $t('general.designForm') }}
|
{{ $t('general.designForm') }}
|
||||||
</MainButton>
|
</MainButton>
|
||||||
|
|
|
||||||
|
|
@ -906,6 +906,7 @@ async function submitRejectCancel() {
|
||||||
/>
|
/>
|
||||||
<FormExpansion
|
<FormExpansion
|
||||||
v-if="value._formExpansion"
|
v-if="value._formExpansion"
|
||||||
|
:request-work-id="value.id"
|
||||||
:readonly="
|
:readonly="
|
||||||
data.requestDataStatus === RequestDataStatus.Canceled
|
data.requestDataStatus === RequestDataStatus.Canceled
|
||||||
"
|
"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { storeToRefs } from 'pinia';
|
||||||
import { QTableSlots } from 'quasar';
|
import { QTableSlots } from 'quasar';
|
||||||
import { CreditNote, useCreditNote } from 'src/stores/credit-note';
|
import { CreditNote, useCreditNote } from 'src/stores/credit-note';
|
||||||
|
|
||||||
import { columns } from './constants.ts';
|
import { columns } from './constants';
|
||||||
import KebabAction from 'src/components/shared/KebabAction.vue';
|
import KebabAction from 'src/components/shared/KebabAction.vue';
|
||||||
|
|
||||||
const creditNote = useCreditNote();
|
const creditNote = useCreditNote();
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { storeToRefs } from 'pinia';
|
||||||
import { QTableSlots } from 'quasar';
|
import { QTableSlots } from 'quasar';
|
||||||
import { DebitNote, useDebitNote } from 'src/stores/debit-note';
|
import { DebitNote, useDebitNote } from 'src/stores/debit-note';
|
||||||
|
|
||||||
import { columns } from './constants.ts';
|
import { columns } from './constants';
|
||||||
import KebabAction from 'src/components/shared/KebabAction.vue';
|
import KebabAction from 'src/components/shared/KebabAction.vue';
|
||||||
|
|
||||||
const debitNote = useDebitNote();
|
const debitNote = useDebitNote();
|
||||||
|
|
|
||||||
9
src/quasar.d.ts
vendored
9
src/quasar.d.ts
vendored
|
|
@ -1,9 +0,0 @@
|
||||||
/* eslint-disable */
|
|
||||||
|
|
||||||
// Forces TS to apply `@quasar/app-vite` augmentations of `quasar` package
|
|
||||||
// Removing this would break `quasar/wrappers` imports as those typings are declared
|
|
||||||
// into `@quasar/app-vite`
|
|
||||||
// As a side effect, since `@quasar/app-vite` reference `quasar` to augment it,
|
|
||||||
// this declaration also apply `quasar` own
|
|
||||||
// augmentations (eg. adds `$q` into Vue component context)
|
|
||||||
/// <reference types="@quasar/app-vite" />
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { route } from 'quasar/wrappers';
|
import { defineRouter } from '#q-app/wrappers';
|
||||||
import {
|
import {
|
||||||
createMemoryHistory,
|
createMemoryHistory,
|
||||||
createRouter,
|
createRouter,
|
||||||
|
|
@ -17,7 +17,7 @@ import routes from './routes';
|
||||||
* with the Router instance.
|
* with the Router instance.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default route(function (/* { store, ssrContext } */) {
|
export default defineRouter(function (/* { store, ssrContext } */) {
|
||||||
const createHistory = process.env.SERVER
|
const createHistory = process.env.SERVER
|
||||||
? createMemoryHistory
|
? createMemoryHistory
|
||||||
: process.env.VUE_ROUTER_MODE === 'history'
|
: process.env.VUE_ROUTER_MODE === 'history'
|
||||||
|
|
|
||||||
10
src/shims-vue.d.ts
vendored
10
src/shims-vue.d.ts
vendored
|
|
@ -1,10 +0,0 @@
|
||||||
/* eslint-disable */
|
|
||||||
|
|
||||||
/// <reference types="vite/client" />
|
|
||||||
|
|
||||||
// Mocks all files ending in `.vue` showing them as plain Vue instances
|
|
||||||
declare module '*.vue' {
|
|
||||||
import type { DefineComponent } from 'vue';
|
|
||||||
const component: DefineComponent<{}, {}, any>;
|
|
||||||
export default component;
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { api } from 'src/boot/axios';
|
import { api } from 'src/boot/axios';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
import type { AppConfig } from './types';
|
||||||
|
|
||||||
export const useConfigStore = defineStore('config-store', () => {
|
export const useConfigStore = defineStore('config-store', () => {
|
||||||
const data = ref<AppConfig>();
|
const data = ref<AppConfig>();
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
type AppConfig = {
|
export type AppConfig = {
|
||||||
vat: number;
|
vat: number;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,17 @@ import {
|
||||||
CreditNoteStatus as Status,
|
CreditNoteStatus as Status,
|
||||||
CreditNotePayload as Payload,
|
CreditNotePayload as Payload,
|
||||||
CreditNotePaybackStatus,
|
CreditNotePaybackStatus,
|
||||||
} from './types.ts';
|
} from './types';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
|
|
||||||
import { api } from 'src/boot/axios.ts';
|
import { api } from 'src/boot/axios';
|
||||||
import { PaginationResult } from 'src/types.ts';
|
import { PaginationResult } from 'src/types';
|
||||||
import { manageAttachment, manageFile } from '../utils/index.ts';
|
import { manageAttachment, manageFile } from '../utils';
|
||||||
|
|
||||||
const ENDPOINT = 'credit-note';
|
const ENDPOINT = 'credit-note';
|
||||||
|
|
||||||
export * from './types.ts';
|
export * from './types';
|
||||||
|
|
||||||
export async function getCreditNoteStats() {
|
export async function getCreditNoteStats() {
|
||||||
const res = await api.get<Record<Status, number>>(`/${ENDPOINT}/stats`);
|
const res = await api.get<Record<Status, number>>(`/${ENDPOINT}/stats`);
|
||||||
|
|
|
||||||
|
|
@ -500,6 +500,6 @@ const useCustomerStore = defineStore('api-customer', () => {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
export * from './types.ts';
|
export * from './types';
|
||||||
|
|
||||||
export default useCustomerStore;
|
export default useCustomerStore;
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,17 @@ import {
|
||||||
DebitNote as Data,
|
DebitNote as Data,
|
||||||
DebitNoteStatus as Status,
|
DebitNoteStatus as Status,
|
||||||
DebitNotePayload as Payload,
|
DebitNotePayload as Payload,
|
||||||
} from './types.ts';
|
} from './types';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
|
|
||||||
import { api } from 'src/boot/axios.ts';
|
import { api } from 'src/boot/axios';
|
||||||
import { PaginationResult } from 'src/types.ts';
|
import { PaginationResult } from 'src/types';
|
||||||
import { manageAttachment, manageFile } from '../utils/index.ts';
|
import { manageAttachment, manageFile } from '../utils';
|
||||||
|
|
||||||
const ENDPOINT = 'debit-note';
|
const ENDPOINT = 'debit-note';
|
||||||
|
|
||||||
export * from './types.ts';
|
export * from './types';
|
||||||
|
|
||||||
export async function getDebitNoteStats() {
|
export async function getDebitNoteStats() {
|
||||||
const res = await api.get<Record<Status, number>>(`/${ENDPOINT}/stats`);
|
const res = await api.get<Record<Status, number>>(`/${ENDPOINT}/stats`);
|
||||||
|
|
|
||||||
|
|
@ -52,8 +52,4 @@ export type Payment = {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum PaymentDataStatus {
|
|
||||||
Success = 'PaymentSuccess',
|
|
||||||
Wait = 'PaymentWait',
|
|
||||||
}
|
|
||||||
export type Receipt = Payment;
|
export type Receipt = Payment;
|
||||||
|
|
|
||||||
|
|
@ -237,4 +237,4 @@ export const useQuotationPayment = defineStore('quotation-payment', () => {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
export * from './types.ts';
|
export * from './types';
|
||||||
|
|
|
||||||
|
|
@ -353,4 +353,4 @@ export const useRequestList = defineStore('request-list', () => {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
export * from './types.ts';
|
export * from './types';
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ export const useTaskOrderStore = defineStore('taskorder-store', () => {
|
||||||
[TaskOrderStatus.Complete]: 0,
|
[TaskOrderStatus.Complete]: 0,
|
||||||
[TaskOrderStatus.Accept]: 0,
|
[TaskOrderStatus.Accept]: 0,
|
||||||
[TaskOrderStatus.Submit]: 0,
|
[TaskOrderStatus.Submit]: 0,
|
||||||
|
[TaskOrderStatus.Restart]: 0,
|
||||||
});
|
});
|
||||||
const fileManager = manageAttachment(api, 'task-order');
|
const fileManager = manageAttachment(api, 'task-order');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,11 @@ import {
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import useBranchStore from '../branch';
|
import useBranchStore from '../branch';
|
||||||
import { Branch } from '../branch/types';
|
import { Branch } from '../branch/types';
|
||||||
import useFlowStore from '../flow';
|
import { getSignature, setSignature } from './signature';
|
||||||
|
|
||||||
const branchStore = useBranchStore();
|
const branchStore = useBranchStore();
|
||||||
|
|
||||||
const useUserStore = defineStore('api-user', () => {
|
const useUserStore = defineStore('api-user', () => {
|
||||||
const flowStore = useFlowStore();
|
|
||||||
const userOption = ref<UserOption>({
|
const userOption = ref<UserOption>({
|
||||||
hqOpts: [],
|
hqOpts: [],
|
||||||
brOpts: [],
|
brOpts: [],
|
||||||
|
|
@ -95,37 +94,15 @@ const useUserStore = defineStore('api-user', () => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchAttachment(
|
async function fetchAttachment(userId: string) {
|
||||||
userId: string,
|
const res = await api.get<UserAttachment[]>(`/user/${userId}/attachment`);
|
||||||
flow?: {
|
|
||||||
sessionId?: string;
|
|
||||||
refTransactionId?: string;
|
|
||||||
transactionId?: string;
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
const res = await api.get<UserAttachment[]>(`/user/${userId}/attachment`, {
|
|
||||||
headers: {
|
|
||||||
'X-Session-Id': flow?.sessionId,
|
|
||||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
|
||||||
'X-Tid': flow?.transactionId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (res && res.status === 200) {
|
if (res && res.status === 200) {
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addAttachment(
|
async function addAttachment(userId: string, payload: UserAttachmentCreate) {
|
||||||
userId: string,
|
|
||||||
payload: UserAttachmentCreate,
|
|
||||||
flow?: {
|
|
||||||
sessionId?: string;
|
|
||||||
refTransactionId?: string;
|
|
||||||
transactionId?: string;
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
const list: { name: string; file: File }[] = [];
|
const list: { name: string; file: File }[] = [];
|
||||||
|
|
||||||
payload.file.forEach((v) => {
|
payload.file.forEach((v) => {
|
||||||
|
|
@ -156,13 +133,6 @@ const useUserStore = defineStore('api-user', () => {
|
||||||
const res = await api.post<(UserAttachment & { uploadUrl: string })[]>(
|
const res = await api.post<(UserAttachment & { uploadUrl: string })[]>(
|
||||||
`/user/${userId}/attachment`,
|
`/user/${userId}/attachment`,
|
||||||
{ file: list.map((v) => v.name) },
|
{ file: list.map((v) => v.name) },
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
'X-Session-Id': flow?.sessionId,
|
|
||||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
|
||||||
'X-Tid': flow?.transactionId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
|
|
@ -182,19 +152,9 @@ const useUserStore = defineStore('api-user', () => {
|
||||||
async function deleteAttachment(
|
async function deleteAttachment(
|
||||||
userId: string,
|
userId: string,
|
||||||
payload: UserAttachmentDelete,
|
payload: UserAttachmentDelete,
|
||||||
flow?: {
|
|
||||||
sessionId?: string;
|
|
||||||
refTransactionId?: string;
|
|
||||||
transactionId?: string;
|
|
||||||
},
|
|
||||||
) {
|
) {
|
||||||
await api.delete(`/user/${userId}/attachment`, {
|
await api.delete(`/user/${userId}/attachment`, {
|
||||||
data: payload,
|
data: payload,
|
||||||
headers: {
|
|
||||||
'X-Session-Id': flow?.sessionId,
|
|
||||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
|
||||||
'X-Tid': flow?.transactionId,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -217,21 +177,8 @@ const useUserStore = defineStore('api-user', () => {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchById(
|
async function fetchById(id: string) {
|
||||||
id: string,
|
const res = await api.get<User>(`/user/${id}`);
|
||||||
flow?: {
|
|
||||||
sessionId?: string;
|
|
||||||
refTransactionId?: string;
|
|
||||||
transactionId?: string;
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
const res = await api.get<User>(`/user/${id}`, {
|
|
||||||
headers: {
|
|
||||||
'X-Session-Id': flow?.sessionId,
|
|
||||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
|
||||||
'X-Tid': flow?.transactionId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res) return false;
|
if (!res) return false;
|
||||||
if (res.status === 200) return res.data;
|
if (res.status === 200) return res.data;
|
||||||
|
|
@ -240,21 +187,8 @@ const useUserStore = defineStore('api-user', () => {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchImageListById(
|
async function fetchImageListById(id: string) {
|
||||||
id: string,
|
const res = await api.get(`/user/${id}/profile-image`);
|
||||||
flow?: {
|
|
||||||
sessionId?: string;
|
|
||||||
refTransactionId?: string;
|
|
||||||
transactionId?: string;
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
const res = await api.get(`/user/${id}/profile-image`, {
|
|
||||||
headers: {
|
|
||||||
'X-Session-Id': flow?.sessionId,
|
|
||||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
|
||||||
'X-Tid': flow?.transactionId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res) return false;
|
if (!res) return false;
|
||||||
if (res.status === 200) return res.data;
|
if (res.status === 200) return res.data;
|
||||||
|
|
@ -274,22 +208,8 @@ const useUserStore = defineStore('api-user', () => {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteImageByName(
|
async function deleteImageByName(id: string, name: string) {
|
||||||
id: string,
|
const res = await api.delete(`/user/${id}/profile-image/${name}`);
|
||||||
name: string,
|
|
||||||
flow?: {
|
|
||||||
sessionId?: string;
|
|
||||||
refTransactionId?: string;
|
|
||||||
transactionId?: string;
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
const res = await api.delete(`/user/${id}/profile-image/${name}`, {
|
|
||||||
headers: {
|
|
||||||
'X-Session-Id': flow?.sessionId,
|
|
||||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
|
||||||
'X-Tid': flow?.transactionId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res) return false;
|
if (!res) return false;
|
||||||
}
|
}
|
||||||
|
|
@ -300,27 +220,12 @@ const useUserStore = defineStore('api-user', () => {
|
||||||
selectedImage: string;
|
selectedImage: string;
|
||||||
list: { url: string; imgFile: File | null; name: string }[];
|
list: { url: string; imgFile: File | null; name: string }[];
|
||||||
},
|
},
|
||||||
flow?: {
|
|
||||||
sessionId?: string;
|
|
||||||
refTransactionId?: string;
|
|
||||||
transactionId?: string;
|
|
||||||
},
|
|
||||||
) {
|
) {
|
||||||
const { zipCode, ...payload } = data;
|
const { zipCode, ...payload } = data;
|
||||||
const res = await api.post<User>(
|
const res = await api.post<User>('/user', {
|
||||||
'/user',
|
...payload,
|
||||||
{
|
selectedImage: imgList.selectedImage || '',
|
||||||
...payload,
|
});
|
||||||
selectedImage: imgList.selectedImage || '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
'X-Session-Id': flow?.sessionId,
|
|
||||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
|
||||||
'X-Tid': flow?.transactionId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (imgList.list.length > 0 && res.data.id) {
|
if (imgList.list.length > 0 && res.data.id) {
|
||||||
for (let index = 0; index < imgList.list.length; index++) {
|
for (let index = 0; index < imgList.list.length; index++) {
|
||||||
|
|
@ -338,42 +243,18 @@ const useUserStore = defineStore('api-user', () => {
|
||||||
async function editById(
|
async function editById(
|
||||||
id: string,
|
id: string,
|
||||||
data: Partial<UserCreate & { status?: 'ACTIVE' | 'INACTIVE' }>,
|
data: Partial<UserCreate & { status?: 'ACTIVE' | 'INACTIVE' }>,
|
||||||
flow?: {
|
|
||||||
sessionId?: string;
|
|
||||||
refTransactionId?: string;
|
|
||||||
transactionId?: string;
|
|
||||||
},
|
|
||||||
) {
|
) {
|
||||||
const { zipCode, ...paylond } = data;
|
const { zipCode, ...payload } = data;
|
||||||
|
|
||||||
const res = await api.put<User>(`/user/${id}`, paylond, {
|
const res = await api.put<User>(`/user/${id}`, payload);
|
||||||
headers: {
|
|
||||||
'X-Session-Id': flow?.sessionId,
|
|
||||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
|
||||||
'X-Tid': flow?.transactionId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res) return false;
|
if (!res) return false;
|
||||||
|
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteById(
|
async function deleteById(id: string) {
|
||||||
id: string,
|
const res = await api.delete<User>(`/user/${id}`);
|
||||||
flow?: {
|
|
||||||
sessionId?: string;
|
|
||||||
refTransactionId?: string;
|
|
||||||
transactionId?: string;
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
const res = await api.delete<User>(`/user/${id}`, {
|
|
||||||
headers: {
|
|
||||||
'X-Session-Id': flow?.sessionId,
|
|
||||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
|
||||||
'X-Tid': flow?.transactionId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res) return false;
|
if (!res) return false;
|
||||||
if (res.status === 200) return res.data;
|
if (res.status === 200) return res.data;
|
||||||
|
|
@ -381,21 +262,8 @@ const useUserStore = defineStore('api-user', () => {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getBranch(
|
async function getBranch(userId: string) {
|
||||||
userId: string,
|
const res = await api.get<Pagination<Branch[]>>(`/user/${userId}/branch`);
|
||||||
flow?: {
|
|
||||||
sessionId?: string;
|
|
||||||
refTransactionId?: string;
|
|
||||||
transactionId?: string;
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
const res = await api.get<Pagination<Branch[]>>(`/user/${userId}/branch`, {
|
|
||||||
headers: {
|
|
||||||
'X-Session-Id': flow?.sessionId,
|
|
||||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
|
||||||
'X-Tid': flow?.transactionId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res) return false;
|
if (!res) return false;
|
||||||
if (res.status === 200) return res.data;
|
if (res.status === 200) return res.data;
|
||||||
|
|
@ -403,26 +271,10 @@ const useUserStore = defineStore('api-user', () => {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addBranch(
|
async function addBranch(userId: string, branchId: string | string[]) {
|
||||||
userId: string,
|
const res = await api.post(`/user/${userId}/branch`, {
|
||||||
branchId: string | string[],
|
branch: ([] as string[]).concat(branchId),
|
||||||
flow?: {
|
});
|
||||||
sessionId?: string;
|
|
||||||
refTransactionId?: string;
|
|
||||||
transactionId?: string;
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
const res = await api.post(
|
|
||||||
`/user/${userId}/branch`,
|
|
||||||
{ branch: ([] as string[]).concat(branchId) },
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
'X-Session-Id': flow?.sessionId,
|
|
||||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
|
||||||
'X-Tid': flow?.transactionId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!res) return false;
|
if (!res) return false;
|
||||||
if (res.status >= 400) return false;
|
if (res.status >= 400) return false;
|
||||||
|
|
@ -430,21 +282,8 @@ const useUserStore = defineStore('api-user', () => {
|
||||||
return res.data || true;
|
return res.data || true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function removeBranch(
|
async function removeBranch(userId: string, branchId: string | string[]) {
|
||||||
userId: string,
|
|
||||||
branchId: string | string[],
|
|
||||||
flow?: {
|
|
||||||
sessionId?: string;
|
|
||||||
refTransactionId?: string;
|
|
||||||
transactionId?: string;
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
const res = await api.delete(`/user/${userId}/branch`, {
|
const res = await api.delete(`/user/${userId}/branch`, {
|
||||||
headers: {
|
|
||||||
'X-Session-Id': flow?.sessionId,
|
|
||||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
|
||||||
'X-Tid': flow?.transactionId,
|
|
||||||
},
|
|
||||||
data: { branch: ([] as string[]).concat(branchId) },
|
data: { branch: ([] as string[]).concat(branchId) },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -454,18 +293,8 @@ const useUserStore = defineStore('api-user', () => {
|
||||||
return res.data || true;
|
return res.data || true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function typeStats(flow?: {
|
async function typeStats() {
|
||||||
sessionId?: string;
|
const res = await api.get('/user/type-stats');
|
||||||
refTransactionId?: string;
|
|
||||||
transactionId?: string;
|
|
||||||
}) {
|
|
||||||
const res = await api.get('/user/type-stats', {
|
|
||||||
headers: {
|
|
||||||
'X-Session-Id': flow?.sessionId,
|
|
||||||
'X-Rtid': flow?.refTransactionId || flowStore.rtid,
|
|
||||||
'X-Tid': flow?.transactionId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (!res) return false;
|
if (!res) return false;
|
||||||
if (res.status === 200) return res.data;
|
if (res.status === 200) return res.data;
|
||||||
|
|
||||||
|
|
@ -499,6 +328,9 @@ const useUserStore = defineStore('api-user', () => {
|
||||||
addAttachment,
|
addAttachment,
|
||||||
deleteAttachment,
|
deleteAttachment,
|
||||||
|
|
||||||
|
getSignature,
|
||||||
|
setSignature,
|
||||||
|
|
||||||
typeStats,
|
typeStats,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
||||||
50
src/stores/user/signature.ts
Normal file
50
src/stores/user/signature.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
import axios from 'axios';
|
||||||
|
import { api } from 'src/boot/axios';
|
||||||
|
import { getUserId } from 'src/services/keycloak';
|
||||||
|
|
||||||
|
export async function getSignature() {
|
||||||
|
const userId = getUserId();
|
||||||
|
|
||||||
|
if (!userId) return;
|
||||||
|
|
||||||
|
const responseSignature = await api.get<string>(
|
||||||
|
'/user/' + userId + '/signature',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!responseSignature.data) return '';
|
||||||
|
|
||||||
|
const responseBlob = await axios.get<Blob>(responseSignature.data, {
|
||||||
|
responseType: 'blob',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (responseBlob.status < 400) {
|
||||||
|
return await new Promise<string>((resolve, reject) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.addEventListener('error', reject);
|
||||||
|
reader.addEventListener('load', () => resolve(reader.result as string));
|
||||||
|
reader.readAsDataURL(responseBlob.data);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function setSignature(image: string) {
|
||||||
|
const userId = getUserId();
|
||||||
|
|
||||||
|
if (!userId) return;
|
||||||
|
|
||||||
|
if (image === '') {
|
||||||
|
return await deleteSignature();
|
||||||
|
} else {
|
||||||
|
return await api.put('/user/' + userId + '/signature', { data: image });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteSignature() {
|
||||||
|
const userId = getUserId();
|
||||||
|
|
||||||
|
if (!userId) return;
|
||||||
|
|
||||||
|
return await api.delete('/user/' + userId + '/signature');
|
||||||
|
}
|
||||||
|
|
@ -42,7 +42,7 @@ export function setTheme(theme: Theme): Theme {
|
||||||
|
|
||||||
export enum Lang {
|
export enum Lang {
|
||||||
English = 'eng',
|
English = 'eng',
|
||||||
Thai = 'tha',
|
Thai = 'tha', // spellchecker:disable-line
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,4 @@
|
||||||
{
|
{
|
||||||
"extends": "@quasar/app-vite/tsconfig-preset",
|
"extends": "./.quasar/tsconfig.json",
|
||||||
"compilerOptions": {
|
"exclude": ["./tests"]
|
||||||
"baseUrl": "."
|
|
||||||
},
|
|
||||||
"exclude": ["tests"]
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue