update 1400-10-09

This commit is contained in:
sedmedgh
2021-12-30 16:13:42 +03:30
parent e510b6ab98
commit 6b6b9a3652
79 changed files with 3323 additions and 395 deletions
+7 -1
View File
@@ -1,6 +1,7 @@
<template>
<div class="clearfix">
<AUpload
:disabled="disabled"
:action="url"
:headers="headers"
:accept="accept"
@@ -50,6 +51,11 @@ export default {
size: {
default: 2
},
disabled: {
required:false,
type:Boolean,
default: false
},
accept: {default: "image/jpeg"},
serverType: {
types: {
@@ -63,7 +69,7 @@ export default {
},
data() {
return {
url: 'http://hr.asco-intl.com/back/public/api/register/upload',
url: 'http://hr.asco-intl.com:2020/back/public/api/register/upload',
previewVisible: false,
previewImage: '',
fileList: [],
+6
View File
@@ -1,6 +1,7 @@
<template>
<div class="clearfix">
<AUpload
:disabled="disabled"
:action="url"
:headers="headers"
accept="image/jpeg"
@@ -48,6 +49,11 @@ export default {
size: {
default: 2
},
disabled: {
required:false,
type:Boolean,
default: false
},
label: {},
serverType: {
types: {
+69
View File
@@ -0,0 +1,69 @@
`Version 0.95`
# Table Engine for Vue 2 Projects
# Requirements
- ant design ^1.3
- fullscreen plugin
- vue-persian-datetime-picker ^2.4
# Example
To define the model layer, we do the following
```js
import XTbl, {Xtc} from './index' // import from x-table directory;
const tbl = new XTbl('http://some-url', 'foo-bar-title');
tbl.add(new Xtc('id', 'آیدی').filterNumber());
tbl.add(new Xtc('title', 'عنوان').filterText())
tbl.add(new Xtc('fname', 'نام کوچک').filterText())
tbl.add(new Xtc('lname', 'نام بزرگ').filterText())
tbl.add(new Xtc('ncode', 'کد ملی').filterText().hidden().noSort())
tbl.add(new Xtc('birth_date', 'تاریخ تولد').filterDate().hidden().noSort())
tbl.add(new Xtc('sts_str', 'وضعیت').renderSlot('sts_str').filterSelect({1: 'گزینه اول'}).noSort())
tbl.add(new Xtc('active', 'فعال').filterSwitch().hidden().noSort())
tbl.add(new Xtc('wow', 'فعال').filterSwitch().renderSlot('wow').noSort())
tbl.addOpt()
export default tbl;
```
And to use the model layer in the view layer, we will do the following in vue file
```vue
<template>
....
<XTable :model="model"/>
....
</template>
<script>
import XTable from "@/components/x-table/XTable";
import model from './some-model';
export default {
components: {XTable},
data(){
return {model:undefined}
},
created(){
this.model = model;
}
}
</script>
```
Feature road map
- [x] Date filter
- [x] Select filter
- [x] Multiple filter
- [x] Switch filter
- [x] Numeric filter
- [x] JSON export
- [x] Print export
- [x] Excel export
- [x] Auto translate columns in export mode
- [x] Auto set title for print report
- [ ] Sort in joined table
- [ ] Exception Handlers for server and client
- [ ] Reset Table Engine feature
- [ ] Store current view in localstorage
- [ ] Add scope to filter
+448
View File
@@ -0,0 +1,448 @@
<template>
<div>
<ACard ref="tblCard" class="overflow-auto">
<template #cover>
<ASpin :spinning="loading">
<div class="flex justify-between p-4">
<div class="flex items-center">
<a-input-search class="md:ml-4" placeholder="عبارت مورد نظر برای جستجو را وارد کنید"
enter-button="جستجو"
@search="onSearch" v-if="!model._noSearch"/>
<AButton @click="toggleVisibleFilter" :type="getFilterType">
<div class="flex items-center">
<feather-icon icon="FilterIcon" svg-classes="h-4 w-4 color-grey cursor-pointer"
class="ml-4"/>
<div v-if="query && query.filters.length > 0">
{{ query.filters.length }}
فیلتر
</div>
<div v-else>
فیلتر ها
</div>
</div>
</AButton>
</div>
<div class="filter-backdrop p-4" v-if="visibleDownload">
<feather-icon icon="XIcon" @click="toggleVisibleDownload"
svg-classes="h-4 w-4 color-grey cursor-pointer"
class="ml-4"/>
<AAlert >
<template #message>
لیست فعلی را می توانید در یکی از قالب های زیر دریافت کنید.
</template>
</AAlert>
<div class="grid grid-cols-3 p-8">
<div class="flex items-center justify-center flex-col cursor-pointer" @click="fetch('json')">
<img :src="jsonIcon" style="max-height: 45px" class="mb-4"/>
خروجی json
</div>
<div class="flex items-center justify-center flex-col cursor-pointer" @click="fetch('excel')">
<img :src="excelIcon" style="max-height: 45px" class="mb-4"/>
خروجی اکسل
</div>
<div class="flex items-center justify-center flex-col cursor-pointer" @click="fetch('print')">
<img :src="printIcon" style="max-height: 45px" class="mb-4"/>
خروجی پرینت
</div>
</div>
</div>
<div class="filter-backdrop p-4" v-if="activeFilter">
<div>
<div class="flex items-center mb-4">
<feather-icon icon="XIcon" @click="toggleVisibleFilter"
svg-classes="h-4 w-4 color-grey cursor-pointer"
class="ml-4"/>
<div class="font-bold">
فیلتر ها
</div>
</div>
<div v-if="query">
<div v-for="(item,index) in query.filters" :key="item.id" class="mb-4">
<XFilterRow :value="item"
@remove="removeFilter"
@input="filterChange"
:index="index"
:id="item.id"
:col-filters="getColsFilter"
:is-first="index < 1"
/>
</div>
</div>
<div class="flex items-center justify-center">
<AButton @click="addFilterRow">
افزودن ردیف جدید
</AButton>
<div class="flex-1"></div>
<AButton @click="doFilter" type="primary" v-if="query" :disabled="query.filters.length == 0">
انجام فیلتر
</AButton>
</div>
<ADivider orientation="left">مرتب سازی</ADivider>
<div class="md:flex gap-4">
<ARadioGroup v-model="sortDirection" class="ml-4" dir="ltr">
<ARadioButton value="asc">صعودی</ARadioButton>
<ARadioButton value="desc">نزولی</ARadioButton>
</ARadioGroup>
<ASelect style="min-width: 250px" placeholder="مرتب سازی" allow-clear v-model="sort">
<ASelectOption :key="index" :value="item.key" v-for="(item, index) in model.getSortFields()">
{{ item.title }}
</ASelectOption>
</ASelect>
<div class="flex-1">
</div>
<AButton @click="doFilter" type="primary">
بروزرسانی
</AButton>
</div>
</div>
</div>
<div class="flex justify-end gap-4 items-center" v-if="!model._noSettings">
<feather-icon :icon="getFullIcon" svg-classes="w-5 h-5 cursor-pointer text-primary" @click="fullScreen"/>
<ADropdown :trigger="['hover']">
<div slot="overlay" class="p-2" style="min-width: 250px">
<ACard @click.stop="noThings" :body-style="{padding:'8px'}">
ستون های جدول
<ADivider class="my-2"/>
<div class="flex flex-col items-start" style="max-height:150px;overflow:auto">
<Draggable v-model="cols">
<div v-for="item,index in cols" :key="index" class="flex items-start">
<feather-icon icon="MoreVerticalIcon" svg-classes="h-4 w-4 color-grey cursor-pointer"
class="mr-0"/>
<feather-icon icon="MoreVerticalIcon" svg-classes="h-4 w-4 color-grey cursor-pointer"
style="position: relative;left: 9px;"/>
<ACheckbox v-model="item.show">
{{ item.title }}
</ACheckbox>
</div>
</Draggable>
</div>
</ACard>
</div>
<feather-icon icon="SettingsIcon" svg-classes="w-5 h-5 cursor-pointer refresh-btn text-primary"/>
</ADropdown>
<feather-icon icon="RotateCwIcon" svg-classes="w-5 h-5 refresh-btn cursor-pointer text-primary"
@click="fetch"/>
<!-- <feather-icon icon="DownloadIcon" svg-classes="w-5 h-5 cursor-pointer text-primary"
@click="showDownload"/>-->
</div>
</div>
<a-table
@change="change"
:indentSize="5"
:pagination="false"
ref="tbl"
:locale="locale"
:columns="visibleCols"
:data-source="data"
>
<template :slot="item" slot-scope="name, record, index" v-for="item,ind in customRender">
<slot :name="item" :text="name" :record="record" :index="index"/>
</template>
<div slot="footer" slot-scope="{item}">
<div class="flex items-center">
<div class="flex-1">
<div v-if="query.total">
<span>{{ query.total }}</span>
رکورد یافت شد.
</div>
</div>
<APagination dir="ltr"
show-size-changer
:pageSizeOptions="['5','10','20']"
:page-size.sync="query.limit"
@change="changePage"
@showSizeChange="changePage"
:default-current="1" :total="query.total" v-model.sync="query.page">
<template slot="buildOptionText" slot-scope="props">
<div dir="rtl">
<span> {{ props.value }} </span>
<span>رکورد</span>
</div>
</template>
</APagination>
</div>
</div>
</a-table>
</ASpin>
</template>
</ACard>
</div>
</template>
<script>
import XTbl from "./model/XTbl";
import Draggable from 'vuedraggable'
import axios from "../../axios";
import {closeFullscreen, openFullscreen} from "@/plugins/fullscreen";
import printIcon from './assets/print.svg'
import excelIcon from './assets/excel.svg'
import jsonIcon from './assets/json.svg'
import FeatherIcon from '@/components/FeatherIcon.vue'
import XFilterRow from "./components/XFilterRow";
export default {
name: 'XTable',
components: {
XFilterRow,
FeatherIcon,
Draggable,
// DatePickerBetweenXTableFilter
},
props: {
model: {
type: XTbl.default
}
},
data() {
return {
data: [],
jsonIcon,
excelIcon,
printIcon,
lastHashStringFilter: undefined,
query: {
search: undefined,
filters: [],
total: 0,
limit: 10,
page: 1,
},
locale: {
emptyText: 'هیج رکوردی یافت نشد.'
},
loading: false,
activeFilter: false,
full: false,
sort: undefined,
sortDirection: 'asc',
colSelector: false,
visibleDownload: false
}
},
methods: {
getFilters() {
return this.query.filters
},
showDownload() {
this.visibleDownload = true;
},
doFilter() {
this.activeFilter = false;
this.fetch();
},
removeFilter(index) {
console.log("index ==> ", index);
this.$delete(this.query.filters, index)
this.$forceUpdate();
},
filterChange(value) {
console.log("value ==> " , value);
this.query.filters[value.index] = value;
},
calcHash() {
},
addFilterRow() {
if (!this.query) this.query = {};
if (!this.query.filters) this.query.filters = []
let rand = parseFloat(`${this.query.filters.length}.${Math.floor(Math.random() * 1000)}`);
this.query.filters.push({id: rand});
this.$forceUpdate();
},
toggleVisibleFilter() {
this.activeFilter = !this.activeFilter;
},
toggleVisibleDownload() {
this.visibleDownload = !this.visibleDownload;
},
// submitFilter({model, column}) {
// if (!this.query.filters) {
// this.query.filters = new Map()
// }
// const e = this.query.filters.values().filter((i) => i.field == (column.__fkey || column.dataIndex));
// if (e) {
// e.forEach((i) => {
// this.$delete(this.query.filters, this.query.filters.indexOf(i));
// });
// }
//
// const vModel = model.filter((i) => i.value)
// this.query.filters = this.query.filters.concat(vModel);
// console.log("this.query.filters ==> ", this.query.filters);
// this.fetch()
// },
hasFiltered(item) {
for (const i of this.query) {
if (item.startsWith(i.field)) {
return true;
}
}
return false;
},
change(item, filter, sorter) {
if (sorter) {
const {columnKey, order} = sorter;
this.query.order = [`${order == 'ascend' ? '-' : '+'}${columnKey}`];
}
this.fetch();
},
changePage(item) {
this.query.page = item;
this.fetch();
},
fullScreen() {
if (this.full) {
closeFullscreen()
this.full = false;
return;
}
openFullscreen(this.$refs.tblCard.$el);
this.full = true;
},
requestData(op) {
this.query.order = this.order;
this.query.filters = this.query.filters.filter((item) => item.value || ['null', 'nn'].includes(item.op) || item.value == 0);
const select = this.visibleCols.map((i) => i.key);
const titles = {};
let hash = JSON.stringify(this.query.filters);
if (this.query.search) {
hash += this.query.search;
}
if (hash != this.lastHashStringFilter) {
this.query.page = 1;
}
this.lastHashStringFilter = hash;
this.visibleCols.forEach((i) => titles[i.key] = i.title);
if (op) {
return {...this.query, op, select, titles, report_title: this.model.title};
}
return {...this.query, select, titles, report_title: this.model.title};
},
async fetch(op) {
try {
this.loading = true;
const {data} = await axios.post(this.model.url, this.requestData(op));
if (op == 'excel' || op == 'json' || op == 'print') {
window.open(data.url);
return;
}
this.data = data.rows;
this.query = data.query
console.log("this.query ==> ", this.query);
this.$emit('fetch', data)
} catch (e) {
this.$message.error('خطا در دریافت اطلاعات');
throw e
} finally {
this.loading = false;
this.visibleDownload = false;
}
},
noThings() {
},
getFilterData() {
},
onSearch(value) {
this.query.search = value;
this.fetch();
// if (value) {
// }
},
showColSelector() {
this.colSelector = !this.colSelector;
}
},
computed: {
order: {
set() {
},
get() {
if (this.sort) {
const direc = (this.sortDirection == 'asc') ? '+' : '-';
return `${direc}${this.sort}`
}
}
},
getFilterType() {
return (this.query && this.query.filters && this.query.filters.length > 0) ? 'primary' : '';
},
getFullIcon() {
return !this.full ? 'Maximize2Icon' : 'Minimize2Icon';
},
customRender() {
return this.model.cols.filter((item) => item.scopedSlots && item.scopedSlots.customRender).map((i) => i.scopedSlots.customRender)
},
filterIcons() {
return this.model.cols.filter((item) => item.scopedSlots && item.scopedSlots.filterIcon).map((i) => i.scopedSlots.filterIcon)
},
cols: {
get() {
return this.model.cols || [];
},
set(value) {
this.model.cols = value;
}
},
getColsFilter() {
return this.cols.filter(item => item.filtered)
},
visibleCols() {
console.log(" ==> " , this.cols.filter(item => item.show));
return this.cols.filter(item => item.show)
}
},
mounted() {
this.fetch();
}
}
</script>
<style scoped>
.fade-enter {
opacity: 0;
}
.fade-enter-active {
opacity: 0.5;
transition: 0.5s ease;
}
.fade-leave {
opacity: 1;
}
.fade-leave-active {
opacity: 0;
transition: 0.5s ease;
}
.refresh-btn {
transition: all 0.15s ease;
}
.refresh-btn:hover {
transform: rotate(90deg);
}
.filter-backdrop {
position: absolute;
z-index: 1000;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: white;
}
</style>
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_extend "http://ns.adobe.com/Extensibility/1.0/">
<!ENTITY ns_ai "http://ns.adobe.com/AdobeIllustrator/10.0/">
<!ENTITY ns_graphs "http://ns.adobe.com/Graphs/1.0/">
<!ENTITY ns_vars "http://ns.adobe.com/Variables/1.0/">
<!ENTITY ns_imrep "http://ns.adobe.com/ImageReplacement/1.0/">
<!ENTITY ns_sfw "http://ns.adobe.com/SaveForWeb/1.0/">
<!ENTITY ns_custom "http://ns.adobe.com/GenericCustomNamespace/1.0/">
<!ENTITY ns_adobe_xpath "http://ns.adobe.com/XPath/1.0/">
]>
<svg version="1.1" id="Livello_1" xmlns:x="&ns_extend;" xmlns:i="&ns_ai;" xmlns:graph="&ns_graphs;"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 2289.75 2130"
enable-background="new 0 0 2289.75 2130" xml:space="preserve">
<metadata>
<sfw xmlns="&ns_sfw;">
<slices></slices>
<sliceSourceBounds bottomLeftOrigin="true" height="2130" width="2289.75" x="-1147.5" y="-1041"></sliceSourceBounds>
</sfw>
</metadata>
<path fill="#185C37" d="M1437.75,1011.75L532.5,852v1180.393c0,53.907,43.7,97.607,97.607,97.607l0,0h1562.036
c53.907,0,97.607-43.7,97.607-97.607l0,0V1597.5L1437.75,1011.75z"/>
<path fill="#21A366" d="M1437.75,0H630.107C576.2,0,532.5,43.7,532.5,97.607c0,0,0,0,0,0V532.5l905.25,532.5L1917,1224.75
L2289.75,1065V532.5L1437.75,0z"/>
<path fill="#107C41" d="M532.5,532.5h905.25V1065H532.5V532.5z"/>
<path opacity="0.1" enable-background="new " d="M1180.393,426H532.5v1331.25h647.893c53.834-0.175,97.432-43.773,97.607-97.607
V523.607C1277.825,469.773,1234.227,426.175,1180.393,426z"/>
<path opacity="0.2" enable-background="new " d="M1127.143,479.25H532.5V1810.5h594.643
c53.834-0.175,97.432-43.773,97.607-97.607V576.857C1224.575,523.023,1180.977,479.425,1127.143,479.25z"/>
<path opacity="0.2" enable-background="new " d="M1127.143,479.25H532.5V1704h594.643c53.834-0.175,97.432-43.773,97.607-97.607
V576.857C1224.575,523.023,1180.977,479.425,1127.143,479.25z"/>
<path opacity="0.2" enable-background="new " d="M1073.893,479.25H532.5V1704h541.393c53.834-0.175,97.432-43.773,97.607-97.607
V576.857C1171.325,523.023,1127.727,479.425,1073.893,479.25z"/>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="203.5132" y1="1729.0183" x2="967.9868" y2="404.9817" gradientTransform="matrix(1 0 0 -1 0 2132)">
<stop offset="0" style="stop-color:#18884F"/>
<stop offset="0.5" style="stop-color:#117E43"/>
<stop offset="1" style="stop-color:#0B6631"/>
</linearGradient>
<path fill="url(#SVGID_1_)" d="M97.607,479.25h976.285c53.907,0,97.607,43.7,97.607,97.607v976.285
c0,53.907-43.7,97.607-97.607,97.607H97.607C43.7,1650.75,0,1607.05,0,1553.143V576.857C0,522.95,43.7,479.25,97.607,479.25z"/>
<path fill="#FFFFFF" d="M302.3,1382.264l205.332-318.169L319.5,747.683h151.336l102.666,202.35
c9.479,19.223,15.975,33.494,19.49,42.919h1.331c6.745-15.336,13.845-30.228,21.3-44.677L725.371,747.79h138.929l-192.925,314.548
L869.2,1382.263H721.378L602.79,1160.158c-5.586-9.45-10.326-19.376-14.164-29.66h-1.757c-3.474,10.075-8.083,19.722-13.739,28.755
l-122.102,223.011H302.3z"/>
<path fill="#33C481" d="M2192.143,0H1437.75v532.5h852V97.607C2289.75,43.7,2246.05,0,2192.143,0L2192.143,0z"/>
<path fill="#107C41" d="M1437.75,1065h852v532.5h-852V1065z"/>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 56 56" style="enable-background:new 0 0 56 56;" xml:space="preserve">
<g>
<path style="fill:#E9E9E0;" d="M36.985,0H7.963C7.155,0,6.5,0.655,6.5,1.926V55c0,0.345,0.655,1,1.463,1h40.074
c0.808,0,1.463-0.655,1.463-1V12.978c0-0.696-0.093-0.92-0.257-1.085L37.607,0.257C37.442,0.093,37.218,0,36.985,0z"/>
<polygon style="fill:#D9D7CA;" points="37.5,0.151 37.5,12 49.349,12 "/>
<path style="fill:#9777A8;" d="M48.037,56H7.963C7.155,56,6.5,55.345,6.5,54.537V39h43v15.537C49.5,55.345,48.845,56,48.037,56z"/>
<g>
<path style="fill:#FFFFFF;" d="M17.021,42.719v7.848c0,0.474-0.087,0.873-0.26,1.196s-0.405,0.583-0.697,0.779
s-0.627,0.333-1.005,0.41c-0.378,0.077-0.768,0.116-1.169,0.116c-0.2,0-0.436-0.021-0.704-0.062s-0.547-0.104-0.834-0.191
s-0.563-0.185-0.827-0.294s-0.487-0.232-0.67-0.369l0.697-1.107c0.091,0.063,0.221,0.13,0.39,0.198s0.354,0.132,0.554,0.191
s0.41,0.111,0.629,0.157s0.424,0.068,0.615,0.068c0.483,0,0.868-0.094,1.155-0.28s0.439-0.504,0.458-0.95v-7.711H17.021z"/>
<path style="fill:#FFFFFF;" d="M25.184,50.238c0,0.364-0.075,0.718-0.226,1.06s-0.362,0.643-0.636,0.902s-0.61,0.467-1.012,0.622
s-0.856,0.232-1.367,0.232c-0.219,0-0.444-0.012-0.677-0.034s-0.467-0.062-0.704-0.116c-0.237-0.055-0.463-0.13-0.677-0.226
s-0.398-0.212-0.554-0.349l0.287-1.176c0.128,0.073,0.289,0.144,0.485,0.212s0.398,0.132,0.608,0.191s0.419,0.107,0.629,0.144
s0.405,0.055,0.588,0.055c0.556,0,0.982-0.13,1.278-0.39s0.444-0.645,0.444-1.155c0-0.31-0.104-0.574-0.314-0.793
s-0.472-0.417-0.786-0.595s-0.654-0.355-1.019-0.533s-0.706-0.388-1.025-0.629s-0.583-0.526-0.793-0.854s-0.314-0.738-0.314-1.23
c0-0.446,0.082-0.843,0.246-1.189s0.385-0.641,0.663-0.882s0.602-0.426,0.971-0.554s0.759-0.191,1.169-0.191
c0.419,0,0.843,0.039,1.271,0.116s0.774,0.203,1.039,0.376c-0.055,0.118-0.118,0.248-0.191,0.39s-0.142,0.273-0.205,0.396
s-0.118,0.226-0.164,0.308s-0.073,0.128-0.082,0.137c-0.055-0.027-0.116-0.063-0.185-0.109s-0.166-0.091-0.294-0.137
s-0.296-0.077-0.506-0.096s-0.479-0.014-0.807,0.014c-0.183,0.019-0.355,0.07-0.52,0.157s-0.31,0.193-0.438,0.321
s-0.228,0.271-0.301,0.431s-0.109,0.313-0.109,0.458c0,0.364,0.104,0.658,0.314,0.882s0.47,0.419,0.779,0.588
s0.647,0.333,1.012,0.492s0.704,0.354,1.019,0.581s0.576,0.513,0.786,0.854S25.184,49.7,25.184,50.238z"/>
<path style="fill:#FFFFFF;" d="M35.082,47.914c0,0.848-0.107,1.595-0.321,2.242s-0.511,1.185-0.889,1.613s-0.82,0.752-1.326,0.971
s-1.06,0.328-1.661,0.328s-1.155-0.109-1.661-0.328s-0.948-0.542-1.326-0.971s-0.675-0.966-0.889-1.613s-0.321-1.395-0.321-2.242
s0.107-1.593,0.321-2.235s0.511-1.178,0.889-1.606s0.82-0.754,1.326-0.978s1.06-0.335,1.661-0.335s1.155,0.111,1.661,0.335
s0.948,0.549,1.326,0.978s0.675,0.964,0.889,1.606S35.082,47.066,35.082,47.914z M30.844,51.729c0.337,0,0.658-0.066,0.964-0.198
s0.579-0.349,0.82-0.649s0.431-0.695,0.567-1.183s0.21-1.082,0.219-1.784c-0.009-0.684-0.08-1.265-0.212-1.743
s-0.314-0.873-0.547-1.183s-0.497-0.533-0.793-0.67s-0.608-0.205-0.937-0.205c-0.337,0-0.658,0.063-0.964,0.191
s-0.579,0.344-0.82,0.649s-0.431,0.699-0.567,1.183c-0.137,0.483-0.21,1.075-0.219,1.777c0.009,0.684,0.08,1.267,0.212,1.75
s0.314,0.877,0.547,1.183s0.497,0.528,0.793,0.67S30.516,51.729,30.844,51.729z"/>
<path style="fill:#FFFFFF;" d="M44.68,42.924V53h-1.668l-3.951-6.945V53h-1.668V42.924h1.668l3.951,6.945v-6.945H44.68z"/>
</g>
<g>
<path style="fill:#9777A8;" d="M19.5,19v-4c0-0.551,0.448-1,1-1c0.553,0,1-0.448,1-1s-0.447-1-1-1c-1.654,0-3,1.346-3,3v4
c0,1.103-0.897,2-2,2c-0.553,0-1,0.448-1,1s0.447,1,1,1c1.103,0,2,0.897,2,2v4c0,1.654,1.346,3,3,3c0.553,0,1-0.448,1-1
s-0.447-1-1-1c-0.552,0-1-0.449-1-1v-4c0-1.2-0.542-2.266-1.382-3C18.958,21.266,19.5,20.2,19.5,19z"/>
<circle style="fill:#9777A8;" cx="27.5" cy="18.5" r="1.5"/>
<path style="fill:#9777A8;" d="M39.5,21c-1.103,0-2-0.897-2-2v-4c0-1.654-1.346-3-3-3c-0.553,0-1,0.448-1,1s0.447,1,1,1
c0.552,0,1,0.449,1,1v4c0,1.2,0.542,2.266,1.382,3c-0.84,0.734-1.382,1.8-1.382,3v4c0,0.551-0.448,1-1,1c-0.553,0-1,0.448-1,1
s0.447,1,1,1c1.654,0,3-1.346,3-3v-4c0-1.103,0.897-2,2-2c0.553,0,1-0.448,1-1S40.053,21,39.5,21z"/>
<path style="fill:#9777A8;" d="M27.5,24c-0.553,0-1,0.448-1,1v3c0,0.552,0.447,1,1,1s1-0.448,1-1v-3
C28.5,24.448,28.053,24,27.5,24z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg version="1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" enable-background="new 0 0 48 48">
<rect x="9" y="11" fill="#424242" width="30" height="3"/>
<path fill="#616161" d="M4,25h40v-7c0-2.2-1.8-4-4-4H8c-2.2,0-4,1.8-4,4V25z"/>
<path fill="#424242" d="M8,36h32c2.2,0,4-1.8,4-4v-8H4v8C4,34.2,5.8,36,8,36z"/>
<circle fill="#00E676" cx="40" cy="18" r="1"/>
<rect x="11" y="4" fill="#90CAF9" width="26" height="10"/>
<path fill="#242424" d="M37.5,31h-27C9.7,31,9,30.3,9,29.5v0c0-0.8,0.7-1.5,1.5-1.5h27c0.8,0,1.5,0.7,1.5,1.5v0 C39,30.3,38.3,31,37.5,31z"/>
<rect x="11" y="31" fill="#90CAF9" width="26" height="11"/>
<rect x="11" y="29" fill="#42A5F5" width="26" height="2"/>
<g fill="#1976D2">
<rect x="16" y="33" width="17" height="2"/>
<rect x="16" y="37" width="13" height="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 915 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>

After

Width:  |  Height:  |  Size: 308 B

@@ -0,0 +1,30 @@
<template>
<div>
<date-picker auto-submit accepted="bottom-left" @change="search" v-model="input" input-class="ant-input"/>
</div>
</template>
<script>
export default {
name: 'DateXTableFilter',
props: ['value'],
data() {
return {
input: undefined
}
},
methods: {
search() {
this.$emit('input', this.input)
},
},
mounted() {
this.input = this.value
}
}
</script>
<style>
.vpd-input-group label{
border-radius: 0 4px 4px 0;
}
</style>
@@ -0,0 +1,27 @@
<template>
<div>
<AInputNumber placehoder="مقدار"
@change="search"
v-model="input"/>
</div>
</template>
<script>
export default {
name: 'NumberXTableFilter',
props: ['value'],
data() {
return {
input: undefined
}
},
methods: {
search() {
this.$emit('input', this.input)
},
},
mounted() {
this.input = this.value
}
}
</script>
@@ -0,0 +1,62 @@
<template>
<div>
<ASelect
:show-search="true"
v-model="input"
placeholder="مقدار"
style="width: 200px"
:default-active-first-option="false"
:show-arrow="true"
:filter-option="false"
:not-found-content="null"
class="w-full"
@search="fetch"
@change="search"
>
<template #notFoundContent>
<div>
هیچ موردی یافت نشد
</div>
</template>
<ASelectOption v-for="item in data" :key="item.id" :value="item.id">
{{ item.title }}
</ASelectOption>
</ASelect>
</div>
</template>
<script>
import axios from "@/axios";
export default {
name: 'QuerySelectTableFilter',
props: ['value', 'action'],
data() {
return {
input: undefined,
data: [],
}
},
methods: {
search() {
this.$emit('input', this.input)
},
async fetch(value) {
try {
if (!value || value.length < 2) return;
const {data} = await axios.get('/te/query', {params: {action: this.action , query:value}});
this.data = data;
} catch (e) {
this.$message.error('خطا در دریافت اطلاعات');
}
}
},
mounted() {
this.input = this.value
}
}
</script>
@@ -0,0 +1,34 @@
<template>
<div>
<ASelect
v-model="input"
class="w-full"
@change="search"
placehoder="مقدار"
>
<ASelectOption v-for="(i,k) in items" :key="k">
{{ i }}
</ASelectOption>
</ASelect>
</div>
</template>
<script>
export default {
name: 'SelectXTableFilter',
props: ['value', 'items'],
data() {
return {
input: undefined
}
},
methods: {
search() {
this.$emit('input', this.input)
},
},
mounted() {
this.input = this.value
}
}
</script>
@@ -0,0 +1,25 @@
<template>
<div>
<ASwitch v-model="input" @change="search"/>
</div>
</template>
<script>
export default {
name: 'SwitchXTableFilter',
props: ['value'],
data() {
return {
input: undefined
}
},
methods: {
search() {
this.$emit('input', this.input)
},
},
mounted() {
this.input = this.value
}
}
</script>
@@ -0,0 +1,30 @@
<template>
<div>
<AInput v-model="input"
placehoder="مقدار"
@change="search"
@pressEnter="() => search()"
/>
</div>
</template>
<script>
export default {
name: 'TextXTableFilter',
props: ['value'],
data() {
return {
input: undefined
}
},
methods: {
search() {
this.$emit('input', this.input)
this.$emit('search', this.input)
},
},
mounted() {
this.input = this.value
}
}
</script>
@@ -0,0 +1,164 @@
<template>
<div class="grid md:grid-cols-4 gap-4">
<div class="flex">
<ARadioGroup :value="cr" v-model="cr" class="ml-4" v-if="!isFirst" @change="change">
<ARadioButton value="and">و</ARadioButton>
<ARadioButton value="or">یا</ARadioButton>
</ARadioGroup>
<ASelect class="flex-1" @change="change" v-model="col" placeholder="عنوان ستون">
<ASelectOption :value="item.key" :key="index" v-for="(item, index) in colFilters">
{{
item.title
}}
</ASelectOption>
</ASelect>
</div>
<ASelect :disabled="!col" placeholder="عملگر" v-model="op" @change="change">
<ASelectOption :value="index" :key="index" v-for="(item, index) in colTypes">
{{
item
}}
</ASelectOption>
</ASelect>
<div v-if="type && hasInput">
<component
@input="change"
:is="getModifierComponent"
:items="filterObject.filterItems"
:action="filterObject.filterAction"
v-model="input"
/>
</div>
<div>
<feather-icon icon="XIcon" class="cursor-pointer" svg-classes="text-danger" @click="$emit('remove', index)"/>
</div>
</div>
</template>
<script>
import NumberXTableFilter from "./NumberXTableFilter";
import SwitchXTableFilter from './SwitchXTableFilter'
import SelectOptionXTableFilter from './SelectOptionXTableFilter'
import DateXTableFilter from './DateXTableFilter'
import TextXTableFilter from './TextXTableFilter'
import QuerySelectTableFilter from './QuerySelectTableFilter'
export default {
name: "XFilterRow",
components: {
NumberXTableFilter,
SwitchXTableFilter,
SelectOptionXTableFilter,
QuerySelectTableFilter,
DateXTableFilter,
TextXTableFilter,
},
props: {
value: {default: {}},
isFirst: {default: false},
id: {},
index: {},
colFilters: {default: []}
},
data() {
return {
col: undefined,
op: undefined,
master: undefined,
cr: 'and',
input: undefined,
}
},
computed: {
hasInput() {
if (this.op) {
return !['null', 'nn'].includes(this.op);
}
},
getModifierComponent() {
const comp = {
'text': 'TextXTableFilter',
'default': 'TextXTableFilter',
'number': 'NumberXTableFilter',
'date': 'DateXTableFilter',
'switch': 'SwitchXTableFilter',
'select': 'SelectOptionXTableFilter',
'query': 'QuerySelectTableFilter',
};
return comp[this.type];
},
getModel() {
return {
cr: this.cr,
index: this.index,
field: this.col,
master: this.master,
type: this.type,
id: this.id,
op: this.op,
value: this.input
}
},
filterObject() {
return this.colFilters.find((item) => item.key == this.col);
},
type() {
if (this.filterObject) {
return this.filterObject.filterType;
}
},
colTypes() {
const exp = {};
if (!this.col) return [];
const filter = this.colFilters.find((item) => item.key == this.col);
if (!filter) return [];
switch (filter.filterType) {
case 'number':
case 'date':
exp.gt = 'بزرگتر';
exp.lt = 'کوچکتر';
exp.gte = 'بزرگتر مساوی';
exp.lte = 'کوچکتر مساوی';
// exp.bet = 'بین';
break;
case 'text':
exp.sw = 'شروع شود';
exp.ew = 'تمام شود';
break;
}
exp.eq = 'برابر';
exp.has = 'شامل';
exp.not = 'نباشد';
exp.null = 'تهی';
exp.nn = 'تهی نباشد';
return exp;
}
},
methods: {
change() {
const filter = this.colFilters.find((item) => item.key == this.col);
this.master = filter.master;
this.$emit('input', this.getModel);
}
},
mounted() {
this.cr = this.value.cr || 'and';
// this.index = this.value.index;
console.log("this.value.field ==> ", this.value);
this.col = this.value.field;
// this.type = this.value.type;
this.op = this.value.op;
this.input = this.value.value;
}
}
</script>
<style scoped>
</style>
+6
View File
@@ -0,0 +1,6 @@
import Xtc from "./model/Xtc";
import XTbl from "./model/XTbl";
export {Xtc};
export default XTbl;
+30
View File
@@ -0,0 +1,30 @@
export interface Xtc {
title: string;
key: string;
filter(): Xtc;
filterSwitch(): Xtc;
filterSelect(items: {}[]): Xtc;
filterDate(): Xtc;
filterNumber(): Xtc;
renderSlot(slotName: string): Xtc;
export(): {};
}
export interface XTbl {
title: string;
url: string;
cols: Xtc[];
addCol(col: Xtc): void;
addAll(cols: Xtc[]): void;
}
+62
View File
@@ -0,0 +1,62 @@
import Xtc from './Xtc'
export default class XTbl {
title;
url;
cols;
opt;
constructor(url, title) {
this.url = url;
this.title = title;
}
add(col) {
if (!this.cols) {
this.cols = [];
}
this.cols.push(col);
}
addOpt(col, slotEdit, slotDelete, ridEdit, ridDelete) {
this.opt = new Xtc('opt', 'عملیات').noSort();
this.opt.opt = true;
this.opt.slotEdit = slotEdit;
this.opt.slotDelete = slotDelete;
this.cols.push(this.opt)
return this;
}
hidePagination() {
this._hidePageination = true;
return this;
}
getSortFields() {
return this.cols.filter((item) => item.__sorter)
}
hideSearch() {
this._hidePageination = true;
return this;
}
addExtraBtn(btn) {
this._hidePageination = true;
return this;
}
noSearch() {
this._noSearch = true;
return this;
}
noSettings() {
this._noSettings = true;
return this;
}
}
+106
View File
@@ -0,0 +1,106 @@
export default class Xtc {
constructor(key, title) {
this.key = key;
this.title = title;
this.dataIndex = key;
this.show = true;
this.__sorter = true;
}
export() {
let exp = {};
exp['key'] = this.key;
exp['__key'] = this.__fkey;
exp['dataIndex'] = this.key;
exp['title'] = this.title;
if (this._slots) {
if(!this._slots.filterIcon){
this._slots.filterIcon = 'filterIcon';
}
exp['scopedSlots'] = this._slots;
}
if (this.filter) {
this.filter = this.filterType;
this.filtered = true;
}
return exp;
}
filterKey(key){
this.__fkey = key;
this.master = key;
return this;
}
renderSlot(name) {
this._slots = {
customRender: name
};
if (!this.scopedSlots) {
this.scopedSlots = {}
}
this.scopedSlots.customRender = name;
return this;
}
__filter() {
this.filtered = true;
if (!this._slots) {
this.scopedSlots = {};
}
this.scopedSlots.filterDropdown = `${this.key}_filterDropdown`;
this.scopedSlots.filterIcon = `${this.key}_filterIcon`;
}
filterText() {
this.__filter();
this.filterType = 'default';
return this;
}
filterSwitch() {
this.__filter();
this.filterType = 'switch';
return this;
}
filterQuery(action) {
this.__filter();
this.filterType = 'query';
this.filterAction = action;
return this;
}
filterDate() {
this.__filter();
this.filterType = 'date';
return this;
}
filterSelect(items) {
this.__filter();
this.filterType = 'select';
this.filterItems = items;
return this;
}
filterNumber() {
this.__filter();
this.filterType = 'number';
return this;
}
noSort() {
this.__sorter = false;
return this;
}
hidden() {
this.show = false;
return this;
}
}
+1
View File
@@ -0,0 +1 @@
git add . && git commit -m "Auto" && git push
+15
View File
@@ -0,0 +1,15 @@
import XTbl, {Xtc} from './index';
const tbl = new XTbl('http://kheyr.flut.ir/api/get-person', 'جدول مشتریان');
tbl.add(new Xtc('id', 'آیدی').filterNumber());
tbl.add(new Xtc('title', 'عنوان').filterText())
tbl.add(new Xtc('fname', 'نام کوچک').filterText())
tbl.add(new Xtc('lname', 'نام بزرگ').filterText())
tbl.add(new Xtc('ncode', 'کد ملی').filterText().hidden().noSort())
tbl.add(new Xtc('birth_date', 'تاریخ تولد').filterDate().hidden().noSort())
tbl.add(new Xtc('sts_str', 'وضعیت').renderSlot('sts_str').filterSelect({1: 'گزینه اول'}).noSort())
tbl.add(new Xtc('active', 'فعال').filterSwitch().hidden().noSort())
tbl.add(new Xtc('wow', 'فعال').filterSwitch().renderSlot('wow').noSort())
tbl.addOpt()
export default tbl;
+1 -1
View File
@@ -238,7 +238,7 @@
},
mounted() {
this.fetch();
console.log("this.model ==> ", this.model);
// console.log("this.model ==> ", this.model);
}
}
</script>