changes
This commit is contained in:
417
plugins/00-datatable.js
Normal file
417
plugins/00-datatable.js
Normal file
@@ -0,0 +1,417 @@
|
||||
|
||||
import { useStore } from '~/stores/index'
|
||||
export default defineNuxtPlugin(() => {
|
||||
const store = useStore()
|
||||
|
||||
//==========Find & filter=================
|
||||
const find = function(arr, obj, attr) {
|
||||
const keys = Object.keys(obj)
|
||||
let found = arr.find(v=>{
|
||||
let valid = true
|
||||
keys.map(key=>{
|
||||
let val = obj[key]
|
||||
if(valid===false) return false
|
||||
else if(Array.isArray(val)) {
|
||||
if(val.findIndex(x=>x===v[key]) <0) valid = false
|
||||
} else if(!(v[key]===val)) valid = false
|
||||
})
|
||||
return valid
|
||||
})
|
||||
return found? (attr? found[attr] : found) : undefined
|
||||
}
|
||||
|
||||
const findIndex = function(arr, obj) {
|
||||
const keys = Object.keys(obj)
|
||||
return arr.findIndex(v=>{
|
||||
let valid = true
|
||||
keys.map(key=>{
|
||||
let val = obj[key]
|
||||
if(valid===false) return false
|
||||
else if(Array.isArray(val)) {
|
||||
if(val.findIndex(x=>x===v[key]) <0) valid = false
|
||||
} else if(!(v[key]===val)) valid = false
|
||||
})
|
||||
return valid
|
||||
})
|
||||
}
|
||||
|
||||
const filter = function(arr, obj, attr) {
|
||||
const keys = Object.keys(obj)
|
||||
let rows = arr.filter(v=>{
|
||||
let valid = true
|
||||
keys.map(key=>{
|
||||
let val = obj[key]
|
||||
if(valid===false) return false
|
||||
else if(Array.isArray(val)) {
|
||||
if(val.findIndex(x=>x===v[key]) <0) valid = false
|
||||
} else if(!(v[key]===val)) valid = false
|
||||
})
|
||||
return valid
|
||||
})
|
||||
return attr? rows.map(v=>v[attr]) : rows
|
||||
}
|
||||
|
||||
//=========Empty & copy============
|
||||
const id = function() {
|
||||
return Math.random().toString(36).substring(2, 12).toUpperCase()
|
||||
}
|
||||
|
||||
const empty = function(val) {
|
||||
if(val === undefined || val === null || val === '' || val==="") return true
|
||||
return false
|
||||
}
|
||||
|
||||
const copy = function(val) {
|
||||
if(val === undefined || val === null || val === '' || val==="") return val
|
||||
return JSON.parse(JSON.stringify(val))
|
||||
}
|
||||
|
||||
const clone = function(obj) {
|
||||
if (obj === null || typeof (obj) !== 'object' || 'isActiveClone' in obj)
|
||||
return obj;
|
||||
if (obj instanceof Date)
|
||||
var temp = new obj.constructor(); //or new Date(obj);
|
||||
else
|
||||
var temp = obj.constructor();
|
||||
for (var key in obj) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
obj['isActiveClone'] = null;
|
||||
temp[key] = clone(obj[key]);
|
||||
delete obj['isActiveClone'];
|
||||
}
|
||||
}
|
||||
return temp
|
||||
}
|
||||
|
||||
const remove = function(arr, idx) {
|
||||
arr.splice(idx, 1)
|
||||
}
|
||||
|
||||
const stripHtml = function(html, length) {
|
||||
if(!html) return null
|
||||
else if(typeof html!=='string') return html
|
||||
if(html? html.indexOf('<')<0 : false) {
|
||||
return length? (html.length > length? html.substring(0, length) + '...' : html ) : html
|
||||
}
|
||||
var tmp = document.createElement("DIV")
|
||||
tmp.innerHTML = html
|
||||
var val = tmp.textContent || tmp.innerText || ""
|
||||
return length? (val.length > length? val.substring(0, length) + '...' : val ) : val
|
||||
}
|
||||
|
||||
//==========Convert=================
|
||||
const isNumber = function(val) {
|
||||
if(val === undefined || val === null || val === '' || val==="") return false
|
||||
val = val.toString().replace(/,/g, "")
|
||||
return !isNaN(val)
|
||||
}
|
||||
|
||||
const numtoString = function(val, type, decimal, mindecimal) {
|
||||
if(val === undefined || val === "" || val==='' || val === null) return
|
||||
val = val.toString().replace(/,/g, "")
|
||||
if(isNaN(val)) return
|
||||
let f = decimal? {maximumFractionDigits: decimal || 0} : {}
|
||||
if(mindecimal) f['minimumFractionDigits'] = mindecimal
|
||||
return decimal? Number(val).toLocaleString(type || 'en-EN', f) : Number(val).toLocaleString(type || 'en-EN')
|
||||
}
|
||||
|
||||
const formatNumber = function(val) {
|
||||
if(val === undefined || val === "" || val==='' || val === null) return
|
||||
val = val.toString().replace(/,/g, "")
|
||||
if (val.indexOf('%') >0) {
|
||||
val = val.replace(/%/g, "")
|
||||
return isNaN(val)? undefined : Number(val)/100
|
||||
}
|
||||
return isNaN(val)? undefined : Number(val)
|
||||
}
|
||||
|
||||
const formatUnit = function(val, unit, decimal, string, mindecimal) {
|
||||
val = formatNumber(val)
|
||||
if(val===undefined) return
|
||||
let percentage = (unit===0.01 || unit==="0.01")? '%' : ''
|
||||
val = unit? val/Number(unit) : val
|
||||
let f = {maximumFractionDigits: decimal || 0}
|
||||
if(mindecimal) f['minimumFractionDigits'] = mindecimal
|
||||
return string? (val.toLocaleString('en-EN', f) + percentage) : (val).toFixed(decimal)
|
||||
}
|
||||
|
||||
//==========Calculate=================
|
||||
const calc = function(fn) {
|
||||
return new Function('return ' + fn)()
|
||||
}
|
||||
|
||||
const calculate = function(row, tags, formula, decimal, unit) {
|
||||
let val = this.$copy(formula)
|
||||
let valid = 0
|
||||
tags.forEach(v => {
|
||||
let myRegExp = new RegExp(v, 'g')
|
||||
let res = this.$formatNumber(row[v])
|
||||
if(res) valid = 1
|
||||
val = val.replace(myRegExp, `(${res || 0})`)
|
||||
})
|
||||
if(valid===0) return {success: false, value : undefined} //all values is null
|
||||
//calculate
|
||||
try {
|
||||
let value = this.$calc(val)
|
||||
if(isNaN(value) || value===Number.POSITIVE_INFINITY || value===Number.NEGATIVE_INFINITY) {
|
||||
var result = {success: false, value : value}
|
||||
} else {
|
||||
value = (value===true || value===false)? value : formatUnit(value, unit, decimal, true, decimal)
|
||||
var result = {success: true, value: value}
|
||||
}
|
||||
}
|
||||
catch(err) {
|
||||
var result = {success: false, value : undefined}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const calculateFunc = function(row, cols, func, decimal, unit) {
|
||||
let value
|
||||
let arr1 = cols.map(v=>this.$formatNumber(row[v]))
|
||||
let arr = arr1.filter(v=>v)
|
||||
if(arr.length===0) return {success: false, value : undefined}
|
||||
if(func==='max') value = Math.max(...arr)
|
||||
else if(func==='min') value = Math.min(...arr)
|
||||
else if(func==='sum') value = arr.reduce((a, b) => a + b, 0)
|
||||
else if(func==='avg') {
|
||||
let total = arr.reduce((a, b) => a + b, 0)
|
||||
value = total / cols.length
|
||||
}
|
||||
if(!value) return {success: false, value: undefined}
|
||||
value = formatUnit(value, unit, decimal, true, decimal)
|
||||
return {success: true, value: value}
|
||||
}
|
||||
|
||||
const calculateData = function(data, fields) {
|
||||
let arr = this.$copy(fields.filter(h=>h.formula))
|
||||
if(arr.length===0) return data
|
||||
let arr1 = arr.filter(v=>v.func)
|
||||
arr1.map(v=>{
|
||||
if(v.vals.indexOf(':')>=0) {
|
||||
let arr2 = v.vals.toLowerCase().replaceAll('c', '').split(':')
|
||||
let cols = []
|
||||
for (let i = parseInt(arr2[0]); i <= parseInt(arr2[1]); i++) {
|
||||
let field = fields.length>i? fields[i] : undefined
|
||||
if(field? (field.format==='number' && field.name!==v.name) : false) cols.push(field.name)
|
||||
}
|
||||
v.cols = cols
|
||||
} else {
|
||||
let arr2 = v.vals.toLowerCase().replaceAll('c', '').split(',')
|
||||
let cols = []
|
||||
arr2.map(v=>{
|
||||
let i = parseInt(v)
|
||||
let field = fields.length>i? fields[i] : undefined
|
||||
if(field? (field.format==='number' && field.name!==v.name) : false) cols.push(field.name)
|
||||
})
|
||||
v.cols = cols
|
||||
}
|
||||
})
|
||||
arr = multiSort(arr, {level: 'asc'})
|
||||
let copy = data
|
||||
copy.map(v=>{
|
||||
arr.map(x=>{
|
||||
if(x.func) {
|
||||
let res = calculateFunc(v, x.cols, x.func, x.decimal, x.unit)
|
||||
if(res? res.success : false) v[x.name] = res.value
|
||||
} else {
|
||||
let res = calculate(v, x.tags, x.formula, x.decimal, x.unit)
|
||||
if(res? res.success : false) v[x.name] = res.value
|
||||
}
|
||||
})
|
||||
})
|
||||
return copy
|
||||
}
|
||||
|
||||
const summary = function(arr, fields, type) {
|
||||
let obj = {}
|
||||
if(type==='total') {
|
||||
fields.map(x=> obj[x] = arr.map(v=>v[x]? v[x] : 0).reduce((a, b) => a + b, 0))
|
||||
} else if(type==='min') {
|
||||
fields.map(x=>obj[x] = Math.min(...arr.map(v=>v[x])))
|
||||
}
|
||||
else if(type==='max') {
|
||||
fields.map(x=>obj[x] = Math.max(...arr.map(v=>v[x])))
|
||||
}
|
||||
else if(type==='count') {
|
||||
fields.map(x=>obj[x] = arr.map(v=>!empty(v[x])).length)
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
//====================Array====================
|
||||
const formatArray = function(data, fields) {
|
||||
let args = fields.filter(v=>v.format==='number')
|
||||
data.map(v=>{
|
||||
args.map(x=>{
|
||||
v[x.name] = empty(v[x.name])? undefined : formatUnit(v[x.name], x.unit, x.decimal, true, x.decimal)
|
||||
})
|
||||
})
|
||||
return data
|
||||
}
|
||||
|
||||
const unique = function(arr, keyProps) {
|
||||
const kvArray = arr.map(entry => {
|
||||
const key = keyProps.map(k => entry[k]).join('|');
|
||||
return [key, entry];
|
||||
});
|
||||
const map = new Map(kvArray);
|
||||
return Array.from(map.values());
|
||||
}
|
||||
|
||||
const arrayMove = function(arr, old_index, new_index) {
|
||||
if (new_index >= arr.length) {
|
||||
var k = new_index - arr.length + 1;
|
||||
while (k--) {
|
||||
arr.push(undefined);
|
||||
}
|
||||
}
|
||||
arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
|
||||
return arr; // for testing
|
||||
}
|
||||
|
||||
const multiSort = function(array, sortObject = {}, format = {}) {
|
||||
const sortKeys = Object.keys(sortObject)
|
||||
|
||||
// Return array if no sort object is supplied.
|
||||
if (!sortKeys.length) return array
|
||||
|
||||
// Change the values of the sortObject keys to -1, 0, or 1.
|
||||
for (let key in sortObject)
|
||||
sortObject[key] = sortObject[key] === 'desc' || sortObject[key] === -1 ? -1 : (sortObject[key] === 'skip' || sortObject[key] === 0 ? 0 : 1)
|
||||
|
||||
const keySort = (a, b, direction) => {
|
||||
direction = direction !== null ? direction : 1
|
||||
if (a === b) return 0
|
||||
|
||||
// If b > a, multiply by -1 to get the reverse direction.
|
||||
return a > b ? direction : -1 * direction;
|
||||
}
|
||||
|
||||
return array.sort((a, b) => {
|
||||
let sorted = 0, index = 0
|
||||
|
||||
// Loop until sorted (-1 or 1) or until the sort keys have been processed.
|
||||
while (sorted === 0 && index < sortKeys.length) {
|
||||
const key = sortKeys[index]
|
||||
if (key) {
|
||||
const direction = sortObject[key]
|
||||
let val1 = format[key]==='number'? (empty(a[key])? 0 : this.$formatNumber(a[key])) : a[key]
|
||||
let val2 = format[key]==='number'? (empty(b[key])? 0 : this.$formatNumber(b[key])) : b[key]
|
||||
sorted = keySort(val1, val2, direction)
|
||||
index++
|
||||
}
|
||||
}
|
||||
return sorted
|
||||
})
|
||||
}
|
||||
|
||||
//======================Fields====================
|
||||
const createField = function(name,label,format,show, minwidth) {
|
||||
let field = {name: name, label: label, format: format, show: show, minwidth: minwidth}
|
||||
if(format==='number') {
|
||||
field.unit = '1'
|
||||
field.textalign = 'right'
|
||||
}
|
||||
return field
|
||||
}
|
||||
|
||||
const updateFields = function(pagename, field, action) {
|
||||
let pagedata = store[pagename]
|
||||
let copy = this.$copy(pagedata.fields)
|
||||
let idx = this.$findIndex(copy, {name: field.name})
|
||||
if(action==='delete') {
|
||||
this.$delete(copy, idx)
|
||||
if(pagedata.filters? pagedata.filters.length>0 : false) {
|
||||
let index = this.$findIndex(pagedata.filters, {name: field.name})
|
||||
if(index>=0) {
|
||||
let copyFilter = this.$copy(this.pagedata.filters)
|
||||
this.$delete(copyFilter, index)
|
||||
this.$store.commit('updateState', {name: pagename, key: 'filterby', data: copyFilter})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
idx>=0? copy[idx] = field : copy.push(field)
|
||||
}
|
||||
this.$store.commit("updateState", {name: pagename, key: "fields", data: copy})
|
||||
}
|
||||
|
||||
const updateSeriesFields = function(fields) {
|
||||
fields.filter(v=>v.series).map(field=>{
|
||||
let obj = field.api==='finitem'? this.$findPeriod(field.series, 'period') : this.$findPeriod(field.series)
|
||||
field.period = field.api==='finitem'? obj.code : obj
|
||||
let idx = field.label.indexOf('[')
|
||||
field.label = (idx>0? field.label.substring(0, idx) : field.label) + '[' + (field.api==='finitem'? obj.show : obj) + ']'
|
||||
})
|
||||
return fields
|
||||
}
|
||||
|
||||
const updateSeriesFilters = function(filters, fields) {
|
||||
if(fields.filter(v=>v.series).length===0) return filters
|
||||
filters.map(v=>{
|
||||
let found = fields.find(x=>x.name===v.name)
|
||||
if(found? found.series : false) {
|
||||
v.label = found.label
|
||||
}
|
||||
})
|
||||
return filters
|
||||
}
|
||||
|
||||
//======================Export===============================
|
||||
const exportExcel = function(data, filename, fields) {
|
||||
var _filename = this.$dayjs(new Date()).format("YYYYMMDDHHmmss") + '-' + filename + '.xlsx'
|
||||
let list = []
|
||||
data.map(v=>{
|
||||
let ele = {}
|
||||
fields.map(x=>{
|
||||
let label = stripHtml(x.label)
|
||||
ele[label] = v[x.name]
|
||||
})
|
||||
list.push(ele)
|
||||
})
|
||||
var XLSX = require('xlsx')
|
||||
//workBook class
|
||||
function Workbook() {
|
||||
if(!(this instanceof Workbook)) return new Workbook()
|
||||
this.SheetNames = []
|
||||
this.Sheets = {}
|
||||
}
|
||||
var exportBook = new Workbook();
|
||||
var worksheet = XLSX.utils.json_to_sheet(list)
|
||||
exportBook.SheetNames.push('sheet1')
|
||||
exportBook.Sheets.sheet1 = worksheet
|
||||
XLSX.writeFile(exportBook, _filename)
|
||||
}
|
||||
|
||||
return {
|
||||
provide: {
|
||||
find,
|
||||
findIndex,
|
||||
filter,
|
||||
id,
|
||||
empty,
|
||||
copy,
|
||||
clone,
|
||||
remove,
|
||||
stripHtml,
|
||||
isNumber,
|
||||
numtoString,
|
||||
formatNumber,
|
||||
formatUnit,
|
||||
calc,
|
||||
calculate,
|
||||
calculateFunc,
|
||||
calculateData,
|
||||
summary,
|
||||
formatArray,
|
||||
unique,
|
||||
arrayMove,
|
||||
multiSort,
|
||||
createField,
|
||||
updateFields,
|
||||
updateSeriesFields,
|
||||
updateSeriesFilters,
|
||||
exportExcel
|
||||
}
|
||||
}
|
||||
})
|
||||
393
plugins/01-common.js
Normal file
393
plugins/01-common.js
Normal file
@@ -0,0 +1,393 @@
|
||||
// nuxt 3 - plugins/my-plugin.ts
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useStore } from '~/stores/index'
|
||||
import dayjs from 'dayjs'
|
||||
import weekday from 'dayjs/plugin/weekday'
|
||||
import weekOfYear from 'dayjs/plugin/weekOfYear'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
dayjs.extend(weekday)
|
||||
dayjs.extend(weekOfYear)
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
export default defineNuxtPlugin(() => {
|
||||
const route = useRoute()
|
||||
const {$id, $empty} = useNuxtApp()
|
||||
const store = useStore()
|
||||
const dialog = function(content, title, type, duration, width, height, vbind) {
|
||||
content = typeof content === 'string'? content : JSON.stringify(content)
|
||||
let vtitle = type==='Success'? `<span class="has-text-primary">${title}</span>` : title
|
||||
if(type==='Error') vtitle = `<span class="has-text-danger">${title}</span>`
|
||||
let data = {id: $id() , component: `dialog/${type || 'Info'}`,
|
||||
vbind: {content: content, duration: duration, vbind: vbind}, title: vtitle, width: width || '600px', height: height || '100px'}
|
||||
store.commit('showmodal', data)
|
||||
}
|
||||
|
||||
const snackbar = function(content, title, type, width, height) {
|
||||
content = typeof content == 'string'? content : JSON.stringify(content)
|
||||
let vtitle = type==='Success'? `<span class="has-text-primary">${title}</span>` : title
|
||||
if(type==='Error') vtitle = `<span class="has-text-danger">${title}</span>`
|
||||
let data = {id: $id() , component: `snackbar/${type || 'Info'}`,
|
||||
vbind: {content: content}, title: vtitle, width: width || '600px', height: height || '100px'}
|
||||
store.commit('snackbar', data)
|
||||
}
|
||||
|
||||
const getLink = function(val) {
|
||||
if(val === undefined || val === null || val === '' || val==="") return ''
|
||||
let json = val.indexOf('{')>=0? JSON.parse(val) : {path: val}
|
||||
return json
|
||||
}
|
||||
|
||||
const errPhone = function(phone) {
|
||||
var text = undefined
|
||||
if ($empty(phone)) {
|
||||
text = 'Số điện thoại di động không được bỏ trống.'
|
||||
} else if (isNaN(phone)) {
|
||||
text = 'Số điện thoại di động không hợp lệ.'
|
||||
} else if(phone.length<9 || phone.length>11) {
|
||||
text = 'Số điện thoại di động phải từ 9-11 số.'
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
const errEmail = function(email) {
|
||||
const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
|
||||
var text = undefined
|
||||
if ($empty(email)) {
|
||||
text = 'Email không được bỏ trống.'
|
||||
} else if (!(re.test(String(email).toLowerCase()))) {
|
||||
text = 'Email không hợp lệ.'
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
const errPhoneEmail = function(contact) {
|
||||
const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
|
||||
var text = undefined
|
||||
|
||||
if ($empty(contact)) {
|
||||
text = 'Số điện thoại di động hoặc Email không được bỏ trống.'
|
||||
} else if (!(re.test(String(contact).toLowerCase()) || !isNaN(contact))) {
|
||||
text = 'Số điện thoại di động hoặc Email không hợp lệ.'
|
||||
} else if(!isNaN(contact) && (contact.length<9 || contact.length>11)) {
|
||||
text = 'Số điện thoại di động không hợp lệ.'
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
const upload = function(file, type, user, convert) {
|
||||
var fileFormat = [{type: 'image', format: ['.png', '.jpg', 'jpeg', '.bmp', '.gif', '.svg', '.webp']},
|
||||
{type: 'video', format: ['.wmv', '.avi', '.mp4', '.flv', '.mov', '.mpg', '.amv', '.rm']}
|
||||
]
|
||||
var valid = undefined
|
||||
if(type==='image' || type==='video') {
|
||||
valid = false
|
||||
let found = fileFormat.find(v=>v.type===type)
|
||||
found.format.map(x=>{
|
||||
if(file.name.toLowerCase().indexOf(x)>=0) valid = true
|
||||
})
|
||||
}
|
||||
if(valid===false) return {name: file.name, error: true, text: 'Định dạng file không hợp lệ'}
|
||||
if((type==='image' || type==='file') && file.size > 500*1024*1024) {
|
||||
return {name: file.name, error: true, text: 'Kích thước ' + (type==='image'? 'hình ảnh' : 'tài liệu') + ' phải dưới 500MB'}
|
||||
} else if(type==='video' && file.size > 1073741274) {
|
||||
return {name: file.name, error: true, text: 'Kích thước video phải dưới 1GB'}
|
||||
}
|
||||
let data = new FormData()
|
||||
let fileName = dayjs(new Date()).format("YYYYMMDDhhmmss") + '-' + nonAccent(file.name)
|
||||
data.append('name', file.name)
|
||||
data.append('filename', fileName)
|
||||
data.append('file', file)
|
||||
data.append('type', type)
|
||||
data.append('size', file.size)
|
||||
data.append('user', user)
|
||||
data.append('convert', convert)
|
||||
return {form: data, type: type, size: file.size, file: file, name: file.name, filename: fileName}
|
||||
}
|
||||
|
||||
const checkChange = function(obj1, obj2, list) {
|
||||
var change = false
|
||||
if(list) {
|
||||
list.map(v=>{if(obj1[v]!==obj2[v]) change = true})
|
||||
} else {
|
||||
for (var k in obj1 ) {
|
||||
if(obj1[k]!==obj2[k]) change = true
|
||||
}
|
||||
}
|
||||
return change
|
||||
}
|
||||
|
||||
const resetNull = function(obj) {
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
if(typeof value==='string') {
|
||||
let val = value.trim()
|
||||
if(val==='' || val==="") val = null
|
||||
obj[key] = val
|
||||
}
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
const copyToClipboard = function(text) {
|
||||
snackbar('Copied to clipboard')
|
||||
if (window.clipboardData && window.clipboardData.setData) {
|
||||
// IE specific code path to prevent textarea being shown while dialog is visible.
|
||||
return clipboardData.setData("Text", text);
|
||||
|
||||
} else if (document.queryCommandSupported && document.queryCommandSupported("copy")) {
|
||||
var textarea = document.createElement("textarea");
|
||||
textarea.textContent = text;
|
||||
textarea.style.position = "fixed"; // Prevent scrolling to bottom of page in MS Edge.
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
try {
|
||||
return document.execCommand("copy"); // Security exception may be thrown by some browsers.
|
||||
} catch (ex) {
|
||||
console.warn("Copy to clipboard failed.", ex);
|
||||
return false;
|
||||
} finally {
|
||||
document.body.removeChild(textarea);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const nonAccent = function(str) {
|
||||
if($empty(str)) return null
|
||||
str = str.replaceAll('/', '-').replaceAll('%', '-').replaceAll('?', '-')
|
||||
str = str.toLowerCase();
|
||||
str = str.replace(/à|á|ạ|ả|ã|â|ầ|ấ|ậ|ẩ|ẫ|ă|ằ|ắ|ặ|ẳ|ẵ/g, "a");
|
||||
str = str.replace(/è|é|ẹ|ẻ|ẽ|ê|ề|ế|ệ|ể|ễ/g, "e");
|
||||
str = str.replace(/ì|í|ị|ỉ|ĩ/g, "i");
|
||||
str = str.replace(/ò|ó|ọ|ỏ|õ|ô|ồ|ố|ộ|ổ|ỗ|ơ|ờ|ớ|ợ|ở|ỡ/g, "o");
|
||||
str = str.replace(/ù|ú|ụ|ủ|ũ|ư|ừ|ứ|ự|ử|ữ/g, "u");
|
||||
str = str.replace(/ỳ|ý|ỵ|ỷ|ỹ/g, "y");
|
||||
str = str.replace(/đ/g, "d");
|
||||
// Some system encode vietnamese combining accent as individual utf-8 characters
|
||||
str = str.replace(/\u0300|\u0301|\u0303|\u0309|\u0323/g, ""); // Huyền sắc hỏi ngã nặng
|
||||
str = str.replace(/\u02C6|\u0306|\u031B/g, ""); // Â, Ê, Ă, Ơ, Ư
|
||||
str = str.split(' ').filter(s => s).join('-')
|
||||
return str
|
||||
}
|
||||
|
||||
const linkID = function(link) {
|
||||
link = link? link : route.params.slug
|
||||
if($empty(link)) return
|
||||
let idx = link.lastIndexOf('-')
|
||||
let id = (idx>-1 && idx<link.length-1)? link.substring(idx+1, link.length) : undefined
|
||||
return id
|
||||
}
|
||||
|
||||
const exportpdf = function(docid, name, size) {
|
||||
var element = document.getElementById(docid)
|
||||
let elms = element.querySelectorAll("[id='ignore']")
|
||||
for(var i = 0; i < elms.length; i++) {
|
||||
elms[i].style.display='none';
|
||||
}
|
||||
var opt = {
|
||||
margin: 0.2,
|
||||
filename: `${name || 'file'}-${dayjs().format('YYYYMMDDHHmmss')}.pdf`,
|
||||
image: { type: 'jpeg', quality: 1 },
|
||||
html2canvas: { scale: 2, useCORS: true},
|
||||
jsPDF: { unit: 'in', format: size || 'a4', orientation: 'portrait' }
|
||||
}
|
||||
html2pdf().set(opt).from(element).save()
|
||||
setTimeout(()=> {
|
||||
for(var i = 0; i < elms.length; i++) {
|
||||
elms[i].style.display='block';
|
||||
}
|
||||
}, 1000)
|
||||
return opt.filename
|
||||
}
|
||||
|
||||
const exportImage = function(docid, name) {
|
||||
var element = document.getElementById(docid)
|
||||
let elms = element.querySelectorAll("[id='ignore']")
|
||||
for(var i = 0; i < elms.length; i++) {
|
||||
elms[i].style.display='none';
|
||||
}
|
||||
let filename = `${name}-${dayjs().format('YYYYMMDDHHmmss')}.png`
|
||||
html2canvas(element).then(canvas => {
|
||||
const link = document.createElement("a");
|
||||
link.href = canvas.toDataURL("image/png");
|
||||
link.download = filename;
|
||||
link.click();
|
||||
link.remove()
|
||||
})
|
||||
setTimeout(()=> {
|
||||
for(var i = 0; i < elms.length; i++) {
|
||||
elms[i].style.display='block';
|
||||
}
|
||||
}, 1000)
|
||||
return filename
|
||||
}
|
||||
|
||||
const download = async function(url, fileName) {
|
||||
let name = dayjs(new Date()).format("YYYYMMDDhhmmss") + '-' + fileName
|
||||
const response = await fetch(url, { method: "GET" });
|
||||
const blob = await response.blob();
|
||||
const urlDownload = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement("a");
|
||||
link.href = urlDownload;
|
||||
link.setAttribute("download", name);
|
||||
link.click();
|
||||
link.remove();
|
||||
}
|
||||
|
||||
const vnmoney = function(amount) {
|
||||
var readGroup = function (group) {
|
||||
let readDigit = [" Không", " Một", " Hai", " Ba", " Bốn", " Năm", " Sáu", " Bảy", " Tám", " Chín"];
|
||||
var temp = "";
|
||||
if (group == "000") return "";
|
||||
temp = readDigit[parseInt(group.substring(0, 1))] + " Trăm";
|
||||
if (group.substring(1, 2) == "0")
|
||||
if (group.substring(2, 3) == "0") return temp;
|
||||
else {
|
||||
temp += " Lẻ" + readDigit[parseInt(group.substring(2, 3))];
|
||||
return temp;
|
||||
}
|
||||
else
|
||||
temp += readDigit[parseInt(group.substring(1, 2))] + " Mươi";
|
||||
if (group.substring(2, 3) == "5") temp += " Lăm";
|
||||
else if (group.substring(2, 3) != "0") temp += readDigit[parseInt(group.substring(2, 3))];
|
||||
return temp;
|
||||
}
|
||||
var readMoney = function(num) {
|
||||
if ((num == null) || (num == "")) return "";
|
||||
let temp = "";
|
||||
while (num.length < 18) {
|
||||
num = "0" + num;
|
||||
}
|
||||
let g1 = num.substring(0, 3);
|
||||
let g2 = num.substring(3, 6);
|
||||
let g3 = num.substring(6, 9);
|
||||
let g4 = num.substring(9, 12);
|
||||
let g5 = num.substring(12, 15);
|
||||
let g6 = num.substring(15, 18);
|
||||
if (g1 != "000") {
|
||||
temp = readGroup(g1);
|
||||
temp += " Triệu";
|
||||
}
|
||||
if (g2 != "000") {
|
||||
temp += readGroup(g2);
|
||||
temp += " Nghìn";
|
||||
}
|
||||
if (g3 != "000") {
|
||||
temp += readGroup(g3);
|
||||
temp += " Tỷ";
|
||||
} else if ("" != temp) {
|
||||
temp += " Tỷ";
|
||||
}
|
||||
if (g4 != "000") {
|
||||
temp += readGroup(g4);
|
||||
temp += " Triệu";
|
||||
}
|
||||
if (g5 != "000") {
|
||||
temp += readGroup(g5);
|
||||
temp += " Nghìn";
|
||||
}
|
||||
temp = temp + readGroup(g6);
|
||||
temp = temp.replaceAll("Một Mươi", "Mười");
|
||||
temp = temp.trim();
|
||||
temp = temp.replaceAll("Không Trăm", "");
|
||||
temp = temp.trim();
|
||||
temp = temp.replaceAll("Mười Không", "Mười");
|
||||
temp = temp.trim();
|
||||
temp = temp.replaceAll("Mươi Không", "Mươi");
|
||||
temp = temp.trim();
|
||||
if (temp.indexOf("Lẻ") == 0) temp = temp.substring(2);
|
||||
temp = temp.trim();
|
||||
temp = temp.replaceAll("Mươi Một", "Mươi Mốt");
|
||||
temp = temp.trim();
|
||||
let result = temp.substring(0, 1).toUpperCase() + temp.substring(1).toLowerCase();
|
||||
return (result == "" ? "Không" : result) + " đồng chẵn"
|
||||
}
|
||||
return readMoney(amount.toString())
|
||||
}
|
||||
|
||||
const lang = function(code) {
|
||||
let field = store.common.find((v) => v.code===code)
|
||||
return field? field[store.lang] : ''
|
||||
}
|
||||
|
||||
const createMeta = function(metainfo) {
|
||||
return {
|
||||
title: metainfo.title,
|
||||
link: [
|
||||
{
|
||||
hid: 'canonical',
|
||||
rel: 'canonical',
|
||||
href: `https://y99.vn${route.path}`
|
||||
}
|
||||
],
|
||||
meta: [
|
||||
{
|
||||
hid: 'description',
|
||||
name: 'description',
|
||||
content: metainfo.description || ''
|
||||
},
|
||||
{
|
||||
hid: 'og:title',
|
||||
property: 'og:title',
|
||||
content: metainfo.title
|
||||
},
|
||||
{
|
||||
hid: 'og:description',
|
||||
property: 'og:description',
|
||||
content: metainfo.description || ''
|
||||
},
|
||||
{
|
||||
hid: 'og:type',
|
||||
property: 'og:type',
|
||||
content: metainfo.type || ''
|
||||
},
|
||||
{
|
||||
hid: 'og:image',
|
||||
property: 'og:image',
|
||||
content: metainfo.image || ''
|
||||
},
|
||||
{
|
||||
hid: 'og:url',
|
||||
property: 'og:url',
|
||||
content: `https://y99.vn${route.path}`
|
||||
},
|
||||
{
|
||||
property: 'og:locale',
|
||||
content: 'vi_VN'
|
||||
},
|
||||
{
|
||||
hid: 'fb:app_id',
|
||||
property: 'fb:app_id',
|
||||
content: metainfo.app_id || '549555567061256'
|
||||
},
|
||||
{
|
||||
hid: 'keywords',
|
||||
name: 'keywords',
|
||||
content: metainfo.keywords || ''
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
provide: {
|
||||
dialog,
|
||||
snackbar,
|
||||
getLink,
|
||||
errPhone,
|
||||
errEmail,
|
||||
errPhoneEmail,
|
||||
upload,
|
||||
checkChange,
|
||||
resetNull,
|
||||
copyToClipboard,
|
||||
nonAccent,
|
||||
linkID,
|
||||
exportpdf,
|
||||
exportImage,
|
||||
vnmoney,
|
||||
createMeta,
|
||||
download,
|
||||
dayjs,
|
||||
lang
|
||||
}
|
||||
}
|
||||
})
|
||||
454
plugins/02-connection.js
Normal file
454
plugins/02-connection.js
Normal file
@@ -0,0 +1,454 @@
|
||||
// nuxt 3 - plugins/my-plugin.ts
|
||||
import { useStore } from '~/stores/index'
|
||||
import axios from 'axios'
|
||||
|
||||
export default defineNuxtPlugin(() => {
|
||||
const module = 'system'
|
||||
const mode = 'dev'
|
||||
const paths = [
|
||||
{ name: "dev", url: "https://api.utopia.com.vn/" },
|
||||
{ name: "local", url: "http://localhost:8000/" },
|
||||
{ name: "prod", url: "https://api.utopia.com.vn/" },
|
||||
];
|
||||
const path = paths.find(v=>v.name===mode).url
|
||||
const apis = [
|
||||
{name: 'bizrights', url: 'data/Biz_Rights/', url_detail: 'data-detail/Biz_Rights/', params: {sort: '-id'}},
|
||||
{ name: "bizsetting", url: "data/Biz_Setting/", url_detail: "data-detail/Biz_Setting/", params: {}},
|
||||
{name: 'backup', url: 'data/Backup/', url_detail: 'data-detail/Backup/', params: {sort: '-id', values: 'id,code,name,status,status__name,start_time,end_time,create_time,file'}},
|
||||
{name: 'apps', url: 'data/Apps/', url_detail: 'data-detail/Apps/', params: {sort: 'id'}},
|
||||
{name: 'relation', commit: 'relation', url: 'data/Relation/', url_detail: 'data-detail/Relation/', params: {}},
|
||||
{name: 'systemsetting', commit: 'common', url: 'data/System_Setting/', url_detail: 'data-detail/System_Setting/', params: {sort: 'index'}},
|
||||
{name: 'approvestatus', url: 'data/Approve_Status/', url_detail: 'data-detail/Approve_Status/', params: {}},
|
||||
{name: 'staffstatus', url: 'data/Staff_Status/', url_detail: 'data-detail/Staff_Status/', params: {}},
|
||||
{name: 'userapps', url: 'data/User_Apps/', url_detail: 'data-detail/User_Apps/', params: {}},
|
||||
{name: 'dealer', url: 'data/Dealer/', url_detail: 'data-detail/Dealer/', params: {values: 'id,code,name,user,user__username,user__fullname,email,create_time'}},
|
||||
{name: 'datadeletion', url: 'data-deletion/', params: {}},
|
||||
{name: 'emailsetup', url: 'data/Email_Setup/', url_detail: 'data-detail/Email_Setup/', params: {sort: '-id'}},
|
||||
{name: 'emailsent', url: 'data/Email_Sent/', url_detail: 'data-detail/Email_Sent/', params: {values: 'id,subject,sender,sender__email,receiver,content,status__code,status,status__name,create_time', sort: '-id'}},
|
||||
{name: 'sendemail', url: 'send-email/', params: {}},
|
||||
{name: 'message', url: 'data/Message/', params: {sort: '-id'}},
|
||||
{ name: "exportcsv", url: "exportcsv/", params: {} },
|
||||
|
||||
{name: 'staff', url: 'data/Staff/', url_detail: 'data-detail/Staff/', params: {
|
||||
values: 'id,zalo,facebook,status,status__name,status__en,country__en,user__username,country,country__code,branch__code,creator,updater,updater__fullname,creator__fullname,issued_date,code,email,fullname,dob,sex,legal_code,sex__name,phone,legal_type,legal_type__name,legal_code,address,note,updater,updater__fullname,create_time,update_time,issued_place',
|
||||
distinct_values: {label: {type: 'Concat', field: ['code', 'fullname', 'phone']}, order: {type: 'RowNumber'}
|
||||
}, filter: {deleted: 0}, sort: '-id', summary: 'annotate'}},
|
||||
{name: 'applyresult', url: 'data/Apply_Result/', url_detail: 'data-detail/Apply_Result/', params: {sort: 'id'}},
|
||||
{name: 'langchoice', url: 'data/Lang_Choice/', url_detail: 'data-detail/Lang_Choice/', params: {sort: 'id'}},
|
||||
{name: 'displaystatus', url: 'data/Display_Status/', url_detail: 'data-detail/Display_Status/', params: {sort: 'id'}},
|
||||
{name: 'datastory', url: 'data/Data_Story/', url_detail: 'data-detail/Data_Story/', params: {sort: '-id', values: 'id,title,subtitle,image,header,content,link,canonical,category,status,language,language__code,language__name,valid_from,valid_to,user,create_time,update_time'}},
|
||||
{name: 'news', url: 'data/News/', url_detail: 'data-detail/News/', params: {sort: '-id', values: 'id,title,subtitle,image,header,content,link,canonical,category,status,language,language__code,language__name,valid_from,valid_to,user,create_time,update_time'}},
|
||||
{name: 'promotion', url: 'data/Promotion/', url_detail: 'data-detail/Promotion/', params: {sort: '-id', values: 'id,title,subtitle,image,header,content,link,canonical,category,status,language,language__code,language__name,valid_from,valid_to,user,create_time,update_time'}},
|
||||
{name: 'file', url: 'data/File/', url_detail: 'data-detail/File/', params: {sort: '-id'}},
|
||||
{name: 'token', url: 'data/Token/', url_detail: 'data-detail/Token/', params: {values: 'id,token,browser,browser_version,ip,os,platform,expiry,create_time,update_time,user,user__fullname,user__username', sort: '-id'}},
|
||||
{name: 'authtoken', url: 'auth-token/', params: {}},
|
||||
{name: 'notification', commit: 'updateNotification', url: 'data/Notify/', url_detail: 'data-detail/Notify/', params: {values:'id,title,content,image,link,task_log,user,user__username,user__fullname,event,seen,create_time,event__code,event__name,update_time'}},
|
||||
{name: 'settingapp', url: 'data/Setting_App/', url_detail: 'data-detail/Setting_App/', params: {sort: 'index'}},
|
||||
{name: 'upload', url: 'upload/', params: {}},
|
||||
{name: 'sendemail', url: 'send-email/', path: 'etl', params: {}},
|
||||
{name: 'sendemailnow', url: 'send-email-now/', path: 'etl', params: {}},
|
||||
{name: 'usersession', url: 'data/User_Session/', url_detail: 'data-detail/User_Session/', params: {values: 'id,token,balance,duration,start_time,end_time,session,create_time',
|
||||
distinct_values: {
|
||||
files: {type: 'ArrayAgg', field: ['usersession__file__file']}
|
||||
}, sort: '-id', summary: 'annotate'}
|
||||
},
|
||||
{name: 'stafffile', url: 'data/Staff_File/', url_detail: 'data-detail/Staff_File/',
|
||||
params: {values: 'id,ref,file,file__name,file__file'}},
|
||||
{name: 'usersetting', url: 'data/User_Setting/', url_detail: 'data-detail/User_Setting/', params: {}},
|
||||
{name: 'settingfields', url: 'data/User_Setting/', url_detail: 'data-detail/User_Setting/', params: {}},
|
||||
{name: 'settingclass', commit: 'settingclass', url: 'data/Setting_Class/', url_detail: 'data-detail/Setting_Class/', params: {}},
|
||||
{name: 'user', url: 'data/User/', url_detail: 'data-detail/User/', params: {sort: '-id', values: 'id,email,is_admin,type__en,type__name,auth_method__code,blocked,auth_status__code,username,register_method__code,fullname,type,type__code,type__name,create_time,create_time__date,auth_method,auth_status,register_method,create_time,update_time',
|
||||
distinct_values: {label: {type: 'Concat', field: ['username', 'fullname']},
|
||||
"apps": {"type": "ArrayAgg", "field": ["userapps__id", "userapps", "userapps__apps", "userapps__apps__code"]}},
|
||||
summary: 'annotate'
|
||||
}},
|
||||
{name: 'gethash', url: 'get-hash/', params: {}},
|
||||
{name: 'login', url: 'login/', params: {values: 'id,username,password,avatar,fullname,display_name,type,type__code,type__name,blocked,block_reason,block_reason__code,block_reason__name,blocked_by,last_login,auth_method,auth_method__code,auth_method__name,auth_status,auth_status__code,auth_status__name,register_method,register_method__code,register_method__name,create_time,update_time'}},
|
||||
{name: 'settingtype', commit: 'settingtype', url: 'data/Setting_Type/', url_detail: 'data-detail/Setting_Type/', params: {}},
|
||||
{name: 'colorchoice', commit: 'colorchoice', url: 'data/Color_Choice/', url_detail: 'data-detail/Color_Choice/', params: {sort: 'id'}},
|
||||
{name: 'filterchoice', commit: 'filterchoice', url: 'data/Filter_Choice/', url_detail: 'data-detail/Filter_Choice/', params: {sort: 'id'}},
|
||||
{name: 'datatype', commit: 'datatype', url: 'data/Data_Type/', url_detail: 'data-detail/Data_Type/', params: {sort: 'id'}},
|
||||
{name: 'textalign', commit: 'textalign', url: 'data/Text_Align/', url_detail: 'data-detail/Text_Align/', params: {sort: 'id'}},
|
||||
{name: 'placement', commit: 'placement', url: 'data/Placement/', url_detail: 'data-detail/Placement/', params: {sort: 'id'}},
|
||||
{name: 'colorscheme', commit: 'colorscheme', url: 'data/Color_Scheme/', url_detail: 'data-detail/Color_Scheme/', params: {sort: 'id'}},
|
||||
{name: 'textcolor', commit: 'textcolor', url: 'data/Text_Color/', url_detail: 'data-detail/Text_Color/', params: {sort: 'id'}},
|
||||
{name: 'filtertype', commit: 'filtertype', url: 'data/Filter_Type/', url_detail: 'data-detail/Filter_Type/', params: {sort: 'id'}},
|
||||
{name: 'sorttype', commit: 'sorttype', url: 'data/Sort_Type/', url_detail: 'data-detail/Sort_Type/', params: {sort: 'id'}},
|
||||
{name: 'tablesetting', commit: 'tablesetting', url: 'data/Table_Setting/', url_detail: 'data-detail/Table_Setting/', params: {sort: 'id', values: 'id,code,name,detail'}},
|
||||
{name: 'settingchoice', commit: 'settingchoice', url: 'data/Setting_Choice/', url_detail: 'data-detail/Setting_Choice/', params: {sort: 'id'}},
|
||||
{name: 'menuchoice', commit: 'menuchoice', url: 'data/Menu_Choice/', url_detail: 'data-detail/Menu_Choice/', params: {}},
|
||||
{name: 'moneyunit', commit: 'moneyunit', url: 'data/Money_Unit/', url_detail: 'data-detail/Money_Unit/', params: {}},
|
||||
{name: 'legaltype', commit: 'legaltype', url: 'data/Legal_Type/', url_detail: 'data-detail/Legal_Type/', params: {page: -1}},
|
||||
{name: 'sex', commit: 'sex', url: 'data/Sex/', url_detail: 'data-detail/Sex/', params: {}},
|
||||
{name: 'usertype', commit: 'UserType', url: 'data/User_Type/', url_detail: 'data-detail/User_Type/', params: {}},
|
||||
{name: 'province', commit: 'province', url: 'data/Province/', url_detail: 'data-detail/Province/', params: {}},
|
||||
{name: 'customerfile', url: 'data/Customer_File/', url_detail: 'data-detail/Customer_File/',
|
||||
params: {values: 'id,ref,file,file__name,file__file'}},
|
||||
{name: 'collaboratorfile', url: 'data/Collaborator_File/', url_detail: 'data-detail/Collaborator_File/',
|
||||
params: {values: 'id,ref,file,file__name,file__file'}},
|
||||
{name: 'customer', url: 'data/Customer/', url_detail: 'data-detail/Customer/', params: {
|
||||
values: 'id,branch__code,creator,updater,updater__fullname,creator__fullname,issued_date,code,email,fullname,dob,sex,legal_code,sex__name,phone,legal_type,legal_type__name,legal_code,address,note,updater,updater__fullname,create_time,update_time,issued_place',
|
||||
distinct_values: {label: {type: 'Concat', field: ['code', 'fullname', 'phone']}, order: {type: 'RowNumber'},
|
||||
image_count: {type: 'Count', field: 'custfile__id', subquery: {model: 'Customer_File', column: 'ref'}},
|
||||
count_note: {type: 'Count', field: 'custnote__id', subquery: {model: 'Customer_Note', column: 'ref'}}
|
||||
},
|
||||
filter: {deleted: 0}, sort: '-id', summary: 'annotate'}},
|
||||
{name: 'service', commit: 'service', url: 'data/Service/', url_detail: 'data-detail/Service/', params: {}},
|
||||
{name: 'useraction', url: 'data/User_Action/', url_detail: 'data-detail/User_Action/', params: {
|
||||
values: 'id,action,action__code,action__name,action__message,action__image,action__file,action__link,user,message,image,file,link,create_time'
|
||||
}},
|
||||
{name: 'filtersetting', url: 'data/Filter_Setting/', url_detail: 'data-detail/Filter_Setting/', params: {}},
|
||||
{name: 'getmodel', url: 'get-model/', params: {}},
|
||||
{name: 'paymenttype', url: 'data/Payment_Type/', url_detail: 'data-detail/Payment_Type/', params: {}},
|
||||
{"name":"payment","url":"data/Payment/","url_detail":"data-detail/Payment/","params":{values: 'id,service,service__code,service__name,session,session__session,type,type__code,type__name,amount,code,content,detail'}},
|
||||
{name: 'datastorycategory', url: 'data/Datastory_Category/', url_detail: 'data-detail/Datastory_Category/',
|
||||
params: {sort: 'id', values: 'id,story,category,category__code,category__name,title,image,url,create_time,update_time'}},
|
||||
{name: 'jobapply', url: 'data/Job_Apply/', url_detail: 'data-detail/Job_Apply/', params: {sort: '-id', values: 'id,staff,staff__code,code,fullname,phone,email,address,link,create_time,job,job__title,file,file__file,result,result__code,result__name'}},
|
||||
{name: 'collaborator', url: 'data/Collaborator/', url_detail: 'data-detail/Collaborator/', params: {values: 'id,zalo,facebook,bank,bank__name,bank_holder,bank_account,user,user__username,legal_type,status,status__code,status__name,code,fullname,phone,email,address,sex,sex__name,create_time,dob,legal_type__name,legal_code,issue_date,issue_place'}},
|
||||
{name: 'collateralcategory' , url: 'data/Collateral_Category/', url_detail: 'data-detail/Collateral_Category/', params: {sort: 'index'}},
|
||||
{name: 'paymenttype', url: 'data/Payment_Type/', url_detail: 'data-detail/Payment_Type/', params: {}},
|
||||
{name: 'country', commit: 'country', url: 'data/Country/', url_detail: 'data-detail/Country/', params: {}},
|
||||
{name: 'people' , url: 'data/People/', url_detail: 'data-detail/People/', params: {sort: '-id', values: 'id,email,creator,avatar,code,fullname,dob,sex,legal_code,sex__name,phone,issued_date,legal_type,legal_type__name,legal_code,address,note,updater,updater__fullname,create_time,update_time,issued_place'}},
|
||||
{name: 'branchtype' , url: 'data/Branch_Type/', url_detail: 'data-detail/Branch_Type/', params: {}},
|
||||
{name: 'branch', url: 'data/Branch/', url_detail: 'data-detail/Branch/', params: {sort: 'index', values: 'id,signature,signature__code,signature__fullname,index,start_date,manager,manager__phone,manager__email,manager__fullname,phone,email,address,code,name,type,type__code,type__name,create_time'}},
|
||||
{name: 'loanproduct' , url: 'data/Loan_Product/', url_detail: 'data-detail/Loan_Product/', params: {sort: '-id', values: 'id,principal,number_days,amount,collat_mandatory,penalty_info,penalty_rate,penalty_ratio,install_cycle_days,prin_cycle_days,itr_cycle_days,currency,currency__code,currency__rate,prin_pay_type,prin_pay_type__name,prin_cycle_days,itr_pay_type,itr_pay_type__name,itr_cycle_days,code,name,type,type__code,type__name,base,base__code,base__name,rate,unit,unit__name,ratio,creator,creator__fullname,create_time,update_time,rate_info,detail',distinct_values: {label: {type: 'Concat', field: ['code', 'name']}}, summary: 'annotate'}},
|
||||
{name: 'currency', url: 'data/Currency/', url_detail: 'data-detail/Currency/', params: {}},
|
||||
{name: 'defaultcurrency', url: 'data/Currency/', url_detail: 'data-detail/Currency/', params: {filter: {id: 1}}},
|
||||
{name: 'interestbase' , url: 'data/Interest_Base/', url_detail: 'data-detail/Interest_Base/', params: {sort: 'index'}},
|
||||
{name: 'paymentmethod' , url: 'data/Payment_Method/', url_detail: 'data-detail/Payment_Method/', params: {sort: 'name'}},
|
||||
{name: 'loantype' , url: 'data/Loan_Type/', url_detail: 'data-detail/Loan_Type/', params: {}},
|
||||
{name: 'loanstatus' , url: 'data/Loan_Status/', url_detail: 'data-detail/Loan_Status/', params: {}},
|
||||
{name: 'status', commit: 'status', url: 'data/Approve_Status/', url_detail: 'data-detail/Approve_Status/', params: {sort: 'index'}},
|
||||
{name: 'applicationstatus', url: 'data/Application_Status/', url_detail: 'data-detail/Application_Status/', params: {}},
|
||||
{name: 'executecommand', url: 'execute-command/', params: {}},
|
||||
{name: 'ssh', url: 'data/Ssh/', url_detail: 'data-detail/Ssh/', params: {filter: {deleted: 0}}},
|
||||
{name: 'sshlist', commit: 'updateSsh', url: 'data/Ssh/', url_detail: 'data-detail/Ssh/', params: {values: 'id,deleted,name,host,port,username,password,path,create_time,update_time', filter: {deleted: 0}, distinct_values: {label: {type: 'Concat', field: ['name', 'host']}}, summary: 'annotate'}},
|
||||
{
|
||||
name: "application",
|
||||
url: "data/Application/",
|
||||
url_detail: "data-detail/Application/",
|
||||
params: {
|
||||
values:
|
||||
"id,customer,customer__code,status,status__name,branch__code,country__code,currency__code,loan_amount,loan_term,code,fullname,phone,province,district,address,legal_type,legal_type__code,sex,sex__name,issue_place,loan_term,loan_amount,legal_type__name,legal_code,issue_date,issue_place,country,collaborator,create_time,update_time",
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const store = useStore()
|
||||
const { $copy, $clone, $updateSeriesFields, $snackbar, $remove, $dialog } = useNuxtApp()
|
||||
|
||||
const requestLogin = function() {
|
||||
store.commit('login', undefined)
|
||||
window.location.href = `https://${mode==='dev'? '' : ''}utopialogin.dev247.net/signin?module=${module}&link=${window.location.origin}`
|
||||
}
|
||||
|
||||
|
||||
const getpath = function(name) {
|
||||
return name? paths.find(v=>v.name===name).url : path
|
||||
}
|
||||
const findapi = function(name) {
|
||||
const result = Array.isArray(name)? apis.filter(v=>name.findIndex(x=>v.name===x)>=0) : apis.find(v=>v.name===name)
|
||||
return $copy(result)
|
||||
}
|
||||
|
||||
const readyapi = function(list) {
|
||||
var array = []
|
||||
list.forEach(element => {
|
||||
let found = apis.find(v=>v.name===element)
|
||||
if(found) {
|
||||
let ele = JSON.parse(JSON.stringify(found))
|
||||
ele.ready = store[element]? true : false
|
||||
array.push(ele)
|
||||
}
|
||||
})
|
||||
return array
|
||||
}
|
||||
|
||||
// get data
|
||||
const getapi = async function(list) {
|
||||
try {
|
||||
let arr = list.map(v => {
|
||||
let found = apis.find(v=>v.name===v.name)
|
||||
let url = (v.path? paths.find(x=>x.name===v.path).url : path) + (v.url? v.url : found.url)
|
||||
let params = v.params? v.params : (found.params===undefined? {} : found.params)
|
||||
params.login = store.login? store.login.id : undefined
|
||||
return {url: url, params: params}
|
||||
})
|
||||
//let data = await Promise.all(arr.map(v=>axios.get(v.url, {params: v.params})))
|
||||
let data = await Promise.all(arr.map(v => $fetch(v.url, { params: v.params })))
|
||||
data.map((v,i) => {
|
||||
list[i].data = v
|
||||
if(list[i].commit) {
|
||||
let data = v.rows? v.rows : v
|
||||
store.commit(list[i].commit, data)
|
||||
}
|
||||
})
|
||||
return list
|
||||
} catch(err) {
|
||||
console.log(err)
|
||||
return 'error'
|
||||
}
|
||||
}
|
||||
|
||||
// insert data
|
||||
const insertapi = async function(name, data, values, notify) {
|
||||
try {
|
||||
let found = findapi(name)
|
||||
let curpath = found.path? paths.find(x=>x.name===found.path).url : path
|
||||
var rs
|
||||
if(!Array.isArray(data))
|
||||
rs = await axios.post(`${curpath}${found.url}`, data, {params: {values: values}})
|
||||
else {
|
||||
let params = {action: 'import', values: values}
|
||||
rs = await axios.post(`${curpath}import-data/${found.url.substring(5, found.url.length-1)}/`, data, {params: params})
|
||||
}
|
||||
// update store
|
||||
if(found.commit) {
|
||||
if(store[found.commit]) {
|
||||
let copy = JSON.parse(JSON.stringify(store[found.commit]))
|
||||
let rows = Array.isArray(rs.data)? rs.data : [rs.data]
|
||||
rows.map(v=>{
|
||||
if(v.id && !v.error) {
|
||||
let idx = copy.findIndex(x=>x.id===v.id)
|
||||
if(idx>=0) copy[idx] = v
|
||||
else copy.push(v)
|
||||
}
|
||||
})
|
||||
store.commit(found.commit, copy)
|
||||
}
|
||||
}
|
||||
if(notify!==false) {
|
||||
store.lang===''? $snackbar('Dữ liệu đã được lưu vào hệ thống', 'Thành công', 'Success')
|
||||
: $snackbar(' The data has been saved to the system', 'Success', 'Success')
|
||||
}
|
||||
return rs.data
|
||||
} catch(err) {
|
||||
console.log(err)
|
||||
return 'error'
|
||||
}
|
||||
}
|
||||
|
||||
// update api
|
||||
const updateapi = async function(name, data, values, notify) {
|
||||
try {
|
||||
let found = findapi(name)
|
||||
let rs = await axios.put(`${path}${found.url_detail}${data.id}/`, data, {params: {values: values? values : found.params.values}})
|
||||
if(found.commit) {
|
||||
let index = store[found.commit]? store[found.commit].findIndex(v=>v.id===rs.data.id) : -1
|
||||
if(index>=0) {
|
||||
var copy = JSON.parse(JSON.stringify(store[found.commit]))
|
||||
if(Array.isArray(rs.data)===false) copy[index] = rs.data
|
||||
else {
|
||||
rs.data.forEach(v => {
|
||||
let index = copy.findIndex(v=>v.id===v.id)
|
||||
if(index>=0) copy[index] = v
|
||||
})
|
||||
}
|
||||
store.commit(found.commit, copy)
|
||||
}
|
||||
}
|
||||
if(notify!==false) {
|
||||
store.lang==='vi'? $snackbar('Dữ liệu đã được lưu vào hệ thống', 'Thành công', 'Success')
|
||||
: $snackbar(' The data has been saved to the system', 'Success', 'Success')
|
||||
}
|
||||
return rs.data
|
||||
} catch(err) {
|
||||
console.log(err)
|
||||
return 'error'
|
||||
}
|
||||
}
|
||||
|
||||
const findpage = function(arr) {
|
||||
var copy = $copy(store.pagetrack)
|
||||
var doFind = function() {
|
||||
let found = undefined
|
||||
for (let i=1; i<=30; i++) {
|
||||
let name = `pagedata${i}`
|
||||
if(!copy[name]) {
|
||||
found = name
|
||||
copy[name] = true
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found) console.log('pagename not found')
|
||||
return found
|
||||
}
|
||||
let result
|
||||
if(arr) {
|
||||
result = []
|
||||
arr.map(v=>{ result.push({name: v, value: doFind()})})
|
||||
} else {
|
||||
result = doFind(copy)
|
||||
}
|
||||
store.commit('pagetrack', copy)
|
||||
return result
|
||||
}
|
||||
|
||||
const getpage = function(showFilter) {
|
||||
return {data: [], fields: [], filters: [], update: undefined, action: undefined, filterby: undefined, api: {full_data: true}, origin_api: {full_data: true},
|
||||
tablesetting: undefined, setting: undefined, tabfield: true, setpage: {}, showFilter: (!showFilter)? true : showFilter}
|
||||
}
|
||||
|
||||
const setpage = function(pagename, row, api) {
|
||||
let json = row.detail
|
||||
let fields = $updateSeriesFields(json.fields)
|
||||
let copy = store[pagename] || getpage()
|
||||
copy.fields = fields
|
||||
copy.setting = $copy(row)
|
||||
if(json.filters) copy.filters = $copy(json.filters)
|
||||
if(json.tablesetting) copy.tablesetting = json.tablesetting
|
||||
if(api) {
|
||||
let copyApi = $copy(api)
|
||||
delete copyApi.data
|
||||
copyApi.full_data = api.data.full_data
|
||||
copyApi.total_rows = api.data.total_rows
|
||||
copy.api = copyApi
|
||||
copy.origin_api = copy
|
||||
}
|
||||
store.commit(pagename, copy)
|
||||
return copy
|
||||
}
|
||||
|
||||
const getdata = async function(name, filter, params, first) {
|
||||
let found = findapi(name)
|
||||
if(params) found.params = params
|
||||
else if(filter) found.params.filter = filter
|
||||
let rs = await getapi([found])
|
||||
let data = rs[0].data
|
||||
if(data) {
|
||||
if(data.rows) {
|
||||
return first? (data.rows.length>0? data.rows[0] : undefined) : data.rows
|
||||
} else {
|
||||
let rows = Array.isArray(data)? data : [data]
|
||||
return first? (rows.length>0? rows[0] : data) : data
|
||||
}
|
||||
} else {
|
||||
let rows = Array.isArray(data)? data : [data]
|
||||
return first? (rows.length>0? rows[0] : data) : data
|
||||
}
|
||||
}
|
||||
|
||||
// insert row
|
||||
var insertrow = async function(name, data, values, pagename, notify) {
|
||||
let result = await insertapi(name, data, values, notify)
|
||||
if(result==='error' || !pagename) return result
|
||||
let arr = Array.isArray(result)? result : [result]
|
||||
//arr = $formatArray(arr, store[pagename].fields)
|
||||
let copy = $clone(store[pagename])
|
||||
arr.map(x=>{
|
||||
let index = copy.data.findIndex(v=>v.id===x.id)
|
||||
index>=0? copy.data[index] = x : copy.data.unshift(x)
|
||||
})
|
||||
copy.update = {data: copy.data}
|
||||
store.commit(pagename, copy)
|
||||
return result
|
||||
}
|
||||
|
||||
// update row
|
||||
const updaterow = async function(name, data, values, pagename, notify) {
|
||||
let result = await updateapi(name, data, values, notify)
|
||||
if(result==='error' || !pagename) return result
|
||||
let arr = Array.isArray(result)? result : [result]
|
||||
//arr = $formatArray(arr, store[pagename].fields)
|
||||
let copy = $clone(store[pagename])
|
||||
arr.map(x=>{
|
||||
let index = copy.data.findIndex(v=>v.id===x.id)
|
||||
index>=0? copy.data[index] = x : copy.data.unshift(x)
|
||||
})
|
||||
copy.update = {data: copy.data}
|
||||
store.commit(pagename, copy)
|
||||
return result
|
||||
}
|
||||
|
||||
// delete data
|
||||
const deleteapi = async function(name, id) {
|
||||
try {
|
||||
var rs
|
||||
let found = findapi(name)
|
||||
if(!Array.isArray(id))
|
||||
rs = await $fetch(`${path}${found.url_detail}${id}`, {method: 'delete'})
|
||||
else {
|
||||
let params = {action: 'delete'}
|
||||
rs = await $fetch(`${path}import-data/${found.url.substring(5,found.url.length-1)}/`, id, {params: params})
|
||||
}
|
||||
if(found.commit) {
|
||||
let copy = JSON.parse(JSON.stringify(store[found.commit]))
|
||||
if(!Array.isArray(id)) {
|
||||
let index = copy.findIndex(v=>v.id===id)
|
||||
if(index>=0) $remove(copy, index)
|
||||
} else {
|
||||
rs.data.forEach(element => {
|
||||
let index = copy.findIndex(v=>v.id===element.id)
|
||||
if(index>=0) $remove(copy, index)
|
||||
})
|
||||
}
|
||||
store.commit(found.name, copy)
|
||||
console.log('copy', copy)
|
||||
}
|
||||
return id
|
||||
} catch(err) {
|
||||
console.log(err)
|
||||
if(err.response) {
|
||||
let content = `<span class="has-text-danger">Đã xảy ra lỗi, xóa dữ liệu không thành công</span>`
|
||||
if(err.response.data) content += `<p class="mt-2 has-text-grey-dark">
|
||||
<sapn class="icon-text">Chi tiết<SvgIcon class="ml-1" v-bind="{name: 'right.svg', type: 'dark', size: 20}"></SvgIcon></span></p>
|
||||
<p class="mt-2 has-text-grey-dark">${JSON.stringify(err.response.data)}</p>`
|
||||
$dialog(content, 'Lỗi', 'Error')
|
||||
}
|
||||
return 'error'
|
||||
}
|
||||
}
|
||||
|
||||
// delete row
|
||||
const deleterow = async function(name, id, pagename) {
|
||||
let result = await deleteapi(name, id)
|
||||
let arr = Array.isArray(id)? id : [{id: id}]
|
||||
let copy = $clone(store[pagename])
|
||||
arr.map(x=>{
|
||||
let index = copy.data.findIndex(v=>v.id===x.id)
|
||||
index>=0? $remove(copy.data,index) : false
|
||||
})
|
||||
copy.update = {data: copy.data}
|
||||
store.commit(pagename, copy)
|
||||
return result
|
||||
}
|
||||
|
||||
// update page
|
||||
const updatepage = function(pagename, row, action) {
|
||||
let copy = $clone(store[pagename])
|
||||
let rows = Array.isArray(row)? row : [row]
|
||||
rows.map(x=>{
|
||||
let idx = copy.data.findIndex(v=>v.id===x.id)
|
||||
if(action==='delete') {
|
||||
if(idx>=0) $remove(copy.data, idx)
|
||||
} else {
|
||||
idx>=0? copy.data[idx] = x : copy.data.unshift(x)
|
||||
}
|
||||
})
|
||||
copy.update = {data: copy.data}
|
||||
store.commit(pagename, copy)
|
||||
}
|
||||
|
||||
return {
|
||||
provide: {
|
||||
getpath,
|
||||
findapi,
|
||||
readyapi,
|
||||
getapi,
|
||||
getdata,
|
||||
insertapi,
|
||||
updateapi,
|
||||
updaterow,
|
||||
findpage,
|
||||
getpage,
|
||||
setpage,
|
||||
insertrow,
|
||||
deleteapi,
|
||||
deleterow,
|
||||
updatepage,
|
||||
store,
|
||||
requestLogin
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
8
plugins/03-api-loader.js
Normal file
8
plugins/03-api-loader.js
Normal file
@@ -0,0 +1,8 @@
|
||||
export default defineNuxtPlugin(async (nuxtApp) => {
|
||||
const { $getapi, $readyapi } = useNuxtApp()
|
||||
let connlist = $readyapi(['moneyunit', 'datatype', 'filterchoice', 'colorchoice', 'textalign', 'placement', 'colorscheme',
|
||||
'filtertype', 'sorttype', 'tablesetting', 'settingchoice', 'sharechoice', 'menuchoice', 'settingtype', 'settingclass',
|
||||
'systemsetting'])
|
||||
let filter = connlist.filter(v=>!v.ready)
|
||||
if(filter.length>0) await $getapi(filter)
|
||||
})
|
||||
42
plugins/04-components.js
Normal file
42
plugins/04-components.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import { defineNuxtPlugin } from '#app'
|
||||
import Notebox from '@/components/common/Notebox.vue'
|
||||
import PickDay from '~/components/datepicker/PickDay.vue'
|
||||
import Datepicker from '~/components/datepicker/Datepicker.vue'
|
||||
import ImageGallery from '~/components/media/ImageGallery.vue'
|
||||
import FileGallery from '~/components/media/FileGallery.vue'
|
||||
import FileUpload from '~/components/media/FileUpload.vue'
|
||||
import ChipImage from '~/components/media/ChipImage.vue'
|
||||
import Avatarbox from '~/components/common/Avatarbox.vue'
|
||||
import Imagebox from '~/components/media/Imagebox.vue'
|
||||
import Editor from '~/components/common/Editor.vue'
|
||||
import InputPhone from '@/components/common/InputPhone'
|
||||
import InputEmail from '@/components/common/InputEmail'
|
||||
import InputNumber from '@/components/common/InputNumber'
|
||||
import MenuAction from '~/components/menu/MenuAction.vue'
|
||||
import MenuAdd from '~/components/menu/MenuAdd.vue'
|
||||
import FormatNumber from '~/components/datatable/format/FormatNumber.vue'
|
||||
import FormatDate from '~/components/datatable/format/FormatDate.vue'
|
||||
import SvgIcon from '~/components/SvgIcon.vue'
|
||||
import DataView from '~/components/datatable/DataView.vue'
|
||||
import DataTable from '~/components/datatable/DataTable.vue'
|
||||
import MenuCheck from '~/components/menu/MenuCheck.vue'
|
||||
import MenuCollab from '~/components/menu/MenuCollab.vue'
|
||||
import MenuPhone from '~/components/menu/MenuPhone.vue'
|
||||
import MenuUser from '~/components/menu/MenuUser.vue'
|
||||
import MenuCV from '~/components/menu/MenuCV.vue'
|
||||
import MenuStaff from '~/components/menu/MenuStaff.vue'
|
||||
import Configuration from '~/components/maintab/Configuration.vue'
|
||||
|
||||
// import DataDeletion from '~/components/maintab/DataDeletion.vue'
|
||||
// import MarkData from '~/components/menu/MarkData.vue'
|
||||
// import MenuCheck from '~/components/menu/MenuCheck.vue'
|
||||
|
||||
const components = {Notebox, MenuAction, Datepicker, PickDay, ImageGallery, FileGallery, FileUpload, ChipImage, Avatarbox,
|
||||
DataTable, Imagebox, Editor, InputPhone, InputEmail, InputNumber, DataView, FormatNumber, SvgIcon, MenuAdd, Configuration,
|
||||
MenuCheck, MenuCollab, MenuPhone, FormatDate, MenuUser, MenuCV, MenuStaff, MenuCheck}
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
Object.entries(components).forEach(([name, component]) => {
|
||||
nuxtApp.vueApp.component(name, component)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user