ilk commit

This commit is contained in:
burakovec
2025-07-04 14:11:18 +03:00
parent 7604d77a89
commit 1754e646a8
306 changed files with 24956 additions and 0 deletions

View File

@ -0,0 +1,17 @@
<template>
<div class="breadcrumb-wrapper">
<icon-button
@click="$router.go(-1)"
icon="arrow"
classList="breadcrumbs-back breadcrumb-link" />
<div class="breadcrumbs-list">
<icon-button toRoute="/" icon="dashboard" classList="breadcrumbs-dashboard" />
<span>{{ currentPageText }}</span>
</div>
</div>
</template>
<script setup lang="ts">
const props = defineProps<{
currentPageText: string
}>()
</script>

View File

@ -0,0 +1,225 @@
<template>
<div class="list-wrapper">
<table class="table-border table-colored table-list">
<thead>
<tr>
<th class="table-head-row-number" v-if="rowNumber">
<div class="table-head-content">Sıra No</div>
</th>
<template v-for="(headCell, h) in tableHeader">
<th :style="headCell.style || ''">
<div
:class="[
'table-head-content',
headCell.sort !== undefined && headCell.sort ? 'clickable' : ''
]"
@click="SortColumn(headCell)">
<span>{{ headCell.title }}</span>
<template
v-if="
headCell.sort !== undefined && headCell.sort && tableData.length > 1
">
<i
class="ico-c ico-sort"
v-if="
localSort?.sortOrder === '' ||
headCell.name !== localSort?.sortColumn
">
<svg>
<use href="@/assets/images/icons.svg#arrowsortable" />
</svg>
</i>
<i
:class="[
'ico-c',
'ico-sort',
localSort?.sortOrder === 'asc' ? 'order-asc' : ''
]"
v-if="
headCell.name === localSort?.sortColumn &&
localSort?.sortOrder !== ''
">
<svg>
<use href="@/assets/images/icons.svg#arrowline" />
</svg>
</i>
</template>
</div>
</th>
</template>
</tr>
</thead>
<tbody>
<tr v-if="tableData.length === 0 && !isPreview">
<td :colspan="rowNumber ? tableHeader.length + 1 : tableHeader.length">
Veri bulunamadı
</td>
</tr>
<tr
v-else
v-for="(dataRow, i) in tableData"
@click="LocalRowAction(dataRow)"
:class="[rowAction !== undefined && rowAction !== '' ? 'clickable' : '']">
<td v-if="rowNumber">
{{
showPagination && localPagination.pageNumber !== undefined
? (Number(localPagination.pageNumber) - 1) *
Number(localPagination.pageSize) +
i +
1
: i + 1
}}
</td>
<slot :name="'dataRow' + i" :rowData="dataRow" :rowIndex="i">
<template v-for="(dataCell, j) in tableHeader">
<td v-if="dataCell.computeHtml === undefined">
<slot
:name="'dataCell' + j"
:cellData="CellData(dataRow, dataCell.name)"
:cellIndex="j">
{{
dataCell.compute !== undefined
? dataCell.compute(dataRow)
: dataRow[dataCell.name]
}}
</slot>
</td>
<td v-else v-html="dataCell.computeHtml(dataRow)"></td>
</template>
</slot>
</tr>
<template
v-if="
localTotalValues !== undefined &&
Object.keys(localTotalValues).length > 0 &&
tableData.length > 0
">
<tr>
<td :colspan="totalValuesSpanLength" class="table-cell-align-right">
<strong>TOPLAM:</strong>
</td>
<template v-for="(val, i) in tableHeader">
<td v-if="localTotalValues[val.name] !== undefined">
{{
val.price
? globalStore.toTrLocale(localTotalValues[val.name])
: localTotalValues[val.name]
}}
</td>
</template>
</tr>
</template>
</tbody>
</table>
</div>
<data-table-pagination
v-if="pagination !== undefined && showPagination && !isPreview"
v-model:pagination="localPagination" />
</template>
<script setup lang="ts">
import { ref, reactive, computed, watch } from 'vue'
import type { Ref } from 'vue'
import { useGlobalStore } from '@/stores/globalStore'
const globalStore = useGlobalStore()
interface ITableHead {
[key: string]: any
title: string
name: string
compute?: Function
sort?: boolean
computeHtml?: Function
}
interface IPagination {
[key: string]: any
pageNumber?: number
pageSize: number
totalRecords: number
}
interface ISort {
[key: string]: any
sortColumn?: string
sortOrder?: string
}
export interface Props {
tableHeader: ITableHead[]
tableData: Record<string, any>
rowAction?: Function | string
pagination?: IPagination
sortData?: ISort
rowNumber?: boolean
totalValues?: Record<string, any>
isPreview?: boolean
}
const props = withDefaults(defineProps<Props>(), {
tableData: () => [],
rowNumber: false,
isPreview: false
})
const emit = defineEmits(['update:sortData', 'update:pagination'])
const localSort: Ref<ISort> = ref(props.sortData as ISort)
const localPagination: Ref<IPagination> = ref(props.pagination as IPagination)
const localTotalValues = reactive<Record<string, any>>(
props.totalValues as Record<string, any>
)
const totalValuesSpanLength = ref<number>(0)
if (localTotalValues !== undefined) {
let totalValuesLength = Object.keys(localTotalValues).length
let headerLength: number =
props.rowNumber !== undefined
? props.tableHeader.length + 1
: props.tableHeader.length
totalValuesSpanLength.value = headerLength - totalValuesLength
}
const showPagination = computed<boolean>(() => {
if (props.pagination !== undefined) {
if (Math.ceil(localPagination.value.totalRecords / globalStore.perPage) > 1)
return true
else return false
} else {
return false
}
})
const LocalRowAction = (d: Record<string, any>) => {
if (props.rowAction !== undefined) {
(props.rowAction! as Function)(d)
}
}
const SortColumn = (d: Record<string, any>) => {
if (d.sort && props.tableData.length > 1) {
let order = ''
if (localSort.value.sortColumn === d.name) {
if (localSort.value.sortOrder === '') order = 'desc'
if (localSort.value.sortOrder === 'desc') order = 'asc'
if (localSort.value.sortOrder === 'asc') {
order = ''
delete localSort.value.sortColumn
}
localSort.value.sortOrder = order
} else {
localSort.value.sortColumn = d.name
localSort.value.sortOrder = 'desc'
}
emit('update:sortData', localSort.value)
}
}
const CellData = (d: Record<string, any>, key: string): any => {
if (d[key] === null) return d
else return d[key]
}
watch(
() => localPagination,
() => {
emit('update:pagination', localPagination.value)
},
{ deep: true }
)
</script>

View File

@ -0,0 +1,88 @@
<template>
<div class="list-paging-wrapper">
<div class="pagination-content">
<icon-button
classList="pagination-nav pagination-nav-prev"
@click="changePage('<')"
icon="arrow" />
<div class="pagination-input">
<input
type="text"
class="pagination-current-page"
:value="pageNumber"
@keydown="validationStore.allowNumbersWithKeys"
@keyup="InputPageControl($event)"
@focus="PageNumberFocus($event)"
min="1"
:max="totalPage()" />
</div>
<div class="pagination-total-page">
/
<span>{{ totalPage() }}</span>
</div>
<div class="button-c" @click="getPage">Git</div>
<icon-button
classList="pagination-nav pagination-nav-next"
@click="changePage('>')"
icon="arrow" />
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import type { Ref } from 'vue'
import { useGlobalStore } from '@/stores/globalStore'
import { useValidationStore } from '@/stores/validationStore'
const globalStore = useGlobalStore()
const validationStore = useValidationStore()
interface IPagination {
pageNumber: number
pageSize: number
totalRecords: number
}
export interface Props {
pagination: IPagination
}
const props = withDefaults(defineProps<Props>(), {
})
const emit = defineEmits(['update:pagination'])
const localPagination: Ref<IPagination> = ref(props.pagination)
const pageNumber: Ref<number> = ref(1)
const totalPage = (): number => {
return Math.ceil(localPagination.value.totalRecords / globalStore.perPage)
}
const changePage = (v: string) => {
if (v === '<') {
if (Number(pageNumber.value) > 1) pageNumber.value--
} else {
if (Number(pageNumber.value) < totalPage()) pageNumber.value++
}
localPagination.value.pageNumber = pageNumber.value
emit('update:pagination', localPagination.value)
}
const InputPageControl = (e: Event) => {
if (Number((e.target as HTMLInputElement).value) < 1)
(e.target as HTMLInputElement).value = '1'
if (Number((e.target as HTMLInputElement).value) > totalPage())
(e.target as HTMLInputElement).value = String(totalPage())
pageNumber.value = Number((e.target as HTMLInputElement).value)
if((e as KeyboardEvent).key === 'Enter') getPage()
}
const PageNumberFocus = (e: Event) => {
;(e.target as HTMLInputElement).select()
}
const getPage = () => {
localPagination.value.pageNumber = pageNumber.value
emit('update:pagination', localPagination.value)
}
</script>

View File

