1405/02/09-change style in configuration page

This commit is contained in:
2026-04-29 11:20:59 +03:30
parent 688c356e7d
commit fcd6420385
8 changed files with 652 additions and 79 deletions
-1
View File
@@ -46,7 +46,6 @@ declare module '@vue/runtime-core' {
ATable: typeof import('ant-design-vue/es')['Table']
ATabPane: typeof import('ant-design-vue/es')['TabPane']
ATabs: typeof import('ant-design-vue/es')['Tabs']
ATag: typeof import('ant-design-vue/es')['Tag']
ATextarea: typeof import('ant-design-vue/es')['Textarea']
ATooltip: typeof import('ant-design-vue/es')['Tooltip']
AUpload: typeof import('ant-design-vue/es')['Upload']
+26
View File
@@ -0,0 +1,26 @@
export interface Const {
id?: number | undefined
key?: string
value?: string | undefined
description?: string
type: string
title_fa: string
}
export interface SupportLink {
show_to_users_goftino: string
show_to_users_eitaa: string
show_to_users_telegram: string
show_to_users_whatsapp: string
show_to_users_bale: string
show_to_users_phone: string
}
export interface itemConfig {
id: number | string
name: string
value: string
key: string
type: string
list: []
}
@@ -0,0 +1,83 @@
<template>
<div class="flex mb-2">
<div class="flex flex-col justify-between ">
<div class=" font-bold">{{ item.name }}</div>
<div class=" text-xs ">کلید: {{ item.key }}</div>
</div>
<BaseIcon
@click="ok()"
icon="vuesax-linear:tick-circle"
class="mr-2 items-center"
color="green"
size="24"
/>
</div>
<BasicTextArea v-model:value="content" />
<!-- <QuillEditor-->
<!-- placeholder="متن قانون"-->
<!-- v-model:content="content"-->
<!-- toolbar="full"-->
<!-- theme="snow"-->
<!-- content-type="html"-->
<!-- class="editor-box"-->
<!-- />-->
</template>
<script setup lang="ts">
import {loading} from '@/utils'
// import '@vueup/vue-quill/dist/vue-quill.snow.css'
import {getConfiguration, setConfiguration} from '@/api/configuration'
import {message} from 'ant-design-vue'
import type { TagItem } from '@/components/BasicTags/model'
import BasicTextArea from "@/components/BasicTextArea.vue";
interface Prop {
item: TagItem
}
const props = defineProps<Prop>()
const emits = defineEmits(['setVal'])
async function ok() {
let obj = {
id: props.item.id,
key: props.item.key,
value: content.value,
description: props.item.description
}
try {
loading.value = true
await setConfiguration(obj)
await getConfiguration()
message.success('تغییر با موفقیت انجام شد')
} catch (e) {
console.error(e)
} finally {
loading.value = false
}
}
const content = computed({
get: () => props.item.value,
set: (val) => {
emits('setVal', val)
}
})
</script>
<style>
.editor-box {
max-height: 40vh;
overflow-y: auto;
border: 1px solid #ddd;
border-radius: 8px;
padding: 10px;
}
.editor-box .ql-editor {
min-height: 10vh;
overflow-y: auto;
box-sizing: border-box;
}
</style>
@@ -0,0 +1,52 @@
<template>
<div class="flex-wrap mb-2 flex justify-between items-center border-1 border-gray-300 border-solid rounded-lg p-3">
<div class="flex flex-col justify-between ">
<div class=" font-bold">{{ item.name }}</div>
<div class=" text-xs ">کلید: {{ item.key }}</div>
</div>
<div class="flex">
<a-switch
checked-children="فعال"
un-checked-children="غیرفعال"
v-model:checked="value"
@change="ok"
/>
</div>
</div>
</template>
<script setup lang="ts">
import type { Order } from '@/model/order'
import { loading } from '@/utils'
import { setConfiguration } from '@/api/configuration'
import { message } from 'ant-design-vue'
import { onMounted } from 'vue'
interface Prop {
item: Order
}
const props = defineProps<Prop>()
const value = ref<string>('false')
async function ok() {
let obj = {
id: props.item.id,
key: props.item.key,
value: value.value,
description: props.item.description
}
try {
loading.value = true
await setConfiguration(obj)
message.success('تغییر با موفقیت انجام شد')
} catch (e) {
console.error(e)
} finally {
loading.value = false
}
}
onMounted(() => (value.value = props.item.value === 'true'))
</script>
@@ -0,0 +1,80 @@
<template>
<div class="mb-2 justify-between border-1 border-gray-300 border-solid rounded-lg p-3">
<div class="flex mb-2 flex-col justify-between ">
<div class=" font-bold">{{ item.name }}</div>
<div class=" text-xs ">کلید: {{ item.key }}</div>
</div> <div class="flex justify-between gap-1">
<BasicSelect class="w-full" v-if="item.list && item.list.length > 0" @change="ok" value-name="value" key-name="lable" v-model:value="value" :items="itemListLocal"/>
<BasicInput v-else class="flex-1" type="text" place-holder="مقدار" v-model:value="value" @input="isChanged=true" />
<div v-if="item.list && item.list.length==0 && isChanged" class="flex items-center " >
<BaseIcon
icon="vuesax-linear:tick-circle"
class="mr-2 items-center cursor-pointer"
color="green"
size="24"
@click="ok()"
/>
<BaseIcon
icon="vuesax-linear:close-circle"
class="mr-2 items-center cursor-pointer"
color="red"
@click="canselFn"
size="24"
/>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import type { Order } from '@/model/order'
import { loading } from '@/utils'
import { setConfiguration } from '@/api/configuration'
import { message } from 'ant-design-vue'
import type {itemConfig} from "@/model/configuration";
interface Prop {
item: itemConfig
}
const props = defineProps<Prop>()
const value = ref<string>('')
const isChanged=ref<boolean>(false)
const itemListLocal = computed(() => {
if (!props.item.list) return []
return props.item.list.map((x) => ({
lable: x,
value: x
}))
})
const canselFn=()=>{
value.value = props.item.value
isChanged.value=false
}
async function ok() {
let obj = {
id: props.item.id,
key: props.item.key,
value: value.value,
description: props.item.description
}
try {
loading.value = true
await setConfiguration(obj)
message.success('تغییر با موفقیت انجام شد')
isChanged.value=false
} catch (e) {
console.error(e)
} finally {
loading.value = false
}
}
onMounted(() => {
console.log(props.item)
return value.value = props.item.value
})
</script>
+247 -56
View File
@@ -1,24 +1,69 @@
<template>
<div>
<BasicShowContent title="تنظیمات">
<BasicTags :items="items" color="green" @add="add" @edit="edit" :key="refresh" :loading="loading"
:closable="false" />
<BaseButton class="mb-10" @click="add" type="primary" icon="vuesax-linear:add">
افزودن
</BaseButton>
<template v-if="items && hasAnyItems">
<div v-if="groupedItems.switch.length > 0" class="mb-4">
<div class="grid lg:grid-cols-2 xl:grid-cols-3 gap-2">
<SwitchConfigs v-for="item in groupedItems.switch" :key="item.id" :item="item"/>
</div>
</div>
<div v-if="groupedItems.text.length > 0" class="mb-4">
<div class="h-1px bg-gray-300 my-4"></div>
<div class="grid lg:grid-cols-2 xl:grid-cols-3 gap-2">
<TextConfigs v-for="item in groupedItems.text" :key="item.id" :item="item"/>
</div>
</div>
<div v-if="groupedItems.longtext.length > 0">
<div class="h-1px bg-gray-300 my-4"></div>
<div class="gap-2">
<LongtextConfigs
v-for="item in groupedItems.longtext"
:key="item.id"
:item="item"
@set-val="(val) => (item.value = val)"
/>
</div>
</div>
</template>
</BasicShowContent>
<BasicModal v-model:visible="addConfigVisible" :title="editId ? `ویرایش` : 'افزودن'"
@close="addConfigVisible = false" @ok="ok" :loading="loading">
<BasicModal
v-model:visible="addConfigVisible"
title="افزودن"
@close="addConfigVisible = false"
@ok="ok"
:loading="loading"
>
<a-form ref="formRef" :model="form" autocomplete="off">
<a-form-item name="is_active">
<span class="ml-2">وضعیت :</span>
<a-checkbox v-model:checked="form.is_active">{{ !form.is_active ? 'غیرفعال' : 'فعال' }}</a-checkbox>
</a-form-item>
<a-form-item v-if="!editId" name="key" label="کلید" >
<a-form-item name="title_fa" label="عنوان">
<BasicInput v-model:value="form.title_fa" :placeHolder="form.title_fa" />
</a-form-item>
<a-form-item name="key" label="کلید">
<BasicInput v-model:value="form.key" :placeHolder="form.key" />
</a-form-item>
<a-form-item name="value" :label="!editId ? 'مقدار' : form.key">
<a-form-item name="type" label="نوع">
<BasicSelect
allowClear
v-model:value="form.type"
:items="typeItems"
valueName="value"
keyName="key"
/>
</a-form-item>
<a-form-item name="value" label="مقدار">
<BasicInput v-model:value="form.value" :placeHolder="form.value" />
</a-form-item>
<a-form-item name="description" :label="'توضیحات'">
<BasicInput v-model:value="form.description" :placeHolder="form.description" />
<a-form-item name="description" label="توضیحات">
<BasicTextArea v-model:value="form.description" :placeHolder="form.description" />
</a-form-item>
</a-form>
</BasicModal>
@@ -28,106 +73,252 @@
<script setup lang="ts">
import BasicShowContent from '@/components/BasicShowContext.vue'
import BasicModal from '@/components/BasicModal.vue'
import BasicTags from '@/components/BasicTags/index.vue'
import type { FormInstance } from 'ant-design-vue'
import { message } from 'ant-design-vue'
import type { Const } from '@/model/const'
import type { TagItem } from '@/components/BasicTags/model'
import BasicInput from '@/components/BasicInput.vue'
import BasicTextArea from '@/components/BasicTextArea.vue'
import TextConfigs from '@/pages/menuPages/configuration/components/TextConfigs.vue'
import LongtextConfigs from '@/pages/menuPages/configuration/components/LongtextConfigs.vue'
import { loading } from '@/utils'
import { getConfiguration, setConfiguration } from '@/api/configuration'
//radio button
const checked = ref(false)
//data Arrays
const items = ref<Array<TagItem>>()
const items = ref<Array<any>>()
const baseData = ref<Array<Const>>()
//nature modal
const addConfigVisible = ref<boolean>()
//refresh
let refresh = 0
//modal
const addConfigVisible = ref<boolean>(false)
const form = ref<Const>({
key: '',
value: ''
value: '',
title_fa:'',
type: 'text',
description: '',
is_active: true
})
const formRef = ref<FormInstance>()
//get nature
const typeItems = [
{
value: 'متنی کوتاه',
key: 'text'
},
{
value: 'متنی بلند',
key: 'longtext'
},
{
value: 'سوییچی',
key: 'switch'
}
]
onMounted(() => {
initConfig()
})
const settingsConfig = {
// اطلاعات پایه
'name_fa': {
title: 'نام فارسی',
list: []
},
'name_en': {
title: 'نام انگلیسی',
list: []
},
'app_url': {
title: 'آدرس اپلیکیشن',
list: []
},
'bace_url': {
title: 'آدرس پایه',
list: []
},
'admin_url': {
title: 'آدرس پنل ادمین',
list: []
},
'server_url': {
title: 'آدرس سرور',
list: []
},
// ته‌حساب
'tahesab_token': {
title: 'توکن ته‌حساب',
list: []
},
'tahesab_db': {
title: 'دیتابیس ته‌حساب',
list: []
},
'send_to_tahesab': {
title: 'ارسال اسناد به ته حساب',
list: ['true', 'false']
},
// تنظیمات صفحه‌ها
'has_page_earn_money': {
title: 'صفحه کسب درآمد',
list: ['true', 'false']
},
'has_page_fund': {
title: 'صفحه سرمایه‌گذاری',
list: ['true', 'false']
},
'has_page_permission': {
title: 'صفحه دسترسی‌ها',
list: ['true', 'false']
},
'has_page_price_trigger': {
title: 'صفحه هشدار قیمت',
list: ['true', 'false']
},
'has_page_physical_gold': {
title: 'صفحه طلای فیزیکی',
list: ['true', 'false']
},
// رنگ‌ها
'color_primary': {
title: 'رنگ اصلی',
list: []
},
'color_secondary': {
title: 'رنگ ثانویه',
list: []
},
// کارمزدها
'fee_service_charge_percentage': {
title: 'کارمزد درصدی',
list: []
},
'fee_cash': {
title: 'کارمزد ریالی',
list: []
},
'fee_single': {
title: 'اختلاف با قیمت واقعی',
list: []
},
'fee_free': {
title: 'تعداد سفارش اول بدون کارمزد',
list: []
},
// تنظیمات عمومی
'has_chat': {
title: 'فعال بودن چت',
list: ['true', 'false']
},
'is_requaire_referral': {
title: 'نیازمند معرف',
list: ['true', 'false']
},
'auto_active_customer': {
title: 'فعالسازی خودکار حساب کاربران',
list: ['true', 'false']
},
'open_register': {
title: 'فعالسازی ثبت ‌نام',
list: ['true', 'false']
},
'charge_notif': {
title: 'ارسال پیام موقع شارژ از سمت ادمین',
list: ['true', 'false']
},
'display_montzar': {
title: 'نمایش منتظر',
list: ['true', 'false']
},
// توکن‌ها
'liman_token': {
title: 'توکن لیمان',
list: []
},
'key': {
title: 'کلید',
list: []
},
// متفرقه
'logo_login': {
title: 'لوگو صفحه ورود',
list: []
},
'logo_register': {
title: 'لوگو صفحه ثبت‌نام',
list: []
}
}
async function initConfig() {
try {
loading.value = true
baseData.value = await getConfiguration()
items.value = baseData.value?.map((x: Const) => {
// Truncate x.value if it's longer than 40 characters
const truncatedValue = x?.value?.length > 40 ? x?.value?.substring(0, 40) + '...' : x.value
const title = x?.title_fa ?? (settingsConfig[x.key]?.title ?? x?.key)
return {
id: x.id,
name: `${x.key ?? ''} : ${truncatedValue}`
};
});
refresh++;
name: `${title}`,
value: x.value,
key: x.key,
type: x.type || 'text',
description: x.description,
is_active: x.is_active,
list: settingsConfig[x.key]?.list ?? []
}
})
} catch (e) {
console.error(e);
console.error(e)
} finally {
loading.value = false;
loading.value = false
}
}
//edit nature
let editId: number | undefined = undefined
const groupedItems = computed(() => {
const result = { switch: [], text: [], longtext: [] } as Record<string, any[]>
items.value?.forEach((item) => {
const type = item.type && result[item.type] ? item.type : 'text'
result[type].push(item)
})
return result
})
function edit(id: number) {
form.value = baseData.value?.find((x: Const) => x.id === id) ?? ({} as Const)
addConfigVisible.value = true
editId = id
}
const hasAnyItems = computed(() =>
Object.values(groupedItems.value).some((list) => list.length > 0)
)
//resetData
async function resetData() {
await getConfiguration()
formRef.value?.resetFields()
form.value = {
key: '',
value: ''
value: '',
title_fa:'',
type: 'text',
description: '',
is_active: true
}
await initConfig()
}
//add
async function add() {
editId = undefined
await resetData()
addConfigVisible.value = true
}
//submit
async function ok() {
let obj = {
id: editId,
key: form.value.key,
value: form.value.value,
description: form.value.description,
is_active: form.value.is_active
}
formRef.value?.validateFields().then(async () => {
try {
loading.value = true
if (editId) {
await setConfiguration(obj)
} else {
await setConfiguration(form.value)
}
debugger
console.log(form.value)
await setConfiguration(form.value)
await resetData()
message.success('عملیات با موفقیت انجام شد')
} catch (e) {
@@ -0,0 +1,143 @@
<template>
<div>
<BasicShowContent title="تنظیمات">
<BasicTags :items="items" color="green" @add="add" @edit="edit" :key="refresh" :loading="loading"
:closable="false" />
</BasicShowContent>
<BasicModal v-model:visible="addConfigVisible" :title="editId ? `ویرایش` : 'افزودن'"
@close="addConfigVisible = false" @ok="ok" :loading="loading">
<a-form ref="formRef" :model="form" autocomplete="off">
<a-form-item name="is_active">
<span class="ml-2">وضعیت :</span>
<a-checkbox v-model:checked="form.is_active">{{ !form.is_active ? 'غیرفعال' : 'فعال' }}</a-checkbox>
</a-form-item>
<a-form-item v-if="!editId" name="key" label="کلید" >
<BasicInput v-model:value="form.key" :placeHolder="form.key" />
</a-form-item>
<a-form-item name="value" :label="!editId ? 'مقدار' : form.key">
<BasicInput v-model:value="form.value" :placeHolder="form.value" />
</a-form-item>
<a-form-item name="description" :label="'توضیحات'">
<BasicInput v-model:value="form.description" :placeHolder="form.description" />
</a-form-item>
</a-form>
</BasicModal>
</div>
</template>
<script setup lang="ts">
import BasicShowContent from '@/components/BasicShowContext.vue'
import BasicModal from '@/components/BasicModal.vue'
import BasicTags from '@/components/BasicTags/index.vue'
import type { FormInstance } from 'ant-design-vue'
import { message } from 'ant-design-vue'
import type { Const } from '@/model/const'
import type { TagItem } from '@/components/BasicTags/model'
import BasicInput from '@/components/BasicInput.vue'
import { loading } from '@/utils'
import { getConfiguration, setConfiguration } from '@/api/configuration'
//radio button
const checked = ref(false)
//data Arrays
const items = ref<Array<TagItem>>()
const baseData = ref<Array<Const>>()
//nature modal
const addConfigVisible = ref<boolean>()
//refresh
let refresh = 0
const form = ref<Const>({
key: '',
value: ''
})
const formRef = ref<FormInstance>()
//get nature
onMounted(() => {
initConfig()
})
async function initConfig() {
try {
loading.value = true
baseData.value = await getConfiguration()
items.value = baseData.value?.map((x: Const) => {
// Truncate x.value if it's longer than 40 characters
const truncatedValue = x?.value?.length > 40 ? x?.value?.substring(0, 40) + '...' : x.value
return {
id: x.id,
name: `${x.key ?? ''} : ${truncatedValue}`
};
});
refresh++;
} catch (e) {
console.error(e);
} finally {
loading.value = false;
}
}
//edit nature
let editId: number | undefined = undefined
function edit(id: number) {
form.value = baseData.value?.find((x: Const) => x.id === id) ?? ({} as Const)
addConfigVisible.value = true
editId = id
}
//resetData
async function resetData() {
await getConfiguration()
formRef.value?.resetFields()
form.value = {
key: '',
value: ''
}
await initConfig()
}
//add
async function add() {
editId = undefined
await resetData()
addConfigVisible.value = true
}
//submit
async function ok() {
let obj = {
id: editId,
key: form.value.key,
value: form.value.value,
description: form.value.description,
is_active: form.value.is_active
}
formRef.value?.validateFields().then(async () => {
try {
loading.value = true
if (editId) {
await setConfiguration(obj)
} else {
await setConfiguration(form.value)
}
await resetData()
message.success('عملیات با موفقیت انجام شد')
} catch (e) {
console.error(e)
} finally {
loading.value = false
addConfigVisible.value = false
}
})
}
</script>
<style lang="less"></style>
@@ -22,17 +22,17 @@
@finish="handleSubmit"
class="rtl-form"
>
<a-form-item label="تاریخ تولد" name="birth_date" required>
<BaseDatePicker
v-model:value="formState.birth_date"
placeholder="انتخاب تاریخ تولد"
format="YYYY-MM-DD"
class="w-full"
size="large"
:disabled-date="disabledDate"
<!-- <a-form-item label="تاریخ تولد" name="birth_date" required>-->
<!-- <BaseDatePicker-->
<!-- v-model:value="formState.birth_date"-->
<!-- placeholder="انتخاب تاریخ تولد"-->
<!-- format="YYYY-MM-DD"-->
<!-- class="w-full"-->
<!-- size="large"-->
<!-- :disabled-date="disabledDate"-->
/>
</a-form-item>
<!-- />-->
<!-- </a-form-item>-->
<a-form-item label="کد ملی" name="national_code" required>
<a-input
@@ -71,12 +71,10 @@
size="large"
:loading="loading"
block
class="h-12 text-base font-semibold border-0"
class="h-12 text-base font-semibold flex justify-center items-center gap-1 border-0"
>
<template #icon>
<svg class="w-5 h-5 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
</svg>
<Icon icon="vuesax-linear:card-tick"></Icon>
</template>
تأیید و ادامه
</a-button>
@@ -94,9 +92,10 @@ import type { FormRules } from 'ant-design-vue/es/form'
import type { CheckCardRequest } from "@/model/user"
import { checkCard } from "@/api/customer"
import DatePicker from "@core/components/_sample/components/datePicker.vue";
import Icon from "@core/components/BaseIcon/src/Icon.vue";
const formState = reactive<CheckCardRequest>({
birth_date: '',
// birth_date: '',
national_code: '',
cart_number: ''
})
@@ -105,9 +104,9 @@ const loading = ref(false)
// Validation rules
const rules: FormRules = {
birth_date: [
{ required: true, message: 'لطفاً تاریخ تولد را انتخاب کنید', trigger: 'change' }
],
// birth_date: [
// { required: true, message: 'لطفاً تاریخ تولد را انتخاب کنید', trigger: 'change' }
// ],
national_code: [
{ required: true, message: 'لطفاً کد ملی را وارد کنید', trigger: 'blur' },
{ len: 10, message: 'کد ملی باید ۱۰ رقم باشد', trigger: 'blur' },
@@ -240,10 +239,10 @@ function showSuccessModal(owners: any[], cartNumber: string, bankName: string) {
// Submit form
async function handleSubmit() {
if (!formState.birth_date) {
message.warning('لطفاً تاریخ تولد را انتخاب کنید')
return
}
// if (!formState.birth_date) {
// message.warning('لطفاً تاریخ تولد را انتخاب کنید')
// return
// }
loading.value = true