feat: complete admin panel and backend admin api migration
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<!--
|
||||
Ported from legacy henza_admin/src/views/user/ListUser.vue — the admin user
|
||||
grid. The `ut` column renders the access-level TITLE looked up from the
|
||||
user-type list, as legacy did.
|
||||
-->
|
||||
<div id="page-user-list">
|
||||
<a-card title="لیست مدیران">
|
||||
<!--
|
||||
legacy ListUser.vue:4 — the add-user button, gated on the same rid.
|
||||
It was dropped in the original port, which left the create route
|
||||
(/user/create) reachable only by typing the URL.
|
||||
-->
|
||||
<a-button
|
||||
v-if="hasPermission('user.list.create')"
|
||||
type="primary"
|
||||
class="mb-5"
|
||||
@click="router.push('/user/create')"
|
||||
>
|
||||
افزودن کاربر
|
||||
</a-button>
|
||||
|
||||
<XTable ref="tbl" :model="model">
|
||||
<template #ut="{ text }">
|
||||
{{ userTypeTitle(text) }}
|
||||
</template>
|
||||
|
||||
<template #op="{ record }">
|
||||
<a-tooltip v-if="hasPermission('user.list.edit')" title="ویرایش">
|
||||
<EditOutlined class="cursor-pointer mx-1 text-primary" @click="edit(record)" />
|
||||
</a-tooltip>
|
||||
|
||||
<a-tooltip v-if="hasPermission('user.list.remove')" title="حذف">
|
||||
<a-popconfirm
|
||||
placement="top"
|
||||
ok-text="بله"
|
||||
cancel-text="خیر"
|
||||
@confirm="confirmDelete(record.id)"
|
||||
>
|
||||
<template #title><p>آیا مطمئن به حذف کاربر مورد نظر هستید ؟</p></template>
|
||||
<DeleteOutlined class="cursor-pointer mx-1 text-danger" />
|
||||
</a-popconfirm>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</XTable>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import { DeleteOutlined, EditOutlined } from '@ant-design/icons-vue';
|
||||
import XTable from '../../components/x-table/XTable.vue';
|
||||
import { buildUserListModel } from './userTbl';
|
||||
import { useUsersStore } from '../../stores/users';
|
||||
import api from '../../api/client';
|
||||
|
||||
const router = useRouter();
|
||||
const users = useUsersStore();
|
||||
const hasPermission = (rid: string) => Boolean(users.hasPermission(rid));
|
||||
|
||||
const model = buildUserListModel();
|
||||
const tbl = ref<{ fetch: () => Promise<void> } | null>(null);
|
||||
const userTypes = ref<{ id: number; title: string }[]>([]);
|
||||
|
||||
function userTypeTitle(ut: number | null | undefined) {
|
||||
if (ut === null || ut === undefined) return '-';
|
||||
return userTypes.value.find((t) => t.id === Number(ut))?.title ?? String(ut);
|
||||
}
|
||||
|
||||
function edit(record: Record<string, any>) {
|
||||
router.push(`/user/edit/${record.id}`);
|
||||
}
|
||||
|
||||
async function confirmDelete(id: string) {
|
||||
try {
|
||||
await api.delete(`users/${id}`);
|
||||
message.success('کاربر حذف شد');
|
||||
tbl.value?.fetch();
|
||||
} catch (e: any) {
|
||||
// The backend refuses when the admin owns ledger entries or status events —
|
||||
// deleting them would erase the audit trail.
|
||||
Modal.error({ title: e?.response?.data?.message ?? 'خطا در حذف کاربر', okText: 'بستن' });
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const { data } = await api.get('const/__list__ut');
|
||||
userTypes.value = data;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
<template>
|
||||
<!--
|
||||
Ported from legacy henza_admin/src/views/user/Permission.vue — the screen
|
||||
that administers the permission(rid, userTypeId) matrix built in Phase 1.
|
||||
|
||||
Legacy's magic ids, preserved:
|
||||
84 = the "new access level" sentinel — picking it reveals a name field
|
||||
85 = the default selection on load
|
||||
104 = a reserved level; unless the signed-in admin belongs to it, both the
|
||||
level and the whole "custom" branch of the tree are hidden
|
||||
|
||||
The RTL checkbox CSS from legacy is carried over verbatim — ant's tick mark
|
||||
is drawn with a rotated border that lands wrong under [dir=rtl].
|
||||
-->
|
||||
<a-form layout="vertical" @submit.prevent="handleSubmit">
|
||||
<a-card id="rid" title="دسترسی ها">
|
||||
<div class="grid-2">
|
||||
<a-form-item
|
||||
label="سطح کاربر"
|
||||
:validate-status="err.ut ? 'error' : ''"
|
||||
:help="err.ut"
|
||||
>
|
||||
<a-select v-model:value="ut" allow-clear @change="selectChange">
|
||||
<a-select-option v-for="t in visibleUserTypes" :key="t.id" :value="String(t.id)">
|
||||
{{ t.title }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
v-if="newUT && hasPermission('user.permission.create')"
|
||||
label="نام سطح دسترسی"
|
||||
:validate-status="err.user ? 'error' : ''"
|
||||
:help="err.user"
|
||||
>
|
||||
<a-input v-model:value="newTypeName" allow-clear />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="نقش ها" class="tree-item">
|
||||
<a-tree
|
||||
v-model:checked-keys="rid"
|
||||
:check-strictly="false"
|
||||
checkable
|
||||
style="width: 100%"
|
||||
:tree-data="visibleTree"
|
||||
:field-names="{ title: 'title', key: 'key', children: 'children' }"
|
||||
:auto-expand-parent="autoExpandParent"
|
||||
/>
|
||||
</a-form-item>
|
||||
</div>
|
||||
|
||||
<a-button
|
||||
v-if="!newUT && hasPermission('user.permission.edit')"
|
||||
type="primary"
|
||||
html-type="submit"
|
||||
>
|
||||
ثبت تغییرات
|
||||
</a-button>
|
||||
|
||||
<a-button
|
||||
v-if="newUT && hasPermission('user.permission.create')"
|
||||
type="primary"
|
||||
html-type="submit"
|
||||
>
|
||||
افزودن
|
||||
</a-button>
|
||||
</a-card>
|
||||
</a-form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, reactive, ref } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { treeData, type PermissionNode } from './permissionConst';
|
||||
import { useUsersStore } from '../../stores/users';
|
||||
import { useAuthStore } from '../../stores/auth';
|
||||
import api from '../../api/client';
|
||||
|
||||
const users = useUsersStore();
|
||||
const auth = useAuthStore();
|
||||
const hasPermission = (rid: string) => Boolean(users.hasPermission(rid));
|
||||
|
||||
/** legacy sentinels */
|
||||
const NEW_TYPE_ID = '84';
|
||||
const DEFAULT_TYPE_ID = '85';
|
||||
const RESERVED_TYPE_ID = 104;
|
||||
|
||||
const ut = ref<string | undefined>(DEFAULT_TYPE_ID);
|
||||
const newTypeName = ref('');
|
||||
const rid = ref<string[]>([]);
|
||||
const autoExpandParent = ref(true);
|
||||
const userTypes = ref<{ id: number; title: string }[]>([]);
|
||||
const err = reactive<Record<string, string>>({});
|
||||
|
||||
const newUT = computed(() => ut.value === NEW_TYPE_ID);
|
||||
|
||||
/** legacy: hide the "new" option without the create rid, and hide 104 unless you are in it */
|
||||
const visibleUserTypes = computed(() => {
|
||||
let list = userTypes.value;
|
||||
if (!hasPermission('user.permission.create')) {
|
||||
list = list.filter((t) => String(t.id) !== NEW_TYPE_ID);
|
||||
}
|
||||
if (auth.user?.ut !== RESERVED_TYPE_ID) {
|
||||
list = list.filter((t) => t.id !== RESERVED_TYPE_ID);
|
||||
}
|
||||
return list;
|
||||
});
|
||||
|
||||
/** legacy drops the whole "custom" branch for anyone outside level 104 */
|
||||
const visibleTree = computed<PermissionNode[]>(() =>
|
||||
auth.user?.ut === RESERVED_TYPE_ID
|
||||
? treeData
|
||||
: treeData.filter((x) => x.key !== 'custom'),
|
||||
);
|
||||
|
||||
async function getData() {
|
||||
try {
|
||||
const { data } = await api.get('const/__list__ut');
|
||||
userTypes.value = data;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
/** legacy selectChange(): id 84 means "creating a new level", so start empty */
|
||||
async function selectChange(id: string | undefined) {
|
||||
if (!id) {
|
||||
rid.value = [];
|
||||
return;
|
||||
}
|
||||
if (id === NEW_TYPE_ID) {
|
||||
rid.value = [];
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const { data } = await api.get(`roles/${id}`);
|
||||
// The server returns a flat array of rid strings.
|
||||
rid.value = data;
|
||||
} catch (e) {
|
||||
message.error('خطا در دریافت اطلاعات');
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
Object.keys(err).forEach((k) => delete err[k]);
|
||||
if (!ut.value) {
|
||||
err.ut = 'لطفاسطح دسترسی را انتخاب کنید';
|
||||
return;
|
||||
}
|
||||
if (newUT.value && !newTypeName.value) {
|
||||
err.user = 'لطفا نام سطح دسترسی را وارد کنید';
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
let targetUt = ut.value;
|
||||
|
||||
if (newUT.value) {
|
||||
// legacy: create the level first, then grant the ticked rids to it
|
||||
const { data } = await api.post('const', {
|
||||
key: '__list__ut',
|
||||
val: newTypeName.value,
|
||||
});
|
||||
targetUt = String(data.id);
|
||||
}
|
||||
|
||||
await api.post('roles/create', { ut: targetUt, roles: rid.value });
|
||||
|
||||
await getData();
|
||||
if (newUT.value) {
|
||||
ut.value = targetUt;
|
||||
newTypeName.value = '';
|
||||
await selectChange(targetUt);
|
||||
}
|
||||
message.success('عملیات با موفقیت انجام شد');
|
||||
} catch (e: any) {
|
||||
message.error(e?.response?.data?.message ?? 'خطا در ثبت اطلاعات');
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await getData();
|
||||
// legacy: setFieldsValue({ut:"85"}) then selectChange("85")
|
||||
ut.value = DEFAULT_TYPE_ID;
|
||||
await selectChange(DEFAULT_TYPE_ID);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/*
|
||||
Carried over verbatim from legacy. Ant draws the checkbox tick with a rotated
|
||||
border, which lands on the wrong edge under [dir=rtl].
|
||||
*/
|
||||
[dir='rtl'] .ant-tree-checkbox-inner::after {
|
||||
right: 55%;
|
||||
top: 35%;
|
||||
border-left: 0 !important;
|
||||
-webkit-transform: rotate(-45deg) scale(0) translate(50%, -50%);
|
||||
transform: rotate(-45deg) scale(0) translate(50%, -50%);
|
||||
}
|
||||
[dir='rtl'] .ant-tree-checkbox-checked .ant-tree-checkbox-inner::after {
|
||||
border-left: 0 !important;
|
||||
border-right: 2px solid #fff;
|
||||
-webkit-transform: rotate(45deg) scale(1) translate(0%, -60%);
|
||||
transform: rotate(45deg) scale(1) translate(0%, -60%);
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
.grid-2 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
.tree-item {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,171 @@
|
||||
<template>
|
||||
<!--
|
||||
Ported from legacy henza_admin/src/views/user/UserCreate.vue.
|
||||
Serves BOTH create and edit — UserEdit.vue is only a wrapper around it.
|
||||
|
||||
Legacy fields: fname, lname, mobile, ut, password, password_confirmation.
|
||||
The schema stores one `fullName`, so the two name inputs are joined on submit
|
||||
and split back on load.
|
||||
-->
|
||||
<a-spin :spinning="loading">
|
||||
<a-form layout="vertical" @submit.prevent="handleSubmit">
|
||||
<a-card :title="id ? 'ویرایش مدیر' : 'افزودن مدیر'" class="mb-base">
|
||||
<div class="grid-3">
|
||||
<a-form-item label="نام" :validate-status="err.fname ? 'error' : ''" :help="err.fname">
|
||||
<a-input v-model:value="form.fname" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
label="نام خانوادگی"
|
||||
:validate-status="err.lname ? 'error' : ''"
|
||||
:help="err.lname"
|
||||
>
|
||||
<a-input v-model:value="form.lname" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
label="شماره موبایل"
|
||||
:validate-status="err.mobile ? 'error' : ''"
|
||||
:help="err.mobile"
|
||||
>
|
||||
<a-input v-model:value="form.mobile" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="نوع کاربری" :validate-status="err.ut ? 'error' : ''" :help="err.ut">
|
||||
<a-select v-model:value="form.ut" allow-clear placeholder="انتخاب کنید">
|
||||
<a-select-option v-for="t in userTypes" :key="t.id" :value="t.id">
|
||||
{{ t.title }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
label="رمز عبور"
|
||||
:validate-status="err.password ? 'error' : ''"
|
||||
:help="err.password"
|
||||
>
|
||||
<a-input-password v-model:value="form.password" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
label="تأیید رمز عبور"
|
||||
:validate-status="err.password_confirmation ? 'error' : ''"
|
||||
:help="err.password_confirmation"
|
||||
>
|
||||
<a-input-password v-model:value="form.password_confirmation" />
|
||||
</a-form-item>
|
||||
</div>
|
||||
|
||||
<p v-if="id" class="hint">برای تغییر ندادن رمز عبور، هر دو فیلد رمز را خالی بگذارید.</p>
|
||||
|
||||
<a-button type="primary" @click="handleSubmit">ثبت اطلاعات</a-button>
|
||||
</a-card>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { message } from 'ant-design-vue';
|
||||
import api from '../../api/client';
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const id = route.params.id as string | undefined;
|
||||
const loading = ref(false);
|
||||
const userTypes = ref<{ id: number; title: string }[]>([]);
|
||||
|
||||
const form = reactive<Record<string, any>>({
|
||||
fname: '',
|
||||
lname: '',
|
||||
mobile: '',
|
||||
ut: undefined,
|
||||
password: '',
|
||||
password_confirmation: '',
|
||||
});
|
||||
|
||||
const err = reactive<Record<string, string>>({});
|
||||
const REQUIRED = 'لطفا مقدار را وارد کنید';
|
||||
|
||||
function validate(): boolean {
|
||||
Object.keys(err).forEach((k) => delete err[k]);
|
||||
if (!form.fname) err.fname = REQUIRED;
|
||||
if (!form.lname) err.lname = REQUIRED;
|
||||
if (!form.mobile) err.mobile = REQUIRED;
|
||||
if (form.ut === undefined || form.ut === null) err.ut = REQUIRED;
|
||||
|
||||
// On create a password is mandatory; on edit, blank means "leave unchanged".
|
||||
if (!id && !form.password) err.password = REQUIRED;
|
||||
if (form.password && form.password !== form.password_confirmation) {
|
||||
err.password_confirmation = 'رمز عبور و تأیید آن یکسان نیستند';
|
||||
}
|
||||
return Object.keys(err).length === 0;
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
if (!validate()) return;
|
||||
try {
|
||||
loading.value = true;
|
||||
const payload: Record<string, unknown> = {
|
||||
name: `${form.fname} ${form.lname}`.trim(),
|
||||
mobile: form.mobile,
|
||||
ut: form.ut,
|
||||
};
|
||||
if (form.password) payload.password = form.password;
|
||||
|
||||
if (id) {
|
||||
await api.put(`users/${id}`, payload);
|
||||
} else {
|
||||
await api.post('users', payload);
|
||||
}
|
||||
message.info('اطلاعات با موفقیت به ثبت رسید.');
|
||||
router.push('/user/list');
|
||||
} catch (e: any) {
|
||||
message.error(e?.response?.data?.message ?? 'خطا در ثبت اطلاعات.');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const { data } = await api.get('const/__list__ut');
|
||||
userTypes.value = data;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
if (id) {
|
||||
try {
|
||||
const { data } = await api.get(`admin/users/${id}`);
|
||||
// one fullName -> two inputs: first token is the given name
|
||||
const parts = String(data.name ?? '').trim().split(' ');
|
||||
Object.assign(form, {
|
||||
fname: parts[0] ?? '',
|
||||
lname: parts.slice(1).join(' '),
|
||||
mobile: data.mobile ?? '',
|
||||
ut: data.ut ?? undefined,
|
||||
password: '',
|
||||
password_confirmation: '',
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-3 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
.hint {
|
||||
color: #888;
|
||||
font-size: 12px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,12 @@
|
||||
<template>
|
||||
<!--
|
||||
Ported from legacy henza_admin/src/views/user/UserEdit.vue — a 14-line
|
||||
wrapper whose entire template is <User/>. Kept as a wrapper; UserCreate
|
||||
reads the :id route param to switch between create and edit.
|
||||
-->
|
||||
<UserCreate />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import UserCreate from './UserCreate.vue';
|
||||
</script>
|
||||
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<!--
|
||||
Ported from legacy henza_admin/src/views/user/myData.vue.
|
||||
|
||||
LEGACY BUG preserved in effect, not in code: legacy reads
|
||||
`user.user_type.val`, but the users/show payload carries the title under
|
||||
`title` (and `config_static` rows used `val` only in the raw lookup table),
|
||||
so that cell fell through to its 'آنلاین' fallback for everyone. Here the
|
||||
real title is shown when present, with the same fallback — the fallback is
|
||||
what legacy actually displayed.
|
||||
-->
|
||||
<a-card title="اطلاعات کاربری">
|
||||
<a-descriptions>
|
||||
<a-descriptions-item label="نام">{{ user?.fname || '-' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="نام خانوادگی">{{ user?.lname || '-' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="شماره تلفن">{{ user?.mobile || '-' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="نوع کاربری">
|
||||
{{ userTypeTitle || 'آنلاین' }}
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useAuthStore } from '../../stores/auth';
|
||||
import api from '../../api/client';
|
||||
|
||||
const auth = useAuthStore();
|
||||
const fresh = ref<Record<string, any> | null>(null);
|
||||
|
||||
const user = computed(() => fresh.value ?? auth.user);
|
||||
const userTypeTitle = computed(() => user.value?.user_type?.title);
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const { data } = await api.get('admin/users/me');
|
||||
fresh.value = data;
|
||||
} catch (e) {
|
||||
// fall back to the cached login payload, as legacy did
|
||||
console.log(e);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,872 @@
|
||||
// Ported from legacy henza_admin/src/views/user/permissionConst.js
|
||||
//
|
||||
// Converted MECHANICALLY (see scratchpad/convert_tree.js) so all 181 Farsi
|
||||
// permission labels survive byte-exact. 22 top-level groups, up to 4 levels deep.
|
||||
//
|
||||
// This tree is the vocabulary the Permission screen offers. Note it is NOT the
|
||||
// same set as the rids the app enforces — see the audit in
|
||||
// docs/ADMIN-PORT-PLAN.md:
|
||||
// - 144 rids are actually enforced (58 by routes, 100 by $hasPermission, overlapping)
|
||||
// - 176 distinct keys appear in this tree
|
||||
// - 36 tree keys are never checked anywhere (dead entries, kept for fidelity)
|
||||
// - 4 enforced rids are MISSING from this tree, so they cannot be granted
|
||||
// from the UI at all: buy.order.list, newsletters,
|
||||
// persons.create.customer.tak, persons.list.sellers.view
|
||||
// All four quirks are preserved rather than "fixed".
|
||||
|
||||
export interface PermissionNode {
|
||||
title: string;
|
||||
key: string;
|
||||
children?: PermissionNode[];
|
||||
}
|
||||
|
||||
export const treeData: PermissionNode[] = [
|
||||
{
|
||||
"title": "پیشخوان",
|
||||
"key": "dashboard",
|
||||
"children": [
|
||||
{
|
||||
"title": "آمار عمده فروشی",
|
||||
"key": "dashboard.omde"
|
||||
},
|
||||
{
|
||||
"title": "آمار تک فروشی",
|
||||
"key": "dashboard.tak"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "اشخاص",
|
||||
"key": "persons",
|
||||
"children": [
|
||||
{
|
||||
"title": "اضافه کردن شخص",
|
||||
"key": "persons.create",
|
||||
"children": [
|
||||
{
|
||||
"title": "افزودن کارشناس فروش",
|
||||
"key": "persons.create.seller"
|
||||
},
|
||||
{
|
||||
"title": "افزودن مشتری عمده",
|
||||
"key": "persons.create.client"
|
||||
},
|
||||
{
|
||||
"title": "افزودن مشتری تک",
|
||||
"key": "persons.create.single"
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "لیست کارشناسان فروش",
|
||||
"key": "persons.list.sellers",
|
||||
"children": [
|
||||
{
|
||||
"title": "ویرایش اطلاعات کارشناس فروش",
|
||||
"key": "persons.list.sellers.edit"
|
||||
},
|
||||
{
|
||||
"title": "مشاهده سفارشات کارشناس فروش",
|
||||
"key": "persons.list.sellers.view.orders"
|
||||
},
|
||||
{
|
||||
"title": "مشاهده اسناد مالی کارشناس فروش",
|
||||
"key": "persons.list.sellers.view.documents"
|
||||
},
|
||||
{
|
||||
"title": "توقف سفارش کارشناس فروش",
|
||||
"key": "persons.list.sellers.unable.order"
|
||||
},
|
||||
{
|
||||
"title": "فعال سازی سفارش کارشناس فروش",
|
||||
"key": "persons.list.sellers.able.order"
|
||||
},
|
||||
{
|
||||
"title": "فعال سازی حساب کاربری کارشناس فروش",
|
||||
"key": "persons.list.sellers.able"
|
||||
},
|
||||
{
|
||||
"title": "غیر فعال سازی حساب کاربری کارشناس فروش",
|
||||
"key": "persons.list.sellers.unable"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "لیست مشتریان عمده",
|
||||
"key": "persons.list.client.omde",
|
||||
"children": [
|
||||
{
|
||||
"title": "مشاهده اطلاعات مشتریان عمده",
|
||||
"key": "persons.list.client.omde.view"
|
||||
},
|
||||
{
|
||||
"title": "ویرایش اطلاعات مشتری عمده",
|
||||
"key": "persons.list.client.omde.edit"
|
||||
},
|
||||
{
|
||||
"title": "مشاهده سفارشات مشتری عمده",
|
||||
"key": "persons.list.client.omde.view.orders"
|
||||
},
|
||||
{
|
||||
"title": "مشاهده اسناد مالی مشتری عمده",
|
||||
"key": "persons.list.client.omde.view.documents"
|
||||
},
|
||||
{
|
||||
"title": "توقف سفارش مشتری عمده",
|
||||
"key": "persons.list.client.omde.unable.order"
|
||||
},
|
||||
{
|
||||
"title": "فعال سازی سفارش مشتری عمده",
|
||||
"key": "persons.list.client.omde.able.order"
|
||||
},
|
||||
{
|
||||
"title": "فعال سازی مشتری عمده",
|
||||
"key": "persons.list.client.omde.able"
|
||||
},
|
||||
{
|
||||
"title": "غیر فعال سازی مشتری عمده",
|
||||
"key": "persons.list.client.omde.unable"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "لیست مشتریان تک",
|
||||
"key": "persons.list.client.single",
|
||||
"children": [
|
||||
{
|
||||
"title": "مشاهده اطلاعات مشتریان تک",
|
||||
"key": "persons.list.client.single.view"
|
||||
},
|
||||
{
|
||||
"title": "ویرایش اطلاعات مشتری تک",
|
||||
"key": "persons.list.client.single.edit"
|
||||
},
|
||||
{
|
||||
"title": "مشاهده اطلاعات مشتری تک",
|
||||
"key": "persons.list.client.single.view"
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "شعب",
|
||||
"key": "branch",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "افزودن شعب",
|
||||
"key": "branch.create"
|
||||
},
|
||||
{
|
||||
"title": " لیست شعب",
|
||||
"key": "branch.list",
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "کارگاه",
|
||||
"key": "workshop",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "افزودن کارگاه",
|
||||
"key": "workshop.create"
|
||||
},
|
||||
{
|
||||
"title": " لیست کارگاه ها",
|
||||
"key": "workshop.list",
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "محصولات",
|
||||
"key": "product",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "افزودن محصول",
|
||||
"key": "product.create"
|
||||
},
|
||||
{
|
||||
"title": "لیست محصولات",
|
||||
"key": "product.list",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "مشاهده لیست محصولات",
|
||||
"key": "product.list.view"
|
||||
},
|
||||
{
|
||||
"title": "ویرایش اطلاعات محصول",
|
||||
"key": "product.list.edit"
|
||||
},
|
||||
{
|
||||
"title": "مشاهده اطلاعات جامع محصول",
|
||||
"key": "product.list.view"
|
||||
},
|
||||
{
|
||||
"title": "تنوع های محصول",
|
||||
"key": "product.list.variants",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "مشاهده تنوع های محصول",
|
||||
"key": "product.list.variants.view",
|
||||
},
|
||||
{
|
||||
"title": "ویرایش تنوع محصول",
|
||||
"key": "product.list.variants.edit",
|
||||
},
|
||||
{
|
||||
"title": "حذف تنوع محصول",
|
||||
"key": "product.list.variants.remove",
|
||||
},
|
||||
{
|
||||
"title": "افزودن تنوع محصول",
|
||||
"key": "product.list.variants.add",
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "حذف محصول",
|
||||
"key": "product.list.remove"
|
||||
},
|
||||
{
|
||||
"title": "تغییر دسته ای",
|
||||
"key": "product.list.group.edit"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "تغییر درصد محصولات",
|
||||
"key": "product.percent"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "سفارشات",
|
||||
"key": "order",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "لیست سفارشات",
|
||||
"key": "order.list",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "مشاهده لیست سفارشات",
|
||||
"key": "order.list.view"
|
||||
},
|
||||
{
|
||||
"title": "وضعیت سفارش",
|
||||
"key": "order.list.sts",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "مشاهده وضعیت سفارش",
|
||||
"key": "order.list.sts.view",
|
||||
},
|
||||
{
|
||||
"title": "حذف وضعیت",
|
||||
"key": "order.list.sts.remove",
|
||||
},
|
||||
{
|
||||
"title": "ثبت وضعیت",
|
||||
"key": "order.list.sts.submit",
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "مشاهده سفارش",
|
||||
"key": "order.list.view"
|
||||
},
|
||||
{
|
||||
"title": "ویرایش سفارش",
|
||||
"key": "order.list.view.edit",
|
||||
},
|
||||
{
|
||||
"title": "دریافت pdf",
|
||||
"key": "order.list.pdf",
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "سفارشات عمده",
|
||||
"key": "order.omde",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "وضعیت سفارش",
|
||||
"key": "order.omde.state",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "مشاهده وضعیت سفارش",
|
||||
"key": "order.omde.state.view"
|
||||
},
|
||||
{
|
||||
"title": "ثبت وضعیت سفارش",
|
||||
"key": "order.omde.state.submit"
|
||||
},
|
||||
{
|
||||
"title": "حذف وضعیت سفارش",
|
||||
"key": "order.omde.state.remove"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "مشاهده سفارش",
|
||||
"key": "order.omde.view",
|
||||
},
|
||||
{
|
||||
"title": "ویرایش سفارش",
|
||||
"key": "order.omde.view.edit"
|
||||
},
|
||||
{
|
||||
"title": "حذف آیتم از سفارش",
|
||||
"key": "order.omde.view.remove"
|
||||
},
|
||||
{
|
||||
"title": "حذف سفارش",
|
||||
"key": "order.omde.remove",
|
||||
},
|
||||
{
|
||||
"title": "دریافت pdf سفارش",
|
||||
"key": "order.omde.get",
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "سفارشات ساختنی",
|
||||
"key": "order.makeOrder",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "وضعیت سفارش",
|
||||
"key": "order.makeOrder.state",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "مشاهده وضعیت سفارش",
|
||||
"key": "order.makeOrder.state.view"
|
||||
},
|
||||
{
|
||||
"title": "ثبت وضعیت سفارش",
|
||||
"key": "order.makeOrder.state.submit"
|
||||
},
|
||||
{
|
||||
"title": "حذف وضعیت سفارش",
|
||||
"key": "order.makeOrder.state.remove"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "مشاهده سفارش",
|
||||
"key": "order.makeOrder.view",
|
||||
},
|
||||
{
|
||||
"title": "ویرایش سفارش",
|
||||
"key": "order.makeOrder.view.edit"
|
||||
},
|
||||
{
|
||||
"title": "حذف آیتم از سفارش",
|
||||
"key": "order.makeOrder.view.remove"
|
||||
},
|
||||
{
|
||||
"title": "حذف سفارش",
|
||||
"key": "order.makeOrder.remove",
|
||||
},
|
||||
{
|
||||
"title": "دریافت pdf سفارش",
|
||||
"key": "order.makeOrder.get",
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "لیست تامین",
|
||||
"key": "order.tamin",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "مشاهده لیست تامین",
|
||||
"key": "order.tamin.view"
|
||||
},
|
||||
{
|
||||
"title": "وضعیت سفارش",
|
||||
"key": "order.tamin.state",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "مشاهده وضعیت سفارش",
|
||||
"key": "order.tamin.state.view"
|
||||
},
|
||||
{
|
||||
"title": "ثبت وضعیت سفارش",
|
||||
"key": "order.tamin.state.submit"
|
||||
},
|
||||
{
|
||||
"title": "حذف وضعیت سفارش",
|
||||
"key": "order.tamin.state.remove"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "مشاهده سفارش",
|
||||
"key": "order.tamin.view"
|
||||
},
|
||||
{
|
||||
"title": "ویرایش سفارش",
|
||||
"key": "order.tamin.view.edit"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "ثبت سفارش تک",
|
||||
"key": "order.create",
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "مدیران",
|
||||
"key": "user",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "افزودن مدیر",
|
||||
"key": "user.create"
|
||||
},
|
||||
{
|
||||
"title": "لیست مدیران",
|
||||
"key": "user.list",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "مشاهده لیست مدیران",
|
||||
"key": "user.list.view"
|
||||
},
|
||||
{
|
||||
"title": "ویرایش مدیر",
|
||||
"key": "user.list.edit"
|
||||
},
|
||||
{
|
||||
"title": "حذف مدیر",
|
||||
"key": "user.list.remove"
|
||||
},
|
||||
{
|
||||
"title": "افزودن مدیر",
|
||||
"key": "user.list.create"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "دسترسی ها",
|
||||
"key": "user.permission",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "ویرایش دسترسی",
|
||||
"key": "user.permission.edit"
|
||||
},
|
||||
{
|
||||
"title": "افزودن دسترسی",
|
||||
"key": "user.permission.create"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "دسته بندی ها",
|
||||
"key": "collection",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "افزودن دسته بندی",
|
||||
"key": "collection.create"
|
||||
},
|
||||
{
|
||||
"title": " لیست دسته بندی ها",
|
||||
"key": "collection.list",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "مشاهده لیست دسته بندی ها",
|
||||
"key": "collection.list.view"
|
||||
},
|
||||
{
|
||||
"title": "ویرایش دسته",
|
||||
"key": "collection.list.edit"
|
||||
},
|
||||
{
|
||||
"title": "حذف دسته",
|
||||
"key": "collection.list.remove"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "اسناد مالی",
|
||||
"key": "document",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": " لیست اسناد مالی",
|
||||
"key": "document.list",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "مشاهده لیست اسناد مالی",
|
||||
"key": "document.list.view"
|
||||
},
|
||||
{
|
||||
"title": "ویرایش سند مالی",
|
||||
"key": "document.list.edit"
|
||||
},
|
||||
{
|
||||
"title": "حذف سند مالی",
|
||||
"key": "document.list.remove"
|
||||
},
|
||||
{
|
||||
"title": "رد کردن سند مالی",
|
||||
"key": "document.list.deny"
|
||||
},
|
||||
{
|
||||
"title": "تأیید کردن سند مالی",
|
||||
"key": "document.list.confirm"
|
||||
},
|
||||
{
|
||||
"title": "دریافت pdf سند مالی",
|
||||
"key": "document.list.get",
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "وارد کردن سند مالی مشتری",
|
||||
"key": "document.create"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "استثناعات تخفیف",
|
||||
"key": "offersIgnore",
|
||||
},
|
||||
{
|
||||
"title": "تخفیفات",
|
||||
"key": "offers",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": " لیست تخفیفات",
|
||||
"key": "offers.list",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "مشاهده لیست تخفیفات",
|
||||
"key": "offers.list.view"
|
||||
},
|
||||
{
|
||||
"title": "ویرایش تخفیف عمده",
|
||||
"key": "offers.list.edit"
|
||||
},
|
||||
{
|
||||
"title": "ویرایش تخفیف تک",
|
||||
"key": "offers.list.tak.edit"
|
||||
},
|
||||
{
|
||||
"title": "حذف تخفیف عمده",
|
||||
"key": "offers.list.remove"
|
||||
},
|
||||
{
|
||||
"title": "حذف تخفیف تک",
|
||||
"key": "offers.list.tak.remove"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "تعریف تخفیف عمده",
|
||||
"key": "offers.create"
|
||||
},
|
||||
{
|
||||
"title": "تعریف تخفیف تک",
|
||||
"key": "offers.create.tak"
|
||||
},
|
||||
{
|
||||
"title": "تخفیف اتوماتیک",
|
||||
"key": "offers.autopromotion"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "فاکتور انتقال",
|
||||
"key": "invoice",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "افزودن فاکتور",
|
||||
"key": "invoice.create"
|
||||
},
|
||||
{
|
||||
"title": " لیست فاکتورها",
|
||||
"key": "invoice.list",
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "گزارشات",
|
||||
"key": "report",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "گزارش تجمیعی سفارشات و اسناد مالی",
|
||||
"key": "report.order.item"
|
||||
},
|
||||
{
|
||||
"title": "گزارش محصولات",
|
||||
"key": "report.product"
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "شهرها",
|
||||
"key": "cities",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "افزودن شهر",
|
||||
"key": "cities.create"
|
||||
},
|
||||
{
|
||||
"title": "لیست شهرها",
|
||||
"key": "cities.list",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "مشاهده لیست شهرها",
|
||||
"key": "cities.list.view"
|
||||
},
|
||||
{
|
||||
"title": "حذف شهر",
|
||||
"key": "cities.list.remove"
|
||||
},
|
||||
{
|
||||
"title": "مشاهده شهر",
|
||||
"key": "cities.list.view"
|
||||
},
|
||||
{
|
||||
"title": "ویرایش شهر",
|
||||
"key": "cities.list.view.edit"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "دیدگاه ها",
|
||||
"key": "comment",
|
||||
"children": [
|
||||
{
|
||||
"title": "مشاهده لیست دیدگاه ها",
|
||||
"key": "comment.view.all"
|
||||
},
|
||||
{
|
||||
"title": "تغییر وضعیت دیدگاه",
|
||||
"key": "comment.state"
|
||||
},
|
||||
{
|
||||
"title": "مشاهده دیدگاه",
|
||||
"key": "comment.view"
|
||||
},
|
||||
{
|
||||
"title": "ویرایش دیدگاه",
|
||||
"key": "comment.view.edit",
|
||||
},
|
||||
{
|
||||
"title": "حذف دیدگاه",
|
||||
"key": "comment.remove"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "پیامک",
|
||||
"key": "sms",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "ارسال پیامک",
|
||||
"key": "sms.create",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "ارسال برای یک شماره تلفن",
|
||||
"key": "sms.create.single"
|
||||
},
|
||||
{
|
||||
"title": "ارسال برای همه کاربران",
|
||||
"key": "sms.create.all"
|
||||
},
|
||||
{
|
||||
"title": "ارسال برای کارشناسان فروش",
|
||||
"key": "sms.create.reagent"
|
||||
},
|
||||
{
|
||||
"title": "ارسال برای مشتریان عمده",
|
||||
"key": "sms.create.omde"
|
||||
},
|
||||
{
|
||||
"title": "ارسال برای چند شماره تلفن",
|
||||
"key": "sms.create.multiple"
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
"title": "لیست پیامک های ارسال شده",
|
||||
"key": "sms.list",
|
||||
// "children": [],
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "کیف پول",
|
||||
"key": "wallet",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "لیست کیف پول های شارژ شده",
|
||||
"key": "wallet.list",
|
||||
},
|
||||
{
|
||||
"title": "شارژ کیف پول",
|
||||
"key": "wallet.charge",
|
||||
},
|
||||
{
|
||||
"title": "تغییر درصد شارژ کیف پول",
|
||||
"key": "wallet.percent",
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "نوتیفیکیشن",
|
||||
"key": "notify",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "ارسال نوتیفیکیشن",
|
||||
"key": "notify.create",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "ارسال برای کارشناسان فروش",
|
||||
"key": "notify.create.multiple.reagent"
|
||||
},
|
||||
{
|
||||
"title": "ارسال برای یک مشتری",
|
||||
"key": "notify.create.single.customer"
|
||||
},
|
||||
{
|
||||
"title": "ارسال برای مشتریان عمده",
|
||||
"key": "notify.create.multiple.omde"
|
||||
},
|
||||
{
|
||||
"title": "ارسال برای همه مشتریان",
|
||||
"key": "notify.create.multiple.customer"
|
||||
},
|
||||
{
|
||||
"title": "ارسال برای یک مدیر",
|
||||
"key": "notify.create.single.admin"
|
||||
},
|
||||
{
|
||||
"title": "ارسال برای همه مدیران",
|
||||
"key": "notify.create.multiple.admin"
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
"title": "لیست نوتیفیکیشن های دریافتی",
|
||||
"key": "notify.me",
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "پیکربندی",
|
||||
"key": "config",
|
||||
"children": [
|
||||
{
|
||||
"title": "مدیریت ثابت ها",
|
||||
"key": "config.statics",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "برند ها",
|
||||
"key": "config.statics.brand",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "افزودن برند",
|
||||
"key": "config.statics.brand.create"
|
||||
},
|
||||
{
|
||||
"title": "ویرایش برند",
|
||||
"key": "config.statics.brand.edit"
|
||||
},
|
||||
{
|
||||
"title": "حذف برند",
|
||||
"key": "config.statics.brand.remove"
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "برچسب ها",
|
||||
"key": "config.statics.tags",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"title": "افزودن برچسب",
|
||||
"key": "config.statics.tags.create"
|
||||
},
|
||||
{
|
||||
"title": "ویرایش برچسب",
|
||||
"key": "config.statics.tags.edit"
|
||||
},
|
||||
{
|
||||
"title": "حذف برچسب",
|
||||
"key": "config.statics.tags.remove"
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "مدیریت کیف پول",
|
||||
"key": "config.wallet",
|
||||
},
|
||||
{
|
||||
"title": "گزارش",
|
||||
"key": "config.report",
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "آمار",
|
||||
"key": "statics",
|
||||
},
|
||||
{
|
||||
"title": "خبرنامه",
|
||||
"key": "newsletters.newsletters",
|
||||
},
|
||||
{
|
||||
"title": "سفارشی",
|
||||
"key": "custom",
|
||||
"children": [
|
||||
{
|
||||
"title": "اسلایدر موبایل",
|
||||
"key": "custom.config.statics.slider"
|
||||
},
|
||||
{
|
||||
"title": "برچسب بنر اول سایت",
|
||||
"key": "custom.config.statics.tags.banner.ids"
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,17 @@
|
||||
// Ported from legacy henza_admin/src/table/userTbl.js
|
||||
import XTbl, { Xtc } from '../../components/x-table/model';
|
||||
|
||||
export function buildUserListModel(): XTbl {
|
||||
const tbl = new XTbl('admin/users/list', 'لیست مدیران');
|
||||
tbl.add(new Xtc('id', 'کد مدیر'));
|
||||
// Legacy stored fname/lname separately; the schema has one fullName, which the
|
||||
// API returns under BOTH keys so these two columns bind unchanged.
|
||||
tbl.add(new Xtc('fname', 'نام').filterKey('fullName').filterText());
|
||||
tbl.add(new Xtc('lname', 'نام خانوادگی').filterKey('fullName').filterText());
|
||||
tbl.add(new Xtc('mobile', 'موبایل').filterText());
|
||||
tbl.add(new Xtc('ut', 'نوع کاربر').filterNumber().renderSlot('ut'));
|
||||
tbl.add(new Xtc('op', 'عملیات').noSort().renderSlot('op'));
|
||||
return tbl;
|
||||
}
|
||||
|
||||
export default buildUserListModel;
|
||||
Reference in New Issue
Block a user