changes
This commit is contained in:
334
components/datatable/NewField.vue
Normal file
334
components/datatable/NewField.vue
Normal file
@@ -0,0 +1,334 @@
|
||||
<template>
|
||||
<div class="tabs is-boxed">
|
||||
<ul>
|
||||
<li :class="selectType.code===v.code? 'is-active fs-16' : 'fs-16'" v-for="v in fieldType">
|
||||
<a @click="selectType = v"><span>{{ v.name }}</span></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<template v-if="selectType.code==='formula'">
|
||||
<b-radio :class="i===1? 'ml-5' : null" v-model="choice" v-for="(v,i) in choices" :key="i"
|
||||
:native-value="v.code">
|
||||
<span :class="v.code===choice? 'fsb-16' : 'fs-16'">{{v.name}}</span>
|
||||
</b-radio>
|
||||
<div class="has-background-light mt-3 px-3 py-3">
|
||||
<div class="tags are-medium mb-0" v-if="choice==='function'">
|
||||
<span :class="`tag ${func===v.code? 'is-primary' : 'is-dark'} is-rounded is-clickable`"
|
||||
v-for="(v,i) in funcs" :key="i" @click="changeFunc(v)" @dblclick="addFunc(v)">{{v.name}}</span>
|
||||
</div>
|
||||
<template v-else>
|
||||
<div class="field px-0 mx-0">
|
||||
<label class="label fs-14">Chọn trường<span class="has-text-danger"> *</span> </label>
|
||||
<div class="control">
|
||||
<!--<b-taginput
|
||||
size="is-small"
|
||||
v-model="tags"
|
||||
:data="fields.filter(v=>v.format==='number')"
|
||||
type="is-dark is-light"
|
||||
autocomplete
|
||||
:open-on-focus="true"
|
||||
field="caption"
|
||||
icon="plus"
|
||||
placeholder="Chọn trường"
|
||||
>
|
||||
<template slot-scope="props">
|
||||
<span class="mr-3 has-text-danger">{{props.option.name}}</span>
|
||||
<span :class="tags.find(v=>v.id===props.option.id)? 'has-text-dark' : ''">{{$stripHtml(props.option.label,50)}}</span>
|
||||
</template>
|
||||
<template slot="empty">
|
||||
Không có trường thỏa mãn
|
||||
</template>
|
||||
</b-taginput>-->
|
||||
</div>
|
||||
<p class="help has-text-danger" v-if="errors.find(v=>v.name==='tags')"> {{errors.find(v=>v.name==='tags').message}} </p>
|
||||
</div>
|
||||
<div class="field mt-3" v-if="tags.length>0">
|
||||
<p class="help is-primary mb-1">Click đúp vào để thêm vào công thức tính.</p>
|
||||
<div class="tags mb-2">
|
||||
<span @dblclick="formula = formula? (formula + ' ' + v.name) : v.name" class="tag is-dark is-rounded is-clickable"
|
||||
v-for="v in tags">
|
||||
{{v.name}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="tags">
|
||||
<span v-for="(v,i) in operator" :key="i">
|
||||
<span @dblclick="addOperator(v)" class="tag is-primary is-rounded is-clickable mr-4">
|
||||
<span class="fs-16">{{v.code}}</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="field mt-3 px-0 mx-0">
|
||||
<label class="label fs-14">Công thức tính <span class="has-text-danger"> * </span> </label>
|
||||
<p class="control">
|
||||
<textarea class="textarea" rows="3" type="text" :placeholder="placeholder" v-model="formula"> </textarea>
|
||||
</p>
|
||||
<p class="help has-text-danger" v-if="errors.find(v=>v.name==='formula')"> {{errors.find(v=>v.name==='formula').message}} </p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field is-horizontal mt-3 px-0 mx-0">
|
||||
<div class="field-body">
|
||||
<div class="field">
|
||||
<label class="label fs-14">Hiển thị theo <span class="has-text-danger"> * </span> </label>
|
||||
<div class="control">
|
||||
<b-autocomplete
|
||||
size="is-small"
|
||||
icon-right="magnify"
|
||||
:value="selectUnit? selectUnit.name : ''"
|
||||
placeholder=""
|
||||
:keep-first=true
|
||||
:open-on-focus=true
|
||||
:data="moneyunit"
|
||||
field="name"
|
||||
@select="option => selectUnit = option">
|
||||
</b-autocomplete>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label fs-14">Phần thập phân</label>
|
||||
<div class="control">
|
||||
<input class="input is-small" type="text" placeholder="" v-model="decimal">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="field px-0 mx-0">
|
||||
<label class="label">Tên trường <span class="has-text-danger"> * </span> </label>
|
||||
<p class="control">
|
||||
<input class="input" type="text" placeholder="Tên trường phải là duy nhất" v-model="name"
|
||||
:readonly="selectType? selectType.code==='formula': false">
|
||||
</p>
|
||||
<p class="help has-text-danger" v-if="errors.find(v=>v.name==='name')"> {{errors.find(v=>v.name==='name').message}} </p>
|
||||
<p class="help has-text-primary" v-else> Tên trường do hệ thống tự sinh.</p>
|
||||
</div>
|
||||
<div class="mt-5">
|
||||
<label class="label">Mô tả<span class="has-text-danger"> *</span></label>
|
||||
<div class="field has-addons">
|
||||
<div class="control is-expanded" >
|
||||
<input
|
||||
class="input"
|
||||
type="text"
|
||||
v-model="label"
|
||||
/>
|
||||
</div>
|
||||
<div class="control">
|
||||
<button class="button" @click="editLabel()">
|
||||
<span><SvgIcon v-bind="{name: 'pen.svg', type: 'dark', size: 17}"></SvgIcon></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help has-text-danger" v-if="errors.find(v=>v.name==='label')"> {{errors.find(v=>v.name==='label').message}} </p>
|
||||
</div>
|
||||
<div class="field mt-5" v-if="selectType.code==='empty'">
|
||||
<label class="label"
|
||||
>Kiểu dữ liệu
|
||||
<span class="has-text-danger"> * </span>
|
||||
</label>
|
||||
<div class="control fs-14">
|
||||
<span class="mr-4" v-for="(v,i) in datatype">
|
||||
<a class="icon-text" @click="changeType(v)">
|
||||
<SvgIcon v-bind="{name: `radio-${radioType.code===v.code? '' : 'un'}checked.svg`, type: 'gray', size: 22}"></SvgIcon>
|
||||
</a>
|
||||
{{v.name}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field mt-5">
|
||||
<p class="control">
|
||||
<a class="button is-primary has-text-white"
|
||||
@click="selectType.code==='formula'? createField() : createEmptyField()">Tạo cột</a>
|
||||
</p>
|
||||
</div>
|
||||
<Modal v-bind="showmodal" v-if="showmodal" @label="changeLabel" @close="close"></Modal>
|
||||
</template>
|
||||
<script setup>
|
||||
import { useStore } from '@/stores/index'
|
||||
import ScrollBox from '~/components/datatable/ScrollBox'
|
||||
const emit = defineEmits(['modalevent'])
|
||||
const store = useStore()
|
||||
const { $id, $copy, $clone, $empty, $stripHtml, $createField, $calc, $isNumber } = useNuxtApp()
|
||||
var props = defineProps({
|
||||
pagename: String,
|
||||
field: Object,
|
||||
filters: Object,
|
||||
filterData: Object,
|
||||
width: String
|
||||
})
|
||||
const moneyunit = store.moneyunit
|
||||
const datatype = store.datatype
|
||||
var showmodal = ref()
|
||||
var pagedata = store[props.pagename]
|
||||
var selectUnit = moneyunit.find(v=>v.code==='one')
|
||||
var data = []
|
||||
var current = 1
|
||||
var filterData = []
|
||||
var loading = false
|
||||
var fieldType = [{code: 'formula', name: 'Tạo công thức'}, {code: 'empty', name: 'Tạo cột rỗng'}]
|
||||
var errors = []
|
||||
var tags = []
|
||||
var formula = undefined
|
||||
var name = `f${$id().toLocaleLowerCase()}`
|
||||
var label = undefined
|
||||
var errors = []
|
||||
var selectType = fieldType.find(v=>v.code==='empty')
|
||||
var radioType = ref(datatype.find(v=>v.code==='string'))
|
||||
var fields = []
|
||||
var options = undefined
|
||||
var columns = $copy(pagedata.fields.filter(v=>v.format==='number'))
|
||||
var decimal = undefined
|
||||
var choices = [{code: 'column', name: 'Dùng cột dữ liệu'}, {code: 'function', name: 'Dùng hàm số'}]
|
||||
var choice = 'column'
|
||||
var funcs = [{code: 'sum', name: 'Sum'}, {code: 'max', name: 'Max'}, {code: 'min', name: 'Min'}, {code: 'avg', name: 'Avg'}]
|
||||
var func = 'sum'
|
||||
var placeholder = 'Minh hoạ công thức: f10001 + f10002'
|
||||
var args = undefined
|
||||
var operator = [{code: '+', name: 'Cộng'}, {code: '-', name: 'Trừ'}, {code: '*', name: 'Nhân'}, {code: '/', name: 'Chia'}, {code: '>', name: 'Lớn hơn'},
|
||||
{code: '>=', name: 'Lớn hơn hoặc bằng'}, {code: '<', name: 'Nhỏ hơn'}, {code: '<=', name: 'Nhỏ hơn hoặc bằng'}, {code: '==', name: 'Bằng'},
|
||||
{code: '&&', name: 'Và'}, {code: '||', name: 'Hoặc'}, {code: 'iif', name: 'Điều kiện rẽ nhánh'}]
|
||||
function editLabel() {
|
||||
if($empty(label)) return
|
||||
showmodal.value = {component: 'datatable/EditLabel', width: '500px', height: '300px', vbind: {label: label}}
|
||||
}
|
||||
function close() {
|
||||
showmodal.value = null
|
||||
}
|
||||
function changeLabel(evt) {
|
||||
label = evt
|
||||
showmodal.value = null
|
||||
}
|
||||
function changeType(v) {
|
||||
radioType.value = v
|
||||
}
|
||||
function addFunc(v) {
|
||||
formula = (formula? formula + ' ' : '') + v.name + '(C0: C2)'
|
||||
}
|
||||
function addOperator(v) {
|
||||
let text = v.code==='iif'? 'a>b? c : d' : v.code
|
||||
formula = `${formula || ''} ${text}`
|
||||
}
|
||||
function changeFunc(v) {
|
||||
placeholder = `${v.name}(C0:C2) hoặc ${v.name}(C0,C1,C2). C là viết tắt của cột dữ liệu, số thứ tự của cột bắt đầu từ 0`
|
||||
func = v.code
|
||||
}
|
||||
function getFields() {
|
||||
fields = pagedata? $copy(pagedata.fields) : []
|
||||
fields.map(v=>v.caption = (v.label? v.label.indexOf('<')>=0 : false)? v.name : v.label)
|
||||
}
|
||||
function checkFunc() {
|
||||
let error = false
|
||||
let val = formula.trim().replaceAll(' ', '')
|
||||
if(val.toLowerCase().indexOf(func)<0) error = true
|
||||
let start = val.toLowerCase().indexOf('(')
|
||||
let end = val.toLowerCase().indexOf(')')
|
||||
if( start<0 || end<0) error = true
|
||||
let content = val.substring(start+1, end)
|
||||
if($empty(content)) error = true
|
||||
let content1 = content.replaceAll(':', ',')
|
||||
let arr = content1.split(',')
|
||||
arr.map(v=>{
|
||||
let arr1 = v.toLowerCase().split('c')
|
||||
if(arr1.length!==2) error = true
|
||||
else if(!$isNumber(arr1[1])) error = true
|
||||
})
|
||||
return error? 'error' : content
|
||||
}
|
||||
function checkValid() {
|
||||
errors = []
|
||||
if(tags.length===0 && choice==='column') {
|
||||
errors.push({name: 'tags', message: 'Chưa chọn trường xây dựng công thức.'})
|
||||
}
|
||||
if(!$empty(formula)? $empty(formula.trim()) : true) {
|
||||
errors.push({name: 'formula', message: 'Công thức không được bỏ trống.'})
|
||||
}
|
||||
if(!$empty(label)? $empty(label.trim()) : true )
|
||||
errors.push({name: 'label', message: 'Mô tả không được bỏ trống.'})
|
||||
else if(pagedata.fields.find(v=>v.label.toLowerCase()===label.toLowerCase())) {
|
||||
errors.push({name: 'label', message: 'Mô tả bị trùng. Hãy đặt mô tả khác.'})
|
||||
}
|
||||
if(errors.length>0) return false
|
||||
//check formula in case use column
|
||||
if(choice==='column') {
|
||||
let val = $copy(formula)
|
||||
tags.forEach(v => {
|
||||
let myRegExp = new RegExp(v.name, 'g')
|
||||
val = val.replace(myRegExp, Math.random())
|
||||
})
|
||||
try {
|
||||
let value = $calc(val)
|
||||
if(isNaN(value) || value===Number.POSITIVE_INFINITY || value===Number.NEGATIVE_INFINITY) {
|
||||
errors.push({name: 'formula', message: 'Công thức không hợp lệ'})
|
||||
}
|
||||
}
|
||||
catch(err) {
|
||||
console.log(err)
|
||||
errors.push({name: 'formula', message: 'Công thức không hợp lệ'})
|
||||
}
|
||||
} else {
|
||||
if(checkFunc()==='error') errors.push({name: 'formula', message: `Hàm ${func.toUpperCase()} không hợp lệ`})
|
||||
}
|
||||
return errors.length>0? false : true
|
||||
}
|
||||
function createField() {
|
||||
if(!checkValid()) return
|
||||
let field = $createField(name.trim(), label.trim(), 'number', true)
|
||||
field.formula = formula.trim().replaceAll(' ', '')
|
||||
if(choice==='function') {
|
||||
field.func = func
|
||||
field.vals = checkFunc()
|
||||
} else field.tags = tags.map(v=>v.name)
|
||||
field.level = Math.max(...pagedata.fields.map(v=>v.level? v.level : 0)) + 1
|
||||
field.unit = selectUnit.detail
|
||||
field.decimal = decimal
|
||||
field.disable = 'search,value'
|
||||
let copy = $copy(pagedata)
|
||||
copy.fields.push(field)
|
||||
store.commit(props.pagename, copy)
|
||||
emit('newfield', field)
|
||||
tags = []
|
||||
formula = undefined
|
||||
label = undefined
|
||||
name = `f${$id()}`
|
||||
emit('close')
|
||||
}
|
||||
function createEmptyField() {
|
||||
errors = []
|
||||
if(!$empty(name)? $empty(name.trim()) : true )
|
||||
errors.push({name: 'name', message: 'Tên không được bỏ trống.'})
|
||||
else if(pagedata.fields.find(v=>v.name.toLowerCase()===name.toLowerCase())) {
|
||||
errors.push({name: 'name', message: 'Tên trường bị trùng. Hãy đặt tên khác.'})
|
||||
}
|
||||
if(!$empty(label)? $empty(label.trim()) : true )
|
||||
errors.push({name: 'label', message: 'Mô tả không được bỏ trống.'})
|
||||
else if(pagedata.fields.find(v=>v.label.toLowerCase()===label.toLowerCase())) {
|
||||
errors.push({name: 'label', message: 'Mô tả bị trùng. Hãy đặt mô tả khác.'})
|
||||
}
|
||||
if(errors.length>0) return
|
||||
let field = $createField(name.trim(), label.trim(), radioType.value.code, true)
|
||||
if(selectType.code==='chart') field = createChartField()
|
||||
let copy = $clone(pagedata)
|
||||
copy.fields.push(field)
|
||||
copy.update = {fields: copy.fields}
|
||||
store.commit(props.pagename, copy)
|
||||
//pagedata = copy
|
||||
emit('newfield', field)
|
||||
label = undefined
|
||||
name = `f${$id()}`
|
||||
emit('close')
|
||||
}
|
||||
function createChartField() {
|
||||
let array = pagedata.fields.filter(v=>v.format==='number' && v.show)
|
||||
if(args) array = $copy(args)
|
||||
let text = ''
|
||||
array.map((v,i)=>text += `'${v.name}${i<array.length-1? "'," : "'"}`)
|
||||
let label = ''
|
||||
array.map((v,i)=>label += `'${$stripHtml(v.label)}${i<array.length-1? "'," : "'"}`)
|
||||
let field = $createField(name.trim(), label.trim(), radioType.value.code, true)
|
||||
field.chart = 'yes'
|
||||
field.template = `<TrendingChart class="is-clickable" v-bind="{row: row, fields: [${text}], labels: [${label}], width: '80', height: '26', 'header': ['stock_code', 'name']}"/>`
|
||||
return field
|
||||
}
|
||||
//============
|
||||
getFields()
|
||||
</script>
|
||||
Reference in New Issue
Block a user