kashkool ver 1

This commit is contained in:
2026-06-13 13:52:47 +03:30
parent 8c5f48e05a
commit 1632b5cd02
4 changed files with 239 additions and 30 deletions
+1
View File
@@ -8,6 +8,7 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
AButton: typeof import('ant-design-vue/es')['Button']
AConfigProvider: typeof import('ant-design-vue/es')['ConfigProvider']
ADivider: typeof import('ant-design-vue/es')['Divider']
AForm: typeof import('ant-design-vue/es')['Form']
AFormItem: typeof import('ant-design-vue/es')['FormItem']
+73 -17
View File
@@ -84,15 +84,24 @@
<div class="home_appear_fade_in_up mt-2">نسخه جدید منتشر شد!</div>
</div>
</van-dialog>
<a v-if="config.config?.name === 'garoosi'" href="https://ble.ir/garoosigallery" target="_blank"
id="support-button">
<div class="bg-green-100 text-green-800 flex gap-2 p-2 rounded-lg mr-2">
<div
v-if="showSupportButton && !showSplash"
id="support-button"
class="draggable-support-button"
:class="{ 'is-dragging': supportDragging }"
:style="supportButtonStyle"
@pointerdown="onSupportPointerDown"
@pointermove="onSupportPointerMove"
@pointerup="handleSupportPointerUp"
@pointercancel="onSupportPointerCancel"
>
<div class="bg-green-100 text-green-800 flex gap-2 p-2 rounded-lg">
<span>پشتیبانی</span>
<div class="w-5">
<img src="/src/assets/img/support.png" alt=""/>
<div class="w-5">
<img src="/logo-montzar.png" alt="" draggable="false" />
</div>
</div>
</a>
</div>
</div>
<div
v-if="!showSplash"
@@ -126,6 +135,12 @@ import {useConfigStore} from "@/store/configStore";
import {getProjectFontFamily, getProjectLoginLogo, getProjectSplashBackground, getProjectBrandRed, hasCustomLoginLogoLayout, isBoursecuProject} from "@/utils/config";
import {ConfigProvider as AConfigProvider} from 'ant-design-vue'
import BasicIcon from "@/components/BasicPacks/BasicIcon.vue";
import {
buildSupportMessengerUrl,
loadSupportMessengerFromSettings,
supportMessengerSettings,
} from '@/utils/supportMessenger'
import {useDraggableFloatingButton} from '@/utils/useDraggableFloatingButton'
const {offlineReady, needRefresh, updateServiceWorker} = useRegisterSW()
const config = useConfigStore()
@@ -139,6 +154,44 @@ const splashIndicator = computed(() => h(LoadingOutlined, {
const showSplash = ref(true)
const popVisible = ref(false)
const GAROOSI_SUPPORT_URL = 'https://ble.ir/garoosigallery'
const supportLink = computed(() => {
if (config.config?.name === 'garoosi') {
return GAROOSI_SUPPORT_URL
}
return buildSupportMessengerUrl(
supportMessengerSettings.value.messenger,
supportMessengerSettings.value.messengerId
)
})
const showSupportButton = computed(() => !!supportLink.value)
const {
dragging: supportDragging,
fabStyle: supportButtonStyle,
handlePointerDown: onSupportPointerDown,
handlePointerMove: onSupportPointerMove,
handlePointerUp: supportPointerUp,
handlePointerCancel: onSupportPointerCancel
} = useDraggableFloatingButton('khaneghi_support_button_position', {
width: 110,
height: 44,
defaultBottomOffset: 120
})
function openSupportLink() {
if (!supportLink.value) return
window.open(supportLink.value, '_blank', 'noopener,noreferrer')
}
function handleSupportPointerUp(event: PointerEvent) {
if (supportPointerUp(event)) {
openSupportLink()
}
}
const antTheme = computed(() => {
if (!config.config?.color) return null
@@ -164,6 +217,7 @@ const antTheme = computed(() => {
onMounted(async () => {
await config.getConfigData()
await loadSupportMessengerFromSettings()
console.log(config?.config?.color)
checkVersion()
setTimeout(() => {
@@ -235,18 +289,20 @@ function update() {
#support-button {
position: fixed;
bottom: calc(80px + var(--app-credit-footer-offset, 28px) + 12px);
right: 20px;
width: 70px;
height: 70px;
//border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
//box-shadow: 0 4px 10px rgba(0,0,0,0.3);
cursor: pointer;
transition: transform 0.2s ease, box-shadow 0.2s ease;
z-index: 9999;
cursor: grab;
user-select: none;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
border-radius: 0.5rem;
&.is-dragging {
cursor: grabbing;
box-shadow: 0 8px 18px rgba(0, 0, 0, 0.22);
}
img {
pointer-events: none;
}
}
@media screen and (min-width: 426px) {
+165
View File
@@ -0,0 +1,165 @@
import { computed, onMounted, onUnmounted, ref } from 'vue'
const DRAG_THRESHOLD = 6
type FabPosition = { x: number; y: number }
type DraggableFloatingOptions = {
width?: number
height?: number
defaultBottomOffset?: number
defaultRightOffset?: number
}
export function useDraggableFloatingButton(
storageKey: string,
options: DraggableFloatingOptions = {}
) {
const width = options.width ?? 96
const height = options.height ?? 44
const defaultBottomOffset = options.defaultBottomOffset ?? 120
const defaultRightOffset = options.defaultRightOffset ?? 20
const pos = ref<FabPosition>({ x: 0, y: 0 })
const dragging = ref(false)
let pointerId: number | null = null
let startX = 0
let startY = 0
let originX = 0
let originY = 0
let hasMoved = false
const fabStyle = computed(() => ({
left: `${pos.value.x}px`,
top: `${pos.value.y}px`,
width: `${width}px`,
touchAction: 'none'
}))
function getViewportWidth() {
return Math.min(window.innerWidth, 426)
}
function getHorizontalOffset() {
const vw = window.innerWidth
const contentWidth = getViewportWidth()
return Math.max(0, (vw - contentWidth) / 2)
}
function resetToDefault() {
const vh = window.innerHeight
const offsetX = getHorizontalOffset()
const contentWidth = getViewportWidth()
pos.value = {
x: offsetX + contentWidth - width - defaultRightOffset,
y: vh - defaultBottomOffset - height
}
}
function clampToViewport() {
const vw = window.innerWidth
const vh = window.innerHeight
pos.value = {
x: Math.max(0, Math.min(vw - width, pos.value.x)),
y: Math.max(0, Math.min(vh - height, pos.value.y))
}
}
function loadPosition() {
try {
const raw = localStorage.getItem(storageKey)
if (!raw) return false
const parsed = JSON.parse(raw) as FabPosition
if (typeof parsed?.x === 'number' && typeof parsed?.y === 'number') {
pos.value = parsed
clampToViewport()
return true
}
} catch {
// ignore
}
return false
}
function savePosition() {
localStorage.setItem(storageKey, JSON.stringify(pos.value))
}
function handleResize() {
clampToViewport()
savePosition()
}
function handlePointerDown(event: PointerEvent) {
dragging.value = true
hasMoved = false
pointerId = event.pointerId
startX = event.clientX
startY = event.clientY
originX = pos.value.x
originY = pos.value.y
;(event.currentTarget as HTMLElement)?.setPointerCapture?.(event.pointerId)
}
function handlePointerMove(event: PointerEvent) {
if (!dragging.value || pointerId !== event.pointerId) return
const dx = event.clientX - startX
const dy = event.clientY - startY
if (Math.abs(dx) > DRAG_THRESHOLD || Math.abs(dy) > DRAG_THRESHOLD) {
hasMoved = true
}
pos.value = {
x: originX + dx,
y: originY + dy
}
clampToViewport()
}
function finishPointer(event: PointerEvent) {
if (!dragging.value || pointerId !== event.pointerId) return false
dragging.value = false
pointerId = null
savePosition()
const clicked = !hasMoved
hasMoved = false
return clicked
}
function handlePointerUp(event: PointerEvent) {
return finishPointer(event)
}
function handlePointerCancel(event: PointerEvent) {
finishPointer(event)
return false
}
onMounted(() => {
if (!loadPosition()) {
resetToDefault()
}
window.addEventListener('resize', handleResize)
})
onUnmounted(() => {
window.removeEventListener('resize', handleResize)
})
return {
dragging,
fabStyle,
handlePointerDown,
handlePointerMove,
handlePointerUp,
handlePointerCancel,
resetToDefault
}
}
-13
View File
@@ -118,8 +118,6 @@
:src="getProjectNavLogo(config.config?.avatar)"
/>
</div>
<!-- <div class="flex justify-center">خرید </div>
<div class="flex justify-center">محصول </div>-->
</div>
</div>
<!-- <div :class="setNavColor('buyProduct')" class="tab" @click="setRoute('buyProduct')">
@@ -157,17 +155,6 @@ import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import {useConfigStore} from "@/store/configStore";
import {getConfigApp, getProjectNavLogo, isBoursecuProject} from "@/utils/config";
/*onMounted(async () => {
const c = await document.getElementById("canvas1");
const ctx = c.getContext("2d");
console.log(ctx)
ctx.beginPath();
ctx.moveTo(0,20);
ctx.lineTo(165,20)
ctx.arc(200, 50, 45, 3.9, 5.5, false);
ctx.lineTo(400,20)
ctx.stroke();
})*/
const currentRoute = computed(() => router.currentRoute.value.name)
const hideMenu = computed(() => !!router.currentRoute.value.meta.hideMenu)
const config = useConfigStore()