Compare commits
No commits in common. "main" and "v1.0.0" have entirely different histories.
1
.gitignore
vendored
|
@ -21,4 +21,3 @@ pnpm-debug.log*
|
||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
|
|
BIN
cmc_fe.tar.gz
|
@ -1,17 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
method="patch"
|
|
||||||
if [[ $1 != "" ]]; then
|
|
||||||
method=$1
|
|
||||||
fi
|
|
||||||
pnpm version $method
|
|
||||||
if [[ $? != 0 ]]; then
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
pnpm run build
|
|
||||||
if [[ $? == 0 ]]; then
|
|
||||||
tar czf cmc_fe.tar.gz dist
|
|
||||||
git add . cmc_fe.tar.gz
|
|
||||||
git commit -m "updated cmc_fe.tar.gz"
|
|
||||||
git push
|
|
||||||
fi
|
|
12709
package-lock.json
generated
44
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "cmc_fe",
|
"name": "cmc_fe",
|
||||||
"version": "0.1.10",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "vue-cli-service serve",
|
"serve": "vue-cli-service serve",
|
||||||
|
@ -9,37 +9,35 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mdi/font": "5.9.55",
|
"@mdi/font": "5.9.55",
|
||||||
"@vuepic/vue-datepicker": "^3.6.8",
|
"@vuepic/vue-datepicker": "^3.6.4",
|
||||||
"animate.css": "^4.1.1",
|
"axios": "^1.2.2",
|
||||||
"axios": "^1.3.4",
|
"core-js": "^3.8.3",
|
||||||
"core-js": "^3.30.0",
|
|
||||||
"html2pdf.js": "^0.10.1",
|
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
"roboto-fontface": "^0.10.0",
|
"roboto-fontface": "*",
|
||||||
"sass": "^1.60.0",
|
"sass": "^1.57.1",
|
||||||
"sass-loader": "^13.2.2",
|
"sass-loader": "^13.2.0",
|
||||||
"scss": "^0.2.4",
|
"scss": "^0.2.4",
|
||||||
"vue": "^3.2.47",
|
"vue": "^3.2.13",
|
||||||
"vue-datepicker": "^1.3.0",
|
"vue-datepicker": "^1.3.0",
|
||||||
"vue-meta": "^2.4.0",
|
"vue-meta": "^2.4.0",
|
||||||
"vue-router": "^4.1.6",
|
"vue-router": "^4.0.3",
|
||||||
"vue-splash": "^1.2.1",
|
"vue-virtual-scroller": "^2.0.0-beta.7",
|
||||||
"vue-virtual-scroller": "2.0.0-beta.8",
|
"vue3-html2pdf": "^1.1.2",
|
||||||
"vue3-print-nb": "^0.1.4",
|
"vue3-print-nb": "^0.1.4",
|
||||||
"vuetify": "^3.1.12",
|
"vuetify": "^3.0.0-beta.0",
|
||||||
"webfontloader": "^1.6.28"
|
"webfontloader": "^1.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.21.4",
|
"@babel/core": "^7.12.16",
|
||||||
"@babel/eslint-parser": "^7.21.3",
|
"@babel/eslint-parser": "^7.12.16",
|
||||||
"@vue/cli-plugin-babel": "~5.0.8",
|
"@vue/cli-plugin-babel": "~5.0.0",
|
||||||
"@vue/cli-plugin-eslint": "~5.0.8",
|
"@vue/cli-plugin-eslint": "~5.0.0",
|
||||||
"@vue/cli-plugin-router": "~5.0.8",
|
"@vue/cli-plugin-router": "~5.0.0",
|
||||||
"@vue/cli-service": "~5.0.8",
|
"@vue/cli-service": "~5.0.0",
|
||||||
"eslint": "^7.32.0",
|
"eslint": "^7.32.0",
|
||||||
"eslint-plugin-vue": "^8.7.1",
|
"eslint-plugin-vue": "^8.0.3",
|
||||||
"vue-cli-plugin-vuetify": "~2.5.8",
|
"vue-cli-plugin-vuetify": "~2.5.8",
|
||||||
"webpack-plugin-vuetify": "^2.0.1"
|
"webpack-plugin-vuetify": "^2.0.0-alpha.0"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"root": true,
|
"root": true,
|
||||||
|
|
7366
pnpm-lock.yaml
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 9.1 KiB |
Before Width: | Height: | Size: 9.3 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 6.9 KiB |
|
@ -4,12 +4,8 @@
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
<link rel="icon" href="<%= BASE_URL %>images/logo_fields.png">
|
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||||
<link rel="icon" href="<%= BASE_URL %>images/favicon32.png" sizes="32x32" />
|
|
||||||
<link rel="icon" href="<%= BASE_URL %>images/favicon192.png" sizes="192x192" />
|
|
||||||
<link rel="apple-touch-icon" href="<%= BASE_URL %>images/favicon180.png" />
|
|
||||||
<meta name="msapplication-TileImage" content="<%= BASE_URL %>images/favicon270.png" />
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>
|
<noscript>
|
||||||
|
|
34
src/App.vue
|
@ -1,40 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<CMCApp @ready="isReady" :class="{ fadein : !isLoading }" />
|
<CMCApp />
|
||||||
<LoadingScreen :isLoading="isLoading" />
|
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import CMCApp from './CMCApp.vue'
|
import CMCApp from './CMCApp.vue'
|
||||||
import LoadingScreen from "./components/LoadingScreen.vue"
|
|
||||||
export default {
|
export default {
|
||||||
data(){
|
|
||||||
return {
|
|
||||||
isLoading: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
components: {
|
components: {
|
||||||
CMCApp,
|
CMCApp
|
||||||
LoadingScreen
|
}
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
isReady() {
|
|
||||||
this.isLoading = false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
|
||||||
.fadein {
|
|
||||||
animation: fadein 1s forwards;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadein {
|
|
||||||
from {
|
|
||||||
opacity:0;
|
|
||||||
visibility:hidden;
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity:1;
|
|
||||||
visibility:visible;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<v-app>
|
<v-app>
|
||||||
<MyNav :user="user" :site_info="site_info" v-if="!isLoading" />
|
<MyNav :user="user" :site_info="site_info" />
|
||||||
<v-main class="ma-4">
|
<v-main class="ma-4">
|
||||||
<v-banner v-if="!site_info.backend_connected"
|
|
||||||
icon="mdi-exclamation"
|
|
||||||
color="error"
|
|
||||||
text="Cannot connect to the data service. Please contact support." >
|
|
||||||
</v-banner>
|
|
||||||
<router-view :site_info="site_info" :user_info="user_info"></router-view>
|
<router-view :site_info="site_info" :user_info="user_info"></router-view>
|
||||||
</v-main>
|
</v-main>
|
||||||
|
<v-footer>
|
||||||
|
<sub>{{ site_info.name }} v{{ site_info.version }}</sub>
|
||||||
|
</v-footer>
|
||||||
</v-app>
|
</v-app>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -19,16 +17,13 @@ import axios from 'axios'
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
components: {
|
components: {
|
||||||
MyNav
|
MyNav,
|
||||||
},
|
},
|
||||||
emits: ["ready"],
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isLoading: true,
|
|
||||||
site_info: {
|
site_info: {
|
||||||
name: "",
|
name: "Loading...",
|
||||||
features: {},
|
features: {}
|
||||||
backend_connected: false
|
|
||||||
},
|
},
|
||||||
user: {
|
user: {
|
||||||
first_name: "",
|
first_name: "",
|
||||||
|
@ -49,14 +44,6 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
checkIfReady(){
|
|
||||||
if (this.site_info.name != "") {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.isLoading = false
|
|
||||||
this.$emit("ready")
|
|
||||||
},1000)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
checkLoginStatus() {
|
checkLoginStatus() {
|
||||||
let url = this.$api_url + "/users/check_login"
|
let url = this.$api_url + "/users/check_login"
|
||||||
console.log("Checking login status...")
|
console.log("Checking login status...")
|
||||||
|
@ -83,24 +70,10 @@ export default {
|
||||||
|
|
||||||
},
|
},
|
||||||
async getSiteInfo() {
|
async getSiteInfo() {
|
||||||
console.log("Trying to get site Info...")
|
|
||||||
axios
|
axios
|
||||||
.get(this.$api_url + "/info")
|
.get(this.$api_url + "/info")
|
||||||
.then(response => {
|
.then(response => {this.site_info = response.data})
|
||||||
this.site_info = response.data
|
.catch(error => (console.log(error)))
|
||||||
console.log(this.site_info)
|
|
||||||
this.site_info.backend_connected = true
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
this.site_info.name = "Error getting data connection"
|
|
||||||
this.site_info.backend_connected = false
|
|
||||||
console.log(error)
|
|
||||||
setTimeout(() => {
|
|
||||||
this.getSiteInfo()
|
|
||||||
},5000)
|
|
||||||
}).finally(() => {
|
|
||||||
this.checkIfReady()
|
|
||||||
})
|
|
||||||
|
|
||||||
},
|
},
|
||||||
async getUserInfo() {
|
async getUserInfo() {
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import axios from 'axios'
|
|
||||||
import Error from '@/types/ErrorType.vue'
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
customer_list: [],
|
|
||||||
errors: {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods:{
|
methods:{
|
||||||
formatDate(d,f) {
|
formatDate(d,f) {
|
||||||
return moment(String(d)).format(f)
|
return moment(String(d)).format(f)
|
||||||
|
@ -34,35 +26,6 @@ export default {
|
||||||
minute: '2-digit',
|
minute: '2-digit',
|
||||||
second: '2-digit'})
|
second: '2-digit'})
|
||||||
},
|
},
|
||||||
async error(msg) {
|
|
||||||
let e = new Error()
|
|
||||||
e.msg = msg
|
|
||||||
e.id = crypto.randomUUID()
|
|
||||||
this.errors[e.id] = e
|
|
||||||
setTimeout(() => {
|
|
||||||
delete this.errors[e.id]
|
|
||||||
}, 10000)
|
|
||||||
},
|
|
||||||
async getCustomerList(name) {
|
|
||||||
console.log("searching customers...")
|
|
||||||
if (this.customer_list.length == 0) {
|
|
||||||
console.log("getting new customers...")
|
|
||||||
let url = this.$api_url + "/customers/full_list"
|
|
||||||
axios.get(url)
|
|
||||||
.then(resp => {
|
|
||||||
this.customer_list = resp.data
|
|
||||||
console.log(this.customer_list)
|
|
||||||
return this.customer_list.filter(x => {
|
|
||||||
x.name.contains(name) || x.acc_no.contains(name)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return this.customer_list
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -67,10 +67,10 @@ table tr.at_risk:hover {
|
||||||
color: grey;
|
color: grey;
|
||||||
}
|
}
|
||||||
.scroller {
|
.scroller {
|
||||||
height: 600px;
|
border: 1px dotted #333;
|
||||||
}
|
}
|
||||||
.scroller.small {
|
.scroller {
|
||||||
height: 300px;
|
height: 600px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
|
@ -82,6 +82,3 @@ table tr.at_risk:hover {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-bottom: 1px solid #000;
|
border-bottom: 1px solid #000;
|
||||||
}
|
}
|
||||||
.clickable {
|
|
||||||
cursor:pointer;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
<template>
|
|
||||||
<v-container>
|
|
||||||
<v-card title="Add Comment">
|
|
||||||
<v-card-text>
|
|
||||||
<p>Add new comment for : {{ customer.acc_no }} - {{ customer.name }}</p>
|
|
||||||
<v-textarea v-model="comment" label="Comment"></v-textarea>
|
|
||||||
</v-card-text>
|
|
||||||
<v-card-actions>
|
|
||||||
<v-btn color="blue" :loading="saving" @click="saveComment">Save</v-btn>
|
|
||||||
<v-spacer></v-spacer>
|
|
||||||
<v-btn color="grey" @click="$emit('return','cancel')">Cancel</v-btn>
|
|
||||||
</v-card-actions>
|
|
||||||
|
|
||||||
</v-card>
|
|
||||||
</v-container>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import axios from 'axios'
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
customer: null
|
|
||||||
},
|
|
||||||
data(){
|
|
||||||
return {
|
|
||||||
comment: "",
|
|
||||||
saving: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
saveComment() {
|
|
||||||
this.saving = true
|
|
||||||
let url = this.$api_url + "/customers/comments"
|
|
||||||
axios.put(url, {
|
|
||||||
acc_no: this.customer.acc_no,
|
|
||||||
comment: this.comment
|
|
||||||
})
|
|
||||||
.then(resp => {
|
|
||||||
console.log(resp.data)
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.saving = false
|
|
||||||
this.$emit('return',"saved")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,156 +0,0 @@
|
||||||
<template>
|
|
||||||
<v-card :class="{ 'bg-red-lighten-5' : complaint.at_risk }">
|
|
||||||
<v-card-title>
|
|
||||||
Complaint Info : {{ complaint.id }}
|
|
||||||
<v-icon v-if="complaint.active" icon="mdi-play" title="Active"></v-icon>
|
|
||||||
<v-icon v-if="complaint.at_risk" color="red" icon="mdi-exclamation" title="At Risk"></v-icon>
|
|
||||||
</v-card-title>
|
|
||||||
<v-card-subtitle>
|
|
||||||
{{ complaint.customer.acc_no }} - {{ complaint.customer.name }}<br/>
|
|
||||||
{{ formatDate(complaint.complaint_date,"DD/MM/YYYY") }}
|
|
||||||
</v-card-subtitle>
|
|
||||||
<v-card-text>
|
|
||||||
Reason: {{ complaint.reason.reason }}<br/>
|
|
||||||
Driver: {{ complaint.driver.name }}<br/>
|
|
||||||
Delivery Date {{ formatDate(complaint.delivery_date,"DD/MM/YYYY") }}<br/>
|
|
||||||
Order : {{ complaint.sop.doc_no }}<br/>
|
|
||||||
</v-card-text>
|
|
||||||
<v-card-subtitle>
|
|
||||||
<v-progress-linear indeterminate :active="info_loading">
|
|
||||||
</v-progress-linear>
|
|
||||||
Comments
|
|
||||||
</v-card-subtitle>
|
|
||||||
<v-card-text>
|
|
||||||
{{ complaint.info.comments }}
|
|
||||||
</v-card-text>
|
|
||||||
<v-card-subtitle>
|
|
||||||
Info
|
|
||||||
</v-card-subtitle>
|
|
||||||
<v-card-text>
|
|
||||||
<v-row>
|
|
||||||
<v-col cols=4>
|
|
||||||
<v-row dense nogutters>
|
|
||||||
<v-btn-toggle dark multiple background-color="primary">
|
|
||||||
<v-btn :active="complaint.info.checks[1]"
|
|
||||||
:loading="loading[1]"
|
|
||||||
@click="clickComplaintCheckbox(1)">1</v-btn>
|
|
||||||
<v-btn :active="complaint.info.checks[2]"
|
|
||||||
:loading="loading[2]"
|
|
||||||
@click="clickComplaintCheckbox(2)">2</v-btn>
|
|
||||||
<v-btn :active="complaint.info.checks[3]"
|
|
||||||
:loading="loading[3]"
|
|
||||||
@click="clickComplaintCheckbox(3)">3</v-btn>
|
|
||||||
</v-btn-toggle>
|
|
||||||
</v-row>
|
|
||||||
<v-row dense nogutters>
|
|
||||||
<v-btn-toggle dark multiple background-color="primary">
|
|
||||||
<v-btn :active="complaint.at_risk"
|
|
||||||
:loading="loading[4]"
|
|
||||||
@click="clickAtRisk">At Risk</v-btn>
|
|
||||||
<v-btn :active="complaint.info.permanent"
|
|
||||||
:loading="loading[5]"
|
|
||||||
@click="clickPermanent">Permanent</v-btn>
|
|
||||||
</v-btn-toggle>
|
|
||||||
</v-row>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
</v-card-text>
|
|
||||||
<v-card-actions>
|
|
||||||
</v-card-actions>
|
|
||||||
</v-card>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import Complaint from '@/types/ComplaintType.vue'
|
|
||||||
import methods from '@/CommonMethods.vue'
|
|
||||||
import axios from 'axios'
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
in_complaint: new Complaint()
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
in_complaint(){
|
|
||||||
this.complaint = this.in_complaint
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mixins: [methods],
|
|
||||||
emits: ["return"],
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
complaint: this.in_complaint,
|
|
||||||
info_loading: true,
|
|
||||||
loading: [false, false, false, false, false, false]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
isThreeDone() {
|
|
||||||
let c = this.complaint.info.checks
|
|
||||||
if (c[1] && c[2] && c[3]) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods:{
|
|
||||||
getComplaintInfo() {
|
|
||||||
this.info_loading = true
|
|
||||||
let url = this.$api_url + "/customers/complaints/" + this.complaint.id + "/info"
|
|
||||||
console.log("Getting Complaint Info...")
|
|
||||||
axios.get(url)
|
|
||||||
.then(resp =>{
|
|
||||||
this.complaint.info = resp.data
|
|
||||||
this.info_loading = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
checkComplaintStatus(){
|
|
||||||
if (!this.complaint.info.permanent && this.complaint.at_risk && this.isThreeDone) {
|
|
||||||
console.log("Contract no longer at risk")
|
|
||||||
this.complaint.at_risk = false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
clickAtRisk(){
|
|
||||||
this.loading[4] = true
|
|
||||||
this.complaint.at_risk = !this.complaint.at_risk
|
|
||||||
if (this.setComplaintStatus(4)) {
|
|
||||||
this.checkComplaintStatus()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
clickComplaintCheckbox(box) {
|
|
||||||
this.loading[box] = true
|
|
||||||
this.complaint.info.checks[box] = !this.complaint.info.checks[box]
|
|
||||||
if (this.setComplaintStatus(box)) {
|
|
||||||
this.checkComplaintStatus()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
clickPermanent(){
|
|
||||||
this.loading[5] = true
|
|
||||||
this.complaint.info.permanent = !this.complaint.info.permanent
|
|
||||||
if (this.setComplaintStatus(5)) {
|
|
||||||
this.checkComplaintStatus()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setComplaintStatus(idx) {
|
|
||||||
this.info_loading = true
|
|
||||||
let url = this.$api_url + "/customers/complaints/" + this.complaint.id + "/info/set"
|
|
||||||
console.log("Getting Complaint Info...")
|
|
||||||
axios.post(url, {
|
|
||||||
checks: JSON.stringify(this.complaint.info.checks),
|
|
||||||
at_risk: this.complaint.at_risk,
|
|
||||||
permanent: this.complaint.info.permanent
|
|
||||||
}).then(resp => {
|
|
||||||
let stat = resp.data
|
|
||||||
console.log(stat)
|
|
||||||
this.getComplaintInfo()
|
|
||||||
this.info_loading = false
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
}).finally(() => {
|
|
||||||
this.loading[idx] = false
|
|
||||||
})
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.getComplaintInfo()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,113 +0,0 @@
|
||||||
<template>
|
|
||||||
<v-card style="min-height:200px">
|
|
||||||
<v-card-title>
|
|
||||||
Comments
|
|
||||||
<v-btn v-if="customer.id != ''" color="warning" size="smaller" variant="text" icon="mdi-plus" @click="showAddNote"></v-btn>
|
|
||||||
<v-btn v-if="customer.id != ''" color="green" size="smaller" variant="text" icon="mdi-refresh" @click="getCustomerComments" :loading="comments_loading"></v-btn>
|
|
||||||
</v-card-title>
|
|
||||||
<v-card-text>
|
|
||||||
<v-progress-linear color="yellow" :active="comments_loading" indeterminate>
|
|
||||||
</v-progress-linear>
|
|
||||||
<v-list>
|
|
||||||
<RecycleScroller
|
|
||||||
class="scroller small"
|
|
||||||
item-size="50"
|
|
||||||
:items="comments"
|
|
||||||
v-slot="{ item }"
|
|
||||||
key-field="id">
|
|
||||||
<v-list-item :class="{ inactive : !item.active }">
|
|
||||||
{{ item.comment }}
|
|
||||||
<template v-slot:append>
|
|
||||||
<v-icon v-if="item.actioned" icon="mdi-tick" color="green" title="Actioned"></v-icon>
|
|
||||||
<v-btn v-if="item.active" variant="text" :loading="item.active_changing" @click="toggleActiveState(item)" size="small" icon="mdi-play" color="blue" title="Active"></v-btn>
|
|
||||||
<v-btn v-if="!item.active" variant="text" :loading="item.active_changing" @click="toggleActiveState(item)" size="small" icon="mdi-pause" title="Inactive"></v-btn>
|
|
||||||
</template>
|
|
||||||
</v-list-item>
|
|
||||||
</RecycleScroller>
|
|
||||||
</v-list>
|
|
||||||
</v-card-text>
|
|
||||||
</v-card>
|
|
||||||
<v-overlay v-model="dialog[0]" contained class="align-center justify-center">
|
|
||||||
<AddNote :customer="customer" @return="closeAddNote"></AddNote>
|
|
||||||
</v-overlay>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import Customer from '@/types/CustomerType.vue'
|
|
||||||
import AddNote from '@/components/AddNote.vue'
|
|
||||||
import axios from 'axios'
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
customer: new Customer()
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
AddNote
|
|
||||||
},
|
|
||||||
data(){
|
|
||||||
return {
|
|
||||||
comments_loading: null,
|
|
||||||
comments: [],
|
|
||||||
active_changing: false,
|
|
||||||
dialog: {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
customer() {
|
|
||||||
this.getCustomerComments()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
showAddNote() {
|
|
||||||
this.dialog[0] = true
|
|
||||||
},
|
|
||||||
closeAddNote(e){
|
|
||||||
if (e == "saved"){
|
|
||||||
this.getCustomerComments()
|
|
||||||
}
|
|
||||||
this.dialog[0] = false
|
|
||||||
},
|
|
||||||
getCustomerComments(){
|
|
||||||
this.comments_loading = true
|
|
||||||
let url = this.$api_url + "/customers/comments"
|
|
||||||
axios.get(url,{
|
|
||||||
params: {
|
|
||||||
c_id: this.customer.id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(resp => {
|
|
||||||
this.comments = resp.data
|
|
||||||
})
|
|
||||||
.catch(error => (console.log(error)))
|
|
||||||
.finally(() => {
|
|
||||||
this.comments_loading = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
toggleActiveState(cmt){
|
|
||||||
cmt.active_changing = true
|
|
||||||
let url = this.$api_url + "/customers/comments/" + cmt.id + "/active"
|
|
||||||
axios.put(url,{
|
|
||||||
state: !cmt.active
|
|
||||||
})
|
|
||||||
.then(resp => {
|
|
||||||
console.log(resp.data)
|
|
||||||
this.getActiveState(cmt)
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
getActiveState(cmt) {
|
|
||||||
let url = this.$api_url + "/customers/comments/" + cmt.id + "/active"
|
|
||||||
axios.get(url)
|
|
||||||
.then(resp => {
|
|
||||||
cmt.active = resp.data
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
cmt.active_changing = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,66 +0,0 @@
|
||||||
<template>
|
|
||||||
<v-card title="Customer Search">
|
|
||||||
<v-card-text>
|
|
||||||
<v-text-field label="Search" v-model="customer_search" append-icon="mdi-magnify" @click:append="searchCustomers" @keyup.enter.prevent="searchCustomers"></v-text-field>
|
|
||||||
<v-progress-linear indeterminate :active="customers_loading">
|
|
||||||
</v-progress-linear>
|
|
||||||
<v-list>
|
|
||||||
<RecycleScroller class="scroller"
|
|
||||||
:items="filteredCustomers"
|
|
||||||
:item-size="50"
|
|
||||||
v-slot="{ item }"
|
|
||||||
key-field="acc_no"
|
|
||||||
>
|
|
||||||
<v-list-item @click="selectCustomer(item)">
|
|
||||||
{{ item.acc_no }} - {{ item.name }}
|
|
||||||
</v-list-item>
|
|
||||||
</RecycleScroller>
|
|
||||||
</v-list>
|
|
||||||
</v-card-text>
|
|
||||||
</v-card>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import axios from 'axios'
|
|
||||||
export default {
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
customer_search: "",
|
|
||||||
customers_loading: null,
|
|
||||||
customers: []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
filteredCustomers(){
|
|
||||||
if (this.customer_search == null){
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
let query = this.customer_search.toLowerCase()
|
|
||||||
let clist = this.customers.filter(q =>
|
|
||||||
q.name.toLowerCase().includes(query) ||
|
|
||||||
q.acc_no.includes(query)
|
|
||||||
)
|
|
||||||
return clist
|
|
||||||
},
|
|
||||||
},
|
|
||||||
emits: ['returnCustomer'],
|
|
||||||
methods: {
|
|
||||||
selectCustomer(cust){
|
|
||||||
this.$emit('returnCustomer',cust)
|
|
||||||
},
|
|
||||||
searchCustomers() {
|
|
||||||
this.customers_loading = true
|
|
||||||
let url = this.$api_url + "/customers/search/" + this.customer_search
|
|
||||||
axios.get(url)
|
|
||||||
.then(resp => {
|
|
||||||
this.customers = resp.data
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.customers_loading = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,25 +0,0 @@
|
||||||
<template>
|
|
||||||
<v-row>
|
|
||||||
<v-col cols=12>
|
|
||||||
<v-expansion-panels v-model="debugPanel">
|
|
||||||
<v-expansion-panel title="Debug Info">
|
|
||||||
<v-expansion-panel-text>
|
|
||||||
{{ data }}
|
|
||||||
</v-expansion-panel-text>
|
|
||||||
</v-expansion-panel>
|
|
||||||
</v-expansion-panels>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
data: {}
|
|
||||||
},
|
|
||||||
data(){
|
|
||||||
return {
|
|
||||||
debugPanel: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,75 +0,0 @@
|
||||||
<template>
|
|
||||||
<v-card title="Driver Search">
|
|
||||||
<v-card-text>
|
|
||||||
<v-text-field label="Search" v-model="driver_search" append-icon="mdi-magnify"></v-text-field>
|
|
||||||
<v-progress-linear indeterminate :active="drivers_loading">
|
|
||||||
</v-progress-linear>
|
|
||||||
<v-list>
|
|
||||||
<RecycleScroller class="scroller"
|
|
||||||
:items="filteredDrivers"
|
|
||||||
:item-size="50"
|
|
||||||
v-slot="{ item }"
|
|
||||||
key-field="id"
|
|
||||||
>
|
|
||||||
<v-list-item @click="setDriver(item)">
|
|
||||||
{{ item.name }}
|
|
||||||
</v-list-item>
|
|
||||||
</RecycleScroller>
|
|
||||||
</v-list>
|
|
||||||
</v-card-text>
|
|
||||||
</v-card>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import axios from 'axios'
|
|
||||||
export default {
|
|
||||||
props:{
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
driver_search: "",
|
|
||||||
drivers: [],
|
|
||||||
drivers_loading: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
emits: ['return'],
|
|
||||||
created() {
|
|
||||||
this.allDrivers()
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
filteredDrivers() {
|
|
||||||
let q = this.driver_search.toLowerCase()
|
|
||||||
if (q == ""){ return this.drivers }
|
|
||||||
let ms = this.drivers.filter(m =>
|
|
||||||
m.name.toLowerCase().includes(q)
|
|
||||||
)
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
allDrivers(){
|
|
||||||
this.drivers_loading = true
|
|
||||||
console.log("All Drivers...")
|
|
||||||
let url = this.$api_url + "/drivers"
|
|
||||||
axios.get(url)
|
|
||||||
.then(resp => {
|
|
||||||
this.drivers = resp.data
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.drivers_loading = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
setDriver(p){
|
|
||||||
this.$emit('return',p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style scoped>
|
|
||||||
.scroller {
|
|
||||||
height:500px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
<template>
|
|
||||||
<v-row>
|
|
||||||
<v-list>
|
|
||||||
<v-list-item v-for="(e, index) in errors" :key="index">
|
|
||||||
<v-banner color="error" icon="$error">
|
|
||||||
<v-banner-text>
|
|
||||||
{{ e }}
|
|
||||||
</v-banner-text>
|
|
||||||
</v-banner>
|
|
||||||
</v-list-item>
|
|
||||||
</v-list>
|
|
||||||
</v-row>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
errors: []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,49 +0,0 @@
|
||||||
<template>
|
|
||||||
<div :class="{ loader: true, fadeout: !isLoading }">
|
|
||||||
<div class="animate__animated animate__rubberBand animate__infinite animate__slow">
|
|
||||||
<v-img style="border-radius:5%" height="128" src="/images/cmc-logo.png" /><br/>
|
|
||||||
</div>
|
|
||||||
<br/>
|
|
||||||
<v-progress-circular
|
|
||||||
color="deep-orange"
|
|
||||||
indeterminate
|
|
||||||
></v-progress-circular>
|
|
||||||
Starting ...
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import 'animate.css';
|
|
||||||
export default {
|
|
||||||
name: "LoadingScreen",
|
|
||||||
props: ["isLoading"]
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.loader {
|
|
||||||
background-color: lightyellow;
|
|
||||||
bottom: 0;
|
|
||||||
color: black;
|
|
||||||
display: block;
|
|
||||||
font-size: 16px;
|
|
||||||
left: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
padding-top: 10vh;
|
|
||||||
position: fixed;
|
|
||||||
right: 0;
|
|
||||||
text-align: center;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fadeout {
|
|
||||||
animation: fadeout 1s forwards;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeout {
|
|
||||||
to {
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,93 +0,0 @@
|
||||||
<template>
|
|
||||||
<v-card title="Med Search">
|
|
||||||
<v-card-text>
|
|
||||||
<v-text-field label="Search" v-model="med_search" append-icon="mdi-magnify" @click:append="searchMeds" @keyup.enter.prevent="searchMeds"></v-text-field>
|
|
||||||
<v-progress-linear indeterminate :active="meds_loading">
|
|
||||||
</v-progress-linear>
|
|
||||||
<v-list>
|
|
||||||
<RecycleScroller class="scroller"
|
|
||||||
:items="filteredMeds"
|
|
||||||
:item-size="50"
|
|
||||||
v-slot="{ item }"
|
|
||||||
key-field="id"
|
|
||||||
>
|
|
||||||
<v-list-item @click="setMed(item)">
|
|
||||||
{{ item.med_code }} : {{ item.name }}
|
|
||||||
{{ item }}
|
|
||||||
</v-list-item>
|
|
||||||
</RecycleScroller>
|
|
||||||
</v-list>
|
|
||||||
</v-card-text>
|
|
||||||
</v-card>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import axios from 'axios'
|
|
||||||
export default {
|
|
||||||
props:{
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
med_search: "",
|
|
||||||
meds: [],
|
|
||||||
meds_loading: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
emits: ['returnMed'],
|
|
||||||
created() {
|
|
||||||
this.allMeds()
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
filteredMeds() {
|
|
||||||
let q = this.med_search.toLowerCase()
|
|
||||||
if (q == ""){ return this.meds }
|
|
||||||
let ms = this.meds.filter(m =>
|
|
||||||
m.name.toLowerCase().includes(q) ||
|
|
||||||
m.med_code.toLowerCase().includes(q)
|
|
||||||
)
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
allMeds(){
|
|
||||||
this.meds_loading = true
|
|
||||||
console.log("All Meds...")
|
|
||||||
let url = this.$api_url + "/meds/list"
|
|
||||||
axios.get(url)
|
|
||||||
.then(resp => {
|
|
||||||
this.meds = resp.data
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.meds_loading = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
searchMeds() {
|
|
||||||
this.meds_loading = true
|
|
||||||
console.log("Searching for " & this.med_search)
|
|
||||||
let url = this.$api_url + "/meds/search/" + this.med_search
|
|
||||||
axios.get(url)
|
|
||||||
.then(resp => {
|
|
||||||
console.log(resp)
|
|
||||||
this.meds = resp.data
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.meds_loading = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
setMed(p){
|
|
||||||
this.$emit('returnMed',p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style scoped>
|
|
||||||
.scroller {
|
|
||||||
height:500px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -4,25 +4,7 @@
|
||||||
<v-app-bar-nav-icon v-if="user.logged_in" variant="text" @click.stop="drawer = !drawer"></v-app-bar-nav-icon>
|
<v-app-bar-nav-icon v-if="user.logged_in" variant="text" @click.stop="drawer = !drawer"></v-app-bar-nav-icon>
|
||||||
<v-toolbar-title>{{ site_info.name }}</v-toolbar-title>
|
<v-toolbar-title>{{ site_info.name }}</v-toolbar-title>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer></v-spacer>
|
||||||
<v-menu>
|
<v-btn variant="text" v-if="user.logged_in">Hi {{ user.first_name }}</v-btn>
|
||||||
<template v-slot:activator="{ props }">
|
|
||||||
<v-btn
|
|
||||||
variant="text"
|
|
||||||
v-if="user.logged_in"
|
|
||||||
v-bind="props">
|
|
||||||
Hi {{ user.first_name }}
|
|
||||||
</v-btn>
|
|
||||||
</template>
|
|
||||||
<v-list theme="dark">
|
|
||||||
<v-list-item
|
|
||||||
v-for="(item, index) in user_items"
|
|
||||||
:key="index"
|
|
||||||
:title="item.title"
|
|
||||||
:to="item.value"
|
|
||||||
>
|
|
||||||
</v-list-item>
|
|
||||||
</v-list>
|
|
||||||
</v-menu>
|
|
||||||
</v-app-bar>
|
</v-app-bar>
|
||||||
<v-navigation-drawer
|
<v-navigation-drawer
|
||||||
v-if="user.logged_in"
|
v-if="user.logged_in"
|
||||||
|
@ -46,22 +28,11 @@
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
<v-divider></v-divider>
|
|
||||||
<v-footer>
|
|
||||||
<v-banner>
|
|
||||||
<v-banner-text>
|
|
||||||
<sub>{{ site_info.name }}<br/>
|
|
||||||
BE v{{ site_info.version }}<br/>
|
|
||||||
FE v{{ appVersion }}
|
|
||||||
</sub>
|
|
||||||
</v-banner-text>
|
|
||||||
</v-banner>
|
|
||||||
</v-footer>
|
|
||||||
</v-list>
|
</v-list>
|
||||||
</v-navigation-drawer>
|
</v-navigation-drawer>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { version } from "@/../package.json"
|
|
||||||
export default{
|
export default{
|
||||||
name: "MyNav",
|
name: "MyNav",
|
||||||
props: {
|
props: {
|
||||||
|
@ -78,19 +49,12 @@ export default{
|
||||||
} else {
|
} else {
|
||||||
this.items = []
|
this.items = []
|
||||||
}
|
}
|
||||||
},
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
user_items() {
|
|
||||||
return this.items.filter(x => x.isUserMgmt == true)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data(){
|
data(){
|
||||||
return {
|
return {
|
||||||
appVersion: version,
|
|
||||||
items: [],
|
items: [],
|
||||||
drawer: null,
|
drawer: null
|
||||||
drawer2: false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
@ -101,6 +65,7 @@ export default{
|
||||||
methods:{
|
methods:{
|
||||||
get_menu() {
|
get_menu() {
|
||||||
let items = []
|
let items = []
|
||||||
|
items.push({title: "Dashboard", value:"/about"})
|
||||||
items.push({title: "Customers",
|
items.push({title: "Customers",
|
||||||
value:"/customers",
|
value:"/customers",
|
||||||
children:[{title:"List",
|
children:[{title:"List",
|
||||||
|
@ -119,7 +84,7 @@ export default{
|
||||||
value:"/sop/printed"}]
|
value:"/sop/printed"}]
|
||||||
})
|
})
|
||||||
|
|
||||||
items.push({title: "Logout", value:"/logout", isUserMgmt: true})
|
items.push({title: "Logout", value:"/logout"})
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
<template>
|
<template>
|
||||||
<v-container class="button-container">
|
<v-container class="button-container">
|
||||||
<v-btn :loading="generating" color="primary" @click="generatePdf()" class="mr-2">Create PDF</v-btn>
|
<v-btn color="primary" @click="generatePdf()" class="mr-2">Create PDF</v-btn>
|
||||||
<v-btn color="grey" v-print="printObj">Print</v-btn>
|
<v-btn color="grey" v-print="printObj">Print</v-btn>
|
||||||
</v-container>
|
</v-container>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import html2pdf from 'html2pdf.js';
|
import html2pdf from 'html2pdf.js';
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
scope: String,
|
scope: String
|
||||||
filename: String
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
generating: false,
|
|
||||||
printObj: {
|
printObj: {
|
||||||
id: this.scope,
|
id: this.scope,
|
||||||
previewTitle: "Report Print",
|
previewTitle: "Report Print",
|
||||||
|
@ -22,16 +20,8 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods:{
|
methods:{
|
||||||
generatePdf() {
|
async generatePdf() {
|
||||||
this.generating = true
|
html2pdf(document.getElementById(this.scope))
|
||||||
setTimeout(() => {
|
|
||||||
let el = document.getElementById(this.scope)
|
|
||||||
let opts = {
|
|
||||||
filename: (this.filename || 'file' ) + ".pdf"
|
|
||||||
}
|
|
||||||
html2pdf().set(opts).from(el).save()
|
|
||||||
this.generating = false
|
|
||||||
},500)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
<template>
|
|
||||||
<v-card title="Product Search">
|
|
||||||
<v-card-text>
|
|
||||||
<v-text-field label="Search" v-model="product_search" append-icon="mdi-magnify" @click:append="searchProducts" @keyup.enter.prevent="searchProducts"></v-text-field>
|
|
||||||
<v-progress-linear indeterminate :active="products_loading">
|
|
||||||
</v-progress-linear>
|
|
||||||
<v-list>
|
|
||||||
<RecycleScroller class="scroller"
|
|
||||||
:items="products"
|
|
||||||
:item-size="50"
|
|
||||||
v-slot="{ item }"
|
|
||||||
key-field="code"
|
|
||||||
>
|
|
||||||
<v-list-item @click="setProduct(item)">
|
|
||||||
|
|
||||||
{{ item.code }} - {{ item.name }}
|
|
||||||
</v-list-item>
|
|
||||||
</RecycleScroller>
|
|
||||||
</v-list>
|
|
||||||
</v-card-text>
|
|
||||||
</v-card>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import axios from 'axios'
|
|
||||||
export default {
|
|
||||||
props:{
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
product_search: "",
|
|
||||||
products: [],
|
|
||||||
products_loading: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
emits: ['returnProduct'],
|
|
||||||
methods: {
|
|
||||||
searchProducts() {
|
|
||||||
this.products_loading = true
|
|
||||||
console.log("Searching for " & this.product_search)
|
|
||||||
let url = this.$api_url + "/products/search/" + this.product_search
|
|
||||||
axios.get(url)
|
|
||||||
.then(resp => {
|
|
||||||
console.log(resp)
|
|
||||||
this.products = resp.data
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.products_loading = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
setProduct(p){
|
|
||||||
this.$emit('returnProduct',p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style scoped>
|
|
||||||
.scroller {
|
|
||||||
height:500px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -1,152 +0,0 @@
|
||||||
<template>
|
|
||||||
<v-card>
|
|
||||||
<v-card-title>
|
|
||||||
{{ doc_types[doc_status] }} Orders - {{ customer.acc_no }} {{ customer.name }}
|
|
||||||
<v-btn v-if="customer.id != ''" size="smaller" icon="mdi-refresh" variant="text" color="green" @click="getCustomerRecentOrders" :loading="orders_loading"></v-btn>
|
|
||||||
|
|
||||||
</v-card-title>
|
|
||||||
<v-progress-linear color="blue" :active="orders_loading" indeterminate>
|
|
||||||
</v-progress-linear>
|
|
||||||
<v-container>
|
|
||||||
<v-row dense>
|
|
||||||
<v-col cols=12>
|
|
||||||
<RecycleScroller :items="orders"
|
|
||||||
class="scroller"
|
|
||||||
:class="{ small : size_small }"
|
|
||||||
:item-size="180"
|
|
||||||
key-field="doc_no"
|
|
||||||
v-slot="{ item }">
|
|
||||||
|
|
||||||
<v-card class="ma-2" density="compact" :class="{ 'bg-green-lighten-5' : item.doc_status == 'Live' }">
|
|
||||||
<v-row dense>
|
|
||||||
<v-col>
|
|
||||||
<v-card-title>
|
|
||||||
Order: {{ item.doc_no }}
|
|
||||||
</v-card-title>
|
|
||||||
<v-card-subtitle>
|
|
||||||
Order Date : {{ formatDate(item.doc_date,"DD/MM/YYYY") }}<br/>
|
|
||||||
Delivery Date : {{ formatDate(item.req_del_date,"DD/MM/YYYY") }}<br/>
|
|
||||||
<v-icon color="blue" v-if="item.doc_status == 'Completed'" icon="mdi-check"></v-icon>
|
|
||||||
<v-icon v-if="item.doc_status == 'Live'" icon="mdi-play"></v-icon>
|
|
||||||
{{ item.doc_status }}
|
|
||||||
<br/>
|
|
||||||
<v-icon color="blue-lighten-1" v-if="item.print_status == 'Printed'" icon="mdi-printer"></v-icon>
|
|
||||||
<v-icon v-if="item.print_status == 'Not printed'" icon="mdi-printer-off"></v-icon>
|
|
||||||
{{ item.print_status }}
|
|
||||||
</v-card-subtitle>
|
|
||||||
<v-card-text>
|
|
||||||
{{ item.customer.acc_no }} - {{ item.customer.name }}
|
|
||||||
</v-card-text >
|
|
||||||
</v-col>
|
|
||||||
<v-col>
|
|
||||||
<v-card-text >
|
|
||||||
<!--<h5>Address :</h5>-->
|
|
||||||
<template v-if="item.del_addr.id != 0 && item.del_addr.postal_name != ''">
|
|
||||||
<h5>Delivery Address :</h5>
|
|
||||||
<template v-for="(v, k , index) in item.del_addr" :key="index">
|
|
||||||
<span class="text-caption" v-if="k != 'id' && (v != '' || v != 0)">
|
|
||||||
{{ v }}<br/>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
</v-card-text>
|
|
||||||
</v-col>
|
|
||||||
<v-col cols=5>
|
|
||||||
<v-card-text style="max-height:160px;overflow-y:scroll;">
|
|
||||||
<h5>Items :</h5>
|
|
||||||
<span class="text-caption" v-for="(i, index) in item.products" :key="index" style="border-bottom: 1px dotted #000;">
|
|
||||||
{{ i.code }} - {{ i.name }}
|
|
||||||
<span v-if="i.quantity != 0">x {{ i.quantity }}</span><br/>
|
|
||||||
</span>
|
|
||||||
</v-card-text>
|
|
||||||
</v-col>
|
|
||||||
<v-col cols=1>
|
|
||||||
<v-btn size="small" color="warning" title="Add Complaint">
|
|
||||||
<v-icon>mdi-plus</v-icon>
|
|
||||||
<v-icon>mdi-exclamation</v-icon>
|
|
||||||
</v-btn>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
|
|
||||||
</v-card>
|
|
||||||
</RecycleScroller>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
</v-container>
|
|
||||||
</v-card>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import axios from 'axios'
|
|
||||||
import Customer from '@/types/CustomerType.vue'
|
|
||||||
import methods from '@/CommonMethods.vue'
|
|
||||||
export default {
|
|
||||||
props:{
|
|
||||||
customer: new Customer(),
|
|
||||||
doc_status: Number,
|
|
||||||
limit: Number,
|
|
||||||
size_small: Boolean
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
customer() {
|
|
||||||
this.getCustomerRecentOrders()
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mixins: [methods],
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
orders_loading: false,
|
|
||||||
orders: [],
|
|
||||||
doc_types: ["Live","","Completed"],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
prog_col(){
|
|
||||||
if (this.doc_status == 2){
|
|
||||||
return "green"
|
|
||||||
} else {
|
|
||||||
return "blue"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
sortedOrders() {
|
|
||||||
let sorted = this.orders
|
|
||||||
sorted.sort((a, b) => {
|
|
||||||
if (a.doc_date < b.doc_date){
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
if (a.doc_date > b.doc_date){
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
})
|
|
||||||
return sorted
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
getCustomerRecentOrders(){
|
|
||||||
this.orders_loading = true
|
|
||||||
let url = this.$api_url + "/customers/" + this.customer.id + "/orders/recent"
|
|
||||||
axios.get(url, {
|
|
||||||
params: {
|
|
||||||
doc_status: this.doc_status,
|
|
||||||
limit: this.limit || 6
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(resp => {
|
|
||||||
this.orders = resp.data
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.orders_loading = false
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
if (this.customer.id != "") {
|
|
||||||
this.getCustomerRecentOrders()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,8 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<PrintButtons :scope="scope" :filename="filename" />
|
<PrintButtons :scope="scope" />
|
||||||
<v-container>
|
<v-container>
|
||||||
<v-card class="a4 page">
|
<v-card class="a4 page">
|
||||||
<div :id="scope" class="pdf-scope" >
|
<div :id="scope" class="pdf-scope">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
</v-card>
|
</v-card>
|
||||||
|
@ -10,11 +10,9 @@
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import PrintButtons from './PrintButtons.vue'
|
import PrintButtons from './PrintButtons.vue'
|
||||||
import '@/assets/css/reports.css';
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
scope: String,
|
scope: String
|
||||||
filename: String
|
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
PrintButtons
|
PrintButtons
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
<template>
|
|
||||||
<v-card title="Vet Search">
|
|
||||||
<v-card-text>
|
|
||||||
<v-text-field label="Search" v-model="vet_search" append-icon="mdi-magnify" @click:append="searchVets" @keyup.enter.prevent="searchVets"></v-text-field>
|
|
||||||
<v-progress-linear indeterminate :active="vets_loading">
|
|
||||||
</v-progress-linear>
|
|
||||||
<v-list>
|
|
||||||
<RecycleScroller class="scroller"
|
|
||||||
:items="vets"
|
|
||||||
:item-size="50"
|
|
||||||
v-slot="{ item }"
|
|
||||||
key-field="id"
|
|
||||||
>
|
|
||||||
<v-list-item @click="setVet(item)">
|
|
||||||
{{ item.practice }}
|
|
||||||
<v-tooltip activator="parent"
|
|
||||||
location="end">
|
|
||||||
{{ item.practice }}
|
|
||||||
<template v-for="(c,index) in item.contacts" :key="index">
|
|
||||||
<template v-if="c != ''">
|
|
||||||
{{ c }}<br/>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
</v-tooltip>
|
|
||||||
|
|
||||||
</v-list-item>
|
|
||||||
</RecycleScroller>
|
|
||||||
</v-list>
|
|
||||||
</v-card-text>
|
|
||||||
</v-card>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import axios from 'axios'
|
|
||||||
export default {
|
|
||||||
props:{
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
vet_search: "",
|
|
||||||
vets: [],
|
|
||||||
vets_loading: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
emits: ['returnVet'],
|
|
||||||
methods: {
|
|
||||||
searchVets() {
|
|
||||||
this.vets_loading = true
|
|
||||||
console.log("Searching for " & this.vet_search)
|
|
||||||
let url = this.$api_url + "/vets/search/" + this.vet_search
|
|
||||||
axios.get(url)
|
|
||||||
.then(resp => {
|
|
||||||
console.log(resp)
|
|
||||||
this.vets = resp.data
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.vets_loading = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
setVet(p){
|
|
||||||
this.$emit('returnVet',p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style scoped>
|
|
||||||
.scroller {
|
|
||||||
height:500px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -10,8 +10,6 @@ import './assets/css/app.scss'
|
||||||
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
|
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import VueVirtualScroller from 'vue-virtual-scroller'
|
import VueVirtualScroller from 'vue-virtual-scroller'
|
||||||
import DebugPanel from '@/components/DebugPanel.vue'
|
|
||||||
import ErrorBanner from '@/components/ErrorBanner.vue'
|
|
||||||
|
|
||||||
axios.defaults.headers.common['X-Authentication'] = `Bearer ${localStorage.getItem('access_token')}`;
|
axios.defaults.headers.common['X-Authentication'] = `Bearer ${localStorage.getItem('access_token')}`;
|
||||||
|
|
||||||
|
@ -21,8 +19,6 @@ const app = createApp(App).use(router)
|
||||||
.use(vuetify)
|
.use(vuetify)
|
||||||
.use(print)
|
.use(print)
|
||||||
.use(VueVirtualScroller)
|
.use(VueVirtualScroller)
|
||||||
.use(DebugPanel)
|
|
||||||
.use(ErrorBanner)
|
|
||||||
.component('DatePicker', Datepicker)
|
.component('DatePicker', Datepicker)
|
||||||
|
|
||||||
var url = window.location.protocol + "//" + window.location.host + "/api/v1"
|
var url = window.location.protocol + "//" + window.location.host + "/api/v1"
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
<script>
|
|
||||||
import axios from 'axios'
|
|
||||||
export default {
|
|
||||||
methods: {
|
|
||||||
customerSearch(query) {
|
|
||||||
let url = this.$api_url + "/customers/search/" + query
|
|
||||||
axios.get(url)
|
|
||||||
.then(resp => {
|
|
||||||
return resp.data
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { createRouter, createWebHistory } from 'vue-router'
|
import { createRouter, createWebHistory } from 'vue-router'
|
||||||
|
import HomeView from '../views/HomeView.vue'
|
||||||
const AboutView = () => import('../views/AboutView.vue')
|
const AboutView = () => import('../views/AboutView.vue')
|
||||||
const LoginPage = () => import('../views/LoginPage.vue')
|
const LoginPage = () => import('../views/LoginPage.vue')
|
||||||
const LogOut = () => import('../components/LogOut.vue')
|
const LogOut = () => import('../components/LogOut.vue')
|
||||||
|
@ -6,14 +7,13 @@ const CustomerList = () => import('../views/customers/CustomerList.vue')
|
||||||
const ContractList = () => import('../views/contracts/ContractList.vue')
|
const ContractList = () => import('../views/contracts/ContractList.vue')
|
||||||
const ComplaintsList = () => import('../views/complaints/ComplaintsList.vue')
|
const ComplaintsList = () => import('../views/complaints/ComplaintsList.vue')
|
||||||
const MedFeedsList = () => import('../views/medfeeds/MedFeedsList.vue')
|
const MedFeedsList = () => import('../views/medfeeds/MedFeedsList.vue')
|
||||||
const OrderList = () => import('../views/salesorders/OrdersList.vue')
|
|
||||||
const SOPPrintedList = () => import('../views/salesorders/SOPPrinted.vue')
|
const SOPPrintedList = () => import('../views/salesorders/SOPPrinted.vue')
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
name: 'home',
|
name: 'home',
|
||||||
component: CustomerList
|
component: HomeView
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/about',
|
path: '/about',
|
||||||
|
@ -40,41 +40,16 @@ const routes = [
|
||||||
name: 'contractlist',
|
name: 'contractlist',
|
||||||
component: ContractList
|
component: ContractList
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/customers/contracts/list/:id',
|
|
||||||
name: 'contractlistid',
|
|
||||||
component: ContractList
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/customers/medicated-feeds/list',
|
path: '/customers/medicated-feeds/list',
|
||||||
name: 'medfeedslist',
|
name: 'medfeedslist',
|
||||||
component: MedFeedsList
|
component: MedFeedsList
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/customers/medicated-feeds/list/:id',
|
|
||||||
name: 'medfeedslistid',
|
|
||||||
component: MedFeedsList
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/customers/complaints/list',
|
path: '/customers/complaints/list',
|
||||||
name: 'complaintslist',
|
name: 'complaintslist',
|
||||||
component: ComplaintsList
|
component: ComplaintsList
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/customers/complaints/list/:id',
|
|
||||||
name: 'complaintslistid',
|
|
||||||
component: ComplaintsList
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/customers/orders/list',
|
|
||||||
name: 'orderslist',
|
|
||||||
component: OrderList
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/customers/orders/list/:id',
|
|
||||||
name: 'orderslistid',
|
|
||||||
component: OrderList
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/sop/printed',
|
path: '/sop/printed',
|
||||||
name: 'sopprinted',
|
name: 'sopprinted',
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
<script>
|
|
||||||
export default class ComplaintInfo {
|
|
||||||
checks = [false, false, false, false]
|
|
||||||
permanent = false
|
|
||||||
comments = ""
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,16 +0,0 @@
|
||||||
<script>
|
|
||||||
import Customer from '@/types/CustomerType.vue'
|
|
||||||
import ComplaintInfo from '@/types/ComplaintInfoType.vue'
|
|
||||||
export default class Complaint {
|
|
||||||
id = 0
|
|
||||||
complaint_date = new Date()
|
|
||||||
delivery_date = ""
|
|
||||||
reason = ""
|
|
||||||
sop = {}
|
|
||||||
at_risk = false
|
|
||||||
driver = ""
|
|
||||||
info = new ComplaintInfo()
|
|
||||||
customer = new Customer()
|
|
||||||
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,18 +0,0 @@
|
||||||
<script>
|
|
||||||
import Customer from '@/types/CustomerType.vue';
|
|
||||||
export default class Contract {
|
|
||||||
no = "";
|
|
||||||
customer = new Customer();
|
|
||||||
terms = "";
|
|
||||||
products = [];
|
|
||||||
start_date = new Date();
|
|
||||||
finish_date = new Date();
|
|
||||||
agree_date = "";
|
|
||||||
tonnage_per_month = 1;
|
|
||||||
total_tonnage = 1;
|
|
||||||
comments = "";
|
|
||||||
office_comments = "";
|
|
||||||
active = true;
|
|
||||||
isNew = true;
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,19 +0,0 @@
|
||||||
<script>
|
|
||||||
export default class CustomerAddress {
|
|
||||||
id = "";
|
|
||||||
description = "";
|
|
||||||
contract = "";
|
|
||||||
postal_name = "";
|
|
||||||
line_1 = "";
|
|
||||||
line_2 = "";
|
|
||||||
line_3 = "";
|
|
||||||
line_4 = "";
|
|
||||||
city = "";
|
|
||||||
county = "";
|
|
||||||
postcode = "";
|
|
||||||
country = "";
|
|
||||||
email = "";
|
|
||||||
faxno = "";
|
|
||||||
telephone = "";
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<script>
|
|
||||||
import CustomerAddress from '@/types/CustomerAddressType.vue'
|
|
||||||
export default class Customer {
|
|
||||||
id = "";
|
|
||||||
acc_no = "";
|
|
||||||
name = "";
|
|
||||||
short_name = "";
|
|
||||||
full_title = "";
|
|
||||||
at_risk = false;
|
|
||||||
address = new CustomerAddress();
|
|
||||||
notes = {}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,6 +0,0 @@
|
||||||
<script>
|
|
||||||
export default class Error {
|
|
||||||
id = "";
|
|
||||||
msg = "";
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,23 +0,0 @@
|
||||||
<script>
|
|
||||||
import Medication from '@/types/MedicationType.vue'
|
|
||||||
import Customer from '@/types/CustomerType.vue'
|
|
||||||
import CustomerAddress from '@/types/CustomerAddressType.vue'
|
|
||||||
import Product from '@/types/ProductType.vue'
|
|
||||||
import Vet from '@/types/VetType.vue'
|
|
||||||
export default class MedicatedFeed {
|
|
||||||
id = 0;
|
|
||||||
med_feed_id = 0;
|
|
||||||
medication = new Medication();
|
|
||||||
customer = new Customer();
|
|
||||||
product = new Product();
|
|
||||||
tonnage = 0;
|
|
||||||
vet = new Vet();
|
|
||||||
date_required = "";
|
|
||||||
delivery_address = new CustomerAddress();
|
|
||||||
alt_adds = [];
|
|
||||||
repeat = false;
|
|
||||||
repeat_message = "";
|
|
||||||
current = true;
|
|
||||||
isNew = true;
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,9 +0,0 @@
|
||||||
<script>
|
|
||||||
export default class Medication {
|
|
||||||
id = 0;
|
|
||||||
name = "";
|
|
||||||
info = [];
|
|
||||||
med_code = "";
|
|
||||||
inclusion_rate = "";
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,7 +0,0 @@
|
||||||
<script>
|
|
||||||
export default class Product {
|
|
||||||
code = "";
|
|
||||||
name = "";
|
|
||||||
price = "";
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,7 +0,0 @@
|
||||||
<script>
|
|
||||||
export default class Vet {
|
|
||||||
id = 0;
|
|
||||||
practice = "";
|
|
||||||
contacts = [];
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,23 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<v-card width="500" min-height="350"
|
<v-card width="500" height="300"
|
||||||
class="mx-auto my-12"
|
class="mx-auto my-12"
|
||||||
id="login-box"
|
|
||||||
title="Welcome!"
|
title="Welcome!"
|
||||||
subtitle="Please Log In">
|
subtitle="Please Log In">
|
||||||
<v-form :disabled="!my_site_info.backend_connected">
|
<v-form>
|
||||||
<v-responsive class="mx-auto" max-width="475">
|
<v-responsive class="mx-auto" max-width="475">
|
||||||
<v-text-field label="Username"
|
<v-text-field label="Email" clearable v-model="user.email"></v-text-field>
|
||||||
@keyup.enter="submitLogin"
|
<v-text-field label="Password" v-model="user.password" clearable
|
||||||
clearable
|
type="password"></v-text-field>
|
||||||
v-model="user.email"></v-text-field>
|
<v-btn color="blue" @click="submitLogin">Login</v-btn>
|
||||||
<v-text-field label="Password"
|
|
||||||
@keyup.enter="submitLogin"
|
|
||||||
v-model="user.password" clearable
|
|
||||||
type="password"></v-text-field>
|
|
||||||
<v-btn :disabled="!my_site_info.backend_connected" color="blue" :loading="logging_in" @click="submitLogin">Login</v-btn>
|
|
||||||
<v-banner v-if="show_error" color="error" icon="mdi-exclamation-thick" theme="dark">
|
|
||||||
<v-banner-text>{{ error_message }}</v-banner-text>
|
|
||||||
</v-banner>
|
|
||||||
</v-responsive>
|
</v-responsive>
|
||||||
</v-form>
|
</v-form>
|
||||||
</v-card>
|
</v-card>
|
||||||
|
@ -27,35 +18,18 @@
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
|
||||||
site_info: {}
|
|
||||||
},
|
|
||||||
name: 'LoginPage',
|
name: 'LoginPage',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
my_site_info: this.site_info,
|
|
||||||
user: {
|
user: {
|
||||||
email: "",
|
email: "",
|
||||||
password: ""
|
password: ""
|
||||||
},
|
}
|
||||||
show_error: false,
|
|
||||||
error_message: "",
|
|
||||||
error_count: 0,
|
|
||||||
logging_in: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
'site_info.backend_connected'(new_val) {
|
|
||||||
console.log(new_val)
|
|
||||||
this.my_site_info.backend_connected = new_val
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
submitLogin() {
|
submitLogin() {
|
||||||
this.error_message = ""
|
|
||||||
this.show_error = false
|
|
||||||
let url = this.$api_url + "/users/login"
|
let url = this.$api_url + "/users/login"
|
||||||
this.logging_in = true
|
|
||||||
console.log("Logging in...")
|
console.log("Logging in...")
|
||||||
axios
|
axios
|
||||||
.post(url, {
|
.post(url, {
|
||||||
|
@ -64,7 +38,6 @@ export default {
|
||||||
})
|
})
|
||||||
.then(resp => {
|
.then(resp => {
|
||||||
let data = resp.data
|
let data = resp.data
|
||||||
console.log(data)
|
|
||||||
if (data.logged_in) {
|
if (data.logged_in) {
|
||||||
let token = data.token
|
let token = data.token
|
||||||
localStorage.setItem('access_token', token.content)
|
localStorage.setItem('access_token', token.content)
|
||||||
|
@ -74,34 +47,10 @@ export default {
|
||||||
console.log("Logged in")
|
console.log("Logged in")
|
||||||
window.location.href = '/'
|
window.location.href = '/'
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
this.error_message = "Login failed. Invalid username or password."
|
|
||||||
this.error_count += 1
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => { console.log(error) })
|
||||||
console.log(error)
|
|
||||||
this.error_message = "Login failed. Invalid username or password."
|
|
||||||
this.error_count += 1
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
setTimeout(() => {
|
|
||||||
if (this.error_message != ""){
|
|
||||||
this.show_error = true
|
|
||||||
}
|
|
||||||
this.logging_in = false
|
|
||||||
if (this.error_count > 2) {
|
|
||||||
let box = document.getElementById("login-box")
|
|
||||||
box.classList.add("animate__animated")
|
|
||||||
box.classList.add("animate__hinge")
|
|
||||||
setTimeout(() => {
|
|
||||||
box.classList.add("animate__fadeInUp")
|
|
||||||
box.classList.remove("animate__hinge")
|
|
||||||
},5000)
|
|
||||||
this.error_count = 0
|
|
||||||
}
|
|
||||||
},2000)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,175 +0,0 @@
|
||||||
<template>
|
|
||||||
<v-card :title="title">
|
|
||||||
<v-card-subtitle>
|
|
||||||
Complaint : {{ complaint.id }}
|
|
||||||
</v-card-subtitle>
|
|
||||||
<v-card-text>
|
|
||||||
<v-container>
|
|
||||||
<v-row>
|
|
||||||
<v-col cols=6>
|
|
||||||
<v-text-field readonly variant="outlined" prepend-inner-icon="mdi-magnify" @click="showCustomerSearch" label="Customer" :model-value="complaint.customer.acc_no + ' - ' + complaint.customer.name">
|
|
||||||
</v-text-field>
|
|
||||||
<label>
|
|
||||||
Complaint Date :
|
|
||||||
<DatePicker v-model="complaint.complaint_date" format="dd/MM/yyyy" />
|
|
||||||
</label>
|
|
||||||
</v-col>
|
|
||||||
<v-col cols=6>
|
|
||||||
<v-text-field label="Sales Order Number" v-model="complaint.sop.doc_no" variant="outlined"></v-text-field>
|
|
||||||
<v-select label="Reason" v-model="complaint.reason" :items="reasons" item-title="reason" item-value="id" return-object variant="outlined"></v-select>
|
|
||||||
<v-text-field readonly prepend-inner-icon="mdi-magnify" label="Driver" v-model="complaint.driver.name" variant="outlined" @click="showDriverSearch"></v-text-field>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
<v-row>
|
|
||||||
<v-col cols=12>
|
|
||||||
<v-progress-linear :active="info_loading" indeterminate></v-progress-linear>
|
|
||||||
<v-textarea variant="outlined" label="Comments" v-model="complaint.info.comments">
|
|
||||||
</v-textarea>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
</v-container>
|
|
||||||
</v-card-text>
|
|
||||||
<DebugPanel :data="complaint"></DebugPanel>
|
|
||||||
<ErrorBanner :errors="errors" />
|
|
||||||
<v-card-actions>
|
|
||||||
<v-btn v-if="!complaint.isNew" color="red-darken-1"
|
|
||||||
variant="text"
|
|
||||||
:loading="saving"
|
|
||||||
@click="saveComplaint(selected_complaint)">Save</v-btn>
|
|
||||||
<v-btn v-if="complaint.isNew" color="red-darken-1"
|
|
||||||
variant="text"
|
|
||||||
:loading="saving"
|
|
||||||
@click="saveComplaint(selected_complaint)">Add</v-btn>
|
|
||||||
<v-spacer></v-spacer>
|
|
||||||
<v-btn color="blue-darken-1"
|
|
||||||
variant="text"
|
|
||||||
@click="close">Close</v-btn>
|
|
||||||
</v-card-actions>
|
|
||||||
</v-card>
|
|
||||||
<v-dialog v-model="search[0]" scrollable>
|
|
||||||
<CustomerSearch @returnCustomer="setCustomer"></CustomerSearch>
|
|
||||||
</v-dialog>
|
|
||||||
<v-dialog v-model="search[1]">
|
|
||||||
<DriverSearch @return="setDriver"></DriverSearch>
|
|
||||||
</v-dialog>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import axios from 'axios'
|
|
||||||
import methods from '@/CommonMethods.vue'
|
|
||||||
import DatePicker from '@vuepic/vue-datepicker'
|
|
||||||
import Complaint from '@/types/ComplaintType.vue'
|
|
||||||
import CustomerSearch from '@/components/CustomerSearch.vue'
|
|
||||||
import DriverSearch from '@/components/DriverSearch.vue'
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
setcomplaint: new Complaint()
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
CustomerSearch,
|
|
||||||
DriverSearch,
|
|
||||||
DatePicker
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
setcomplaint(newval) {
|
|
||||||
this.complaint = newval
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mixins: [methods],
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
complaint: this.setcomplaint,
|
|
||||||
saving: false,
|
|
||||||
info_loading: false,
|
|
||||||
search: [],
|
|
||||||
customer_search: null,
|
|
||||||
customers_loading: false,
|
|
||||||
customers: [],
|
|
||||||
errors: [],
|
|
||||||
reasons: [],
|
|
||||||
debugPanel: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
title() {
|
|
||||||
if ( this.complaint.isNew ) {
|
|
||||||
return "New Complaint"
|
|
||||||
} else {
|
|
||||||
return "Edit Complaint"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
emits: ['closetab','complaintupdate'],
|
|
||||||
methods: {
|
|
||||||
close() {
|
|
||||||
this.$emit('closetab')
|
|
||||||
},
|
|
||||||
showCustomerSearch() {
|
|
||||||
this.search[0] = true
|
|
||||||
},
|
|
||||||
showDriverSearch() {
|
|
||||||
this.search[1] = true
|
|
||||||
},
|
|
||||||
async saveComplaint(){
|
|
||||||
this.errors = []
|
|
||||||
this.saving = true
|
|
||||||
let url = this.$api_url + "/customers/complaints/" + this.complaint.id + "/save"
|
|
||||||
if (this.complaint.isNew) {
|
|
||||||
url = this.$api_url + "/customers/complaints/add"
|
|
||||||
}
|
|
||||||
axios.post(url, {
|
|
||||||
complaint: this.complaint
|
|
||||||
}).then(resp => {
|
|
||||||
console.log("Saved Complaint : " + JSON.stringify(resp.data))
|
|
||||||
this.saving = false
|
|
||||||
let stat = resp.data
|
|
||||||
if (stat.status == true ) {
|
|
||||||
if (this.complaint.isNew) {
|
|
||||||
this.$emit('complaintupdate', resp.data)
|
|
||||||
} else {
|
|
||||||
this.$emit('complaintupdate', resp.data)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.errors.push("Complaint not saved.")
|
|
||||||
console.log("Not Saved")
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
this.saving = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
setCustomer(c){
|
|
||||||
this.complaint.customer = c
|
|
||||||
this.search[0] = false
|
|
||||||
},
|
|
||||||
setDriver(d) {
|
|
||||||
this.complaint.driver = d
|
|
||||||
this.search[1] = false
|
|
||||||
},
|
|
||||||
getComplaintInfo(){
|
|
||||||
this.info_loading = true
|
|
||||||
let url = this.$api_url + "/customers/complaints/" + this.complaint.id + "/info"
|
|
||||||
console.log("Getting Complaint Info...")
|
|
||||||
axios.get(url)
|
|
||||||
.then(resp =>{
|
|
||||||
this.complaint.info = resp.data
|
|
||||||
}).finally(() => {
|
|
||||||
this.info_loading = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
getComplaintReasons() {
|
|
||||||
let url = this.$api_url + "/customers/complaints/reasons"
|
|
||||||
axios.get(url).
|
|
||||||
then(resp => {
|
|
||||||
this.reasons = resp.data
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
if (!this.complaint.isNew) {
|
|
||||||
this.getComplaintInfo()
|
|
||||||
}
|
|
||||||
this.getComplaintReasons()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,88 +1,119 @@
|
||||||
<template>
|
<template>
|
||||||
<h3>Complaints</h3>
|
<h3>Complaints</h3>
|
||||||
<v-tabs v-model="tab" >
|
<v-tabs v-model="tab" fixed-tabs>
|
||||||
<v-tab title="List" value="isList"></v-tab>
|
<v-tab title="List" v-model="list" />
|
||||||
<v-tab title="Edit" value="edit" v-if="edit"></v-tab>
|
<v-tab title="Edit" v-model="edit" v-if="edit" />
|
||||||
<v-tab title="Report" value="report" v-if="report" ></v-tab>
|
<v-tab title="Report" v-model="report" v-if="report" />
|
||||||
</v-tabs>
|
</v-tabs>
|
||||||
<v-window v-model="tab">
|
<v-window v-model="tab">
|
||||||
<v-window-item value="isList">
|
<v-window-item v-model="list">
|
||||||
<v-col cols="12" xs="12" sm="12" md="12" lg=8>
|
<v-responsive
|
||||||
<v-text-field label="Search"
|
max-width="500"
|
||||||
variant="outlined"
|
>
|
||||||
v-model="searchQuery"
|
<v-text-field
|
||||||
density="compact"
|
clearable
|
||||||
append-inner-icon="mdi-magnify"></v-text-field>
|
label="Search"
|
||||||
<v-row justify="space-between">
|
variant="outlined"
|
||||||
<v-col cols=4>
|
v-model="searchQuery"
|
||||||
<v-btn v-if="site_info.features.addcomplaint" color="warning" prepend-icon="mdi-plus" variant="text" @click="showAddComplaint">Add</v-btn>
|
density="compact"
|
||||||
</v-col>
|
append-inner-icon="mdi-magnify"></v-text-field>
|
||||||
<v-col cols=3>
|
<v-switch color="blue" label="Show Only Active" v-model="showActive"></v-switch>
|
||||||
<v-btn align="end" variant="text" @click="showActive = !showActive">
|
<v-btn v-if="site_info.features.addcomplaint" color="warning">+ Add</v-btn>
|
||||||
Showing <span v-if="showActive">Active Only</span><span v-else>Inactive</span>
|
</v-responsive>
|
||||||
</v-btn>
|
<v-table>
|
||||||
</v-col>
|
<thead>
|
||||||
</v-row>
|
<tr>
|
||||||
<v-progress-linear indeterminate color="orange" :active="loading"></v-progress-linear>
|
<th>Comp No</th>
|
||||||
<v-card variant="outlined">
|
<th>Date</th>
|
||||||
<RecycleScroller class="scroller"
|
<th>Order</th>
|
||||||
:items="filteredComplaints"
|
<th>Acc No</th>
|
||||||
:item-size="100"
|
<th>Name</th>
|
||||||
v-slot="{ item }"
|
<th>Reason</th>
|
||||||
key-field="id">
|
<th>Active</th>
|
||||||
<v-row dense class="item" :class="{ 'bg-red-lighten-4' : item.at_risk }">
|
<th></th>
|
||||||
<v-col cols="4">
|
</tr>
|
||||||
Complaint : {{ item.id }}<br/>
|
</thead>
|
||||||
<span class="text-caption">
|
<tbody>
|
||||||
Complaint Date : {{ item.complaint_date }}<br/>
|
<tr v-if="loading">
|
||||||
Sales Order: {{ item.sop.doc_no }}<br/>
|
<td colspan=7>
|
||||||
</span>
|
<img class="loading" src="/images/icons/loading.gif"/>
|
||||||
</v-col>
|
</td>
|
||||||
<v-col cols="4" class="text-body-2">
|
</tr>
|
||||||
{{ item.customer.acc_no }} - {{ item.customer.name }}<br/>
|
<template v-for="complaint in filteredComplaints" :key="complaint.id">
|
||||||
Reason : {{ item.reason.reason }}<br/>
|
<tr :class="{ at_risk : complaint.at_risk, cust_at_risk: complaint.customer.at_risk }">
|
||||||
Driver : {{ item.driver.name }}
|
<td>{{ complaint.id }}</td>
|
||||||
</v-col>
|
<td>{{ complaint.complaint_date }}</td>
|
||||||
<v-col cols=4>
|
<td>{{ complaint.sop.doc_no }}</td>
|
||||||
<div class="d-flex justify-space-around align-center flex-column flex-sm-row fill-height">
|
<td>{{ complaint.customer.acc_no }}</td>
|
||||||
<v-row>
|
<td>{{ complaint.customer.name }}
|
||||||
<v-icon icon="mdi-exclamation" v-if="item.at_risk" color="red" title="At Risk"></v-icon>
|
</td>
|
||||||
<v-icon icon="mdi-play" v-if="item.active" title="Active"></v-icon>
|
<td>{{ complaint.reason }}</td>
|
||||||
</v-row>
|
<td>
|
||||||
<v-btn @click="showInfo(item)" color="blue-lighten-1">View</v-btn>
|
<img class="icon" v-if="complaint.active" v-bind:alt="complaint.active" v-bind:title="complaint.active" src="/images/icons/Live.png"/>
|
||||||
<v-btn v-if="site_info.features.editcomplaint" color="orange-lighten-2" @click="showEditComplaint(item)">Edit</v-btn>
|
</td>
|
||||||
</div>
|
<td>
|
||||||
</v-col>
|
<v-btn @click="showInfo(complaint)">
|
||||||
</v-row>
|
<span v-if="complaint.info_shown">
|
||||||
</RecycleScroller>
|
Hide
|
||||||
</v-card>
|
</span>
|
||||||
</v-col>
|
<span v-else>
|
||||||
</v-window-item>
|
View
|
||||||
<v-window-item value="edit">
|
</span>
|
||||||
<ComplaintEdit ref="edit" :setcomplaint="selected_complaint" @closetab="tab = 'isList'" @complaintupdate="complaintUpdated"></ComplaintEdit>
|
</v-btn>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="complaint.info_shown">
|
||||||
|
<template v-if="complaint.info">
|
||||||
|
<template v-if="complaint.info_loaded">
|
||||||
|
<td colspan=4>
|
||||||
|
{{ complaint.info.comments }}
|
||||||
|
<br />
|
||||||
|
<sub>- {{ complaint.info.added_by }}</sub>
|
||||||
|
</td>
|
||||||
|
<td colspan=2>
|
||||||
|
<v-container>
|
||||||
|
<v-form :disabled="complaint.info.loading">
|
||||||
|
<v-row dense nogutters>
|
||||||
|
<v-checkbox label="1" type="checkbox" v-model="complaint.info.one" @change="changeComplaintCheckbox(complaint)" />
|
||||||
|
<v-checkbox label="2" v-model="complaint.info.two" @change="changeComplaintCheckbox(complaint)"/>
|
||||||
|
<v-checkbox label="3" v-model="complaint.info.three" @change="changeComplaintCheckbox(complaint)"/>
|
||||||
|
</v-row>
|
||||||
|
<v-row dense nogutters>
|
||||||
|
<v-checkbox label="At Risk" v-model="complaint.at_risk" @change="changeComplaintCheckbox(complaint)" />
|
||||||
|
<v-checkbox label="Permanent" v-model="complaint.info.permanent" @change="changeComplaintCheckbox(complaint)" />
|
||||||
|
</v-row>
|
||||||
|
</v-form>
|
||||||
|
</v-container>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<img v-if="complaint.info.loading" class="loading" src="/images/icons/loading.gif"/>
|
||||||
|
<template v-else>
|
||||||
|
<v-btn v-if="site_info.features.editcomplaint" color="warning">Edit</v-btn>
|
||||||
|
</template>
|
||||||
|
</td>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<td colspan=6>
|
||||||
|
<img class="loading" src="/images/icons/loading.gif"/>
|
||||||
|
</td>
|
||||||
|
</template>
|
||||||
|
</tr>
|
||||||
|
</template>
|
||||||
|
</tbody>
|
||||||
|
</v-table>
|
||||||
</v-window-item>
|
</v-window-item>
|
||||||
</v-window>
|
</v-window>
|
||||||
<v-dialog v-model="showComplaintInfo">
|
|
||||||
<ComplaintInfo :in_complaint="selected_complaint" @return="doInfoReturn" />
|
|
||||||
</v-dialog>
|
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import Complaint from '@/types/ComplaintType.vue'
|
|
||||||
import ComplaintInfo from '@/components/ComplaintInfo.vue'
|
|
||||||
import ComplaintEdit from '@/views/complaints/ComplaintEdit.vue'
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
site_info:{},
|
site_info:{},
|
||||||
user_info:{}
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
ComplaintInfo,
|
|
||||||
ComplaintEdit
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
tab: "isList",
|
tab: "list",
|
||||||
list: [],
|
list: [],
|
||||||
listreceived: false,
|
listreceived: false,
|
||||||
showActive: true,
|
showActive: true,
|
||||||
|
@ -90,9 +121,7 @@ export default {
|
||||||
limit: 300,
|
limit: 300,
|
||||||
searchQuery: "",
|
searchQuery: "",
|
||||||
edit: false,
|
edit: false,
|
||||||
report: false,
|
report: false
|
||||||
showComplaintInfo: false,
|
|
||||||
selected_complaint: {}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -105,7 +134,7 @@ export default {
|
||||||
q.customer.name.toLowerCase().includes(query) ||
|
q.customer.name.toLowerCase().includes(query) ||
|
||||||
q.customer.acc_no.includes(query) ||
|
q.customer.acc_no.includes(query) ||
|
||||||
q.id == query ||
|
q.id == query ||
|
||||||
q.reason.reason.toLowerCase().includes(query)
|
q.reason.toLowerCase().includes(query)
|
||||||
)
|
)
|
||||||
if (this.showActive) {
|
if (this.showActive) {
|
||||||
clist = clist.filter(q =>
|
clist = clist.filter(q =>
|
||||||
|
@ -116,65 +145,64 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getComplaintsList(){
|
async getComplaintsList(){
|
||||||
this.loading = true
|
this.loading = true
|
||||||
let url = this.$api_url + "/customers/complaints/list"
|
let url = this.$api_url + "/customers/complaints/list"
|
||||||
let c_id = this.$route.params.id || ""
|
console.log("Getting Complaint list...")
|
||||||
console.log("Getting Contracts list..." + c_id)
|
|
||||||
axios.get(url,{
|
axios.get(url,{
|
||||||
params: {
|
params: {
|
||||||
limit: this.limit,
|
limit: this.limit,
|
||||||
query: this.searchQuery,
|
query: this.searchQuery
|
||||||
c_id: c_id
|
|
||||||
}
|
}
|
||||||
}).then(resp => {
|
}).then(resp => {
|
||||||
this.list = resp.data
|
this.list = resp.data
|
||||||
this.listreceived = true
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
}).finally(() => {
|
|
||||||
this.loading = false
|
this.loading = false
|
||||||
|
this.listreceived = true
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
showInfo(complaint) {
|
async getComplaintInfo(complaint) {
|
||||||
this.showComplaintInfo = true
|
complaint.info.loading = true
|
||||||
this.selected_complaint = complaint
|
let url = this.$api_url + "/customers/complaints/" + complaint.id + "/info"
|
||||||
|
console.log("Getting Complaint Info...")
|
||||||
|
axios.get(url)
|
||||||
|
.then(resp =>{
|
||||||
|
complaint.info = resp.data
|
||||||
|
complaint.info.loading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async showInfo(complaint) {
|
||||||
|
console.log(complaint.id)
|
||||||
complaint.info_loaded = false
|
complaint.info_loaded = false
|
||||||
|
complaint.info_shown = !complaint.info_shown
|
||||||
|
if (complaint.info_shown) {
|
||||||
|
complaint.info = await this.getComplaintInfo(complaint)
|
||||||
|
complaint.info_loaded = true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
doInfoReturn(code) {
|
async changeComplaintCheckbox(complaint) {
|
||||||
console.log(code)
|
let set = await this.setComplaintStatus(complaint)
|
||||||
|
if (complaint.at_risk && set && complaint.info.one && complaint.info.two && complaint.info.three) {
|
||||||
|
console.log("Contract no longer at risk")
|
||||||
|
complaint.at_risk = false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
showAddComplaint() {
|
async setComplaintStatus(complaint) {
|
||||||
this.selected_complaint = new Complaint()
|
complaint.info.loading = true
|
||||||
this.selected_complaint.isNew = true
|
let url = this.$api_url + "/customers/complaints/" + complaint.id + "/info/set"
|
||||||
this.edit = true
|
console.log("Getting Complaint Info...")
|
||||||
this.tab = "edit"
|
axios.post(url, {
|
||||||
|
one: complaint.info.one,
|
||||||
|
two: complaint.info.two,
|
||||||
|
three: complaint.info.three,
|
||||||
|
at_risk: complaint.at_risk,
|
||||||
|
permanent: complaint.info.permanent
|
||||||
|
}).then(resp => {
|
||||||
|
console.log(resp.data)
|
||||||
|
this.getComplaintInfo(complaint)
|
||||||
|
complaint.info_loaded = true
|
||||||
|
})
|
||||||
|
return true
|
||||||
},
|
},
|
||||||
showEditComplaint(cmp) {
|
|
||||||
this.selected_complaint = cmp
|
|
||||||
this.selected_complaint.isNew = false
|
|
||||||
this.edit = true
|
|
||||||
this.tab = "edit"
|
|
||||||
},
|
|
||||||
complaintUpdated(cmp) {
|
|
||||||
console.log(cmp)
|
|
||||||
this.tab = "isList"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
|
||||||
.scroller {
|
|
||||||
height:600px;
|
|
||||||
}
|
|
||||||
.item {
|
|
||||||
height: 100px;
|
|
||||||
overflow-y:hidden;
|
|
||||||
padding: 0 1em;
|
|
||||||
margin-bottom:2px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
border-bottom: 1px solid #000;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
<template>
|
<template>
|
||||||
<v-card :title="title" :subtitle="'Contract : ' + contract.no">
|
<v-card title="Edit Contract" :subtitle="'Contract : ' + contract.no">
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-container>
|
<v-container>
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="6">
|
<v-col cols="6">
|
||||||
<v-text-field readonly variant="outlined" prepend-inner-icon="mdi-magnify" @click="showCustomerSearch" label="Customer" :model-value="contract.customer.acc_no + ' - ' + contract.customer.name">
|
<v-text-field label="Customer" v-model="contract.customer.name" readonly></v-text-field>
|
||||||
</v-text-field>
|
<v-text-field type="number" label="Tonnage Per Month" v-model="contract.tonnage_per_month"></v-text-field>
|
||||||
<v-text-field type="number" variant="outlined" label="Tonnage Per Month" v-model="contract.tonnage_per_month"></v-text-field>
|
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="6">
|
<v-col cols="6">
|
||||||
<label>
|
<label>
|
||||||
Start Date
|
Start Date
|
||||||
<DatePicker v-model="contract.start_date" format="dd/MM/yyyy" />
|
<DatePicker v-model="contract.start_date" format="dd/MM/yyyy" />
|
||||||
</label><br />
|
</label><br />
|
||||||
<label>
|
<label>
|
||||||
Finish Date
|
Finish Date
|
||||||
|
@ -19,36 +18,33 @@
|
||||||
</label><br />
|
</label><br />
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
<v-table density="compact">
|
<template v-for="p in contract.products" :key="p.code">
|
||||||
<thead>
|
<v-row>
|
||||||
<tr>
|
<v-col cols="6">
|
||||||
<th style="width:65%;">
|
<v-autocomplete v-model="p.code"
|
||||||
Product
|
v-model:search="product_search"
|
||||||
</th>
|
:loading="products_loading"
|
||||||
<th style="width:20%">
|
:items="products"
|
||||||
Price
|
cache-items
|
||||||
</th>
|
hide-no-data
|
||||||
<th>
|
hide-details
|
||||||
</th>
|
solo-inverted
|
||||||
</tr>
|
label="Code"
|
||||||
</thead>
|
no-data-text="No Products Found"
|
||||||
<tbody>
|
item-title="code"
|
||||||
<tr v-for="(p, index) in contract.products" :key="index">
|
item-value="code" ></v-autocomplete>
|
||||||
<td>
|
</v-col>
|
||||||
<v-text-field readonly variant="outlined" prepend-inner-icon="mdi-magnify" @click="showProductSearch(index)" :model-value="p.code + ' - ' + p.name"></v-text-field>
|
<v-col cols="4">
|
||||||
</td>
|
<v-text-field type="number" label="Price" v-model="p.price"></v-text-field>
|
||||||
<td>
|
</v-col>
|
||||||
<v-text-field prepend-icon="mdi-currency-gbp" type="number" density="compact" variant="outlined" v-model="p.price"></v-text-field>
|
<v-col cols="2">
|
||||||
</td>
|
<v-btn size="small" color="error" title="Remove" variant="plain" icon @click="contract.products.pop()"><v-icon>mdi-minus</v-icon></v-btn>
|
||||||
<td>
|
</v-col>
|
||||||
<v-btn size="small" color="error" title="Remove" variant="plain" @click="removeProduct(p.code)" icon="mdi-minus"></v-btn>
|
</v-row>
|
||||||
</td>
|
</template>
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</v-table>
|
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="4">
|
<v-col cols="4">
|
||||||
<v-btn @click="addProduct()" v-if="contract.products.length < 4">+ Add Product</v-btn>
|
<v-btn @click="contract.products.push({})" v-if="contract.products.length < 4">+ Add Product</v-btn>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
<v-row>
|
<v-row>
|
||||||
|
@ -59,145 +55,107 @@
|
||||||
</label>
|
</label>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
<v-textarea rows=3 label="Comments" variant="outlined" v-model="contract.comments"></v-textarea>
|
<v-textarea rows=3 label="Comments" v-model="contract.comments"></v-textarea>
|
||||||
<v-textarea rows=3 label="Office Comments" variant="outlined" v-model="contract.office_comments"></v-textarea>
|
<v-textarea rows=3 label="Office Comments" v-model="contract.office_comments"></v-textarea>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-container>
|
</v-container>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<DebugPanel :data="contract"></DebugPanel>
|
|
||||||
<ErrorBanner :errors="errors" />
|
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-btn v-if="!contract.isNew" color="red-darken-1"
|
<v-btn color="red-darken-1"
|
||||||
variant="text"
|
variant="text"
|
||||||
:loading="saving"
|
@click="saveContract(selected_contract)">Save</v-btn>
|
||||||
@click="saveContract(selected_contract)">Save</v-btn>
|
|
||||||
<v-btn v-if="contract.isNew" color="red-darken-1"
|
|
||||||
variant="text"
|
|
||||||
:loading="saving"
|
|
||||||
@click="saveContract(selected_contract)">Add</v-btn>
|
|
||||||
<v-spacer></v-spacer>
|
<v-spacer></v-spacer>
|
||||||
<v-btn color="blue-darken-1"
|
<v-btn color="blue-darken-1"
|
||||||
variant="text"
|
variant="text"
|
||||||
@click="close">Close</v-btn>
|
@click="close">Close</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
<v-dialog v-model="search[0]" scrollable>
|
|
||||||
<CustomerSearch @returnCustomer="setCustomer"></CustomerSearch>
|
|
||||||
</v-dialog>
|
|
||||||
<v-dialog v-model="search[1]">
|
|
||||||
<ProductSearch @returnProduct="setProduct"></ProductSearch>
|
|
||||||
</v-dialog>
|
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import DatePicker from '@vuepic/vue-datepicker'
|
import DatePicker from '@vuepic/vue-datepicker'
|
||||||
import ErrorBanner from '@/components/ErrorBanner.vue'
|
|
||||||
import methods from '@/CommonMethods.vue'
|
|
||||||
import Product from '@/types/ProductType.vue'
|
|
||||||
import ProductSearch from '@/components/ProductSearch.vue'
|
|
||||||
import CustomerSearch from '@/components/CustomerSearch.vue'
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
setcontract: {}
|
setcontract: {
|
||||||
|
no: Number,
|
||||||
|
customer: {
|
||||||
|
acc_no: String,
|
||||||
|
name: String,
|
||||||
|
at_risk: Boolean,
|
||||||
|
},
|
||||||
|
products: [{
|
||||||
|
code: String,
|
||||||
|
name: String,
|
||||||
|
price: Number,
|
||||||
|
}],
|
||||||
|
start_date: String,
|
||||||
|
finish_date: String,
|
||||||
|
agree_date: String,
|
||||||
|
tonnage_per_month: Number,
|
||||||
|
comments: String,
|
||||||
|
office_comments: String,
|
||||||
|
active: Boolean
|
||||||
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
DatePicker,
|
DatePicker
|
||||||
ErrorBanner,
|
|
||||||
ProductSearch,
|
|
||||||
CustomerSearch
|
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
setcontract(newval) {
|
setcontract(newval) {
|
||||||
this.contract = newval
|
this.contract = newval
|
||||||
},
|
},
|
||||||
|
product_search(val) {
|
||||||
|
if (val && val.length > 1) {
|
||||||
|
this.searchProducts(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
mixins: [methods],
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
contract: this.setcontract,
|
contract: this.setcontract,
|
||||||
dialog: this.opendialog,
|
dialog: this.opendialog,
|
||||||
saving: false,
|
saving: false,
|
||||||
search: [],
|
|
||||||
searchProdIndex: null,
|
|
||||||
product_search: null,
|
product_search: null,
|
||||||
products_loading: false,
|
products_loading: false,
|
||||||
products: [],
|
products: [],
|
||||||
customer_search: null,
|
|
||||||
customers_loading: false,
|
|
||||||
customers: [],
|
|
||||||
errors: []
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
title() {
|
|
||||||
if ( this.contract.isNew ) {
|
|
||||||
return "New Contract"
|
|
||||||
} else {
|
|
||||||
return "Edit Contract"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
emits: ['closetab','contractupdate'],
|
|
||||||
methods: {
|
methods: {
|
||||||
close() {
|
close() {
|
||||||
this.$emit('closetab','list')
|
this.$emit('closetab','list')
|
||||||
},
|
},
|
||||||
addProduct() {
|
|
||||||
this.contract.products.push(new Product())
|
|
||||||
},
|
|
||||||
removeProduct(code){
|
|
||||||
this.contract.products = this.contract.products.filter((c) => {
|
|
||||||
return c.code !== code
|
|
||||||
})
|
|
||||||
},
|
|
||||||
showCustomerSearch() {
|
|
||||||
this.search[0] = true
|
|
||||||
},
|
|
||||||
showProductSearch(num) {
|
|
||||||
this.search[1] = true
|
|
||||||
this.searchProdIndex = num
|
|
||||||
},
|
|
||||||
async saveContract(){
|
async saveContract(){
|
||||||
this.errors = []
|
|
||||||
this.saving = true
|
this.saving = true
|
||||||
let url = this.$api_url + "/customers/contracts/" + this.contract.no + "/save"
|
let url = this.$api_url + "/customers/contracts/" + this.contract.no + "/save"
|
||||||
if (this.contract.isNew) {
|
console.log("Saving Contract : ", this.contract.no)
|
||||||
url = this.$api_url + "/customers/contracts/add"
|
console.log(this.contract)
|
||||||
}
|
|
||||||
axios.post(url, {
|
axios.post(url, {
|
||||||
contract: this.contract
|
contract: this.contract
|
||||||
}).then(resp => {
|
}).then(resp => {
|
||||||
console.log("Saved Contract : " + JSON.stringify(resp.data))
|
console.log("Saved Contract : " + JSON.stringify(resp.data))
|
||||||
this.saving = false
|
this.saving = false
|
||||||
let stat = resp.data
|
this.$emit('contractupdate', resp.data)
|
||||||
if (stat.status == true ) {
|
|
||||||
if (this.contract.isNew) {
|
|
||||||
this.$emit('contractupdate', resp.data)
|
|
||||||
} else {
|
|
||||||
this.$emit('contractupdate', resp.data)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.errors.push("Contract not saved.")
|
|
||||||
console.log("Not Saved")
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
this.saving = false
|
this.saving = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
searchProducts(code) {
|
||||||
|
let url = this.$api_url + "/products/search/" + code
|
||||||
|
console.log(url)
|
||||||
|
axios.get(url)
|
||||||
|
.then(resp => {
|
||||||
|
console.log(resp)
|
||||||
|
this.products = resp.data
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.log(err)
|
||||||
|
this.products = [{code:"NoProductsFound", name:"No Products Found"}]
|
||||||
|
})
|
||||||
|
},
|
||||||
productCodeName(p) {
|
productCodeName(p) {
|
||||||
return p.code + ' - ' + p.name
|
return p.code + ' - ' + p.name
|
||||||
},
|
|
||||||
setProduct(p){
|
|
||||||
let q = this.contract.products[this.searchProdIndex]
|
|
||||||
p.price = q.price
|
|
||||||
this.contract.products[this.searchProdIndex] = p
|
|
||||||
this.search[1] = false
|
|
||||||
},
|
|
||||||
setCustomer(c){
|
|
||||||
this.contract.customer = c
|
|
||||||
this.search[0] = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,114 +7,114 @@
|
||||||
</v-tabs>
|
</v-tabs>
|
||||||
<v-window v-model="tab" >
|
<v-window v-model="tab" >
|
||||||
<v-window-item value="list">
|
<v-window-item value="list">
|
||||||
<v-row>
|
<v-responsive
|
||||||
<v-col cols="8" xs="12" sm="12" md="12" lg="8">
|
max-width="500"
|
||||||
|
>
|
||||||
<v-text-field clearable
|
<v-text-field clearable
|
||||||
label="Search"
|
label="Search"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
v-model="searchQuery"
|
v-model="searchQuery"
|
||||||
density="compact"
|
density="compact"
|
||||||
append-inner-icon="mdi-magnify"></v-text-field>
|
append-inner-icon="mdi-magnify"></v-text-field>
|
||||||
<v-btn color="warning"
|
</v-responsive>
|
||||||
v-if="site_info.features.addcontract"
|
<v-dialog v-model="showDialog">
|
||||||
@click="showEditContract()"
|
</v-dialog>
|
||||||
prepend-icon="mdi-plus"
|
<v-row>
|
||||||
variant="text"
|
<v-col cols="8" xs="12" sm="12" md="8">
|
||||||
>Add</v-btn>
|
<v-progress-linear indeterminate color="blue" :active="loading"></v-progress-linear>
|
||||||
<v-progress-linear indeterminate color="blue" :active="loading"></v-progress-linear>
|
<RecycleScroller class="scroller"
|
||||||
<v-card variant="outlined">
|
:items="filteredContracts"
|
||||||
<RecycleScroller class="scroller"
|
:item-size="130"
|
||||||
:items="filteredContracts"
|
v-slot="{ item }"
|
||||||
:item-size="130"
|
key-field="no"
|
||||||
v-slot="{ item }"
|
>
|
||||||
key-field="no"
|
<v-row :class="[{inactive : !item.active}]" class="item">
|
||||||
>
|
<v-col cols="4" >
|
||||||
<v-row :class="[{inactive : !item.active}]" class="item">
|
<h3>Contract : {{ item.no }}</h3>
|
||||||
<v-col cols="4" >
|
{{ item.customer.acc_no }} - {{ item.customer.name }}
|
||||||
<h3>Contract : {{ item.no }}</h3>
|
<v-switch v-model="item.active" color="green" @change="setContractInactive(item)" label="Active"></v-switch>
|
||||||
{{ item.customer.acc_no }} - {{ item.customer.name }}
|
</v-col>
|
||||||
<v-switch v-model="item.active" color="green" @change="setContractInactive(item)" label="Active"></v-switch>
|
<v-col >
|
||||||
</v-col>
|
<template v-for="p in item.products" :key="p.code">
|
||||||
<v-col >
|
<span v-if="p.code != ''">
|
||||||
<template v-for="p in item.products" :key="p.code">
|
{{ p.code }} @ {{ p.price }}<br/>
|
||||||
<span v-if="p.code != ''">
|
</span>
|
||||||
{{ p.code }} @ {{ p.price }}<br/>
|
</template>
|
||||||
</span>
|
</v-col>
|
||||||
</template>
|
<v-col >
|
||||||
</v-col>
|
<v-icon title="Start">mdi-play</v-icon>: {{ formatDate(item.start_date,"DD/MM/YYYY") }}<br/>
|
||||||
<v-col >
|
<v-icon title="Finish">mdi-flag-checkered</v-icon>: {{ formatDate(item.finish_date,"DD/MM/YYYY") }}<br/>
|
||||||
<v-icon title="Start">mdi-play</v-icon>: {{ formatDate(item.start_date,"DD/MM/YYYY") }}<br/>
|
<v-icon title="Duration">mdi-clock</v-icon>: {{ item.duration }} months
|
||||||
<v-icon title="Finish">mdi-flag-checkered</v-icon>: {{ formatDate(item.finish_date,"DD/MM/YYYY") }}<br/>
|
</v-col>
|
||||||
<v-icon title="Duration">mdi-clock</v-icon>: {{ item.duration }} months
|
<v-col>
|
||||||
</v-col>
|
{{ item.tonnage_per_month }} per month<br/>
|
||||||
<v-col>
|
= {{ formatNumber(item.tonnage_per_month * item.duration,2) }} total<br/>
|
||||||
{{ item.tonnage_per_month }} per month<br/>
|
= {{ formatNumber(item.tonnage_per_month * item.remaining_duration,2) }} remaining<br/>
|
||||||
= {{ formatNumber(item.tonnage_per_month * item.duration,2) }} total<br/>
|
</v-col>
|
||||||
= {{ formatNumber(item.tonnage_per_month * item.remaining_duration,2) }} remaining<br/>
|
<v-col>
|
||||||
</v-col>
|
<v-row>
|
||||||
<v-col>
|
<v-col cols="12">
|
||||||
<div class="d-flex justify-space-around align-center flex-column flex-sm-row fill-height">
|
<v-btn color="info">
|
||||||
<v-btn color="info">
|
More
|
||||||
More
|
<v-overlay activator="parent" class="align-center justify-center">
|
||||||
<v-overlay activator="parent" class="align-center justify-center">
|
<v-card title="Info" width="600">
|
||||||
<v-card title="Info" width="600">
|
<v-card-subtitle>Comments</v-card-subtitle>
|
||||||
<v-card-subtitle>Comments</v-card-subtitle>
|
<v-card-text>{{ item.comments}} </v-card-text>
|
||||||
<v-card-text>{{ item.comments}} </v-card-text>
|
<v-card-subtitle>Office</v-card-subtitle>
|
||||||
<v-card-subtitle>Office</v-card-subtitle>
|
<v-card-text>{{ item.office_comments}}</v-card-text>
|
||||||
<v-card-text>{{ item.office_comments}}</v-card-text>
|
<v-card-subtitle>Agreed</v-card-subtitle>
|
||||||
<v-card-subtitle>Agreed</v-card-subtitle>
|
<v-card-text>{{ formatDate(item.agree_date,"DD/MM/YYYY") }}</v-card-text>
|
||||||
<v-card-text>{{ formatDate(item.agree_date,"DD/MM/YYYY") }}</v-card-text>
|
<v-card-subtitle>Products</v-card-subtitle>
|
||||||
<v-card-subtitle>Products</v-card-subtitle>
|
<v-card-text>
|
||||||
<v-card-text>
|
<template v-for="p in item.products" :key="p.code">
|
||||||
<template v-for="p in item.products" :key="p.code">
|
<span v-if="p.code != ''">
|
||||||
<span v-if="p.code != ''">
|
{{ p.code }} - {{ p.name }} @ {{ p.price }}<br/>
|
||||||
{{ p.code }} - {{ p.name }} @ {{ p.price }}<br/>
|
</span>
|
||||||
</span>
|
</template>
|
||||||
</template>
|
</v-card-text>
|
||||||
</v-card-text>
|
<v-card-actions>
|
||||||
<v-card-actions>
|
<v-btn color="info"
|
||||||
|
target="blank"
|
||||||
|
@click="getContractPrint(item.no)"
|
||||||
|
class="ma-2 pa-2"
|
||||||
|
:loading="item.multiloading"
|
||||||
|
>
|
||||||
|
Multi
|
||||||
|
</v-btn>
|
||||||
|
|
||||||
<v-btn color="info"
|
<v-btn color="info"
|
||||||
target="blank"
|
target="blank"
|
||||||
@click="getContractPrint(item.no)"
|
@click="getContractPrint(item.no,true)"
|
||||||
|
:loading="item.totalloading"
|
||||||
class="ma-2 pa-2"
|
class="ma-2 pa-2"
|
||||||
:loading="multiloading"
|
|
||||||
>
|
>
|
||||||
Multi
|
Total
|
||||||
</v-btn>
|
</v-btn>
|
||||||
|
<v-btn color="warning"
|
||||||
<v-btn color="info"
|
v-if="site_info.features.editcontract"
|
||||||
target="blank"
|
@click="showEditContract(item)"
|
||||||
@click="getContractPrint(item.no,true)"
|
|
||||||
:loading="totalloading"
|
|
||||||
class="ma-2 pa-2"
|
|
||||||
>
|
>
|
||||||
Total
|
Edit
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn color="warning"
|
</v-card-actions>
|
||||||
v-if="site_info.features.editcontract"
|
</v-card>
|
||||||
@click="showEditContract(item)"
|
</v-overlay>
|
||||||
:loading="editloading"
|
</v-btn>
|
||||||
>
|
</v-col>
|
||||||
Edit
|
<v-col cols="12">
|
||||||
</v-btn>
|
<v-btn color="warning"
|
||||||
</v-card-actions>
|
v-if="site_info.features.editcontract"
|
||||||
</v-card>
|
@click="showEditContract(item)"
|
||||||
</v-overlay>
|
>
|
||||||
</v-btn>
|
Edit
|
||||||
<v-btn color="warning"
|
</v-btn>
|
||||||
v-if="site_info.features.editcontract"
|
|
||||||
@click="showEditContract(item)"
|
|
||||||
:loading="editloading"
|
|
||||||
>
|
|
||||||
Edit
|
|
||||||
</v-btn>
|
|
||||||
</div>
|
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</RecycleScroller>
|
</v-col>
|
||||||
</v-card>
|
</v-row>
|
||||||
</v-col>
|
</RecycleScroller>
|
||||||
</v-row>
|
</v-col>
|
||||||
|
</v-row>
|
||||||
</v-window-item>
|
</v-window-item>
|
||||||
<v-window-item value="edit">
|
<v-window-item value="edit">
|
||||||
<ContractEdit ref="edit" :setcontract="selected_contract" @closetab="tab = 'list'" @contractupdate="contractUpdated"/>
|
<ContractEdit ref="edit" :setcontract="selected_contract" @closetab="tab = 'list'" @contractupdate="contractUpdated"/>
|
||||||
|
@ -123,14 +123,11 @@
|
||||||
<ContractMulti :contract="selected_contract" :total="total" />
|
<ContractMulti :contract="selected_contract" :total="total" />
|
||||||
</v-window-item>
|
</v-window-item>
|
||||||
</v-window>
|
</v-window>
|
||||||
<v-dialog v-model="showDialog">
|
|
||||||
</v-dialog>
|
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import ContractEdit from './ContractEdit.vue';
|
import ContractEdit from './ContractEdit.vue';
|
||||||
import ContractMulti from './ContractMulti.vue';
|
import ContractMulti from './ContractMulti.vue';
|
||||||
import methods from '@/CommonMethods.vue'
|
import methods from '@/CommonMethods.vue'
|
||||||
import ContractType from '@/types/ContractType.vue';
|
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
|
@ -182,37 +179,25 @@ export default {
|
||||||
edit: false,
|
edit: false,
|
||||||
report: false,
|
report: false,
|
||||||
total: false,
|
total: false,
|
||||||
content: "",
|
content: ""
|
||||||
editloading: false,
|
|
||||||
multiloading: false,
|
|
||||||
totalloading: false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mixins: [methods],
|
mixins: [methods],
|
||||||
methods: {
|
methods: {
|
||||||
async showEditContract(contract) {
|
async showEditContract(contract) {
|
||||||
this.editloading = true
|
this.selected_contract = contract
|
||||||
setTimeout(() => {
|
//this.selected_contract = contract
|
||||||
if ( contract != undefined ) {
|
this.tab = "edit"
|
||||||
this.selected_contract = contract
|
this.edit = true
|
||||||
} else {
|
|
||||||
this.selected_contract = new ContractType()
|
|
||||||
}
|
|
||||||
this.tab = "edit"
|
|
||||||
this.edit = true
|
|
||||||
this.editloading = false
|
|
||||||
},1000)
|
|
||||||
},
|
},
|
||||||
async getContractsList() {
|
async getContractsList() {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
let url = this.$api_url + "/customers/contracts/list"
|
let url = this.$api_url + "/customers/contracts/list"
|
||||||
let c_id = this.$route.params.id || ""
|
console.log("Getting Contracts list...")
|
||||||
console.log("Getting Contracts list..." + c_id)
|
|
||||||
axios.get(url, {
|
axios.get(url, {
|
||||||
params: {
|
params: {
|
||||||
limit: this.limit,
|
limit: this.limit,
|
||||||
query: this.searchQuery,
|
query: this.searchQuery
|
||||||
c_id: c_id
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(resp => {
|
.then(resp => {
|
||||||
|
@ -222,16 +207,12 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
getContractPrint(contract, total = false) {
|
getContractPrint(contract, total = false) {
|
||||||
if (total){ this.totalloading = true } else { this.multiloading = true }
|
|
||||||
axios.get(this.$api_url + "/customers/contracts/" + contract + "/info")
|
axios.get(this.$api_url + "/customers/contracts/" + contract + "/info")
|
||||||
.then(resp => {
|
.then(resp => {
|
||||||
this.selected_contract = resp.data
|
this.selected_contract = resp.data
|
||||||
this.total = total
|
this.total = total
|
||||||
this.tab = "report"
|
this.tab = "report"
|
||||||
this.report = true
|
this.report = true
|
||||||
}).finally(() => {
|
|
||||||
this.totalloading = false
|
|
||||||
this.multiloading = false
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
findContract(id) {
|
findContract(id) {
|
||||||
|
@ -268,7 +249,7 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.scroller {
|
.scroller {
|
||||||
height: 70vw;
|
height: 600px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<ReportLayout scope="contract" :filename="filename">
|
<ReportLayout scope="contract">
|
||||||
<div class="letter">
|
<div class="letter">
|
||||||
<p><span class="text-bold">Date: </span>{{ current_date }}</p>
|
<p><span class="text-bold">Date: </span>{{ current_date }}</p>
|
||||||
<p class="text-bold">Customer's Address:</p>
|
<p class="text-bold">Customer's Address:</p>
|
||||||
|
@ -57,6 +57,7 @@
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
import '@/assets/css/reports.css';
|
||||||
import ReportLayout from '@/components/ReportLayout.vue'
|
import ReportLayout from '@/components/ReportLayout.vue'
|
||||||
import Common from '@/common.js';
|
import Common from '@/common.js';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
@ -71,7 +72,6 @@ export default {
|
||||||
},
|
},
|
||||||
data(){
|
data(){
|
||||||
return {
|
return {
|
||||||
filename: "Contract_" + this.contract.no,
|
|
||||||
current_date: Common.getDateNow(),
|
current_date: Common.getDateNow(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,76 +1,33 @@
|
||||||
<template>
|
<template>
|
||||||
<v-text-field
|
<h3>Customer List</h3>
|
||||||
label="Search"
|
<v-responsive
|
||||||
variant="outlined"
|
max-width="500"
|
||||||
v-model="searchQuery"
|
>
|
||||||
density="compact"
|
<v-text-field
|
||||||
append-inner-icon="mdi-magnify"></v-text-field>
|
clearable
|
||||||
<v-row>
|
label="Search"
|
||||||
<v-col cols="12" sm=12 lg=6>
|
variant="outlined"
|
||||||
<v-card>
|
v-model="searchQuery"
|
||||||
<v-card-title>
|
density="compact"
|
||||||
Customer List
|
append-inner-icon="mdi-magnify"></v-text-field>
|
||||||
</v-card-title>
|
</v-responsive>
|
||||||
<v-progress-linear color="blue" :active="customers_loading" indeterminate>
|
<RecycleScroller
|
||||||
</v-progress-linear>
|
class="scroller"
|
||||||
<v-list>
|
:items="filteredCustomers"
|
||||||
<RecycleScroller
|
:item-size="50"
|
||||||
class="scroller"
|
key-field="acc_no"
|
||||||
:items="filteredCustomers"
|
v-slot="{ item }"
|
||||||
:item-size="60"
|
>
|
||||||
key-field="acc_no"
|
<v-row class="customer">
|
||||||
v-slot="{ item }"
|
<v-col cols="6">
|
||||||
>
|
{{ item.acc_no }} - {{ item.name }}
|
||||||
<v-list-item >
|
</v-col>
|
||||||
<v-sheet class="clickable" @click="getCustomerInfo(item)" rounded :class="{ 'bg-error' : item.at_risk }">
|
</v-row>
|
||||||
<v-icon v-if="item.acc_no == selected_cust.acc_no">mdi-checkbox-marked-outline</v-icon>
|
<hr />
|
||||||
<v-icon v-else>mdi-checkbox-blank-outline</v-icon>
|
</RecycleScroller>
|
||||||
{{ item.acc_no }} - {{ item.name }}:
|
|
||||||
<span class="text-caption">{{ item.address.line_1 }}, {{ item.address.line_2 }}, <br/>
|
|
||||||
{{ item.address.city }}, {{ item.address.county}}, {{ item.address.postcode }},
|
|
||||||
</span>
|
|
||||||
</v-sheet>
|
|
||||||
<template v-slot:append>
|
|
||||||
<v-btn-toggle>
|
|
||||||
<v-btn @click.prevent="viewOrders(item)" color="blue-lighten-1" title="View Orders">
|
|
||||||
<v-icon>mdi-cart-outline</v-icon>
|
|
||||||
</v-btn>
|
|
||||||
<v-btn @click.prevent="goToContracts(item)" color="blue-lighten-1" title="View Contracts">
|
|
||||||
<v-icon>mdi-file-edit-outline</v-icon>
|
|
||||||
<v-badge v-if="item.contract_count > 0" color="blue-lighten-4" floating :content="item.contract_count">
|
|
||||||
</v-badge>
|
|
||||||
</v-btn>
|
|
||||||
<v-btn @click.prevent="goToMedFeeds(item)" color="orange-lighten-1" title="View Med Feeds">
|
|
||||||
<v-icon>mdi-pill</v-icon>
|
|
||||||
<v-badge v-if="item.medfeed_count > 0" color="orange-lighten-4" floating :content="item.medfeed_count">
|
|
||||||
</v-badge>
|
|
||||||
</v-btn>
|
|
||||||
<v-btn @click.prevent="goToComplaints(item)" color="orange-lighten-1" title="View Complaints">
|
|
||||||
<v-icon>mdi-exclamation-thick</v-icon>
|
|
||||||
<v-badge v-if="item.complaint_count > 0" color="red-lighten-4" floating :content="item.complaint_count">
|
|
||||||
</v-badge>
|
|
||||||
</v-btn>
|
|
||||||
</v-btn-toggle>
|
|
||||||
</template>
|
|
||||||
</v-list-item>
|
|
||||||
</RecycleScroller>
|
|
||||||
</v-list>
|
|
||||||
</v-card>
|
|
||||||
<br/>
|
|
||||||
<RecentOrders :customer="selected_cust" size_small doc_status=0></RecentOrders>
|
|
||||||
</v-col>
|
|
||||||
<v-col cols="12" sm=12 lg=6>
|
|
||||||
<CustomerComments :customer="selected_cust"></CustomerComments>
|
|
||||||
<br/>
|
|
||||||
<RecentOrders :customer="selected_cust" doc_status=2></RecentOrders>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import RecentOrders from '@/components/RecentOrders.vue'
|
|
||||||
import CustomerComments from '@/components/CustomerComments.vue'
|
|
||||||
import Customer from '@/types/CustomerType.vue'
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
site_info: {},
|
site_info: {},
|
||||||
|
@ -79,16 +36,15 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
searchQuery: "",
|
searchQuery: "",
|
||||||
customer_list: [],
|
showSearch: true,
|
||||||
customers_loading: null,
|
open: false,
|
||||||
selected_cust: new Customer(),
|
list: [],
|
||||||
limit: 5000,
|
limit: 5000,
|
||||||
listreceived: false,
|
loading: true,
|
||||||
|
listreceived: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
RecentOrders,
|
|
||||||
CustomerComments
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
filteredCustomers() {
|
filteredCustomers() {
|
||||||
|
@ -96,58 +52,38 @@ export default {
|
||||||
if (!this.listreceived){
|
if (!this.listreceived){
|
||||||
this.getCustomerList()
|
this.getCustomerList()
|
||||||
}
|
}
|
||||||
let clist = this.customer_list.filter(q =>
|
let clist = this.list.filter(q =>
|
||||||
q.name.toLowerCase().includes(query) ||
|
q.name.toLowerCase().includes(query) ||
|
||||||
q.acc_no.includes(query) ||
|
q.acc_no.includes(query)
|
||||||
q.address.line_1.toLowerCase().includes(query) ||
|
|
||||||
q.address.line_2.toLowerCase().includes(query) ||
|
|
||||||
q.address.city.toLowerCase().includes(query) ||
|
|
||||||
q.address.postcode.toLowerCase().includes(query)
|
|
||||||
)
|
)
|
||||||
return clist
|
return clist
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getCustomerInfo(c) {
|
|
||||||
this.selected_cust = c
|
|
||||||
},
|
|
||||||
goToContracts(c){
|
|
||||||
this.$router.push('/customers/contracts/list/' + c.id)
|
|
||||||
},
|
|
||||||
goToMedFeeds(c){
|
|
||||||
this.$router.push('/customers/medicated-feeds/list/' + c.id)
|
|
||||||
},
|
|
||||||
goToComplaints(c){
|
|
||||||
this.$router.push('/customers/complaints/list/' + c.id)
|
|
||||||
},
|
|
||||||
viewOrders(c){
|
|
||||||
this.$router.push('/customers/orders/list/' + c.id)
|
|
||||||
},
|
|
||||||
async getCustomerList() {
|
async getCustomerList() {
|
||||||
this.customers_loading = true
|
this.loading = true
|
||||||
let url = this.$api_url + "/customers/list"
|
let url = this.$api_url + "/customers/list"
|
||||||
axios
|
axios
|
||||||
.get(url,{
|
.get(url,{
|
||||||
params: {
|
params: { limit: this.limit, query: this.searchQuery }})
|
||||||
limit: this.limit,
|
|
||||||
query: "" }})
|
|
||||||
.then(resp => {
|
.then(resp => {
|
||||||
this.customer_list = resp.data
|
this.list = resp.data
|
||||||
this.listreceived = true
|
this.listreceived = true
|
||||||
|
this.loading = false
|
||||||
})
|
})
|
||||||
.catch(error => (console.log(error)))
|
.catch(error => (console.log(error)))
|
||||||
.finally(() => {
|
|
||||||
this.customers_loading = false
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.scroller {
|
.scroller {
|
||||||
height: 300px;
|
height: 500px;
|
||||||
}
|
}
|
||||||
.scroller.small {
|
.customer {
|
||||||
height: 200px;
|
height: 32%;
|
||||||
|
padding: 0 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,191 +1,3 @@
|
||||||
<template>
|
<template>
|
||||||
<v-card :title="title" :subtitle="'Medicated Feed : ' + mf.id">
|
Not Implemented, yet :-)
|
||||||
<v-card-text>
|
|
||||||
<v-container>
|
|
||||||
<v-row>
|
|
||||||
<v-col cols="6">
|
|
||||||
<v-text-field label="Customer" readonly variant="outlined" prepend-inner-icon="mdi-magnify" @click="showCustomerSearch" :model-value="mf.customer.acc_no + ' - ' + mf.customer.name">
|
|
||||||
</v-text-field>
|
|
||||||
<v-text-field label="Vet" readonly variant="outlined" prepend-inner-icon="mdi-magnify" @click="showVetSearch" :model-value="mf.vet.practice">
|
|
||||||
</v-text-field>
|
|
||||||
|
|
||||||
</v-col>
|
|
||||||
<v-col cols="6">
|
|
||||||
<v-card title="Medication :">
|
|
||||||
<v-card-text>
|
|
||||||
<v-text-field label="Medication" readonly variant="outlined" prepend-inner-icon="mdi-magnify" @click="showMedSearch" :model-value="mf.medication.name">
|
|
||||||
</v-text-field>
|
|
||||||
<template v-for="(i, idx) in mf.medication.info" :key="idx" >
|
|
||||||
<template v-if="i != ''">
|
|
||||||
{{ i }}<br/>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
Med Code : {{ mf.medication.med_code }}<br/>
|
|
||||||
Inclusion Rate : {{ mf.medication.inclusion_rate }}
|
|
||||||
</v-card-text>
|
|
||||||
</v-card>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
<v-row>
|
|
||||||
<v-col cols="12">
|
|
||||||
<v-text-field label="Product" readonly variant="outlined" prepend-inner-icon="mdi-magnify" @click="showProductSearch" :model-value="mf.product.code + ' - ' + mf.product.name">
|
|
||||||
</v-text-field>
|
|
||||||
</v-col>
|
|
||||||
<v-col cols="6">
|
|
||||||
<v-text-field label="Tonnage" variant="outlined" type="number" v-model="mf.tonnage"></v-text-field>
|
|
||||||
</v-col>
|
|
||||||
<v-col cols="6">
|
|
||||||
<label>
|
|
||||||
Date Required :
|
|
||||||
<DatePicker v-model="mf.date_required" format="dd/MM/yyyy" />
|
|
||||||
</label>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
<v-row>
|
|
||||||
<v-col cols="6">
|
|
||||||
<v-switch color="blue" label="Repeat prescription" v-model="mf.repeat"></v-switch>
|
|
||||||
</v-col>
|
|
||||||
<v-col cols="6">
|
|
||||||
<v-textarea :disabled="!mf.repeat" label="Repeat Message" v-model="mf.repeat_message" variant="outlined"></v-textarea>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
</v-container>
|
|
||||||
</v-card-text>
|
|
||||||
<DebugPanel :data="mf"></DebugPanel>
|
|
||||||
<ErrorBanner :errors="errors" />
|
|
||||||
<v-card-actions>
|
|
||||||
<v-btn v-if="!mf.isNew" color="red-darken-1"
|
|
||||||
variant="text"
|
|
||||||
:loading="saving"
|
|
||||||
@click="saveMedFeed(mf)">Save</v-btn>
|
|
||||||
<v-btn v-if="mf.isNew" color="red-darken-1"
|
|
||||||
variant="text"
|
|
||||||
:loading="saving"
|
|
||||||
@click="saveMedFeed(mf)">Add</v-btn>
|
|
||||||
<v-spacer></v-spacer>
|
|
||||||
<v-btn color="blue-darken-1"
|
|
||||||
variant="text"
|
|
||||||
@click="close">Close</v-btn>
|
|
||||||
</v-card-actions>
|
|
||||||
</v-card>
|
|
||||||
<v-dialog v-model="search[0]">
|
|
||||||
<CustomerSearch @returnCustomer="setCustomer"></CustomerSearch>
|
|
||||||
</v-dialog>
|
|
||||||
<v-dialog v-model="search[1]">
|
|
||||||
<ProductSearch @returnProduct="setProduct"></ProductSearch>
|
|
||||||
</v-dialog>
|
|
||||||
<v-dialog v-model="search[2]">
|
|
||||||
<VetSearch @returnVet="setVet"></VetSearch>
|
|
||||||
</v-dialog>
|
|
||||||
<v-dialog v-model="search[3]">
|
|
||||||
<MedSearch @returnMed="setMed"></MedSearch>
|
|
||||||
</v-dialog>
|
|
||||||
</template>
|
</template>
|
||||||
<script>
|
|
||||||
import DatePicker from '@vuepic/vue-datepicker'
|
|
||||||
import axios from 'axios';
|
|
||||||
import CustomerSearch from '@/components/CustomerSearch.vue'
|
|
||||||
import ProductSearch from '@/components/ProductSearch.vue'
|
|
||||||
import VetSearch from '@/components/VetSearch.vue'
|
|
||||||
import MedSearch from '@/components/MedSearch.vue'
|
|
||||||
import ErrorBanner from '@/components/ErrorBanner.vue'
|
|
||||||
export default {
|
|
||||||
props:{
|
|
||||||
set_mf: {}
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
DatePicker,
|
|
||||||
CustomerSearch,
|
|
||||||
ProductSearch,
|
|
||||||
ErrorBanner,
|
|
||||||
VetSearch,
|
|
||||||
MedSearch
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
set_mf(newval) {
|
|
||||||
this.mf = newval
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
mf: this.set_mf,
|
|
||||||
vets: [],
|
|
||||||
medications: [],
|
|
||||||
products: [],
|
|
||||||
search: [],
|
|
||||||
searching: {},
|
|
||||||
errors: [],
|
|
||||||
saving: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
title() {
|
|
||||||
if ( this.mf.isNew ) {
|
|
||||||
return "New Medicated Feed"
|
|
||||||
} else {
|
|
||||||
return "Edit Medicated Feed"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
emits: ['closetab','medfeedupdated'],
|
|
||||||
methods: {
|
|
||||||
close() {
|
|
||||||
this.$emit('closetab','list')
|
|
||||||
},
|
|
||||||
saveMedFeed(medfeed) {
|
|
||||||
this.errors = []
|
|
||||||
this.saving = true
|
|
||||||
let url = this.$api_url + "/customers/medicated-feeds/" + this.mf.id + "/save"
|
|
||||||
if (this.mf.isNew) {
|
|
||||||
url = this.$api_url + "/customers/medicated-feeds/add"
|
|
||||||
}
|
|
||||||
console.log("Saving Med Feed...")
|
|
||||||
axios.post(url,{
|
|
||||||
medfeed: medfeed
|
|
||||||
})
|
|
||||||
.then(resp => {
|
|
||||||
let stat = resp.data
|
|
||||||
if (stat.status == true ) {
|
|
||||||
this.$emit('medfeedupdated')
|
|
||||||
} else {
|
|
||||||
this.errors.push("Error Saving... ")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
.finally(()=>{
|
|
||||||
this.saving = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
showCustomerSearch(){
|
|
||||||
this.search[0] = true
|
|
||||||
},
|
|
||||||
setCustomer(c){
|
|
||||||
this.mf.customer = c
|
|
||||||
this.search[0] = false
|
|
||||||
},
|
|
||||||
showProductSearch() {
|
|
||||||
this.search[1] = true
|
|
||||||
},
|
|
||||||
setProduct(p) {
|
|
||||||
this.mf.product = p
|
|
||||||
this.search[1] = false
|
|
||||||
},
|
|
||||||
showVetSearch() {
|
|
||||||
this.search[2] = true
|
|
||||||
},
|
|
||||||
setVet(v) {
|
|
||||||
this.mf.vet = v
|
|
||||||
this.search[2] = false
|
|
||||||
},
|
|
||||||
showMedSearch() {
|
|
||||||
this.search[3] = true
|
|
||||||
},
|
|
||||||
setMed(med) {
|
|
||||||
this.mf.medication = med
|
|
||||||
this.search[3] = false
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
|
@ -10,68 +10,63 @@
|
||||||
<v-window-item value="list">
|
<v-window-item value="list">
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col>
|
<v-col>
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
<v-row>
|
|
||||||
<v-col cols="12" xs="12" sm="12" md="12" lg=8>
|
|
||||||
<v-text-field clearable
|
<v-text-field clearable
|
||||||
label="Search"
|
label="Search"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
v-model="searchQuery"
|
v-model="searchQuery"
|
||||||
density="compact"
|
density="compact"
|
||||||
append-inner-icon="mdi-magnify"></v-text-field>
|
append-inner-icon="mdi-magnify"></v-text-field>
|
||||||
<v-btn v-if="site_info.features.addmedfeed" color="warning" @click="editMedFeed()" prepend-icon="mdi-plus" variant="text">Add</v-btn>
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
<v-btn v-if="site_info.features.addmedfeed" color="warning" @click="editMedFeed({})">+ Add</v-btn>
|
||||||
|
<v-row>
|
||||||
|
<v-col cols="8" xs="12" sm="12" md="8">
|
||||||
<v-progress-linear indeterminate color="blue" :active="loading"></v-progress-linear>
|
<v-progress-linear indeterminate color="blue" :active="loading"></v-progress-linear>
|
||||||
<v-card variant="outlined">
|
<RecycleScroller class="scroller"
|
||||||
<RecycleScroller class="scroller"
|
:items="filteredMedFeeds"
|
||||||
:items="filteredMedFeeds"
|
:item-size="130"
|
||||||
:item-size="100"
|
v-slot="{ item }"
|
||||||
v-slot="{ item }"
|
key-field="id"
|
||||||
key-field="id">
|
>
|
||||||
<v-row dense class="item" :class="{ at_risk : item.customer.at_risk }">
|
<v-row class="item" :class="{ at_risk : item.customer.at_risk }">
|
||||||
<v-col cols="4">
|
<v-col cols="4">
|
||||||
Medicated Feed : {{ item.id }}<br/>
|
Medicated Feed : {{ item.id }},
|
||||||
<span class="text-caption">
|
{{ item.customer.acc_no }} - {{ item.customer.name }}
|
||||||
{{ item.customer.acc_no }} - {{ item.customer.name }}<br/>
|
</v-col>
|
||||||
Vet: {{ item.vet.practice }}</span>
|
<v-col>
|
||||||
</v-col>
|
{{ item.medication.name }} {{ item.medication.inclusion_rate }}<br />
|
||||||
<v-col class="text-caption">
|
{{ item.product.name }}
|
||||||
{{ item.medication.name }} {{ item.medication.inclusion_rate }}<br />
|
</v-col>
|
||||||
{{ item.product.name }}
|
<v-col>
|
||||||
</v-col>
|
Required : {{ formatDate(item.date_required,"DD/MM/YYYY") }} <br/>
|
||||||
<v-col class="text-caption">
|
Repeat Prescription? : <v-icon v-if="item.repeat">mdi-refresh</v-icon>
|
||||||
Required : {{ formatDate(item.date_required,"DD/MM/YYYY") }} <br/>
|
</v-col>
|
||||||
Repeat Prescription? : <v-icon v-if="item.repeat">mdi-refresh</v-icon>
|
<v-col>
|
||||||
</v-col>
|
<v-btn>
|
||||||
<v-col>
|
More
|
||||||
<div class="d-flex justify-space-around align-center flex-column flex-sm-row fill-height">
|
<v-overlay activator="parent" class="align-center justify-center">
|
||||||
<v-btn>
|
<v-container>
|
||||||
More
|
<v-card width="600">
|
||||||
<v-overlay activator="parent" class="align-center justify-center">
|
<v-card-title>Info</v-card-title>
|
||||||
<v-container>
|
<v-card-subtitle>Repeat Message</v-card-subtitle>
|
||||||
<v-card width="600">
|
<v-card-text>{{ item.repeat_message }}</v-card-text>
|
||||||
<v-card-title>Info</v-card-title>
|
<v-card-actions>
|
||||||
<v-card-subtitle>Repeat Message</v-card-subtitle>
|
<v-btn class="mb-2 mr-2" color="blue" @click="reportScriptReq(item)">Script Request</v-btn>
|
||||||
<v-card-text>{{ item.repeat_message }}</v-card-text>
|
<v-btn class="mb-2 mr-2" color="blue" @click="reportOrderForm(item)">Order Form</v-btn>
|
||||||
<v-card-actions>
|
</v-card-actions>
|
||||||
<v-btn class="mb-2 mr-2" color="blue" @click="reportScriptReq(item)">Script Request</v-btn>
|
</v-card>
|
||||||
<v-btn class="mb-2 mr-2" color="blue" @click="reportOrderForm(item)">Order Form</v-btn>
|
</v-container>
|
||||||
</v-card-actions>
|
</v-overlay>
|
||||||
</v-card>
|
</v-btn>
|
||||||
</v-container>
|
<v-btn v-if="site_info.editmedfeed" >Edit</v-btn>
|
||||||
</v-overlay>
|
</v-col>
|
||||||
</v-btn><br/>
|
</v-row>
|
||||||
<v-btn v-if="site_info.features.editmedfeed" color="warning" @click="editMedFeed(item)">Edit</v-btn>
|
</RecycleScroller>
|
||||||
</div>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
</RecycleScroller>
|
|
||||||
</v-card>
|
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-window-item>
|
</v-window-item>
|
||||||
<v-window-item value="edit">
|
<v-window-item value="edit">
|
||||||
<MedFeedsEdit :set_mf="selected_mf" @closetab="tab = 'list'" @medfeedupdated="medfeedUpdated" />
|
<MedFeedsEdit />
|
||||||
</v-window-item>
|
</v-window-item>
|
||||||
<v-window-item value="scriptreq">
|
<v-window-item value="scriptreq">
|
||||||
<ScriptReq :mf="selected_mf" :user="user_info"></ScriptReq>
|
<ScriptReq :mf="selected_mf" :user="user_info"></ScriptReq>
|
||||||
|
@ -87,7 +82,6 @@ import MedFeedsEdit from './MedFeedsEdit.vue'
|
||||||
import ScriptReq from './MedFeedsScriptReq.vue'
|
import ScriptReq from './MedFeedsScriptReq.vue'
|
||||||
import OrderForm from './MedFeedsOrderForm.vue'
|
import OrderForm from './MedFeedsOrderForm.vue'
|
||||||
import methods from '@/CommonMethods.vue'
|
import methods from '@/CommonMethods.vue'
|
||||||
import MedFeedType from '@/types/MedFeedType.vue';
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
site_info: {},
|
site_info: {},
|
||||||
|
@ -120,8 +114,7 @@ export default {
|
||||||
}
|
}
|
||||||
let clist = this.list.filter(q =>
|
let clist = this.list.filter(q =>
|
||||||
q.customer.name.toLowerCase().includes(query) ||
|
q.customer.name.toLowerCase().includes(query) ||
|
||||||
q.customer.acc_no.includes(query) ||
|
q.customer.acc_no.includes(query)
|
||||||
q.id == query
|
|
||||||
)
|
)
|
||||||
return clist
|
return clist
|
||||||
}
|
}
|
||||||
|
@ -131,13 +124,11 @@ export default {
|
||||||
async getMedFeedsList(){
|
async getMedFeedsList(){
|
||||||
this.loading = true
|
this.loading = true
|
||||||
let url = this.$api_url + "/customers/medicated-feeds/list"
|
let url = this.$api_url + "/customers/medicated-feeds/list"
|
||||||
let c_id = this.$route.params.id || ""
|
console.log("Getting Medicated Feeds list...")
|
||||||
console.log("Getting Medicated Feeds list..." + c_id)
|
|
||||||
axios.get(url,{
|
axios.get(url,{
|
||||||
params: {
|
params: {
|
||||||
limit: this.limit,
|
limit: this.limit,
|
||||||
query: this.searchQuery,
|
query: this.searchQuery
|
||||||
c_id: c_id
|
|
||||||
}
|
}
|
||||||
}).then(resp => {
|
}).then(resp => {
|
||||||
this.list = resp.data
|
this.list = resp.data
|
||||||
|
@ -171,19 +162,9 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
async editMedFeed(mf) {
|
async editMedFeed(mf) {
|
||||||
console.log(mf)
|
|
||||||
if ( mf != undefined ) {
|
|
||||||
this.selected_mf = mf
|
|
||||||
} else {
|
|
||||||
this.selected_mf = new MedFeedType()
|
|
||||||
}
|
|
||||||
this.edit = true
|
this.edit = true
|
||||||
this.tab = "edit"
|
this.tab = "edit"
|
||||||
},
|
this.selected_mf = mf
|
||||||
medfeedUpdated(){
|
|
||||||
this.getMedFeedsList()
|
|
||||||
this.edit = false
|
|
||||||
this.tab = "list"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,9 +175,9 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
height: 100px;
|
height: 138px;
|
||||||
overflow-y:hidden;
|
overflow-y:hidden;
|
||||||
padding: 0 1em;
|
padding: 0 12px;
|
||||||
margin-bottom:2px;
|
margin-bottom:2px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
|
@ -74,7 +74,6 @@
|
||||||
size is 2 tonnes.</p>
|
size is 2 tonnes.</p>
|
||||||
<p>If you require any further information about the veterinary
|
<p>If you require any further information about the veterinary
|
||||||
medicinal products we stock, please get in touch.</p>
|
medicinal products we stock, please get in touch.</p>
|
||||||
<p class="text-underline">Please ensure the prescription is filled out as per the Veterinary Medicines Regulations 2013.</p>
|
|
||||||
<h4>The customer requires this order on {{ formatDate(mf.date_required,"DD/MM/yyyy") }}</h4>
|
<h4>The customer requires this order on {{ formatDate(mf.date_required,"DD/MM/yyyy") }}</h4>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
<template>
|
|
||||||
<h3>Orders List</h3>
|
|
||||||
<v-row>
|
|
||||||
<v-col cols="8" xs="12" sm="12" md="8">
|
|
||||||
<RecentOrders :customer="customer" limit=20 doc_status="0"></RecentOrders>
|
|
||||||
<br/>
|
|
||||||
<RecentOrders :customer="customer" limit=20 doc_status="2"></RecentOrders>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import Customer from '@/types/CustomerType.vue'
|
|
||||||
import RecentOrders from '@/components/RecentOrders.vue'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
site_info: {},
|
|
||||||
user_info: {}
|
|
||||||
},
|
|
||||||
components:{
|
|
||||||
RecentOrders
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
customer: new Customer()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created(){
|
|
||||||
let c_id = this.$route.params.id || 0
|
|
||||||
this.customer.id = c_id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
|
@ -1,135 +0,0 @@
|
||||||
<template>
|
|
||||||
<v-card>
|
|
||||||
<v-card-title>
|
|
||||||
{{ doc_types[doc_status] }} Orders - {{ customer.acc_no }} {{ customer.name }}
|
|
||||||
<v-btn v-if="customer.id != ''" size="smaller" icon="mdi-refresh" variant="text" color="green" @click="getCustomerRecentOrders" :loading="orders_loading"></v-btn>
|
|
||||||
|
|
||||||
</v-card-title>
|
|
||||||
<v-progress-linear color="blue" :active="orders_loading" indeterminate>
|
|
||||||
</v-progress-linear>
|
|
||||||
<v-container>
|
|
||||||
<v-row dense>
|
|
||||||
<v-col cols=12 v-for="item in sortedOrders" :key="item.doc_no">
|
|
||||||
<v-card density="compact" :class="{ 'bg-green-lighten-5' : item.doc_status == 'Live' }">
|
|
||||||
<v-row dense>
|
|
||||||
<v-col>
|
|
||||||
<v-card-title>
|
|
||||||
Order: {{ item.doc_no }}
|
|
||||||
</v-card-title>
|
|
||||||
<v-card-subtitle>
|
|
||||||
{{ formatDate(item.doc_date,"DD/MM/YYYY") }}
|
|
||||||
<v-icon v-if="item.doc_status == 'Completed'" icon="mdi-check"></v-icon>
|
|
||||||
<v-icon v-if="item.doc_status == 'Live'" icon="mdi-play"></v-icon>
|
|
||||||
{{ item.doc_status }}
|
|
||||||
</v-card-subtitle>
|
|
||||||
<v-card-text>
|
|
||||||
{{ item.customer.acc_no }} - {{ item.customer.name }}
|
|
||||||
</v-card-text>
|
|
||||||
</v-col>
|
|
||||||
<v-col>
|
|
||||||
<v-card-text>
|
|
||||||
<!--<h5>Address :</h5>-->
|
|
||||||
<template v-if="item.del_addr.id != 0 && item.del_addr.postal_name != ''">
|
|
||||||
<h5>Delivery Address :</h5>
|
|
||||||
<template v-for="(v, k , index) in item.del_addr" :key="index">
|
|
||||||
<span class="text-caption" v-if="k != 'id' && (v != '' || v != 0)">
|
|
||||||
{{ v }}<br/>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
</v-card-text>
|
|
||||||
</v-col>
|
|
||||||
<v-col cols=5>
|
|
||||||
<v-card-text>
|
|
||||||
<h5>Items :</h5>
|
|
||||||
<span class="text-caption" v-for="(i, index) in item.products" :key="index" style="border-bottom: 1px dotted #000;">
|
|
||||||
{{ i.code }} - {{ i.name }}
|
|
||||||
<span v-if="i.quantity != 0">x {{ i.quantity }}</span><br/>
|
|
||||||
</span>
|
|
||||||
</v-card-text>
|
|
||||||
</v-col>
|
|
||||||
<v-col cols=1>
|
|
||||||
<v-btn variant="text" icon="mdi-exclamation" color="red"></v-btn>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
|
|
||||||
</v-card>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
</v-container>
|
|
||||||
</v-card>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import axios from 'axios'
|
|
||||||
import Customer from '@/types/CustomerType.vue'
|
|
||||||
import methods from '@/CommonMethods.vue'
|
|
||||||
export default {
|
|
||||||
props:{
|
|
||||||
customer: new Customer(),
|
|
||||||
doc_status: Number,
|
|
||||||
limit: Number
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
customer() {
|
|
||||||
this.getCustomerRecentOrders()
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mixins: [methods],
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
orders_loading: false,
|
|
||||||
orders: [],
|
|
||||||
doc_types: ["Live","","Completed"],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
prog_col(){
|
|
||||||
if (this.doc_status == 2){
|
|
||||||
return "green"
|
|
||||||
} else {
|
|
||||||
return "blue"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
sortedOrders() {
|
|
||||||
let sorted = this.orders
|
|
||||||
sorted.sort((a, b) => {
|
|
||||||
if (a.doc_date < b.doc_date){
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
if (a.doc_date > b.doc_date){
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
})
|
|
||||||
return sorted
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
getCustomerRecentOrders(){
|
|
||||||
this.orders_loading = true
|
|
||||||
let url = this.$api_url + "/customers/" + this.customer.id + "/orders/recent"
|
|
||||||
axios.get(url, {
|
|
||||||
params: {
|
|
||||||
doc_status: this.doc_status,
|
|
||||||
limit: this.limit || 6
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(resp => {
|
|
||||||
this.orders = resp.data
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.orders_loading = false
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
if (this.customer.id != "") {
|
|
||||||
this.getCustomerRecentOrders()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
34
todo.md
|
@ -1,34 +0,0 @@
|
||||||
### Basic
|
|
||||||
- [ ] login screen animated logo a la calckey
|
|
||||||
- [ ] log out button under "Hi {USER]" area
|
|
||||||
- [ ] store customer, products, complaints, contracts, etc. in var and repeatedly check for updates
|
|
||||||
|
|
||||||
### Contracts
|
|
||||||
- [x] contracts list
|
|
||||||
- [x] print contract
|
|
||||||
- [x] new contract
|
|
||||||
- [x] edit contract?
|
|
||||||
|
|
||||||
### Complaints
|
|
||||||
- [x] complaints list
|
|
||||||
- [x] view complaint info (comments, 1, 2, 3, at risk, permanent, added by)
|
|
||||||
- [ ] make list recycle box
|
|
||||||
- [ ] add driver to complaint info
|
|
||||||
- [ ] edit complaint text
|
|
||||||
- [ ] add complaint
|
|
||||||
- [ ] edit complaint
|
|
||||||
|
|
||||||
### Medicated Feeds
|
|
||||||
- [x] Medicated Feeds List
|
|
||||||
- [x] more info on list?
|
|
||||||
- [x] Medicated feeds report 1
|
|
||||||
- [x] medicated feeds report 2
|
|
||||||
- [ ] add medicated feeds
|
|
||||||
- [ ] edit medicated feeds
|
|
||||||
- [ ] add/edit medicines
|
|
||||||
|
|
||||||
### Farmers Cheques
|
|
||||||
- [ ] Farmers Cheques
|
|
||||||
|
|
||||||
### Poultry Letters (?)
|
|
||||||
- [ ] Find out whatever these actually are
|
|