@ -0,0 +1,136 @@
<template>
<teleport to="body">
<div class="dialog-w">
<span class="dialog-close" @click="CloseDialog"></span>
<div class="dialog-c">
<div
class="dialog-header"
v-if="localData.title !== undefined && localData.title !== ''">
<h3>{{ localData.title }}</h3>
</div>
<div
class="dialog-content"
v-if="localData.content !== undefined && localData.content !== ''">
{{ localData.content }}
</div>
<div class="dialog-footer">
<template
v-if="localData.buttons !== undefined && localData.buttons.length > 0"
v-for="(button, i) in dialogData.buttons">
<button
:class="['button-c', 'button-' + button.type]"
@click="button.function(id, button.data)">
{{ button.label }}
</button>
</template>
<button
v-if="localData.showClose"
class="button-c button-cancel"
@click="localData.closeFunction">
{{ localData.closeText }}
</button>
</div>
</div>
<div class="dialog-shadow" @click="CloseDialog"></div>
</div>
</teleport>
</template>
<script setup lang="ts">
import { onBeforeMount, reactive } from 'vue'
import { useDialogStore } from './dialogStore'
const dialogStore = useDialogStore()
export interface Props {
id: number
dialogData: Record<string, any>
}
const props = withDefaults(defineProps<Props>(), {})
const localData = reactive({
title: '',
content: '',
showClose: true,
closeText: 'Kapat',
closeFunction: () => {
CloseDialog()
},
buttons: []
})
const CreateData = () => {
Object.assign(localData, props.dialogData)
}
const CloseDialog = () => {
delete dialogStore.dialogs[props.id]
}
onBeforeMount(() => {
CreateData()
})
</script>
<style scoped>
.dialog-w {
display: flex;
justify-content: center;
align-items: center;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 9999;
}
.dialog-shadow {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1;
}
.dialog-c {
display: flex;
flex-direction: column;
width: 90%;
max-width: 480px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
z-index: 9;
position: relative;
padding: 24px;
}
.dialog-header {
margin-bottom: 16px;
}
.dialog-content {
margin-bottom: 16px;
}
.dialog-footer {
display: flex;
}
.dialog-close {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 24px;
right: 24px;
z-index: 9;
cursor: pointer;
}
.dialog-close::before,
.dialog-close::after {
content: '';
flex-direction: block;
width: 32px;
height: 2px;
background-color: #fff;
position: absolute;
transform: rotate(45deg);
}
.dialog-close::after {
transform: rotate(-45deg);
}
</style>

View File

@ -0,0 +1,12 @@
<template>
<template v-if="Object.keys(dialogStore.dialogs).length > 0">
<template v-for="(dialog, i) in dialogStore.dialogs">
<dialog-item :id="dialog.id" :dialogData="dialog.data" />
</template>
</template>
</template>
<script setup lang="ts">
import DialogItem from './DialogItem.vue'
import { useDialogStore } from './dialogStore'
const dialogStore = useDialogStore()
</script>

View File

@ -0,0 +1,103 @@
<template>
<template v-if="!onlyPreview">
<div :class="['file-item']">
<div
class="file-item-title"
v-if="localData[title as string] !== undefined && localData[title as string] !== ''">
{{ localData[title as string] }}
</div>
<div class="file-item-file-c">
<a :href="localFilePath" target="_blank" class="file-item-file clickable">
<div :class="['file-item-preview form-item-picture small-picture']">
<div class="image-c" v-if="isPicture">
<img :src="localFilePath" />
</div>
<div v-else>{{ fileType.toLocaleUpperCase() }}</div>
</div>
<div class="file-item-name">
{{ fileName }}
</div>
</a>
<i
class="ico-c ico-section ico-section-header-btn ico-replace"
@click="OnClick"
v-if="editable">
<svg><use href="/src/assets/images/icons.svg#replace"></use></svg>
</i>
</div>
</div>
</template>
<template v-else>
<div class="form-item-picture only-image clickable">
<a :href="localFilePath" target="_blank">
<div class="image-c" v-if="isPicture">
<img :src="localFilePath" />
</div>
<div v-else>{{ fileType.toLocaleUpperCase() }}</div>
</a>
<i
class="ico-c ico-section ico-section-header-btn ico-replace"
@click="OnClick"
v-if="editable">
<svg><use href="/src/assets/images/icons.svg#replace"></use></svg>
</i>
</div>
</template>
</template>
<script setup lang="ts">
import { ref, reactive, watch } from 'vue'
import axios from 'axios'
import { useGlobalStore } from '@/stores/globalStore'
const globalStore = useGlobalStore()
export interface Props {
data: Record<string, any>
onlyPreview?: boolean
filePath: string | null | undefined
title?: string
editable?: boolean
usePath?: boolean
}
const props = withDefaults(defineProps<Props>(), {
onlyPreview: false,
editable: true,
usePath: false
})
const emit = defineEmits(['click'])
const localData = reactive<Record<string, any>>(props.data)
const localFilePath = ref<string>('')
const fileType = ref<string>('')
const fileName = ref<string>('')
const isPicture = ref<boolean>(true)
if (props.filePath !== undefined && props.filePath !== null) {
localFilePath.value = props.usePath
? props.filePath as string
: (axios.defaults.baseURL as string + props.filePath as string) as string
fileType.value = globalStore.FileType(localFilePath.value)
fileName.value = globalStore.FileName(localFilePath.value)
isPicture.value = globalStore.IsImage(localFilePath.value)
}
const OnClick = () => {
let d = {
fileType: fileType.value,
fileName: fileName.value
}
Object.assign(localData, d)
emit('click', localData)
}
watch(
() => props.filePath,
() => {
localFilePath.value = props.usePath
? props.filePath as string
: (axios.defaults.baseURL as string + props.filePath as string) as string
}
)
</script>

View File

@ -0,0 +1,125 @@
<template>
<slot name="input">
<template v-if="listData !== undefined">
<div :class="['form-item', half ? 'form-item-half' : '', elclass || '']">
<span class="form-item-title" v-if="title !== undefined && title !== ''">
{{ title }}
<i v-if="required" class="form-item-alert">*</i>
</span>
<label :class="['label-radio', disabled ? 'disabled' : '']" v-for="(item, i) in listData">
<input
type="checkbox"
v-model="localValue"
:value="item[listVal!]"
:disabled="disabled"
:checked="item[listVal!] === localValue"
@click="OnClick"
@change="OnChange($event)"
:class="[
invalidText !== undefined && invalidText !== '' ? 'invalid' : '',
iclass || ''
]" />
<slot name="radiotext" :itemData="item">
<slot :name="'checktext' + i">
<span>{{ item[listText!] }}</span>
</slot>
</slot>
</label>
</div>
</template>
<template v-else>
<label :class="['label-radio', disabled ? 'disabled' : '']">
<input
type="checkbox"
v-model="localValue"
:value="val"
:disabled="disabled"
@click="OnClick"
@change="OnChange"
:class="[
invalidText !== undefined && invalidText !== '' ? 'invalid' : '',
iclass || ''
]" />
<slot name="checktext">
<span>{{ label }}</span>
</slot>
</label>
</template>
<span
class="form-item-alert"
v-if="InvalidMessages.length > 0 && InvalidMessages !== ''">
{{ InvalidMessages }}
</span>
<span
class="form-item-description"
v-if="description !== undefined && description !== ''">
{{ description }}
</span>
</slot>
</template>
<script setup lang="ts">
import { ref, reactive, computed, watch } from 'vue'
interface CheckObj {
[key: string]: any
text: string
}
export interface Props {
listData?: CheckObj[]
listText?: string
listVal?: string
val?: number | string | boolean
label?: string
disabled?: boolean
modelValue: (string | number)[] | boolean | string | number | null
half?: boolean
title?: string
invalidText?: string
description?: string
required?: boolean
iclass?: string
elclass?: string
}
const props = withDefaults(defineProps<Props>(), {
disabled: false,
half: false,
required: false
})
const emit = defineEmits(['update:modelValue', 'change', 'click'])
const localValue = ref<(string | number)[] | boolean | null | string | number>(
props.modelValue
)
const InvalidMessageText = reactive<Record<string, any>>({})
const InvalidMessages = computed<string>(() => {
let text = ''
Object.keys(InvalidMessageText).forEach((k: string, i: number) => {
text += InvalidMessageText[k] + ', '
})
return text
})
const OnChange = (e: Event) => {
emit('update:modelValue', localValue.value)
emit('change', e)
}
const OnClick = (e: Event) => {
emit('click', e)
}
watch(
() => props.invalidText,
() => {
if (props.invalidText !== undefined && props.invalidText !== '') {
Object.assign(InvalidMessageText, {})
InvalidMessageText.invalid = props.invalidText
} else {
delete InvalidMessageText.invalid
}
}
)
</script>

View File

