This commit is contained in:
glovetleong
2021-06-17 09:53:04 +08:00
commit 8fa80e4a1a
2382 changed files with 196486 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
<template>
<div id="app">
<component :is="layout">
<transition name="fade" mode="out-in">
<router-view></router-view>
</transition>
</component>
</div>
</template>
<script>
const default_layout = "default";
export default {
computed: {
layout() {
let vm = this;
return (vm.$route.meta.layout || default_layout) + '-layout';
}
}
}
</script>
+112
View File
@@ -0,0 +1,112 @@
window._ = require('lodash');
// Axios
window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
// Token
let token = document.head.querySelector('meta[name="csrf-token"]');
if (token) {
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}
// Vuetify
import Vuetify, {
VApp,
VTextField,
VBtn,
VBreadcrumbs,
VSwitch,
VRadioGroup,
VRadio
} from 'vuetify/lib';
// import 'material-design-icons-iconfont/dist/material-design-icons.css';
import 'vuetify/src/stylus/app.styl';
Vue.use(Vuetify, {
components: {
VApp,
VTextField,
VBtn,
VBreadcrumbs,
VSwitch,
VRadioGroup,
VRadio
},
options: {
customProperties: true
},
iconfont: 'md' || 'mdi',
});
// Vue Meta
import VueMeta from 'vue-meta'
Vue.use(VueMeta)
// Boostrap
import BootstrapVue from 'bootstrap-vue'
Vue.use(BootstrapVue);
// Form Wiziard
import VueFormWizard from 'vue-form-wizard'
import 'vue-form-wizard/dist/vue-form-wizard.min.css'
Vue.use(VueFormWizard);
// Tags Input
import VueTagsInput from '@johmun/vue-tags-input';
Vue.component('vue-tags-input', VueTagsInput);
// Toasted
import Toasted from 'vue-toasted';
let Options = {
// iconPack : 'fontawesome'
}
Vue.use(Toasted, Options);
// Sprintf
window.Sprintf = require('sprintf-js').sprintf;
// Youtube
import VueYouTubeEmbed from 'vue-youtube-embed';
Vue.use(VueYouTubeEmbed);
// VueElementLoading
import VueElementLoading from 'vue-element-loading';
Vue.component('vue-element-loading', VueElementLoading);
//Utilities
import Form from './utilities/form';
window.Form = Form;
import Constants from './utilities/constants';
window.Constants = Constants;
window.General = require('./utilities/general');
window.NavigationAccess = require('./utilities/navigationAccess');
import En from './langs/en';
window.En = En;
import ENV from './utilities/env';
window.ENV = ENV;
/**
* Echo exposes an expressive API for subscribing to channels and listening
* for events that are broadcast by Laravel. Echo and event broadcasting
* allows your team to easily build robust real-time web applications.
*/
// import Echo from 'laravel-echo';
// window.Pusher = require('pusher-js');
// window.Echo = new Echo({
// broadcaster: 'pusher',
// key: process.env.MIX_PUSHER_APP_KEY,
// cluster: process.env.MIX_PUSHER_APP_CLUSTER,
// forceTLS: true
// });
@@ -0,0 +1,45 @@
<template>
<div >
<label v-if="label" for="name">{{ label }}</label>
<div class="form-group" :class="{'has-error': form.errors.has(input_name)}">
<datepicker
:name="input_name"
input-class="form-control"
:placeholder="placeholder"
v-model="form[input_name]"
@input="form.errors.clear(input_name)"
format="dd-MM-yy"
:disabled-dates="state.disabledDates"
></datepicker>
<div class="text-danger text-left" v-if="form.errors.has(input_name)" v-text="form.errors.get(input_name)"></div>
</div>
</div>
</template>
<script type="text/javascript">
import Datepicker from 'vuejs-datepicker';
import moment from 'moment';
export default {
props: ['input_name', 'form', 'placeholder', 'label', 'disable_pass_date'],
components: {
Datepicker
},
data() {
let vm = this;
return {
state : {
disabledDates: {
customPredictor: function(date) {
if (!vm.disable_pass_date) {
if(date < moment().startOf('day') ){
return true
}
}
}
}
}
}
}
}
</script>
@@ -0,0 +1,63 @@
<template>
<div >
<label v-if="label" for="name">{{ label }}</label>
<div class="row">
<div class="col-6">
<div class="form-group" :class="{'has-error': form.errors.has(input_name_1)}">
<datepicker
:name="input_name_1"
input-class="form-control"
:placeholder="placeholder"
v-model="form[input_name_1]"
@input="form.errors.clear(input_name_1)"
format="dd-MM-yy"
:disabled-dates="state.disabledDates"
></datepicker>
<div class="text-danger text-left" v-if="form.errors.has(input_name_1)" v-text="form.errors.get(input_name_1)"></div>
</div>
</div>
<div class="col-6">
<div class="form-group" :class="{'has-error': form.errors.has(input_name_2)}">
<datepicker
:name="input_name_2"
input-class="form-control"
:placeholder="placeholder"
v-model="form[input_name_2]"
@input="form.errors.clear(input_name_2)"
format="dd-MM-yy"
:disabled-dates="state.disabledDates"
></datepicker>
<div class="text-danger text-left" v-if="form.errors.has(input_name_2)" v-text="form.errors.get(input_name_2)"></div>
</div>
</div>
</div>
</div>
</template>
<script type="text/javascript">
import Datepicker from 'vuejs-datepicker';
import moment from 'moment';
export default {
props: ['input_name_1', 'input_name_2', 'form', 'placeholder', 'label', 'disable_pass_date'],
components: {
Datepicker
},
data() {
let vm = this;
return {
state : {
disabledDates: {
customPredictor: function(date) {
if (!vm.disable_pass_date) {
if(date < moment().startOf('day') ){
return true
}
}
}
}
}
}
}
}
</script>
@@ -0,0 +1,32 @@
<template>
<div class="form-group">
<label v-if="label" for="name">{{ label }}</label>
<div class="row">
<div class="col-6">
<div class="form-group">
<input type="text"
class="form-control"
v-model="form[input_name_1]"
:readonly="true"
>
</div>
</div>
<div class="col-6">
<div class="form-group">
<input type="text"
class="form-control"
v-model="form[input_name_2]"
:readonly="true"
>
</div>
</div>
</div>
</div>
</template>
<script type="text/javascript">
export default {
props: ['input_name_1', 'input_name_2', 'form', 'label', 'disable_pass_date'],
}
</script>
@@ -0,0 +1,52 @@
<template>
<div >
<label v-if="label" for="name">{{ label }}</label>
<div class="row">
<div class="col-6">
<div class="form-group" :class="{'has-error': form.errors.has(input_name_1)}">
<datetime
type="datetime"
class="form-control"
v-model="form[input_name_1]"
value-zone="Asia/Singapore"
zone="Asia/Singapore"
@input="form.errors.clear(input_name_1)"
></datetime>
<div class="text-danger text-left" v-if="form.errors.has(input_name_1)" v-text="form.errors.get(input_name_1)"></div>
</div>
</div>
<div class="col-6">
<div class="form-group" :class="{'has-error': form.errors.has(input_name_2)}">
<datetime
type="datetime"
class="form-control"
v-model="form[input_name_2]"
value-zone="Asia/Singapore"
zone="Asia/Singapore"
@input="form.errors.clear(input_name_2)"
></datetime>
<div class="text-danger text-left" v-if="form.errors.has(input_name_2)" v-text="form.errors.get(input_name_2)"></div>
</div>
</div>
</div>
</div>
</template>
<script type="text/javascript">
import { Datetime } from 'vue-datetime';
import 'vue-datetime/dist/vue-datetime.css';
import moment from 'moment';
export default {
props: ['input_name_1', 'input_name_2', 'form', 'placeholder', 'label', 'disable_pass_date'],
components: {
Datetime
},
data() {
let vm = this;
return {
}
}
}
</script>
@@ -0,0 +1,43 @@
<template>
<div class="form-group" :class="{'has-error': form.errors.has(input_name)}">
<label v-if="label" for="name">{{ label }}</label>
<div class="upload-box">
<div class="file-container mb-1">
<i class="fa fa-download"></i>
<input type='file'
:name="input_name"
@change="onChange"
/>
<div>{{ file_name }}</div>
</div>
</div>
<div class="text-danger text-left" v-if="form.errors.has(input_name)" v-text="form.errors.get(input_name)"></div>
</div>
</template>
<script>
export default {
props: ['input_name', 'form', 'placeholder', 'label'],
components: {
},
data() {
return {
file_name: '',
file: []
}
},
methods: {
onChange(e) {
let vm = this;
let files = e.target.files;
General.imageBase64(e.target.files).then(data => {
vm.file = data[0];
vm.file_name = e.target.files[0].name;
vm.form[vm.input_name] = [vm.file];
});
},
}
}
</script>
@@ -0,0 +1,89 @@
<template>
<div class="form-group" :class="{'has-error': form.errors.has(input_name)}">
<label v-if="label" for="name">{{ label }}</label>
<div class="upload-box">
<div class="file-container mb-1">
<i class="fa fa-download"></i>
<input type='file'
:name="input_name"
@change="onChange"
/>
</div>
<div v-if="preview" v-for="(img, $index) in preview" :key="$index">
<a v-if="mime_type == 'application/pdf'" class="btn btn-xs btn-light" :href="img" target="_blank">
<i class="fa fa-file-pdf"></i>
</a>
<div v-if="mime_type != 'application/pdf'">
<img class="img-fluid" alt='' :src="img"/>
</div>
</div>
</div>
<div class="text-danger text-left" v-if="form.errors.has(input_name)" v-text="form.errors.get(input_name)"></div>
<cropper-modal
:img="img"
@clicked="getCropImage"
>
</cropper-modal>
</div>
</template>
<script>
import CropperModal from "../modals/CropperModal";
export default {
props: {
input_name: String,
form: Object,
placeholder: String,
label: String,
exist_img: Array,
},
components: {
CropperModal
},
data() {
return {
preview: [],
img: [],
mime_type: '',
}
},
methods: {
onChange(e) {
let vm = this;
let files = e.target.files;
vm.mime_type = files[0].type;
General.imageBase64(e.target.files).then(data => {
vm.img = data[0];
vm.cropperModalToggle();
});
},
cropperModalToggle() {
let vm = this;
vm.$bvModal.show('cropper-modal');
},
getCropImage(img) {
let vm = this;
vm.form[vm.input_name] = [img];
vm.preview = [img];
},
loadExistingImg() {
let vm = this;
if (vm.exist_img[0]) {
vm.mime_type = vm.exist_img[0].mime_type;
Array.from(vm.exist_img).forEach(file => {
vm.preview.push(file.file_info.original.file);
});
}
}
},
watch: {
'exist_img': 'loadExistingImg',
},
created() {
let vm = this;
vm.loadExistingImg();
}
}
</script>
@@ -0,0 +1,46 @@
<template>
<div class="form-group">
<label v-if="label" for="name">{{ label }}</label>
<div class="upload-box">
<div v-if="preview" v-for="(img, $index) in preview" :key="$index">
<div>
<img class="img-fluid" alt='' :src="img"/>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
label: String,
exist_img: Array,
},
data() {
return {
preview: [],
img: [],
mime_type: '',
}
},
methods: {
loadExistingImg() {
let vm = this;
if (vm.exist_img[0]) {
vm.mime_type = vm.exist_img[0].mime_type;
Array.from(vm.exist_img).forEach(file => {
vm.preview.push(file.file_info.original.file);
});
}
}
},
watch: {
'exist_img': 'loadExistingImg',
},
created() {
let vm = this;
vm.loadExistingImg();
}
}
</script>
@@ -0,0 +1,34 @@
<template>
<div class="form-group" :class="{'has-error': form.errors.has(input_name)}">
<label v-if="label" for="name">{{ label }}</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text">{{ icon }}</span>
</div>
<input type="text"
class="form-control"
:placeholder="placeholder"
v-model="form[input_name]"
@keydown="form.errors.clear(input_name)"
@keypress="isNumber($event)"
@input="$emit('clicked')"
:readonly="readonly"
>
</div>
<div class="text-danger text-left" v-if="form.errors.has(input_name)" v-text="form.errors.get(input_name)"></div>
</div>
</template>
<script type="text/javascript">
export default {
props: ['input_name', 'form', 'icon', 'placeholder', 'label', 'readonly'],
methods: {
isNumber($event) {
let keyCode = ($event.keyCode ? $event.keyCode : $event.which);
if ((keyCode < 48 || keyCode > 57) && keyCode !== 46) { // 46 is dot
$event.preventDefault();
}
}
}
}
</script>
@@ -0,0 +1,36 @@
<template>
<div class="form-group" :class="{'has-error': form.errors.has(input_name)}">
<label v-if="label" for="name">{{ label }}</label>
<input type="text"
:name="input_name"
class="form-control"
:placeholder="placeholder"
v-model="form[input_name]"
@keydown="form.errors.clear(input_name)"
@keypress="isNumber($event)"
@keyup="$emit('clicked')"
:readonly="readonly"
>
<div class="text-danger text-left" v-if="form.errors.has(input_name)" v-text="form.errors.get(input_name)"></div>
</div>
</template>
<script type="text/javascript">
export default {
props: {
input_name: String,
form: Object,
placeholder: String,
label: String,
readonly: Boolean,
},
methods: {
isNumber($event) {
let keyCode = ($event.keyCode ? $event.keyCode : $event.which);
if ((keyCode < 48 || keyCode > 57) && keyCode !== 46) { // 46 is dot
$event.preventDefault();
}
}
}
}
</script>
@@ -0,0 +1,44 @@
<template>
<div class="form-group" :class="{'has-error': form.errors.has(input_name)}">
<label v-if="label" for="name">{{ label }}</label>
<div class="input-group">
<input :type="password_type ? 'password' : 'text'"
class="form-control"
:placeholder="placeholder"
v-model="form[input_name]"
@keydown="form.errors.clear(input_name)"
>
<div class="input-group-prepend pointer-cursor" @click="passwordToggle">
<span class="input-group-text">
<i :class="password_type ? 'fa fa-eye-slash' : 'fa fa-eye'" aria-hidden="true"></i>
</span>
</div>
</div>
<div class="text-danger text-left" v-if="form.errors.has(input_name)" v-text="form.errors.get(input_name)"></div>
</div>
</template>
<script type="text/javascript">
export default {
props: {
input_name: String,
form: Object,
placeholder: String,
label: String
},
data() {
let vm = this;
return {
password_type: true
}
},
methods: {
passwordToggle() {
let vm = this;
vm.password_type = !vm.password_type;
}
}
}
</script>
@@ -0,0 +1,27 @@
<template>
<div class="form-group" :class="{'has-error': form.errors.has(input_name)}">
<div>
<label v-if="label" for="name">{{ label }}</label>
</div>
<v-radio-group v-model="form[input_name]" :mandatory="false">
<v-radio
v-if="list" v-for="(item, $index) in list" :key="$index"
color="primary"
:label="item.name"
:value="item.id"
></v-radio>
</v-radio-group>
<div class="text-danger text-left" v-if="form.errors.has(input_name)" v-text="form.errors.get(input_name)"></div>
</div>
</template>
<script type="text/javascript">
export default {
props: {
input_name: String,
form: Object,
list: Array,
label: String,
}
}
</script>
@@ -0,0 +1,140 @@
<template>
<div class="form-group" :class="{'has-error': form.errors.has(input_name)}">
<label v-if="label" for="name">{{ label }}</label>
<vue-tags-input
ref="tags_input"
v-model="tag"
:tags="tags"
:autocomplete-min-length="0"
:add-on-blur="false"
:autocomplete-items="autocompleteItems"
:before-deleting-tag="deleteTag"
:max-tags="limit_tag"
:add-only-from-autocomplete="!can_add_new_tag ? true : false"
:placeholder="''"
@tags-changed="update"
@before-adding-tag="checkTag"
@focus="focus()"
>
</vue-tags-input>
<div class="text-danger text-left" v-if="form.errors.has(input_name)" v-text="form.errors.get(input_name)"></div>
</div>
</template>
<script type="text/javascript">
export default {
props: {
input_name: String,
form: Object,
exist_data: Array,
data_set: Array,
placeholder: String,
label: String,
endpoint: String,
params: Object,
search_field: String,
is_array: Boolean,
limit_tag: Number,
return_key: String,
can_add_new_tag: Boolean
},
data() {
let vm = this;
return {
tag: '',
original_tag: [],
tags: vm.exist_data ? vm.exist_data : [],
autocompleteItems: [],
pervious_item: []
}
},
methods: {
focus() {
let vm = this;
if (vm.pervious_item.length > 0) {
vm.pervious_item = [];
vm.initItems();
}
},
checkTag(obj) {
let vm = this;
if (vm.limit_tag >= vm.tags.length) {
vm.tags = [];
}
obj.addTag();
},
update(newTags = '') {
let vm = this;
vm.tags = newTags;
vm.pervious_item = vm.autocompleteItems;
vm.autocompleteItems = [];
vm.keyConvert();
vm.$emit('clicked', vm.extractRow(vm.tags));
vm.form.errors.clear(vm.input_name);
},
deleteTag() {
vm.$emit('clicked', vm.extractRow(vm.tags));
},
keyConvert() {
let vm = this;
if (!vm.original) {
vm.form[vm.input_name] = General.getKey(vm.tags, (!vm.return_key ? 'id' : vm.return_key));
}
else {
vm.form[vm.input_name] = vm.original_tag;
}
},
initItems() {
let vm = this;
if (vm.pervious_item.length > 0) {
return;
}
if (!vm.data_set) {
let search_field = {};
search_field[vm.search_field] = vm.array ? [vm.tag] : vm.tag;
let form = new Form({...vm.params, ...search_field});
General.getCall(vm.endpoint, form).then(data => {
vm.autocompleteItems = data.data.map(item => {
vm.original_tag.push(vm.tag);
return {
id: item.id,
hash_id: (item.hash_id ? item.hash_id : ''),
row: item,
text: (item.name ? item.name : item.hash_id )
};
});
});
}
else {
vm.autocompleteItems = vm.data_set;
}
},
extractRow() {
let vm = this;
let return_row = [];
vm.tags.forEach(function(element, index) {
return_row.push(element.row);
});
return return_row;
}
},
created() {
let vm = this;
setTimeout(function(){
vm.tags = vm.exist_data ? vm.exist_data : [];
vm.$emit('clicked', vm.extractRow(vm.tags));
}, 1000);
vm.initItems();
},
watch: {
'tag': 'initItems',
}
}
</script>
@@ -0,0 +1,23 @@
<template>
<div class="form-group" :class="{'has-error': form.errors.has(input_name)}">
<label v-if="label">{{ label }}</label>
<select
class="form-control"
v-model="form[input_name]"
@change="$emit('clicked')"
:disabled="readonly"
>
<option disabled value="">Select Option</option>
<option :value="option.id" v-if="list" v-for="(option, $index) in list" :key="$index">
{{ option.name }}
</option>
</select>
<div class="text-danger text-left" v-if="form.errors.has(input_name)" v-text="form.errors.get(input_name)"></div>
</div>
</template>
<script type="text/javascript">
export default {
props: ['input_name', 'form', 'label', 'list', 'readonly']
}
</script>
@@ -0,0 +1,25 @@
<template>
<div class="mb-2">
<label v-if="label">{{ label }}</label>
<v-switch
v-model="form[input_name]"
color="primary"
:value="1"
hide-details
></v-switch>
<div class="text-danger text-left" v-if="form.errors.has(input_name)" v-text="form.errors.get(input_name)"></div>
</div>
</template>
<script type="text/javascript">
import {ToggleButton} from 'vue-js-toggle-button'
export default {
props: {
input_name: String,
form: Object,
label: String
}
}
</script>
@@ -0,0 +1,31 @@
<template>
<div class="form-group" :class="{'has-error': form.errors.has(input_name)}">
<div>
<label v-if="label" for="name">{{ label }}</label>
</div>
<div class="col">
<div class="row">
<div :class="full == true ? 'col-12' : 'col-3'" class="p-0" v-if="list.data" v-for="(item, $index) in list.data" :key="$index">
<div class="float-left mr-3">{{ item.value }}</div>
<div class="float-right">
<v-switch
:name="input_name"
v-model="form[input_name]"
color="primary"
:value="item.key"
hide-details
@keydown="form.errors.clear(input_name)"
></v-switch>
</div>
</div>
</div>
</div>
<div class="text-danger text-left" v-if="form.errors.has(input_name)" v-text="form.errors.get(input_name)"></div>
</div>
</template>
<script type="text/javascript">
export default {
props: ['input_name', 'form', 'list', 'label', 'full']
}
</script>
@@ -0,0 +1,21 @@
<template>
<div class="mb-2">
<label v-if="label">{{ label }}</label>
<v-switch
v-model="form[input_name]"
color="primary"
:value="value"
hide-details
></v-switch>
<div class="text-danger text-left" v-if="form.errors.has(input_name)" v-text="form.errors.get(input_name)"></div>
</div>
</template>
<script type="text/javascript">
import {ToggleButton} from 'vue-js-toggle-button'
export default {
props: ['input_name', 'value', 'form', 'label', 'value']
}
</script>
@@ -0,0 +1,27 @@
<template>
<div class="form-group" :class="{'has-error': form.errors.has(input_name)}">
<label v-if="label" for="name">{{ label }}</label>
<textarea
:name="input_name"
class="form-control"
:placeholder="placeholder"
v-model="form[input_name]"
@keydown="form.errors.clear(input_name)"
:readonly="readonly"
>
</textarea>
<div class="text-danger text-left" v-if="form.errors.has(input_name)" v-text="form.errors.get(input_name)"></div>
</div>
</template>
<script type="text/javascript">
export default {
props: {
input_name: String,
form: Object,
placeholder: String,
label: String,
readonly: Boolean
}
}
</script>
@@ -0,0 +1,18 @@
<template>
<div class="form-group">
<label v-if="label" for="name">{{ label }}</label>
<textarea type="text"
rows="8" cols="50"
class="form-control"
:value="value"
:readonly="true"
>
</textarea>
</div>
</template>
<script type="text/javascript">
export default {
props: ['value', 'label']
}
</script>
@@ -0,0 +1,26 @@
<template>
<div class="form-group" :class="{'has-error': form.errors.has(input_name)}">
<label v-if="label">{{ label }}</label>
<input type="text"
:name="input_name"
class="form-control"
:placeholder="placeholder"
v-model="form[input_name]"
@keydown="form.errors.clear(input_name)"
:readonly="readonly"
>
<div class="text-danger text-left" v-if="form.errors.has(input_name)" v-text="form.errors.get(input_name)"></div>
</div>
</template>
<script type="text/javascript">
export default {
props: {
input_name: String,
form: Object,
placeholder: String,
label: String,
readonly: Boolean
}
}
</script>
@@ -0,0 +1,53 @@
<template>
<div class="form-group" :class="{'has-error': form.errors.has(input_name)}">
<div class="mb-2">
<label v-if="label" for="name">{{ label }}</label>
</div>
<b-row class="mb-2"
v-for="(input, $index) in form[input_name]" :key="$index"
>
<b-col md="10">
<input type="text"
class="form-control mb-1"
v-model="form[input_name][$index]"
@keydown="form.errors.clear(input_name)"
>
</b-col>
<b-col md="2" class="text-right">
<button type="button" class="btn btn-xs btn-danger" @click="removeField($index)">
<i class="fa fa-trash"></i>
</button>
</b-col>
</b-row>
<div>
<button
class="btn btn-xs btn-light"
@click="addField"
>
<i class="fa fa-plus"></i> Add Option
</button>
</div>
<div class="text-danger text-left" v-if="form.errors.has(input_name)" v-text="form.errors.get(input_name)"></div>
</div>
</template>
<script type="text/javascript">
export default {
props: ['input_name', 'form', 'placeholder', 'label', 'readonly'],
methods: {
addField() {
let vm = this;
vm.form[vm.input_name].push([]);
},
removeField(index) {
let vm = this;
vm.form[vm.input_name].splice(index, 1);
}
},
created() {
let vm = this;
}
}
</script>
@@ -0,0 +1,23 @@
<template>
<div class="form-group">
<label v-if="label" for="name">{{ label }}</label>
<b-row class="mb-2"
v-for="(input, $index) in form[input_name]" :key="$index"
>
<b-col md="12">
<input type="text"
class="form-control mb-1"
v-model="form[input_name][$index]"
:readonly="true"
>
</b-col>
</b-row>
</div>
</template>
<script type="text/javascript">
export default {
props: ['input_name', 'form', 'label'],
}
</script>
@@ -0,0 +1,19 @@
<template>
<div class="form-group">
<label v-if="label" for="name">{{ label }}</label>
<input type="text"
class="form-control"
:value="value"
:readonly="true"
>
</div>
</template>
<script type="text/javascript">
export default {
props: {
label: String,
value: String
}
}
</script>
@@ -0,0 +1,56 @@
<template>
<div>
<b-modal :id="'cropper-modal'" size="lg" scrollable>
<template v-slot:modal-title>
<h4 class="modal-title">Crop Image</h4>
</template>
<vue-cropper
ref='cropper'
:guides="true"
:view-mode="2"
drag-mode="crop"
:auto-crop-area="0.5"
:min-container-width="250"
:min-container-height="180"
:background="true"
:rotatable="true"
:src="img"
alt="Source Image"
:img-style="{ 'width': '400px', 'height': '300px' }"
>
</vue-cropper>
<template v-slot:modal-footer>
<form>
<v-btn
:block="true"
type="button"
color="primary"
class="white--text"
@click="cropImage"
>
Crop
</v-btn>
</form>
</template>
</b-modal>
</div>
</template>
<script>
import VueCropper from 'vue-cropperjs';
export default {
props: ['img'],
components: {
VueCropper
},
methods: {
cropImage() {
let vm = this;
let cropImg = '';
cropImg = this.$refs.cropper.getCroppedCanvas().toDataURL();
vm.$bvModal.hide('cropper-modal');
vm.$emit('clicked', cropImg);
}
}
}
</script>
@@ -0,0 +1,48 @@
<template>
<div>
<b-modal :id="'img-pop-modal'" size="lg" scrollable>
<template v-slot:modal-title>
<h4 class="modal-title">{{ label }}</h4>
</template>
<div v-if="img[0]" class="text-center">
<img class="img-fluid"
:src="img[0].file_info.original.file"
width="300px" height="300px"
>
</div>
<template v-slot:modal-footer>
<form>
<v-btn
depressed
small
type="button"
color="warning"
class="m-0"
@click="$bvModal.hide('img-pop-modal')"
>
Close
</v-btn>
</form>
</template>
</b-modal>
</div>
</template>
<script>
import VueCropper from 'vue-cropperjs';
export default {
props: ['label', 'img'],
components: {
VueCropper
},
methods: {
cropImage() {
let vm = this;
let cropImg = '';
cropImg = this.$refs.cropper.getCroppedCanvas().toDataURL();
vm.$bvModal.hide('cropper-modal');
vm.$emit('clicked', cropImg);
}
}
}
</script>
@@ -0,0 +1,31 @@
<template>
<tr>
<td class="pl-0 pr-0" :colspan="colspan">
<ul class="pagination pull-right">
<li v-if="pervious_page" class="page-item">
<span
@click="$emit('clicked', pervious_page)"
class="page-link"
title="left" value="">
«
</span>
</li>
<li v-if="next_page" class="page-item">
<span
@click="$emit('clicked', next_page)"
class="page-link"
title="right" value="">
»
</span>
</li>
</ul>
</td>
</tr>
</template>
<script type="text/javascript">
export default {
props: ['pervious_page', 'next_page', 'colspan']
}
</script>
@@ -0,0 +1,21 @@
<template>
<div class="app-page-title">
<div class="page-title-wrapper">
<div class="page-title-heading">
<div class="page-title-icon">
<i :class="icon"></i>
</div>
<div>
{{heading}}
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: ['icon', 'heading'],
}
</script>
+18
View File
@@ -0,0 +1,18 @@
window.Vue = require('vue');
require('./bootstrap');
import router from './router'
import App from './App'
import DefaultLayout from './layouts/DefaultLayout.vue';
import PageLayout from './layouts/PageLayout.vue';
Vue.component('default-layout', DefaultLayout);
Vue.component('userpages-layout', PageLayout);
const app = new Vue({
el: '#app',
router,
template: '<App/>',
components: { App }
});
+53
View File
@@ -0,0 +1,53 @@
const En = {
// Input
'name': 'name',
'username': 'username',
'email': 'email',
'password': 'password',
'role_id': 'role',
'permission_id': 'permission',
'phone_code': 'phone code',
'code': 'code',
'currency_id': 'currency',
'language_id': 'language',
'symbol': 'symbol',
'sell': 'sell',
'buy': 'buy',
'description': 'description',
'min_file_size': 'min file size',
'max_file_size': 'max file size',
'credit_amount': 'credit amount',
'media_property_type_id': 'media property type',
'type': 'type',
'mime_type_id': 'mime type',
'trending_count': 'trending count',
'bank_name': 'bank name',
'holder_name': 'holder name',
'holder_no': 'holder no',
'country_id': 'country',
// Error
'incorrect_account_or_password': 'Incorrect account or password',
'this_field_required': 'This %(att)s field required',
'incorrect_email_format': 'Incorrect email format',
'the_content_has_already_been_taken': 'The %(att)s has already been taken',
'the_content_confirmation_does_not_match': 'The %(att)s confirmation does not match',
'incorrect_image_format': 'Incorrect image format',
'incorrect_excel_format': 'Incorrect excel format',
'the_content_must_be_a_number': 'The %(att)s must be a number',
'the_content_must_be_greater_than_0': 'The %(att)s must be greater than 0',
'the_content_not_exist': 'The %(att)s not exist',
'the_content_must_be_at_least_10_characters': 'The %(att)s must be at least 10 characters',
'the_content_must_be_less_than_100': 'The %(att)s must be less than 100',
'status_error': 'status not allow update',
// toasted
'have_been_successfully_created': '%(value[0].att)s ( %(value[1].att)s ) have been successfully created',
'have_been_successfully_updated': '%(value[0].att)s ( %(value[1].att)s ) have been successfully updated',
'have_been_successfully_imported': '%(value[0].att)s have been successfully imported',
'error_mass_import': '%(value[0].att)s excel file have error when import',
};
export default En;
@@ -0,0 +1,71 @@
<template>
<v-app id="benesApp">
<div v-if="!loading" class="app-container app-theme-white">
<transition name="fade" mode="out-in" appear>
<app-header
:admin_detail="admin_detail"
>
</app-header>
</transition>
<transition name="fade" mode="out-in" appear>
<app-sidebar
:permission_list="permission_list"
>
</app-sidebar>
</transition>
<div class="app-main__outer">
<div class="app-main__inner">
<slot></slot>
</div>
<transition name="fade" mode="out-in" appear>
<app-footer></app-footer>
</transition>
</div>
</div>
<div v-if="loading" class="main-loading-box">
<vue-element-loading :active="true" spinner="line-scale" color="var(--primary)"></vue-element-loading>
</div>
</v-app>
</template>
<script>
import AppHeader from "./parts/Header";
import AppSidebar from "./parts/Sidebar";
import AppFooter from "./parts/Footer";
export default {
name: 'app',
components: {
AppHeader,
AppSidebar,
AppFooter
},
data() {
return {
form: new Form({}),
isConfigOpen: false,
admin_detail: {},
permission_list: [],
loading: true,
}
},
methods: {
getAdminDetail() {
let vm = this;
let url = 'admin/self';
General.getCall(url, vm.form).then(response => {
if (response.data) {
vm.admin_detail = response.data;
vm.permission_list = response.data.permission_list;
vm.loading = false;
}
});
}
},
created() {
let vm = this;
vm.getAdminDetail();
},
}
</script>
+14
View File
@@ -0,0 +1,14 @@
<template>
<v-app id="benesApp">
<div class="app-container app-theme-white">
<slot></slot>
</div>
</v-app>
</template>
<script>
export default {
name: 'app',
}
</script>
@@ -0,0 +1,22 @@
<template>
<div v-if="menu_item_list" class="mb-3">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item" :class="menu.active ? 'active' : ''" v-for="(menu, $index) in menu_item_list" :key="$index">
<router-link :to="menu.path" tag="button">
{{ menu.title }}
</router-link>
</li>
</ol>
</nav>
</div>
</template>
<script>
export default {
props: ['menu_item_list'],
}
</script>
@@ -0,0 +1,21 @@
<template>
<div class="app-footer">
<div class="app-footer__inner">
<div class="app-footer-left">
Copyright &copy; {{ site_title }} {{ year }}
</div>
</div>
</div>
</template>
<script>
export default {
data() {
let vm = this;
return {
site_title: Constants.site.title,
year: General.getYear()
}
}
}
</script>
@@ -0,0 +1,86 @@
<template>
<div :class="headerbg" class="app-header header-shadow bg-plum-plate text-lighter">
<div class="app-header__content">
<div class="app-header-right">
<HeaderUserArea
:admin_detail="admin_detail"
/>
</div>
</div>
<div class="app-header__mobile-menu">
<div>
<button type="button" class="hamburger close-sidebar-btn hamburger--elastic" :class="{ 'is-active' : isOpen }" @click="toggleMobile('closed-sidebar-open')">
<span class="hamburger-box">
<span class="hamburger-inner"></span>
</span>
</button>
</div>
</div>
<div class="app-header__menu">
<span>
<b-button class="btn-icon btn-icon-only" variant="primary" size="sm" :class="{ 'active' : isOpenMobileMenu }" @click="toggleMobile2('header-menu-open')">
<div class="btn-icon-wrapper">
<i class="fa fa-ellipsis-v"></i>
</div>
</b-button>
</span>
</div>
</div>
</template>
<script>
import HeaderUserArea from './HeaderUserArea';
export default {
name: "Header",
components: {
HeaderUserArea,
},
data() {
return {
isOpen: false,
isOpenMobileMenu: false,
}
},
props: {
headerbg: String,
admin_detail: Object
},
methods: {
toggleMobile(className) {
let vm = this;
const bu = document.getElementsByClassName('close-sidebar-btn')[0];
const el = document.body;
if (bu.classList.contains('is-active')) {
vm.isOpen = false;
bu.classList.remove('is-active');
}
else {
vm.isOpen = true;
bu.classList.add('is-active');
}
if (vm.isOpen) {
el.classList.add(className);
} else {
el.classList.remove(className);
}
},
toggleMobile2(className) {
let vm = this;
const el = document.body;
vm.isOpenMobileMenu = !vm.isOpenMobileMenu;
if (vm.isOpenMobileMenu) {
el.classList.add(className);
} else {
el.classList.remove(className);
}
},
}
};
</script>
@@ -0,0 +1,87 @@
<template>
<div v-if="admin_detail.name" class="d-flex">
<div class="header-btn-lg pr-0">
<div class="widget-content p-0">
<div class="widget-content-wrapper">
<div class="widget-content-left">
<b-dropdown toggle-class="p-0 mr-2" menu-class="dropdown-menu-lg" variant="link" no-caret right>
<span slot="button-content">
<div class="icon-wrapper icon-wrapper-alt rounded-circle">
<img width="50" height="50" class="rounded-circle" :src="admin_detail.img[0].file_info.small.file" alt="">
</div>
</span>
<div class="dropdown-menu-header">
<div class="dropdown-menu-header-inner bg-info">
<div class="menu-header-image opacity-2 dd-header-bg-6"></div>
<div class="menu-header-content text-left">
<div class="widget-content p-0">
<div class="widget-content-wrapper">
<div class="widget-content-left mr-3">
<img width="42" class="rounded-circle" :src="admin_detail.img[0].file_info.small.file" alt="">
</div>
<div class="widget-content-left">
<div class="widget-heading">{{ admin_detail.name}}</div>
<div class="widget-subheading opacity-8">{{ admin_detail.role_list[0].name }}</div>
</div>
<div class="widget-content-right mr-2">
<button
@click="logout"
class="btn-shadow btn-shine btn btn-focus"
>
Logout
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="scroll-area-xs" style="height: 80px;">
<vue-perfect-scrollbar class="scrollbar-container" v-once>
<ul class="nav flex-column">
<li class="nav-item-header nav-item">My Account</li>
<li class="nav-item">
<router-link
:to="'/admin/profile/update'"
class="nav-link"
title="Profile"
>
My Profile
</router-link>
</li>
</ul>
</vue-perfect-scrollbar>
</div>
</b-dropdown>
</div>
<div class="widget-content-left ml-3 header-user-info">
<div class="widget-heading">{{ admin_detail.name }}</div>
<div class="widget-subheading">{{ admin_detail.role_list[0].name }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import VuePerfectScrollbar from 'vue-perfect-scrollbar'
import VueCircle from 'vue2-circle-progress'
export default {
components: {
VuePerfectScrollbar,
VueCircle,
},
props: {
admin_detail: Object
},
methods: {
logout() {
General.logout();
}
}
}
</script>
@@ -0,0 +1,120 @@
<template>
<div class="app-sidebar sidebar-shadow bg-plum-plate text-lighter" @mouseover="toggleSidebarHover('add','closed-sidebar-open')" @mouseleave="toggleSidebarHover('remove','closed-sidebar-open')">
<div class="app-header__logo">
<div class="text-white m-2">
<router-link
:to="'/'"
class="btn-link"
>
<div class="logo-src" :style='{ background: "url(" + share_url + "favicon.png" + ")" }'></div>
</router-link>
</div>
<div class="header__pane ml-auto">
<button type="button" class="hamburger close-sidebar-btn hamburger--elastic" v-bind:class="{ 'is-active' : is_open }" @click="toggleBodyClass('closed-sidebar')">
<span class="hamburger-box">
<span class="hamburger-inner"></span>
</span>
</button>
</div>
</div>
<div class="app-sidebar-content">
<vue-perfect-scrollbar v-if="menu[0]" class="app-sidebar-scroll" v-once>
<sidebar-menu
showOneChild
:menu="menu"
@item-click="onItemClick"
/>
</vue-perfect-scrollbar>
</div>
</div>
</template>
<script>
import { SidebarMenu } from 'vue-sidebar-menu'
import VuePerfectScrollbar from 'vue-perfect-scrollbar'
export default {
props: {
permission_list: Array
},
components: {
SidebarMenu,
VuePerfectScrollbar
},
data() {
return {
is_open: false,
sidebar_active: false,
menu: [],
collapsed: true,
window_width: 0,
share_url: ENV.SHARE_URL,
site_short_title: Constants.site.short_title,
}
},
methods: {
onItemClick(event, item) {
let vm = this;
if (!item.child) {
const el = document.body;
el.classList.remove('closed-sidebar-open');
const bu = document.getElementsByClassName('close-sidebar-btn')[0];
bu.classList.remove('is-active');
}
},
toggleBodyClass(className) {
let vm = this;
const el = document.body;
vm.is_open = !vm.is_open;
if (vm.is_open) {
el.classList.add(className);
} else {
el.classList.remove(className);
}
},
toggleSidebarHover(add, className) {
let vm = this;
const el = document.body;
vm.sidebar_active = !vm.sidebar_active;
vm.window_width = document.documentElement.clientWidth;
if (vm.window_width > '992') {
if (add === 'add') {
el.classList.add(className);
} else {
el.classList.remove(className);
}
}
},
getWindowWidth() {
let vm = this;
const el = document.body;
vm.window_width = document.documentElement.clientWidth;
el.classList.add('closed-sidebar', 'closed-sidebar-md');
},
loadMenu() {
let vm = this;
vm.menu = NavigationAccess.menuDefine(vm.permission_list);
}
},
created() {
let vm = this;
vm.loadMenu();
},
mounted() {
let vm = this;
vm.$nextTick(function () {
window.addEventListener('resize', vm.getWindowWidth);
//Init
vm.getWindowWidth()
})
},
beforeDestroy() {
let vm = this;
window.removeEventListener('resize', vm.getWindowWidth);
}
}
</script>
@@ -0,0 +1,58 @@
<template>
<div>
<page-title
:heading="heading"
:icon="icon"
:add="true"
></page-title>
<breadcrumb
:menu_item_list="menu_item_list"
></breadcrumb>
<admin-role-form
:mode="'create'"
></admin-role-form>
</div>
</template>
<script>
import PageTitle from "../../components/titles/PageTitle";
import Breadcrumb from "../../layouts/parts/Breadcrumb";
import AdminRoleForm from "./Form";
export default {
metaInfo() {
let vm = this;
return {
title: Constants.site.title,
titleTemplate: '%s | ' + vm.$router.currentRoute.name
}
},
components: {
PageTitle,
Breadcrumb,
AdminRoleForm
},
data() {
return {
heading: 'Create Admin Role',
icon: 'fa fa-plus',
menu_item_list: [
{
title: 'Dashboard',
active: false,
path: '/'
},
{
title: 'Admin Role List',
active: false,
path: '/admin-role/list'
},
{
title: 'Create Admin Role',
active: true,
path: '/admin-role/create'
},
],
}
}
}
</script>
@@ -0,0 +1,59 @@
<template>
<div>
<page-title
:heading="heading"
:icon="icon"
:add="true"
></page-title>
<breadcrumb
:menu_item_list="menu_item_list"
></breadcrumb>
<admin-role-form
:mode="'edit'"
></admin-role-form>
</div>
</template>
<script>
import PageTitle from "../../components/titles/PageTitle";
import Breadcrumb from "../../layouts/parts/Breadcrumb";
import AdminRoleForm from "./Form";
export default {
metaInfo() {
let vm = this;
return {
title: Constants.site.title,
titleTemplate: '%s | ' + vm.$router.currentRoute.name
}
},
components: {
PageTitle,
Breadcrumb,
AdminRoleForm
},
data() {
let vm = this;
return {
heading: 'Edit Admin Role',
icon: 'fa fa-edit',
menu_item_list: [
{
title: 'Dashboard',
active: false,
path: '/'
},
{
title: 'Admin Role List',
active: false,
path: '/admin-role/list'
},
{
title: 'Edit Admin Role',
active: true,
path: '/admin-role/edit/' + vm.$route.params.hash_id
},
]
}
}
}
</script>
@@ -0,0 +1,75 @@
<template>
<b-col md="12">
<form @submit.prevent="$emit('clicked')" @keydown="form.errors.clear($event.target.name)">
<text-input
:input_name="'name'"
:form="form"
:label="'Name'"
>
</text-input>
<select-option-auto-complete-input
:input_name="'status'"
:form="form"
:exist_data="exist_role_status"
:placeholder="''"
:label="'Status'"
:data_set="role_status"
:array="true"
></select-option-auto-complete-input>
<v-btn
depressed
small
type="submit"
color="primary"
class="m-0"
>
Submit
</v-btn>
<v-btn
depressed
small
type="button"
color="warning"
class="m-0"
@click="$emit('reset')"
>
Reset
</v-btn>
</form>
</b-col>
</template>
<script>
import TextInput from '../../components/inputs/TextInput';
import SelectOptionAutoCompleteInput from '../../components/inputs/SelectOptionAutoCompleteInput';
export default {
props: {
form: Object
},
components: {
TextInput,
SelectOptionAutoCompleteInput
},
data() {
let vm = this;
return {
exist_role_status: [],
role_status: General.autoCompleteKeyConvert(Constants.role_status)
}
},
methods: {
initForm() {
let vm = this;
if (vm.form.status[0]) {
let status_list = [];
vm.exist_role_status = General.initFormArray(vm.role_status, vm.form.status);
}
}
},
created() {
let vm = this;
vm.initForm();
}
}
</script>
@@ -0,0 +1,127 @@
<template>
<b-card class="main-card mb-3">
<div v-if="!this_admin_role.data && mode == 'edit'" class="text-center">
<vue-element-loading :active="true" spinner="line-scale" color="var(--primary)"></vue-element-loading>
</div>
<div v-if="this_admin_role.data || mode == 'create'">
<form-wizard
@on-complete="onComplete"
title=""
subtitle=""
finish-button-text="Submit"
@keydown="form.errors.clear($event.target.name)"
color="var(--primary)"
>
<tab-content
title="Details"
:before-change="validOne"
ref="valid_one"
icon="fa fa-info-circle"
>
<!-- ///////////////////////////////////////////////////// -->
<text-input
:input_name="'name'"
:form="form"
:label="'Name*'"
></text-input>
<!-- ///////////////////////////////////////////////////// -->
<switch-list-input
:input_name="'permission_id'"
:form="form"
:label="'Permission*'"
:list="permission_list"
></switch-list-input>
<!-- ///////////////////////////////////////////////////// -->
<switch-input
:input_name="'status'"
:form="form"
:label="'Status'"
></switch-input>
<!-- ///////////////////////////////////////////////////// -->
</tab-content>
</form-wizard>
</div>
</b-card>
</template>
<script>
import TextInput from '../../components/inputs/TextInput';
import SwitchListInput from '../../components/inputs/SwitchListInput';
import SwitchInput from '../../components/inputs/SwitchInput';
export default {
props: {
mode: String
},
components: {
TextInput,
SwitchListInput,
SwitchInput
},
data() {
return {
form: new Form({
name: '',
permission_id: [],
status: 1
}),
this_admin_role: [],
permission_list: [],
}
},
methods: {
validOne() {
let vm = this;
let ref_inputs = ['name', 'permission_id', 'status'];
let url = vm.mode == 'create' ? 'admin-role/valid-check' : 'admin-role/valid-check/' + vm.this_admin_role.data.hash_id;
return General.validCheck(url, vm.form, ref_inputs);
},
onComplete() {
let vm = this;
let method = vm.mode == 'create' ? 'post' : 'put';
let url = vm.mode == 'create' ? 'admin-role/store' : 'admin-role/update/' + vm.this_admin_role.data.hash_id;
return General.onComplete(url, vm.form, method)
.then(data => {
let pervious_query = data.pervious_query ? '?' + data.pervious_query : '';
vm.$router.push('/admin-role/list' + pervious_query);
if (vm.mode == 'create') {
General.toastedMessage('create', 'Admin Role', data.data.name);
}
else {
General.toastedMessage('edit', 'Admin Role', data.data.name);
}
});
},
getAllPermissionList() {
let vm = this;
let url = 'permission/list';
let form = new Form({
'guard_name': 'admin'
});
General.getCall(url, form).then(response => {
vm.permission_list = General.selectStructure(response.data, 'hash_id', 'name');
});
},
loadThisRole() {
let vm = this;
let url = 'admin-role/show/' + vm.$route.params.hash_id;
let form = new Form({});
General.getCall(url, form).then(response => {
vm.this_admin_role = response;
vm.form.name = vm.this_admin_role.data.name;
vm.form.status = vm.this_admin_role.data.status;
vm.form.permission_id = General.getKey(vm.this_admin_role.data.permission_list, 'hash_id');
});
}
},
created() {
let vm = this;
vm.getAllPermissionList();
if (vm.mode == 'edit') {
vm.loadThisRole();
}
}
}
</script>
@@ -0,0 +1,51 @@
<template>
<div>
<page-title
:heading="heading"
:icon="icon"
:add="true"
></page-title>
<breadcrumb
:menu_item_list=menu_item_list
></breadcrumb>
<admin-role-table></admin-role-table>
</div>
</template>
<script>
import PageTitle from "../../components/titles/PageTitle";
import Breadcrumb from "../../layouts/parts/Breadcrumb";
import AdminRoleTable from "./Table";
export default {
metaInfo() {
let vm = this;
return {
title: Constants.site.title,
titleTemplate: '%s | ' + vm.$router.currentRoute.name
}
},
components: {
PageTitle,
Breadcrumb,
AdminRoleTable
},
data() {
return {
heading: 'Admin Role List',
icon: 'fa fa-list',
menu_item_list: [
{
title: 'Dashboard',
active: false,
path: '/'
},
{
title: 'Admin Role List',
active: true,
path: 'list'
},
],
}
}
}
</script>
@@ -0,0 +1,198 @@
<template>
<div>
<b-card class="main-card mb-4">
<b-row class="mb-2" no-gutters>
<b-col md="6">
<button type="button" class="btn btn-primary" @click="filterToggle">
<i class="fa fa-filter"></i>
</button>
<div v-if="filter_status" class="filter dropdown-menu show">
<admin-role-filter
:form="form"
@clicked="filterSubmit"
@reset="FilterReset"
></admin-role-filter>
</div>
</b-col>
<b-col md="6" v-if="permission_list.includes('add role')" class="text-right">
<router-link
class="btn btn-primary"
to="create"
tag="button"
>
<i class="fa fa-plus"></i>
</router-link>
</b-col>
</b-row>
<table class="table table-striped">
<thead>
<paginate-nav
v-if="admin_role_list.page"
:colspan="colspan"
:pervious_page="admin_role_list.page.pervious_page"
:next_page="admin_role_list.page.next_page"
@clicked="dataHandler"
></paginate-nav>
<tr>
<th>#</th>
<th>Name</th>
<th>Permission</th>
<th>Status</th>
<th>Created</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-if="admin_role_list.data" v-for="(role, $index) in admin_role_list.data" :key="$index">
<td>{{ $index + 1 }}</td>
<td>
{{ role.name }}
</td>
<td>
<b-row>
<b-col
v-if="role.permission_list"
v-for="(permission, $index_permission) in role.permission_list"
:key="$index_permission"
md="3"
>
{{ permission.name }}
</b-col>
</b-row>
</td>
<td>
<span :class="'badge badge-' + role.status[0].color">{{ role.status[0].name }}</span>
</td>
<td>
{{ role.created_at }}
</td>
<td>
<router-link
v-if="permission_list.includes('edit role')"
:to="'edit/' + role.hash_id"
class="btn btn-xs btn-light"
title="Edit"
>
<i class="fa fa-edit"></i>
</router-link>
</td>
</tr>
<tr v-if="!admin_role_list.data || !admin_role_list.data[0]">
<td class="text-center" :colspan="colspan">
<vue-element-loading v-if="loading" :active="true" spinner="line-scale" color="var(--primary)"></vue-element-loading>
<span v-if="!loading">Empty</span>
</td>
</tr>
</tbody>
<tfoot v-if="admin_role_list.page">
<paginate-nav
:colspan="colspan"
:pervious_page="admin_role_list.page.pervious_page"
:next_page="admin_role_list.page.next_page"
@clicked="dataHandler"
>
</paginate-nav>
<tr>
<td class="text-right" :colspan="colspan">
<small>Total: {{ admin_role_list.total }}</small>
</td>
</tr>
</tfoot>
</table>
</b-card>
</div>
</template>
<script>
import AdminRoleFilter from "./Filter";
import PaginateNav from '../../components/paginations/NextPerviousPagination';
export default {
components: {
AdminRoleFilter,
PaginateNav
},
data() {
return {
form: new Form({
name: General.getURLParam('name'),
status: General.returnAray(General.getURLParam('status[]')),
page: General.getURLParam('page')
}),
colspan: 6,
filter_status: false,
loading: true,
admin_role_list: [],
selected_img: [],
permission_list: []
}
},
methods: {
getPermissionList() {
let vm = this;
let url = 'admin/self';
let form = new Form({});
General.getCall(url, form).then(response => {
vm.permission_list = response.data.permission_list;
});
},
getAdminRoleList() {
let vm = this;
let url = 'admin-role/list';
vm.tableCall(url);
},
tableCall(url) {
let vm = this;
vm.loading = true;
General.tableCall(url, vm.form).then(response => {
vm.loading = false;
vm.admin_role_list = response;
vm.form.page = General.getURLParam('page');
vm.convertStatus();
});
},
convertStatus() {
let vm = this;
vm.admin_role_list.data.forEach(function(element, index) {
element.status = General.initFormArray(Constants.role_status, [element.status]);
});
},
dataHandler(url) {
let vm = this;
vm.form.page = General.getStringParam('page', url);
vm.tableCall('admin-role/list');
},
filterToggle() {
let vm = this;
vm.filter_status = !vm.filter_status;
},
filterCloseClick(e) {
let vm = this;
if (!vm.$el.contains(e.target) && !e.target.classList.contains('filter')) {
vm.filter_status = false;
}
},
filterSubmit() {
let vm = this;
let url = 'admin-role/list';
vm.form.page = '';
vm.tableCall(url);
vm.filterToggle();
},
FilterReset() {
let vm = this;
vm.form.reset();
vm.filterSubmit();
}
},
mounted() {
let vm = this;
document.addEventListener('click', vm.filterCloseClick);
},
created() {
let vm = this;
vm.getPermissionList();
vm.getAdminRoleList();
}
}
</script>
@@ -0,0 +1,58 @@
<template>
<div>
<page-title
:heading="heading"
:icon="icon"
:add="true"
></page-title>
<breadcrumb
:menu_item_list="menu_item_list"
></breadcrumb>
<admin-form
:mode="'create'"
></admin-form>
</div>
</template>
<script>
import PageTitle from "../../components/titles/PageTitle";
import Breadcrumb from "../../layouts/parts/Breadcrumb";
import AdminForm from "./Form";
export default {
metaInfo() {
let vm = this;
return {
title: Constants.site.title,
titleTemplate: '%s | ' + vm.$router.currentRoute.name
}
},
components: {
PageTitle,
Breadcrumb,
AdminForm
},
data() {
return {
heading: 'Create Admin',
icon: 'fa fa-plus',
menu_item_list: [
{
title: 'Dashboard',
active: false,
path: '/'
},
{
title: 'Admin List',
active: false,
path: '/admin/list'
},
{
title: 'Create Admin',
active: true,
path: '/admin/create'
},
],
}
}
}
</script>
+59
View File
@@ -0,0 +1,59 @@
<template>
<div>
<page-title
:heading="heading"
:icon="icon"
:add="true"
></page-title>
<breadcrumb
:menu_item_list="menu_item_list"
></breadcrumb>
<admin-form
:mode="'edit'"
></admin-form>
</div>
</template>
<script>
import PageTitle from "../../components/titles/PageTitle";
import Breadcrumb from "../../layouts/parts/Breadcrumb";
import AdminForm from "./Form";
export default {
metaInfo() {
let vm = this;
return {
title: Constants.site.title,
titleTemplate: '%s | ' + vm.$router.currentRoute.name
}
},
components: {
PageTitle,
Breadcrumb,
AdminForm
},
data() {
let vm = this;
return {
heading: 'Edit Admin',
icon: 'fa fa-edit',
menu_item_list: [
{
title: 'Dashboard',
active: false,
path: '/'
},
{
title: 'Admin List',
active: false,
path: '/admin/list'
},
{
title: 'Edit Admin',
active: true,
path: '/admin/edit/' + vm.$route.params.hash_id
},
]
}
}
}
</script>
@@ -0,0 +1,81 @@
<template>
<b-col md="12">
<form @submit.prevent="$emit('clicked')" @keydown="form.errors.clear($event.target.name)">
<text-input
:input_name="'name'"
:form="form"
:label="'Name'"
>
</text-input>
<text-input
:input_name="'email'"
:form="form"
:label="'Email'"
>
</text-input>
<select-option-auto-complete-input
:input_name="'status'"
:form="form"
:exist_data="exist_admin_status"
:placeholder="''"
:label="'Status'"
:data_set="admin_status"
:array="true"
></select-option-auto-complete-input>
<v-btn
depressed
small
type="submit"
color="primary"
class="m-0"
>
Submit
</v-btn>
<v-btn
depressed
small
type="button"
color="warning"
class="m-0"
@click="$emit('reset')"
>
Reset
</v-btn>
</form>
</b-col>
</template>
<script>
import TextInput from '../../components/inputs/TextInput';
import SelectOptionAutoCompleteInput from '../../components/inputs/SelectOptionAutoCompleteInput';
export default {
props: {
form: Object
},
components: {
TextInput,
SelectOptionAutoCompleteInput
},
data() {
let vm = this;
return {
exist_admin_status: [],
admin_status: General.autoCompleteKeyConvert(Constants.admin_status)
}
},
methods: {
initForm() {
let vm = this;
if (vm.form.status[0]) {
let status_list = [];
vm.exist_admin_status = General.initFormArray(vm.admin_status, vm.form.status);
}
}
},
created() {
let vm = this;
vm.initForm();
}
}
</script>
+170
View File
@@ -0,0 +1,170 @@
<template>
<b-card class="main-card mb-3">
<div v-if="!this_admin.data && mode == 'edit'" class="text-center">
<vue-element-loading :active="true" spinner="line-scale" color="var(--primary)"></vue-element-loading>
</div>
<div v-if="this_admin.data || mode == 'create'">
<form-wizard
@on-complete="onComplete"
title=""
subtitle=""
finish-button-text="Submit"
@keydown="form.errors.clear($event.target.name)"
color="var(--primary)"
>
<tab-content
title="Details"
:before-change="validOne"
ref="valid_one"
icon="fa fa-info-circle"
>
<!-- ///////////////////////////////////////////////////// -->
<image-input
:input_name="'img'"
:form="form"
:label="'Profile Img'"
:exist_img="exist_img"
></image-input>
<!-- ///////////////////////////////////////////////////// -->
<text-input
:input_name="'name'"
:form="form"
:label="'Name*'"
></text-input>
<!-- ///////////////////////////////////////////////////// -->
<text-input
:input_name="'email'"
:form="form"
:label="'Email*'"
></text-input>
<!-- ///////////////////////////////////////////////////// -->
<password-input
:input_name="'password'"
:form="form"
:label="'Password*'"
></password-input>
<!-- ///////////////////////////////////////////////////// -->
<password-input
:input_name="'password_confirmation'"
:form="form"
:label="'Confirm Password*'"
></password-input>
<!-- ///////////////////////////////////////////////////// -->
<select-option-auto-complete-input
v-if="mode != 'profile'"
:input_name="'role_id'"
:form="form"
:exist_data="exist_admin_role"
:placeholder="''"
:label="'Role*'"
:endpoint="'admin-role/list'"
:search_field="'name'"
:limit_tag="1"
:return_key="'hash_id'"
></select-option-auto-complete-input>
<!-- ///////////////////////////////////////////////////// -->
<text-read-only-input
v-if="mode == 'profile'"
:value="this_admin.data.role_list[0].name"
:label="'Role'"
>
</text-read-only-input>
<!-- ///////////////////////////////////////////////////// -->
<switch-input
:input_name="'status'"
:form="form"
:label="'Status'"
></switch-input>
<!-- ///////////////////////////////////////////////////// -->
</tab-content>
</form-wizard>
</div>
</b-card>
</template>
<script>
import TextInput from '../../components/inputs/TextInput';
import TextReadOnlyInput from '../../components/inputs/TextReadOnlyInput';
import PasswordInput from '../../components/inputs/PasswordInput';
import SwitchInput from '../../components/inputs/SwitchInput';
import SelectOptionAutoCompleteInput from '../../components/inputs/SelectOptionAutoCompleteInput';
import ImageInput from '../../components/inputs/ImageInput';
export default {
props: {
mode: String
},
components: {
TextInput,
TextReadOnlyInput,
PasswordInput,
SelectOptionAutoCompleteInput,
SwitchInput,
ImageInput
},
data() {
return {
form: new Form({
img: [],
name: '',
email: '',
password: '',
password_confirmation: '',
role_id: [],
status: 1
}),
this_admin: [],
exist_img: [],
exist_admin_role: []
}
},
methods: {
validOne() {
let vm = this;
let ref_inputs = ['img', 'name', 'email', 'password', 'password_confirmation', 'role_id', 'status'];
let url = vm.mode == 'create' ? 'admin/valid-check' : 'admin/valid-check/' + vm.this_admin.data.hash_id;
return General.validCheck(url, vm.form, ref_inputs);
},
onComplete() {
let vm = this;
let method = vm.mode == 'create' ? 'post' : 'put';
let url = vm.mode == 'create' ? 'admin/store' : 'admin/update/' + vm.this_admin.data.hash_id;
return General.onComplete(url, vm.form, method)
.then(data => {
if (vm.mode != 'profile') {
let pervious_query = data.pervious_query ? '?' + data.pervious_query : '';
vm.$router.push('/admin/list' + pervious_query);
}
if (vm.mode == 'create') {
General.toastedMessage('create', 'Admin', data.data.name);
}
else {
General.toastedMessage('edit', 'Admin', data.data.name);
}
});
},
loadThisAdmin() {
let vm = this;
let url = vm.mode == 'edit' ? 'admin/show/' + vm.$route.params.hash_id : 'admin/self';
let form = new Form({});
General.getCall(url, form).then(data => {
vm.this_admin = data;
vm.exist_img = vm.this_admin.data.img;
vm.form.name = vm.this_admin.data.name;
vm.form.email = vm.this_admin.data.email;
vm.form.status = vm.this_admin.data.status;
vm.form.role_id = General.getKey(vm.this_admin.data.role_list, 'id');
vm.exist_admin_role = General.autoCompleteKeyConvert(vm.this_admin.data.role_list);
});
}
},
created() {
let vm = this;
if (vm.mode == 'edit' || vm.mode == 'profile') {
vm.loadThisAdmin();
}
}
}
</script>
+51
View File
@@ -0,0 +1,51 @@
<template>
<div>
<page-title
:heading="heading"
:icon="icon"
:add="true"
></page-title>
<breadcrumb
:menu_item_list=menu_item_list
></breadcrumb>
<admin-table></admin-table>
</div>
</template>
<script>
import PageTitle from "../../components/titles/PageTitle";
import Breadcrumb from "../../layouts/parts/Breadcrumb";
import AdminTable from "./Table";
export default {
metaInfo() {
let vm = this;
return {
title: Constants.site.title,
titleTemplate: '%s | ' + vm.$router.currentRoute.name
}
},
components: {
PageTitle,
Breadcrumb,
AdminTable
},
data() {
return {
heading: 'Admin List',
icon: 'fa fa-list',
menu_item_list: [
{
title: 'Dashboard',
active: false,
path: '/'
},
{
title: 'Admin List',
active: true,
path: 'list'
},
],
}
}
}
</script>
@@ -0,0 +1,59 @@
<template>
<div>
<page-title
:heading="heading"
:icon="icon"
:add="true"
></page-title>
<breadcrumb
:menu_item_list="menu_item_list"
></breadcrumb>
<admin-form
:mode="'profile'"
></admin-form>
</div>
</template>
<script>
import PageTitle from "../../components/titles/PageTitle";
import Breadcrumb from "../../layouts/parts/Breadcrumb";
import AdminForm from "./Form";
export default {
metaInfo() {
let vm = this;
return {
title: Constants.site.title,
titleTemplate: '%s | ' + vm.$router.currentRoute.name
}
},
components: {
PageTitle,
Breadcrumb,
AdminForm
},
data() {
let vm = this;
return {
heading: 'Edit Profile',
icon: 'fa fa-edit',
menu_item_list: [
{
title: 'Dashboard',
active: false,
path: '/'
},
{
title: 'Admin List',
active: false,
path: '/admin/list'
},
{
title: 'Edit Profile',
active: true,
path: '/admin/edit/' + vm.$route.params.hash_id
},
]
}
}
}
</script>
+211
View File
@@ -0,0 +1,211 @@
<template>
<div>
<b-card class="main-card mb-4">
<b-row class="mb-2" no-gutters>
<b-col md="6">
<button type="button" class="btn btn-primary" @click="filterToggle">
<i class="fa fa-filter"></i>
</button>
<div v-if="filter_status" class="filter dropdown-menu show">
<admin-filter
:form="form"
@clicked="filterSubmit"
@reset="FilterReset"
></admin-filter>
</div>
</b-col>
<b-col md="6" v-if="permission_list.includes('add admin')" class="text-right">
<router-link
class="btn btn-primary"
to="create"
tag="button"
>
<i class="fa fa-plus"></i>
</router-link>
</b-col>
</b-row>
<table class="table table-striped">
<thead>
<paginate-nav
v-if="admin_list.page"
:colspan="colspan"
:pervious_page="admin_list.page.pervious_page"
:next_page="admin_list.page.next_page"
@clicked="dataHandler"
></paginate-nav>
<tr>
<th>#</th>
<th>Profile</th>
<th style="width: 25%">Details</th>
<th>Role</th>
<th>Status</th>
<th>Created</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-if="admin_list.data" v-for="(admin, $index) in admin_list.data" :key="$index">
<td>{{ $index + 1 }}</td>
<td>
<img class="img-fluid pointer-cursor"
:src="admin.img[0].file_info.original.file" width="60px" height="60px"
@click="ImgPopModalToggle(admin.img)"
>
</td>
<td>
<div><b>Name</b>: {{ admin.name }}</div>
<div><b>Email</b>: {{ admin.email }}</div>
<div><b>Country</b>: {{ admin.country_list[0].name }}</div>
</td>
<td>
{{ admin.role_list[0].name }}
</td>
<td>
<span :class="'badge badge-' + admin.status[0].color">{{ admin.status[0].name }}</span>
</td>
<td>
{{ admin.created_at }}
</td>
<td>
<router-link
v-if="permission_list.includes('edit admin')"
:to="'edit/' + admin.hash_id"
class="btn btn-xs btn-light"
title="Edit"
>
<i class="fa fa-edit"></i>
</router-link>
</td>
</tr>
<tr v-if="!admin_list.data || !admin_list.data[0]">
<td class="text-center" :colspan="colspan">
<vue-element-loading v-if="loading" :active="true" spinner="line-scale" color="var(--primary)"></vue-element-loading>
<span v-if="!loading">Empty</span>
</td>
</tr>
</tbody>
<tfoot v-if="admin_list.page">
<paginate-nav
:colspan="colspan"
:pervious_page="admin_list.page.pervious_page"
:next_page="admin_list.page.next_page"
@clicked="dataHandler"
>
</paginate-nav>
<tr>
<td class="text-right" :colspan="colspan">
<small>Total: {{ admin_list.total }}</small>
</td>
</tr>
</tfoot>
</table>
</b-card>
<img-pop-modal
:label="'Profile'"
:img="selected_img"
>
</img-pop-modal>
</div>
</template>
<script>
import AdminFilter from "./Filter";
import ImgPopModal from "../../components/modals/ImgPopModal";
import PaginateNav from '../../components/paginations/NextPerviousPagination';
export default {
components: {
AdminFilter,
ImgPopModal,
PaginateNav
},
data() {
return {
form: new Form({
name: General.getURLParam('name'),
email: General.getURLParam('email'),
status: General.returnAray(General.getURLParam('status[]')),
page: General.getURLParam('page')
}),
colspan: 7,
filter_status: false,
loading: true,
admin_list: [],
selected_img: [],
permission_list: []
}
},
methods: {
ImgPopModalToggle(img) {
let vm = this;
vm.selected_img = img;
vm.$bvModal.show('img-pop-modal');
},
getPermissionList() {
let vm = this;
let url = 'admin/self';
let form = new Form({});
General.getCall(url, form).then(response => {
vm.permission_list = response.data.permission_list;
});
},
getAdminList() {
let vm = this;
let url = 'admin/list';
vm.tableCall(url);
},
tableCall(url) {
let vm = this;
vm.loading = true;
General.tableCall(url, vm.form).then(response => {
vm.loading = false;
vm.admin_list = response;
vm.form.page = General.getURLParam('page');
vm.convertStatus();
});
},
convertStatus() {
let vm = this;
vm.admin_list.data.forEach(function(element, index) {
element.status = General.initFormArray(Constants.admin_status, [element.status]);
});
},
dataHandler(url) {
let vm = this;
vm.form.page = General.getStringParam('page', url);
vm.tableCall('admin/list');
},
filterToggle() {
let vm = this;
vm.filter_status = !vm.filter_status;
},
filterCloseClick(e) {
let vm = this;
if (!vm.$el.contains(e.target) && !e.target.classList.contains('filter')) {
vm.filter_status = false;
}
},
filterSubmit() {
let vm = this;
let url = 'admin/list';
vm.form.page = '';
vm.tableCall(url);
vm.filterToggle();
},
FilterReset() {
let vm = this;
vm.form.reset();
vm.filterSubmit();
}
},
mounted() {
let vm = this;
document.addEventListener('click', vm.filterCloseClick);
},
created() {
let vm = this;
vm.getPermissionList();
vm.getAdminList();
}
}
</script>
@@ -0,0 +1,34 @@
<template>
<div>
<page-title :heading=heading :icon=icon></page-title>
</div>
</template>
<script>
import PageTitle from "../../components/titles/PageTitle.vue";
export default {
metaInfo() {
let vm = this;
return {
title: Constants.site.title,
titleTemplate: '%s | ' + vm.$router.currentRoute.name
}
},
components: {
PageTitle,
},
data() {
return {
heading: 'Analytics Dashboard',
icon: 'fa fa-home',
}
},
methods: {
},
created() {
let vm = this;
}
}
</script>
+132
View File
@@ -0,0 +1,132 @@
<template>
<div>
<div class="vh-100 bg-plum-plate bg-animation">
<div class="">
<div class="app-header header-shadow bg-light text-lighter">
<router-link
:to="'/'"
class="btn-link pl-3"
>
<div class="logo-src" :style='{ background: "url(" + share_url + "favicon.png" + ")" }'></div>
</router-link>
<div class="pl-3 app-header-title">
<h5 class="card-title">Login</h5>
</div>
</div>
<div class="d-flex justify-content-center align-items-center">
<b-col md="4" class="top-margin-100">
<div class="mx-auto p-0 m-0">
<form @submit.prevent="onSubmit" @keydown="form.errors.clear($event.target.name)">
<div class="modal-content">
<div class="modal-body">
<div class="h5 modal-title text-center">
<div class="m-3 text-center">
<img class="img-fluid big-logo" :src="share_url + 'logo.png'">
</div>
</div>
<!-- ///////////////////////////////////////////////////// -->
<text-input
:input_name="'email'"
:form="form"
:label="'Email'"
>
</text-input>
<!-- ///////////////////////////////////////////////////// -->
<password-input
:input_name="'password'"
:form="form"
:label="'Password'"
>
</password-input>
<!-- ///////////////////////////////////////////////////// -->
</div>
<div class="modal-footer">
<div>
<v-btn
:loading="loading"
:disabled="loading"
:block="true"
type="submit"
color="primary"
class="white--text"
@click="loader = 'loading'"
>
Login
</v-btn>
</div>
</div>
</div>
</form>
</div>
</b-col>
</div>
<div class="footer text-center text-white opacity-8 p-3">
Copyright &copy; {{ site_title }} {{ year }}
</div>
</div>
</div>
</div>
</template>
<script>
import TextInput from '../../components/inputs/TextInput';
import PasswordInput from '../../components/inputs/PasswordInput';
export default {
metaInfo() {
let vm = this;
return {
title: Constants.site.title,
titleTemplate: '%s | ' + vm.$router.currentRoute.name
}
},
components: {
TextInput,
PasswordInput
},
data() {
let vm = this;
return {
form: new Form({
email: '',
password: ''
}),
site_title: Constants.site.title,
site_short_title: Constants.site.short_title,
share_url: ENV.SHARE_URL,
year: General.getYear(),
loader: null,
loading: false
}
},
methods: {
onSubmit() {
let vm = this;
const l = vm.loader
vm[l] = !vm[l]
vm.form.post(
ENV.API_URL + 'login',
{
'App-Key': ENV.APP_KEY
}
)
.then(response => {
localStorage.setItem('admin_detail',JSON.stringify(response.data))
localStorage.setItem('admin_jwt', response.access_token);
if (localStorage.getItem('admin_jwt') != null) {
window.location.replace(ENV.APP_URL + '/');
}
})
.catch(function (error) {
vm[l] = false
vm.loader = null;
});
}
},
created() {
let vm = this;
}
}
</script>
@@ -0,0 +1,53 @@
<template>
<div>
<div class="vh-100 bg-plum-plate bg-animation">
<div class="">
<div class="app-header header-shadow bg-light text-lighter">
<router-link
:to="'/'"
class="btn-link pl-3"
>
<div class="logo-src" :style='{ background: "url(" + share_url + "favicon.png" + ")" }'></div>
</router-link>
<div class="pl-3 app-header-title">
<h5 class="card-title">Page 404</h5>
</div>
</div>
<div class="d-flex justify-content-center align-items-center">
<b-col class="mobile-none top-margin-100" md="5">
<div class="mb-3 text-center">
<img class="img-fluid big-logo" :src="share_url + 'logo.png'">
</div>
<div class="text-white text-center">
<h1 class="mb-2">Page 404</h1>
</div>
</b-col>
</div>
<div class="footer text-center text-white opacity-8 p-3">
Copyright &copy; {{ site_title }} {{ year }}
</div>
</div>
</div>
</div>
</template>
<script>
export default {
metaInfo() {
let vm = this;
return {
title: Constants.site.title,
titleTemplate: '%s | ' + vm.$router.currentRoute.name
}
},
data() {
let vm = this;
return {
share_url: ENV.SHARE_URL,
site_title: Constants.site.title,
year: General.getYear()
}
}
}
</script>
+59
View File
@@ -0,0 +1,59 @@
<template>
<div>
<page-title
:heading="heading"
:icon="icon"
:add="true"
></page-title>
<breadcrumb
:menu_item_list="menu_item_list"
></breadcrumb>
<user-form
:mode="'create'"
></user-form>
</div>
</template>
<script>
import PageTitle from "../../components/titles/PageTitle";
import Breadcrumb from "../../layouts/parts/Breadcrumb";
import UserForm from "./Form";
export default {
metaInfo() {
let vm = this;
return {
title: Constants.site.title,
titleTemplate: '%s | ' + vm.$router.currentRoute.name
}
},
components: {
PageTitle,
Breadcrumb,
UserForm
},
data() {
let vm = this;
return {
heading: 'User Detail',
icon: 'fa fa-plus',
menu_item_list: [
{
title: 'Dashboard',
active: false,
path: '/'
},
{
title: 'User List',
active: false,
path: '/user/list'
},
{
title: 'User Detail',
active: true,
path: '/user/detail/' + vm.$route.params.hash_id
},
],
}
}
}
</script>
+81
View File
@@ -0,0 +1,81 @@
<template>
<b-col md="12">
<form @submit.prevent="$emit('clicked')" @keydown="form.errors.clear($event.target.name)">
<text-input
:input_name="'name'"
:form="form"
:label="'Name'"
>
</text-input>
<text-input
:input_name="'email'"
:form="form"
:label="'Email'"
>
</text-input>
<select-option-auto-complete-input
:input_name="'status'"
:form="form"
:exist_data="exist_user_status"
:placeholder="''"
:label="'Status'"
:data_set="user_status"
:array="true"
></select-option-auto-complete-input>
<v-btn
depressed
small
type="submit"
color="primary"
class="m-0"
>
Submit
</v-btn>
<v-btn
depressed
small
type="button"
color="warning"
class="m-0"
@click="$emit('reset')"
>
Reset
</v-btn>
</form>
</b-col>
</template>
<script>
import TextInput from '../../components/inputs/TextInput';
import SelectOptionAutoCompleteInput from '../../components/inputs/SelectOptionAutoCompleteInput';
export default {
props: {
form: Object
},
components: {
TextInput,
SelectOptionAutoCompleteInput
},
data() {
let vm = this;
return {
exist_user_status: [],
user_status: General.autoCompleteKeyConvert(Constants.user_status)
}
},
methods: {
initForm() {
let vm = this;
if (vm.form.status[0]) {
let status_list = [];
vm.exist_user_status = General.initFormArray(vm.user_status, vm.form.status);
}
}
},
created() {
let vm = this;
vm.initForm();
}
}
</script>
+97
View File
@@ -0,0 +1,97 @@
<template>
<b-card class="main-card mb-3">
<div v-if="!this_user.data" class="text-center">
<vue-element-loading :active="true" spinner="line-scale" color="var(--primary)"></vue-element-loading>
</div>
<div v-if="this_user.data">
<form-wizard
@on-complete="onComplete"
title=""
subtitle=""
finish-button-text="Back"
@keydown="form.errors.clear($event.target.name)"
color="var(--primary)"
>
<tab-content
title="Details"
icon="fa fa-info-circle"
>
<image-read-only-input
:label="'Profile'"
:exist_img="this_user.data.img"
>
</image-read-only-input>
<!-- ///////////////////////////////////////////////////// -->
<text-read-only-input
:label="'Username'"
:value="this_user.data.username"
>
</text-read-only-input>
<!-- ///////////////////////////////////////////////////// -->
<text-read-only-input
:label="'Email'"
:value="this_user.data.email"
>
</text-read-only-input>
<!-- ///////////////////////////////////////////////////// -->
<text-read-only-input
:label="'Country'"
:value="this_user.data.country_list[0].name"
>
</text-read-only-input>
<!-- ///////////////////////////////////////////////////// -->
<text-read-only-input
:label="'Status'"
:value="this_user.data.status[0].name"
>
</text-read-only-input>
<!-- ///////////////////////////////////////////////////// -->
</tab-content>
</form-wizard>
</div>
</b-card>
</template>
<script>
import TextReadOnlyInput from '../../components/inputs/TextReadOnlyInput';
import ImageReadOnlyInput from '../../components/inputs/ImageReadOnlyInput';
export default {
props: {
mode: String
},
components: {
TextReadOnlyInput,
ImageReadOnlyInput
},
data() {
return {
this_user: [],
}
},
methods: {
onComplete() {
let vm = this;
vm.$router.push('/user/list');
return true;
},
loadThisUser() {
let vm = this;
let url = 'user/show/' + vm.$route.params.hash_id;
let form = new Form({});
General.getCall(url, form).then(response => {
vm.this_user = response;
vm.convertStatus();
});
},
convertStatus() {
let vm = this;
vm.this_user.data.status = General.initFormArray(Constants.admin_status, [vm.this_user.data.status]);
},
},
created() {
let vm = this;
vm.loadThisUser();
}
}
</script>
+51
View File
@@ -0,0 +1,51 @@
<template>
<div>
<page-title
:heading="heading"
:icon="icon"
:add="true"
></page-title>
<breadcrumb
:menu_item_list=menu_item_list
></breadcrumb>
<user-table></user-table>
</div>
</template>
<script>
import PageTitle from "../../components/titles/PageTitle";
import Breadcrumb from "../../layouts/parts/Breadcrumb";
import UserTable from "./Table";
export default {
metaInfo() {
let vm = this;
return {
title: Constants.site.title,
titleTemplate: '%s | ' + vm.$router.currentRoute.name
}
},
components: {
PageTitle,
Breadcrumb,
UserTable
},
data() {
return {
heading: 'User List',
icon: 'fa fa-list',
menu_item_list: [
{
title: 'Dashboard',
active: false,
path: '/'
},
{
title: 'User List',
active: true,
path: 'list'
},
],
}
}
}
</script>
+199
View File
@@ -0,0 +1,199 @@
<template>
<div>
<b-card class="main-card mb-4">
<b-row class="mb-2" no-gutters>
<b-col md="6">
<button type="button" class="btn btn-primary" @click="filterToggle">
<i class="fa fa-filter"></i>
</button>
<div v-if="filter_status" class="filter dropdown-menu show">
<user-filter
:form="form"
@clicked="filterSubmit"
@reset="FilterReset"
></user-filter>
</div>
</b-col>
</b-row>
<table class="table table-striped">
<thead>
<paginate-nav
v-if="user_list.page"
:colspan="colspan"
:pervious_page="user_list.page.pervious_page"
:next_page="user_list.page.next_page"
@clicked="dataHandler"
></paginate-nav>
<tr>
<th>#</th>
<th>Profile</th>
<th style="width: 25%">Details</th>
<th>Status</th>
<th>Created</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-if="user_list.data" v-for="(user, $index) in user_list.data" :key="$index">
<td>{{ $index + 1 }}</td>
<td>
<img class="img-fluid pointer-cursor"
:src="user.img[0].file_info.original.file" width="60px" height="60px"
@click="ImgPopModalToggle(user.img)"
>
</td>
<td>
<div><b>Name</b>: {{ user.username }}</div>
<div><b>Email</b>: {{ user.email }}</div>
<div><b>Country</b>: {{ user.country_list[0].name }}</div>
</td>
<td>
<span :class="'badge badge-' + user.status[0].color">{{ user.status[0].name }}</span>
</td>
<td>
{{ user.created_at }}
</td>
<td>
<router-link
v-if="permission_list.includes('view user')"
:to="'detail/' + user.hash_id"
class="btn btn-xs btn-light"
title="View"
>
<i class="fa fa-eye"></i>
</router-link>
</td>
</tr>
<tr v-if="!user_list.data || !user_list.data[0]">
<td class="text-center" :colspan="colspan">
<vue-element-loading v-if="loading" :active="true" spinner="line-scale" color="var(--primary)"></vue-element-loading>
<span v-if="!loading">Empty</span>
</td>
</tr>
</tbody>
<tfoot v-if="user_list.page">
<paginate-nav
:colspan="colspan"
:pervious_page="user_list.page.pervious_page"
:next_page="user_list.page.next_page"
@clicked="dataHandler"
>
</paginate-nav>
<tr>
<td class="text-right" :colspan="colspan">
<small>Total: {{ user_list.total }}</small>
</td>
</tr>
</tfoot>
</table>
</b-card>
<img-pop-modal
:label="'Profile'"
:img="selected_img"
>
</img-pop-modal>
</div>
</template>
<script>
import userFilter from "./Filter";
import ImgPopModal from "../../components/modals/ImgPopModal";
import PaginateNav from '../../components/paginations/NextPerviousPagination';
export default {
components: {
userFilter,
ImgPopModal,
PaginateNav
},
data() {
return {
form_permission: new Form({}),
form: new Form({
username: General.getURLParam('username'),
email: General.getURLParam('email'),
status: General.returnAray(General.getURLParam('status[]')),
page: General.getURLParam('page')
}),
colspan: 6,
filter_status: false,
loading: true,
user_list: [],
selected_img: [],
permission_list: []
}
},
methods: {
ImgPopModalToggle(img) {
let vm = this;
vm.selected_img = img;
vm.$bvModal.show('img-pop-modal');
},
getPermissionList() {
let vm = this;
let url = 'admin/self';
let params = {}
General.getCall(url, vm.form_permission).then(response => {
vm.permission_list = response.data.permission_list;
});
},
getUserList() {
let vm = this;
let url = 'user/list';
vm.tableCall(url);
},
tableCall(url) {
let vm = this;
vm.loading = true;
General.tableCall(url, vm.form).then(response => {
vm.loading = false;
vm.user_list = response;
vm.form.page = General.getURLParam('page');
vm.convertStatus();
});
},
convertStatus() {
let vm = this;
vm.user_list.data.forEach(function(element, index) {
element.status = General.initFormArray(Constants.user_status, [element.status]);
});
},
dataHandler(url) {
let vm = this;
vm.form.page = General.getStringParam('page', url);
vm.tableCall('user/list');
},
filterToggle() {
let vm = this;
vm.filter_status = !vm.filter_status;
},
filterCloseClick(e) {
let vm = this;
if (!vm.$el.contains(e.target) && !e.target.classList.contains('filter')) {
vm.filter_status = false;
}
},
filterSubmit() {
let vm = this;
let url = 'user/list';
vm.tableCall(url);
vm.form.page = '';
vm.filterToggle();
},
FilterReset() {
let vm = this;
vm.form.reset();
vm.filterSubmit();
}
},
mounted() {
let vm = this;
document.addEventListener('click', vm.filterCloseClick);
},
created() {
let vm = this;
vm.getPermissionList();
vm.getUserList();
}
}
</script>
+168
View File
@@ -0,0 +1,168 @@
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router);
import Logins from './pages/logins/Index';
import Dashboards from './pages/dashboards/Index';
import UserList from './pages/users/List';
import UserDetail from './pages/users/Detail';
import AdminList from './pages/admins/List';
import AdminCreate from './pages/admins/Create';
import AdminEdit from './pages/admins/Edit';
import AdminProfile from './pages/admins/Profile';
import AdminRoleList from './pages/admin-roles/List';
import AdminRoleCreate from './pages/admin-roles/Create';
import AdminRoleEdit from './pages/admin-roles/Edit';
import PageNotFound from './pages/page-not-founds/Index';
let router = new Router({
mode: 'history',
base: process.env.MIX_SUB_URL + 'admin-sys',
scrollBehavior() {
return window.scrollTo({ top: 0, behavior: 'smooth' });
},
routes: [
/////////////////////////////////////////////////////
// Login
{
path: '/login',
name: 'Login',
meta: {
layout: 'userpages',
guest: true
},
component: Logins
},
/////////////////////////////////////////////////////
// Dashboard
{
path: '/',
name: 'Dashboards',
meta: {
auth: true
},
component: Dashboards
},
/////////////////////////////////////////////////////
// User
{
path: '/user/list',
name: 'User List',
meta: {
auth: true
},
component: UserList
},
{
path: '/user/detail/:hash_id',
name: 'User Detail',
meta: {
auth: true
},
component: UserDetail
},
/////////////////////////////////////////////////////
// Admin
{
path: '/admin/list',
name: 'Admin List',
meta: {
auth: true
},
component: AdminList
},
{
path: '/admin/create',
name: 'Admin Create',
meta: {
auth: true
},
component: AdminCreate
},
{
path: '/admin/edit/:hash_id',
name: 'Admin Edit',
meta: {
auth: true
},
component: AdminEdit
},
{
path: '/admin/profile/update',
name: 'Admin Profile',
meta: {
auth: true
},
component: AdminProfile
},
/////////////////////////////////////////////////////
// Admin Role
{
path: '/admin-role/list',
name: 'Admin Role List',
meta: {
auth: true
},
component: AdminRoleList
},
{
path: '/admin-role/create',
name: 'Admin Role Create',
meta: {
auth: true
},
component: AdminRoleCreate
},
{
path: '/admin-role/edit/:hash_id',
name: 'Admin Role Edit',
meta: {
auth: true
},
component: AdminRoleEdit
},
/////////////////////////////////////////////////////
// 404
{
path: '*',
name: 'Page 404',
meta: {
layout: 'userpages',
guest: true
},
component: PageNotFound
},
/////////////////////////////////////////////////////
]
});
window.ADMIN_DETAIL = localStorage.getItem('admin_detail') != null ? JSON.parse(localStorage.getItem('admin_detail')) : null;
window.TOKEN = localStorage.getItem('admin_jwt');
router.beforeEach((to, from, next) => {
if(to.matched.some(record => record.meta.auth)) {
if (localStorage.getItem('admin_jwt') == null) {
next({ path: 'login' })
}
else {
next();
}
}
if(to.matched.some(record => record.meta.without_auth)) {
if (localStorage.getItem('admin_jwt') != null) {
next({ path: '/' })
}
else {
next();
}
}
next();
});
export default router;
+44
View File
@@ -0,0 +1,44 @@
const Constant = {
'site': {
'title': 'Unity',
'short_title': 'Unity',
'description': 'Unity'
},
'user_status': [
{
'id': 1,
'name': 'Active',
'color': 'primary'
},
{
'id': 2,
'name': 'De-active',
'color': 'danger'
},
],
'admin_status': [
{
'id': 1,
'name': 'Active',
'color': 'primary'
},
{
'id': 2,
'name': 'De-active',
'color': 'danger'
},
],
'role_status': [
{
'id': 1,
'name': 'Active',
'color': 'primary'
},
{
'id': 2,
'name': 'De-active',
'color': 'danger'
},
],
};
export default Constant;
+7
View File
@@ -0,0 +1,7 @@
const ENV = {
'APP_URL': process.env.MIX_APP_URL + 'admin-sys/',
'API_URL': process.env.MIX_API_URL + 'admin-backsys/api/',
'SHARE_URL': process.env.MIX_API_URL + 'share/',
'APP_KEY': process.env.MIX_APP_KEY
};
export default ENV;
+35
View File
@@ -0,0 +1,35 @@
class Errors {
constructor() {
this.errors = {};
}
has(field) {
return this.errors.hasOwnProperty(field);
}
any() {
return Object.keys(this.errors).length > 0;
}
get(field) {
if (this.errors[field]) {
return this.errors[field][0];
}
}
record(errors) {
this.errors = errors;
}
clear(field) {
if (field) {
delete this.errors[field];
return;
}
this.errors = {};
}
}
export default Errors;
+164
View File
@@ -0,0 +1,164 @@
import Errors from './errors';
class Form {
constructor(data) {
this.originalData = data;
for (let field in data) {
this[field] = data[field];
}
this.errors = new Errors();
}
data() {
let data = {};
for (let property in this.originalData) {
data[property] = this[property];
}
return data;
}
reset() {
for (let field in this.originalData) {
this[field] = '';
}
this.errors.clear();
}
get(url, header) {
return this.submit('get', url, header);
}
post(url, header) {
return this.submit('post', url, header);
}
put(url, header) {
return this.submit('put', url, header);
}
patch(url, header) {
return this.submit('patch', url, header);
}
delete(url, header) {
return this.submit('delete', url, header);
}
submit(method, url, header) {
let vm = this;
let params = vm.data();
let set = {};
if (method == 'get') {
set = {
method: method,
url: url,
params: params,
headers: header
}
}
else {
set = {
method: method,
url: url,
data: params,
headers: header
}
}
return new Promise((resolve, reject) => {
axios(set)
.then(response => {
vm.onSuccess(response.data);
resolve(response.data);
})
.catch(error => {
if (error.response.data.errors) {
let error_return = error.response.data.errors;
Object.keys(error_return).forEach(function (key) {
error.response.data.errors[key] = vm.errorCodeConvert(error_return[key], key);
});
vm.onFail(error.response.data.errors)
return reject(error.response.data.errors)
}
return reject(error)
});
});
}
onSuccess(data) {
// this.reset();
}
onFail(errors) {
this.errors.record(errors);
}
errorCodeConvert(code = [], key) {
let value = {
att: General.lang(key)
}
let return_message = [];
for (var i = 0; i < code.length; i++) {
if(code[i] == 'LOGIN_ERROR') {
return_message.push(General.lang('incorrect_account_or_password'));
}
else if (code[i] == 'REQUIRED') {
return_message.push(Sprintf(General.lang('this_field_required'), value));
}
else if(code[i] == 'EMAIL_ERROR') {
return_message.push(General.lang('incorrect_email_format'));
}
else if(code[i] == 'UNIQUE_ERRO') {
return_message.push(Sprintf(General.lang('the_content_has_already_been_taken'), value));
}
else if(code[i] == 'CONFIRM_ERROR') {
return_message.push(Sprintf(General.lang('the_content_confirmation_does_not_match'), value));
}
else if(code[i] == 'IMG_ERROR') {
return_message.push(Sprintf(General.lang('incorrect_image_format'), value));
}
else if(code[i] == 'EXCEL_ERROR') {
return_message.push(Sprintf(General.lang('incorrect_excel_format'), value));
}
else if(code[i] == 'NUMERIC_ERROR') {
return_message.push(Sprintf(General.lang('the_content_must_be_a_number'), value));
}
else if(code[i] == 'GREATER_ERROR_0') {
return_message.push(Sprintf(General.lang('the_content_must_be_greater_than_0'), value));
}
else if(code[i] == 'GREATER_ERROR_-1') {
return_message.push(Sprintf(General.lang('the_content_must_be_greater_than_0'), value));
}
else if(code[i] == 'LESS_ERROR_100') {
return_message.push(Sprintf(General.lang('the_content_must_be_less_than_100'), value));
}
else if(code[i] == 'MIN_ERROR_10') {
return_message.push(Sprintf(General.lang('the_content_must_be_at_least_10_characters'), value));
}
else if(code[i] == 'EXIST_ERROR') {
return_message.push(Sprintf(General.lang('the_content_not_exist'), value));
}
else if(code[i] == 'STATUS_ERROR') {
return_message.push(Sprintf(General.lang('status_error'), value));
}
else if(code[i] == 'CURRENT_PASSWORD_NOT_MATCH') {
return_message.push(Sprintf(General.lang('current_password_not_match'), value));
}
else {
return_message.push(code[i]);
}
}
return return_message;
}
}
export default Form;
+626
View File
@@ -0,0 +1,626 @@
module.exports.getYear = function() {
let dt = new Date();
return dt.getFullYear();
};
module.exports.logout = function() {
localStorage.removeItem('admin_detail');
localStorage.removeItem('admin_jwt');
localStorage.removeItem('login_redirect');
window.location.replace(ENV.APP_URL + 'login');
};
module.exports.tableCall = function(url, form, recall = 0, path = 'list', append = true) {
if (recall <= 3) {
return form.get(
ENV.API_URL + url,
{
'Authorization': 'Bearer '+ TOKEN,
'App-Key': ENV.APP_KEY
}
).then(response => {
if (append) {
let query_string = response.query_string ? path + '?' + response.query_string : path;
window.history.replaceState('', '', query_string);
}
return response
})
.catch(function (error) {
if(error.response) {
if (recall >= 3 && error.response.status == 401) {
module.exports.logout();
}
console.log(recall++);
return module.exports.tableCall(url, form, recall++, path, append);
}
});
}
};
module.exports.getCall = function(url, form, recall = 0) {
if (recall <= 3) {
return form.get(
ENV.API_URL + url,
{
'Authorization': 'Bearer '+ TOKEN,
'App-Key': ENV.APP_KEY
}
).then(response => {
return response
})
.catch(function (error) {
if(error.response) {
if (recall >= 3 && error.response.status == 401) {
module.exports.logout();
}
console.log(recall++);
return module.exports.getCall(url, form, recall++);
}
});
}
};
module.exports.validCheck = function(url, form, ref_inputs) {
return new Promise((resolve, reject) => {
form.post(
ENV.API_URL + url,
{
'Authorization': 'Bearer '+ TOKEN,
'App-Key': ENV.APP_KEY
}
).then(data => {
resolve(true);
})
.catch(error => {
let ref_inputs_data = ref_inputs;
let error_status = true;
Object.keys(ref_inputs_data).forEach(function (key) {
if (form.errors.has(ref_inputs_data[key])) {
error_status = false;
}
});
if (!error_status) {
resolve(false);
}
else {
resolve(true);
form.errors.clear();
}
});
});
};
module.exports.onComplete = function(url, form, method) {
return new Promise((resolve, reject) => {
form[method](
ENV.API_URL + url,
{
'Authorization': 'Bearer '+ TOKEN,
'App-Key': ENV.APP_KEY
}
).then(data => {
resolve(data);
})
.catch(error => {
reject(false);
});
});
};
module.exports.getURLParam = function(key) {
const queryString = require('query-string');
const parsed = queryString.parse(location.search);
return parsed[key];
};
module.exports.getStringParam = function(key, url) {
url = url.split('?');
url = url[1] ? url[1] : url[0];
const queryString = require('query-string');
const parsed = queryString.parse('?' + url);
return parsed[key];
};
module.exports.getKey = function(set = [], type = 'key', null_type = 'text') {
let return_data = [];
if (set.length > 0) {
set.forEach(function(element, index) {
return_data.push(element[type] ? element[type] : element[null_type]);
});
}
return return_data;
};
module.exports.autoCompleteKeyConvert = function(set = [], tag = '') {
let return_date = [];
set.forEach(function(element, index) {
return_date.push({
'id': element.id,
'hash_id': element.hash_id,
'row': element,
'text': element.name,
'tiClasses':[ "ti-valid" ]
});
});
return return_date;
};
module.exports.initFormArray = function(set, form_field) {
let return_date = [];
if (form_field[0]) {
form_field.forEach(function(element, index) {
return_date.push(module.exports.filterByProperty(set, 'id', element))
});
}
return return_date;
};
module.exports.selectStructure = function(set = [], id = '', value = '', other = null, other_2 = null) {
let return_set = {
'data': [],
'actual_data': set
};
set.forEach(function(element, index) {
return_set.data.push({
'key': element[id],
'value': element[value] + ' ' + (other ? '(' + element[other][0].name + ')' : '') + ' ' + (other_2 ? '(' + element[other_2][0].name + ')' : '')
});
});
return return_set;
};
module.exports.returnAray = function(set) {
if (set !== undefined && set !== null) {
set = Array.isArray(set) ? set : [set];
}
else {
set = [];
}
return set;
};
// module.exports.postCall = function(url, params = {}) {
// return axios.post(
// ENV.API_URL + url, params, {
// headers: {
// 'Authorization': 'Bearer '+ TOKEN
// }
// }).then(response => {
// return response.data
// })
// .catch(function (error) {
// });
// };
// module.exports.putCall = function(url, params = {}) {
// return axios.put(
// ENV.API_URL + url, params, {
// headers: {
// 'Authorization': 'Bearer '+ TOKEN
// }
// }).then(response => {
// return response.data
// })
// .catch(function (error) {
// });
// };
// module.exports.setpUpdate = function(url, ref_inputs, form) {
// return new Promise((resolve, reject) => {
// form.put(
// ENV.API_URL + url, {
// headers: {
// 'Authorization': 'Bearer '+ TOKEN
// }
// }).then(data => {
// resolve(true);
// })
// .catch(error => {
// let ref_inputs_data = ref_inputs.split(',');
// let error_status = true;
// Object.keys(ref_inputs_data).forEach(function (key) {
// // variation_rule
// if(typeof form[ref_inputs_data[key]] === 'object') {
// if (ref_inputs_data[key] == 'variation_rule' && form[ref_inputs_data[key]].type) {
// if (form[ref_inputs_data[key]].type == 1) {
// let set = form[ref_inputs_data[key]].content.detail;
// set.forEach(function(element, index) {
// let set_key = Object.keys(element);
// set_key.forEach(function(element_2, index_2) {
// if (form.errors.has(ref_inputs_data[key] + '.content.detail.' + index + '.' + element_2)) {
// error_status = false;
// }
// });
// });
// }
// else {
// let set = form[ref_inputs_data[key]].content.detail;
// set.forEach(function(element, index) {
// let set_2 = element.content.detail;
// set_2.forEach(function(element_2, index_2) {
// let set_key = Object.keys(element_2);
// set_key.forEach(function(element_3, index_3) {
// if (form.errors.has(ref_inputs_data[key] + '.content.detail.' + index + '.content.detail.' + index_2 + '.' + element_3)) {
// error_status = false;
// }
// });
// });
// });
// }
// }
// }
// if (Array.isArray(form[ref_inputs_data[key]])) {
// let set = form[ref_inputs_data[key]];
// set.forEach(function(element, index) {
// let set_key = Object.keys(element);
// set_key.forEach(function(element_2, index_2) {
// if (form.errors.has(ref_inputs_data[key] + '.' + index + '.' + element_2)) {
// error_status = false;
// }
// });
// });
// }
// else {
// if (form.errors.has(ref_inputs_data[key])) {
// error_status = false;
// }
// }
// });
// if (!error_status) {
// resolve(false);
// }
// else {
// resolve(true);
// form.errors.clear();
// }
// });
// });
// };
module.exports.filterByProperty = function(array, prop, value) {
for(var i = 0; i < array.length; i++){
var obj = array[i];
for(var key in obj){
if(typeof(obj[key] == "object")){
var item = obj[key];
if(key == prop && item == value){
return obj;
}
}
}
}
};
module.exports.arrayConvert = function(set = []) {
let return_date = [];
set.forEach(function(element, index) {
return_date.push({
'id': element,
'name': element
});
});
return return_date;
};
module.exports.imageBase64 = function(imgs) {
let num = 1;
let base = [];
let count = imgs.length;
return new Promise((resolve, reject) => {
Array.from(imgs).forEach(file => {
let reader = new FileReader();
reader.onload = () => {
base.push(reader.result);
if (num >= count) {
resolve(base);
}
num++;
};
reader.readAsDataURL(file);
})
});
};
module.exports.toastedMessage = function(type, object, key) {
let message = '';
let value = [
{att: object},
{att: key},
];
if (type == 'create') {
message = Sprintf(module.exports.lang('have_been_successfully_created'), {value: value});
}
else if(type == 'edit') {
message = Sprintf(module.exports.lang('have_been_successfully_updated'), {value: value});
}
Vue.toasted.success(message, {
icon : {
name : 'check',
}
}).goAway(3500);
};
module.exports.lang = function(code) {
let lang_selected = localStorage.getItem('lang_selected');
if (lang_selected == 'cn') {
return Cn[code];
}
else {
return En[code];
}
};
module.exports.selectOptionConvert = function(set = [], id = '', value = '', other = null, other_2 = null) {
let return_set = [];
set.forEach(function(element, index) {
return_set.push({
'key': element[id],
'value': element[value] + ' ' + (other ? '(' + element[other][0].name + ')' : '') + ' ' + (other_2 ? '(' + element[other_2][0].name + ')' : '')
});
});
return return_set;
};
module.exports.filterOut = function(set = [], out = []) {
let filter_set = [];
set.forEach(function(element, index) {
let allow = true;
out.forEach(function(element_out, index_out) {
if (element.id == element_out) {
allow = false;
}
});
if (allow == true) {
filter_set.push(element);
}
});
return filter_set;
};
module.exports.videoBase64 = function(video) {
let num = 1;
let base = [];
let count = video.length;
return new Promise((resolve, reject) => {
Array.from(video).forEach(file => {
let reader = new FileReader();
reader.onload = () => {
base.push(reader.result);
if (num >= count) {
resolve(base);
}
num++;
};
reader.readAsDataURL(file);
})
});
};
module.exports.errorData = function(data) {
let error_data = [];
let error_message = '';
Object.keys(data).forEach(function(key) {
error_data.push(data[key]);
});
error_message = error_data.join('<br>');
return error_message;
};
module.exports.timeSince = function(date) {
var seconds = Math.floor((new Date() - date) / 1000);
var interval = Math.floor(seconds / 31536000);
if (interval > 1) {
return 'Active ' + interval + ' Years Ago';
}
interval = (seconds / 2592000);
if (interval > 1) {
return 'Active ' + Math.floor(interval) + ' Months Ago';
}
interval = (seconds / 86400);
if (interval > 1) {
return 'Active ' + Math.floor(interval) + ' Days Ago';
}
interval = (seconds / 3600);
if (interval > 1) {
return 'Active' + Math.floor(interval) + ' Hours Ago';
}
interval = (seconds / 60);
if (interval > 1) {
return 'Active ' + Math.floor(interval) + ' Minutes Ago';
}
return 'Active ' + Math.floor(seconds) + ' Seconds Ago';
};
module.exports.shortenNumber = function(num) {
let nformat = 0;
if (num < 1000) {
nformat = number_format(num);
}
else if (num < 1000000) {
// Anything less than a million
nformat = (num / 1000).toFixed(1) + 'k';
}
else if (num < 1000000000) {
// Anything less than a billion
nformat = (num / 1000000).toFixed(3) + 'm';
}
else {
// At least a billion
nformat = (num / 1000000000, 3).toFixed(3) + 'b';
}
return nformat;
};
// public static function shortenNumber($number){
// if ($number < 1000) {
// $nformat = number_format($number);
// }else if ($number < 1000000) {
// // Anything less than a million
// $nformat = number_format($number/1000,1) . 'k';
// } else if ($number < 1000000000) {
// // Anything less than a billion
// $nformat = number_format($number / 1000000, 3) . 'm';
// } else {
// // At least a billion
// $nformat = number_format($number / 1000000000, 3) . 'b';
// }
// return $nformat;
// }
// module.exports.selectStructureNonDB = function(set = []) {
// let return_set = {
// 'data': [],
// 'actual_data': set.data
// };
// set.data.forEach(function(element, index) {
// return_set.data.push({
// 'key': element,
// 'value': element
// });
// });
// return return_set;
// };
module.exports.httpConvert = function(params) {
let query_string = '';
Object.keys(params).forEach(function(element, index) {
if( Object.prototype.toString.call( params[element] ) === '[object Array]' ) {
if (params[element][0]) {
params[element].forEach(function(element_2, index_2) {
query_string += element + '[]=' + element_2 + '&';
});
}
}
else {
if (params[element]) {
console.log(params[element]);
query_string += element + '=' + params[element] + '&';
}
}
});
return query_string;
};
// return filter_set;
// };
// module.exports.pluckID = function(set = []) {
// let return_set = [];
// set.forEach(function(element, index) {
// return_set.push(element.id);
// });
// return return_set;
// };
// module.exports.dateConvert = function(date) {
// let return_date = '';
// if (date) {
// let parts = date.split('-');
// return_date = new Date(parts[2], parts[1] - 1, parts[0]);
// }
// return return_date;
// };
// module.exports.foreachErrorToasted = function(data) {
// let error_data = module.exports.errorData(data);
// error_data.forEach(function(element, index) {
// Vue.toasted.error(element, {
// icon : {
// name : 'close',
// }
// }).goAway(3500);
// });
// };
// module.exports.getURLParam = function(key) {
// const queryString = require('query-string');
// const parsed = queryString.parse(location.search);
// return parsed[key];
// };
// module.exports.returnAray = function(set) {
// if (set !== undefined) {
// set = Array.isArray(set) ? set : [set];
// }
// else {
// set = [];
// }
// return set;
// };
// module.exports.autoCompleteKeyConvert = function(set = []) {
// let return_date = [];
// set.forEach(function(element, index) {
// return_date.push({
// 'id': element.id,
// 'row': element,
// 'text': element.name,
// 'tiClasses':[ "ti-valid" ]
// });
// });
// return return_date;
// };
// module.exports.formatNumber = function(set, form_field) {
// if (form_field[0]) {
// form_field.forEach(function(num) {
// return num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,");
// });
// }
// };
+83
View File
@@ -0,0 +1,83 @@
module.exports.menuDefine = function(permission = []) {
let menu = [];
menu.push({
header: true,
title: 'Main Navigation',
});
/////////////////////////////////////////////////////
menu.push({
title: 'Dashboard',
icon: 'fa fa-home',
child: [
{
href: '/',
title: 'Analytics',
},
]
});
/////////////////////////////////////////////////////
if (permission.includes('view user')) {
let admin_access_menu = {};
admin_access_menu = {
title: 'User',
icon: 'fa fa-user',
child: [
{
href: '/user/list',
title: 'List',
},
]
};
menu.push(admin_access_menu);
}
/////////////////////////////////////////////////////
if (permission.includes('view admin')) {
let admin_access_menu = {};
admin_access_menu = {
title: 'Admin',
icon: 'fa fa-user-astronaut',
child: [
{
href: '/admin/list',
title: 'List',
},
]
};
if (permission.includes('add admin')) {
admin_access_menu.child.push(
{
href: '/admin/create',
title: 'Create',
}
);
}
menu.push(admin_access_menu);
}
/////////////////////////////////////////////////////
if (permission.includes('view role')) {
let admin_access_menu = {};
admin_access_menu = {
title: 'Role',
icon: 'fa fa-user-tag',
child: [
{
href: '/admin-role/list',
title: 'Admin List',
},
{
href: '/reviewer-role/list',
title: 'Reviewer List',
},
]
};
menu.push(admin_access_menu);
}
/////////////////////////////////////////////////////
return menu;
};