1404/06/05-first
|
|
@ -0,0 +1,24 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"recommendations": ["Vue.volar"]
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + Vue + TS</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"name": "macharta",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc -b && vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@lucky-canvas/vue": "^0.1.11",
|
||||
"@types/node": "^24.3.0",
|
||||
"@vitejs/plugin-vue-jsx": "^5.0.1",
|
||||
"@vueuse/core": "^13.7.0",
|
||||
"ant-design-vue": "^4.2.6",
|
||||
"axios": "^1.11.0",
|
||||
"jalaliday": "^3.1.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lucky-canvas": "^1.7.27",
|
||||
"moment": "^2.30.1",
|
||||
"moment-jalaali": "^0.10.4",
|
||||
"pinia": "^3.0.3",
|
||||
"vant": "^4.9.21",
|
||||
"vue": "^3.5.18",
|
||||
"vue-router": "^4.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^6.0.1",
|
||||
"@vue/tsconfig": "^0.7.0",
|
||||
"less": "^4.4.1",
|
||||
"typescript": "~5.8.3",
|
||||
"unocss": "^66.4.2",
|
||||
"vite": "^7.1.2",
|
||||
"vue-tsc": "^3.0.5"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
|
@ -0,0 +1,89 @@
|
|||
|
||||
<template>
|
||||
<AConfigProvider
|
||||
direction="rtl"
|
||||
:theme="{
|
||||
token: {
|
||||
fontFamily: 'iran-sans',
|
||||
colorPrimary: colors.primary,
|
||||
colorLink: colors.primary,
|
||||
colorLinkActive: colors.primary,
|
||||
colorLinkHover: colors['primary']
|
||||
}
|
||||
}"
|
||||
>
|
||||
|
||||
<div class="relative ">
|
||||
<!-- <InstallPWA v-if="userStore.user" class="fixed left-0 bottom-24 w-full flex justify-center z-50"/>-->
|
||||
<!-- <AAffix :offset-top="0">-->
|
||||
<!-- <div class="shadow-md primaryColor">-->
|
||||
<!-- <div class="container mx-auto max-w-[92rem]">-->
|
||||
<!-- <Navbar class="md:hidden" v-if="router.currentRoute.value.meta.showNavbar" />-->
|
||||
<!-- <div class="hidden md:block relative" v-if="router.currentRoute.value.meta.showMenu">-->
|
||||
<!-- <Menu />-->
|
||||
<!-- <div class="flex justify-center absolute top-0 bottom-0 left-4">-->
|
||||
<!-- <div class="hidden md:flex items-center">-->
|
||||
<!-- <ADropdown placement="bottom">-->
|
||||
<!-- <div-->
|
||||
<!-- class="bg-[#E2E8F0] p-2 rounded-full flex justify-center items-center cursor-pointer w-12 h-12">-->
|
||||
<!--<!– <img :src="avatar" alt="">–>-->
|
||||
<!-- </div>-->
|
||||
<!-- <template #overlay>-->
|
||||
<!-- <div class="w-[334px] backUserSetting1 shadow-lg py-6 px-4 rounded-md">-->
|
||||
<!-- <UserSetting />-->
|
||||
<!-- </div>-->
|
||||
<!-- </template>-->
|
||||
<!-- </ADropdown>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="flex justify-center absolute top-0 bottom-0 p-2 right-4">-->
|
||||
<!--<!– <img :src="logo" alt="">–>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </AAffix>-->
|
||||
<AAffix offset-top="0" >
|
||||
<div v-if="router.currentRoute.value.meta.showNavbar" class="flex px-4 items-center pt-10 mb-3 bg-gradient-to-b from-[#EAEAEA] ">
|
||||
<div class="bg-[#C1FCE2] flex items-center relative rounded-full h-6vh w-1/2">
|
||||
<div class="absolute bottom-0"><img src="@/assets/img/boy_3752622%201.svg"></div>
|
||||
<div class=" text-center w-full font-700 pr-8 ">امیر علی</div>
|
||||
</div>
|
||||
<div class="flex gap-3 w-1/2 justify-end ">
|
||||
<div><img src="@/assets/img/alertIcon.png"></div>
|
||||
<div><img src="@/assets/img/menu_8917404%201.png"></div>
|
||||
</div>
|
||||
</div>
|
||||
</AAffix>
|
||||
<RouterView v-slot="{ Component }">
|
||||
<transition mode="out-in" name="fade">
|
||||
<KeepAlive>
|
||||
<Component class="container mx-auto max-w-[90rem] px-4 overflow-y-auto py-6 h-75vh" :is="Component" />
|
||||
</KeepAlive>
|
||||
</transition>
|
||||
</RouterView>
|
||||
<!-- <Affix offset-bottom="3" class="w-full " >-->
|
||||
<div class="fixed z-2 bottom-0 w-full bg-gradient-to-t from-[#EAEAEA] pt-15 px-4 pb-3">
|
||||
<div class=" border-1 border-black rounded-3xl box-border" style="box-shadow: 0px 3.75px 16px 0px #00000030;">
|
||||
<Menu v-if="router.currentRoute.value.meta.showMenu" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- </Affix>-->
|
||||
</div>
|
||||
</AConfigProvider>
|
||||
</template>
|
||||
|
||||
|
||||
<script setup lang="ts">
|
||||
import {colors} from "@/themeConfig.ts";
|
||||
import router from "@/router";
|
||||
import Menu from "@/components/Menu.vue";
|
||||
import {route} from "vant/es/composables/use-route";
|
||||
const keepAliveList = ['product-list']
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
.ant-modal-content {
|
||||
padding: 16px !important;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
@import (less) 'var.less';
|
||||
|
||||
@font-face {
|
||||
font-family: @prefixCls-font-family;
|
||||
src: url('../fonts/iranSans/woff2/IRANSansWeb(FaNum).woff2') format('woff2');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: @prefixCls-font-family;
|
||||
src: url('../fonts/iranSans/woff2/IRANSansWeb(FaNum)_Light.woff2') format('woff2');
|
||||
font-weight: 100;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: @prefixCls-font-family;
|
||||
src: url('../fonts/iranSans/woff2/IRANSansWeb(FaNum)_UltraLight.woff2') format('woff2');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: @prefixCls-font-family;
|
||||
src: url('../fonts/iranSans/woff2/IRANSansWeb(FaNum)_Medium.woff2') format('woff2');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: @prefixCls-font-family;
|
||||
src: url('../fonts/iranSans/woff2/IRANSansWeb(FaNum)_Bold.woff2') format('woff');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: @prefixCls-font-family;
|
||||
src: url('../fonts/iranSans/woff2/IRANSansWeb(FaNum)_Black.woff2') format('woff');
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
}
|
||||
|
|
@ -0,0 +1,302 @@
|
|||
|
||||
body {
|
||||
background: #EAEAEA;
|
||||
color: #000000;
|
||||
}
|
||||
body .menuItem{
|
||||
color: #5F6368;
|
||||
fill: #5F6368;
|
||||
stroke: #5F6368;
|
||||
}
|
||||
body .menuItemSelect svg{
|
||||
color: #081023;
|
||||
fill: #ff0c0c;
|
||||
stroke: #2563EB;
|
||||
}
|
||||
body .textColor1{
|
||||
color: #616161;
|
||||
}
|
||||
body .textColor2{
|
||||
color: #9E9E9E;
|
||||
}
|
||||
body .ant-tabs-tab-btn{
|
||||
color: #000000;
|
||||
}
|
||||
body .text_Primary{
|
||||
color: #424242;
|
||||
}
|
||||
body .text_Secondary{
|
||||
color: #2563EB;
|
||||
}
|
||||
body .background_Primary{
|
||||
background: #424242;
|
||||
}
|
||||
body .background_Secondary{
|
||||
background: #F5F5F5;
|
||||
}
|
||||
body .primaryColor{
|
||||
color: #000000 ;
|
||||
}
|
||||
body .ant-menu{
|
||||
color: #FFFFFFFF ;
|
||||
}
|
||||
body .text_green{
|
||||
color: #4CAF50FF ;
|
||||
}
|
||||
body .background_green{
|
||||
background: #4CAF50FF ;
|
||||
}
|
||||
body .text_red{
|
||||
color: #F44336FF ;
|
||||
}
|
||||
body .background_red{
|
||||
background: #F44336FF ;
|
||||
}
|
||||
body .ant-table-cell{
|
||||
background: #ffffff ;
|
||||
border-color: #e5e7eb ;
|
||||
}
|
||||
body .ant-table-wrapper .ant-table-thead>tr>th {
|
||||
background: #fafafa ;
|
||||
border-color: #e5e7eb ;
|
||||
}
|
||||
body .ant-table-wrapper .ant-table-thead > tr > th::before,
|
||||
.ant-table-wrapper .ant-table-thead > tr > td::before {
|
||||
background-color: #F44336FF;
|
||||
}
|
||||
body .ab-base-table .ant-table-wrapper {
|
||||
border: none ;
|
||||
}
|
||||
body .ant-table-wrapper .ant-table {
|
||||
color: #000000;
|
||||
}
|
||||
body :where(.css-dev-only-do-not-override-ajjz7p).ant-btn-primary {
|
||||
background-color: #000000 ;
|
||||
}
|
||||
body .ant-modal .ant-modal-content {
|
||||
background-color: #ffffff ;
|
||||
}
|
||||
body .ant-modal-title{
|
||||
background-color: #ffffff ;
|
||||
color: #000000;
|
||||
}
|
||||
body .ant-input{
|
||||
background: #ffffff ;
|
||||
border-color: #e5e7eb ;
|
||||
color: #000000 ;
|
||||
}
|
||||
body .ant-input-group-addon{
|
||||
background: #2563EB ;
|
||||
border-color: #e5e7eb ;
|
||||
color: #ffffff;
|
||||
}
|
||||
body .ant-form-item .ant-form-item-label >label {
|
||||
color: #000000 ;
|
||||
}
|
||||
//User Setting
|
||||
body .backUserSetting1 {
|
||||
background-color: #ffffff ;
|
||||
}
|
||||
body .backUserSetting2 {
|
||||
background-color: #fafafa ;
|
||||
border-color: #e5e7eb ;
|
||||
}
|
||||
body .iconUserSetting {
|
||||
stroke: #000000 ;
|
||||
fill: #000000 ;
|
||||
}
|
||||
body .okButtonUserSetting {
|
||||
background-color: #2563EB ;
|
||||
border-color: #2563EB ;
|
||||
color: #ffffff ;
|
||||
}
|
||||
body .cancelButtonUserSetting {
|
||||
color: #000000 ;
|
||||
border-color: #e5e7eb ;
|
||||
background-color: #ffffff ;
|
||||
}
|
||||
//Security
|
||||
body .backSecurity {
|
||||
background-color: #ffffff ;
|
||||
}
|
||||
body .ant-input-password {
|
||||
//border: none ;
|
||||
border-color: #e5e7eb ;
|
||||
background-color: #ffffff ;
|
||||
}
|
||||
body .ant-input-password.input {
|
||||
//color: @bg ;
|
||||
}
|
||||
//Quit
|
||||
body .exit {
|
||||
color: #F44336 ;
|
||||
background-color: #F44336 ;
|
||||
}
|
||||
body .exitButton {
|
||||
color: #000000 ;
|
||||
background-color: #ffffff ;
|
||||
}
|
||||
//Login
|
||||
body .backLogin {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
body .textColorLogin1 {
|
||||
color: #424242;
|
||||
}
|
||||
body .textColorLogin2 {
|
||||
color: #9E9E9E;
|
||||
}
|
||||
body .buttonLogin {
|
||||
background-color: #2563EB ;
|
||||
color: #ffffff ;
|
||||
}
|
||||
body .textColorLogin1 {
|
||||
color: #424242;
|
||||
}
|
||||
body .ab-login .ant-tabs-nav-wrap {
|
||||
background: #f9fafb ;
|
||||
}
|
||||
body .buttonHover{
|
||||
border-color: #e5e7eb ;
|
||||
}
|
||||
//BuySell
|
||||
body .BuySell_Style{
|
||||
//background: #FAFAFA;
|
||||
border-color: #e5e7eb;
|
||||
}
|
||||
body .BuySell_text1{
|
||||
color: #616161;
|
||||
}
|
||||
body .BuySell_text2{
|
||||
color: #000000 ;
|
||||
}
|
||||
body .BuySell_button{
|
||||
background-color: #2563EB ;
|
||||
color: #ffffff ;
|
||||
}
|
||||
body .BuySell_cancelButton{
|
||||
background-color: #ffffff ;
|
||||
color: #000000 ;
|
||||
}
|
||||
body .BuySell_button_{
|
||||
border-color: #e5e7eb ;
|
||||
background: #ffffff ;
|
||||
}
|
||||
body .BuySell_back{
|
||||
border-color: #e5e7eb ;
|
||||
background: #ffffff ;
|
||||
}
|
||||
body .mobileBuySell_back{
|
||||
background: #ffffff ;
|
||||
color: #000000 ;
|
||||
}
|
||||
//hover style
|
||||
body .ant-input:hover {
|
||||
border-color: #2563EB;
|
||||
border-inline-end-width: 1px;
|
||||
}
|
||||
//mobile Header
|
||||
body .backHeader{
|
||||
background: #ffffff ;
|
||||
}
|
||||
//transaction card
|
||||
body .backCard{
|
||||
background: #ffffff;
|
||||
}
|
||||
body .textCard1{
|
||||
color: #616161;
|
||||
}
|
||||
body .textCard2{
|
||||
color: #BDBDBD;
|
||||
}
|
||||
body .textCard3{
|
||||
color: #9E9E9E;
|
||||
}
|
||||
body .MobileNavbar{
|
||||
background: #ffffff;
|
||||
border-color: #e5e7eb;
|
||||
color: #000000;
|
||||
}
|
||||
body .back_SearchBoxCard{
|
||||
background: #ffffff ;
|
||||
border-color: #e5e7eb ;
|
||||
}
|
||||
body .back_SearchBoxCard2{
|
||||
background: #ffffff;
|
||||
}
|
||||
body .searchIcon{
|
||||
stroke: #d9d9d9 ;
|
||||
}
|
||||
body .transferIcon{
|
||||
stroke: #000000;
|
||||
}
|
||||
//ADrawer
|
||||
body .ADrawer{
|
||||
background: #ffffff;
|
||||
border-color: #e5e7eb;
|
||||
}
|
||||
body .icon_MobileNavbar{
|
||||
stroke: #000000 ;
|
||||
}
|
||||
body .drawer-body{
|
||||
background: #112234FF ;
|
||||
}
|
||||
//order card
|
||||
body .orderCard_text{
|
||||
color: #616161 ;
|
||||
}
|
||||
body .orderCard_back{
|
||||
background: #dfdfdf;
|
||||
}
|
||||
body :where(.css-dev-only-do-not-override-1yhcnou).ant-float-btn-primary .ant-float-btn-body{
|
||||
background-color: #2563EB;
|
||||
}
|
||||
body :where(.css-dev-only-do-not-override-1yhcnou).ant-input-affix-wrapper{
|
||||
background-color: #ffffff;
|
||||
border-color: #d9d9d9;
|
||||
}
|
||||
body .ant-pagination .ant-pagination-item a {
|
||||
color: #616161;
|
||||
}
|
||||
body .ant-select {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
body :where(.css-dev-only-do-not-override-ajjz7p).ant-select:not(.ant-select-customize-input) .ant-select-selector {
|
||||
position: relative;
|
||||
background-color: #ffffff;
|
||||
transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
}
|
||||
body :where(.css-dev-only-do-not-override-1yhcnou).ant-btn-default:not(:disabled):hover {
|
||||
border-color: #2563EB;
|
||||
}
|
||||
body :where(.css-dev-only-do-not-override-1yhcnou).ant-tabs .ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn{
|
||||
//color: #2563EB;
|
||||
}
|
||||
body .ant-select-selector, .ant-tooltip-open, .ant-select-selection-item, .ant-select-item .ant-select-item-option{
|
||||
color: #616161;
|
||||
}
|
||||
body .ant-tabs-nav-wrap{
|
||||
justify-content: center;
|
||||
}
|
||||
body .avatarIcon {
|
||||
fill: #5F6368;
|
||||
stroke: #5F6368;
|
||||
}
|
||||
//User Card
|
||||
body .userCard:hover {
|
||||
border-color: #2563EB;
|
||||
}
|
||||
body .userCard {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
//product Price Card
|
||||
body .productPriceCard {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
body .backProductPriceCard {
|
||||
background-color: #2563EB;
|
||||
}
|
||||
body .iconProductPriceCard {
|
||||
color: #2563EB;
|
||||
background-color: rgba(37, 99, 235, 0.29);
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
@import (less) 'var.less';
|
||||
@import (less) 'fonts.less';
|
||||
@import (less) 'ant.less';
|
||||
@import (less) 'macharta.less';
|
||||
|
||||
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: @prefixCls-font-family !important;
|
||||
background-color: @prefixCls-background-color-mobile;
|
||||
direction: rtl !important;
|
||||
height: unset !important;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
body {
|
||||
background-color: @prefixCls-background-color;
|
||||
}
|
||||
}
|
||||
|
||||
pre, .ant-btn, span, label, input, div {
|
||||
font-family: @prefixCls-font-family !important;
|
||||
}
|
||||
|
||||
.en-font {
|
||||
font-family: Arial !important;
|
||||
direction: rtl !important;
|
||||
}
|
||||
|
||||
.ant-form .ant-form-item .ant-form-item-label, .ant-form .ant-form-item .ant-form-item-control {
|
||||
flex: 0 0 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.ant-form-item .ant-form-item-label {
|
||||
margin: 0;
|
||||
padding: 0 0 8px;
|
||||
white-space: initial;
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.ant-modal .ant-modal-footer {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
@prefixCls: 'ab';
|
||||
@border-radius-base: 8px;
|
||||
@primary-color: #1d4ed8;
|
||||
// Border color
|
||||
@border-color-base: @gray-100; // base border outline a component
|
||||
// Form
|
||||
@form-item-label-font-size: 14px;
|
||||
//variables
|
||||
@prefixCls-font-family: 'iran-sans';
|
||||
@prefixCls-background-color-mobile: #fafafa;
|
||||
@prefixCls-background-color: #fff;
|
||||
@gray-50: #f6f7f9;
|
||||
@gray-100: #e8eaee;
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"vuesax-bulk:shop": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path opacity=\"0.4\" d=\"M21.37 11.39V17.38C21.37 20.14 19.13 22.38 16.37 22.38H7.63C4.87 22.38 2.63 20.14 2.63 17.38V11.46C3.39 12.28 4.47 12.75 5.64 12.75C6.9 12.75 8.11 12.12 8.87 11.11C9.55 12.12 10.71 12.75 12 12.75C13.28 12.75 14.42 12.15 15.11 11.15C15.88 12.14 17.07 12.75 18.31 12.75C19.52 12.75 20.62 12.26 21.37 11.39Z\" fill=\"#292D32\"/>\n<path d=\"M14.99 1.25H8.98997L8.24997 8.61C8.18997 9.29 8.28997 9.93 8.53997 10.51C9.11997 11.87 10.48 12.75 12 12.75C13.54 12.75 14.87 11.89 15.47 10.52C15.65 10.09 15.76 9.59 15.77 9.08V8.89L14.99 1.25Z\" fill=\"#292D32\"/>\n<path opacity=\"0.6\" d=\"M22.36 8.27L22.07 5.5C21.65 2.48 20.28 1.25 17.35 1.25H13.51L14.25 8.75C14.26 8.85 14.27 8.96 14.27 9.15C14.33 9.67 14.49 10.15 14.73 10.58C15.45 11.9 16.85 12.75 18.31 12.75C19.64 12.75 20.84 12.16 21.59 11.12C22.19 10.32 22.46 9.31 22.36 8.27Z\" fill=\"#292D32\"/>\n<path opacity=\"0.6\" d=\"M6.59002 1.25C3.65002 1.25 2.29002 2.48 1.86002 5.53L1.59002 8.28C1.49002 9.35 1.78002 10.39 2.41002 11.2C3.17002 12.19 4.34002 12.75 5.64002 12.75C7.10002 12.75 8.50002 11.9 9.21002 10.6C9.47002 10.15 9.64002 9.63 9.69002 9.09L10.47 1.26H6.59002V1.25Z\" fill=\"#292D32\"/>\n<path d=\"M11.35 16.66C10.08 16.79 9.12 17.87 9.12 19.15V22.38H14.87V19.5C14.88 17.41 13.65 16.42 11.35 16.66Z\" fill=\"#292D32\"/>\n</svg>\n",
|
||||
"vuesax-bulk:strongbox-2": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path opacity=\"0.4\" d=\"M16.19 2H7.82002C4.18002 2 2.01001 4.17 2.01001 7.81V16.18C2.01001 19.82 4.18002 21.99 7.82002 21.99H16.19C19.83 21.99 22 19.82 22 16.18V7.81C22 4.17 19.83 2 16.19 2Z\" fill=\"#292D32\"/>\n<path d=\"M16 9.23999H18C18.55 9.23999 19 8.78999 19 8.23999V8C19 6.34 17.66 5 16 5H8C6.34 5 5 6.34 5 8V8.5C5 9.05 5.45 9.5 6 9.5H7.34C8.65 9.5 9.84 10.44 9.97 11.75C10.12 13.25 8.95 14.51 7.48 14.51H6C5.45 14.51 5 14.96 5 15.51V16.01C5 17.67 6.34 19.01 8 19.01H16C17.66 19.01 19 17.67 19 16.01V15.76C19 15.21 18.55 14.76 18 14.76H16C15.59 14.76 15.25 14.42 15.25 14.01C15.25 13.6 15.59 13.26 16 13.26H18C18.55 13.26 19 12.81 19 12.26V11.75C19 11.2 18.55 10.75 18 10.75H16C15.59 10.75 15.25 10.42 15.25 10C15.25 9.58 15.59 9.23999 16 9.23999Z\" fill=\"#292D32\"/>\n<path d=\"M7 13H6C5.45 13 5 12.55 5 12C5 11.45 5.45 11 6 11H7C7.55 11 8 11.45 8 12C8 12.55 7.55 13 7 13Z\" fill=\"#292D32\"/>\n</svg>\n",
|
||||
"vuesax-bulk:receipt-2": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path opacity=\"0.4\" d=\"M20 7.04V16.96C20 18.48 19.86 19.56 19.5 20.33C19.5 20.34 19.49 20.36 19.48 20.37C19.26 20.65 18.97 20.79 18.63 20.79C18.1 20.79 17.46 20.44 16.77 19.7C15.95 18.82 14.69 18.89 13.97 19.85L12.96 21.19C12.56 21.73 12.03 22 11.5 22C10.97 22 10.44 21.73 10.04 21.19L9.02002 19.84C8.31002 18.89 7.05999 18.82 6.23999 19.69L6.22998 19.7C5.09998 20.91 4.10002 21.09 3.52002 20.37C3.51002 20.36 3.5 20.34 3.5 20.33C3.14 19.56 3 18.48 3 16.96V7.04C3 5.52 3.14 4.44 3.5 3.67C3.5 3.66 3.50002 3.65 3.52002 3.64C4.09002 2.91 5.09998 3.09 6.22998 4.3L6.23999 4.31C7.05999 5.18 8.31002 5.11 9.02002 4.16L10.04 2.81C10.44 2.27 10.97 2 11.5 2C12.03 2 12.56 2.27 12.96 2.81L13.97 4.15C14.69 5.11 15.95 5.18 16.77 4.3C17.46 3.56 18.1 3.21 18.63 3.21C18.97 3.21 19.26 3.36 19.48 3.64C19.5 3.65 19.5 3.66 19.5 3.67C19.86 4.44 20 5.52 20 7.04Z\" fill=\"#292D32\"/>\n<path d=\"M16 11H8C7.59 11 7.25 10.66 7.25 10.25C7.25 9.84 7.59 9.5 8 9.5H16C16.41 9.5 16.75 9.84 16.75 10.25C16.75 10.66 16.41 11 16 11Z\" fill=\"#292D32\"/>\n<path d=\"M14 14.5H8C7.59 14.5 7.25 14.16 7.25 13.75C7.25 13.34 7.59 13 8 13H14C14.41 13 14.75 13.34 14.75 13.75C14.75 14.16 14.41 14.5 14 14.5Z\" fill=\"#292D32\"/>\n</svg>\n",
|
||||
"vuesax-bulk:convert-card": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path opacity=\"0.4\" fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M22 14.25C22.4142 14.25 22.75 14.5858 22.75 15C22.75 19.2842 19.2842 22.75 15 22.75C14.7298 22.75 14.4805 22.6047 14.3474 22.3695C14.2142 22.1344 14.2179 21.8458 14.3569 21.6141L15.4069 19.8641C15.62 19.5089 16.0807 19.3938 16.4359 19.6069C16.791 19.82 16.9062 20.2807 16.6931 20.6359L16.4218 21.0881C19.1909 20.4456 21.25 17.9666 21.25 15C21.25 14.5858 21.5858 14.25 22 14.25Z\" fill=\"#292D32\"/>\n<path opacity=\"0.4\" fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M7.57821 2.91194C4.8091 3.55436 2.75 6.03342 2.75 9C2.75 9.41421 2.41421 9.75 2 9.75C1.58579 9.75 1.25 9.41421 1.25 9C1.25 4.71579 4.71579 1.25 9 1.25C9.2702 1.25 9.51952 1.39534 9.65265 1.63047C9.78578 1.8656 9.78214 2.15417 9.64312 2.38587L8.59313 4.13587C8.38002 4.49105 7.91933 4.60623 7.56414 4.39312C7.20896 4.18001 7.09378 3.71932 7.30689 3.36413L7.57821 2.91194Z\" fill=\"#292D32\"/>\n<path opacity=\"0.4\" d=\"M12 15.7V16.31H2V15.7C2 13.94 2.44 13.5 4.22 13.5H9.78C11.56 13.5 12 13.94 12 15.7Z\" fill=\"#292D32\"/>\n<path d=\"M2 16.31V17.81V19.8C2 21.56 2.44 22 4.22 22H9.78C11.56 22 12 21.56 12 19.8V17.81V16.31H2Z\" fill=\"#292D32\"/>\n<path opacity=\"0.4\" d=\"M22 4.2V4.81H12V4.2C12 2.44 12.44 2 14.22 2H19.78C21.56 2 22 2.44 22 4.2Z\" fill=\"#292D32\"/>\n<path d=\"M12 4.81V6.31V8.3C12 10.06 12.44 10.5 14.22 10.5H19.78C21.56 10.5 22 10.06 22 8.3V6.31V4.81H12Z\" fill=\"#292D32\"/>\n</svg>\n",
|
||||
"vuesax-bulk:bag-happy": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\">\n<path opacity=\"0.4\" d=\"M19.24 5.58H18.84L15.46 2.2C15.19 1.93 14.75 1.93 14.47 2.2C14.2 2.47 14.2 2.91 14.47 3.19L16.86 5.58H7.14L9.53 3.19C9.8 2.92 9.8 2.48 9.53 2.2C9.26 1.93 8.82 1.93 8.54 2.2L5.17 5.58H4.77C3.87 5.58 2 5.58 2 8.14C2 9.11 2.2 9.75 2.62 10.17C2.86 10.42 3.15 10.55 3.46 10.62C3.75 10.69 4.06 10.7 4.36 10.7H19.64C19.95 10.7 20.24 10.68 20.52 10.62C21.36 10.42 22 9.82 22 8.14C22 5.58 20.13 5.58 19.24 5.58Z\" fill=\"#292D32\"/>\n<path d=\"M19.65 10.7H4.36002C4.07002 10.7 3.75002 10.69 3.46002 10.61L4.72002 18.3C5.00002 20.02 5.75002 22 9.08002 22H14.69C18.06 22 18.66 20.31 19.02 18.42L20.53 10.61C20.25 10.68 19.95 10.7 19.65 10.7ZM12 18.5C9.66002 18.5 7.75002 16.59 7.75002 14.25C7.75002 13.84 8.09002 13.5 8.50002 13.5C8.91002 13.5 9.25002 13.84 9.25002 14.25C9.25002 15.77 10.48 17 12 17C13.52 17 14.75 15.77 14.75 14.25C14.75 13.84 15.09 13.5 15.5 13.5C15.91 13.5 16.25 13.84 16.25 14.25C16.25 16.59 14.34 18.5 12 18.5Z\" fill=\"#292D32\"/>\n</svg>",
|
||||
"vuesax-bulk:bulk-more":"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\">\n<path opacity=\"0.4\" d=\"M20.0001 5.85001C20.0001 7.20864 18.8987 8.31001 17.5401 8.31001C16.1815 8.31001 15.0801 7.20863 15.0801 5.85001C15.0801 4.49139 16.1815 3.39001 17.5401 3.39001C18.8987 3.39001 20.0001 4.49139 20.0001 5.85001Z\" fill=\"#6B7280\" stroke=\"#6B7280\"/>\n<path d=\"M6.46 8.81001C8.09476 8.81001 9.42 7.48478 9.42 5.85001C9.42 4.21525 8.09476 2.89001 6.46 2.89001C4.82524 2.89001 3.5 4.21525 3.5 5.85001C3.5 7.48478 4.82524 8.81001 6.46 8.81001Z\" fill=\"#6B7280\"/>\n<path d=\"M17.5401 21.11C19.1748 21.11 20.5001 19.7848 20.5001 18.15C20.5001 16.5152 19.1748 15.19 17.5401 15.19C15.9053 15.19 14.5801 16.5152 14.5801 18.15C14.5801 19.7848 15.9053 21.11 17.5401 21.11Z\" fill=\"#6B7280\"/>\n<path opacity=\"0.4\" d=\"M6.46 21.11C8.09476 21.11 9.42 19.7848 9.42 18.15C9.42 16.5152 8.09476 15.19 6.46 15.19C4.82524 15.19 3.5 16.5152 3.5 18.15C3.5 19.7848 4.82524 21.11 6.46 21.11Z\" fill=\"#6B7280\"/>\n</svg>",
|
||||
"vuesax-bulk:people": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M18 7.16C17.94 7.15 17.87 7.15 17.81 7.16C16.43 7.11 15.33 5.98 15.33 4.58C15.33 3.15 16.48 2 17.91 2C19.34 2 20.49 3.16 20.49 4.58C20.48 5.98 19.38 7.11 18 7.16Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M16.9699 14.44C18.3399 14.67 19.8499 14.43 20.9099 13.72C22.3199 12.78 22.3199 11.24 20.9099 10.3C19.8399 9.59004 18.3099 9.35003 16.9399 9.59003\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M5.96998 7.16C6.02998 7.15 6.09998 7.15 6.15998 7.16C7.53998 7.11 8.63998 5.98 8.63998 4.58C8.63998 3.15 7.48998 2 6.05998 2C4.62998 2 3.47998 3.16 3.47998 4.58C3.48998 5.98 4.58998 7.11 5.96998 7.16Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M6.99994 14.44C5.62994 14.67 4.11994 14.43 3.05994 13.72C1.64994 12.78 1.64994 11.24 3.05994 10.3C4.12994 9.59004 5.65994 9.35003 7.02994 9.59003\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M12 14.63C11.94 14.62 11.87 14.62 11.81 14.63C10.43 14.58 9.32996 13.45 9.32996 12.05C9.32996 10.62 10.48 9.46997 11.91 9.46997C13.34 9.46997 14.49 10.63 14.49 12.05C14.48 13.45 13.38 14.59 12 14.63Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M9.08997 17.78C7.67997 18.72 7.67997 20.26 9.08997 21.2C10.69 22.27 13.31 22.27 14.91 21.2C16.32 20.26 16.32 18.72 14.91 17.78C13.32 16.72 10.69 16.72 9.08997 17.78Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n",
|
||||
"vuesax-bulk:user": "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M12 12C14.7614 12 17 9.76142 17 7C17 4.23858 14.7614 2 12 2C9.23858 2 7 4.23858 7 7C7 9.76142 9.23858 12 12 12Z\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n<path d=\"M20.5899 22C20.5899 18.13 16.7399 15 11.9999 15C7.25991 15 3.40991 18.13 3.40991 22\" stroke=\"#292D32\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n</svg>\n"
|
||||
}
|
||||
|
After Width: | Height: | Size: 797 B |
|
After Width: | Height: | Size: 592 B |
|
After Width: | Height: | Size: 579 B |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 728 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 57 KiB |
|
After Width: | Height: | Size: 469 KiB |
|
After Width: | Height: | Size: 753 B |
|
After Width: | Height: | Size: 625 B |
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 882 B |
|
After Width: | Height: | Size: 12 KiB |
|
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="163" height="163" viewBox="0 0 163 163">
|
||||
<image x="8" width="147" height="163" xlink:href="data:img/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJMAAACjCAYAAACOnyy4AAAESklEQVR4nO3dQVIcNwAFUJFi4SU3gBtkbgA5iXOE+AQhJ/AVnFskK8gN8A3wLkuWWYVUV/VUxkrjDPAZST3vVanKjaHc3fPdEpJaKityXUp5HLBcr+Uj+K6Dc2AlhIkYYSLmZOBb+bGUstk5vpjLaO7nsnVXSvkw4HWU0w7O4aWmIF2NeepfGfU/wX+o5ogRJmJGajPVbaTpz2cNz+etPMztpq1h21A9uxm0U/K15WaUD0g1R4wwEdNz10A9ZrWKX59f4GLhXnQ5ntdzA/yxg3PoVZefm2qOGGEippc201nVh8S31cNId3P/FPPNOcY+pFTpYoxSNUeMMBEjTMQIEzHCRIwwESNMxLTqtJz6RS53jo91EHdVPJmIESZihImYVm2maVD3x53jd43OYy0+VgO9v5ZSPh362lqF6UyjO6qecfFHi5NQzREjTMQIEzHCRIwwESNMxAgTMcJEjDARI0zECBMxwkSMMBEjTMQIEzHCRIwwESNMxAgTMSNvxMO/6sVkmywu68lEjDARI0zEtFqcvN6wbzO/SMjL/FRK+bzzk/XumgfRqgHe5GJXbArSbevLU80RI0zECBMxwkSMMBEjTMT0Mjb310JXgfWbnlZ3A3Sxo1MvOypOwXlffa3LrUM7YSdM1k2YiOm5zcRg7B4+Jm0m1k2YiBEmYnoO00lVms/XaeR24V50yZOJGGEiRpiI6bmfqbaZN/DZml5A+H7neKRr2XU3l60/Sym/7xw/VH/frZHe6K1vaBcj5QEPVe///ai/bKjmiBEmYkZeuOLTQnWw2246r3bb7MV03l92zqV+h3At1feqTNvd/12VxwalPoertd5w1RwxwkTMmhf7mtohv1Rfa9EXVc/LMgkQAAAAAI7EdaOxt9eW1SzQYTiFGGEiRpiI6XkS/s0zv7/e9WAUL1lg/4cer80qKGOyCgrrJkzEtJoc977Tyf6jqNuTv80vb259bvHiZqswTQ3ly+pro76R20L9UsLUgH+3c/ylxUmp5ogRJmIOVc1dVY/mS9Va1KbqY7uo7vftIdYvOGSYfj7Qv3WMNntc85uHSTVHjDAR81bVXL0w17mPrKnzqg01zAJiZe5UG3Gi2rGU5w6i70U1R4wwEZNqM9Xd+2dPfB99OFv4zF7ddZDqODT3aHyvzoJqjhhhIkaYiHlpPamNtH7PzoYnEzHCRIwwEbNPp+Vm3kGJ41KP3334v8HhfcK01FvK+j17VEM1R4wwESNMxAgTMcJEjDARs9Q1UL8w6WUAyrzYyDdf7HwqTF6YpLa0as1XYVLNESNMxAgTMcJEjDARI0zECBMxp3Nn1O6qY/XCpbAXTyZihIkYYSLmZJ44bo43r3XryUSMMBEjTMQIEzHCRIwwESNMxAgTMcJEjDARI0zECBMxwkSMMBEjTMScLix6eVHNCYcl93PZWlw89dpOkcoe5boOjmqOGGEiRpjIKKX8A71aXsXRpXaeAAAAAElFTkSuQmCC"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 496 B |
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"primary": "#1D4ED8",
|
||||
"secondary": "#16A34A",
|
||||
"background": "#FFFFFF",
|
||||
"bgm": "#FAFAFA"
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
import BaseDatePicker from './src/BaseDatePicker.vue'
|
||||
export default BaseDatePicker
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
|
||||
<template>
|
||||
<DatePicker v-model:value="localValue" :locale="locale" class="w-full" />
|
||||
<!-- <DatePicker :locale="locale" class="w-full" />-->
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import locale from 'ant-design-vue/es/date-picker/locale/fa_IR'
|
||||
import { DatePicker } from 'ant-design-vue'
|
||||
import { computed } from 'vue'
|
||||
import moment from 'moment-jalaali'
|
||||
//@ts-ignore
|
||||
import fa from 'moment/src/locale/fa'
|
||||
|
||||
moment.locale('fa', fa)
|
||||
moment.loadPersian()
|
||||
// import momentj from 'moment-jalaali'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
interface Prop {
|
||||
value?: string | number | boolean | string[] | number[]
|
||||
}
|
||||
|
||||
const emit = defineEmits(['update:value'])
|
||||
|
||||
const props = withDefaults(defineProps<Prop>(), { allowClear: true, hasTooltip: true })
|
||||
|
||||
const localValue = computed({
|
||||
get() {
|
||||
const dayjsDate = props.value ? dayjs(props.value) : null
|
||||
// console.log('test', dayjsDate)
|
||||
// if (dayjsDate !== null)
|
||||
// console.log('get')
|
||||
return dayjsDate
|
||||
},
|
||||
set(value) {
|
||||
const date = dayjs(value).format('YYYY-MM-DD')
|
||||
// const formatDate = moment.utc(date).format('YYYY-MM-DD')
|
||||
console.log(moment(date, 'jYYYY/jM/jD HH:mm').format('YYYY-M-D'))
|
||||
emit('update:value', moment(date, 'jYYYY/jM/jD HH:mm').format('YYYY-M-D'))
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
import dayjs from 'dayjs'
|
||||
import updateLocale from 'dayjs/plugin/updateLocale'
|
||||
import jalaliday from 'dayjalali'
|
||||
dayjs.extend(jalaliday)
|
||||
dayjs.extend(updateLocale)
|
||||
dayjs.calendar('jalali') // Jalali Calendar
|
||||
const months = [
|
||||
'فروردین',
|
||||
'اردیبهشت',
|
||||
'خرداد',
|
||||
'تیر',
|
||||
'مرداد',
|
||||
'شهریور',
|
||||
'مهر',
|
||||
'آبان',
|
||||
'آذر',
|
||||
'دی',
|
||||
'بهمن',
|
||||
'اسفند',
|
||||
]
|
||||
dayjs.updateLocale('fa', {
|
||||
monthsShort: months,
|
||||
months,
|
||||
})
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
import BaseSwitch from './src/BaseSwitch.vue'
|
||||
export default BaseSwitch
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<template>
|
||||
<ASwitch v-model:checked="checked"></ASwitch>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
value?: boolean
|
||||
}
|
||||
const props = withDefaults(defineProps<Props>(), {})
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:value', val: boolean): void
|
||||
}>()
|
||||
|
||||
const checked = ref<boolean>(false)
|
||||
|
||||
watch(
|
||||
checked,
|
||||
() => {
|
||||
emit('update:value', checked.value)
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
() => {
|
||||
//if (props.value !== undefined)
|
||||
checked.value = props.value
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
</script>
|
||||
|
||||
<style lang="less"></style>
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
import type { ColumnTypeFilter, FilterOP } from '@core/type/baseTable'
|
||||
/*interface FilterOperator {
|
||||
label: string
|
||||
value: FilterOP
|
||||
// showIn: ColumnTypeFilter[]
|
||||
}*/
|
||||
|
||||
//type ColumnTypeFilter = 'Date' | 'Time' | 'DateTime' | 'Select' | 'Text' | 'Boolean' | 'Number'
|
||||
/*export const filterOperatorList: FilterOperator[] = [
|
||||
{
|
||||
value: 'eq',
|
||||
label: 'برابر'
|
||||
// showIn: ['Date', 'Time', 'DateTime', 'Select', 'Text', 'Boolean', 'Number']
|
||||
},
|
||||
{
|
||||
value: 'not',
|
||||
label: 'نابرابر'
|
||||
},
|
||||
{
|
||||
value: 'gt',
|
||||
label: 'بزرگتر'
|
||||
},
|
||||
{
|
||||
value: 'lt',
|
||||
label: 'کوچکتر'
|
||||
},
|
||||
{
|
||||
value: 'gte',
|
||||
label: 'بزرگتر مساوی'
|
||||
},
|
||||
{
|
||||
value: 'lte',
|
||||
label: 'کوچکتر مساوی'
|
||||
},
|
||||
{
|
||||
value: 'sw',
|
||||
label: 'شروع با'
|
||||
},
|
||||
{
|
||||
value: 'ew',
|
||||
label: 'خاتمه با'
|
||||
},
|
||||
{
|
||||
value: 'has',
|
||||
label: 'شامل'
|
||||
},
|
||||
/!*{
|
||||
value: 'bet',
|
||||
label: 'بین'
|
||||
},*!/
|
||||
{
|
||||
value: 'null',
|
||||
label: 'تهی'
|
||||
},
|
||||
{
|
||||
value: 'nn',
|
||||
label: 'تهی نباشد'
|
||||
},
|
||||
{
|
||||
value: 'in',
|
||||
label: 'شامل در'
|
||||
}
|
||||
]*/
|
||||
|
||||
export const MapFilterOpToFaString: Record<FilterOP, string> = {
|
||||
sw: 'شروع با',
|
||||
bet: '',
|
||||
gte: 'بزرگتر مساوی',
|
||||
has: 'شامل',
|
||||
lte: 'کوچکتر مساوی',
|
||||
not: 'نابرابر',
|
||||
eq: 'برابر',
|
||||
ew: 'خاتمه با',
|
||||
null: 'تهی',
|
||||
lt: 'کوچکتر',
|
||||
in: 'شامل در',
|
||||
gt: 'بزرگتر',
|
||||
nn: 'تهی نباشد'
|
||||
}
|
||||
|
||||
export const availableFilterType: Record<ColumnTypeFilter, FilterOP[]> = {
|
||||
Text: ['eq', 'sw', 'ew', 'has', 'in', 'nn', 'not', 'null'],
|
||||
Number: ['eq', 'gt', 'lt', 'gte', 'lte', 'not', 'nn', 'in', 'null'],
|
||||
Boolean: ['eq', 'not', 'nn', 'null', 'in'],
|
||||
Date: ['eq', 'gt', 'lt', 'gte', 'lte', 'sw', 'ew', 'has', 'not', 'null', 'in', 'nn'],
|
||||
Time: ['eq', 'gt', 'lt', 'gte', 'lte', 'sw', 'ew', 'has', 'not', 'null', 'in', 'nn'],
|
||||
DateTime: ['eq', 'gt', 'lt', 'gte', 'lte', 'sw', 'ew', 'has', 'not', 'null', 'in', 'nn'],
|
||||
Select: ['eq', 'gt', 'lt', 'gte', 'lte', 'sw', 'ew', 'nn', 'not', 'null', 'has', 'in']
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import type { BaseTableEmit } from '@core/type/baseTable'
|
||||
|
||||
function useBaseTable() {
|
||||
let reload = (): any => {
|
||||
throw 'base table not register reload function'
|
||||
}
|
||||
const runReload = () => {
|
||||
reload()
|
||||
}
|
||||
const register = (data?: BaseTableEmit) => {
|
||||
if (data && data.reload) {
|
||||
reload = data.reload
|
||||
}
|
||||
}
|
||||
return [register, runReload]
|
||||
}
|
||||
|
||||
export default useBaseTable
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
import BaseTable from './src/BaseTable.vue'
|
||||
export default BaseTable
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
import type { VNode, Component } from 'vue'
|
||||
interface BaseTableColumn {
|
||||
title?: string //pass
|
||||
name?: string //pass
|
||||
dataIndex: string // pass
|
||||
key: string //pass
|
||||
slot?: string //pass
|
||||
//customRenderer?:
|
||||
width?: number // pass
|
||||
type?: ColumnTypeFilter
|
||||
filterable?: boolean
|
||||
sortable?: boolean
|
||||
draggable?: boolean
|
||||
show?: boolean //pass
|
||||
fixed?: boolean | string //string is (left/right) //pass
|
||||
align?: 'center' | 'right' | 'left' //pass
|
||||
ellipsis?: boolean
|
||||
children?: BaseTableColumn[]
|
||||
resizable?: boolean //pass - no support for rtl on resize
|
||||
responsive?: string[]
|
||||
customRender?: (data: { text: string; record: any; index: number }) => VNode | string //pass
|
||||
customCell?: (record: any, rowIndex: number, column: any) => void
|
||||
className?: string
|
||||
filterComponentProps?: any
|
||||
filterComponent?: Component | VNode
|
||||
filterField?: string
|
||||
sortField?: string
|
||||
}
|
||||
|
||||
//boolean switch - boolean checkbox
|
||||
//for client
|
||||
type ColumnTypeFilter = 'Date' | 'Time' | 'DateTime' | 'Select' | 'Text' | 'Boolean' | 'Number'
|
||||
|
||||
//for server
|
||||
type FilterType = 'number' | 'date' | 'text' | 'select' | 'switch'
|
||||
|
||||
export const mapColumnTypeFilterToFilterType: Record<ColumnTypeFilter, FilterType> = {
|
||||
Date: 'date',
|
||||
Time: 'date',
|
||||
DateTime: 'date',
|
||||
Select: 'select',
|
||||
Text: 'text',
|
||||
Boolean: 'switch',
|
||||
Number: 'number'
|
||||
}
|
||||
|
||||
interface TableInput {
|
||||
limit?: number //number of record that return
|
||||
filters?: Filter[]
|
||||
filtersOpt?: any
|
||||
key?: any
|
||||
order?: string
|
||||
search?: string | null
|
||||
select?: string[]
|
||||
sort?: TableSort | null
|
||||
page?: number //current page
|
||||
titles?: Record<string, string>
|
||||
report_title?: string
|
||||
total?: number
|
||||
}
|
||||
|
||||
interface TableInputMongo {
|
||||
f: any[]
|
||||
o: {}
|
||||
p: {
|
||||
s: number
|
||||
c: number
|
||||
}
|
||||
s: {}
|
||||
}
|
||||
|
||||
interface TableSort {
|
||||
key: string
|
||||
order: 'asc' | 'desc'
|
||||
}
|
||||
|
||||
interface Filter {
|
||||
cr: 'and' | 'or'
|
||||
index?: number
|
||||
field: string
|
||||
type: FilterType
|
||||
op: FilterOP | null
|
||||
value: any
|
||||
hidden?: boolean
|
||||
}
|
||||
|
||||
type FilterOP =
|
||||
| 'gt' //>
|
||||
| 'lt' //<
|
||||
| 'eq' //=
|
||||
| 'gte' //>=
|
||||
| 'lte' //<=
|
||||
| 'bet' //between
|
||||
| 'not' //<>
|
||||
| 'nn' // not null
|
||||
| 'null' // null
|
||||
| 'sw' //'like', $this->value . '%'
|
||||
| 'ew' //'like', '%' . $this->value
|
||||
| 'has' // 'like', '%' . $this->value . '%'
|
||||
| 'in' // in array
|
||||
|
||||
//const available
|
||||
//const availableFilterType = {}
|
||||
|
||||
interface TableOutput<T> {
|
||||
rows: T[]
|
||||
query: TableInput
|
||||
}
|
||||
|
||||
interface TableOutputMongo<T> {
|
||||
rows: T[]
|
||||
total: number
|
||||
page: number
|
||||
te: TableInputMongo
|
||||
}
|
||||
|
||||
interface BaseTableEmit {
|
||||
reload: () => void
|
||||
}
|
||||
|
||||
export type {
|
||||
BaseTableColumn,
|
||||
TableInput,
|
||||
TableOutput,
|
||||
BaseTableEmit,
|
||||
Filter,
|
||||
FilterType,
|
||||
FilterOP,
|
||||
ColumnTypeFilter,
|
||||
TableSort,
|
||||
TableInputMongo,
|
||||
TableOutputMongo
|
||||
//availableFilterType
|
||||
}
|
||||
|
|
@ -0,0 +1,740 @@
|
|||
<template>
|
||||
<div :class="[prefixCls]">
|
||||
<ASpin tip="در حال دریافت اطلاعات..." :indicator="indicator" :spinning="loading">
|
||||
<!-- <div ref="skeletonWidth" class="w-full"></div>-->
|
||||
<!-- <transition>-->
|
||||
<!-- TODO Check -->
|
||||
<!-- relative h-full-->
|
||||
<div class="scrollable-container" id="components-affix-demo-target" ref="containerRef">
|
||||
<!--- TODO remove AFFix -->
|
||||
<AAffix :target="() => containerRef">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="flex items-center gap-1">
|
||||
<!-- <AInputSearch placeholder="جستجو" enter-button />-->
|
||||
<AInput
|
||||
@keyup.enter="handleSearchText"
|
||||
placeholder="جستجو"
|
||||
class="pl-0"
|
||||
size="small"
|
||||
v-model:value="searchText"
|
||||
>
|
||||
<template #suffix>
|
||||
<BasicButton
|
||||
type="text"
|
||||
icon="vuesax-linear:search-normal-1"
|
||||
icon-size="15"
|
||||
class="text-gray cursor-pointer"
|
||||
@click="handleSearchText"
|
||||
/>
|
||||
</template>
|
||||
</AInput>
|
||||
<div class="flex gap-1 items-center">
|
||||
<BasicButton
|
||||
type="text"
|
||||
class="text-gray-500"
|
||||
suffixIcon
|
||||
size="small"
|
||||
icon="vuesax-linear:refresh"
|
||||
iconSize="17"
|
||||
@click="reload"
|
||||
>
|
||||
</BasicButton>
|
||||
<ABadge :count="activeFilterCount">
|
||||
<BasicButton
|
||||
type="text"
|
||||
class="text-gray-500 p-0"
|
||||
suffixIcon
|
||||
size="small"
|
||||
icon="vuesax-linear:filter"
|
||||
iconSize="17"
|
||||
@click="showFilterModal = true"
|
||||
>
|
||||
فیلتر
|
||||
</BasicButton>
|
||||
</ABadge>
|
||||
<!-- <BasicButton
|
||||
type="text"
|
||||
class="text-gray-500"
|
||||
suffixIcon
|
||||
size="small"
|
||||
icon="vuesax-linear:setting-2"
|
||||
iconSize="17"
|
||||
>
|
||||
</BasicButton>
|
||||
<BasicButton
|
||||
type="text"
|
||||
class="text-gray-500"
|
||||
suffixIcon
|
||||
size="small"
|
||||
icon="vuesax-linear:printer"
|
||||
iconSize="17"
|
||||
>
|
||||
</BasicButton>
|
||||
<BasicButton
|
||||
type="text"
|
||||
class="text-gray-500"
|
||||
suffixIcon
|
||||
size="small"
|
||||
icon="vuesax-linear:direct-inbox"
|
||||
iconSize="17"
|
||||
>
|
||||
</BasicButton>-->
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<slot name="extraHeader" />
|
||||
</div>
|
||||
</div>
|
||||
</AAffix>
|
||||
<ATable
|
||||
:columns="_columns"
|
||||
:data-source="data"
|
||||
v-bind="_props"
|
||||
:pagination="false"
|
||||
:scroll="{ y: '62.7vh' }"
|
||||
@resizeColumn="handleResizeColumn"
|
||||
>
|
||||
<template #bodyCell="{ ...data }">
|
||||
<template v-for="item in slotColumns">
|
||||
<template v-if="data.column.key === item.key">
|
||||
<slot :name="item.slot" v-bind="data"></slot>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
<!-- <template #loading> sdfsdfsdfsd </template>-->
|
||||
</ATable>
|
||||
<!-- absolute bottom-0 w-full-->
|
||||
<!-- absolute bottom-0-->
|
||||
<div class="flex items-center justify-between mt-5 w-full">
|
||||
<span> {{ totalRecord }} مورد یافت شد </span>
|
||||
<div class="flex items-center gap-2 justify-between">
|
||||
<APagination
|
||||
:pageSize="tableInput?.limit"
|
||||
:current="tableInput?.page"
|
||||
:total="totalRecord"
|
||||
show-less-items
|
||||
:show-size-changer="false"
|
||||
@change="handleChangePage"
|
||||
/>
|
||||
<ASelect
|
||||
:options="pageSizeOptions"
|
||||
:value="tableInput?.limit"
|
||||
@change="handleChangePageSize"
|
||||
></ASelect>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ASpin>
|
||||
<!-- <div v-else>
|
||||
<ContentLoader
|
||||
:width="skeletonWidthSize.width"
|
||||
height="500"
|
||||
:viewBox="`0 0 ${skeletonWidthSize.width} 500`"
|
||||
backgroundColor="#f5f5f5"
|
||||
foregroundColor="#dbdbdb"
|
||||
>
|
||||
<!– top –>
|
||||
<rect x="5" y="0" rx="3" ry="3" width="130" height="32" />
|
||||
<circle :cx="skeletonWidthSize.width - 495" cy="15" r="15" />
|
||||
<circle :cx="skeletonWidthSize.width - 445" cy="15" r="15" />
|
||||
<circle :cx="skeletonWidthSize.width - 395" cy="15" r="15" />
|
||||
<rect :x="skeletonWidthSize.width - 345" y="0" rx="3" ry="3" width="64" height="32" />
|
||||
<circle :cx="skeletonWidthSize.width - 235" cy="15" r="15" />
|
||||
<rect :x="skeletonWidthSize.width - 205" y="0" rx="3" ry="3" width="205" height="32" />
|
||||
|
||||
|
||||
|
||||
<!– framework –>
|
||||
<!– <rect x="5" y="39" rx="3" ry="3" :width="skeletonWidthSize.width - 5" height="5" />–>
|
||||
<!– <rect x="5" y="39" rx="3" ry="3" width="5" :height="skeletonHeight" /><!––>–>
|
||||
<!– <rect
|
||||
:x="skeletonWidthSize.width - 5"
|
||||
y="39"
|
||||
rx="3"
|
||||
ry="3"
|
||||
width="5"
|
||||
:height="skeletonHeight"
|
||||
/>–>
|
||||
<!– <rect
|
||||
x="5"
|
||||
:y="skeletonHeight + 39"
|
||||
rx="3"
|
||||
ry="3"
|
||||
:width="skeletonWidthSize.width - 5"
|
||||
height="5"
|
||||
/>–>
|
||||
<!– items –>
|
||||
<rect x="5" :y="50" rx="3" ry="3" :width="skeletonWidthSize.width - 5" height="60" />
|
||||
<rect x="5" :y="120" rx="3" ry="3" :width="skeletonWidthSize.width - 5" height="60" />
|
||||
<rect x="5" :y="190" rx="3" ry="3" :width="skeletonWidthSize.width - 5" height="60" />
|
||||
<rect x="5" :y="260" rx="3" ry="3" :width="skeletonWidthSize.width - 5" height="60" />
|
||||
<rect x="5" :y="330" rx="3" ry="3" :width="skeletonWidthSize.width - 5" height="60" />
|
||||
<!– bottom –>
|
||||
<rect x="5" :y="skeletonHeight + 60" rx="3" ry="3" :width="60" height="31" />
|
||||
<circle :cx="90" :cy="skeletonHeight + 75" r="15" />
|
||||
<circle :cx="125" :cy="skeletonHeight + 75" r="15" />
|
||||
<circle :cx="160" :cy="skeletonHeight + 75" r="15" />
|
||||
<rect
|
||||
:x="skeletonWidthSize.width - 200"
|
||||
:y="420"
|
||||
rx="3"
|
||||
ry="3"
|
||||
:width="skeletonWidthSize.width - 25"
|
||||
height="31"
|
||||
/>
|
||||
</ContentLoader>
|
||||
</div>-->
|
||||
<!-- </transition>-->
|
||||
<BasicModal
|
||||
@close="handleCancelFilter"
|
||||
v-model:visible="showFilterModal"
|
||||
title="فیلتر"
|
||||
width="60%"
|
||||
@ok="applyFilter"
|
||||
:wrapClassName="`${prefixCls}-filter-modal`"
|
||||
>
|
||||
<div>
|
||||
<div class="flex items-center gap-2">
|
||||
<ASelect placeholder="مرتب سازی"
|
||||
class="flex-1"
|
||||
:options="sortableColumns"
|
||||
v-model:value="orderColumnKey"
|
||||
allow-clear
|
||||
></ASelect>
|
||||
<BaseButton
|
||||
@click="toggleOrder"
|
||||
type="text"
|
||||
class="text-gray-500"
|
||||
suffixIcon
|
||||
:iconClass="`${order === 'asc' ? 'rotate-180' : ''}`"
|
||||
size="small"
|
||||
icon="vuesax-linear:sort"
|
||||
iconSize="17"
|
||||
>
|
||||
</BaseButton>
|
||||
</div>
|
||||
<ADivider class="!my-2" />
|
||||
<!-- {{ filterColumns }}-->
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex items-center gap-2" v-for="(item, index) in filters" :key="index">
|
||||
<div class="flex-1 flex gap-1">
|
||||
<ASelect
|
||||
v-model:value="filters[index].cr"
|
||||
class="!w-14"
|
||||
v-if="index != 0"
|
||||
:options="[
|
||||
{ label: 'و ', value: 'and' },
|
||||
{ label: 'یا ', value: 'or' }
|
||||
]"
|
||||
/>
|
||||
<!-- <span v-else-if="filters.length > 1" class="w-15"></span>-->
|
||||
|
||||
<!-- <div class="grid grid-cols-1">
|
||||
|
||||
</div>-->
|
||||
<ASelect placeholder="انتخاب کنید"
|
||||
@change="handleChangeFilterColumn(filters[index].field, index)"
|
||||
:options="filterColumns"
|
||||
class="flex-1"
|
||||
v-model:value="filters[index].field"
|
||||
/>
|
||||
<!-- @change="handleChangeFilterColumn(filters[index].field)"-->
|
||||
<!-- @change="handleChangeFilterColumn(filters[index].field)"-->
|
||||
<!-- filterOperatorList-->
|
||||
</div>
|
||||
<!-- <ASelect
|
||||
:options="getFilterOp(filters[index].field)"
|
||||
class="flex-1"
|
||||
v-model:value="filters[index].op"
|
||||
/>-->
|
||||
<div class="flex-1">
|
||||
<!-- 11111-->
|
||||
<!-- {{ filters[index] }}-->
|
||||
<Component placeholder="مقدار را وارد کنید"
|
||||
v-bind="getComponentProps(filters[index].field)"
|
||||
:is="getComponentFilter(filters[index].field)"
|
||||
class="flex-1"
|
||||
v-model:value="filters[index].value"
|
||||
/>
|
||||
<!-- v-model:checked="filters[index].value"-->
|
||||
</div>
|
||||
<!-- {{ filters[index].field }}-->
|
||||
<BasicButton
|
||||
icon="vuesax-linear:trash"
|
||||
iconSize="18"
|
||||
iconClass="text-red"
|
||||
@click="handleDeleteFilter(index)"
|
||||
type="text"
|
||||
></BasicButton>
|
||||
</div>
|
||||
</div>
|
||||
<BasicButton icon="vuesax-linear:add" type="text" @click="handleAddFilter" class="mt-3">
|
||||
افزودن فیلتر
|
||||
</BasicButton>
|
||||
</div>
|
||||
</BasicModal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="tsx" setup>
|
||||
|
||||
import type {
|
||||
BaseTableColumn,
|
||||
BaseTableEmit,
|
||||
Filter,
|
||||
TableInput,
|
||||
TableInputMongo,
|
||||
TableOutput,
|
||||
TableOutputMongo
|
||||
} from '../model/baseTable'
|
||||
import { Input, Select } from 'ant-design-vue'
|
||||
import BasicModal from '@/components/BasicPacks/BasicModal.vue'
|
||||
import { LoadingOutlined } from '@ant-design/icons-vue'
|
||||
//import { filterOperatorList } from '../hooks/filterOperator'
|
||||
import { computed, ref } from 'vue'
|
||||
import { mapColumnTypeFilterToFilterType } from '../model/baseTable'
|
||||
import {
|
||||
availableFilterType
|
||||
//MapFilterOpToFaString
|
||||
} from '../hooks/filterOperator'
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import { usePrefix } from '@/composable/usePrefix'
|
||||
import BaseDatePicker from '@/components/BasicPacks/BaseDatePicker'
|
||||
import BaseSwitch from '@/components/BasicPacks/BaseSwitch'
|
||||
import {cloneDeep,get,omit} from 'lodash'
|
||||
//import { mapColumnTypeFilterToFilterType } from '@core/type/baseTable'
|
||||
//import { useElementSize } from '@vueuse/core'
|
||||
//import { ContentLoader } from 'vue-content-loader'
|
||||
//skeleton
|
||||
//const skeletonWidth = ref(null)
|
||||
/*const skeletonWidthSize = reactive(
|
||||
useElementSize(skeletonWidth, { width: 0, height: 0 }, { box: 'border-box' })
|
||||
)*/
|
||||
//const skeletonHeight = 357
|
||||
/*const skeletonHeight = ref(null)
|
||||
const skeletonHeightSize = reactive(
|
||||
useElementSize(skeletonHeight, { width: 0, height: 0 }, { box: 'border-box' })
|
||||
)*/
|
||||
/*
|
||||
watch(skeletonHeightSize, (v) => {
|
||||
console.log('ttt', v)
|
||||
})
|
||||
*/
|
||||
|
||||
interface Props {
|
||||
bordered?: boolean
|
||||
driver?: 'laravel-sql' | 'mongodb'
|
||||
mode?: 'simple' | 'pro'
|
||||
columns?: BaseTableColumn[]
|
||||
defaultPageLimit?: number
|
||||
scroll?: { x: true | string | number; y?: string | number }
|
||||
api?: (params?: TableInput | TableInputMongo) => Promise<TableOutput<any> | TableOutputMongo<any>>
|
||||
pageSize?: number[]
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
bordered: false,
|
||||
driver: 'laravel-sql',
|
||||
mode: 'pro',
|
||||
columns: () => [],
|
||||
scroll: () => ({ x: true }), //y: '100%' //y: 600
|
||||
pageSize: () => [5, 10, 20, 50, 100],
|
||||
defaultPageLimit: 10
|
||||
})
|
||||
|
||||
const tableInput = ref<TableInput>({ page: 1, limit: props.defaultPageLimit, select: [] })
|
||||
const tableOutput = ref<TableOutput<any> | TableOutputMongo<any> | null>(null)
|
||||
const { prefixCls } = usePrefix('base-table')
|
||||
const searchText = ref<string | null>('')
|
||||
const showFilterModal = ref<boolean>(false)
|
||||
const filters = ref<Filter[]>([])
|
||||
const order = ref<'asc' | 'desc'>('asc')
|
||||
const orderColumnKey = ref<string | null>(null)
|
||||
const containerRef = ref()
|
||||
//const route = useRoute()
|
||||
const loading = ref<boolean>(false)
|
||||
const _props = computed(() => {
|
||||
return omit(props, ['columns', 'pagination', 'dataSource'])
|
||||
})
|
||||
const emit = defineEmits<{
|
||||
(e: 'register', data: BaseTableEmit): void
|
||||
}>()
|
||||
|
||||
const mapComponent = {
|
||||
Text: Input,
|
||||
Date: BaseDatePicker,
|
||||
Time: BaseDatePicker,
|
||||
DateTime: BaseDatePicker,
|
||||
Select: Select,
|
||||
Boolean: BaseSwitch, //Switch,
|
||||
Number: Input
|
||||
}
|
||||
|
||||
const indicator = h(LoadingOutlined, {
|
||||
style: {
|
||||
fontSize: '24px'
|
||||
},
|
||||
spin: true
|
||||
})
|
||||
|
||||
const transformTableInput = computed(() => {
|
||||
if (props.driver == 'mongodb') {
|
||||
const data: TableInputMongo = {
|
||||
f: [],
|
||||
s: {},
|
||||
p: { c: tableInput.value.page as number, s: tableInput.value.limit as number },
|
||||
o: {}
|
||||
}
|
||||
return { te: data }
|
||||
//Object
|
||||
}
|
||||
return tableInput.value
|
||||
})
|
||||
|
||||
function getComponentProps(columnDataIndex: string) {
|
||||
const column = _columns.value.find((column) => {
|
||||
return column.dataIndex == columnDataIndex || column.filterField == columnDataIndex
|
||||
})
|
||||
if (column && column.filterComponentProps) return column.filterComponentProps
|
||||
return {}
|
||||
}
|
||||
|
||||
/*watch(showFilterModal, () => {
|
||||
console.log('change filter modal show')
|
||||
})*/
|
||||
|
||||
function toggleOrder() {
|
||||
if (order.value == 'asc') order.value = 'desc'
|
||||
else order.value = 'asc'
|
||||
}
|
||||
|
||||
function findColumn(columnDataIndex: string): BaseTableColumn | undefined {
|
||||
const cols = get(props, 'columns', [])
|
||||
return cols.find((column) => {
|
||||
return column.dataIndex == columnDataIndex || column.filterField == columnDataIndex
|
||||
})
|
||||
}
|
||||
|
||||
function getComponentFilter(columnDataIndex: string) {
|
||||
// console.log('ttt', columnDataIndex)
|
||||
const column = findColumn(columnDataIndex)
|
||||
//console.log('col', column)
|
||||
if (column) {
|
||||
if (Object.hasOwn(column, 'filterComponent')) {
|
||||
//@ts-ignore
|
||||
return markRaw(toRaw(column.filterComponent))
|
||||
}
|
||||
if (column.type && Object.hasOwn(mapComponent, column.type)) {
|
||||
//console.log('aaa', column.type)
|
||||
return mapComponent[column.type]
|
||||
}
|
||||
}
|
||||
return Input
|
||||
}
|
||||
|
||||
//column: Partial<BaseTableColumn>, filter: Filter
|
||||
function handleChangeFilterColumn(columnDataIndex: string, index: number) {
|
||||
// console.log(filters.value[index])
|
||||
filters.value[index].value = ''
|
||||
const column = findColumn(columnDataIndex)
|
||||
//console.log('col', column)
|
||||
if (column) {
|
||||
//console.log()
|
||||
filters.value[index].type = mapColumnTypeFilterToFilterType[column?.type ?? 'Text']
|
||||
filters.value[index].op = get(availableFilterType[column?.type ?? 'Text'], '[0]', null)
|
||||
filters.value[index].op = 'has'
|
||||
//filter.type = mapColumnTypeFilterToFilterType[column?.type ?? 'Text']
|
||||
}
|
||||
//console.log('aaa', a, b, c)
|
||||
//return
|
||||
//filter.type = mapColumnTypeFilterToFilterType[column?.type ?? 'Text']
|
||||
//console.log('ffff', filter.type, column)
|
||||
//console.log(a, b, c, d)
|
||||
}
|
||||
|
||||
async function applyFilter() {
|
||||
filters.value = filters.value.filter((item) => {
|
||||
return item.field != ''
|
||||
})
|
||||
tableInput.value.filters = cloneDeep(filters.value)
|
||||
pageReset()
|
||||
showFilterModal.value = false
|
||||
await callApi()
|
||||
}
|
||||
|
||||
const activeFilterCount = computed(() => {
|
||||
return tableInput.value?.filters?.length ?? 0
|
||||
})
|
||||
|
||||
function handleCancelFilter() {
|
||||
filters.value = cloneDeep(tableInput.value.filters ?? [])
|
||||
showFilterModal.value = false
|
||||
orderColumnKey.value = null
|
||||
|
||||
}
|
||||
|
||||
const pageSizeOptions = computed(() => {
|
||||
return props.pageSize.map((item) => {
|
||||
return { label: `${item} ردیف`, value: item }
|
||||
})
|
||||
})
|
||||
|
||||
const _columns = computed(() => {
|
||||
const cols = cloneDeep(get(props, 'columns', [])).filter((column) => {
|
||||
return (
|
||||
(Object.hasOwn(column, 'show') && column.show == true) || !Object.hasOwn(column, 'show')
|
||||
//&& !Object.hasOwn(column, 'slot')
|
||||
)
|
||||
})
|
||||
cols.forEach((column) => {
|
||||
if (!Object.hasOwn(column, 'align')) {
|
||||
column.align = 'center'
|
||||
}
|
||||
//@ts-ignore
|
||||
column.dataIndex = column.dataIndex.split('.')
|
||||
//if(isArray(column.dataIndex))
|
||||
/*if(!isArray(column.dataIndex)){
|
||||
}*/
|
||||
//column.dataIndex = column.dataIndex.split('.')
|
||||
/*if(){
|
||||
column.dataIndex=
|
||||
}*/
|
||||
})
|
||||
return cols
|
||||
})
|
||||
|
||||
const filterColumns = computed(() => {
|
||||
const cols = get(props, 'columns', [])
|
||||
.filter((column) => {
|
||||
return !Object.hasOwn(column, 'filterable') || column.filterable
|
||||
})
|
||||
.map((column) => {
|
||||
return {
|
||||
type: column.type,
|
||||
label: column.title,
|
||||
value: get(column, 'filterField', column.dataIndex)
|
||||
} //type: column.type ?? 'Text'
|
||||
})
|
||||
//console.log('cols', cols)
|
||||
return cols
|
||||
})
|
||||
|
||||
const sortableColumns = computed(() => {
|
||||
const cols = get(props, 'columns', [])
|
||||
.filter((column) => {
|
||||
return !Object.hasOwn(column, 'sortable') || column.sortable
|
||||
})
|
||||
.map((column) => {
|
||||
return {
|
||||
//type: column.type,
|
||||
label: column.title,
|
||||
value: get(column, 'sortField', get(column, 'filterField', column.dataIndex))
|
||||
} //type: column.type ?? 'Text'
|
||||
})
|
||||
//console.log('cols', cols)
|
||||
return cols
|
||||
})
|
||||
|
||||
/*
|
||||
const filterOperators = computed(() => {
|
||||
//return filterOperatorList
|
||||
return
|
||||
})
|
||||
*/
|
||||
|
||||
async function handleSearchText() {
|
||||
tableInput.value.search = searchText.value
|
||||
pageReset()
|
||||
await callApi()
|
||||
}
|
||||
|
||||
function handleDeleteFilter(index: number) {
|
||||
filters.value.splice(index, 1)
|
||||
}
|
||||
|
||||
function handleAddFilter() {
|
||||
filters.value.push({
|
||||
field: null,
|
||||
type: 'text',
|
||||
value: '',
|
||||
cr: 'and',
|
||||
op: null,
|
||||
hidden: false
|
||||
})
|
||||
//console.log('sadsadasd', filters.value)
|
||||
}
|
||||
|
||||
const data = computed(() => {
|
||||
if (tableOutput.value != null) {
|
||||
const temp = get(tableOutput.value, 'rows', [])
|
||||
/* temp.push(...temp)
|
||||
temp.push(...temp)
|
||||
temp.push(...temp)
|
||||
temp.push(...temp)*/
|
||||
return temp //get(tableOutput.value, 'rows', [])
|
||||
}
|
||||
return []
|
||||
})
|
||||
|
||||
/*function getFilterOp(columnDataIndex: string) {
|
||||
// console.log('aaa', columnDataIndex)
|
||||
// console.log('find', findColumn(columnDataIndex))
|
||||
const column = findColumn(columnDataIndex)
|
||||
if (column) {
|
||||
if (Object.hasOwn(availableFilterType, column.type ?? 'Text')) {
|
||||
const temp = availableFilterType[column.type ?? 'Text']
|
||||
// console.log('teeee', temp)
|
||||
return temp.map((item) => ({
|
||||
label: MapFilterOpToFaString[item],
|
||||
value: item
|
||||
}))
|
||||
}
|
||||
return []
|
||||
//return availableFilterType.console.log('column: ', column)
|
||||
}
|
||||
return []
|
||||
}*/
|
||||
|
||||
const totalRecord = computed(() => {
|
||||
/* if (props.driver === 'mongodb') {
|
||||
return get(tableInput.value, 'total', 0)
|
||||
}*/
|
||||
return get(tableInput.value, 'total', 0)
|
||||
})
|
||||
|
||||
console.log(totalRecord.value,'aaaa')
|
||||
|
||||
const slotColumns = computed(() => {
|
||||
return _columns.value.filter((column) => Object.hasOwn(column, 'slot'))
|
||||
})
|
||||
|
||||
function handleResizeColumn(w: number, col: any) {
|
||||
col.width = w
|
||||
}
|
||||
|
||||
async function handleChangePageSize(value: number, option: any) {
|
||||
if (tableInput.value) {
|
||||
tableInput.value.limit = value
|
||||
}
|
||||
await reload()
|
||||
}
|
||||
|
||||
function pageReset() {
|
||||
tableInput.value.page = 1
|
||||
}
|
||||
|
||||
async function handleChangePage(page: number, pageSize: number) {
|
||||
tableInput.value.page = page
|
||||
await callApi()
|
||||
}
|
||||
|
||||
async function reload() {
|
||||
await callApi()
|
||||
}
|
||||
|
||||
async function callApi() {
|
||||
const api = get(_props.value, 'api', null)
|
||||
if (api != null) {
|
||||
try {
|
||||
loading.value = true
|
||||
if (orderColumnKey.value != null) {
|
||||
tableInput.value.sort = { key: orderColumnKey.value, order: order.value }
|
||||
if (order.value == 'asc') {
|
||||
tableInput.value.order = `+${orderColumnKey.value}`
|
||||
} else {
|
||||
tableInput.value.order = `-${orderColumnKey.value}`
|
||||
}
|
||||
} else {
|
||||
delete tableInput.value.order
|
||||
delete tableInput.value.sort
|
||||
}
|
||||
const data = await api(cloneDeep(transformTableInput.value)) //tableInput.value
|
||||
transformTableOutput(data)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function transformTableOutput(output: TableOutput<any> | TableOutputMongo<any>) {
|
||||
console.log('1111', data)
|
||||
if (props.driver === 'mongodb') {
|
||||
tableOutput.value = output.data
|
||||
tableInput.value = {
|
||||
page: output.data.page,
|
||||
limit: get(output.data, 'te.p.s', 10),
|
||||
total: output.data.total
|
||||
}
|
||||
//TODO for set query
|
||||
//tableInput.value = output.query
|
||||
//TODO for set search text
|
||||
//searchText.value = output.query.search ?? ''
|
||||
//TODO for ser filters
|
||||
//filters.value=''
|
||||
//TODO for set order columns
|
||||
} else {
|
||||
tableInput.value = output.query
|
||||
tableOutput.value = output
|
||||
searchText.value = output.query.search ?? ''
|
||||
filters.value = cloneDeep(output?.output?.filters ?? []).filter((item) => {
|
||||
return Object.hasOwn(item, 'hidden') && item.hidden == false
|
||||
})
|
||||
if (output.query.order != undefined) {
|
||||
if (output.query.order?.startsWith('+') || output.query.order?.startsWith('-')) {
|
||||
orderColumnKey.value = output.query.order?.slice(1)
|
||||
} else {
|
||||
orderColumnKey.value = output.query.order
|
||||
}
|
||||
if (output.query.order?.startsWith('-')) {
|
||||
order.value = 'desc'
|
||||
} else {
|
||||
order.value = 'asc'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await callApi()
|
||||
emit('register', { reload })
|
||||
//console.log('router', route.query)
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
loading
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@prefix: ~'@{prefixCls}-base-table';
|
||||
|
||||
.@{prefix} {
|
||||
@apply h-full;
|
||||
|
||||
.ant-table-wrapper {
|
||||
border: 1px solid #eee;
|
||||
border-radius: var(--border-radius-base);
|
||||
}
|
||||
|
||||
.ant-spin-container,
|
||||
.ant-spin-nested-loading {
|
||||
height: 100%;
|
||||
@apply relative;
|
||||
}
|
||||
|
||||
.ant-badge-count {
|
||||
background-color: @primary-color;
|
||||
}
|
||||
|
||||
&-filter-modal {
|
||||
.ant-select {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
:where(.css-dev-only-do-not-override-1yhcnou).ant-btn.ant-btn-sm{
|
||||
height: unset;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
<!--
|
||||
<template>
|
||||
<!– <van-action-sheet v-model:show="show" title="Title">–>
|
||||
<van-action-sheet>
|
||||
<div><slot/></div>
|
||||
</van-action-sheet>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
<style scoped></style>-->
|
||||
|
||||
<template>
|
||||
<VanActionSheet :z-index="1000" teleport="body" dir="rtl">
|
||||
<div class="justify-center cursor-pointer flex mt-1" @click="$emit('update:show', false)">
|
||||
<span class="rounded-sm w-12 border-t-2 border-t-solid border-t-gray-500 mt-2"></span>
|
||||
</div>
|
||||
<div class="mx-4 mb-5 mt-3 max-h-90% overflow-y-auto">
|
||||
<slot></slot>
|
||||
<div
|
||||
class="grid gap-3 mb-5 mt-2"
|
||||
:class="[!props.showOk || !props.showCancel ? 'grid-cols-1' : 'grid-cols-12']"
|
||||
v-if="props.showButton && (props.showCancel || props.showOk)"
|
||||
>
|
||||
<AButton
|
||||
v-if="props.showCancel"
|
||||
@click="$emit('cancel')"
|
||||
type="primary"
|
||||
:class="[{ 'col-span-4': props.showOk }]"
|
||||
size="large"
|
||||
ghost
|
||||
block
|
||||
>
|
||||
{{ props.cancelText }}
|
||||
</AButton>
|
||||
<AButton
|
||||
@click="$emit('ok')"
|
||||
type="primary"
|
||||
:class="[{ 'col-span-8': props.showCancel }]"
|
||||
size="large"
|
||||
block
|
||||
v-if="props.showOk"
|
||||
>
|
||||
{{ props.okText }}
|
||||
</AButton>
|
||||
</div>
|
||||
</div>
|
||||
</VanActionSheet>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
interface Props {
|
||||
cancelText?: string
|
||||
showButton?: boolean
|
||||
showCancel?: boolean
|
||||
showOk?: boolean
|
||||
okText?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
cancelText: 'بازگشت',
|
||||
showButton: false,
|
||||
showCancel: true,
|
||||
showOk: true,
|
||||
okText: 'ثبت',
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less"></style>
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
<template>
|
||||
<AButton :type="props.type" :size="props.size" :class="[prefixCls, _class]" :loading="props.loading">
|
||||
<!-- py-1 px-2-->
|
||||
<div
|
||||
class="flex items-center gap-1 justify-center flex-row-reverse gap-2 py-1 px-2"
|
||||
:class="[{ 'flex-row-reverse': suffixIcon }]"
|
||||
>
|
||||
<slot v-if="$slots.default"></slot>
|
||||
|
||||
<Icon :size="iconSize" :icon="icon" v-if="icon" :class="iconClass" />
|
||||
</div>
|
||||
</AButton>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
// import { usePrefix } from '@core/composable/usePrefix'
|
||||
|
||||
import {computed, useSlots} from 'vue'
|
||||
import {baseButtonIconSize} from "@/themeConfig";
|
||||
import Icon from "@/components/BasicPacks/BasicIcon.vue";
|
||||
import { usePrefix } from '@/composable/usePrefix'
|
||||
|
||||
interface Props {
|
||||
icon?: string
|
||||
iconSize?: string
|
||||
iconClass?: string
|
||||
suffixIcon?: boolean
|
||||
type?: string
|
||||
size?: string
|
||||
loading?: boolean
|
||||
// prefixIcon?: string
|
||||
}
|
||||
|
||||
const slot = useSlots()
|
||||
|
||||
const _class = computed(() => {
|
||||
if (!slot.default) {
|
||||
return '!px-1 !py-1'
|
||||
}
|
||||
return ''
|
||||
})
|
||||
|
||||
const _loading = computed(() => {
|
||||
if (props.loading){
|
||||
return 'flex'
|
||||
} else return 'unset'
|
||||
})
|
||||
const { prefixCls } = usePrefix('base-button')
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
iconSize: baseButtonIconSize,
|
||||
// iconLeft: false,
|
||||
iconClass: ''
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@prefix:~'@{prefixCls}-base-button';
|
||||
.@{prefix}{
|
||||
//width: fit-content;
|
||||
height: auto;
|
||||
/*padding: 8px;*/
|
||||
display: v-bind(_loading);
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
<template>
|
||||
<span
|
||||
ref="refIcon"
|
||||
:style="{ color }"
|
||||
:class="[prefixCls]"
|
||||
class="!flex"
|
||||
v-html="tempIcon"
|
||||
></span>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import icons from '@/components/BasicPacks/tools/icons/icons.json'
|
||||
import {computed, onMounted, ref, withDefaults, defineProps} from "vue";
|
||||
import { usePrefix } from '@/composable/usePrefix'
|
||||
|
||||
interface Props {
|
||||
icon: string
|
||||
color?: string | null
|
||||
size?: string | number
|
||||
}
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
color: null,
|
||||
})
|
||||
|
||||
const { prefixCls } = usePrefix('icons')
|
||||
const tempIcon = ref<string>()
|
||||
const refIcon = ref<HTMLDivElement>()
|
||||
tempIcon.value = icons[`${props.icon}`] as string
|
||||
const color = computed(() => {
|
||||
return props.color
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
if (props.size) {
|
||||
const svg: SVGElement = refIcon.value?.children[0] as SVGElement
|
||||
svg.setAttribute('width', props.size as string)
|
||||
svg.setAttribute('height', props.size as string)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="less" scoped>
|
||||
@prefix: ~'@{prefixCls}-icons';
|
||||
|
||||
.@{prefix} {
|
||||
& :deep(svg path) {
|
||||
stroke: currentColor;
|
||||
}
|
||||
/* & :deep(svg path) {
|
||||
fill: currentColor;
|
||||
}*/
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
<template>
|
||||
<div :class="isLine?'flex justify-between items-center':''">
|
||||
<div class="flex items-center gap-1">
|
||||
<div class="text-gray-400">{{ title }}:</div>
|
||||
<BasicIcon v-if="info" icon="vuesax-linear:info-circle" size="18" color="orange" @click="infoVisible = true"/>
|
||||
</div>
|
||||
<div v-if="value" class="font-bold mt-1">{{ value }}</div>
|
||||
<div v-else class="mt-1">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
<van-dialog v-model:show="infoVisible" class="updateButton" confirm-button-text="متوجه شدم"
|
||||
show-confirm-button @confirm="update()">
|
||||
<div class="flex flex-col items-center p-2">
|
||||
<!-- <div class="home_appear_fade_in_up delay-100">به روز رسانی</div>-->
|
||||
<div class="home_appear_fade_in_up mt-2 text-sm">{{info}}</div>
|
||||
</div>
|
||||
</van-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import { update } from 'lodash'
|
||||
import { ref } from 'vue'
|
||||
// import anim from '@/assets/lottie/animInfo.json'
|
||||
|
||||
interface Prop {
|
||||
title: string
|
||||
info?: string
|
||||
isLine?: boolean
|
||||
value?: string | number
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Prop>(),{
|
||||
isLine: false
|
||||
})
|
||||
const infoVisible = ref<boolean>()
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
<template>
|
||||
<div :class="[prefixCls]">
|
||||
<div>
|
||||
{{ props.title }}
|
||||
</div>
|
||||
<a-input-password
|
||||
v-if="isPassword"
|
||||
v-model:value="localValue"
|
||||
:addon-after="props.addonAfter"
|
||||
:addon-before="props.addonBefore"
|
||||
:disabled="props.disabled"
|
||||
:placeHolder="props.placeHolder"
|
||||
:size="props.size"
|
||||
:type="props.type"
|
||||
class=""
|
||||
@change="handlerChange"
|
||||
/>
|
||||
<a-input
|
||||
v-else
|
||||
v-model:value="localValue"
|
||||
:addon-after="props.addonAfter"
|
||||
:addon-before="props.addonBefore"
|
||||
:disabled="props.disabled"
|
||||
:placeHolder="props.placeHolder"
|
||||
:size="props.size"
|
||||
:type="props.type === 'price'? 'tel':props.type"
|
||||
:inputmode="props.inputmode"
|
||||
:pattern="props.pattern"
|
||||
class=""
|
||||
@change="handlerChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {computed} from "vue";
|
||||
import {usePrice} from "@/components/BasicPacks/BasicPriceInput/src/utils/usePrice";
|
||||
import { usePrefix } from '@/composable/usePrefix'
|
||||
|
||||
//Props
|
||||
interface Prop {
|
||||
title?: String
|
||||
value?: String | Number
|
||||
size?: String
|
||||
type?: String
|
||||
inputmode?: String
|
||||
pattern?: String
|
||||
isPassword?: boolean
|
||||
disabled?: boolean
|
||||
addonAfter?: String
|
||||
addonBefore?: String
|
||||
addonBgColor?: String
|
||||
addonTextColor?: String
|
||||
placeHolder?: String
|
||||
}
|
||||
|
||||
const addonBgColor = computed(() => props.addonBgColor)
|
||||
const addonTextColor = computed(() => props.addonTextColor)
|
||||
//emits
|
||||
const localValue = computed({
|
||||
set(value) {
|
||||
// console.log(value?.toString().replaceAll(',', ''))
|
||||
props.type === 'price' ? emits('update:value', value?.toString().replaceAll(',', '')) : emits('update:value', value)
|
||||
},
|
||||
get() {
|
||||
let a = props.type === 'price' ? props.value ? usePrice(props.value as number, true, '').trim() : '' : props.value
|
||||
// console.log(props.value)
|
||||
return a
|
||||
},
|
||||
})
|
||||
|
||||
const props = withDefaults(defineProps<Prop>(), {
|
||||
isPassword: false
|
||||
})
|
||||
const emits = defineEmits(['update:value', 'onchange'])
|
||||
|
||||
const handlerChange = (e: any) => {
|
||||
// emits('onchange', e.target.value)
|
||||
props.type === 'price' ? emits('update:value', e.target.value?.toString().replaceAll(',', '')) : emits('update:value', e.target.value)
|
||||
props.type === 'price' ? emits('onchange', e.target.value?.toString().replaceAll(',', '')) : emits('onchange', e.target.value)
|
||||
// console.log('sas')
|
||||
}
|
||||
|
||||
//css style
|
||||
const {prefixCls} = usePrefix('input')
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@prefix: ~'@{prefixCls}-input';
|
||||
|
||||
.@{prefix} {
|
||||
/* .ant-input-group-addon:first-child {
|
||||
!* border: #d9d9d9 1px solid;
|
||||
border-radius: 0 6px 6px 0;*!
|
||||
}*/
|
||||
|
||||
.ant-input-group {
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.ant-input-group > .ant-input-rtl:first-child,
|
||||
.ant-input-group-rtl .ant-input-group-addon:first-child {
|
||||
border-radius: @border-radius-base 0 0 @border-radius-base;
|
||||
}
|
||||
|
||||
.ant-input-group > .ant-input:last-child,
|
||||
.ant-input-group-addon:last-child {
|
||||
border-radius: 0 @border-radius-base @border-radius-base 0;
|
||||
}
|
||||
|
||||
.ant-input-group-addon {
|
||||
background-color: v-bind(addonBgColor);
|
||||
color: v-bind(addonTextColor);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
<template>
|
||||
|
||||
<a-modal
|
||||
centered
|
||||
v-model:open="localValue"
|
||||
:title="props.title"
|
||||
@ok="emits('ok')"
|
||||
@cancel="emits('close')"
|
||||
@close="emits('close')"
|
||||
:width="props.width"
|
||||
:ok-text="props.okText"
|
||||
:cancel-text="props.cancelText"
|
||||
:wrapClassName="props.wrapClassName"
|
||||
>
|
||||
<template v-if="props.customFooter" #footer>
|
||||
<slot name="footer" />
|
||||
</template>
|
||||
<a-spin :spinning="props.loading">
|
||||
<div class="overflow-y-auto py-2 px-1 relative max-h-[80vh]" id="body">
|
||||
<slot />
|
||||
</div>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
//define emit
|
||||
import { computed } from 'vue'
|
||||
|
||||
const emits = defineEmits(['ok', 'close', 'update:visible'])
|
||||
|
||||
//define props
|
||||
interface Prop {
|
||||
visible: boolean
|
||||
title?: string
|
||||
okText?: string
|
||||
width?: string
|
||||
cancelText?: string
|
||||
customFooter?: boolean
|
||||
loading?: boolean
|
||||
wrapClassName?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Prop>(), {
|
||||
visible: false,
|
||||
cancelText: 'انصراف',
|
||||
okText: 'ثبت',
|
||||
customFooter: false,
|
||||
loading: false,
|
||||
wrapClassName: ''
|
||||
})
|
||||
|
||||
const localValue = computed({
|
||||
get() {
|
||||
return props.visible
|
||||
},
|
||||
|
||||
set(value) {
|
||||
emits('update:visible', value)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.ant-modal-content {
|
||||
border-radius: 0.6rem;
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import BasicPriceInput from './src/BasicPriceInput.vue'
|
||||
|
||||
export default BasicPriceInput
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<template>
|
||||
<BasicInput v-model:value="_val">
|
||||
<template v-for="(_, slotKey) in $slots" #[slotKey]="data">
|
||||
<slot :name="slotKey" v-bind="data || {}"></slot>
|
||||
</template>
|
||||
</BasicInput>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {usePrice} from './utils/usePrice'
|
||||
import {computed} from "vue";
|
||||
import BasicInput from "../../BasicInput.vue";
|
||||
|
||||
interface Props {
|
||||
value?: string | number
|
||||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:value', val: string | number): void
|
||||
}>()
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {})
|
||||
|
||||
const _val = computed({
|
||||
set(val: string) {
|
||||
// const temp = val.toString().replaceAll(',', '')
|
||||
const temp = val.toString().replaceAll(',', '')
|
||||
emit('update:value', temp)
|
||||
},
|
||||
get() {
|
||||
return props.value ? usePrice(props.value as number, true, '').trim() : ''
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less"></style>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
export function usePrice(price: number | 0, digit = true, unit = 'ریال') {
|
||||
let _price = price?.toString()
|
||||
if (digit) {
|
||||
_price = _price?.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
||||
}
|
||||
return `${_price} ${unit}`
|
||||
}
|
||||
|
||||
export function useTowDecimal(num: string | number): string | number {
|
||||
const temp = num.toString().match(/^-?\d+(?:\.\d{0,2})?/)
|
||||
if (temp && temp.length > 0) return temp[0]
|
||||
return Math.round(+num * 100) / 100
|
||||
}
|
||||
|
||||
export function useFormat(num: string | number, unit = '') {
|
||||
return usePrice(Math.abs(+useTowDecimal(num)), true, unit)
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
<template>
|
||||
<div :class="[prefixCls]">
|
||||
<div>
|
||||
{{ props.title }}
|
||||
</div>
|
||||
<a-select
|
||||
class="w-full"
|
||||
:size="props.size"
|
||||
v-model:value="localValue"
|
||||
:disabled="props.disabled"
|
||||
show-search
|
||||
:mode="props.mode"
|
||||
:style="props.style"
|
||||
:multiple="props.multiple"
|
||||
@change="handleChange"
|
||||
:placeholder="props.placeholder"
|
||||
:allowClear="props.allowClear"
|
||||
:filter-option="filterOption"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="(val, i) in props.items"
|
||||
:key="i"
|
||||
:label="get(val, props.valueName)"
|
||||
:value="get(val, props.keyName)"
|
||||
>
|
||||
<a-tooltip v-if="props.hasTooltip" placement="left" class="cursor-pointer">
|
||||
<template #title>
|
||||
<span>{{ get(val, props.valueName) }}</span>
|
||||
</template>
|
||||
<div class="truncate max-w-40">{{ get(val, props.valueName) }}</div>
|
||||
</a-tooltip>
|
||||
<div v-else>{{ get(val, props.valueName) }}</div>
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { usePrefix } from '@/composable/usePrefix'
|
||||
import { get } from 'lodash'
|
||||
import { computed, onMounted } from 'vue'
|
||||
|
||||
//Props
|
||||
interface Prop {
|
||||
title?: string
|
||||
value?: string | number | boolean | string[] | number[]
|
||||
valueText?: string | number | boolean | string[] | number[]
|
||||
style?: string
|
||||
size?: string
|
||||
keyName: string
|
||||
disabled?: boolean
|
||||
mode?: string
|
||||
valueName: string
|
||||
multiple?: boolean
|
||||
items?: any[]
|
||||
placeholder?: string
|
||||
allowClear?: boolean
|
||||
hasTooltip?: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Prop>(), { allowClear: true, hasTooltip: true })
|
||||
|
||||
// console.log('props.items ====>', props.items)
|
||||
//define emits
|
||||
const emit = defineEmits(['update:value', 'change', 'update:valueText'])
|
||||
onMounted(() => {
|
||||
for (let val in props.items) {
|
||||
// console.log('new', get(props.items[val], props.valueName))
|
||||
}
|
||||
})
|
||||
|
||||
const localValue = computed({
|
||||
get() {
|
||||
return props.value
|
||||
},
|
||||
|
||||
set(value) {
|
||||
emit('update:value', value)
|
||||
}
|
||||
})
|
||||
|
||||
function setValueText(val: any) {
|
||||
// console.log(val, get(val, props.valueName))
|
||||
localTextValue.value = get(val, props.valueName)
|
||||
}
|
||||
|
||||
const localTextValue = computed({
|
||||
get() {
|
||||
return props.valueText
|
||||
},
|
||||
|
||||
set(value) {
|
||||
emit('update:valueText', value)
|
||||
}
|
||||
})
|
||||
|
||||
const filterOption = (input: string, option: any) => {
|
||||
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}
|
||||
|
||||
const handleChange = (e: any) => {
|
||||
// console.log('e ====>', e)
|
||||
setValueText(props.items.find((x) => get(x, props.keyName) === e))
|
||||
emit(
|
||||
'change',
|
||||
props.items.find((x) => get(x, props.keyName) === e)
|
||||
)
|
||||
}
|
||||
|
||||
//css style
|
||||
const { prefixCls } = usePrefix('select')
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@prefix: ~'@{prefixCls}-select';
|
||||
|
||||
.@{prefix} {
|
||||
//padding: 5px;
|
||||
/* .ant-select {
|
||||
.ant-select-selector {
|
||||
border-color: @primary-color;
|
||||
border-radius: @border-radius-base;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
<template>
|
||||
<div v-if="!props.loading">
|
||||
<div class="gap-2">
|
||||
<a-tag
|
||||
v-for="item in props.items"
|
||||
:color="props.color"
|
||||
:closable="props.closable"
|
||||
@close="emits('delete', item.id)"
|
||||
class="cursor-pointer"
|
||||
@click="emits('edit', item.id)"
|
||||
>{{ item.name }}
|
||||
</a-tag>
|
||||
<a-tag
|
||||
v-if="props.hasAdd"
|
||||
style="background: #fff; border-style: dashed; margin-top: 0.5rem"
|
||||
@click="emits('add')"
|
||||
class="cursor-pointer"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<BaseIcon icon="vuesax-linear:add" size="0.7rem" />
|
||||
<div class="mr-1">افزودن</div>
|
||||
</div>
|
||||
</a-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<ContentLoader
|
||||
width="350"
|
||||
height="100"
|
||||
viewBox="0 0 350 100"
|
||||
backgroundColor="#f5f5f5"
|
||||
foregroundColor="#dbdbdb"
|
||||
>
|
||||
<rect x="0" y="0" rx="3" ry="3" width="80" height="20" />
|
||||
<rect x="90" y="0" rx="3" ry="3" width="80" height="20" />
|
||||
<rect x="180" y="0" rx="3" ry="3" width="80" height="20" />
|
||||
<rect x="270" y="0" rx="3" ry="3" width="80" height="20" />
|
||||
</ContentLoader>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ContentLoader } from 'vue-content-loader'
|
||||
|
||||
//define emits
|
||||
const emits = defineEmits(['add', 'edit', 'delete'])
|
||||
|
||||
//define props
|
||||
interface Prop {
|
||||
items?: Array<string>
|
||||
color: string
|
||||
loading?: boolean
|
||||
closable?: boolean
|
||||
hasAdd?: boolean
|
||||
}
|
||||
const props = withDefaults(defineProps<Prop>(), {
|
||||
closable: false,
|
||||
hasAdd: true
|
||||
})
|
||||
|
||||
/*watch(props, (val) => {
|
||||
console.log('val ====>', val)
|
||||
})*/
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
export interface TagItem {
|
||||
id: number | undefined
|
||||
name: string | undefined
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
<template>
|
||||
<div :class="[prefixCls]">
|
||||
<div>
|
||||
{{ props.title }}
|
||||
</div>
|
||||
<a-textarea
|
||||
v-model:value="localValue"
|
||||
class=""
|
||||
:type="props.type"
|
||||
:show-count="props.showCount"
|
||||
:placeHolder="props.placeHolder"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {computed} from "vue";
|
||||
import { usePrefix } from '@/composable/usePrefix'
|
||||
|
||||
//Props
|
||||
interface Prop {
|
||||
title?: string
|
||||
value: string | null
|
||||
showCount?: boolean
|
||||
maxlength?: number
|
||||
placeHolder?: string
|
||||
}
|
||||
|
||||
const props = defineProps<Prop>()
|
||||
|
||||
const emit = defineEmits(['update:value'])
|
||||
|
||||
const localValue = computed({
|
||||
get() {
|
||||
return props.value
|
||||
},
|
||||
|
||||
set(value) {
|
||||
emit('update:value', value)
|
||||
}
|
||||
})
|
||||
|
||||
//css style
|
||||
const { prefixCls } = usePrefix('input-area')
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@prefix: ~'@{prefixCls}-input-area';
|
||||
|
||||
.@{prefix} {
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
<template>
|
||||
<a-upload-dragger
|
||||
v-model:fileList="fileList"
|
||||
name="file"
|
||||
:multiple="props.multiple"
|
||||
:action="props.url"
|
||||
@change="handleChange"
|
||||
:headers="props.headers"
|
||||
:maxCount="props.maxCount"
|
||||
:showUploadList="true"
|
||||
>
|
||||
<div class="py-10 px-5">
|
||||
<BaseIcon icon="vuesax-linear:document-upload" size="40" color="#4A5568" />
|
||||
<p class="ant-upload-text">برای آپلود، روی فایل کلیک کنید یا فایل را درون این قسمت بکشید</p>
|
||||
</div>
|
||||
</a-upload-dragger>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { InboxOutlined } from '@ant-design/icons-vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import type { UploadChangeParam } from 'ant-design-vue'
|
||||
|
||||
const handleChange = (info: UploadChangeParam) => {
|
||||
// console.log(info)
|
||||
const status = info.file.status
|
||||
if (status !== 'uploading') {
|
||||
// console.log(info.file, info.fileList)
|
||||
/*emits('ok', info.file.response.id)*/
|
||||
}
|
||||
if (status === 'done') {
|
||||
// message.success(`${info.file.name} file uploaded successfully.`)
|
||||
console.log(fileList)
|
||||
emits('ok', info.file.response.id)
|
||||
} else if (status === 'error') {
|
||||
message.error(`خطا در بارگذاری فایل`)
|
||||
} else if (status === 'removed') {
|
||||
emits('delete', info.file.uid)
|
||||
}
|
||||
}
|
||||
|
||||
//props
|
||||
interface Prop {
|
||||
url: string
|
||||
multiple?: boolean
|
||||
fileList?: Array<FileList>
|
||||
maxCount?: number
|
||||
headers?: any
|
||||
}
|
||||
|
||||
const props = defineProps<Prop>()
|
||||
|
||||
//emits
|
||||
const emits = defineEmits(['update:fileList', 'ok', 'delete'])
|
||||
|
||||
// const fileList = ref([])
|
||||
|
||||
const fileList = computed({
|
||||
get() {
|
||||
return props.fileList || ([] as Array<FileList>)
|
||||
},
|
||||
set(value) {
|
||||
emits('update:fileList', value)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
export interface FileList {
|
||||
uid?: any | null | undefined
|
||||
name?: any | null | undefined
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
<template>
|
||||
<span
|
||||
ref="refIcon"
|
||||
:style="{ color, fill: color }"
|
||||
class="!flex examplee"
|
||||
v-html="tempIcon"
|
||||
></span>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import icons from '../assets/icons/bulk-icon.json'
|
||||
// import { usePrefix } from '@/composable/usePrefix'
|
||||
|
||||
interface Props {
|
||||
icon: string
|
||||
color?: string | null
|
||||
size?: string | number
|
||||
}
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
// color: '#D1D5DB',
|
||||
size: undefined
|
||||
})
|
||||
// const siza=computed(()=>{
|
||||
// return `w-[${props.size}px] h-[${props.size}px]`
|
||||
// })
|
||||
|
||||
// const { prefixCls } = usePrefix('icons')
|
||||
const tempIcon = ref<string>()
|
||||
const refIcon = ref<HTMLDivElement>()
|
||||
tempIcon.value = icons[`${props.icon}`] as string
|
||||
const color = computed(() => {
|
||||
return props.color
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
if (props.size) {
|
||||
const svg: SVGElement = refIcon.value?.children[0] as SVGElement
|
||||
svg.setAttribute('width', props.size as string)
|
||||
svg.setAttribute('height', props.size as string)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
//@prefix:~ '@{prefixCls}-icons';
|
||||
//
|
||||
//.@{prefix} {
|
||||
// & :deep(svg path) {
|
||||
// stroke: currentColor;
|
||||
// }
|
||||
//}
|
||||
.examplee svg path {
|
||||
//stroke: v-bind(color);
|
||||
fill: v-bind(color);
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<template>
|
||||
<div
|
||||
:style="{ color: props.textColor, backgroundColor: props.bgColor }"
|
||||
class="w-fit p-1 rounded-lg"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
//props
|
||||
interface Prop {
|
||||
textColor: string
|
||||
bgColor: string
|
||||
}
|
||||
|
||||
const props = defineProps<Prop>()
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
<template>
|
||||
<!-- <div v-if="modelValue">-->
|
||||
<van-dialog class="oneButtonDialog">
|
||||
<div class="my-4">
|
||||
<div class="w-full flex justify-center">
|
||||
<slot name="img">{{ text2 }}</slot>
|
||||
|
||||
</div>
|
||||
<div class="w-full flex justify-center text-[18px] font-semibold">
|
||||
<slot name="title">{{ text1 }}</slot>
|
||||
</div>
|
||||
<div class=" border-t border-solid border-[#E5E7EB] pt-4 mx-2 mt-6 font-semibold text-[15px]">
|
||||
<slot name="button">{{ text3 }}</slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</van-dialog>
|
||||
<!-- <van-dialog style="background-color: #2b3f6e" show-cancel-button cancelButtonText="بیخیال" confirmButtonText="بله" cancelButtonColor="">-->
|
||||
<!-- <div class="w-full mt-6 text-white ">-->
|
||||
<!-- <div class="w-full flex mb-[10px] ">-->
|
||||
<!-- <Icon icon="vuesax-linear:info-circle" class="mx-4" size="25"/>-->
|
||||
<!-- <span class="text-lg flex-1">-->
|
||||
<!-- <slot name="title">{{text1}}</slot>-->
|
||||
<!-- </span>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="flex justify-start mb-6 mt-8" style="font-weight:700;">-->
|
||||
<!-- <slot name="button">{{text2}}</slot>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </van-dialog>-->
|
||||
<!-- </div>-->
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
// import Icon from "/@/assets/icons/Icon.vue";
|
||||
import {ref, watch} from 'vue';
|
||||
|
||||
const show = ref(true);
|
||||
const props = withDefaults(defineProps<{
|
||||
// modelValue: boolean,
|
||||
timeOut: number,
|
||||
text1?: string,
|
||||
text2?: string,
|
||||
text3?: string
|
||||
// top?: string,
|
||||
|
||||
}>(), {})
|
||||
const emit = defineEmits<{ (e: 'update:modelValue', value: boolean): void }>()
|
||||
watch(() => props.modelValue, (value) => {
|
||||
if (props.timeOut !== -1) showNotify()
|
||||
})
|
||||
const showNotify = () => {
|
||||
console.log('notify', show.value)
|
||||
setTimeout(() => {
|
||||
emit('update:modelValue', false)
|
||||
}, props.timeOut);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.notify-enter-active {
|
||||
animation: notify-in 0.2s;
|
||||
}
|
||||
|
||||
.notify-leave-active {
|
||||
animation: notify-in 0.2s reverse;
|
||||
}
|
||||
|
||||
.oneButtonDialog .van-dialog__confirm, .van-dialog__cancel {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
|
||||
.van-dialog__confirm, .van-dialog__cancel {
|
||||
//background-color: ;
|
||||
}
|
||||
|
||||
.oneButtonDialog .van-dialog__confirm .van-button__text {
|
||||
color: #1C2D56;
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.oneButtonDialog .van-dialog__cancel .van-button__text {
|
||||
color: #6b7280;
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
<template>
|
||||
<span
|
||||
ref="refIcon"
|
||||
:style="{ color }"
|
||||
:class="[prefixCls]"
|
||||
class="!flex"
|
||||
v-html="tempIcon"
|
||||
></span>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import icons from '@/components/BasicPacks/tools/icons/icons.json'
|
||||
import {usePrefix} from "@/utils/usePrefix";
|
||||
import {computed, onMounted, ref, withDefaults, defineProps} from "vue";
|
||||
|
||||
interface Props {
|
||||
icon: string
|
||||
color?: string | null
|
||||
size?: string | number
|
||||
}
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
color: null,
|
||||
})
|
||||
|
||||
const { prefixCls } = usePrefix('icons')
|
||||
const tempIcon = ref<string>()
|
||||
const refIcon = ref<HTMLDivElement>()
|
||||
tempIcon.value = icons[`${props.icon}`] as string
|
||||
const color = computed(() => {
|
||||
return props.color
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
if (props.size) {
|
||||
const svg: SVGElement = refIcon.value?.children[0] as SVGElement
|
||||
svg.setAttribute('width', props.size as string)
|
||||
svg.setAttribute('height', props.size as string)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="less" scoped>
|
||||
@prefix: ~'@{prefixCls}-icons';
|
||||
|
||||
.@{prefix} {
|
||||
& :deep(svg path) {
|
||||
stroke: currentColor;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
<template>
|
||||
<div :class="[prefixCls]">
|
||||
<AButton class="w-full flex justify-center" :size="props.size" :type="props.type" :disabled="disabled">
|
||||
<template class="flex items-center gap-2">
|
||||
<Icon :icon="props.icon" :size="props.iconSize" />
|
||||
<slot></slot>
|
||||
</template>
|
||||
</AButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { usePrefix } from '@/composable/usePrefix'
|
||||
import Icon from '@/components/Icon.vue'
|
||||
|
||||
interface Props {
|
||||
icon: string
|
||||
iconSize?: number | string
|
||||
size?: string
|
||||
type?: string
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
iconSize: 20,
|
||||
size: 'middle',
|
||||
type: 'default',
|
||||
disabled: false
|
||||
})
|
||||
|
||||
const { prefixCls } = usePrefix('icon-button')
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@prefix: ~'@{prefixCls}-icon-button';
|
||||
|
||||
.@{prefix} {
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<template>
|
||||
<div class="">
|
||||
<div class="text-gray-400">{{ title }}:</div>
|
||||
<div v-if="value" class="font-bold mt-1">{{ value }}</div>
|
||||
<slot v-else></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
interface Prop {
|
||||
title: string
|
||||
value?: string | number
|
||||
}
|
||||
|
||||
const props = defineProps<Prop>()
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
<template>
|
||||
<div class="install-container">
|
||||
<button v-show="pwaStore.showInstall" @click="install" class="install-btn fade-slide-in">
|
||||
<!-- <button @click="install" class="install-btn fade-slide-in">-->
|
||||
نصب اپلیکیشن
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { usePWAStore } from '@/store/usePWAStore'
|
||||
|
||||
const pwaStore = usePWAStore()
|
||||
|
||||
const install = async () => {
|
||||
if (!pwaStore.deferredPrompt) return
|
||||
pwaStore.deferredPrompt.prompt()
|
||||
const result = await pwaStore.deferredPrompt.userChoice
|
||||
if (result.outcome === 'accepted') {
|
||||
console.log('User accepted install')
|
||||
}
|
||||
pwaStore.clearPrompt()
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/*.install-btn {
|
||||
padding: 10px 20px;
|
||||
background: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
width: 5rem;
|
||||
cursor: pointer;
|
||||
}*/
|
||||
.install-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@keyframes fadeSlideIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.fade-slide-in {
|
||||
animation: fadeSlideIn 0.5s ease forwards;
|
||||
}
|
||||
|
||||
.install-btn {
|
||||
padding: 0.8rem 2rem;
|
||||
background: linear-gradient(to right, #214368, #2b5a92);
|
||||
color: #ffffff;
|
||||
border: 1px solid #315d96;
|
||||
border-radius: 14px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
box-shadow:
|
||||
0 8px 15px rgba(0, 0, 0, 0.2),
|
||||
0 0 0 2px rgba(255, 255, 255, 0.05) inset;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
backdrop-filter: blur(2px);
|
||||
}
|
||||
|
||||
.install-btn:hover {
|
||||
background: linear-gradient(to right, #2b5a92, #214368);
|
||||
box-shadow:
|
||||
0 10px 20px rgba(33, 67, 104, 0.6),
|
||||
0 0 0 2px rgba(255, 255, 255, 0.08) inset;
|
||||
transform: translateY(-3px);
|
||||
}
|
||||
|
||||
.install-btn:active {
|
||||
transform: scale(0.97);
|
||||
box-shadow:
|
||||
0 4px 8px rgba(33, 67, 104, 0.4),
|
||||
0 0 0 2px rgba(255, 255, 255, 0.1) inset;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,201 @@
|
|||
<template>
|
||||
<div :class="[prefixCls]">
|
||||
<!-- <AMenu-->
|
||||
<!-- class="p-2 flex bg-[#28C792] rounded-3xl justify-evenly md:justify-center h-5.4rem md:h-unset"-->
|
||||
<!-- v-model:selected-keys="current"-->
|
||||
<!-- mode="horizontal"-->
|
||||
<!-- @change="changeHandler"-->
|
||||
<!-- >-->
|
||||
<!-- <template v-for="item in items">-->
|
||||
<!-- <AMenuItem-->
|
||||
<!-- class="!px-3 md:w-[180px]"-->
|
||||
<!-- :key="item.key"-->
|
||||
<!-- v-if="item.show"-->
|
||||
<!-- @click="item.key === 'mobileProfile' ? showProfile() : changeHandler(item?.key)"-->
|
||||
<!-- >-->
|
||||
<!-- <div class="flex flex-col items-center gap-1">-->
|
||||
<!-- <BulkIcon-->
|
||||
<!-- class="menuItemSelect"-->
|
||||
<!-- :icon="`vuesax-bulk:${item?.icon}`"-->
|
||||
<!-- v-if="item.key === current[0]"-->
|
||||
<!-- />-->
|
||||
<!-- <Icon :icon="`vuesax-linear:${item?.icon}`" class="menuItem" v-else/>-->
|
||||
<!-- <span class="text-xs " :class=" item.key === current[0] ? 'text_Secondary' : 'textColor1' ">{{-->
|
||||
<!-- item?.title-->
|
||||
<!-- }}</span>-->
|
||||
<!-- </div>-->
|
||||
<!-- </AMenuItem>-->
|
||||
<!-- </template>-->
|
||||
<!-- </AMenu>-->
|
||||
<div class=" p-2 flex flex bg-[#28C792] rounded-3xl justify-evenly items-center md:justify-center md:h-unset ">
|
||||
<div class=" md:w-[180px]" v-for="item in items" @click="item.key === 'mobileProfile' ? showProfile() : changeHandler(item?.key)">
|
||||
<div class="flex justify-center bg-[#FABF3D] border-black border-1 px-4 py-1 rounded-t-6 rounded-b-4" v-show="item.key==current[0] ||item.childrenName==current[0] ">
|
||||
<img :src="item.href">
|
||||
</div>
|
||||
<div class=" flex justify-center bg-[#28C792] px-4 py-1 " v-show="item.key!=current[0] && item.childrenName!=current[0] ">
|
||||
<img :src="item.href">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<ProfileDrawer v-model:open="open" @close="handleDrawerClose"/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {onMounted, ref, computed, watch, onBeforeUnmount} from 'vue'
|
||||
import {usePrefix} from '@/composable/usePrefix'
|
||||
import Icon from '@/components/Icon.vue'
|
||||
import router from '@/router'
|
||||
import BulkIcon from '@/components/BulkIcon.vue'
|
||||
import ProfileDrawer from '@/components/ProfileDrawer.vue'
|
||||
import {useUserStore} from '@/store/user'
|
||||
import homeImg from '@/assets/img/home.png'
|
||||
import homeImgSelected from '@/assets/img/home.png'
|
||||
import storyImg from '@/assets/img/audio.png'
|
||||
import storyImgSelected from '@/assets/img/audio.png'
|
||||
import luckywheelImg from '@/assets/img/luckywheel.png'
|
||||
import luckywheelImgSelected from '@/assets/img/luckywheel.png'
|
||||
import userImg from '@/assets/img/user_120.png'
|
||||
|
||||
|
||||
|
||||
|
||||
const open = ref<boolean>(false)
|
||||
const isMobile = ref(false)
|
||||
const userStore = useUserStore()
|
||||
const {prefixCls} = usePrefix('footer')
|
||||
const current = ref<string[]>([''])
|
||||
const items = computed(() => [
|
||||
{
|
||||
show: true,
|
||||
title: 'خانه',
|
||||
icon: 'home',
|
||||
key: 'home',
|
||||
href: homeImg,
|
||||
childrenName:'',
|
||||
hrefSelected: homeImg
|
||||
},
|
||||
{
|
||||
show: true,
|
||||
title: 'داستان ها',
|
||||
icon: 'storys',
|
||||
key: 'storys',
|
||||
childrenName:'storyPage',
|
||||
href: storyImg,
|
||||
hrefSelected: homeImg
|
||||
|
||||
},
|
||||
{
|
||||
show: true,
|
||||
title: 'گردونه',
|
||||
icon: '',
|
||||
key: 'luckyWheel',
|
||||
href: luckywheelImg,
|
||||
childrenName:'',
|
||||
hrefSelected: homeImg
|
||||
|
||||
},
|
||||
/* {
|
||||
show: true,
|
||||
title: 'تراکنش ها',
|
||||
icon: 'receipt-2',
|
||||
key: 'transactions'
|
||||
},*/
|
||||
// {
|
||||
// show: true,
|
||||
// title: 'سفارشات',
|
||||
// icon: 'bag-happy',
|
||||
// key: 'orders'
|
||||
// },
|
||||
/*{
|
||||
show: true,
|
||||
title: 'برداشت',
|
||||
icon: 'convert-card',
|
||||
key: 'transfer'
|
||||
},*/
|
||||
// {
|
||||
// show: userStore.user?.type_str === 'نماینده',
|
||||
// title: 'مشتریان',
|
||||
// icon: 'people',
|
||||
// key: 'users',
|
||||
// },
|
||||
{
|
||||
show: isMobile.value,
|
||||
title: 'پروفایل',
|
||||
icon: 'user',
|
||||
key: 'mobileProfile',
|
||||
href: userImg,
|
||||
childrenName:'',
|
||||
hrefSelected: userImg
|
||||
}
|
||||
])
|
||||
|
||||
const checkDevice = () => {
|
||||
isMobile.value = window.innerWidth <= 768
|
||||
}
|
||||
|
||||
const showProfile = () => {
|
||||
open.value = true
|
||||
}
|
||||
|
||||
const currentRoute = computed(() => {
|
||||
return router.currentRoute.value.name
|
||||
})
|
||||
|
||||
const setCurrentValue = () => {
|
||||
const currentRoute = router.currentRoute.value.name
|
||||
current.value = [currentRoute as string]
|
||||
}
|
||||
|
||||
const changeHandler = (key: string) => {
|
||||
console.log(key)
|
||||
router.push({name: key})
|
||||
}
|
||||
|
||||
const handleDrawerClose = () => {
|
||||
const currentRouteName = router.currentRoute.value.name
|
||||
current.value = [currentRouteName as string]
|
||||
}
|
||||
|
||||
|
||||
watch(router.currentRoute, () => {
|
||||
setCurrentValue()
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
setCurrentValue()
|
||||
window.addEventListener('resize', checkDevice)
|
||||
checkDevice()
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('resize', checkDevice)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@prefix: ~'@{prefixCls}-footer';
|
||||
|
||||
.@{prefix} {
|
||||
.ant-menu-horizontal > .ant-menu-item-selected::after {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.ant-menu-light.ant-menu-horizontal > .ant-menu-item::after {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.ant-menu-horizontal {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.ant-menu::before {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.ant-menu-horizontal::after {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<template>
|
||||
<div class="fixed top-0 w-inherit p-4 z-1000">
|
||||
<div class="md:hidden p-2 border MobileNavbar rounded-md grid grid-cols-3">
|
||||
<Icon
|
||||
class="self-start icon_MobileNavbar"
|
||||
icon="vuesax-linear:arrow-right-1"
|
||||
@click="router.go(-1)"
|
||||
/>
|
||||
<div class="text-base font-semibold text-center whitespace-nowrap">{{title}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
import router from '@/router'
|
||||
interface Prop {
|
||||
title: string
|
||||
}
|
||||
const props = defineProps<Prop>()
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<template>
|
||||
<div class="backHeader" :class="[prefixCls]">
|
||||
<div class="p-4">
|
||||
<div
|
||||
class="flex justify-between items-center p-2 rounded border border-solid borderHeader"
|
||||
>
|
||||
<div v-if="mode === 'marandigold' " class="flex items-center ">
|
||||
<img :src="logo" class="h-8" alt="logo">
|
||||
<span class="text-sm font-bold mr-2">اپلیکیشن معاملاتی آبشده مرندی</span>
|
||||
</div>
|
||||
<span v-if="mode !== 'marandigold' " class="text-sm font-medium">{{ userStore.user?.name }}</span>
|
||||
<Icon icon="vuesax-linear:profile-circle" size="30" @click="open = true" class="avatarIcon" />
|
||||
</div>
|
||||
</div>
|
||||
<ProfileDrawer v-model:open="open" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { usePrefix } from '@/composable/usePrefix'
|
||||
import ProfileDrawer from '@/components/ProfileDrawer.vue'
|
||||
import { ref } from 'vue'
|
||||
import { useUserStore } from '@/store/user'
|
||||
import logo from '@/assets/img/marandiLogo.svg'
|
||||
import Icon from '@/components/Icon.vue'
|
||||
const mode = import.meta.env.MODE
|
||||
const { prefixCls } = usePrefix('header')
|
||||
const open = ref<boolean>(false)
|
||||
const userStore = useUserStore()
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
@prefix: ~'@{prefixCls}-header';
|
||||
.@{prefix} {
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
<template>
|
||||
<div class="" :class="[prefixCls]" v-if="item.show">
|
||||
<ACard class="border-none shadow-md primaryColor" v-if="mode !== 'marandigold'">
|
||||
<div class="flex flex-col">
|
||||
<div class="flex gap-2 justify-between w-full items-center">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<!-- <img v-if="item?.icon" :src="item.icon" alt="" class="w-6 h-6">
|
||||
<img v-else :src="defImg" alt="" class="w-6 h-6">-->
|
||||
<h2 class="text-sm font-semibold text-center">{{ props.item?.title }}</h2>
|
||||
</div>
|
||||
<div class="flex items-center gap-1">
|
||||
<span class="text-sm font-medium">{{ item.active ? 'باز' : 'بسته' }}</span>
|
||||
<span
|
||||
class="size-2 rounded-full mt-0.5"
|
||||
:class="[item.active ? 'background_green' : 'background_red']"
|
||||
></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2 text-base font-bold">
|
||||
<BasicButton
|
||||
v-if="buyOpen"
|
||||
class="w-full text-center px-4 py-2 border rounded-md cursor-pointer font-bold !text-green-600 BuySell_button_ box-shadow"
|
||||
:class="{ 'glow-effect': buyOpen }"
|
||||
@click="item.active && emit('buy')"
|
||||
>
|
||||
{{ usePrice(item.buy ?? 0, true, '') }}
|
||||
</BasicButton>
|
||||
<BasicButton
|
||||
v-else
|
||||
class="w-full text-center content-center px-4 py-2 rounded-md cursor-pointer font-bold BuySell_button_ !text-green-600"
|
||||
>{{ 'غیرفعال' }}</BasicButton
|
||||
>
|
||||
<BasicButton
|
||||
v-if="sellOpen"
|
||||
class="w-full text-center px-4 py-2 border rounded-md cursor-pointer font-bold BuySell_button_ !text-red-600"
|
||||
:class="{ 'glow-effect-red': sellOpen }"
|
||||
@click="item.active && emit('sell')"
|
||||
>
|
||||
{{ usePrice(item.sell ?? 0, true, '') }}
|
||||
</BasicButton>
|
||||
<BasicButton
|
||||
v-else
|
||||
class="w-full text-center content-center px-4 py-2 BuySell_button_ rounded-md cursor-pointer font-bold !text-red-600"
|
||||
>{{ 'غیرفعال' }}</BasicButton
|
||||
>
|
||||
</div>
|
||||
<div class="flex justify-between items-center mt-3">
|
||||
<div class="flex items-center gap-1 justify-center w-full">
|
||||
<span class="text-xs font-semibold textColor2">آخرین بروز رسانی :</span>
|
||||
<!-- <span class="text-sm font-bold text-gray-700">{{// toJalali(item?.updated_at)}}</span>-->
|
||||
<span class="text-sm font-bold textColor1">{{ item?.updated_at }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ACard>
|
||||
<div v-else class="rounded-lg p2 bg-gradient-to-l from-[#62a1b1] to-[#b5f5df]">
|
||||
<div class="flex flex-col">
|
||||
<div class="flex gap-2 justify-between w-full items-center">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<div class="bg-gray-100 rounded-full p3 w-15 h-15">
|
||||
<img v-if="item?.icon" :src="item.icon" alt="" class="w-full" />
|
||||
<img v-else :src="logo" alt="" class="w-full" />
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-sm font-semibold text-black">{{ props.item?.title }}</h2>
|
||||
<div class="flex items-center gap-1 justify-center w-full">
|
||||
<span class="text-xs font-semibold text-gray-600">آخرین قیمت در </span>
|
||||
<!-- <span class="text-sm font-bold text-gray-700">{{// toJalali(item?.updated_at)}}</span>-->
|
||||
<span class="text-sm font-bold text-gray-600">{{ item?.updated_at.split(' ')[0] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-1">
|
||||
<span class="text-sm font-medium text-gray-600">{{ item.active ? 'باز' : 'بسته' }}</span>
|
||||
<span
|
||||
class="size-2 rounded-full mt-0.5"
|
||||
:class="[item.active ? 'background_green' : 'background_red']"
|
||||
></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2 text-base font-bold">
|
||||
<BasicButton
|
||||
v-if="buyOpen"
|
||||
type="link"
|
||||
class="w-full text-center px-4 py-2 border rounded-md cursor-pointer font-bold !text-green-600 BuySell_button_ box-shadow border-unset "
|
||||
:class="{ 'glow-effect': buyOpen }"
|
||||
@click="item.active && emit('buy')"
|
||||
>
|
||||
<div>
|
||||
<span>{{ item.buy.toString().slice(0,3) }}</span>
|
||||
<span>,</span>
|
||||
<span class="font-bold text-2xl">{{ item.buy.toString().slice(3,6) }}</span>
|
||||
<span>,</span>
|
||||
<span class="text-xs">{{ item.buy.toString().slice(6, 9) }}</span>
|
||||
</div>
|
||||
</BasicButton>
|
||||
<BasicButton
|
||||
v-else
|
||||
type="link"
|
||||
class="w-full text-center content-center px-4 py-2 rounded-md cursor-pointer font-bold BuySell_button_ !text-green-600 border-unset !bg-transparent"
|
||||
>{{ 'غیرفعال' }}</BasicButton
|
||||
>
|
||||
<BasicButton
|
||||
v-if="sellOpen"
|
||||
type="link"
|
||||
class="w-full text-center px-4 py-2 border rounded-md cursor-pointer font-bold BuySell_button_ !text-red-600 border-unset "
|
||||
:class="{ 'glow-effect-red': sellOpen }"
|
||||
@click="item.active && emit('sell')"
|
||||
>
|
||||
<div>
|
||||
<span>{{ item.sell.toString().slice(0,3) }}</span>
|
||||
<span>,</span>
|
||||
<span class="font-bold text-2xl">{{ item.sell.toString().slice(3,6) }}</span>
|
||||
<span>,</span>
|
||||
<span class="text-xs">{{ item.sell.toString().slice(6,9) }}</span>
|
||||
</div> </BasicButton>
|
||||
<BasicButton
|
||||
v-else
|
||||
type="link"
|
||||
class="w-full text-center content-center px-4 py-2 BuySell_button_ rounded-md cursor-pointer font-bold !text-red-600 border-unset !bg-transparent"
|
||||
>{{ 'غیرفعال' }}</BasicButton
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { usePrefix } from '@/composable/usePrefix'
|
||||
import { usePrice } from '../composable/usePrice'
|
||||
import type { Product, ProductShow } from '@/model/product'
|
||||
import { toJalali } from '../utils/useDateTime'
|
||||
import defImg from '@/assets/img/logo_desktop.svg'
|
||||
import { computed } from 'vue'
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
|
||||
interface Props {
|
||||
item: ProductShow
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {})
|
||||
const emit = defineEmits<{
|
||||
(e: 'sell'): void
|
||||
(e: 'buy'): void
|
||||
}>()
|
||||
|
||||
const mode = import.meta.env.MODE
|
||||
const logo = import.meta.env.VITE_PROJECT_LOGO
|
||||
|
||||
const { prefixCls } = usePrefix('product-card')
|
||||
|
||||
const buyOpen = computed(() => {
|
||||
return props.item.active && props.item.open_buy
|
||||
})
|
||||
|
||||
const sellOpen = computed(() => {
|
||||
return props.item.active && props.item.open_sell
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@prefix: ~'@{prefixCls}-product-card';
|
||||
|
||||
.@{prefix} {
|
||||
.ant-card-body {
|
||||
padding: 8px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
<template>
|
||||
<div :class="[prefixCls]">
|
||||
<ADrawer
|
||||
class="rounded-t-2xl ADrawer"
|
||||
:open="props.open"
|
||||
height="500"
|
||||
placement="bottom"
|
||||
:header-style="{ display: 'none' }"
|
||||
:body-style="{ padding: '16px', height: 'fit-content' }"
|
||||
@close="visible = false"
|
||||
@click:outside="visible = false"
|
||||
>
|
||||
<template #closeIcon></template>
|
||||
<UserSetting />
|
||||
</ADrawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { usePrefix } from '@/composable/usePrefix'
|
||||
import UserSetting from '@/components/UserSetting.vue'
|
||||
import { computed, watch } from 'vue'
|
||||
import router from '@/router'
|
||||
|
||||
interface Props {
|
||||
open: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
open: false
|
||||
})
|
||||
|
||||
watch(router.currentRoute,()=>{
|
||||
visible.value = false
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:open', value: boolean): void
|
||||
}>()
|
||||
|
||||
const visible = computed({
|
||||
get() {
|
||||
return props.open
|
||||
},
|
||||
set(value) {
|
||||
emit('update:open', value)
|
||||
if (!value) emit('close')
|
||||
}
|
||||
})
|
||||
|
||||
const { prefixCls } = usePrefix('profile-drawer')
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
@prefix: ~'@{prefixCls}-profile-drawer';
|
||||
|
||||
.@{prefix} {
|
||||
&-drawer {
|
||||
.ant-drawer .ant-drawer-content {
|
||||
border-radius: 16px 16px 0 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
<template>
|
||||
<div v-if="store.user?.type === 1 ">
|
||||
<BasicButton
|
||||
class="mt-2 w-full border-0 px0 configButton configIcon"
|
||||
:class="setActionSheetItemColor('home')"
|
||||
icon="vuesax-linear:user"
|
||||
icon-size="16"
|
||||
@click="stopSheet('home')"
|
||||
>
|
||||
<BasicIcon
|
||||
class="configIcon"
|
||||
icon="vuesax-linear:arrow-left-1"
|
||||
/>
|
||||
<div class="flex w-full justify-right" >
|
||||
مشتریان
|
||||
</div>
|
||||
</BasicButton>
|
||||
<!-- <BasicButton
|
||||
class="mt-2 w-full border-0 px0 configButton configIcon"
|
||||
:class="setActionSheetItemColor('home')"
|
||||
icon="vuesax-linear:trend-up"
|
||||
icon-size="16"
|
||||
@click="stopSheet('packages')"
|
||||
>
|
||||
<BasicIcon
|
||||
class="configIcon"
|
||||
icon="vuesax-linear:arrow-left-1"
|
||||
|
||||
/>
|
||||
<div class="flex w-full justify-right" >
|
||||
سودها
|
||||
</div>
|
||||
</BasicButton>-->
|
||||
</div>
|
||||
|
||||
<!-- <BasicButton
|
||||
class="mt-2 w-full border-0 px0 configButton configIcon"
|
||||
:class="setActionSheetItemColor('home')"
|
||||
icon="vuesax-linear:receipt-item"
|
||||
icon-size="16"
|
||||
@click="stopSheet('transaction')"
|
||||
>
|
||||
<BasicIcon
|
||||
class="configIcon"
|
||||
icon="vuesax-linear:arrow-left-1"
|
||||
/>
|
||||
<div class="flex w-full justify-right" >
|
||||
گزارشات
|
||||
</div>
|
||||
</BasicButton>-->
|
||||
|
||||
<BasicButton
|
||||
class="mt-2 w-full border-0 px0 configButton configIcon"
|
||||
:class="setActionSheetItemColor('home')"
|
||||
icon="vuesax-linear:convertshape"
|
||||
icon-size="16"
|
||||
@click="stopSheet('transfer')"
|
||||
>
|
||||
<BasicIcon
|
||||
class="configIcon"
|
||||
icon="vuesax-linear:arrow-left-1"
|
||||
|
||||
/>
|
||||
<div class="flex w-full justify-right" >
|
||||
برداشت
|
||||
</div>
|
||||
</BasicButton>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import {computed, onMounted, ref, watch} from "vue";
|
||||
import router from "@/router";
|
||||
import { openResult, openConfirm, rejectOrder, confirmOrder, orderResult, stsOfferInfo } from '@/utils/order'
|
||||
import BasicActionSheet from "@/components/BasicPacks/BasicActionSheet.vue";
|
||||
import { useUserStore } from '@/store/user'
|
||||
// const { prefixCls } = usePrefix('settin-users')
|
||||
const store = useUserStore()
|
||||
const emit = defineEmits(['close'])
|
||||
const currentRoute = computed(() => router.currentRoute.value.name)
|
||||
const stopSheet=(routeName:string)=>{
|
||||
router.push({name: routeName})
|
||||
emit('close')
|
||||
}
|
||||
function setActionSheetItemColor(val: string) {
|
||||
if (currentRoute.value === val) {
|
||||
return '!text-primary !bg-blue-50'
|
||||
} else if (val === '') {
|
||||
return '!text-red !bg-red-50'
|
||||
} else {
|
||||
return 'text-gray-400'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped lang="less">
|
||||
@prefix: ~'@{prefixCls}-settin-users';
|
||||
.@{prefix} {
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
<template>
|
||||
<div :class="[prefixCls]">
|
||||
<div class="flex flex-col gap-4">
|
||||
<div
|
||||
class="flex justify-between items-center p-4 backUserSetting2 textColor1 rounded-md"
|
||||
>
|
||||
<div class="flex gap-1 items-center">
|
||||
<Icon icon="vuesax-linear:user" class="iconUserSetting" />
|
||||
<span class="text-base font-bold">{{ userStore.user?.name }}</span>
|
||||
</div>
|
||||
<ATag class="border-none px-6 py-[6px] font-semibold buttonLogin">{{
|
||||
userStore.user?.type_str
|
||||
}}</ATag>
|
||||
</div>
|
||||
<div>
|
||||
<div v-if="userStore.user?.item && baseURL !== 'https://emexgold.com'" class="p-2 border-1px border-gray-100 rounded">
|
||||
<div class="">لینک درگاه:</div>
|
||||
<div class="mb-2 flex gap-2 w-full justify-between items-center mt-1" ref="url">
|
||||
<a :href="`https://www.payping.ir/d/${userStore.user?.item}`"
|
||||
target="_blank">{{ `https://www.payping.ir/d/${userStore.user?.item}` }}</a>
|
||||
<BasicIcon v-if="userStore.user?.item" icon="vuesax-linear:copy" class="cursor-pointer"
|
||||
@click="copyText(`https://www.payping.ir/d/${userStore.user?.item}`)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="userStore.user?.deposit_id" class="p-2 border-1px border-gray-100 rounded mt-2">
|
||||
<div class="">شناسه:</div>
|
||||
<div class="w-full justify-between items-center flex mt-1">
|
||||
<div class="mb-2">{{ userStore.user?.deposit_id ?? '_' }}</div>
|
||||
<BasicIcon v-if="userStore.user.deposit_id" icon="vuesax-linear:copy" color="#2563EB"
|
||||
class="cursor-pointer"
|
||||
@click="copyText(userStore.user?.deposit_id)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex justify-between items-center p-4 rounded-md backUserSetting2 cursor-pointer hover:bg-gray-100"
|
||||
@click="router.push({ name: 'profile' })"
|
||||
>
|
||||
<div class="flex gap-4 items-center">
|
||||
<Icon icon="vuesax-linear:user-edit" class="iconUserSetting"/>
|
||||
<span class="text-base font-medium textColor1">اطلاعات کاربری</span>
|
||||
</div>
|
||||
<icon icon="vuesax-linear:arrow-left-1" class="iconUserSetting" />
|
||||
</div>
|
||||
<div
|
||||
class="flex justify-between items-center p-4 rounded-md backUserSetting2 cursor-pointer hover:bg-gray-100"
|
||||
@click="router.push({ name: 'security' })"
|
||||
>
|
||||
<div class="flex gap-4 items-center">
|
||||
<Icon icon="vuesax-linear:shield-tick" class="iconUserSetting" />
|
||||
<span class="text-base font-medium textColor1">امنیت</span>
|
||||
</div>
|
||||
<icon icon="vuesax-linear:arrow-left-1" class="iconUserSetting" />
|
||||
</div>
|
||||
<div
|
||||
v-if="userStore.user?.type_str === 'نماینده' "
|
||||
class="flex justify-between items-center p-4 rounded-md backUserSetting2 cursor-pointer hover:bg-gray-100"
|
||||
@click="router.push({ name: 'packages' })"
|
||||
>
|
||||
<div class="flex gap-4 items-center">
|
||||
<Icon icon="vuesax-linear:setting-2" class="iconUserSetting" />
|
||||
<span class="text-base font-medium textColor1">تنظیمات قیمت</span>
|
||||
</div>
|
||||
<icon icon="vuesax-linear:arrow-left-1" class="iconUserSetting" />
|
||||
</div>
|
||||
<div
|
||||
class="flex justify-between items-center p-4 rounded-md backUserSetting2 cursor-pointer hover:bg-gray-100"
|
||||
@click="exit"
|
||||
>
|
||||
<div class="flex gap-4 items-center">
|
||||
<Icon icon="vuesax-linear:login" class="iconUserSetting" />
|
||||
<span class="text-base font-medium textColor1">خروج</span>
|
||||
</div>
|
||||
<icon icon="vuesax-linear:arrow-left-1" class="iconUserSetting" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { usePrefix } from '@/composable/usePrefix'
|
||||
import router from '@/router'
|
||||
import Icon from '@/components/Icon.vue'
|
||||
import { message, Modal } from 'ant-design-vue'
|
||||
import { useUserStore } from '@/store/user'
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
const { prefixCls } = usePrefix('user-setting')
|
||||
const userStore = useUserStore()
|
||||
const baseURL = ref(window.location.origin)
|
||||
const exit = () => {
|
||||
Modal.confirm({
|
||||
title: 'آیا میخواهید از برنامه خارج شوید؟',
|
||||
okText: 'بی خیال',
|
||||
okType: 'default',
|
||||
okButtonProps: {
|
||||
class: 'exitButton'
|
||||
},
|
||||
cancelText: 'بله',
|
||||
cancelButtonProps: { type: 'primary', danger: true },
|
||||
onOk() {
|
||||
console.log('logout canceled')
|
||||
},
|
||||
onCancel() {
|
||||
userStore.logout()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function copyText(val: string) {
|
||||
// nextTick(() => {
|
||||
navigator.clipboard.writeText(val)
|
||||
message.info('لینک رونوشت شد')
|
||||
// })
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@prefix: ~'@{prefixCls}-user-setting';
|
||||
|
||||
.@{prefix} {
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
import { baseURL } from '@/themeConfig'
|
||||
import axios from 'axios'
|
||||
import type { AxiosRequestConfig, AxiosResponse } from 'axios'
|
||||
import { getToken, removeToken } from '@/utils'
|
||||
import router from '@/router'
|
||||
import { get } from 'lodash'
|
||||
import { message } from 'ant-design-vue'
|
||||
|
||||
interface Meta {
|
||||
errorMessage?: 'message' | 'notification' | 'toast' | 'none'
|
||||
}
|
||||
|
||||
interface MyAxiosRequestConfig<D = any> extends AxiosRequestConfig<D> {
|
||||
meta?: Meta
|
||||
}
|
||||
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json'
|
||||
}
|
||||
|
||||
const _axios = axios.create({
|
||||
baseURL,
|
||||
headers
|
||||
})
|
||||
|
||||
_axios.interceptors.request.use(
|
||||
(config) => {
|
||||
//console.log('request config', config)
|
||||
if (config.headers) {
|
||||
const token = getToken()
|
||||
if (token) {
|
||||
//@ts-ignore
|
||||
config.headers['Authorization'] = 'Bearer ' + token
|
||||
}
|
||||
}
|
||||
return config
|
||||
},
|
||||
(error) => {
|
||||
//console.log('this is error on interceptors.request', error)
|
||||
Promise.reject(error)
|
||||
}
|
||||
)
|
||||
_axios.interceptors.response.use(
|
||||
(response) => {
|
||||
//console.log('this is response')
|
||||
// Any status code that lie within the range of 2xx cause this function to trigger
|
||||
// Do something with response data
|
||||
// console.log('this is fulfilled on interceptors.response', response.data)
|
||||
return response.data
|
||||
},
|
||||
function (error) {
|
||||
console.log('this is axios error', error)
|
||||
if (error.response.data && error.response.data.message) {
|
||||
checkStatus(error.response.data.message, error.response.status, error.config)
|
||||
}
|
||||
|
||||
//console.log('this is error on interceptors.response', error.config.meta)
|
||||
if (error.response && (error.response.status == 401)) {
|
||||
//debugger
|
||||
removeToken()
|
||||
router.push({ name: 'login' })
|
||||
}
|
||||
// Any status codes that falls outside the range of 2xx cause this function to trigger
|
||||
// Do something with response error
|
||||
|
||||
//const { response, code, message, config } = error || {}
|
||||
//const errorMessageMode = config?.requestOptions?.errorMessageMode || 'none'
|
||||
//const msg: string = response?.data?.error?.message ?? ''
|
||||
//checkStatus(error?.response?.status, msg)
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
function checkStatus(msg: string, code: number, config: any) {
|
||||
//const { code, data, message } = data
|
||||
const errorMessage = get(config, 'meta.errorMessage', 'message')
|
||||
/*if (config.meta) {
|
||||
if (config.meta.message) {
|
||||
errorMessage = config.meta.message
|
||||
}
|
||||
}*/
|
||||
if (errorMessage == 'none') return
|
||||
switch (errorMessage) {
|
||||
case 'message':
|
||||
message.error(msg)
|
||||
break
|
||||
default:
|
||||
message.error(msg)
|
||||
}
|
||||
}
|
||||
|
||||
const myAxios = {
|
||||
//AxiosResponse<T>
|
||||
post<T = any, R = T, D = any>(
|
||||
url: string,
|
||||
data?: D,
|
||||
config?: MyAxiosRequestConfig<D>
|
||||
): Promise<R> {
|
||||
return _axios.post(url, data, config)
|
||||
},
|
||||
request<T = any, R = AxiosResponse<T>, D = any>(config: MyAxiosRequestConfig<D>): Promise<R> {
|
||||
return _axios.request(config)
|
||||
},
|
||||
//AxiosResponse<T>
|
||||
get<T = any, R = T, D = any>(url: string, config?: MyAxiosRequestConfig<D>): Promise<R> {
|
||||
return _axios.get(url, config)
|
||||
},
|
||||
//AxiosResponse<T>
|
||||
delete<T = any, R = T, D = any>(url: string, config?: MyAxiosRequestConfig<D>): Promise<R> {
|
||||
return _axios.delete(url, config)
|
||||
},
|
||||
//AxiosResponse<T>
|
||||
head<T = any, R = T, D = any>(url: string, config?: MyAxiosRequestConfig<D>): Promise<R> {
|
||||
return _axios.head(url, config)
|
||||
},
|
||||
//AxiosResponse<T>
|
||||
options<T = any, R = T, D = any>(url: string, config?: MyAxiosRequestConfig<D>): Promise<R> {
|
||||
return _axios.options(url, config)
|
||||
},
|
||||
//AxiosResponse<T>
|
||||
put<T = any, R = T, D = any>(
|
||||
url: string,
|
||||
data?: D,
|
||||
config?: MyAxiosRequestConfig<D>
|
||||
): Promise<R> {
|
||||
return _axios.put(url, data, config)
|
||||
},
|
||||
//AxiosResponse<T>
|
||||
patch<T = any, R = T, D = any>(
|
||||
url: string,
|
||||
data?: D,
|
||||
config?: MyAxiosRequestConfig<D>
|
||||
): Promise<R> {
|
||||
return _axios.patch(url, data, config)
|
||||
},
|
||||
//AxiosResponse<T>
|
||||
postForm<T = any, R = T, D = any>(
|
||||
url: string,
|
||||
data?: D,
|
||||
config?: MyAxiosRequestConfig<D>
|
||||
): Promise<R> {
|
||||
return _axios.postForm(url, data, config)
|
||||
},
|
||||
//AxiosResponse<T>
|
||||
putForm<T = any, R = T, D = any>(
|
||||
url: string,
|
||||
data?: D,
|
||||
config?: MyAxiosRequestConfig<D>
|
||||
): Promise<R> {
|
||||
return _axios.putForm(url, data, config)
|
||||
},
|
||||
//AxiosResponse<T>
|
||||
patchForm<T = any, R = T, D = any>(
|
||||
url: string,
|
||||
data?: D,
|
||||
config?: MyAxiosRequestConfig<D>
|
||||
): Promise<R> {
|
||||
return _axios.patchForm(url, data, config)
|
||||
}
|
||||
}
|
||||
|
||||
export default myAxios
|
||||
export { _axios }
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
import {onMounted, ref} from 'vue'
|
||||
import moment from 'moment'
|
||||
//sample 00:30 - 1:50 - 00:59
|
||||
export default function useCountdownTimer(_startTime = '00:00:30', format = 'HH:mm:ss', _endTime = '00:00:00', fromNow = false) {
|
||||
let interval: number
|
||||
let startTime = moment(_startTime, 'HH:mm:ss')
|
||||
//const isActiveMenu=
|
||||
const endTime = moment(_endTime, 'HH:mm:ss')
|
||||
const time = ref('')
|
||||
let tempHook: () => void
|
||||
let tempHookStop: () => void
|
||||
let tempHookStart: () => void
|
||||
let tempHookRestart: () => void
|
||||
|
||||
function decrement() {
|
||||
if (!fromNow) {
|
||||
if (startTime > endTime) {
|
||||
startTime.subtract('1', 'second')
|
||||
time.value = startTime.format(format)
|
||||
} else {
|
||||
clearInterval(interval)
|
||||
if (tempHook) {
|
||||
tempHook()
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
const nowTime = moment().format(format)
|
||||
time.value = moment(nowTime).fromNow(true)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function start() {
|
||||
if (interval) {
|
||||
stop()
|
||||
}
|
||||
interval = setInterval(decrement, 1000)
|
||||
if (tempHookStart) {
|
||||
tempHookStart()
|
||||
}
|
||||
}
|
||||
|
||||
function stop() {
|
||||
clearInterval(interval)
|
||||
if (tempHookStop) {
|
||||
tempHookStop()
|
||||
}
|
||||
}
|
||||
|
||||
function onFinish(hook: () => any) {
|
||||
tempHook = hook
|
||||
}
|
||||
|
||||
function setTime(_time = '00:00:30') {
|
||||
startTime = moment(_time, 'HH:mm:ss')
|
||||
time.value = startTime.format(format)
|
||||
stop()
|
||||
start()
|
||||
}
|
||||
|
||||
function reset() {
|
||||
startTime = moment(_startTime, 'HH:mm:ss')
|
||||
time.value = startTime.format(format)
|
||||
stop()
|
||||
start()
|
||||
if (tempHookRestart) {
|
||||
tempHookRestart()
|
||||
}
|
||||
}
|
||||
|
||||
function onStop(hook: () => any) {
|
||||
tempHookStop = hook
|
||||
}
|
||||
|
||||
function onStart(hook: () => any) {
|
||||
tempHookStart = hook
|
||||
}
|
||||
|
||||
function onRestart(hook: () => any) {
|
||||
tempHookRestart = hook
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
time.value = startTime.format(format)
|
||||
})
|
||||
|
||||
return {
|
||||
time,
|
||||
stop,
|
||||
start,
|
||||
onFinish,
|
||||
reset,
|
||||
setTime,
|
||||
onRestart,
|
||||
onStart,
|
||||
onStop,
|
||||
}
|
||||
}
|
||||
export function diffdateBySeconds(date:string){
|
||||
const fromTime= moment(date)
|
||||
// console.log(fromTime)
|
||||
const now=moment()
|
||||
// console.log(now)
|
||||
const seconds =fromTime.diff(now ,"seconds")
|
||||
// console.log(seconds)
|
||||
//
|
||||
// console.log(moment.duration(seconds ,"seconds" ))
|
||||
|
||||
const time ={
|
||||
years:moment.duration(seconds ,"seconds" ).years(),
|
||||
months:moment.duration(seconds ,"seconds" ).months(),
|
||||
days:moment.duration(seconds ,"seconds" ).days(),
|
||||
hours:moment.duration(seconds ,"seconds" ).hours(),
|
||||
minutes:moment.duration(seconds ,"seconds" ).minutes(),
|
||||
seconds:moment.duration(seconds ,"seconds" ).seconds(),
|
||||
}
|
||||
return {
|
||||
years:time.years>=10?time.years:`0${time.years}`,
|
||||
months:time.months>=10?time.months:`0${time.months}`,
|
||||
days:time.days>=10?time.days:`0${time.days}`,
|
||||
hours:time.hours>=10?time.hours:`0${time.hours}`,
|
||||
minutes:time.minutes>=10?time.minutes:`0${time.minutes}`,
|
||||
seconds:time.seconds>=10?time.seconds:`0${time.seconds}`,
|
||||
diffSeconds:seconds,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import { prefixCls } from '@/themeConfig'
|
||||
|
||||
export function usePrefix(name = '') {
|
||||
return {
|
||||
prefixVar: prefixCls,
|
||||
prefixCls: `${prefixCls}-${name}`
|
||||
}
|
||||
}
|
||||