@ -0,0 +1,253 @@
<template>
<div :class="['form-item', half ? 'form-item-half' : '', elclass || '']">
<span class="form-item-title" v-if="title !== undefined && title !== ''">
{{ title }}
</span>
<slot name="input">
<label>
<span v-if="label !== undefined && label !== ''">
{{ label }}
<i v-if="required" class="form-item-alert">*</i>
</span>
<input
:value="localValue"
:type="type"
:placeholder="placeholder"
:disabled="disabled"
:min="localMin"
:max="localMax"
@click="OnClick"
@change="OnChange"
@focus="OnFocus"
@keydown="OnKeyDown"
@keyup="OnKeyUp"
:class="[
invalidText !== undefined && invalidText !== '' ? 'invalid' : '',
iclass || ''
]" />
<span
class="form-item-alert"
v-if="InvalidMessages.length > 0 && InvalidMessages !== ''">
{{ InvalidMessages }}
</span>
<span
class="form-item-description"
v-if="description !== undefined && description !== ''">
{{ description }}
</span>
</label>
</slot>
</div>
</template>
<script setup lang="ts">
import { ref, computed, watch, onBeforeMount } from 'vue'
import { useDateStore } from '@/stores/dateStore'
const dateStore = useDateStore()
export interface Props {
type?: string
label?: string
disabled?: boolean
modelValue: number | string | Date | null | undefined
half?: boolean
title?: string
invalidText?: string
description?: string
placeholder?: string
required?: boolean
iclass?: string
elclass?: string
modelKey?: string
min?: string | Date | null
max?: string | Date | null
}
const props = withDefaults(defineProps<Props>(), {
type: 'datetime-local',
disabled: false,
half: false,
required: false
})
const emit = defineEmits([
'update:modelValue',
'change',
'focus',
'click',
'keydown',
'keyup'
])
const localValue = ref<any>()
const localMin = ref<string>()
const localMax = ref<string>()
const SetMin = () => {
if (props.min !== undefined && props.min !== null) {
if (props.type === 'datetime-local') {
let dmin = new Date(props.min)
dmin.setHours(0, 0, 0, 0)
localMin.value = dateStore.dateFormat({
date: dmin,
pattern: 'yy-mm-dd-t',
splitTime: 'T',
splitDate: '-'
})
} else {
localMin.value = dateStore.dateFormat({
date: props.min,
pattern: 'yy-mm-dd',
splitDate: '-'
})
}
}
}
const SetMax = () => {
if (props.max !== undefined && props.max !== null) {
if (props.type === 'datetime-local') {
let dmax = new Date(props.max)
dmax.setHours(0, 0, 0, 0)
localMax.value = dateStore.dateFormat({
date: props.max,
pattern: 'yy-mm-dd-t',
splitTime: 'T',
splitDate: '-'
})
} else {
localMax.value = dateStore.dateFormat({
date: props.max,
pattern: 'yy-mm-dd',
splitDate: '-'
})
}
}
}
if (props.type === 'date') {
if (props.modelValue !== undefined && props.modelValue !== null) {
if ((props.modelValue as string).includes('T')) {
localValue.value = (props.modelValue as string).split('T')[0]
} else {
localValue.value = props.modelValue
}
}
} else {
localValue.value = props.modelValue
}
const InvalidMessageText = ref<Record<string,any>>({})
const InvalidMessages = computed<string>(() => {
let text = ''
Object.keys(InvalidMessageText.value).forEach((k: string, i: number) => {
text += InvalidMessageText.value[k] + ', '
})
return text
})
const OnChange = (e: Event) => {
let val = (e.target as HTMLInputElement).value
if (val !== undefined && val !== '') {
if (localMin.value !== undefined) {
if (val < localMin.value) {
let min: string
if (props.type === 'datetime-local') {
min = dateStore.dateFormat({
date: localMin.value,
pattern: 'dd-mm-yy-t'
})
} else {
min = dateStore.dateFormat({
date: localMin.value,
pattern: 'dd-mm-yy'
})
}
InvalidMessageText.value[
props.modelKey + 'Min'
] = `Girdiğiniz tarih ${min} tarihinden büyük olmalıdır.`
} else {
delete InvalidMessageText.value[props.modelKey + 'Min']
}
}
if (localMax.value !== undefined) {
if (val > localMax.value) {
let max: string
if (props.type === 'datetime-local') {
max = dateStore.dateFormat({
date: localMax.value,
pattern: 'dd-mm-yy-t'
})
} else {
max = dateStore.dateFormat({
date: localMax.value,
pattern: 'dd-mm-yy'
})
}
InvalidMessageText.value[
props.modelKey + 'Max'
] = `Girdiğiniz tarih ${max} tarihinden küçük olmalıdır.`
} else {
delete InvalidMessageText.value[props.modelKey + 'Max']
}
}
}
localValue.value = (e.target as HTMLInputElement).value
emit('update:modelValue', localValue.value)
emit('change', e)
}
const OnFocus = (e: Event) => {
emit('focus', e)
}
const OnClick = (e: Event) => {
emit('click', e)
}
const OnKeyDown = (e: Event) => {
localValue.value = (e.target as HTMLInputElement).value
emit('update:modelValue', localValue.value)
emit('keydown', e)
}
const OnKeyUp = (e: Event) => {
localValue.value = (e.target as HTMLInputElement).value
if (props.required) {
if (localValue.value !== undefined && localValue.value.length < 1) {
InvalidMessageText.value[props.modelKey + 'Empty'] = 'Bu alan boş bırakılamaz'
} else {
delete InvalidMessageText.value[props.modelKey + 'Empty']
}
}
emit('update:modelValue', localValue.value)
emit('keyup', e)
}
watch(
() => props.invalidText,
() => {
if (props.invalidText !== undefined && props.invalidText !== '') {
InvalidMessageText.value = {}
InvalidMessageText.value.invalid = props.invalidText
} else {
delete InvalidMessageText.value.invalid
}
}
)
watch(
() => props.min,
() => {
if (props.min !== undefined && props.min !== '') {
SetMin()
}
}
)
watch(
() => props.max,
() => {
if (props.max !== undefined && props.max !== '') {
SetMax()
}
}
)
onBeforeMount(() => {
SetMin()
SetMax()
})
</script>

View File

@ -0,0 +1,153 @@
<template>
<div :class="['form-item', half ? 'form-item-half' : '', elclass || '']">
<span class="form-item-title" v-if="title !== undefined && title !== ''">
{{ title }}
</span>
<slot name="input">
<label>
<span v-if="label !== undefined && label !== ''">
{{ label }}
<i v-if="required" class="form-item-alert">*</i>
</span>
<input
:value="modelValue"
:type="type"
:placeholder="placeholder"
:disabled="disabled"
@input="OnInput"
@click="OnClick"
@change="OnChange"
@focus="OnFocus"
@keydown="OnKeyDown"
@keyup="OnKeyUp"
:class="[
invalidText !== undefined && invalidText !== '' ? 'invalid' : '',
iclass || ''
]"
:min="min"
:max="max"
:minlength="minlength"
:maxlength="maxlength" />
<span
class="form-item-alert"
v-if="InvalidMessages.length > 0 && InvalidMessages !== ''">
{{ InvalidMessages }}
</span>
<span
class="form-item-description"
v-if="description !== undefined && description !== ''">
{{ description }}
</span>
</label>
</slot>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, computed, watch } from 'vue'
import { useValidationStore } from '@/stores/validationStore'
const validationStore = useValidationStore()
export interface Props {
type?: string
label?: string
disabled?: boolean
modelValue: number | string | null | undefined
half?: boolean
title?: string
invalidText?: string
description?: string
placeholder?: string
required?: boolean
min?: string | number
max?: string | number
maxlength?: string | number
minlength?: string | number
iclass?: string
elclass?: string
modelKey?: string
}
const props = withDefaults(defineProps<Props>(), {
type: 'text',
disabled: false,
half: false,
required: false
})
const emit = defineEmits([
'update:modelValue',
'change',
'input',
'focus',
'click',
'keydown',
'keyup'
])
const localValue = ref<any>()
const InvalidMessageText = reactive<Record<string, any>>({})
const InvalidMessages = computed<string>(() => {
let text = ''
Object.keys(InvalidMessageText).forEach((k: string, i: number) => {
text += InvalidMessageText[k] + ', '
})
return text
})
const OnChange = (e: Event) => {
emit('update:modelValue', (e.target as HTMLInputElement).value)
emit('change', e)
}
const OnInput = (e: Event) => {
emit('update:modelValue', (e.target as HTMLInputElement).value)
emit('input', e)
}
const OnFocus = (e: Event) => {
emit('focus', e)
}
const OnClick = (e: Event) => {
emit('click', e)
}
const OnKeyDown = (e: Event) => {
emit('update:modelValue', (e.target as HTMLInputElement).value)
emit('keydown', e)
}
const OnKeyUp = (e: Event) => {
if (props.minlength !== undefined) {
if ((e.target as HTMLInputElement).value.length < Number(props.minlength)) {
InvalidMessageText.minlength = `Girdiğiniz bilgi en az ${props.minlength} karakter uzunluğunda olmalı`
} else {
delete InvalidMessageText.minlength
}
}
if (props.required) {
if ((e.target as HTMLInputElement).value.length < 1) {
InvalidMessageText[props.modelKey + 'Empty'] = 'Bu alan boş bırakılamaz'
} else {
delete InvalidMessageText[props.modelKey + 'Empty']
}
}
if (props.type === 'email') {
if (!validationStore.checkEmail((e.target as HTMLInputElement).value))
InvalidMessageText.validmail =
'Lütfen e-postayı doğru formatta giriniz. Örn: isim@alanadi.td'
else delete InvalidMessageText.validmail
}
emit('update:modelValue', (e.target as HTMLInputElement).value)
emit('keyup', e)
}
watch(
() => props.invalidText,
() => {
if (props.invalidText !== undefined && props.invalidText !== '') {
Object.assign(InvalidMessageText, {})
InvalidMessageText.invalid = props.invalidText
} else {
delete InvalidMessageText.invalid
}
}
)
</script>

View File

