Replace Ant Design Vue icons with a local admin Icon component.
Drop @ant-design/icons-vue and wire list pages, nav, and forms through the shared icons map. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -11,7 +11,6 @@
|
||||
"lint": "eslint \"src/**/*.{ts,vue}\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@ant-design/icons-vue": "^7.0.1",
|
||||
"@hedena-gold/shared-types": "workspace:*",
|
||||
"@vueuse/core": "^9.13.0",
|
||||
"ant-design-vue": "^4.2.6",
|
||||
|
||||
@@ -39,6 +39,15 @@
|
||||
--warning-color: #ff9f43;
|
||||
}
|
||||
|
||||
// Vuesax Icon spin (replaces ant LoadingOutlined / SyncOutlined animation)
|
||||
.icon-spin {
|
||||
display: inline-flex;
|
||||
animation: icon-spin 1s linear infinite;
|
||||
}
|
||||
@keyframes icon-spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
// ── Text colour ──────────────────────────────────────────────────────
|
||||
.text-primary { color: var(--primary-color); }
|
||||
.text-secondary { color: var(--secondary-color); }
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<div class="conn">
|
||||
<!-- ── status ─────────────────────────────────────────────── -->
|
||||
<div class="status" :class="`status--${status.tone}`">
|
||||
<component :is="status.icon" class="status__icon" />
|
||||
<Icon :icon="status.icon" class="status__icon" size="22" />
|
||||
<div class="status__body">
|
||||
<div class="status__title">
|
||||
{{ status.title }}
|
||||
@@ -82,7 +82,7 @@
|
||||
|
||||
<a-form-item label="توکن وبسرویس" required class="grid__full">
|
||||
<div v-if="tokenSaved && !editingToken[p]" class="token">
|
||||
<LockOutlined class="token__icon" />
|
||||
<Icon icon="vuesax-linear:lock" class="token__icon" size="18" />
|
||||
<span v-if="pub(p)?.tokenReadable">توکن ذخیره شده است و نمایش داده نمیشود.</span>
|
||||
<span v-else class="text-danger">توکن ذخیرهشده قابلخواندن نیست؛ دوباره وارد کنید.</span>
|
||||
<a-space class="token__actions">
|
||||
@@ -123,7 +123,7 @@
|
||||
|
||||
<!-- trusted (pinned) -->
|
||||
<div v-if="form[p].caCert" class="cert cert--ok">
|
||||
<SafetyCertificateOutlined class="cert__icon" />
|
||||
<Icon icon="vuesax-linear:security-safe" class="cert__icon" size="22" />
|
||||
<div class="cert__body">
|
||||
<div class="cert__title">
|
||||
گواهی سرور تأیید شده است
|
||||
@@ -148,7 +148,7 @@
|
||||
|
||||
<!-- just checked, waiting for a decision -->
|
||||
<div v-else-if="checked && !checked.trustedBySystem" class="cert cert--ask">
|
||||
<ExclamationCircleOutlined class="cert__icon" />
|
||||
<Icon icon="vuesax-linear:info-circle" class="cert__icon" size="22" />
|
||||
<div class="cert__body">
|
||||
<div class="cert__title">این گواهی را تأیید میکنید؟</div>
|
||||
<div class="help">اثرانگشت زیر را با گواهی نصبشده روی سرور حسابداری مقایسه کنید. اگر یکی است تأیید کنید.</div>
|
||||
@@ -170,7 +170,7 @@
|
||||
|
||||
<!-- public certificate: nothing to do -->
|
||||
<div v-else-if="checked?.trustedBySystem" class="cert cert--ok">
|
||||
<SafetyCertificateOutlined class="cert__icon" />
|
||||
<Icon icon="vuesax-linear:security-safe" class="cert__icon" size="22" />
|
||||
<div class="cert__body">
|
||||
<div class="cert__title">گواهی سرور معتبر است</div>
|
||||
<div class="help">این سرور گواهی معتبر عمومی دارد؛ کاری لازم نیست.</div>
|
||||
@@ -179,7 +179,7 @@
|
||||
|
||||
<!-- nothing yet -->
|
||||
<div v-else class="cert">
|
||||
<SafetyCertificateOutlined class="cert__icon cert__icon--muted" />
|
||||
<Icon icon="vuesax-linear:security-safe" class="cert__icon cert__icon--muted" size="22" />
|
||||
<div class="cert__body">
|
||||
<div class="cert__title">گواهیای تأیید نشده</div>
|
||||
<div class="help">اگر «تست اتصال» خطای گواهی داد، اینجا گواهی سرور را بررسی کنید.</div>
|
||||
@@ -236,16 +236,9 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive, ref, watch } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import {
|
||||
CheckCircleFilled,
|
||||
CloseCircleFilled,
|
||||
ExclamationCircleOutlined,
|
||||
LockOutlined,
|
||||
MinusCircleFilled,
|
||||
SafetyCertificateOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import moment from 'moment-jalaali';
|
||||
import api from '../../api/client';
|
||||
import Icon from '../icon/Icon.vue';
|
||||
|
||||
type ProviderName = 'tahesab' | 'zarrin';
|
||||
|
||||
@@ -301,24 +294,24 @@ interface StatusRow {
|
||||
const jdt = (v?: string | null) => (v ? moment(v).format('jYYYY/jMM/jDD ساعت HH:mm') : '');
|
||||
const status = computed(() => {
|
||||
const ov = props.overview;
|
||||
if (!ov) return { tone: 'off', icon: MinusCircleFilled, title: '…', text: '', rows: [] as StatusRow[] };
|
||||
if (!ov) return { tone: 'off', icon: 'vuesax-linear:minus-cirlce', title: '…', text: '', rows: [] as StatusRow[] };
|
||||
const c = ov.config;
|
||||
if (c.provider === 'none') {
|
||||
return { tone: 'off', icon: MinusCircleFilled, title: 'اتصال خاموش است', text: 'هیچ اطلاعاتی با نرمافزار حسابداری رد و بدل نمیشود.' };
|
||||
return { tone: 'off', icon: 'vuesax-linear:minus-cirlce', title: 'اتصال خاموش است', text: 'هیچ اطلاعاتی با نرمافزار حسابداری رد و بدل نمیشود.' };
|
||||
}
|
||||
const label = LABEL[c.provider as ProviderName];
|
||||
if (ov.inactiveReason) {
|
||||
return { tone: 'bad', icon: CloseCircleFilled, title: `اتصال به ${label} کار نمیکند`, text: ov.inactiveReason };
|
||||
return { tone: 'bad', icon: 'vuesax-linear:close-circle', title: `اتصال به ${label} کار نمیکند`, text: ov.inactiveReason };
|
||||
}
|
||||
const rt = ov.realtime;
|
||||
if (rt?.lastError) {
|
||||
return { tone: 'bad', icon: CloseCircleFilled, title: `${label}: ارتباط برقرار نیست`, text: rt.lastError };
|
||||
return { tone: 'bad', icon: 'vuesax-linear:close-circle', title: `${label}: ارتباط برقرار نیست`, text: rt.lastError };
|
||||
}
|
||||
const conn = c[c.provider];
|
||||
const rows: StatusRow[] = [{ label: 'آدرس', value: conn.baseUrl, ltr: true }];
|
||||
if (c.provider === 'tahesab') rows.push({ label: 'دیتابیس', value: c.tahesab.dbName, ltr: true });
|
||||
if (rt?.lastOkAt) rows.push({ label: 'آخرین ارتباط موفق', value: jdt(rt.lastOkAt) });
|
||||
return { tone: 'ok', icon: CheckCircleFilled, title: `متصل به ${label}`, text: '', rows };
|
||||
return { tone: 'ok', icon: 'vuesax-linear:tick-circle', title: `متصل به ${label}`, text: '', rows };
|
||||
});
|
||||
|
||||
// ── token ──
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
sync on the server, waits for it and reports what happened.
|
||||
-->
|
||||
<a-button v-if="connected" :loading="busy" @click="run">
|
||||
<template #icon><SyncOutlined /></template>
|
||||
<template #icon><Icon icon="vuesax-linear:refresh-2" size="16" class="icon-spin" /></template>
|
||||
سینک با {{ provider || 'حسابداری' }}
|
||||
</a-button>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../icon/Icon.vue';
|
||||
import { h, onMounted, ref } from 'vue';
|
||||
import { Modal, message } from 'ant-design-vue';
|
||||
import { SyncOutlined } from '@ant-design/icons-vue';
|
||||
import api from '../../api/client';
|
||||
|
||||
const props = defineProps<{ endpoint: string }>();
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
search bar, rather than in a row of its own above the table.
|
||||
-->
|
||||
<a-button v-if="!rid || hasPermission(rid)" type="primary" @click="$emit('add')">
|
||||
<template #icon><PlusOutlined /></template>
|
||||
<template #icon><Icon icon="vuesax-linear:add" size="16" /></template>
|
||||
{{ addLabel }}
|
||||
</a-button>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { PlusOutlined } from '@ant-design/icons-vue';
|
||||
import Icon from '../icon/Icon.vue';
|
||||
import { useUsersStore } from '../../stores/users';
|
||||
|
||||
withDefaults(
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<span ref="refIcon" :style="{ color: color ?? undefined }" class="liman-icons" v-html="tempIcon"></span>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, nextTick, ref, watch } from 'vue'
|
||||
import icons from './icons.json'
|
||||
|
||||
interface Props {
|
||||
icon: string
|
||||
color?: string | null
|
||||
size?: string | number
|
||||
}
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
color: null,
|
||||
})
|
||||
const refIcon = ref<HTMLSpanElement>()
|
||||
|
||||
// FIXED: this used to be a plain ref, assigned once at setup —
|
||||
// tempIcon.value = icons[props.icon]
|
||||
// — instead of a computed. Vue reuses the same component instance across
|
||||
// re-renders when an `Icon` sits in the same template position (which every
|
||||
// caller in this app does; none pass a `:key` keyed to the icon name), so
|
||||
// setup only runs once per mount and that assignment never ran again. Any
|
||||
// caller that swaps `icon` on an already-mounted instance — the exact pattern
|
||||
// the cart quantity steppers use, `:icon="qty === 1 ? 'trash' : 'minus'"` —
|
||||
// had its SVG freeze on whichever icon happened to render first and silently
|
||||
// stop tracking the prop after that: incrementing a cart line past 1 never
|
||||
// swapped the frozen trash glyph back to minus, and the reverse (decrementing
|
||||
// back down to 1) never swapped a frozen minus back to trash either. A
|
||||
// computed re-evaluates on every `icon` change, so the markup — and, via the
|
||||
// watcher below, the width/height attributes size() sets on it — now actually
|
||||
// track the prop instead of only reading it once.
|
||||
const tempIcon = computed(() => (icons as Record<string, string>)[`${props.icon}`])
|
||||
|
||||
function applySize() {
|
||||
if (!props.size) return
|
||||
const svg = refIcon.value?.children[0] as SVGElement | undefined
|
||||
svg?.setAttribute('width', props.size as string)
|
||||
svg?.setAttribute('height', props.size as string)
|
||||
}
|
||||
|
||||
// v-html replaces refIcon's children synchronously with the DOM update, but
|
||||
// that update itself is queued — nextTick() waits for it so applySize() finds
|
||||
// the new <svg> already in the DOM rather than the previous one (or none, on
|
||||
// the very first render).
|
||||
watch(tempIcon, () => nextTick(applySize), { immediate: true })
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.liman-icons {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
line-height: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.liman-icons :deep(svg path) {
|
||||
stroke: currentColor;
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because one or more lines are too long
@@ -1,81 +1,159 @@
|
||||
// Shared legacy-Feather-name -> ant-design-vue icon map.
|
||||
// Shared legacy-Feather-name -> Vuesax Linear icon id map.
|
||||
//
|
||||
// Originally lived only inside TooltipBtn.vue (row-action icons). Extracted
|
||||
// here so the sidebar (navMenuItems.ts icon: values) can resolve the SAME
|
||||
// names through the SAME map instead of duplicating it — one source of
|
||||
// truth for "legacy Feather icon name" -> "ant component" across the app.
|
||||
import {
|
||||
AppstoreOutlined,
|
||||
BarChartOutlined,
|
||||
BellOutlined,
|
||||
BlockOutlined,
|
||||
BookOutlined,
|
||||
CameraOutlined,
|
||||
CheckOutlined,
|
||||
CloseOutlined,
|
||||
CreditCardOutlined,
|
||||
DeleteOutlined,
|
||||
DollarOutlined,
|
||||
EditOutlined,
|
||||
EyeOutlined,
|
||||
FileOutlined,
|
||||
FileTextOutlined,
|
||||
GiftOutlined,
|
||||
HomeOutlined,
|
||||
InboxOutlined,
|
||||
MailOutlined,
|
||||
MessageOutlined,
|
||||
PercentageOutlined,
|
||||
PlusOutlined,
|
||||
SettingOutlined,
|
||||
ShoppingOutlined,
|
||||
StopOutlined,
|
||||
TeamOutlined,
|
||||
UnorderedListOutlined,
|
||||
UserAddOutlined,
|
||||
UserOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
|
||||
/** legacy Feather name -> ant component. */
|
||||
export const ICONS: Record<string, unknown> = {
|
||||
// Originally Feather names mapped to @ant-design/icons-vue components.
|
||||
// Now they resolve to the same `vuesax-linear:*` pack used by the user-app
|
||||
// Icon component, so sidebar (navMenuItems.ts) and TooltipBtn share one
|
||||
// string map instead of Ant components.
|
||||
export const ICONS: Record<string, string> = {
|
||||
// row-action icons (TooltipBtn.vue's original set)
|
||||
ListIcon: UnorderedListOutlined,
|
||||
FileIcon: FileOutlined,
|
||||
TrashIcon: DeleteOutlined,
|
||||
EditIcon: EditOutlined,
|
||||
CheckIcon: CheckOutlined,
|
||||
CameraIcon: CameraOutlined,
|
||||
EyeIcon: EyeOutlined,
|
||||
PlusIcon: PlusOutlined,
|
||||
XIcon: CloseOutlined,
|
||||
FileTextIcon: FileTextOutlined,
|
||||
ListIcon: 'vuesax-linear:row-vertical',
|
||||
FileIcon: 'vuesax-linear:document',
|
||||
TrashIcon: 'vuesax-linear:trash',
|
||||
EditIcon: 'vuesax-linear:edit-2',
|
||||
CheckIcon: 'vuesax-linear:tick-circle',
|
||||
CameraIcon: 'vuesax-linear:camera',
|
||||
EyeIcon: 'vuesax-linear:eye',
|
||||
PlusIcon: 'vuesax-linear:add',
|
||||
XIcon: 'vuesax-linear:close-circle',
|
||||
FileTextIcon: 'vuesax-linear:document-text',
|
||||
|
||||
// sidebar icons (navMenuItems.ts), added when the sidebar started
|
||||
// rendering them for the first time
|
||||
HomeIcon: HomeOutlined,
|
||||
PackageIcon: InboxOutlined,
|
||||
UserIcon: UserOutlined,
|
||||
UsersIcon: TeamOutlined,
|
||||
UserPlusIcon: UserAddOutlined,
|
||||
ShoppingBagIcon: ShoppingOutlined,
|
||||
BoxIcon: InboxOutlined,
|
||||
GridIcon: AppstoreOutlined,
|
||||
LayersIcon: BlockOutlined,
|
||||
CreditCardIcon: CreditCardOutlined,
|
||||
DollarSignIcon: DollarOutlined,
|
||||
PercentIcon: PercentageOutlined,
|
||||
GiftIcon: GiftOutlined,
|
||||
SlashIcon: StopOutlined,
|
||||
BookIcon: BookOutlined,
|
||||
MessageSquareIcon: MessageOutlined,
|
||||
MailIcon: MailOutlined,
|
||||
BellIcon: BellOutlined,
|
||||
BarChartIcon: BarChartOutlined,
|
||||
SettingsIcon: SettingOutlined,
|
||||
InboxIcon: InboxOutlined,
|
||||
// sidebar icons (navMenuItems.ts)
|
||||
HomeIcon: 'vuesax-linear:home-2',
|
||||
PackageIcon: 'vuesax-linear:box',
|
||||
UserIcon: 'vuesax-linear:user',
|
||||
UsersIcon: 'vuesax-linear:people',
|
||||
UserPlusIcon: 'vuesax-linear:user-add',
|
||||
ShoppingBagIcon: 'vuesax-linear:bag-2',
|
||||
BoxIcon: 'vuesax-linear:box-1',
|
||||
GridIcon: 'vuesax-linear:category-2',
|
||||
LayersIcon: 'vuesax-linear:layer',
|
||||
CreditCardIcon: 'vuesax-linear:card',
|
||||
DollarSignIcon: 'vuesax-linear:dollar-circle',
|
||||
PercentIcon: 'vuesax-linear:percentage-square',
|
||||
GiftIcon: 'vuesax-linear:gift',
|
||||
SlashIcon: 'vuesax-linear:slash',
|
||||
BookIcon: 'vuesax-linear:book',
|
||||
MessageSquareIcon: 'vuesax-linear:message-text',
|
||||
MailIcon: 'vuesax-linear:sms',
|
||||
BellIcon: 'vuesax-linear:notification',
|
||||
BarChartIcon: 'vuesax-linear:chart',
|
||||
SettingsIcon: 'vuesax-linear:setting-2',
|
||||
InboxIcon: 'vuesax-linear:box',
|
||||
};
|
||||
|
||||
export function resolveIcon(name: string | undefined): unknown | undefined {
|
||||
/** Direct Ant Design icon component name → Vuesax id (for view migrations). */
|
||||
export const ANT_TO_VUESAX: Record<string, string> = {
|
||||
EditOutlined: 'vuesax-linear:edit-2',
|
||||
DeleteOutlined: 'vuesax-linear:trash',
|
||||
EyeOutlined: 'vuesax-linear:eye',
|
||||
PlusOutlined: 'vuesax-linear:add',
|
||||
CloseOutlined: 'vuesax-linear:close-circle',
|
||||
CheckOutlined: 'vuesax-linear:tick-circle',
|
||||
SearchOutlined: 'vuesax-linear:search-normal-1',
|
||||
SettingOutlined: 'vuesax-linear:setting-2',
|
||||
UserOutlined: 'vuesax-linear:user',
|
||||
TeamOutlined: 'vuesax-linear:people',
|
||||
UserAddOutlined: 'vuesax-linear:user-add',
|
||||
HomeOutlined: 'vuesax-linear:home-2',
|
||||
InboxOutlined: 'vuesax-linear:box',
|
||||
AppstoreOutlined: 'vuesax-linear:category-2',
|
||||
ShoppingOutlined: 'vuesax-linear:bag-2',
|
||||
CreditCardOutlined: 'vuesax-linear:card',
|
||||
DollarOutlined: 'vuesax-linear:dollar-circle',
|
||||
PercentageOutlined: 'vuesax-linear:percentage-square',
|
||||
GiftOutlined: 'vuesax-linear:gift',
|
||||
StopOutlined: 'vuesax-linear:slash',
|
||||
BookOutlined: 'vuesax-linear:book',
|
||||
MessageOutlined: 'vuesax-linear:message-text',
|
||||
MailOutlined: 'vuesax-linear:sms',
|
||||
BellOutlined: 'vuesax-linear:notification',
|
||||
BarChartOutlined: 'vuesax-linear:chart',
|
||||
FileOutlined: 'vuesax-linear:document',
|
||||
FileTextOutlined: 'vuesax-linear:document-text',
|
||||
UnorderedListOutlined: 'vuesax-linear:row-vertical',
|
||||
CameraOutlined: 'vuesax-linear:camera',
|
||||
BlockOutlined: 'vuesax-linear:layer',
|
||||
CloudUploadOutlined: 'vuesax-linear:document-upload',
|
||||
UploadOutlined: 'vuesax-linear:document-upload',
|
||||
LoadingOutlined: 'vuesax-linear:refresh-2',
|
||||
MenuFoldOutlined: 'vuesax-linear:menu',
|
||||
MenuUnfoldOutlined: 'vuesax-linear:menu',
|
||||
LogoutOutlined: 'vuesax-linear:logout',
|
||||
SafetyCertificateOutlined: 'vuesax-linear:security-safe',
|
||||
LockOutlined: 'vuesax-linear:lock',
|
||||
MobileOutlined: 'vuesax-linear:mobile',
|
||||
ExclamationCircleOutlined: 'vuesax-linear:info-circle',
|
||||
InfoCircleOutlined: 'vuesax-linear:info-circle',
|
||||
WarningOutlined: 'vuesax-linear:warning-2',
|
||||
ArrowLeftOutlined: 'vuesax-linear:arrow-left',
|
||||
ArrowRightOutlined: 'vuesax-linear:arrow-right',
|
||||
FilterOutlined: 'vuesax-linear:filter',
|
||||
DownloadOutlined: 'vuesax-linear:document-download',
|
||||
ExportOutlined: 'vuesax-linear:export',
|
||||
ImportOutlined: 'vuesax-linear:import',
|
||||
SyncOutlined: 'vuesax-linear:refresh-2',
|
||||
ReloadOutlined: 'vuesax-linear:refresh-2',
|
||||
EnvironmentOutlined: 'vuesax-linear:location',
|
||||
PhoneOutlined: 'vuesax-linear:call',
|
||||
CalendarOutlined: 'vuesax-linear:calendar',
|
||||
ClockCircleOutlined: 'vuesax-linear:clock',
|
||||
CopyOutlined: 'vuesax-linear:copy',
|
||||
SaveOutlined: 'vuesax-linear:save-2',
|
||||
PrinterOutlined: 'vuesax-linear:printer',
|
||||
LinkOutlined: 'vuesax-linear:link',
|
||||
MoreOutlined: 'vuesax-linear:more',
|
||||
EllipsisOutlined: 'vuesax-linear:more',
|
||||
DownOutlined: 'vuesax-linear:arrow-down',
|
||||
UpOutlined: 'vuesax-linear:arrow-up',
|
||||
LeftOutlined: 'vuesax-linear:arrow-left',
|
||||
RightOutlined: 'vuesax-linear:arrow-right',
|
||||
CaretDownOutlined: 'vuesax-linear:arrow-down',
|
||||
CaretUpOutlined: 'vuesax-linear:arrow-up',
|
||||
MinusOutlined: 'vuesax-linear:minus',
|
||||
MinusCircleOutlined: 'vuesax-linear:minus-cirlce',
|
||||
PlusCircleOutlined: 'vuesax-linear:add-circle',
|
||||
CheckCircleOutlined: 'vuesax-linear:tick-circle',
|
||||
CloseCircleOutlined: 'vuesax-linear:close-circle',
|
||||
QuestionCircleOutlined: 'vuesax-linear:message-question',
|
||||
StarOutlined: 'vuesax-linear:star',
|
||||
HeartOutlined: 'vuesax-linear:heart',
|
||||
PictureOutlined: 'vuesax-linear:gallery',
|
||||
PaperClipOutlined: 'vuesax-linear:paperclip-2',
|
||||
SendOutlined: 'vuesax-linear:send-2',
|
||||
WalletOutlined: 'vuesax-linear:wallet-2',
|
||||
ShopOutlined: 'vuesax-linear:shop',
|
||||
BankOutlined: 'vuesax-linear:bank',
|
||||
TagOutlined: 'vuesax-linear:tag',
|
||||
TagsOutlined: 'vuesax-linear:tag-2',
|
||||
DashboardOutlined: 'vuesax-linear:element-3',
|
||||
ProfileOutlined: 'vuesax-linear:profile',
|
||||
IdcardOutlined: 'vuesax-linear:personalcard',
|
||||
SolutionOutlined: 'vuesax-linear:briefcase',
|
||||
AuditOutlined: 'vuesax-linear:clipboard-text',
|
||||
FormOutlined: 'vuesax-linear:edit',
|
||||
TableOutlined: 'vuesax-linear:grid-6',
|
||||
DatabaseOutlined: 'vuesax-linear:data',
|
||||
ApiOutlined: 'vuesax-linear:code',
|
||||
ToolOutlined: 'vuesax-linear:setting',
|
||||
ClearOutlined: 'vuesax-linear:broom',
|
||||
RetweetOutlined: 'vuesax-linear:arrange-square-2',
|
||||
SwapOutlined: 'vuesax-linear:arrow-swap-horizontal',
|
||||
HistoryOutlined: 'vuesax-linear:clock',
|
||||
FieldTimeOutlined: 'vuesax-linear:timer',
|
||||
RiseOutlined: 'vuesax-linear:chart-2',
|
||||
FallOutlined: 'vuesax-linear:chart-1',
|
||||
PoweroffOutlined: 'vuesax-linear:logout',
|
||||
LoginOutlined: 'vuesax-linear:login',
|
||||
KeyOutlined: 'vuesax-linear:key',
|
||||
UnlockOutlined: 'vuesax-linear:unlock',
|
||||
};
|
||||
|
||||
export function resolveIcon(name: string | undefined): string | undefined {
|
||||
if (!name) return undefined;
|
||||
return ICONS[name];
|
||||
}
|
||||
|
||||
export function resolveAntIcon(name: string | undefined): string | undefined {
|
||||
if (!name) return undefined;
|
||||
return ANT_TO_VUESAX[name] ?? ICONS[name];
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<a-card class="stat-card" :bordered="true">
|
||||
<div class="stat-row">
|
||||
<span class="stat-icon">
|
||||
<component :is="iconComponent" />
|
||||
<Icon :icon="iconId" size="20" />
|
||||
</span>
|
||||
<div class="stat-copy">
|
||||
<span class="stat-title">{{ statisticTitle }}</span>
|
||||
@@ -19,13 +19,8 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import {
|
||||
ShoppingOutlined,
|
||||
TeamOutlined,
|
||||
DollarOutlined,
|
||||
BarChartOutlined,
|
||||
CreditCardOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import { resolveIcon } from '../icons';
|
||||
import Icon from '../icon/Icon.vue';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
@@ -40,16 +35,7 @@ const props = withDefaults(
|
||||
{ color: 'primary', hideChart: true },
|
||||
);
|
||||
|
||||
/** feather name -> ant icon, matching the icons the live cards ask for */
|
||||
const ICONS: Record<string, unknown> = {
|
||||
UsersIcon: TeamOutlined,
|
||||
ShoppingBagIcon: ShoppingOutlined,
|
||||
DollarSignIcon: DollarOutlined,
|
||||
BarChartIcon: BarChartOutlined,
|
||||
CreditCardIcon: CreditCardOutlined,
|
||||
};
|
||||
|
||||
const iconComponent = computed(() => ICONS[props.icon ?? ''] ?? BarChartOutlined);
|
||||
const iconId = computed(() => resolveIcon(props.icon) ?? 'vuesax-linear:chart');
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
Same API (title, popTitle, icon, iconClass) and same behaviour: with popTitle
|
||||
it confirms first, without it fires immediately.
|
||||
|
||||
Legacy rendered <feather-icon icon="ListIcon">. vue-feather has no Vue 3
|
||||
build, so the feather NAME is mapped to an ant-design icon via the shared
|
||||
map in components/icons.ts (also used by the sidebar). Ported views keep
|
||||
writing icon="ListIcon" unchanged.
|
||||
Legacy rendered <feather-icon icon="ListIcon">. The feather NAME is mapped
|
||||
to a Vuesax Linear id via components/icons.ts (also used by the sidebar).
|
||||
Ported views keep writing icon="ListIcon" unchanged.
|
||||
-->
|
||||
<div>
|
||||
<a-tooltip :title="title">
|
||||
@@ -18,13 +17,14 @@
|
||||
:title="popTitle"
|
||||
@confirm="onClick"
|
||||
>
|
||||
<component :is="iconComponent" class="cursor-pointer" :class="iconClass" />
|
||||
<Icon :icon="iconId" class="cursor-pointer" :class="iconClass" size="18" />
|
||||
</a-popconfirm>
|
||||
<div v-else>
|
||||
<component
|
||||
:is="iconComponent"
|
||||
<Icon
|
||||
:icon="iconId"
|
||||
class="cursor-pointer"
|
||||
:class="iconClass"
|
||||
size="18"
|
||||
@click="onClick"
|
||||
/>
|
||||
</div>
|
||||
@@ -34,8 +34,8 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { UnorderedListOutlined } from '@ant-design/icons-vue';
|
||||
import { resolveIcon } from '../icons';
|
||||
import Icon from '../icon/Icon.vue';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
@@ -49,7 +49,7 @@ const props = withDefaults(
|
||||
|
||||
const emit = defineEmits<{ (e: 'click'): void }>();
|
||||
|
||||
const iconComponent = computed(() => resolveIcon(props.icon) ?? UnorderedListOutlined);
|
||||
const iconId = computed(() => resolveIcon(props.icon) ?? 'vuesax-linear:row-vertical');
|
||||
|
||||
function onClick() {
|
||||
emit('click');
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
:before-upload="beforeUpload"
|
||||
>
|
||||
<div class="gallery-upload__zone">
|
||||
<CloudUploadOutlined class="gallery-upload__icon" />
|
||||
<Icon icon="vuesax-linear:document-upload" size="16" class="gallery-upload__icon" />
|
||||
<p class="gallery-upload__title">{{ placeholder }}</p>
|
||||
<p class="gallery-upload__hint">
|
||||
تصاویر را اینجا بکشید و رها کنید یا کلیک کنید — انتخاب چند تصویر بهصورت همزمان امکانپذیر است
|
||||
@@ -37,10 +37,10 @@
|
||||
|
||||
<div v-else class="tile__overlay">
|
||||
<button type="button" class="tile__btn" title="نمایش" @click="preview(item)">
|
||||
<EyeOutlined />
|
||||
<Icon icon="vuesax-linear:eye" size="16" />
|
||||
</button>
|
||||
<button type="button" class="tile__btn tile__btn--danger" title="حذف" @click="remove(item.uid)">
|
||||
<DeleteOutlined />
|
||||
<Icon icon="vuesax-linear:trash" size="16" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -49,7 +49,7 @@
|
||||
<div v-if="items.length" class="gallery-upload__meta">
|
||||
<span>{{ doneCount }} تصویر</span>
|
||||
<span v-if="pendingCount" class="gallery-upload__pending">
|
||||
<LoadingOutlined /> در حال بارگذاری {{ pendingCount }} تصویر…
|
||||
<Icon icon="vuesax-linear:refresh-2" size="16" class="icon-spin" /> در حال بارگذاری {{ pendingCount }} تصویر…
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -60,9 +60,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../icon/Icon.vue';
|
||||
import { computed, onBeforeUnmount, ref, watch } from 'vue';
|
||||
import { message, Upload } from 'ant-design-vue';
|
||||
import { CloudUploadOutlined, DeleteOutlined, EyeOutlined, LoadingOutlined } from '@ant-design/icons-vue';
|
||||
import api from '../../api/client';
|
||||
|
||||
const props = withDefaults(
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<div v-if="fileList.length === 0">
|
||||
<a-spin v-if="uploading" size="small" />
|
||||
<div v-else>
|
||||
<plus-outlined />
|
||||
<Icon icon="vuesax-linear:add" size="16" />
|
||||
<div style="margin-top: 8px">{{ placeholder }}</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -36,9 +36,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../icon/Icon.vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { PlusOutlined } from '@ant-design/icons-vue';
|
||||
import api from '../../api/client';
|
||||
|
||||
const props = withDefaults(
|
||||
|
||||
@@ -27,20 +27,20 @@
|
||||
<a-badge v-if="!model._noFilters" :count="query.filters.length">
|
||||
<a-button type="text" :class="{ 'x-table__action--active': activeFilter }" @click="toggleVisibleFilter">
|
||||
فیلتر
|
||||
<template #icon><FilterOutlined /></template>
|
||||
<template #icon><Icon icon="vuesax-linear:filter" size="16" /></template>
|
||||
</a-button>
|
||||
</a-badge>
|
||||
|
||||
<a-tooltip title="چاپ">
|
||||
<a-button type="text" shape="circle">
|
||||
<template #icon><PrinterOutlined /></template>
|
||||
<template #icon><Icon icon="vuesax-linear:printer" size="16" /></template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
|
||||
<a-dropdown :trigger="['click']">
|
||||
<a-tooltip title="ستونها">
|
||||
<a-button type="text" shape="circle">
|
||||
<template #icon><SettingOutlined /></template>
|
||||
<template #icon><Icon icon="vuesax-linear:setting-2" size="16" /></template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<template #overlay>
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
<a-tooltip title="بارگذاری مجدد">
|
||||
<a-button class="refresh-btn" type="text" shape="circle" :loading="loading" @click="fetch()">
|
||||
<template #icon><ReloadOutlined /></template>
|
||||
<template #icon><Icon icon="vuesax-linear:refresh-2" size="16" class="icon-spin" /></template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
|
||||
@@ -217,8 +217,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../icon/Icon.vue';
|
||||
import { computed, onMounted, reactive, ref } from 'vue';
|
||||
import { FilterOutlined, PrinterOutlined, ReloadOutlined, SettingOutlined } from '@ant-design/icons-vue';
|
||||
import api from '../../api/client';
|
||||
import type { XTbl, Xtc } from './model';
|
||||
import { gridDate } from '../../utils/filters';
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
nests natively, the fixed two-level template just didn't recurse into it.
|
||||
-->
|
||||
<a-sub-menu v-if="node.submenu" :key="menuKey" popup-class-name="nav-popup">
|
||||
<template #icon><component :is="resolveIcon(node.icon)" v-if="node.icon" /></template>
|
||||
<template #icon>
|
||||
<Icon v-if="iconId" :icon="iconId" size="18" />
|
||||
</template>
|
||||
<template #title>{{ node.i18n || node.name }}</template>
|
||||
<NavMenuNode
|
||||
v-for="(child, k) in visibleChildren(node.submenu)"
|
||||
@@ -17,19 +19,24 @@
|
||||
</a-sub-menu>
|
||||
|
||||
<a-menu-item v-else :key="menuKey">
|
||||
<template #icon><component :is="resolveIcon(node.icon)" v-if="node.icon" /></template>
|
||||
<template #icon>
|
||||
<Icon v-if="iconId" :icon="iconId" size="18" />
|
||||
</template>
|
||||
{{ node.i18n || node.name }}
|
||||
</a-menu-item>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { useUsersStore } from '../../stores/users';
|
||||
import { resolveIcon } from '../../components/icons';
|
||||
import Icon from '../../components/icon/Icon.vue';
|
||||
import type { NavMenuNode as NavMenuNodeType } from '../navMenuItems';
|
||||
|
||||
defineProps<{ node: NavMenuNodeType; menuKey: string }>();
|
||||
const props = defineProps<{ node: NavMenuNodeType; menuKey: string }>();
|
||||
|
||||
const users = useUsersStore();
|
||||
const iconId = computed(() => resolveIcon(props.node.icon));
|
||||
|
||||
// Same visibility rule as VerticalNavMenu.vue: no permissionId = always visible.
|
||||
function canSee(node: NavMenuNodeType): boolean {
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
<a-layout-header class="the-navbar">
|
||||
<div class="nav-left">
|
||||
<a-button type="text" @click="$emit('toggle-sidebar')">
|
||||
<MenuUnfoldOutlined v-if="collapsed" />
|
||||
<MenuFoldOutlined v-else />
|
||||
<Icon icon="vuesax-linear:menu" size="16" v-if="collapsed" />
|
||||
<Icon icon="vuesax-linear:menu" size="16" v-else />
|
||||
</a-button>
|
||||
<span class="page-title">{{ pageTitle }}</span>
|
||||
<a-breadcrumb v-if="breadcrumb" class="breadcrumb">
|
||||
@@ -47,12 +47,16 @@
|
||||
|
||||
<a-menu class="user-card__menu">
|
||||
<a-menu-item key="my-data" @click="router.push('/my-data')">
|
||||
<UserOutlined />
|
||||
اطلاعات من
|
||||
<span class="user-card__row">
|
||||
<Icon icon="vuesax-linear:user" size="16" />
|
||||
<span>اطلاعات من</span>
|
||||
</span>
|
||||
</a-menu-item>
|
||||
<a-menu-item v-if="canSeePermissions" key="permission" @click="router.push('/permission')">
|
||||
<SafetyCertificateOutlined />
|
||||
دسترسی ها
|
||||
<span class="user-card__row">
|
||||
<Icon icon="vuesax-linear:security-safe" size="16" />
|
||||
<span>دسترسی ها</span>
|
||||
</span>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
|
||||
@@ -60,8 +64,10 @@
|
||||
|
||||
<a-menu class="user-card__menu">
|
||||
<a-menu-item key="logout" @click="onLogout">
|
||||
<LogoutOutlined />
|
||||
خروج
|
||||
<span class="user-card__row">
|
||||
<Icon icon="vuesax-linear:logout" size="16" />
|
||||
<span>خروج</span>
|
||||
</span>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</div>
|
||||
@@ -72,15 +78,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../components/icon/Icon.vue';
|
||||
import { computed } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import {
|
||||
LogoutOutlined,
|
||||
MenuFoldOutlined,
|
||||
MenuUnfoldOutlined,
|
||||
SafetyCertificateOutlined,
|
||||
UserOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import { useAuthStore } from '../../stores/auth';
|
||||
import { useUsersStore } from '../../stores/users';
|
||||
|
||||
@@ -233,24 +233,36 @@ async function onLogout() {
|
||||
}
|
||||
|
||||
.user-dropdown-overlay .user-card__menu .ant-menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
height: 34px;
|
||||
line-height: 34px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
margin: 0;
|
||||
padding-inline: 6px !important;
|
||||
padding-inline: 8px !important;
|
||||
border-radius: 6px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.user-dropdown-overlay .user-card__menu .ant-menu-title-content {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.user-dropdown-overlay .user-card__row {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.user-dropdown-overlay .user-card__menu .ant-menu-item:hover {
|
||||
background: #f4f5f6;
|
||||
color: #1d4ed8;
|
||||
}
|
||||
|
||||
.user-dropdown-overlay .user-card__menu .anticon {
|
||||
font-size: 15px;
|
||||
.user-dropdown-overlay .user-card__menu .liman-icons {
|
||||
color: #8a909c;
|
||||
}
|
||||
|
||||
.user-dropdown-overlay .user-card__menu .ant-menu-item:hover .liman-icons {
|
||||
color: #1d4ed8;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -64,7 +64,6 @@ import { computed, ref, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { getMenu, type NavMenuNode as NavMenuNodeData } from '../navMenuItems';
|
||||
import { useUsersStore } from '../../stores/users';
|
||||
import { resolveIcon } from '../../components/icons';
|
||||
import NavMenuNode from './NavMenuNode.vue';
|
||||
import { brand } from '../../brand';
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<p class="dash-head__sub">خلاصه عملکرد فروش در ۳۰ روز گذشته</p>
|
||||
</div>
|
||||
<div class="dash-head__date">
|
||||
<CalendarOutlined />
|
||||
<Icon icon="vuesax-linear:calendar" size="16" />
|
||||
<span>{{ todayLabel }}</span>
|
||||
</div>
|
||||
</header>
|
||||
@@ -26,7 +26,7 @@
|
||||
<section class="kpi-grid">
|
||||
<div class="kpi kpi--success">
|
||||
<div class="kpi__top">
|
||||
<span class="kpi__icon"><ShoppingCartOutlined /></span>
|
||||
<span class="kpi__icon"><Icon icon="vuesax-linear:bag-2" size="16" /></span>
|
||||
<span class="kpi__label">تعداد سفارشات (۳۰ روز گذشته)</span>
|
||||
</div>
|
||||
<div class="kpi__value">{{ fmt(data.ordercount) }}<small>سفارش</small></div>
|
||||
@@ -42,7 +42,7 @@
|
||||
|
||||
<div class="kpi kpi--primary">
|
||||
<div class="kpi__top">
|
||||
<span class="kpi__icon"><GoldOutlined /></span>
|
||||
<span class="kpi__icon"><Icon icon="vuesax-linear:diamonds" size="16" /></span>
|
||||
<span class="kpi__label">طلای فروش رفته (۳۰ روز گذشته)</span>
|
||||
</div>
|
||||
<div class="kpi__value">{{ fmt(data.allgram) }}<small>گرم</small></div>
|
||||
@@ -53,7 +53,7 @@
|
||||
|
||||
<div class="kpi kpi--warning">
|
||||
<div class="kpi__top">
|
||||
<span class="kpi__icon"><UserAddOutlined /></span>
|
||||
<span class="kpi__icon"><Icon icon="vuesax-linear:user-add" size="16" /></span>
|
||||
<span class="kpi__label">مشتریان جدید (۳۰ روز گذشته)</span>
|
||||
</div>
|
||||
<div class="kpi__value">{{ fmt(data.customerCount) }}<small>نفر</small></div>
|
||||
@@ -64,7 +64,7 @@
|
||||
|
||||
<div class="kpi kpi--danger">
|
||||
<div class="kpi__top">
|
||||
<span class="kpi__icon"><DollarOutlined /></span>
|
||||
<span class="kpi__icon"><Icon icon="vuesax-linear:dollar-circle" size="16" /></span>
|
||||
<span class="kpi__label">نرخ هر گرم طلای ۱۸ عیار</span>
|
||||
</div>
|
||||
<div class="kpi__value kpi__value--price">{{ goldPriceLabel }}</div>
|
||||
@@ -156,22 +156,22 @@
|
||||
</div>
|
||||
<ul class="metric-list">
|
||||
<li>
|
||||
<span class="metric-list__icon tone-primary"><CheckCircleOutlined /></span>
|
||||
<span class="metric-list__icon tone-primary"><Icon icon="vuesax-linear:tick-circle" size="16" /></span>
|
||||
<span class="metric-list__label">تعداد سفارش (۳۰ روز)</span>
|
||||
<b>{{ fmt(data.sumLastOrder) }}</b>
|
||||
</li>
|
||||
<li>
|
||||
<span class="metric-list__icon tone-success"><GoldOutlined /></span>
|
||||
<span class="metric-list__icon tone-success"><Icon icon="vuesax-linear:diamonds" size="16" /></span>
|
||||
<span class="metric-list__label">مجموع وزن (۳۰ روز)</span>
|
||||
<b>{{ fmt(data.sumLastOrderMonth) }} گرم</b>
|
||||
</li>
|
||||
<li>
|
||||
<span class="metric-list__icon tone-warning"><FundOutlined /></span>
|
||||
<span class="metric-list__icon tone-warning"><Icon icon="vuesax-linear:chart" size="16" /></span>
|
||||
<span class="metric-list__label">میانگین هر سفارش</span>
|
||||
<b>{{ avgWeightPerOrder }} گرم</b>
|
||||
</li>
|
||||
<li>
|
||||
<span class="metric-list__icon tone-danger"><CreditCardOutlined /></span>
|
||||
<span class="metric-list__icon tone-danger"><Icon icon="vuesax-linear:card" size="16" /></span>
|
||||
<span class="metric-list__label">مجموع بدهی طلای مشتریان</span>
|
||||
<b>{{ totalDebtLabel }} گرم</b>
|
||||
</li>
|
||||
@@ -282,17 +282,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../components/icon/Icon.vue';
|
||||
import { computed, onMounted, reactive, ref } from 'vue';
|
||||
import {
|
||||
CalendarOutlined,
|
||||
CheckCircleOutlined,
|
||||
CreditCardOutlined,
|
||||
DollarOutlined,
|
||||
FundOutlined,
|
||||
GoldOutlined,
|
||||
ShoppingCartOutlined,
|
||||
UserAddOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import { jdate, price } from '../utils/filters';
|
||||
import { useLayoutStore } from '../stores/layout';
|
||||
import { useUsersStore } from '../stores/users';
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
<template #opt="{ record }">
|
||||
<a-tooltip v-if="hasPermission('collection.list.edit')" title="ویرایش">
|
||||
<EditOutlined class="cursor-pointer mx-1 text-primary" @click="openEdit(record.id)" />
|
||||
<Icon icon="vuesax-linear:edit-2" size="16" class="cursor-pointer mx-1 text-primary" @click="openEdit(record.id)" />
|
||||
</a-tooltip>
|
||||
<a-tooltip v-if="hasPermission('collection.list.remove')" title="حذف">
|
||||
<a-popconfirm
|
||||
@@ -32,7 +32,7 @@
|
||||
@confirm="confirmDelete(`category/${record.id}`)"
|
||||
>
|
||||
<template #title><p>آیا مطمئن به حذف دسته مورد نظر هستید ؟</p></template>
|
||||
<DeleteOutlined class="cursor-pointer mx-1 text-danger" />
|
||||
<Icon icon="vuesax-linear:trash" size="16" class="cursor-pointer mx-1 text-danger" />
|
||||
</a-popconfirm>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
@@ -44,9 +44,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../../components/icon/Icon.vue';
|
||||
import { ref } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { DeleteOutlined, EditOutlined } from '@ant-design/icons-vue';
|
||||
import XTable from '../../../components/x-table/XTable.vue';
|
||||
import ListPageHeader from '../../../components/common/ListPageHeader.vue';
|
||||
import CategoryAdd from './Add.vue';
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<div id="page-user-view" class="pf-page">
|
||||
<header class="pf-head">
|
||||
<a-button class="pf-head__back" shape="circle" @click="handleBack">
|
||||
<template #icon><ArrowRightOutlined /></template>
|
||||
<template #icon><Icon icon="vuesax-linear:arrow-right" size="16" /></template>
|
||||
</a-button>
|
||||
<div class="pf-head__text">
|
||||
<h1>افزودن شخص</h1>
|
||||
@@ -37,12 +37,12 @@
|
||||
:aria-selected="activeTab === k.key"
|
||||
@click="activeTab = k.key"
|
||||
>
|
||||
<span class="kind-card__icon"><component :is="k.icon" /></span>
|
||||
<span class="kind-card__icon"><Icon :icon="k.icon" size="22" /></span>
|
||||
<span class="kind-card__text">
|
||||
<b>{{ k.title }}</b>
|
||||
<small>{{ k.hint }}</small>
|
||||
</span>
|
||||
<CheckCircleFilled v-if="activeTab === k.key" class="kind-card__check" />
|
||||
<Icon icon="vuesax-linear:tick-circle" size="16" class="kind-card__check" v-if="activeTab === k.key" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -54,16 +54,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../../components/icon/Icon.vue';
|
||||
import { computed, ref, type Component } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import {
|
||||
ShopOutlined,
|
||||
TeamOutlined,
|
||||
UserOutlined,
|
||||
ArrowRightOutlined,
|
||||
CheckCircleFilled,
|
||||
IdcardOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import BulkCustomer from './bulkCustomer.vue';
|
||||
import ReagentCustomer from './ReagentCustomer.vue';
|
||||
import SingleCustomer from './singleCustomer.vue';
|
||||
@@ -83,18 +76,18 @@ interface Kind {
|
||||
key: 'omde' | 'reagent' | 'tak';
|
||||
title: string;
|
||||
hint: string;
|
||||
icon: Component;
|
||||
icon: string;
|
||||
}
|
||||
const kinds = computed<Kind[]>(() => {
|
||||
const out: Kind[] = [];
|
||||
if (hasPermission('persons.create.client')) {
|
||||
out.push({ key: 'omde', title: 'مشتری عمده', hint: 'مغازهدار، بنکدار و خریدار عمده', icon: ShopOutlined });
|
||||
out.push({ key: 'omde', title: 'مشتری عمده', hint: 'مغازهدار، بنکدار و خریدار عمده', icon: 'vuesax-linear:shop' });
|
||||
}
|
||||
if (hasPermission('persons.create.seller')) {
|
||||
out.push({ key: 'reagent', title: 'کارشناس فروش', hint: 'کارشناس با کمیسیون و سقف اعتبار', icon: IdcardOutlined });
|
||||
out.push({ key: 'reagent', title: 'کارشناس فروش', hint: 'کارشناس با کمیسیون و سقف اعتبار', icon: 'vuesax-linear:personalcard' });
|
||||
}
|
||||
if (users.isSuperAdmin) {
|
||||
out.push({ key: 'tak', title: 'مشتری تک', hint: 'مشتری خردهفروشی حضوری', icon: UserOutlined });
|
||||
out.push({ key: 'tak', title: 'مشتری تک', hint: 'مشتری خردهفروشی حضوری', icon: 'vuesax-linear:user' });
|
||||
}
|
||||
return out;
|
||||
});
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<div class="pf-main">
|
||||
<section class="pf-section">
|
||||
<div class="pf-section__head">
|
||||
<span class="pf-section__icon"><UserOutlined /></span>
|
||||
<span class="pf-section__icon"><Icon icon="vuesax-linear:user" size="16" /></span>
|
||||
<div>
|
||||
<h3>اطلاعات پایه</h3>
|
||||
<p>مشخصات هویتی و اطلاعات ورود کارشناس</p>
|
||||
@@ -71,7 +71,7 @@
|
||||
|
||||
<section class="pf-section">
|
||||
<div class="pf-section__head">
|
||||
<span class="pf-section__icon"><ShopOutlined /></span>
|
||||
<span class="pf-section__icon"><Icon icon="vuesax-linear:shop" size="16" /></span>
|
||||
<div>
|
||||
<h3>اطلاعات تجاری</h3>
|
||||
<p>کد و مشخصات فروشگاه</p>
|
||||
@@ -92,7 +92,7 @@
|
||||
|
||||
<section class="pf-section">
|
||||
<div class="pf-section__head">
|
||||
<span class="pf-section__icon"><EnvironmentOutlined /></span>
|
||||
<span class="pf-section__icon"><Icon icon="vuesax-linear:location" size="16" /></span>
|
||||
<div>
|
||||
<h3>آدرس</h3>
|
||||
<p>انتخاب شهر، درصد کمیسیون را بر اساس همان شهر پر میکند</p>
|
||||
@@ -117,7 +117,7 @@
|
||||
<aside class="pf-side">
|
||||
<section class="pf-section">
|
||||
<div class="pf-section__head">
|
||||
<span class="pf-section__icon"><CameraOutlined /></span>
|
||||
<span class="pf-section__icon"><Icon icon="vuesax-linear:camera" size="16" /></span>
|
||||
<div>
|
||||
<h3>عکس پروفایل</h3>
|
||||
<p>تصویر نمایش دادهشده برای کارشناس</p>
|
||||
@@ -136,7 +136,7 @@
|
||||
|
||||
<section class="pf-section">
|
||||
<div class="pf-section__head">
|
||||
<span class="pf-section__icon"><PercentageOutlined /></span>
|
||||
<span class="pf-section__icon"><Icon icon="vuesax-linear:percentage-square" size="16" /></span>
|
||||
<div>
|
||||
<h3>کمیسیون و اعتبار</h3>
|
||||
<p>درصد کمیسیون و سقف اعتبار</p>
|
||||
@@ -153,10 +153,10 @@
|
||||
</div>
|
||||
|
||||
<div class="pf-actions">
|
||||
<span class="pf-actions__hint"><InfoCircleOutlined /> فیلدهای ستارهدار الزامی هستند.</span>
|
||||
<span class="pf-actions__hint"><Icon icon="vuesax-linear:info-circle" size="16" /> فیلدهای ستارهدار الزامی هستند.</span>
|
||||
<a-button @click="router.go(-1)">انصراف</a-button>
|
||||
<a-button type="primary" class="form-submit" :loading="loading" @click="handleSubmit">
|
||||
<template #icon><CheckOutlined /></template>
|
||||
<template #icon><Icon icon="vuesax-linear:tick-circle" size="16" /></template>
|
||||
ثبت اطلاعات
|
||||
</a-button>
|
||||
</div>
|
||||
@@ -165,20 +165,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../../components/icon/Icon.vue';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { message } from 'ant-design-vue';
|
||||
import {
|
||||
TeamOutlined,
|
||||
ShopOutlined,
|
||||
EnvironmentOutlined,
|
||||
CheckOutlined,
|
||||
ArrowRightOutlined,
|
||||
CameraOutlined,
|
||||
InfoCircleOutlined,
|
||||
PercentageOutlined,
|
||||
UserOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import api from '../../../api/client';
|
||||
import CityTreeSelect from '../../../components/common/CityTreeSelect.vue';
|
||||
import ImageUploadInput from '../../../components/upload/ImageUploadInput.vue';
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
<div class="pf-main">
|
||||
<section class="pf-section">
|
||||
<div class="pf-section__head">
|
||||
<span class="pf-section__icon"><UserOutlined /></span>
|
||||
<span class="pf-section__icon"><Icon icon="vuesax-linear:user" size="16" /></span>
|
||||
<div>
|
||||
<h3>اطلاعات پایه</h3>
|
||||
<p>مشخصات هویتی و اطلاعات ورود مشتری</p>
|
||||
@@ -183,7 +183,7 @@
|
||||
|
||||
<section class="pf-section">
|
||||
<div class="pf-section__head">
|
||||
<span class="pf-section__icon"><ShopOutlined /></span>
|
||||
<span class="pf-section__icon"><Icon icon="vuesax-linear:shop" size="16" /></span>
|
||||
<div>
|
||||
<h3>اطلاعات تجاری</h3>
|
||||
<p>نوع کاربری و مشخصات فروشگاه</p>
|
||||
@@ -217,7 +217,7 @@
|
||||
|
||||
<section class="pf-section">
|
||||
<div class="pf-section__head">
|
||||
<span class="pf-section__icon"><EnvironmentOutlined /></span>
|
||||
<span class="pf-section__icon"><Icon icon="vuesax-linear:location" size="16" /></span>
|
||||
<div>
|
||||
<h3>آدرس</h3>
|
||||
<p>انتخاب شهر، درصد را بر اساس همان شهر پر میکند</p>
|
||||
@@ -236,7 +236,7 @@
|
||||
<aside class="pf-side">
|
||||
<section class="pf-section">
|
||||
<div class="pf-section__head">
|
||||
<span class="pf-section__icon"><PercentageOutlined /></span>
|
||||
<span class="pf-section__icon"><Icon icon="vuesax-linear:percentage-square" size="16" /></span>
|
||||
<div>
|
||||
<h3>کارشناس و اعتبار</h3>
|
||||
<p>کارشناس فروش، درصد و سقف اعتبار</p>
|
||||
@@ -265,7 +265,7 @@
|
||||
|
||||
<section class="pf-section">
|
||||
<div class="pf-section__head">
|
||||
<span class="pf-section__icon"><SafetyCertificateOutlined /></span>
|
||||
<span class="pf-section__icon"><Icon icon="vuesax-linear:security-safe" size="16" /></span>
|
||||
<div>
|
||||
<h3>مدارک</h3>
|
||||
<p>تصویر مدارک هویتی و فروشگاه</p>
|
||||
@@ -287,10 +287,10 @@
|
||||
</div>
|
||||
|
||||
<div class="pf-actions">
|
||||
<span class="pf-actions__hint"><InfoCircleOutlined /> فیلدهای ستارهدار الزامی هستند.</span>
|
||||
<span class="pf-actions__hint"><Icon icon="vuesax-linear:info-circle" size="16" /> فیلدهای ستارهدار الزامی هستند.</span>
|
||||
<a-button @click="router.go(-1)">انصراف</a-button>
|
||||
<a-button type="primary" class="form-submit" :loading="loading" @click="handleSubmitOmde">
|
||||
<template #icon><CheckOutlined /></template>
|
||||
<template #icon><Icon icon="vuesax-linear:tick-circle" size="16" /></template>
|
||||
ثبت اطلاعات
|
||||
</a-button>
|
||||
</div>
|
||||
@@ -299,20 +299,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../../components/icon/Icon.vue';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { message } from 'ant-design-vue';
|
||||
import {
|
||||
UserOutlined,
|
||||
ShopOutlined,
|
||||
EnvironmentOutlined,
|
||||
FileImageOutlined,
|
||||
CheckOutlined,
|
||||
ArrowRightOutlined,
|
||||
InfoCircleOutlined,
|
||||
PercentageOutlined,
|
||||
SafetyCertificateOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import BaseFormModal from '../../../components/common/BaseFormModal.vue';
|
||||
import ImageUploadInput from '../../../components/upload/ImageUploadInput.vue';
|
||||
import api from '../../../api/client';
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<div class="pf-main">
|
||||
<section class="pf-section">
|
||||
<div class="pf-section__head">
|
||||
<span class="pf-section__icon"><UserOutlined /></span>
|
||||
<span class="pf-section__icon"><Icon icon="vuesax-linear:user" size="16" /></span>
|
||||
<div>
|
||||
<h3>{{ id ? 'ویرایش مشتری' : 'افزودن مشتری' }}</h3>
|
||||
<p>مشخصات مشتری تک</p>
|
||||
@@ -43,10 +43,10 @@
|
||||
</div>
|
||||
|
||||
<div class="pf-actions">
|
||||
<span class="pf-actions__hint"><InfoCircleOutlined /> فیلدهای ستارهدار الزامی هستند.</span>
|
||||
<span class="pf-actions__hint"><Icon icon="vuesax-linear:info-circle" size="16" /> فیلدهای ستارهدار الزامی هستند.</span>
|
||||
<a-button @click="router.go(-1)">انصراف</a-button>
|
||||
<a-button type="primary" class="form-submit" :loading="loading" @click="handleSubmit">
|
||||
<template #icon><CheckOutlined /></template>
|
||||
<template #icon><Icon icon="vuesax-linear:tick-circle" size="16" /></template>
|
||||
ثبت اطلاعات
|
||||
</a-button>
|
||||
</div>
|
||||
@@ -55,16 +55,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../../components/icon/Icon.vue';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { message } from 'ant-design-vue';
|
||||
import {
|
||||
UserOutlined,
|
||||
EnvironmentOutlined,
|
||||
CheckOutlined,
|
||||
ArrowRightOutlined,
|
||||
InfoCircleOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import api from '../../../api/client';
|
||||
import CityTreeSelect from '../../../components/common/CityTreeSelect.vue';
|
||||
import DateInput from '../../../components/input/DateInput.vue';
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<!-- ── page header ── -->
|
||||
<header class="pf-head">
|
||||
<a-button class="pf-head__back" shape="circle" @click="handleBack">
|
||||
<template #icon><ArrowRightOutlined /></template>
|
||||
<template #icon><Icon icon="vuesax-linear:arrow-right" size="16" /></template>
|
||||
</a-button>
|
||||
<div class="pf-head__text">
|
||||
<h1>{{ id ? 'ویرایش محصول' : 'افزودن محصول' }}</h1>
|
||||
@@ -51,7 +51,7 @@
|
||||
<div class="pf-main">
|
||||
<section class="pf-section">
|
||||
<div class="pf-section__head">
|
||||
<span class="pf-section__icon"><FileTextOutlined /></span>
|
||||
<span class="pf-section__icon"><Icon icon="vuesax-linear:document-text" size="16" /></span>
|
||||
<div>
|
||||
<h3>اطلاعات پایه</h3>
|
||||
<p>نام، کد و توضیحات محصول</p>
|
||||
@@ -103,7 +103,7 @@
|
||||
<!-- تنوع ها -->
|
||||
<section v-if="hasPermission('product.list.variants')" class="pf-section">
|
||||
<div class="pf-section__head">
|
||||
<span class="pf-section__icon"><AppstoreOutlined /></span>
|
||||
<span class="pf-section__icon"><Icon icon="vuesax-linear:category-2" size="16" /></span>
|
||||
<div>
|
||||
<h3>تنوع ها</h3>
|
||||
<p>وزن، اجرت و موجودی هر مدل از محصول</p>
|
||||
@@ -114,7 +114,7 @@
|
||||
class="pf-section__action"
|
||||
@click="showModal()"
|
||||
>
|
||||
<template #icon><PlusOutlined /></template>
|
||||
<template #icon><Icon icon="vuesax-linear:add" size="16" /></template>
|
||||
افزودن تنوع
|
||||
</a-button>
|
||||
</div>
|
||||
@@ -128,7 +128,7 @@
|
||||
v-if="hasPermission('product.list.variants.add')"
|
||||
@click="showModal()"
|
||||
>
|
||||
<template #icon><PlusOutlined /></template>
|
||||
<template #icon><Icon icon="vuesax-linear:add" size="16" /></template>
|
||||
افزودن اولین تنوع
|
||||
</a-button>
|
||||
</a-empty>
|
||||
@@ -146,7 +146,7 @@
|
||||
<template #bodyCell="{ column, record, index }">
|
||||
<template v-if="column.dataIndex === 'image'">
|
||||
<img v-if="record.image_url" :src="record.image_url" class="variant-thumb" alt="" />
|
||||
<span v-else class="variant-thumb variant-thumb--empty"><PictureOutlined /></span>
|
||||
<span v-else class="variant-thumb variant-thumb--empty"><Icon icon="vuesax-linear:gallery" size="16" /></span>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'title'">
|
||||
<span class="pf-table__title">{{ record.title }}</span>
|
||||
@@ -163,12 +163,12 @@
|
||||
<div class="pf-table__ops">
|
||||
<a-tooltip v-if="hasPermission('product.list.variants.edit')" title="ویرایش">
|
||||
<a-button type="text" size="small" @click="showModal(record, index)">
|
||||
<template #icon><EditOutlined class="text-primary" /></template>
|
||||
<template #icon><Icon icon="vuesax-linear:edit-2" size="16" class="text-primary" /></template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip v-if="hasPermission('product.list.variants.remove')" title="حذف">
|
||||
<a-button type="text" size="small" danger @click="variants.splice(index, 1)">
|
||||
<template #icon><DeleteOutlined /></template>
|
||||
<template #icon><Icon icon="vuesax-linear:trash" size="16" /></template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
@@ -190,7 +190,7 @@
|
||||
|
||||
<section class="pf-section">
|
||||
<div class="pf-section__head">
|
||||
<span class="pf-section__icon"><PictureOutlined /></span>
|
||||
<span class="pf-section__icon"><Icon icon="vuesax-linear:gallery" size="16" /></span>
|
||||
<div>
|
||||
<h3>گالری تصاویر</h3>
|
||||
<p>تصاویر جداگانه برای نمایش در سایت و اپلیکیشن موبایل</p>
|
||||
@@ -221,7 +221,7 @@
|
||||
<aside class="pf-side">
|
||||
<section class="pf-section">
|
||||
<div class="pf-section__head">
|
||||
<span class="pf-section__icon"><EyeOutlined /></span>
|
||||
<span class="pf-section__icon"><Icon icon="vuesax-linear:eye" size="16" /></span>
|
||||
<div>
|
||||
<h3>وضعیت نمایش</h3>
|
||||
<p>نمایش یا عدم نمایش محصول برای مشتریان</p>
|
||||
@@ -238,7 +238,7 @@
|
||||
|
||||
<section class="pf-section">
|
||||
<div class="pf-section__head">
|
||||
<span class="pf-section__icon"><TagsOutlined /></span>
|
||||
<span class="pf-section__icon"><Icon icon="vuesax-linear:tag-2" size="16" /></span>
|
||||
<div>
|
||||
<h3>دستهبندی</h3>
|
||||
<p>دسته، برند و سینیهای محصول</p>
|
||||
@@ -279,7 +279,7 @@
|
||||
|
||||
<section class="pf-section">
|
||||
<div class="pf-section__head">
|
||||
<span class="pf-section__icon"><FileImageOutlined /></span>
|
||||
<span class="pf-section__icon"><Icon icon="vuesax-linear:gallery" size="16" /></span>
|
||||
<div>
|
||||
<h3>تصویر شاخص</h3>
|
||||
<p>تصویر اصلی در لیست محصولات</p>
|
||||
@@ -300,12 +300,12 @@
|
||||
<!-- ── sticky action bar ── -->
|
||||
<div class="pf-actions">
|
||||
<span class="pf-actions__hint">
|
||||
<InfoCircleOutlined />
|
||||
<Icon icon="vuesax-linear:info-circle" size="16" />
|
||||
تغییرات تنوعها و تصاویر پس از «ثبت اطلاعات» ذخیره میشوند.
|
||||
</span>
|
||||
<a-button @click="handleBack">انصراف</a-button>
|
||||
<a-button type="primary" class="form-submit" :loading="loading" @click="handleSubmit">
|
||||
<template #icon><CheckOutlined /></template>
|
||||
<template #icon><Icon icon="vuesax-linear:tick-circle" size="16" /></template>
|
||||
ثبت اطلاعات
|
||||
</a-button>
|
||||
</div>
|
||||
@@ -393,26 +393,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../../components/icon/Icon.vue';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { Empty, message } from 'ant-design-vue';
|
||||
import {
|
||||
ShoppingOutlined,
|
||||
UnorderedListOutlined,
|
||||
FileTextOutlined,
|
||||
AppstoreOutlined,
|
||||
FileImageOutlined,
|
||||
LockOutlined,
|
||||
CheckOutlined,
|
||||
ArrowRightOutlined,
|
||||
EditOutlined,
|
||||
DeleteOutlined,
|
||||
PlusOutlined,
|
||||
PictureOutlined,
|
||||
EyeOutlined,
|
||||
TagsOutlined,
|
||||
InfoCircleOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import { useUsersStore } from '../../../stores/users';
|
||||
import api from '../../../api/client';
|
||||
import ImageUploadInput from '../../../components/upload/ImageUploadInput.vue';
|
||||
|
||||
@@ -47,14 +47,11 @@
|
||||
<template #op="{ record }">
|
||||
<div v-if="!is_branch" class="w-48 flex">
|
||||
<a-tooltip v-if="hasPermission('product.list.edit')" title="ویرایش">
|
||||
<EditOutlined class="cursor-pointer mx-1 text-primary" @click="toEdit(record.id)" />
|
||||
<Icon icon="vuesax-linear:edit-2" size="16" class="cursor-pointer mx-1 text-primary" @click="toEdit(record.id)" />
|
||||
</a-tooltip>
|
||||
|
||||
<a-tooltip v-if="hasPermission('product.list.view')" title="اطلاعات جامع">
|
||||
<ExclamationCircleOutlined
|
||||
class="cursor-pointer mx-1 text-warning"
|
||||
@click="showProductModal(record)"
|
||||
/>
|
||||
<Icon icon="vuesax-linear:info-circle" size="16" class="cursor-pointer mx-1 text-warning" @click="showProductModal(record)" />
|
||||
</a-tooltip>
|
||||
|
||||
<a-tooltip v-if="hasPermission('product.list.remove')" title="حذف">
|
||||
@@ -65,7 +62,7 @@
|
||||
@confirm="confirmDelete(record.id)"
|
||||
>
|
||||
<template #title><p>آیا مطمئن به حذف محصول مورد نظر هستید ؟</p></template>
|
||||
<DeleteOutlined class="cursor-pointer mx-1 text-danger" />
|
||||
<Icon icon="vuesax-linear:trash" size="16" class="cursor-pointer mx-1 text-danger" />
|
||||
</a-popconfirm>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
@@ -109,14 +106,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../../components/icon/Icon.vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { message } from 'ant-design-vue';
|
||||
import {
|
||||
DeleteOutlined,
|
||||
EditOutlined,
|
||||
ExclamationCircleOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import XTable from '../../../components/x-table/XTable.vue';
|
||||
import AccountingSyncButton from '../../../components/accounting/AccountingSyncButton.vue';
|
||||
import { buildProductListModel } from './productListModel';
|
||||
|
||||
@@ -73,9 +73,9 @@
|
||||
</div>
|
||||
|
||||
<ul class="chips">
|
||||
<li><LineChartOutlined /> گزارش لحظهای</li>
|
||||
<li><TeamOutlined /> مدیریت مشتریان</li>
|
||||
<li><ShoppingOutlined /> پیگیری سفارش</li>
|
||||
<li><Icon icon="vuesax-linear:chart-2" size="16" /> گزارش لحظهای</li>
|
||||
<li><Icon icon="vuesax-linear:people" size="16" /> مدیریت مشتریان</li>
|
||||
<li><Icon icon="vuesax-linear:bag-2" size="16" /> پیگیری سفارش</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
class="ltr-input"
|
||||
@blur="touchedMobile = true"
|
||||
>
|
||||
<template #prefix><MobileOutlined class="field-icon" /></template>
|
||||
<template #prefix><Icon icon="vuesax-linear:mobile" size="16" class="field-icon" /></template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
@blur="touchedPassword = true"
|
||||
@pressEnter="loginJWT"
|
||||
>
|
||||
<template #prefix><LockOutlined class="field-icon" /></template>
|
||||
<template #prefix><Icon icon="vuesax-linear:lock" size="16" class="field-icon" /></template>
|
||||
</a-input-password>
|
||||
</a-form-item>
|
||||
|
||||
@@ -134,12 +134,12 @@
|
||||
@click="loginJWT"
|
||||
>
|
||||
<span>ورود</span>
|
||||
<ArrowLeftOutlined v-if="!loading" class="btn-arrow" />
|
||||
<Icon icon="vuesax-linear:arrow-left" size="16" class="btn-arrow" v-if="!loading" />
|
||||
</a-button>
|
||||
</a-form>
|
||||
|
||||
<p class="secure-note">
|
||||
<SafetyCertificateOutlined />
|
||||
<Icon icon="vuesax-linear:security-safe" size="16" />
|
||||
<span>اتصال شما رمزنگاری شده و امن است</span>
|
||||
</p>
|
||||
</div>
|
||||
@@ -151,19 +151,11 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../components/icon/Icon.vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { brand } from '../../brand';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { message } from 'ant-design-vue';
|
||||
import {
|
||||
ArrowLeftOutlined,
|
||||
LineChartOutlined,
|
||||
LockOutlined,
|
||||
MobileOutlined,
|
||||
SafetyCertificateOutlined,
|
||||
ShoppingOutlined,
|
||||
TeamOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import { useAuthStore } from '../../stores/auth';
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
@@ -24,19 +24,17 @@
|
||||
<template #actions="{ record }">
|
||||
<div class="flex gap-2">
|
||||
<a-tooltip v-if="addRid" title="ویرایش">
|
||||
<EditOutlined class="cursor-pointer mx-1 text-primary" @click="openEdit(record.id)" />
|
||||
<Icon icon="vuesax-linear:edit-2" size="16" class="cursor-pointer mx-1 text-primary" @click="openEdit(record.id)" />
|
||||
</a-tooltip>
|
||||
<a-tooltip v-else title="ویرایش">
|
||||
<EditOutlined class="cursor-pointer mx-1 text-primary" @click="toEdit(record.id)" />
|
||||
<Icon icon="vuesax-linear:edit-2" size="16" class="cursor-pointer mx-1 text-primary" @click="toEdit(record.id)" />
|
||||
</a-tooltip>
|
||||
|
||||
<a-tooltip title="وضعیت">
|
||||
<CheckOutlined
|
||||
v-if="record.is_active"
|
||||
class="cursor-pointer mx-1 text-success"
|
||||
@click="setOffer(record.id)"
|
||||
/>
|
||||
<CloseOutlined v-else class="cursor-pointer mx-1 text-danger" @click="setOffer(record.id)" />
|
||||
<Icon icon="vuesax-linear:tick-circle" size="16" class="cursor-pointer mx-1 text-success" v-if="record.is_active"
|
||||
|
||||
@click="setOffer(record.id)" />
|
||||
<Icon icon="vuesax-linear:close-circle" size="16" class="cursor-pointer mx-1 text-danger" v-else @click="setOffer(record.id)" />
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
@@ -47,10 +45,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../components/icon/Icon.vue';
|
||||
import { ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { CheckOutlined, CloseOutlined, EditOutlined } from '@ant-design/icons-vue';
|
||||
import XTable from '../../components/x-table/XTable.vue';
|
||||
import ListPageHeader from '../../components/common/ListPageHeader.vue';
|
||||
import api from '../../api/client';
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<XTable ref="tbl" :model="model" mobile-cards>
|
||||
<template #opt="{ record }">
|
||||
<a-tooltip title="مشاهده">
|
||||
<EyeOutlined class="cursor-pointer mx-1 text-primary" @click="view(record)" />
|
||||
<Icon icon="vuesax-linear:eye" size="16" class="cursor-pointer mx-1 text-primary" @click="view(record)" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</XTable>
|
||||
@@ -47,8 +47,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../components/icon/Icon.vue';
|
||||
import { ref } from 'vue';
|
||||
import { EyeOutlined } from '@ant-design/icons-vue';
|
||||
import XTable from '../../components/x-table/XTable.vue';
|
||||
import { buildBranchBuyListModel } from './orderListModel';
|
||||
import { jdate } from '../../utils/filters';
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
<a-dropdown>
|
||||
<a-button style="margin-left: 8px">
|
||||
افزودن
|
||||
<DownOutlined />
|
||||
<Icon icon="vuesax-linear:arrow-down" size="16" />
|
||||
</a-button>
|
||||
<template #overlay>
|
||||
<a-menu @click="onVariantPick(record, $event)">
|
||||
@@ -74,7 +74,7 @@
|
||||
>
|
||||
<template #bodyCell="{ column, record, index }">
|
||||
<template v-if="column.dataIndex === 'delete'">
|
||||
<CloseOutlined class="cursor-pointer" @click="cart.remove(record)" />
|
||||
<Icon icon="vuesax-linear:close-circle" size="16" class="cursor-pointer" @click="cart.remove(record)" />
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'product'">
|
||||
<div class="flex items-center">
|
||||
@@ -118,10 +118,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../../components/icon/Icon.vue';
|
||||
import { computed, onMounted, reactive, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { CloseOutlined, DownOutlined } from '@ant-design/icons-vue';
|
||||
import XTable from '../../../components/x-table/XTable.vue';
|
||||
import { buildProductListModel } from '../../apps/product/productListModel';
|
||||
import { useCartStore, type CartItem, type CartVariant } from '../../../stores/cart';
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
<template #opt="{ record }">
|
||||
<a-tooltip v-if="hasPermission('cities.list.view.edit')" title="ویرایش">
|
||||
<EditOutlined class="cursor-pointer mx-1 text-primary" @click="edit(record)" />
|
||||
<Icon icon="vuesax-linear:edit-2" size="16" class="cursor-pointer mx-1 text-primary" @click="edit(record)" />
|
||||
</a-tooltip>
|
||||
|
||||
<a-tooltip v-if="hasPermission('cities.list.remove')" title="حذف">
|
||||
@@ -37,7 +37,7 @@
|
||||
@confirm="confirmDelete(`cities/${record.id}`)"
|
||||
>
|
||||
<template #title><p>آیا مطمئن به حذف شهر مورد نظر هستید ؟</p></template>
|
||||
<DeleteOutlined class="cursor-pointer mx-1 text-danger" />
|
||||
<Icon icon="vuesax-linear:trash" size="16" class="cursor-pointer mx-1 text-danger" />
|
||||
</a-popconfirm>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
@@ -72,9 +72,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../components/icon/Icon.vue';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { DeleteOutlined, EditOutlined } from '@ant-design/icons-vue';
|
||||
import XTable from '../../components/x-table/XTable.vue';
|
||||
import ListPageHeader from '../../components/common/ListPageHeader.vue';
|
||||
import CreateCity from './createCity.vue';
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
@click="(e: Event) => e.preventDefault()"
|
||||
>
|
||||
{{ record.sts === 1 ? 'در انتظار تایید' : record.sts === 2 ? 'تایید' : 'عدم تایید' }}
|
||||
<DownOutlined />
|
||||
<Icon icon="vuesax-linear:arrow-down" size="16" />
|
||||
</a-tag>
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
@@ -97,7 +97,7 @@
|
||||
<ul>
|
||||
<li class="comment-item">
|
||||
<span class="img">
|
||||
<UserOutlined style="font-size: 48px; color: #1d4ed8" />
|
||||
<Icon icon="vuesax-linear:user" size="16" style="font-size: 48px; color: #1d4ed8" />
|
||||
</span>
|
||||
<div class="comment-body">
|
||||
<h5>
|
||||
@@ -158,9 +158,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../../components/icon/Icon.vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { DownOutlined, UserOutlined } from '@ant-design/icons-vue';
|
||||
import XTable from '../../../components/x-table/XTable.vue';
|
||||
import TooltipBtn from '../../../components/tooltip-btn/TooltipBtn.vue';
|
||||
import { buildCommentListModel } from './CommentListModel';
|
||||
|
||||
@@ -35,19 +35,19 @@
|
||||
</div>
|
||||
<div class="hero-meta">
|
||||
<span v-if="customer?.mobile" class="meta-item">
|
||||
<PhoneOutlined />
|
||||
<Icon icon="vuesax-linear:call" size="16" />
|
||||
<span dir="ltr">{{ customer.mobile }}</span>
|
||||
</span>
|
||||
<span v-if="customer?.city?.title" class="meta-item">
|
||||
<EnvironmentOutlined />
|
||||
<Icon icon="vuesax-linear:location" size="16" />
|
||||
{{ customer.city.title }}
|
||||
</span>
|
||||
<span v-if="customer?.reagent?.name" class="meta-item">
|
||||
<UserOutlined />
|
||||
<Icon icon="vuesax-linear:user" size="16" />
|
||||
کارشناس فروش: {{ customer.reagent.name }}
|
||||
</span>
|
||||
<span v-if="customer?.caj" class="meta-item">
|
||||
<CalendarOutlined />
|
||||
<Icon icon="vuesax-linear:calendar" size="16" />
|
||||
عضویت از {{ jdate(customer.caj) }}
|
||||
</span>
|
||||
</div>
|
||||
@@ -55,11 +55,11 @@
|
||||
</div>
|
||||
<div class="hero-actions">
|
||||
<a-button @click="router.back()">
|
||||
<template #icon><ArrowRightOutlined /></template>
|
||||
<template #icon><Icon icon="vuesax-linear:arrow-right" size="16" /></template>
|
||||
بازگشت
|
||||
</a-button>
|
||||
<a-button v-if="canEdit" type="primary" @click="router.push({ name: editRoute, params: { id } })">
|
||||
<template #icon><EditOutlined /></template>
|
||||
<template #icon><Icon icon="vuesax-linear:edit-2" size="16" /></template>
|
||||
ویرایش مشتری
|
||||
</a-button>
|
||||
</div>
|
||||
@@ -262,17 +262,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../components/icon/Icon.vue';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { theme } from 'ant-design-vue';
|
||||
import {
|
||||
ArrowRightOutlined,
|
||||
CalendarOutlined,
|
||||
EditOutlined,
|
||||
EnvironmentOutlined,
|
||||
PhoneOutlined,
|
||||
UserOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import { jdate, jdateTime } from '../../utils/filters';
|
||||
import api from '../../api/client';
|
||||
import { useUsersStore } from '../../stores/users';
|
||||
|
||||
@@ -54,8 +54,8 @@
|
||||
<div class="flex">
|
||||
<a-dropdown>
|
||||
<div class="cursor-pointer flex items-center">
|
||||
<DownOutlined />
|
||||
<SettingOutlined class="cursor-pointer w-5 ml-1" />
|
||||
<Icon icon="vuesax-linear:arrow-down" size="16" />
|
||||
<Icon icon="vuesax-linear:setting-2" size="16" class="cursor-pointer w-5 ml-1" />
|
||||
</div>
|
||||
<template #overlay>
|
||||
<a-menu @click="handleMenuClick($event, record.id)">
|
||||
@@ -65,7 +65,7 @@
|
||||
@click="toEdit(record.id)"
|
||||
>
|
||||
<div class="flex gap-2">
|
||||
<EditOutlined class="cursor-pointer w-5 ml-1" />
|
||||
<Icon icon="vuesax-linear:edit-2" size="16" class="cursor-pointer w-5 ml-1" />
|
||||
<div>ویرایش</div>
|
||||
</div>
|
||||
</a-menu-item>
|
||||
@@ -76,7 +76,7 @@
|
||||
@click="toView(record.id)"
|
||||
>
|
||||
<div class="flex gap-2">
|
||||
<EyeOutlined class="cursor-pointer w-5 ml-1" />
|
||||
<Icon icon="vuesax-linear:eye" size="16" class="cursor-pointer w-5 ml-1" />
|
||||
<div>مشاهده اطلاعات</div>
|
||||
</div>
|
||||
</a-menu-item>
|
||||
@@ -87,7 +87,7 @@
|
||||
@click="viewOrder(record)"
|
||||
>
|
||||
<div class="flex gap-2">
|
||||
<UnorderedListOutlined class="cursor-pointer w-5 ml-1" />
|
||||
<Icon icon="vuesax-linear:row-vertical" size="16" class="cursor-pointer w-5 ml-1" />
|
||||
<div>مشاهده سفارش</div>
|
||||
</div>
|
||||
</a-menu-item>
|
||||
@@ -98,7 +98,7 @@
|
||||
@click="viewCash(record)"
|
||||
>
|
||||
<div class="flex gap-2">
|
||||
<FileTextOutlined class="cursor-pointer w-5 ml-1" />
|
||||
<Icon icon="vuesax-linear:document-text" size="16" class="cursor-pointer w-5 ml-1" />
|
||||
<div>سند های مالی</div>
|
||||
</div>
|
||||
</a-menu-item>
|
||||
@@ -111,7 +111,7 @@
|
||||
@confirm="toggleArchive(record.id)"
|
||||
>
|
||||
<div class="flex gap-2">
|
||||
<CloudDownloadOutlined class="cursor-pointer w-5 ml-1" />
|
||||
<Icon icon="vuesax-linear:document-download" size="16" class="cursor-pointer w-5 ml-1" />
|
||||
<div>بایگانی کردن</div>
|
||||
</div>
|
||||
</a-popconfirm>
|
||||
@@ -131,8 +131,9 @@
|
||||
@cancel="onCancelStepOne(record)"
|
||||
>
|
||||
<div class="flex gap-2">
|
||||
<component
|
||||
:is="stepIconComponent(getStepOneIcon(record))"
|
||||
<Icon
|
||||
:icon="stepIconId(getStepOneIcon(record))"
|
||||
size="18"
|
||||
class="cursor-pointer w-5 ml-1"
|
||||
:class="stepIconClass(getStepOneIcon(record))"
|
||||
/>
|
||||
@@ -160,8 +161,9 @@
|
||||
@cancel="onCancelStepTwo(record)"
|
||||
>
|
||||
<div class="flex gap-2">
|
||||
<component
|
||||
:is="stepIconComponent(getStepTwoIcon(record))"
|
||||
<Icon
|
||||
:icon="stepIconId(getStepTwoIcon(record))"
|
||||
size="18"
|
||||
class="cursor-pointer w-5 ml-1"
|
||||
:class="stepIconClass(getStepTwoIcon(record))"
|
||||
/>
|
||||
@@ -182,8 +184,9 @@
|
||||
@confirm="toggleSts(record)"
|
||||
>
|
||||
<div class="flex gap-2">
|
||||
<component
|
||||
:is="record.sts === 1 ? CheckOutlined : StopOutlined"
|
||||
<Icon
|
||||
:icon="record.sts === 1 ? 'vuesax-linear:tick-circle' : 'vuesax-linear:slash'"
|
||||
size="18"
|
||||
class="cursor-pointer w-5 ml-1"
|
||||
:class="record.sts === 1 ? 'text-success' : 'text-danger'"
|
||||
/>
|
||||
@@ -209,8 +212,9 @@
|
||||
colouring by getActiveIcon(record) — it shows the ORDER
|
||||
status icon next to the ACCOUNT label. Preserved.
|
||||
-->
|
||||
<component
|
||||
:is="record.sts === 1 ? CheckOutlined : StopOutlined"
|
||||
<Icon
|
||||
:icon="record.sts === 1 ? 'vuesax-linear:tick-circle' : 'vuesax-linear:slash'"
|
||||
size="18"
|
||||
class="cursor-pointer w-5 ml-1"
|
||||
:class="record.active === 1 ? 'text-success' : 'text-danger'"
|
||||
/>
|
||||
@@ -261,22 +265,11 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../../components/icon/Icon.vue';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import moment from 'moment-jalaali';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { message } from 'ant-design-vue';
|
||||
import {
|
||||
CheckOutlined,
|
||||
CloudDownloadOutlined,
|
||||
DownOutlined,
|
||||
EditOutlined,
|
||||
EyeOutlined,
|
||||
FileTextOutlined,
|
||||
QuestionCircleOutlined,
|
||||
SettingOutlined,
|
||||
StopOutlined,
|
||||
UnorderedListOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import XTable from '../../../components/x-table/XTable.vue';
|
||||
import ListPageHeader from '../../../components/common/ListPageHeader.vue';
|
||||
import AccountingSyncButton from '../../../components/accounting/AccountingSyncButton.vue';
|
||||
@@ -394,11 +387,11 @@ function getStepTwoIcon(row: Record<string, any>) {
|
||||
}
|
||||
}
|
||||
|
||||
/** feather name -> ant component, matching legacy's three icons */
|
||||
function stepIconComponent(name?: string) {
|
||||
if (name === 'HelpCircleIcon') return QuestionCircleOutlined;
|
||||
if (name === 'CheckIcon') return CheckOutlined;
|
||||
return StopOutlined; // SlashIcon
|
||||
/** feather name -> Vuesax id, matching legacy's three icons */
|
||||
function stepIconId(name?: string) {
|
||||
if (name === 'HelpCircleIcon') return 'vuesax-linear:message-question';
|
||||
if (name === 'CheckIcon') return 'vuesax-linear:tick-circle';
|
||||
return 'vuesax-linear:slash'; // SlashIcon
|
||||
}
|
||||
function stepIconClass(name?: string) {
|
||||
if (name === 'HelpCircleIcon') return 'text-primary';
|
||||
|
||||
@@ -9,18 +9,15 @@
|
||||
<XTable ref="tbl" :model="model" mobile-cards>
|
||||
<template #op="{ record }">
|
||||
<a-tooltip title="ویرایش">
|
||||
<EditOutlined class="cursor-pointer mx-1 text-primary" @click="toEdit(record.id)" />
|
||||
<Icon icon="vuesax-linear:edit-2" size="16" class="cursor-pointer mx-1 text-primary" @click="toEdit(record.id)" />
|
||||
</a-tooltip>
|
||||
<a-tooltip v-if="hasPermission('wallet.charge') && !is_branch" title="شارژ کیف پول">
|
||||
<CreditCardOutlined
|
||||
class="cursor-pointer mx-1"
|
||||
style="color: #d48806"
|
||||
@click="toCharge(record.id)"
|
||||
/>
|
||||
<Icon icon="vuesax-linear:card" size="16" class="cursor-pointer mx-1" style="color: #d48806"
|
||||
@click="toCharge(record.id)" />
|
||||
</a-tooltip>
|
||||
<!-- legacy gates this on wallet.charge too — preserved -->
|
||||
<a-tooltip v-if="hasPermission('wallet.charge')" title="مشاهده اطلاعات">
|
||||
<EyeOutlined class="cursor-pointer mx-1 text-success" @click="toView(record.id)" />
|
||||
<Icon icon="vuesax-linear:eye" size="16" class="cursor-pointer mx-1 text-success" @click="toView(record.id)" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</XTable>
|
||||
@@ -55,10 +52,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../../components/icon/Icon.vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { CreditCardOutlined, EditOutlined, EyeOutlined } from '@ant-design/icons-vue';
|
||||
import XTable from '../../../components/x-table/XTable.vue';
|
||||
import { buildSingleCustomerListModel } from './SingleCustomerListModel';
|
||||
import { useUsersStore } from '../../../stores/users';
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
@confirm="changeConfirme(record)"
|
||||
>
|
||||
<template #title><p>آیا سند تایید شود ؟</p></template>
|
||||
<CheckOutlined class="cursor-pointer mx-1 text-success" />
|
||||
<Icon icon="vuesax-linear:tick-circle" size="16" class="cursor-pointer mx-1 text-success" />
|
||||
</a-popconfirm>
|
||||
</a-tooltip>
|
||||
|
||||
@@ -39,12 +39,12 @@
|
||||
@confirm="changeConfirme(record)"
|
||||
>
|
||||
<template #title><p>آیا سند رد شود ؟</p></template>
|
||||
<CloseOutlined class="cursor-pointer mx-1 text-danger" />
|
||||
<Icon icon="vuesax-linear:close-circle" size="16" class="cursor-pointer mx-1 text-danger" />
|
||||
</a-popconfirm>
|
||||
</a-tooltip>
|
||||
|
||||
<a-tooltip v-if="hasPermission('document.list.edit')" title="ویرایش">
|
||||
<EditOutlined class="cursor-pointer mx-1 text-primary" @click="openEdit(record.id)" />
|
||||
<Icon icon="vuesax-linear:edit-2" size="16" class="cursor-pointer mx-1 text-primary" @click="openEdit(record.id)" />
|
||||
</a-tooltip>
|
||||
|
||||
<a-tooltip v-if="hasPermission('document.list.remove')" title="حذف">
|
||||
@@ -55,7 +55,7 @@
|
||||
@confirm="deleteCash(record)"
|
||||
>
|
||||
<template #title><p>آیا مطمئن به حذف سند مورد نظر هستید ؟</p></template>
|
||||
<DeleteOutlined class="cursor-pointer mx-1 text-danger" />
|
||||
<Icon icon="vuesax-linear:trash" size="16" class="cursor-pointer mx-1 text-danger" />
|
||||
</a-popconfirm>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
@@ -68,14 +68,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../components/icon/Icon.vue';
|
||||
import { ref } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import {
|
||||
CheckOutlined,
|
||||
CloseOutlined,
|
||||
DeleteOutlined,
|
||||
EditOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import XTable from '../../components/x-table/XTable.vue';
|
||||
import ListPageHeader from '../../components/common/ListPageHeader.vue';
|
||||
import AddFinDoc from './addFinDoc.vue';
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
<a-table :columns="columns" :data-source="items" bordered :pagination="false" row-key="pid">
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'delete'">
|
||||
<CloseOutlined class="cursor-pointer" @click="cart.remove(record)" />
|
||||
<Icon icon="vuesax-linear:close-circle" size="16" class="cursor-pointer" @click="cart.remove(record)" />
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'product'">
|
||||
<div class="flex items-center">
|
||||
@@ -113,7 +113,7 @@
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'delete'">
|
||||
<CloseOutlined class="cursor-pointer" @click="cart.remove(record)" />
|
||||
<Icon icon="vuesax-linear:close-circle" size="16" class="cursor-pointer" @click="cart.remove(record)" />
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'product'">
|
||||
<div class="flex items-center">
|
||||
@@ -161,10 +161,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../components/icon/Icon.vue';
|
||||
import { computed, onMounted, reactive, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { CloseOutlined } from '@ant-design/icons-vue';
|
||||
import BaseFormModal from '../../components/common/BaseFormModal.vue';
|
||||
import XTable from '../../components/x-table/XTable.vue';
|
||||
import { buildInvoiceProductModel } from './AddInvoice';
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
<template #actions="{ record }">
|
||||
<div class="flex gap-2">
|
||||
<a-tooltip title="مشاهده">
|
||||
<EyeOutlined class="cursor-pointer mx-1 text-success" @click="view(record)" />
|
||||
<Icon icon="vuesax-linear:eye" size="16" class="cursor-pointer mx-1 text-success" @click="view(record)" />
|
||||
</a-tooltip>
|
||||
|
||||
<a-tooltip title="ویرایش">
|
||||
<EditOutlined class="cursor-pointer mx-1 text-primary" @click="openEdit(record.id)" />
|
||||
<Icon icon="vuesax-linear:edit-2" size="16" class="cursor-pointer mx-1 text-primary" @click="openEdit(record.id)" />
|
||||
</a-tooltip>
|
||||
|
||||
<a-tooltip title="حذف">
|
||||
@@ -32,7 +32,7 @@
|
||||
@confirm="confirmDelete(`branch/product/${record.id}`)"
|
||||
>
|
||||
<template #title><p>آیا مطمئن به حذف فاکتور مورد نظر هستید ؟</p></template>
|
||||
<DeleteOutlined class="cursor-pointer mx-1 text-danger" />
|
||||
<Icon icon="vuesax-linear:trash" size="16" class="cursor-pointer mx-1 text-danger" />
|
||||
</a-popconfirm>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
@@ -74,9 +74,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../components/icon/Icon.vue';
|
||||
import { ref } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { DeleteOutlined, EditOutlined, EyeOutlined } from '@ant-design/icons-vue';
|
||||
import XTable from '../../components/x-table/XTable.vue';
|
||||
import ListPageHeader from '../../components/common/ListPageHeader.vue';
|
||||
import AddInvoice from './AddInvoice.vue';
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'op'">
|
||||
<a-tooltip v-if="hasPermission('config.statics.brand.edit')" title="ویرایش">
|
||||
<EditOutlined class="cursor-pointer mx-1 text-primary" @click="editBrand(record)" />
|
||||
<Icon icon="vuesax-linear:edit-2" size="16" class="cursor-pointer mx-1 text-primary" @click="editBrand(record)" />
|
||||
</a-tooltip>
|
||||
<a-tooltip v-if="hasPermission('config.statics.brand.remove')" title="حذف">
|
||||
<a-popconfirm
|
||||
@@ -53,7 +53,7 @@
|
||||
title="آیا مطمئن هستید؟"
|
||||
@confirm="removeBrand(record.id)"
|
||||
>
|
||||
<DeleteOutlined class="cursor-pointer mx-1 text-danger" />
|
||||
<Icon icon="vuesax-linear:trash" size="16" class="cursor-pointer mx-1 text-danger" />
|
||||
</a-popconfirm>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
@@ -105,7 +105,7 @@
|
||||
<span class="slider-count">{{ sliders.length }} اسلاید</span>
|
||||
<div class="row">
|
||||
<a-button @click="addSlide">
|
||||
<template #icon><PlusOutlined /></template>
|
||||
<template #icon><Icon icon="vuesax-linear:add" size="16" /></template>
|
||||
افزودن اسلاید
|
||||
</a-button>
|
||||
<a-button type="primary" @click="saveSliders">ذخیره اسلایدر</a-button>
|
||||
@@ -125,7 +125,7 @@
|
||||
@confirm="removeSlide(index)"
|
||||
>
|
||||
<a-button type="text" danger size="small" title="حذف">
|
||||
<template #icon><DeleteOutlined /></template>
|
||||
<template #icon><Icon icon="vuesax-linear:trash" size="16" /></template>
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
</div>
|
||||
@@ -163,10 +163,7 @@
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'op'">
|
||||
<a-tooltip title="ویرایش">
|
||||
<EditOutlined
|
||||
class="cursor-pointer mx-1 text-primary"
|
||||
@click="editCollection(record)"
|
||||
/>
|
||||
<Icon icon="vuesax-linear:edit-2" size="16" class="cursor-pointer mx-1 text-primary" @click="editCollection(record)" />
|
||||
</a-tooltip>
|
||||
<a-tooltip title="حذف">
|
||||
<a-popconfirm
|
||||
@@ -175,7 +172,7 @@
|
||||
title="آیا مطمئن هستید؟"
|
||||
@confirm="removeCollection(record.id)"
|
||||
>
|
||||
<DeleteOutlined class="cursor-pointer mx-1 text-danger" />
|
||||
<Icon icon="vuesax-linear:trash" size="16" class="cursor-pointer mx-1 text-danger" />
|
||||
</a-popconfirm>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
@@ -192,9 +189,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../components/icon/Icon.vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { DeleteOutlined, EditOutlined, PlusOutlined } from '@ant-design/icons-vue';
|
||||
import { useUsersStore } from '../../stores/users';
|
||||
import { useDeleteHandler } from '../../composables/useDeleteHandler';
|
||||
import api from '../../api/client';
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<XTable ref="tbl" :model="model" mobile-cards>
|
||||
<template #opt="{ record }">
|
||||
<a-tooltip title="مشاهده">
|
||||
<EyeOutlined class="cursor-pointer mx-1 text-primary" @click="view(record)" />
|
||||
<Icon icon="vuesax-linear:eye" size="16" class="cursor-pointer mx-1 text-primary" @click="view(record)" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</XTable>
|
||||
@@ -52,9 +52,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../components/icon/Icon.vue';
|
||||
import { ref } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { EyeOutlined } from '@ant-design/icons-vue';
|
||||
import XTable from '../../components/x-table/XTable.vue';
|
||||
import { buildNotifyModel } from './notifyTbl';
|
||||
import api from '../../api/client';
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<a-dropdown>
|
||||
<a-button style="margin-left: 8px">
|
||||
افزودن
|
||||
<DownOutlined />
|
||||
<Icon icon="vuesax-linear:arrow-down" size="16" />
|
||||
</a-button>
|
||||
<template #overlay>
|
||||
<a-menu @click="onVariantPick(record, $event)">
|
||||
@@ -53,7 +53,7 @@
|
||||
>
|
||||
<template #bodyCell="{ column, record, index }">
|
||||
<template v-if="column.dataIndex === 'delete'">
|
||||
<CloseOutlined class="cursor-pointer" @click="cart.remove(record)" />
|
||||
<Icon icon="vuesax-linear:close-circle" size="16" class="cursor-pointer" @click="cart.remove(record)" />
|
||||
</template>
|
||||
|
||||
<template v-else-if="column.dataIndex === 'product'">
|
||||
@@ -85,11 +85,11 @@
|
||||
<div class="flex">
|
||||
<template v-if="!variant.grams || variant.id !== getVariant(record).id">
|
||||
<span style="width: max-content">{{ getVariant(record).title }}</span>
|
||||
<EditOutlined class="cursor-pointer ml-2 text-primary" @click="toEdit(record)" />
|
||||
<Icon icon="vuesax-linear:edit-2" size="16" class="cursor-pointer ml-2 text-primary" @click="toEdit(record)" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<a-input-number v-model:value="variant.grams" />
|
||||
<CheckOutlined class="cursor-pointer ml-2 text-success" @click="editGram" />
|
||||
<Icon icon="vuesax-linear:tick-circle" size="16" class="cursor-pointer ml-2 text-success" @click="editGram" />
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
@@ -191,15 +191,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../components/icon/Icon.vue';
|
||||
import { computed, onMounted, reactive, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { message } from 'ant-design-vue';
|
||||
import {
|
||||
CheckOutlined,
|
||||
CloseOutlined,
|
||||
DownOutlined,
|
||||
EditOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import XTable from '../../components/x-table/XTable.vue';
|
||||
import { buildProductListModel } from '../apps/product/productListModel';
|
||||
import { useCartStore, type CartItem, type CartVariant } from '../../stores/cart';
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
<template #op="{ record }">
|
||||
<a-tooltip v-if="canEdit(record)" title="ویرایش">
|
||||
<EditOutlined class="cursor-pointer mx-1 text-primary" @click="openEdit(record)" />
|
||||
<Icon icon="vuesax-linear:edit-2" size="16" class="cursor-pointer mx-1 text-primary" @click="openEdit(record)" />
|
||||
</a-tooltip>
|
||||
|
||||
<a-tooltip v-if="canRemove(record)" title="حذف">
|
||||
@@ -47,7 +47,7 @@
|
||||
@confirm="deletePromotion(record)"
|
||||
>
|
||||
<template #title><p>آیا مطمئن به حذف تخفیف مورد نظر هستید ؟</p></template>
|
||||
<DeleteOutlined class="cursor-pointer mx-1 text-danger" />
|
||||
<Icon icon="vuesax-linear:trash" size="16" class="cursor-pointer mx-1 text-danger" />
|
||||
</a-popconfirm>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
@@ -74,9 +74,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../components/icon/Icon.vue';
|
||||
import { ref } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { DeleteOutlined, EditOutlined } from '@ant-design/icons-vue';
|
||||
import XTable from '../../components/x-table/XTable.vue';
|
||||
import ListPageHeader from '../../components/common/ListPageHeader.vue';
|
||||
import PromotionAddEdit from './promotion_add_edit.vue';
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
<template #op="{ record }">
|
||||
<a-tooltip v-if="hasPermission('user.list.edit')" title="ویرایش">
|
||||
<EditOutlined class="cursor-pointer mx-1 text-primary" @click="openEdit(record)" />
|
||||
<Icon icon="vuesax-linear:edit-2" size="16" class="cursor-pointer mx-1 text-primary" @click="openEdit(record)" />
|
||||
</a-tooltip>
|
||||
|
||||
<a-tooltip v-if="hasPermission('user.list.remove')" title="حذف">
|
||||
@@ -29,7 +29,7 @@
|
||||
@confirm="confirmDelete(`users/${record.id}`)"
|
||||
>
|
||||
<template #title><p>آیا مطمئن به حذف کاربر مورد نظر هستید ؟</p></template>
|
||||
<DeleteOutlined class="cursor-pointer mx-1 text-danger" />
|
||||
<Icon icon="vuesax-linear:trash" size="16" class="cursor-pointer mx-1 text-danger" />
|
||||
</a-popconfirm>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
@@ -41,9 +41,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../../components/icon/Icon.vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { DeleteOutlined, EditOutlined } from '@ant-design/icons-vue';
|
||||
import XTable from '../../components/x-table/XTable.vue';
|
||||
import ListPageHeader from '../../components/common/ListPageHeader.vue';
|
||||
import UserCreate from './UserCreate.vue';
|
||||
|
||||
Generated
-3
@@ -17,9 +17,6 @@ importers:
|
||||
|
||||
apps/admin-panel:
|
||||
dependencies:
|
||||
'@ant-design/icons-vue':
|
||||
specifier: ^7.0.1
|
||||
version: 7.0.1(vue@3.5.42(typescript@5.9.3))
|
||||
'@hedena-gold/shared-types':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/shared-types
|
||||
|
||||
Reference in New Issue
Block a user