This commit is contained in:
2026-06-12 20:30:00 +03:30
parent 19064b8a50
commit a14f1587c6
10 changed files with 92 additions and 19 deletions
+5
View File
@@ -3,5 +3,10 @@ import useAxios from "@core/utils/useAxios"
export const setConfiguration = async (obj: Const) => await useAxios.post<Const>(`/admin/get_settings`, obj)
/** همه تنظیمات — برای خواندن داخلی (is_store، unit و ...) */
export const getConfiguration = async () =>
await useAxios.get<Array<Const>>(`/admin/get_settings`)
/** فقط تنظیمات قابل ویرایش — برای صفحه تنظیمات ادمین */
export const getEditableConfiguration = async () =>
await useAxios.get<Array<Const>>(`/admin/get_settings`, { params: { editable_only: 1 } })
+2
View File
@@ -13,6 +13,7 @@ import { setupRoutes } from '@/router'
//import { resetRouter } from '@core/router'
import { useUserStore } from '@/store/userStore'
import { setupPinia } from '@core/plugins/pinia'
import { initStoreModeFromSettings } from '@/utils/config'
const init = async () => {
const app = createApp(App)
@@ -27,6 +28,7 @@ const init = async () => {
const token = getToken()
if (token) {
await userStore.getMyInfo()
await initStoreModeFromSettings()
setupRoutes(['*'])
//setupRoutes(['project'])
/*router.removeRoute('usersMain')
+2
View File
@@ -41,6 +41,8 @@ export interface Product{
file_id?: number
file?: File
original_image?: File
inventory?: number
description?: string | null
}
export interface MethodePrices {
+11 -2
View File
@@ -171,14 +171,16 @@ import type { FormInstance } from 'ant-design-vue'
import { message } from 'ant-design-vue'
import type { Const } from '@/model/configuration'
import { loading } from '@/utils'
import { getConfiguration, setConfiguration } from '@/api/configuration'
import { getEditableConfiguration, setConfiguration } from '@/api/configuration'
import SettingValueField from './SettingValueField.vue'
import SettingCard from './SettingCard.vue'
import { setStoreModeFromSettings } from '@/utils/config'
import {
SETTING_TYPE_OPTIONS,
formatValueForSave,
helpText,
isSettingVisible,
isSwitchOn,
resolveSettingFieldType
} from './settingTypes'
@@ -410,7 +412,11 @@ onMounted(() => {
async function initConfig() {
try {
loading.value = true
baseData.value = (await getConfiguration()) ?? []
baseData.value = (await getEditableConfiguration()) ?? []
const storeRow = baseData.value.find((row) => row.key === 'is_store')
if (storeRow) {
setStoreModeFromSettings(isSwitchOn(storeRow.value))
}
syncDraftsFromBase()
} catch (e) {
console.error(e)
@@ -481,6 +487,9 @@ async function saveSettingRow(row: Const, overrides?: { isActive?: boolean }) {
row.value = value
row.is_active = isActive
drafts.value[id] = value
if (row.key === 'is_store') {
setStoreModeFromSettings(isSwitchOn(value))
}
savedFlashIds.value.add(id)
if (saveTimers.has(id)) clearTimeout(saveTimers.get(id))
saveTimers.set(
@@ -5,7 +5,6 @@ export type SettingFieldType = 'text' | 'number' | 'switch' | 'select' | 'longte
/** کلیدهای legacy — در پنل نمایش داده نمی‌شوند (جایگزین: price_provider) */
export const HIDDEN_LEGACY_SETTING_KEYS = new Set([
'tabanGohar_price',
'main_product_price',
'montzar_price',
'etehadie_api_url',
@@ -149,7 +148,7 @@ export function parseSelectOptions(
source = source.split('|').pop() || ''
}
const deprecatedOpts = new Set(['taban_gohar', 'etehadie'])
const deprecatedOpts = new Set(['etehadie'])
const opts = source
.split(',')
.map((s) => s.trim())
@@ -194,6 +194,14 @@
<a-form-item label="واحد" name="unit" :rules="inputRules()">
<BasicSelect v-model:value="form.unit" :items="unitItems" valueName="value" keyName="value" />
</a-form-item>
<a-form-item
v-if="isStore && !isMeltedCategory"
label="تعداد موجودی"
name="inventory"
:rules="inputRules()"
>
<BasicInput v-model:value="form.inventory" type="number" />
</a-form-item>
<a-form-item label="هزینه نقدی موقع خرید" name="cash_fee_buy" :rules="inputRules()">
<BasicInput v-model:value="form.cash_fee_buy" addon-before="ریال" type="price" />
</a-form-item>
@@ -249,6 +257,7 @@ import Icon from '@core/components/BaseIcon/src/Icon.vue'
import BaseCollapse from '@/components/BaseCollapse.vue'
import IndexImageUploader from '@/components/ProductUploader/IndexImageUploader.vue'
import { getConfiguration } from '@/api/configuration'
import { isSwitchOn } from '@/pages/menuPages/configuration/settingTypes'
import type { last } from '@/model/price'
import type { MethodePrices } from '@/model/product'
import { usePrice } from '@core/utils/usePrice'
@@ -275,8 +284,11 @@ const props = defineProps<{
customLocale: any
productIndexImage: any[]
editId?: number
isStore?: boolean
}>()
const isStore = ref(Boolean(props.isStore))
const tradeWeightUnit = ref('گرم')
const isMeltedCategory = computed(() => isMeltedTradeGroup(props.form.group_type))
@@ -314,6 +326,11 @@ onMounted(async () => {
const rows = await getConfiguration()
const unitRow = Array.isArray(rows) ? rows.find((row) => row.key === 'unit') : null
tradeWeightUnit.value = resolveTradeWeightUnit(unitRow?.value)
const storeRow = Array.isArray(rows) ? rows.find((row) => row.key === 'is_store') : null
if (storeRow) {
isStore.value = isSwitchOn(storeRow.value)
}
} catch {
tradeWeightUnit.value = 'گرم'
}
@@ -121,7 +121,7 @@ import {
getCustomerTable,
setActiveTime
} from '@/api/product'
import { cols } from '@/pages/menuPages/products/base/hooks/productColumns'
import { getProductColumns } from '@/pages/menuPages/products/base/hooks/productColumns'
import ProductMobileCardList from '@/pages/menuPages/products/base/components/ProductMobileCardList.vue'
import useBaseTable from '@core/components/BaseTable/hooks/useBaseTable'
import type { TableInput } from '@core/type/baseTable'
@@ -148,7 +148,7 @@ const customLocale = ref({
})
const tblProps = ref<any>({
columns: cols,
columns: getProductColumns(),
api: async (params: TableInput) => {
const data = (await getCustomerTable(params)) as any
startTime.value = dayjs(data?.auto_open_at, 'HH:mm:ss')
@@ -1,7 +1,16 @@
import type { BaseTableColumn } from '@core/type/baseTable'
import CustomTag from '@/components/CustomTag.vue'
import { isStoreApp } from '@/utils/config'
export const cols: BaseTableColumn[] = [
const inventoryColumn: BaseTableColumn = {
title: 'موجودی',
dataIndex: 'inventory',
key: 'inventory',
type: 'Number'
}
export function getProductColumns(): BaseTableColumn[] {
return [
{
title: 'ردیف',
dataIndex: 'id',
@@ -78,6 +87,7 @@ export const cols: BaseTableColumn[] = [
key: 'cash_fee_sell',
type: 'Number'
},
...(isStoreApp() ? [inventoryColumn] : []),
{
title: 'وضعیت محصول',
dataIndex: 'active',
@@ -102,4 +112,8 @@ export const cols: BaseTableColumn[] = [
slot: 'action',
filterable: false
}
]
]
}
/** @deprecated از getProductColumns استفاده کنید */
export const cols = getProductColumns()
+7 -3
View File
@@ -1,6 +1,5 @@
<template>
<CustomersStoreView v-if="isStoreApp()" />
<div v-else class="h-full min-h-0 min-w-0 overflow-hidden">
<div class="h-full min-h-0 min-w-0 overflow-hidden">
<tbl ref="table" class="h-full min-h-0 w-full" @edit="edit" @add="add" />
<BasicActionSheet
v-model:visible="addUserVisible"
@@ -34,6 +33,7 @@
:productIndexImage="ProductIndexImage"
:editId="editId"
:meltedPriceOption="meltedPriceOption"
:isStore="isStoreApp()"
@update:methodOption="methodOption = $event"
@update:weightOption="weightOption = $event"
@update:meltedPriceOption="meltedPriceOption = $event"
@@ -57,7 +57,6 @@ import { cloneDeep } from 'lodash'
import dayjs from 'dayjs'
import customParseFormat from 'dayjs/plugin/customParseFormat'
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
import CustomersStoreView from '@/pages/menuPages/customers/base/index.vue'
import { isStoreApp } from '@/utils/config'
import { createProduct, getCustomerById, updateCustomer } from '@/api/product'
import { fetchProductImageUrl } from '@/api/file'
@@ -326,6 +325,7 @@ function resetData() {
order_limit_enabled: false,
show_in_assets: false,
use_last_price_if_zero: false,
inventory: 0,
min_order_cash: undefined,
max_order_cash: undefined,
auto_open_at: dayjs('00:00:00', 'HH:mm:ss'),
@@ -375,6 +375,10 @@ async function ok() {
}
if (weightOption.value === '2') payload.amount = 1
if (isStoreApp() && !isMeltedTradeGroup(payload.group_type)) {
payload.inventory = Math.max(0, Number(payload.inventory ?? 0))
}
payload.auto_open_at = payload.auto_open_at
? dayjs(payload.auto_open_at).format('HH:mm:ss')
: '00:00:00'
+29 -8
View File
@@ -1,6 +1,5 @@
export function getConfigApp(key: string) {
const config = window.__APP_CONFIG__ ? window.__APP_CONFIG__.user:{}
const config = window.__APP_CONFIG__ ? window.__APP_CONFIG__.user : {}
if (config) {
return config[key]
@@ -8,11 +7,33 @@ export function getConfigApp(key: string) {
return null
}
let storeModeFromSettings: boolean | null = null
function isSwitchOn(value: string | undefined | null): boolean {
const v = (value ?? '').trim().toLowerCase()
return v === 'true' || v === '1' || v === 'yes'
}
export function setStoreModeFromSettings(value: boolean): void {
storeModeFromSettings = value
}
/** is_store فقط از API تنظیمات (get_settings) خوانده می‌شود — نه از get_user */
export async function initStoreModeFromSettings(): Promise<boolean> {
if (storeModeFromSettings !== null) return storeModeFromSettings
try {
const { getConfiguration } = await import('@/api/configuration')
const rows = await getConfiguration()
const row = Array.isArray(rows) ? rows.find((item) => item.key === 'is_store') : null
storeModeFromSettings = row ? isSwitchOn(row.value) : false
} catch {
storeModeFromSettings = false
}
return storeModeFromSettings
}
export function isStoreApp(): boolean {
const value = getConfigApp('is_store')
if (value === true || value === 1) return true
if (typeof value === 'string') {
return ['true', '1', 'yes'].includes(value.trim().toLowerCase())
}
return false
return storeModeFromSettings === true
}