@ -0,0 +1,210 @@
<template>
<div :class="['form-item', half ? 'form-item-half' : '', elclass || '']">
<span class="form-item-title" v-if="title !== undefined && title !== ''">
{{ title }}
</span>
<slot name="input">
<label>
<span v-if="label !== undefined && label !== ''">
{{ label }}
<i v-if="required" class="form-item-alert">*</i>
</span>
<div :ref="'quillContainer' + rnd"></div>
<span
class="form-item-alert"
v-if="InvalidMessages.length > 0 && InvalidMessages !== ''">
{{ InvalidMessages }}
</span>
<span
class="form-item-description"
v-if="description !== undefined && description !== ''">
{{ description }}
</span>
</label>
</slot>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, computed, onMounted, useTemplateRef, watch } from 'vue'
import Quill from 'quill'
import 'quill/dist/quill.snow.css'
declare const window: any
window.Quill = Quill
export interface Props {
label?: string
disabled?: boolean
modelValue: string
half?: boolean
title?: string
invalidText?: string
description?: string
placeholder?: string
required?: boolean
maxlength?: string
minlength?: string
iclass?: string
elclass?: string
modelKey?: string
}
const props = withDefaults(defineProps<Props>(), {
disabled: false,
half: false,
required: false,
placeholder: ''
})
const emit = defineEmits(['update:modelValue', 'change', 'text-change'])
const rnd = ref<number>(Number(Math.random() * 10000000))
const toolbar = ref<any[]>([
[{ font: [] }, { size: [] }],
['bold', 'italic', 'underline', 'strike'],
[{ color: [] }, { background: [] }],
[{ script: 'super' }, { script: 'sub' }],
[{ header: '1' }, { header: '2' }, 'blockquote'],
[{ list: 'ordered' }, { list: 'bullet' }, { indent: '-1' }, { indent: '+1' }],
[{ align: [] }],
['link', 'image', 'video'],
['clean']
])
const options = reactive<Record<string, any>>({
theme: 'snow',
modules: {
toolbar: toolbar.value,
imageResize: {
modules: ['Resize', 'DisplaySize', 'Toolbar']
}
},
placeholder: props.placeholder,
readOnly: false,
debug: false
})
const QuillImageResize = ref<any>()
const editor = useTemplateRef<any>('quillContainer' + rnd.value)
const quill = ref<Quill | null>(null)
const localValue = ref<string>(props.modelValue)
const InvalidMessageText = ref<Record<string, any>>({})
const InvalidMessages = computed(() => {
let text = ''
Object.keys(InvalidMessageText.value).forEach((k: string, i: number) => {
text += InvalidMessageText.value[k] + ', '
})
return text
})
const OnTextChange = (e: any) => {
if (props.minlength !== undefined) {
if (localValue.value.length < Number(props.minlength)) {
InvalidMessageText.value.minlength = `Girdiğiniz bilgi en az ${props.minlength} karakter uzunluğunda olmalı`
} else {
delete InvalidMessageText.value.minlength
}
}
if (quill.value !== null) {
localValue.value = quill.value!.container.querySelector('.ql-editor')!.innerHTML
}
emit('update:modelValue', localValue.value)
emit('change', e)
}
const InitializeEditor = async () => {
await setupQuillEditor()
SetContent()
RegisterEditorEventListeners()
}
const SetContent = () => {
if (props.modelValue) quill.value!.root.innerHTML = props.modelValue
}
const setupQuillEditor = async () => {
//let Parchment = Quill.import('parchment')
window.Quill.imports.parchment.Attributor.Style =
window.Quill.imports.parchment.StyleAttributor
//@ts-ignore
QuillImageResize.value = await import('quill-image-resize-module')
quill.value = new Quill(editor.value, options) as Quill
;(quill.value!.getModule('toolbar') as Record<
string,
any
>)!.container.addEventListener('mousedown', (e: Event) => {
e.preventDefault()
})
;(quill.value!.getModule('toolbar') as Record<
string,
any
>)!.container.addEventListener('click', (e: Event) => {
if ((e.target as HTMLElement).className !== 'ql-image') e.preventDefault()
})
}
const RegisterEditorEventListeners = () => {
quill.value!.on('text-change', OnTextChange)
quill.value!.on('editor-change', OnTextChange)
//image resize imaja tıklandığını anlamıyor.
quill.value!.root.addEventListener('mouseover', OnMouseOver, false)
ListenForEditorEvent('text-change')
}
const ListenForEditorEvent = (type: any) => {
quill.value!.on(type, (...args) => {
emit(type, ...args)
})
}
const OnMouseOver = (e: Event) => {
if (
(e.target as HTMLElement)!.firstChild &&
((e.target as HTMLElement)!.firstChild as HTMLElement)!.tagName &&
((e.target as HTMLElement)!.firstChild as HTMLElement)!.tagName.toUpperCase() ===
'IMG'
) {
;(e.target as HTMLElement)!.classList.add('remove-click-p')
;((e.target as HTMLElement)!.firstChild as HTMLElement)!.classList.add(
'add-click-img'
)
}
}
onMounted(async () => {
InitializeEditor()
})
watch(
() => props.invalidText,
() => {
if (props.invalidText !== undefined && props.invalidText !== '') {
InvalidMessageText.value.invalid = props.invalidText
} else {
delete InvalidMessageText.value.invalid
}
}
)
</script>
<style>
.ql-toolbar {
width: 100%;
}
.ql-container {
width: 100%;
min-height: 120px;
}
.remove-click-p {
pointer-events: none;
}
.add-click-img {
pointer-events: all;
}
</style>

View File

@ -0,0 +1,128 @@
<template>
<slot name="input">
<template v-if="listData !== undefined">
<div :class="['form-item', half ? 'form-item-half' : '', elclass || '']">
<span class="form-item-title" v-if="title !== undefined && title !== ''">
{{ title }}
<i v-if="required" class="form-item-alert">*</i>
</span>
<label
:class="['label-radio', disabled ? 'disabled' : '']"
v-for="(item, i) in listData">
<input
type="radio"
:name="'radio' + rnd"
v-model="localValue"
:value="item[listVal!]"
:disabled="disabled"
@click="OnClick"
@change="OnChange"
:class="[
invalidText !== undefined && invalidText !== '' ? 'invalid' : '',
iclass || ''
]" />
<slot name="radiotext" :itemData="item">
<slot :name="'radiotext' + i">
<span>{{ item[listText!] }}</span>
</slot>
</slot>
</label>
</div>
</template>
<template v-else>
<label :class="['label-radio', disabled ? 'disabled' : '']">
<input
type="radio"
:name="group"
v-model="localValue"
:value="val"
:disabled="disabled"
@click="OnClick"
@change="OnChange"
:class="[
invalidText !== undefined && invalidText !== '' ? 'invalid' : '',
iclass || ''
]" />
<slot name="radiotext">
<span>{{ label }}</span>
</slot>
</label>
</template>
<span
class="form-item-alert"
v-if="InvalidMessages.length > 0 && InvalidMessages !== ''">
{{ InvalidMessages }}
</span>
<span
class="form-item-description"
v-if="description !== undefined && description !== ''">
{{ description }}
</span>
</slot>
</template>
<script setup lang="ts">
import { ref, reactive, computed, watch } from 'vue'
interface RadioObj {
[key: string]: any
text: string
}
export interface Props {
listData?: RadioObj[]
listText?: string
listVal?: string
val?: number | string | boolean
group?: string
label?: string
disabled?: boolean
modelValue: string | number | boolean | null
half?: boolean
title?: string
invalidText?: string
description?: string
required?: boolean
iclass?: string
elclass?: string
}
const props = withDefaults(defineProps<Props>(), {
disabled: false,
half: false,
required: false
})
const emit = defineEmits(['update:modelValue', 'change', 'click'])
const localValue = ref<string | number | boolean | null>(props.modelValue)
const rnd = ref<number>(Number(Math.floor(Math.random() * 1000000000)))
const InvalidMessageText = reactive<Record<string, any>>({})
const InvalidMessages = computed<string>(() => {
let text = ''
Object.keys(InvalidMessageText).forEach((k: string, i: number) => {
text += InvalidMessageText[k] + ', '
})
return text
})
const OnChange = (e: Event) => {
emit('update:modelValue', localValue.value)
emit('change', e)
}
const OnClick = (e: Event) => {
emit('click', e)
}
watch(
() => props.invalidText,
() => {
if (props.invalidText !== undefined && props.invalidText !== '') {
Object.assign(InvalidMessageText, {})
InvalidMessageText.invalid = props.invalidText
} else {
delete InvalidMessageText.invalid
}
}
)
</script>

View File

