Expand SuperAdmin web for SMS, servers, plugins, admins, and UI config.

Align SMS tenant panel with Hamkar, add Jalali dates, and support hamkar/khanegi appearance editing.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-30 18:19:54 +03:30
co-authored by Cursor
parent 3371015b96
commit cfee6b0546
27 changed files with 4528 additions and 408 deletions
+146
View File
@@ -0,0 +1,146 @@
<script setup lang="ts">
import { computed } from 'vue'
import Vue3PersianDatetimePicker from 'vue3-persian-datetime-picker'
import {
iranDateInputToIso,
isoToIranDateInput,
todayIranDateInput,
} from '@/utils/datetime'
const props = withDefaults(
defineProps<{
modelValue?: string | null
/** 'iso' = ISO string for API; 'ymd' = YYYY-MM-DD Gregorian (Iran day) */
valueType?: 'iso' | 'ymd'
placeholder?: string
disabled?: boolean
clearable?: boolean
size?: 'large' | 'middle' | 'small'
}>(),
{
modelValue: null,
valueType: 'iso',
placeholder: 'انتخاب تاریخ',
disabled: false,
clearable: true,
size: 'large',
},
)
const emit = defineEmits<{
'update:modelValue': [value: string | null]
}>()
const pickerValue = computed({
get() {
if (!props.modelValue) return ''
if (props.valueType === 'ymd') return props.modelValue
return isoToIranDateInput(props.modelValue)
},
set(val: string | null | undefined) {
const raw = (val || '').trim()
if (!raw) {
emit('update:modelValue', null)
return
}
if (props.valueType === 'ymd') {
emit('update:modelValue', raw)
return
}
emit('update:modelValue', iranDateInputToIso(raw))
},
})
function setToday() {
const ymd = todayIranDateInput()
if (props.valueType === 'ymd') {
emit('update:modelValue', ymd)
} else {
emit('update:modelValue', iranDateInputToIso(ymd))
}
}
</script>
<template>
<div class="jalali-date-field" :class="[`size-${size}`]">
<Vue3PersianDatetimePicker
v-model="pickerValue"
simple
:disabled="disabled"
:clearable="clearable"
format="YYYY-MM-DD"
display-format="jYYYY/jMM/jDD"
:placeholder="placeholder"
input-class="jalali-date-input"
class="jalali-picker"
/>
<button
v-if="!disabled"
type="button"
class="today-btn"
@click="setToday"
>
امروز
</button>
</div>
</template>
<style scoped>
.jalali-date-field {
display: flex;
gap: 8px;
align-items: stretch;
width: 100%;
}
.jalali-date-field :deep(.vpd-input-group),
.jalali-date-field :deep(.jalali-picker) {
flex: 1;
width: 100%;
}
.jalali-date-field :deep(.jalali-date-input),
.jalali-date-field :deep(input) {
width: 100%;
height: 40px;
border: 1px solid #d9d9d9;
border-radius: 8px;
padding: 4px 11px;
font-family: inherit;
font-size: 14px;
direction: ltr;
text-align: left;
background: #fff;
}
.size-large :deep(.jalali-date-input),
.size-large :deep(input) {
height: 48px;
font-size: 16px;
border-radius: 10px;
}
.jalali-date-field :deep(input:focus) {
border-color: #20c997;
outline: none;
box-shadow: 0 0 0 2px rgba(32, 201, 151, 0.15);
}
.today-btn {
appearance: none;
border: 1px solid #d9d9d9;
background: #f8fafc;
border-radius: 10px;
padding: 0 12px;
cursor: pointer;
font-family: inherit;
font-weight: 700;
color: #475569;
white-space: nowrap;
}
.today-btn:hover {
border-color: #20c997;
color: #0f766e;
}
</style>