Init project

This commit is contained in:
alirezakarari
2021-01-09 20:53:13 +03:30
commit 8d06c89a89
1005 changed files with 105625 additions and 0 deletions
@@ -0,0 +1,83 @@
<template>
<div>
<a-range-picker
:default-value="[moment('2015/01/01', dateFormat), moment('2015/01/01', dateFormat)]"
:format="dateFormat"
/>
<a-button v-if="this.n==0"
@click="change"
type="primary"
size="small"
style="width: 90px; margin-right: 8px"
>
کمتر از
</a-button>
<a-button v-if="this.n==1"
@click="change"
type="primary"
size="small"
style="width: 90px; margin-right: 8px"
>
مساوی با
</a-button>
<a-button v-if="this.n==2"
@click="change"
type="primary"
size="small"
style="width: 90px; margin-right: 8px"
>
بیشتر از
</a-button>
</div>
</template>
<script>
import moment from 'moment';
export default {
name: 'TextSearchXTableFilter',
props:[
'setSelectedKeys',
'selectedKeys',
'confirm',
'clearFilters',
'column'
],
data () {
return {
dateFormat: 'YYYY/MM/DD',
monthFormat: 'YYYY/MM',
dateFormatList: ['DD/MM/YYYY', 'DD/MM/YY'],
size: 'default',
searchText: '',
searchedColumn: undefined,
n:"0"
}
},
methods: {
moment,
handleSearch (selectedKeys, confirm, dataIndex) {
confirm()
this.searchText = selectedKeys[0]
this.searchedColumn = dataIndex
},
handleReset (clearFilters) {
clearFilters()
this.searchText = ''
},
change(){
this.n++;
if(this.n==3){
this.n=0
}
console.log("n:",this.n)
}
},
mounted () {
console.log(this.props)
},
created () {
}
}
</script>
@@ -0,0 +1,93 @@
<template>
<div class="p-3" style="min-width: 250px">
<div class="flex mb-2" v-for="item,index in filter" :key="index">
<a-button @click="toggleCr(item)"
>{{getCrTitle(item)}}
</a-button>
<ADatePicker :disabled="item.op === 'nil'"
v-model="item.value"
@pressEnter="() => search()"
/>
</div>
<ADivider class="my-2"/>
<div class="flex">
<a @click="add">
<feather-icon icon="PlusIcon" svg-classes="w-5 h-5"/>
</a>
<div class="flex-1"></div>
<a v-if="filter.length > 1" @click="remove">
<feather-icon icon="MinusIcon" svg-classes="w-5 h-5 color-danger"/>
</a>
</div>
<div class="flex">
<AButton class="flex-1 mr-2" type="flat" size="small" @click="reset">ریست</AButton>
<AButton class="flex-1" type="primary" size="small" @click="search">فیلتر</AButton>
</div>
</div>
</template>
<script>
export default {
name: 'DateXTableFilter',
props: ['column'],
data() {
return {
filter: [],
crs: ['not', 'nn', 'nil', 'gt', 'lt']
}
},
methods: {
toggleCr(item) {
const ind = this.crs.indexOf(item.op) + 1;
if (ind in this.crs) {
item.op = this.crs[ind]
return;
}
item.op = this.crs[0];
},
add() {
this.filter.push({
op: 'and',
id: `${this.column.key}-${this.filter.length}`,
field: this.column.key,
value: undefined
})
},
remove() {
this.filter.pop();
},
search() {
this.$emit('search', {model: this.filter.filter((item) => item.value), column: this.column})
},
reset() {
this.filter = [
{
op: 'and',
id: `${this.column.key}-${this.filter.length}`,
field: this.column.key,
value: undefined
}
];
this.$emit('search', {model: this.filter.filter((item) => item.value), key: this.column})
},
getCrTitle(item) {
return {and: 'و', or: 'یا', not: 'نباشد', nn: 'انباشته', nil: 'تهی', gt: "بزرگتر", lt: 'کوچکتر'}[item.op];
},
getCrType(item) {
return {
and: 'primary',
or: 'danger',
not: 'warning',
nn: 'flat',
nil: '',
gt: "primary",
lt: 'primary'
}[item.op]
}
},
created() {
this.add()
}
}
</script>
@@ -0,0 +1,93 @@
<template>
<div class="p-3" style="min-width: 250px">
<div class="flex mb-2" v-for="item,index in filter" :key="index">
<a-button @click="toggleCr(item)"
>{{getCrTitle(item)}}
</a-button>
<AInputNumber :disabled="item.op === 'nil'"
v-model="item.value"
@pressEnter="() => search()"
/>
</div>
<ADivider class="my-2"/>
<div class="flex">
<a @click="add">
<feather-icon icon="PlusIcon" svg-classes="w-5 h-5"/>
</a>
<div class="flex-1"></div>
<a v-if="filter.length > 1" @click="remove">
<feather-icon icon="MinusIcon" svg-classes="w-5 h-5 color-danger"/>
</a>
</div>
<div class="flex">
<AButton class="flex-1 mr-2" type="flat" size="small" @click="reset">ریست</AButton>
<AButton class="flex-1" type="primary" size="small" @click="search">فیلتر</AButton>
</div>
</div>
</template>
<script>
export default {
name: 'NumberXTableFilter',
props: ['column'],
data() {
return {
filter: [],
crs: ['not', 'nn', 'nil', 'gt', 'lt']
}
},
methods: {
toggleCr(item) {
const ind = this.crs.indexOf(item.op) + 1;
if (ind in this.crs) {
item.op = this.crs[ind]
return;
}
item.op = this.crs[0];
},
add() {
this.filter.push({
op: 'and',
id: `${this.column.key}-${this.filter.length}`,
field: this.column.key,
value: undefined
})
},
remove() {
this.filter.pop();
},
search() {
this.$emit('search', {model: this.filter.filter((item) => item.value), column: this.column})
},
reset() {
this.filter = [
{
op: 'and',
id: `${this.column.key}-${this.filter.length}`,
field: this.column.key,
value: undefined
}
];
this.$emit('search', {model: this.filter.filter((item) => item.value), key: this.column})
},
getCrTitle(item) {
return {and: 'و', or: 'یا', not: 'نباشد', nn: 'انباشته', nil: 'تهی', gt: "بزرگتر", lt: 'کوچکتر'}[item.op];
},
getCrType(item) {
return {
and: 'primary',
or: 'danger',
not: 'warning',
nn: 'flat',
nil: '',
gt: "primary",
lt: 'primary'
}[item.op]
}
},
created() {
this.add()
}
}
</script>
@@ -0,0 +1,59 @@
<template>
<div class="flex">
<a-button @click="changeStatus()" style="width:20%;margin: 0px 0 0" type="primary" v-if="status==1">و</a-button>
<a-button @click="changeStatus()" style="width:20%;margin: 0px 0 0" type="danger" v-if="status==2">یا</a-button>
<a-button @click="changeStatus()" style="width:20%;margin: 0px 0 0" v-if="status==3">تهی</a-button>
<a-select v-if="status===3" disabled v-ant-ref="c => (searchInput = c)" :value="selectedKeys[0]" :default-value="0" style="width: 80%; margin-bottom: 8px; display: block;" @change="e => setSelectedKeys(e.target.value ? [e.target.value] : [])" @pressEnter="() => handleSearch(selectedKeys, confirm, column.dataIndex)">
<a-select-option v-for="i in 25" :key="(i + 9).toString(36) + i">
{{i}}
</a-select-option>
</a-select>
<a-select v-else v-ant-ref="c => (searchInput = c)" :value="selectedKeys[0]" :default-value="0" style="width: 80%; margin-bottom: 8px; display: block;" @change="e => setSelectedKeys(e.target.value ? [e.target.value] : [])" @pressEnter="() => handleSearch(selectedKeys, confirm, column.dataIndex)">
<a-select-option v-for="i in 25" :key="(i + 9).toString(36) + i">
{{i}}
</a-select-option>
</a-select>
</div>
</template>
<script>
export default {
name: 'TextSearchXTableFilter',
props: [
'setSelectedKeys',
'selectedKeys',
'confirm',
'clearFilters',
'column'
],
data() {
return {
searchText: '',
searchedColumn: undefined,
status: 1
}
},
methods: {
handleSearch(selectedKeys, confirm, dataIndex) {
confirm()
this.searchText = selectedKeys[0]
this.searchedColumn = dataIndex
},
changeStatus() {
this.status = this.status + 1;
if (this.status === 4) {
this.status = 1;
}
},
handleReset(clearFilters) {
clearFilters()
this.searchText = ''
}
},
mounted() {
console.log(this.props)
},
created() {}
}
</script>
@@ -0,0 +1,79 @@
<template>
<div class="p-3" style="min-width: 250px">
<div class="flex mb-2 items-center" v-for="item,index in filter" :key="index">
<div class="flex-1"></div>
<ASwitch :disabled="item.op === 'nil'"
v-model="item.value"
@pressEnter="() => search()"
/>
</div>
<ADivider class="my-2"/>
<div class="flex">
<AButton class="flex-1 mr-2" type="flat" size="small" @click="reset">ریست</AButton>
<AButton class="flex-1" type="primary" size="small" @click="search">فیلتر</AButton>
</div>
</div>
</template>
<script>
export default {
name: 'SwitchXTableFilter',
props: ['column'],
data() {
return {
filter: [],
crs: ['and', 'or']
}
},
methods: {
toggleCr(item) {
const ind = this.crs.indexOf(item.op) + 1;
if (ind in this.crs) {
item.op = this.crs[ind]
return;
}
item.op = this.crs[0];
},
add() {
this.filter.push({
op: 'and',
id: `${this.column.key}-${this.filter.length}`,
field: this.column.key,
value: true
})
},
remove() {
this.filter.pop();
},
search() {
this.$emit('search', {model: this.filter.filter((item) => item.value != undefined), column: this.column})
},
reset() {
this.filter = [{
op: 'and',
id: `${this.column.key}-${this.filter.length}`,
field: this.column.key,
value: undefined
}];
this.$emit('search', {model: this.filter.filter((item) => item.value != undefined), key: this.column})
},
getCrTitle(item) {
return {and: 'و', or: 'یا'}[item.op];
},
getCrType(item) {
return {
and: 'primary',
or: 'danger',
not: 'warning',
nn: 'flat',
nil: '',
gt: "primary",
lt: 'primary'
}[item.op]
}
},
created() {
this.add()
}
}
</script>
@@ -0,0 +1,93 @@
<template>
<div class="p-3" style="min-width: 250px">
<div class="flex mb-2" v-for="item,index in filter" :key="index">
<a-button @click="toggleCr(item)"
>{{getCrTitle(item)}}
</a-button>
<AInput :disabled="item.op === 'nil'"
v-model="item.value"
@pressEnter="() => search()"
/>
</div>
<ADivider class="my-2"/>
<div class="flex">
<a @click="add">
<feather-icon icon="PlusIcon" svg-classes="w-5 h-5"/>
</a>
<div class="flex-1"></div>
<a v-if="filter.length > 1" @click="remove">
<feather-icon icon="MinusIcon" svg-classes="w-5 h-5 color-danger"/>
</a>
</div>
<div class="flex">
<AButton class="flex-1 mr-2" type="flat" size="small" @click="reset">ریست</AButton>
<AButton class="flex-1" type="primary" size="small" @click="search">فیلتر</AButton>
</div>
</div>
</template>
<script>
export default {
name: 'TextXTableFilter',
props: ['column'],
data() {
return {
filter: [],
crs: ['not', 'nn', 'nil']
}
},
methods: {
toggleCr(item) {
const ind = this.crs.indexOf(item.op) + 1;
if (ind in this.crs) {
item.op = this.crs[ind]
return;
}
item.op = this.crs[0];
},
add() {
this.filter.push({
op: 'and',
id: `${this.column.key}-${this.filter.length}`,
field: this.column.key,
value: undefined
})
},
remove() {
this.filter.pop();
},
search() {
this.$emit('search', {model: this.filter.filter((item) => item.value), column: this.column})
},
reset() {
this.filter = [
{
op: 'and',
id: `${this.column.key}-${this.filter.length}`,
field: this.column.key,
value: undefined
}
];
this.$emit('search', {model: this.filter.filter((item) => item.value), key: this.column})
},
getCrTitle(item) {
return {and: 'و', or: 'یا', not: 'نباشد', nn: 'انباشته', nil: 'تهی', gt: "بزرگتر", lt: 'کوچکتر'}[item.op];
},
getCrType(item) {
return {
and: 'primary',
or: 'danger',
not: 'warning',
nn: 'flat',
nil: '',
gt: "primary",
lt: 'primary'
}[item.op]
}
},
created() {
this.add()
}
}
</script>
+286
View File
@@ -0,0 +1,286 @@
<template>
<div>
<ACard ref="tblCard">
<ASpin :spinning="loading">
<div class="flex w-full justify-between">
<a-input-search class="w-1/4 pb-4 input-ltr" placeholder="جستجو بر اساس نام / کد ملی / کد پرسنلی / شمار بیمه" enter-button="جستجو" @search="onSearch"/>
<div class="flex items-center">
<a class="left-table-btn" @click="fullScreen">
<feather-icon :icon="getFullIcon" svg-classes="w-5 h-5"/>
</a>
<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>
<a class="left-table-btn ">
<feather-icon icon="SettingsIcon" svg-classes="w-5 h-5"/>
</a>
</ADropdown>
<a class="left-table-btn refresh-btn" @click="fetch">
<feather-icon icon="RotateCwIcon" svg-classes="w-5 h-5"/>
</a>
</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
show-size-changer
:pageSizeOptions="['5','10','20']"
:page-size.sync="query.pageSize"
@change="changePage"
@showSizeChange="changePage"
:default-current="1" :total="query.total" v-model.sync="query.currentPage">
<template slot="buildOptionText" slot-scope="props">
<div dir="rtl">
<span> {{ props.value }} </span>
<span>رکورد</span>
</div>
</template>
</APagination>
</div>
</div>
<div v-for="item,index in getColsFilter" :slot="item.scopedSlots.filterDropdown"
slot-scope="{ setSelectedKeys, selectedKeys, confirm, clearFilters, column }">
<div>
<TextXTableFilter v-if="item.filterType === 'default'"
:column="column"
@search="submitFilter"
/>
<SwitchXTableFilter v-if="item.filterType === 'switch'"
:column="column"
@search="submitFilter"
/>
<NumberXTableFilter v-if="item.filterType === 'number'"
:column="column"
@search="submitFilter"
/>
<SelectOptionXTableFilter v-if="item.filterType === 'select'" :column="item"
:set-selected-keys="setSelectedKeys" :selected-keys="selectedKeys"
:confirm="confirm" :clear-filters="clearFilters"/>
<DateXTableFilter v-if="item.filterType === 'date'"
:column="column"
@search="submitFilter"
/>
</div>
<a-icon :slot="item.scopedSlots.filterIcon" slot-scope="filtered" type="search"
:style="{ color: filtered ? '#108ee9' : undefined }"/>
</div>
</a-table>
</ASpin>
</ACard>
</div>
</template>
<script>
import SwitchXTableFilter from './SwitchXTableFilter'
import SelectOptionXTableFilter from './SelectOptionXTableFilter'
import DateXTableFilter from './DateXTableFilter'
import TextXTableFilter from './TextXTableFilter'
import XTbl from "./model/XTbl";
import Draggable from 'vuedraggable'
import axios from "../../axios";
import {openFullscreen, closeFullscreen} from "@/plugins/fullscreen";
import NumberXTableFilter from "./NumberXTableFilter";
export default {
name: 'XTable',
components: {
TextXTableFilter,
NumberXTableFilter,
SwitchXTableFilter,
SelectOptionXTableFilter,
Draggable,
DateXTableFilter,
// DatePickerBetweenXTableFilter
},
props: {
model: {
type: XTbl.default
}
},
data() {
return {
data: [],
query: {
search: undefined,
total: 0,
pageSize: 10,
currentPage: 1,
},
locale: {
emptyText: 'هیج رکوردی یافت نشد.'
},
loading: false,
full: false,
colSelector: false
}
},
methods: {
submitFilter({model, column}) {
if (!this.query.filters) {
this.query.filters = []
}
this.query.filters = this.query.filters.filter((item) => item.field !== column.key);
this.query.filters = this.query.filters.concat(model);
this.fetch()
},
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() {
return this.query;
},
async fetch() {
try {
this.loading = true;
const {data: {list, pagination}} = await axios.post(this.model.url, this.requestData());
this.data = list;
this.query = pagination;
} catch (e) {
throw e
} finally {
this.loading = false;
}
},
noThings() {
},
onSearch(value) {
console.log(value);
this.query.search = value;
if (value) {
this.fetch();
}
},
showColSelector() {
this.colSelector = !this.colSelector;
}
},
computed: {
getFullIcon() {
return !this.full ? 'Maximize2Icon' : 'Minimize2Icon';
},
customRender() {
return this.model.cols.filter((item) => item.scopedSlots && item.scopedSlots.customRender).map((i) => i.scopedSlots.customRender)
},
cols: {
get() {
return this.model.cols || [];
},
set(value) {
this.model.cols = value;
}
},
getColsFilter() {
return this.cols.filter(item => item.filtered)
},
visibleCols() {
return this.cols.filter(item => item.show)
}
},
mounted() {
this.fetch();
console.log("this.model ==> ", this.model);
}
}
</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;
}
.left-table-btn {
height: 30px;
margin-left: 15px;
}
.refresh-btn {
transition: all 0.2s ease;
}
.refresh-btn:hover {
transform: rotate(-45deg);
}
.input-ltr {
direction: ltr !important;
}
.ant-input-wrapper.ant-input-group input[type="text"]{
direction: rtl !important;
}
</style>
+7
View File
@@ -0,0 +1,7 @@
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;
}
+47
View File
@@ -0,0 +1,47 @@
import Xtc from './Xtc.js';
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;
}
hideSearch() {
this._hidePageination = true;
return this;
}
addExtraBtn(btn) {
this._hidePageination = true;
return this;
}
}
+97
View File
@@ -0,0 +1,97 @@
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['dataIndex'] = this.key;
exp['title'] = this.title;
if (this._slots) {
exp['scopedSlots'] = this._slots;
}
if (this.filter) {
this.filter = this.filterType;
this.filtered = true;
}
return exp;
}
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`;
}
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;
}
}
+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;