@ -0,0 +1,393 @@
<template>
<div
:class="[
'form-item',
half ? 'form-item-half' : '',
elclass || '',
$slots.button ? 'form-item-wb' : ''
]"
:id="'formselect' + rnd">
<span class="form-item-title" v-if="title !== undefined && title !== ''">
{{ title }}
</span>
<slot name="input">
<label class="form-select-list-c">
<span v-if="label !== undefined && label !== ''">
{{ label }}
<i v-if="required" class="form-item-alert">*</i>
</span>
<div
tabindex="0"
:class="[
'form-select-activator',
invalidText !== undefined && invalidText !== '' ? 'invalid' : '',
iclass || '',
disabled ? 'disabled' : '',
disabledClass || ''
]"
v-if="!activated"
@click="OpenList">
<slot name="activator" :activatorData="selectedOption">
{{ activatorText }}
</slot>
<i
class="ico-c ico-close"
v-if="
clearable &&
localValue !== '' &&
localValue !== undefined &&
localValue !== null
"
@click="ClearSelection($event)">
<svg><use href="/src/assets/images/icons.svg#close"></use></svg>
</i>
<i class="ico-c">
<svg><use href="/src/assets/images/icons.svg#arrow"></use></svg>
</i>
</div>
<div class="form-select-input" v-if="activated">
<form-input v-model="q" placeholder="Listede arayın" />
</div>
<teleport to="body" v-if="activated">
<div class="form-select-list" :id="'selectlist' + rnd">
<i
class="ico-c ico-close select-close-selection"
@click="CloseListFromSelection">
<svg><use href="/src/assets/images/icons.svg#close"></use></svg>
</i>
<div class="form-select-list-item" v-if="selectList.length === 0">
<span>Sonuç Bulunamadı</span>
</div>
<template v-else>
<div
class="form-select-list-item"
v-if="multiple"
@click="MultipleSelectAll($event)">
<input
class="select-box-check"
type="checkbox"
v-model="multipleAllSelected" />
<span>{{ multipleText }}</span>
</div>
<template v-for="(item, i) in selectList">
<div
v-if="localView(item)"
:class="['form-select-list-item', isSelected(item) ? 'selected' : '']"
@click="updateVal($event, item)">
<input
v-if="multiple"
class="select-box-check"
type="checkbox"
:value="listVal !== undefined ? item[listVal] : item"
v-model="localValue" />
<slot name="option" :optionData="item">
<span>{{ listText !== undefined ? item[listText] : item }}</span>
</slot>
</div>
</template>
</template>
</div>
</teleport>
<span
class="form-item-alert"
v-if="InvalidMessages.length > 0 && InvalidMessages !== ''">
{{ InvalidMessages }}
</span>
<span
class="form-item-description"
v-if="description !== undefined && description !== ''">
{{ description }}
</span>
</label>
<div v-if="$slots.button" class="form-item-button"><slot name="button"></slot></div>
</slot>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, computed, onMounted, watch } from 'vue'
import { useGlobalStore } from '@/stores/globalStore'
const globalStore = useGlobalStore()
export interface Props {
listData: Record<string, any>[]
listText?: string
listVal?: string
label?: string
disabled?: boolean
modelValue: string | number | number[] | string[] | null
half?: boolean
title?: string
invalidText?: string
description?: string
placeholder?: string
required?: boolean
iclass?: string
elclass?: string
clearable?: boolean
extraData?: any
multiple?: boolean
multipleText?: string
view?: Function
disabledClass?: string
}
const props = withDefaults(defineProps<Props>(), {
listData: () => [],
disabled: false,
half: false,
required: false,
clearable: false,
extraData: '',
multiple: false,
multipleText: 'Tümü'
})
const emit = defineEmits(['update:modelValue', 'change','clear'])
const activated = ref<Boolean>(false)
const multipleAllSelected = ref<boolean>(false)
const q = ref<string>('')
const rnd = ref<number>(Number(Math.floor(Math.random() * 1000000000)))
const localValue = ref<string | number | boolean | null | string[]>()
const selectedOption = ref<Record<string, any>>({})
if (props.multiple) {
if (props.modelValue === null || props.modelValue === undefined) {
localValue.value = [] as string[]
} else {
localValue.value = props.modelValue as string[]
}
} else {
localValue.value = props.modelValue as string
}
const localView = (data: Record<string, any>) => {
if (props.view !== undefined) {
if (props.extraData !== undefined) return props.view(data, props.extraData)
else return props.view(data, props)
} else {
return true
}
}
const localExtra = ref<any>(props.extraData)
const InvalidMessageText = reactive<Record<string, any>>({})
const InvalidMessages = computed<string>(() => {
let text = ''
Object.keys(InvalidMessageText).forEach((k: string, i: number) => {
text += InvalidMessageText[k] + ', '
})
return text
})
const activatorText = computed<any>(() => {
if (
localValue.value === '' ||
localValue.value === null ||
localValue.value === undefined
) {
return props.placeholder || 'Lütfen Seçim Yapınız'
} else {
if (props.multiple) {
if (multipleAllSelected.value) {
return props.multipleText
} else {
let textm = props.listData.filter((v: Record<string, any>) => {
let val = props.listVal !== undefined ? v[props.listVal] : v
return (localValue.value as string[]).includes(val)
})
if (textm !== undefined) {
if (props.listVal !== undefined) {
let listText = ''
textm.forEach((itm: Record<string, any>) => {
listText += itm[props.listText as string] + ', '
})
return listText.slice(0, -2)
} else {
return textm.toString()
}
} else {
return 'Lütfen Seçim Yapınız'
}
}
} else {
let text = props.listData.filter((v: Record<string, any>) => {
let val = props.listVal !== undefined ? v[props.listVal] : v
return localValue.value === val
})[0]
return text !== undefined
? props.listText !== undefined
? text[props.listText]
: text
: 'Lütfen Seçim Yapınız'
}
}
})
const selectList = computed<Record<string, any>[]>(() => {
if (q.value.length > 1) {
return props.listData.filter((v: Record<string, any>) => {
let val = props.listText !== undefined ? v[props.listText] : v
return globalStore.trToUpper(val).includes(globalStore.trToUpper(q.value))
})
} else {
return props.listData
}
})
const isSelected = (d: Record<string, any>): boolean => {
if (localValue.value !== null && localValue.value !== undefined) {
let val = props.listVal !== undefined ? d[props.listVal] : d
return props.multiple
? (localValue.value as string[]).includes(val)
: val === localValue.value
} else {
return false
}
}
const MultipleSelectAll = (e: Event) => {
if (props.multiple) {
if (multipleAllSelected.value) {
localValue.value = []
multipleAllSelected.value = false
} else {
props.listData.forEach((data: any, i: number) => {
if (props.listVal !== undefined)
(localValue.value as string[]).push(data[props.listVal])
else (localValue.value as string[]).push(data)
})
multipleAllSelected.value = true
}
let item: Record<string, any> = {}
emit('update:modelValue', localValue.value as string[])
emit('change', e, localValue.value, item, localExtra.value)
}
}
const ClearSelection = (e: Event) => {
e.stopPropagation()
if (typeof localValue.value === 'number') localValue.value = null
if (typeof localValue.value === 'string') localValue.value = ''
if (typeof localValue.value === 'boolean') localValue.value = false
let item: Record<string, any> = {}
selectedOption.value = {}
emit('update:modelValue', localValue.value)
emit('change', e, localValue.value, item, localExtra.value)
emit('clear', e, localValue.value)
}
const CloseListFromSelection = () => {
activated.value = false
document.removeEventListener('click', closeList)
}
const closeList = (e: Event) => {
let p = e.composedPath && e.composedPath()
var open = false
if (p) {
p.pop()
p.forEach((pv) => {
if (
(pv as HTMLElement).id !== '' &&
(pv as HTMLElement).id !== undefined &&
(pv as HTMLElement).id.includes(String(rnd.value))
)
open = true
})
}
if (!open) {
activated.value = false
document.removeEventListener('click', closeList)
}
}
const OpenList = (e: Event) => {
if (props.disabled) return
e.stopPropagation()
q.value = ''
activated.value = true
setTimeout(() => {
let actEl = document.querySelector('#formselect' + rnd.value) as HTMLElement
let el = document.querySelector('#selectlist' + rnd.value) as HTMLElement
let rcAct = actEl.getBoundingClientRect() as DOMRect
el.style.width = rcAct.width - 8 + 'px'
el.style.left = rcAct.left + 4 + 'px'
if (window.innerHeight - rcAct.bottom < 100) {
el.style.bottom = window.innerHeight - rcAct.top - 24 + 'px'
el.style.maxHeight = rcAct.top - 64 + 'px'
} else {
el.style.top = rcAct.bottom + 'px'
el.style.maxHeight = window.innerHeight - rcAct.bottom - 16 + 'px'
}
}, 5)
setTimeout(() => {
document.addEventListener('click', closeList)
}, 10)
}
const updateVal = (e: Event, item: Record<string, any>) => {
e.stopPropagation()
let val = props.listVal !== undefined ? item[props.listVal] : item
if (props.multiple) {
if ((localValue.value as string[]).indexOf(val) > -1)
(localValue.value as string[]).splice(
(localValue.value as string[]).indexOf(val),
1
)
else (localValue.value as string[]).push(val)
multipleAllSelected.value =
(localValue.value as string[]).length === props.listData.length
} else {
localValue.value = val
activated.value = false
document.removeEventListener('click', closeList)
}
selectedOption.value = item
emit('update:modelValue', localValue.value)
emit('change', e, localValue.value, item, localExtra.value)
}
const SetSelectedOption = () => {
selectedOption.value = props.listData.filter((v: Record<string, any>) => {
return v[props.listVal as string] === props.modelValue
})[0]
}
onMounted(() => {
if (props.multiple) {
multipleAllSelected.value =
(localValue.value as string[]).length === props.listData.length
}
SetSelectedOption()
})
watch(
() => props.invalidText,
() => {
if (props.invalidText !== undefined && props.invalidText !== '') {
Object.assign(InvalidMessageText, {})
InvalidMessageText.invalid = props.invalidText
} else {
delete InvalidMessageText.invalid
}
}
)
watch(
() => props.listData,
() => {
if (props.modelValue !== undefined) {
if (props.listData !== undefined) {
SetSelectedOption()
}
}
}
)
</script>

View File

@ -0,0 +1,185 @@
<template>
<div :class="['form-item', half ? 'form-item-half' : '', elclass || '']">
<span class="form-item-title" v-if="title !== undefined && title !== ''">
{{ title }}
</span>
<slot name="input">
<span v-if="label !== undefined && label !== ''" class="summer-label">
{{ label }}
<i v-if="required" class="form-item-alert">*</i>
</span>
<div :ref="'summerContainer' + rnd" class="summer-editor"></div>
<span
class="form-item-alert"
v-if="InvalidMessages.length > 0 && InvalidMessages !== ''">
{{ InvalidMessages }}
</span>
<span
class="form-item-description"
v-if="description !== undefined && description !== ''">
{{ description }}
</span>
</slot>
</div>
</template>
<script setup lang="ts">
import {
ref,
reactive,
computed,
onMounted,
useTemplateRef,
watch,
onBeforeUnmount
} from 'vue'
import $ from 'jquery'
import 'summernote/dist/summernote-lite.min.css'
import 'summernote/dist/summernote-lite.min.js'
//import SummernoteEditor from 'vue3-summernote-editor'
export interface Props {
label?: string
disabled?: boolean
modelValue: string
half?: boolean
title?: string
invalidText?: string
description?: string
placeholder?: string
required?: boolean
maxlength?: string
minlength?: string
iclass?: string
elclass?: string
modelKey?: string
}
const props = withDefaults(defineProps<Props>(), {
disabled: false,
half: false,
required: false,
placeholder: ''
})
const emit = defineEmits(['update:modelValue', 'change', 'text-change'])
const rnd = ref<number>(Number(Math.random() * 10000000))
const editorElement = useTemplateRef<any>('summerContainer' + rnd.value)
const editor = ref<any>(null)
const localValue = ref<string>(props.modelValue)
const InvalidMessageText = ref<Record<string, any>>({})
const InvalidMessages = computed(() => {
let text = ''
Object.keys(InvalidMessageText.value).forEach((k: string, i: number) => {
text += InvalidMessageText.value[k] + ', '
})
return text
})
const SetupEditor = async () => {
await InitializeEditor()
SetContent()
}
const InitializeEditor = async () => {
if (editorElement.value) {
editor.value = $(editorElement.value).summernote({
height: 300,
codeviewFilter: false,
codeviewIframeFilter: false,
toolbar: [
['style', ['style']],
[
'font',
[
'bold',
'italic',
'underline',
'strikethrough',
'superscript',
'subscript',
'clear'
]
],
['fontname', ['fontname']],
['color', ['color']],
['para', ['ul', 'ol', 'paragraph']],
['height', ['height']],
['table', ['table']],
['insert', ['link', 'picture', 'video']],
['view', ['fullscreen', 'codeview', 'undo', 'redo', 'help']]
],
callbacks: {
onChange: (content: any, e: any) => {
localValue.value = content
OnTextChange()
emit('update:modelValue', localValue.value)
emit('change', e)
},
onInit: () => {}
}
})
}
}
const SetContent = () => {
if (props.modelValue) $(editorElement.value).summernote('code', props.modelValue)
}
const OnTextChange = () => {
if (props.minlength !== undefined) {
if (localValue.value.length < Number(props.minlength)) {
InvalidMessageText.value.minlength = `Girdiğiniz bilgi en az ${props.minlength} karakter uzunluğunda olmalı`
} else {
delete InvalidMessageText.value.minlength
}
}
}
onMounted(async () => {
SetupEditor()
})
watch(
() => props.invalidText,
() => {
if (props.invalidText !== undefined && props.invalidText !== '') {
InvalidMessageText.value.invalid = props.invalidText
} else {
delete InvalidMessageText.value.invalid
}
}
)
</script>
<style>
.summer-label {
width: 100%;
}
.summer-editor {
width: 100%;
}
.note-editor {
width: 100%;
}
.note-editor.note-frame.fullscreen {
background-color: #fff;
}
.note-color.open .note-dropdown-menu {
display: flex;
}
.note-editor .note-toolbar .note-color-palette div .note-color-btn {
min-height: inherit;
}
.note-editable ul {
list-style-type: inherit;
list-style-image: inherit;
margin: inherit;
padding: inherit;
}
.note-editable ul li {
list-style-type: inherit;
list-style-image: inherit;
}
.note-editable ol li {
list-style-type: inherit;
list-style-image: inherit;
}
</style>

View File

@ -0,0 +1,133 @@
<template>
<div :class="['form-item', half ? 'form-item-half' : '', elclass || '']">
<span class="form-item-title" v-if="title !== undefined && title !== ''">
{{ title }}
</span>
<slot name="input">
<label>
<span v-if="label !== undefined && label !== ''">
{{ label }}
<i v-if="required" class="form-item-alert">*</i>
</span>
<textarea
:value="modelValue"
:rows="rows"
:placeholder="placeholder"
:disabled="disabled"
@input="OnInput"
@click="OnClick"
@change="OnChange"
@focus="OnFocus"
@keydown="OnKeyDown"
@keyup="OnKeyUp"
:class="[
invalidText !== undefined && invalidText !== '' ? 'invalid' : '',
iclass || ''
]"
:minlength="minlength"
:maxlength="maxlength"></textarea>
<span
class="form-item-alert"
v-if="InvalidMessages.length > 0 && InvalidMessages !== ''">
{{ InvalidMessages }}
</span>
<span
class="form-item-description"
v-if="description !== undefined && description !== ''">
{{ description }}
</span>
</label>
</slot>
</div>
</template>
<script setup lang="ts">
import { ref, computed, watch } from 'vue'
export interface Props {
label?: string
disabled?: boolean
modelValue: number | string | null | undefined
half?: boolean
title?: string
rows?: number
invalidText?: string
description?: string
placeholder?: string
required?: boolean
maxlength?: string
minlength?: string
iclass?: string
elclass?: string
modelKey?: string
}
const props = withDefaults(defineProps<Props>(), {
disabled: false,
half: false,
rows: 4,
required: false
})
const emit = defineEmits([
'update:modelValue',
'change',
'input',
'focus',
'click',
'keydown',
'keyup'
])
interface InvalidMessagesObj {
[key: string]: any
}
const InvalidMessageText = ref<InvalidMessagesObj>({})
const InvalidMessages = computed(() => {
let text = ''
Object.keys(InvalidMessageText.value).forEach((k: string, i: number) => {
text += InvalidMessageText.value[k] + ', '
})
return text
})
const OnChange = (e: Event) => {
emit('update:modelValue', (e.target as HTMLInputElement).value)
emit('change', e)
}
const OnInput = (e: Event) => {
emit('update:modelValue', (e.target as HTMLInputElement).value)
emit('input', e)
}
const OnFocus = (e: Event) => {
emit('focus', e)
}
const OnClick = (e: Event) => {
emit('focus', e)
}
const OnKeyDown = (e: Event) => {
emit('update:modelValue', (e.target as HTMLInputElement).value)
emit('keydown', e)
}
const OnKeyUp = (e: Event) => {
if (props.minlength !== undefined) {
if ((e.target as HTMLInputElement)?.value.length < Number(props.minlength)) {
InvalidMessageText.value.minlength = `Girdiğiniz bilgi en az ${props.minlength} karakter uzunluğunda olmalı`
} else {
delete InvalidMessageText.value.minlength
}
}
emit('update:modelValue', (e.target as HTMLInputElement).value)
emit('keyup', e)
}
watch(
() => props.invalidText,
() => {
if (props.invalidText !== undefined && props.invalidText !== '') {
InvalidMessageText.value = {}
InvalidMessageText.value.invalid = props.invalidText
} else {
delete InvalidMessageText.value.invalid
}
}
)
</script>

View File

@ -0,0 +1,42 @@
<template>
<div :class="[classList]">
<template v-if="toRoute === undefined">
<div class="ico-clickable" @click="OnClick">
<i :class="['ico-c', iconClass]">
<svg>
<use :href="icourl + '#' + icon" />
</svg>
</i>
</div>
</template>
<template v-else>
<router-link :to="toRoute">
<i :class="['ico-c', iconClass]">
<svg>
<use :href="icourl + '#' + icon" />
</svg>
</i>
</router-link>
</template>
</div>
</template>
<script setup lang="ts">
import icourl from '@/assets/images/icons.svg'
export interface Props {
icon: string
iconClass?: string
classList?: string
toRoute?: string
}
const props = withDefaults(defineProps<Props>(), {
iconClass: '',
classList: ''
})
const emit = defineEmits(['click'])
const OnClick = (e: Event) => {
emit('click', e)
}
</script>

View File

@ -0,0 +1,437 @@
<template>
<div
:class="[
page === 'list' ? 'section-header' : '',
page === 'form' ? 'form-part-title' : ''
]">
<i class="ico-c ico-section back-grad-title" v-if="icon !== undefined && icon !== ''">
<svg height="20">
<use :href="icourl + '#' + icon" />
</svg>
</i>
<h1 v-if="title !== undefined && title !== ''">
<span>{{ title }}</span>
<span class="section-header-count">{{ localTotalRecord }} {{ listText }}</span>
</h1>
<h4 v-if="formTitle !== undefined && formTitle !== ''">{{ formTitle }}</h4>
<div class="section-header-buttons-c collapsable" v-if="!isPreview">
<div class="header-extra-buttons-C"><slot name="extraButtons"></slot></div>
<div class="list-search-c" v-if="search">
<i
class="ico-c ico-section ico-section-header-btn btn-list-search menu-have-sub"
@click="OpenSearchForm($event)">
<svg>
<use href="@/assets/images/icons.svg#search" />
</svg>
</i>
<div
v-if="searchForm"
class="menu-sub menu-sub-top menu-sub-right menu-sub-mobile-fix section-header-search"
:style="searchFieldPos">
<div id="list-search-form">
<input
:id="'listsearch' + rnd"
type="text"
placeholder="Ara"
v-model="localQuery"
@keyup="SearchInputKeyUp" />
<button @click="SearchQuery">
<svg>
<use href="@/assets/images/icons.svg#search" />
</svg>
</button>
</div>
</div>
</div>
<div class="header-buttons-C">
<div class="menu-have-sub section-header-mobile-menu" @click="OpenMobileButtons">
<i class="ico-c ico-section ico-section-header-btn">
<svg>
<use href="@/assets/images/icons.svg#oplist" />
</svg>
</i>
</div>
<div
class="section-header-buttons menu-sub menu-sub-right menu-sub-top"
v-if="mobileButtons">
<icon-button
v-if="export"
classList="ico-section ico-section-header-btn"
@click="exportPanel = !exportPanel"
icon="export" />
<icon-button
v-if="filterable()"
classList="ico-section ico-section-header-btn"
@click="OpenFilterPanel"
icon="filter" />
<icon-button
v-if="addRoute !== undefined && addRoute !== ''"
classList="ico-section ico-section-header-btn"
:toRoute="addRoute"
icon="plus" />
<icon-button
v-else-if="addAction !== undefined && addAction !== ''"
classList="ico-section ico-section-header-btn"
@click="localAddAction"
icon="plus" />
</div>
</div>
</div>
</div>
<div
:class="[
page === 'list' ? 'section-content section-inner' : '',
page === 'form' ? 'form-part-content' : ''
]">
<div class="list-filter-wrapper" v-if="filters() || searched">
<h4>Filtreler ve Arama</h4>
<div class="list-filter-content">
<template v-if="localQuery !== ''">
<div class="list-filter-item" data-filter="durum-onaylanmis">
<strong>Arama:</strong>
<span>
{{ localQuery }}
</span>
<span class="list-filter-close" @click="RemoveSearch"></span>
</div>
</template>
<template v-for="(filter, k) in filterParams">
<div class="list-filter-item" data-filter="durum-onaylanmis">
<strong>{{ filter.title }}:</strong>
<span>
{{ filter.text || filter.val }} {{ filter.op === '=' ? '' : filter.op }}
</span>
<span class="list-filter-close" @click="RemoveFilterKey(k as string)"></span>
</div>
</template>
</div>
</div>
<slot name="datatable">
<data-table
:tableHeader="tableHeader"
:tableData="localTableData"
:rowAction="rowAction"
v-model:sortData="localSort"
v-model:pagination="localPagination"
:rowNumber="rowNumber"
:totalValues="localTotalValues"
:isPreview="isPreview" />
</slot>
</div>
<panel-wrapper v-if="filterPanel" v-model="filterPanel" :panel-title="'Filtreleme'">
<template #panelContent>
<panel-filter :filterHead="tableHeader" v-model:filterParams="localFilterParams" />
</template>
<template #footerButton>
<div class="button-c button-save" @click="FilterData">Filtrele</div>
</template>
</panel-wrapper>
<panel-wrapper v-if="exportPanel" v-model="exportPanel" :panel-title="'Dışa Aktar'">
<template #panelContent>
<panel-export v-model:selectedExport="selectedExport" />
</template>
</panel-wrapper>
</template>
<script setup lang="ts">
import { ref, reactive, onBeforeMount, watch, computed } from 'vue'
import axios from 'axios'
import { useGlobalStore } from '@/stores/globalStore'
const globalStore = useGlobalStore()
import { useDataStore } from '@/stores/dataStore'
const dataStore = useDataStore()
import icourl from '@/assets/images/icons.svg'
import PanelWrapper from '@/components/PanelWrapper.vue'
import PanelFilter from './PanelFilter.vue'
import PanelExport from './PanelExport.vue'
interface ITableHead {
[key: string]: any
title: string
name: string
compute?: Function
computeHtml?: Function
sort?: boolean
filter?: Record<string, any>
}
interface IPagination {
[key: string]: any
pageNumber?: number | string
pageSize: number | string
totalRecords: number | string
}
interface ISort {
[key: string]: any
sortColumn?: string
sortOrder?: string
}
export interface Props {
tableHeader: ITableHead[]
tableData?: Record<string, any>[]
pagination?: IPagination
rowAction?: Function | string
title?: string
formTitle?: string
listText?: string
icon?: string
apiList?: string
addRoute?: string
addAction?: Function | string
filterData?: Record<string, any>
sortData?: ISort
totalRecord?: string | number
query?: string
apiText?: string
page?: string
refresh?: boolean
export?: boolean
search?: boolean
rowNumber?: boolean
totalValues?: Record<string, any>
isPreview?: boolean
}
const props = withDefaults(defineProps<Props>(), {
tableData: () => [],
totalRecord: 0,
apiText: '',
page: 'list',
refresh: false,
export: true,
search: true,
rowNumber: false,
isPreview: false
})
const emit = defineEmits([
'click',
'update:tableData',
'update:pagination',
'update:sortData',
'update:query',
'update:refresh',
'update:totalRecord'
])
const rnd = ref<number>(Number(Math.floor(Math.random() * 1000000000)))
const filterPanel = ref<boolean>(false)
const exportPanel = ref<boolean>(false)
const searchForm = ref<boolean>(false)
const mobileButtons = ref<boolean>(false)
const selectedExport = ref<number | null>(null)
const searched = ref<boolean>(false)
const localSort = ref<ISort>({} as ISort)
const localPagination = ref<IPagination>({} as IPagination)
const localTotalValues = reactive<Record<string, any>>({})
const searchFieldPos = ref<string>('')
if (props.totalValues !== undefined) Object.assign(localTotalValues, props.totalValues)
if (props.pagination !== undefined)
Object.assign(localPagination.value, props.pagination)
const localTableData = ref<Record<string, any>[]>([])
if (props.tableData !== undefined) localTableData.value = props.tableData
const localQuery = ref<string>('')
const localTotalRecord = ref<string | number>(0)
if (props.totalRecord !== undefined) localTotalRecord.value = props.totalRecord
const localFilterParams = ref<Record<string, any>>({})
const filterParams = reactive<Record<string, any>>({})
const OpenFilterPanel = () => {
Object.assign(localFilterParams.value, filterParams)
filterPanel.value = true
}
const EqualObjects = (source: Record<string, any>, dest: Record<string, any>) => {
Object.keys(source).forEach((keys, is) => {
if (dest[keys] === undefined) delete source[keys]
})
}
const FilterData = async () => {
Object.assign(filterParams, localFilterParams.value)
EqualObjects(filterParams, localFilterParams.value)
setTimeout(async () => {
await GetLocalData()
filterPanel.value = false
}, 50)
}
const localAddAction = () => {
if (props.addAction !== undefined && props.addAction !== '')
(props.addAction as Function)()
}
const filterable = () => {
return props.tableHeader.filter((e) => e.hasOwnProperty('filter')).length > 0
}
const filters = (): boolean => {
return Object.keys(filterParams).length > 0
}
const RemoveFilterKey = (k: string) => {
delete localFilterParams.value[k]
delete filterParams[k]
GetLocalData()
}
const RemoveSearch = () => {
localQuery.value = ''
searched.value = false
GetLocalData()
}
const GetLocalData = async () => {
if (selectedExport.value !== null) {
const exportUrl =
axios.defaults.baseURL + dataStore.apiBase + props.apiList + '?isPdf=true'
const link = document.createElement('a')
link.href = exportUrl
document.body.appendChild(link)
link.dispatchEvent(
new MouseEvent('click', { bubbles: true, cancelable: true, view: window })
)
link.remove()
window.URL.revokeObjectURL(link.href)
selectedExport.value = null
exportPanel.value = false
} else {
let apiData: Record<string, any> = {
params: {
pageNumber: props.isPreview ? 0 : localPagination.value.pageNumber || 1,
pageSize: globalStore.perPage
}
}
if (localSort.value.sortColumn !== undefined) {
apiData.params.sortColumn = localSort.value.sortColumn
if (localSort.value.sortOrder !== undefined && localSort.value.sortOrder !== '')
apiData.params.sortOrder = localSort.value.sortOrder
}
if (localQuery.value !== '') {
apiData.params.searchString = localQuery.value
} else {
delete apiData.params.searchString
}
if (props.apiText !== undefined && props.apiText !== '')
apiData.text = props.apiText
var filterparam: Record<string, any> = {}
if (filters()) {
Object.keys(filterParams).forEach((f, k) => {
filterparam['Filters[' + f + ']'] = filterParams[f].op + filterParams[f].val
})
Object.assign(apiData.params, filterparam)
}
let dt = await dataStore.dataGet(props.apiList as string, apiData)
// buraya dikkat cekilis itiraz modulunde liste duzgun calışması için nullable kullanıldı
if (dt !== 'errorfalse') localTableData.value = dt.data ?? dt
else localTableData.value = []
localPagination.value.totalRecords = dt.totalRecords
localPagination.value.pageSize = dt.pageSize
localTotalRecord.value = dt.totalRecords || localTableData.value.length
if (props.pagination !== undefined) emit('update:pagination', localPagination.value)
if (props.totalRecord !== undefined)
emit('update:totalRecord', localTotalRecord.value)
if (props.totalValues !== undefined) {
Object.keys(props.totalValues).forEach((key, i) => {
localTotalValues[key] = dt[props.totalValues![key]]
})
}
emit('update:refresh', false)
}
}
const OpenMobileButtons = () => {
searchForm.value = false
mobileButtons.value = !mobileButtons.value
}
const OpenSearchForm = (e: Event) => {
searchFieldPos.value = ''
if (globalStore.screenWidth <= globalStore.breakPoints.tabletp) {
mobileButtons.value = false
let eltRect = (e.target as HTMLElement).getBoundingClientRect() as DOMRect
searchFieldPos.value = `top:${eltRect.top + eltRect.height}px;`
}
searchForm.value = !searchForm.value
if (searchForm.value) {
setTimeout(() => {
let el: HTMLInputElement = document.getElementById(
'listsearch' + rnd.value
) as HTMLInputElement
el.focus
el.select()
}, 50)
}
}
const SearchInputKeyUp = (e: KeyboardEvent) => {
if (e.key === 'Enter') SearchQuery()
}
const SearchQuery = () => {
if (props.apiList !== undefined) GetLocalData()
else emit('update:query', localQuery.value)
searchForm.value = false
searched.value = true
}
const Resize = () => {
searchForm.value = false
mobileButtons.value = false
}
onBeforeMount(() => {
if (globalStore.screenWidth >= globalStore.breakPoints.tabletp)
mobileButtons.value = true
if (props.apiList !== undefined) GetLocalData()
window.addEventListener('resize', Resize)
})
watch(
() => localSort.value,
() => {
GetLocalData()
},
{ deep: true }
)
watch(
() => localPagination.value.pageNumber,
() => {
GetLocalData()
}
)
watch(
() => props.refresh,
() => {
if (props.refresh) GetLocalData()
}
)
watch(
() => localQuery.value,
() => {
if (props.apiList !== undefined && localQuery.value.length === 0) GetLocalData()
else if (localQuery.value.length === 0) emit('update:query', localQuery.value)
}
)
watch(
() => selectedExport.value,
() => {
if (selectedExport.value !== null) GetLocalData()
}
)
</script>

View File

@ -0,0 +1,54 @@
<template>
<div class="panel-content panel-export-content">
<div class="panel-content-item">
<div class="button-c button-icon button-export" @click="SelectExport(1)">
<i class="ico-c">
<svg>
<use :href="icourl + '#pdf'"></use>
</svg>
</i>
<span class="panel-date">PDF</span>
</div>
</div>
<div class="panel-content-item" v-if="showExport">
<div class="button-c button-icon button-export" @click="SelectExport(2)">
<i class="ico-c">
<svg>
<use :href="icourl + '#xls'"></use>
</svg>
</i>
<span class="panel-date">Excell</span>
</div>
</div>
<div class="panel-content-item" v-if="showExport">
<div class="button-c button-icon button-export" @click="SelectExport(3)">
<i class="ico-c">
<svg>
<use :href="icourl + '#csv'"></use>
</svg>
</i>
<span class="panel-date">CSV</span>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import icourl from '@/assets/images/icons.svg'
const props = defineProps<{
selectedExport?: number | null
}>()
const emit = defineEmits(['update:selectedExport'])
const selected = ref<number>(0)
const showExport = ref<boolean>(false)
const SelectExport = (exp: number) => {
selected.value = exp
emit('update:selectedExport', selected.value)
}
</script>

View File

@ -0,0 +1,123 @@
<template>
<template v-for="(filter, i) in filterHead">
<template v-if="filter.filter !== undefined">
<template v-if="filter.filter.type === 'datetime-local'">
<div class="panel-content-item">
<form-date
v-model="localFilterData[filter.name]"
:label="filter.title"
@change="UpdateFilter(filter)" />
<form-select
v-if="filter.filter.range !== undefined && filter.filter.range"
:listData="filterOperator"
v-model="localFilterData[filter.name + 'op']"
@change="UpdateFilter(filter)" />
</div>
</template>
<template v-if="filter.filter.type === 'date'">
<div class="panel-content-item">
<form-date
type="date"
v-model="localFilterData[filter.name]"
:label="filter.title"
@change="UpdateFilter(filter)" />
<form-select
v-if="filter.filter.range !== undefined && filter.filter.range"
:listData="filterOperator"
v-model="localFilterData[filter.name + 'op']"
@change="UpdateFilter(filter)" />
</div>
</template>
<template v-if="filter.filter.type === 'text'">
<div class="panel-content-item">
<form-input
v-model="localFilterData[filter.name]"
:label="filter.title"
@change="UpdateFilter(filter)" />
<form-select
v-if="filter.filter.range !== undefined && filter.filter.range"
:listData="filterOperator"
v-model="localFilterData[filter.name + 'op']"
@change="UpdateFilter(filter)" />
</div>
</template>
<template v-if="filter.filter.type === 'select'">
<div class="panel-content-item">
<form-select
:listData="filter.filter.data"
:listText="filter.filter.listText"
:listVal="filter.filter.listVal"
:extraData="filter"
:label="filter.title"
v-model="localFilterData[filter.filter.filterId || filter.name]"
@change="UpdateFilterSelect"
clearable />
</div>
</template>
</template>
</template>
</template>
<script setup lang="ts">
import { ref, reactive, onBeforeMount } from 'vue'
const props = defineProps<{
filterHead: Record<string, any>
filterParams: Record<string, any>
}>()
const emit = defineEmits(['update:filterParams'])
const localFilterData = reactive<Record<string, any>>({})
const localFilterParams = reactive<Record<string, any>>(
Object.assign(props.filterParams)
)
const filterOperator = ref<string[]>(['=', '<', '>'])
const createFilterData = () => {
props.filterHead.forEach((d: Record<string, any>) => {
if (d.filter !== undefined) {
let filterKey = d.filter.filterId || d.name
localFilterData[filterKey] = ''
localFilterData[filterKey + 'op'] = '='
}
})
Object.keys(localFilterParams).forEach((k, i) => {
localFilterData[k] = localFilterParams[k].val
localFilterData[k + 'op'] = localFilterParams[k].op
})
}
const UpdateFilter = (k: Record<string, any>) => {
let filterKey = k.filter.filterId || k.name
if (localFilterData[filterKey] !== '') {
localFilterParams[filterKey] = {}
localFilterParams[filterKey].val = localFilterData[filterKey]
localFilterParams[filterKey].op = localFilterData[filterKey + 'op']
localFilterParams[filterKey].title = k.title
} else delete localFilterParams[filterKey]
emit('update:filterParams', localFilterParams)
}
const UpdateFilterSelect = (
e: Event,
v: string,
d: Record<string, any>,
ext: Record<string, any>
) => {
let filterKey = ext.filter.filterId || ext.name
if (v !== '' && v !== null && localFilterData[filterKey] !== '') {
localFilterParams[filterKey] = {}
localFilterParams[filterKey].val = localFilterData[filterKey]
localFilterParams[filterKey].op = localFilterData[filterKey + 'op']
localFilterParams[filterKey].title = ext.title
localFilterParams[filterKey].text = d[ext.filter.listText]
} else {
delete localFilterParams[filterKey]
}
emit('update:filterParams', localFilterParams)
}
onBeforeMount(() => {
createFilterData()
})
</script>

View File

@ -0,0 +1,109 @@
<template>
<div class="tabs-buttons-c" :id="'tabnav' + rnd">
<template v-for="(tab, i) in tabList">
<div
:class="['tab-button', currentTab === i ? 'tab-selected' : '']"
@click="ChangeTab(i)"
:style="[i === 0 ? tabPosition : '']">
<slot :name="'tabname' + i">{{ tab.text }}</slot>
</div>
</template>
<div class="tab-nav-button tab-nav-button-prev" @click="ChangeTab('<')">
<i class="ico-c ico-tab-nav">
<svg width="8"><use href="/src/assets/images/icons.svg#arrow"></use></svg>
</i>
</div>
<div class="tab-nav-button tab-nav-button-next" @click="ChangeTab('>')">
<i class="ico-c ico-tab-nav">
<svg width="8"><use href="/src/assets/images/icons.svg#arrow"></use></svg>
</i>
</div>
</div>
<div class="tabs-contents-c" :id="'tabs' + rnd">
<template v-for="(tabc, j) in tabList">
<div
class="tab-content tab-animate"
:style="[j === 0 ? tabContentPosition : '', { width: tabWidth + 'px' }]">
<template v-if="currentTab === j">
<slot :name="tabc.id"></slot>
</template>
</div>
</template>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue'
import { useGlobalStore } from '@/stores/globalStore'
const globalStore = useGlobalStore()
interface TabObj {
[key: string]: any
text: string
id: string
}
const props = defineProps<{
tabList: TabObj[]
}>()
const currentTab = ref<number>(0)
const rnd = ref<number>(Math.ceil(Number(Math.random() * 1000000000)))
const tabWidth = ref<number>(0)
const tabPosition = ref<string>('')
const tabContentPosition = computed<string>(() => {
var tabPos = ''
let pos = -(tabWidth.value * currentTab.value)
tabPos = `margin-left:${pos}px`
return tabPos
})
const CalculateNavPosition = () => {
tabPosition.value = ''
let screenWidth = document.body.offsetWidth
if (screenWidth <= 1024) {
let pos = -(tabWidth.value * currentTab.value - 50)
tabPosition.value = `margin-left:${pos}px`
}
}
const ChangeTab = (d: number | string) => {
if (d === '<') {
if (currentTab.value !== 0) {
currentTab.value--
}
} else if (d == '>') {
if (currentTab.value !== props.tabList.length - 1) {
currentTab.value++
}
} else {
currentTab.value = Number(d)
}
CalculateNavPosition()
}
const TabWidth = () => {
let screenWidth = document.body.offsetWidth
let tabel = document.getElementById('tabs' + rnd.value) as HTMLElement
if (screenWidth <= globalStore.breakPoints.tablet) {
tabWidth.value = screenWidth - 48
} else {
const menuSideW = document.querySelector('.menu-side-w')
let sideW = globalStore.sideMenu ? menuSideW!.getBoundingClientRect().width : 0
tabWidth.value = screenWidth - sideW - 48
}
}
const Resize = () => {
TabWidth()
CalculateNavPosition()
}
onMounted(() => {
TabWidth()
window.addEventListener('resize', Resize)
})
watch(
() => globalStore.sideMenu,
() => {
TabWidth()
}
)
</script>

View File

@ -0,0 +1,40 @@
<template>
<div :class="['page-toast-item', type !== undefined ? 'toast-item-' + type : '']">
<span class="toast-close-btn" @click="CloseToast"></span>
<span>{{ text }}</span>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useToastStore } from './toastStore'
const toastStore = useToastStore()
export interface Props {
id: number
text: string
type: string
timeout?: number
show?: boolean
}
const props = withDefaults(defineProps<Props>(), {
type: '',
timeout: 0,
show: false
})
const emit = defineEmits(['update:show'])
const localTimeout = ref<number>(props.timeout)
const CloseToast = () => {
delete toastStore.toasts[props.id]
}
onMounted(() => {
if (localTimeout.value === 0) localTimeout.value = toastStore.toastTimeout
if (localTimeout.value >= 0) {
setTimeout(() => {
CloseToast()
}, localTimeout.value)
}
})
</script>

View File

@ -0,0 +1,20 @@
<template>
<template v-if="Object.keys(toastStore.toasts).length > 0">
<teleport to="body">
<div class="page-toast-w">
<template v-for="(toast, i) in toastStore.toasts">
<toast-item
:type="toast.type"
:id="toast.id"
:timeout="toast.timeout"
:text="toast.text" />
</template>
</div>
</teleport>
</template>
</template>
<script setup lang="ts">
import ToastItem from './ToastItem.vue'
import { useToastStore } from './toastStore'
const toastStore = useToastStore()
</script>

View File

@ -0,0 +1,22 @@
import { defineStore } from 'pinia'
import { ref, reactive } from 'vue'
export const useDialogStore = defineStore('dialogStore', () => {
const dialogs = reactive<Record<string, any>>({})
const CreateDialog = (data: Record<string, any>) => {
const rnd: number = Number(Math.floor(Math.random() * 10000000000))
dialogs[rnd] = {} as Record<string, any>
dialogs[rnd].id = rnd
dialogs[rnd].data = data
}
const CloseDialog = (id: number) => {
delete dialogs[id]
}
return {
dialogs,
CreateDialog,
CloseDialog
}
})

View File

@ -0,0 +1,40 @@
import DataTable from './DataTable.vue'
import DataTablePagination from './DataTablePagination.vue'
import ListTableContent from './ListTableContent.vue'
import FormInput from './FormInput.vue'
import FormDate from './FormDate.vue'
import FormFile from './FormFile.vue'
import FormTextarea from './FormTextarea.vue'
import FormQuill from './FormQuill.vue'
import FormSummer from './FormSummer.vue'
import FormSelect from './FormSelect.vue'
import FormRadio from './FormRadio.vue'
import FormCheckbox from './FormCheckbox.vue'
import Tabs from './Tabs.vue'
import IconButton from './IconButton.vue'
import Breadcrumb from './Breadcrumb.vue'
import FileListItem from './FileListItem.vue'
import FormDisplay from './FormDisplay.vue'
import Toasts from './Toasts.vue'
import Dialogs from './Dialogs.vue'
export {
DataTable,
DataTablePagination,
ListTableContent,
FormInput,
FormDate,
FormFile,
FormTextarea,
FormQuill,
FormSummer,
FormSelect,
FormRadio,
FormCheckbox,
Tabs,
IconButton,
Breadcrumb,
FileListItem,
FormDisplay,
Toasts,
Dialogs
}

View File

@ -0,0 +1,23 @@
import { defineStore } from 'pinia'
import { ref, reactive } from 'vue'
export const useToastStore = defineStore('toastStore', () => {
const toastTimeout = ref<number>(5000)
const toasts = reactive<Record<string, any>>({})
const AddToast = (toast: string, type: string, timeout?: number) => {
const iTimeout: number = timeout || 0
const rnd: number = Number(Math.floor(Math.random() * 10000000000))
toasts[rnd] = {} as Record<string, any>
toasts[rnd].text = toast
toasts[rnd].timeout = iTimeout
toasts[rnd].id = rnd
toasts[rnd].type = type
}
return {
toastTimeout,
toasts,
AddToast
}
})