first commit

This commit is contained in:
Noor E Ilahi
2026-01-09 12:54:53 +05:30
commit 7ccf44f7da
1070 changed files with 113036 additions and 0 deletions

View File

@@ -0,0 +1,82 @@
<template>
<div class="invite-form">
<validation-observer ref="form">
<div v-for="(user, index) in users" :key="index" class="row invite-form__group">
<validation-provider v-slot="{ errors }" :vid="`users.${index}.email`" class="col-14">
<at-input
v-model="users[index]['email']"
:placeholder="$t('field.email')"
:status="errors.length > 0 ? 'error' : ''"
>
<template slot="prepend">{{ $t('field.email') }}</template>
</at-input>
<small>{{ errors[0] }}</small>
</validation-provider>
<validation-provider :vid="`users.${index}.role_id`" class="col-6">
<role-select v-model="users[index]['role_id']"></role-select>
</validation-provider>
<at-button v-if="index > 0" class="col-2 invite-form__remove" @click="removeUser(index)"
><i class="icon icon-x"></i
></at-button>
</div>
</validation-observer>
<at-button type="default" size="small" class="col-4" @click="handleAdd">{{ $t('control.add') }}</at-button>
</div>
</template>
<script>
import { ValidationObserver, ValidationProvider } from 'vee-validate';
import RoleSelect from '@/components/RoleSelect';
export default {
name: 'InviteInput',
components: {
ValidationObserver,
ValidationProvider,
RoleSelect,
},
props: {
value: {
type: [Array, Object],
},
},
data() {
return {
users: [
{
email: null,
role_id: 2,
},
],
};
},
mounted() {
this.$emit('input', this.users);
},
methods: {
handleAdd() {
this.users.push({ email: null, role_id: 2 });
},
removeUser(index) {
this.users.splice(index, 1);
},
},
watch: {
users(value) {
this.$emit('input', value);
},
},
};
</script>
<style lang="scss" scoped>
.invite-form {
&__group {
margin-bottom: 1rem;
}
&__remove {
max-height: 40px;
}
}
</style>

View File

@@ -0,0 +1,9 @@
{
"invitations": {
"grid-title": "Invitations",
"crud-title": "Invitation"
},
"navigation": {
"invitations": "Invitations"
}
}

View File

@@ -0,0 +1,9 @@
{
"invitations": {
"grid-title": "Приглашения",
"crud-title": "Приглашение"
},
"navigation": {
"invitations": "Приглашения"
}
}

View File

@@ -0,0 +1,16 @@
export const ModuleConfig = {
routerPrefix: 'settings',
loadOrder: 10,
moduleName: 'Invitations',
};
export function init(context, router) {
context.addCompanySection(require('./sections/invitations').default(context, router));
context.addLocalizationData({
en: require('./locales/en'),
ru: require('./locales/ru'),
});
return context;
}

View File

@@ -0,0 +1,136 @@
import Vue from 'vue';
import cloneDeep from 'lodash/cloneDeep';
import { store } from '@/store';
import i18n from '@/i18n';
import { formatDate } from '@/utils/time';
import InvitationService from '../services/invitation.service';
import InvitationForm from '../components/InvitationForm';
import Invitations from '../views/Invitations';
import { hasRole } from '@/utils/user';
export function fieldsToFillProvider() {
return [
{
label: 'field.users',
key: 'users',
required: true,
render: (h, props) => {
return h(InvitationForm, {
props: {
value: props.currentValue,
},
on: {
input(value) {
props.inputHandler(value);
},
},
});
},
},
];
}
export const config = { fieldsToFillProvider };
export default (context, router) => {
const invitationsContext = cloneDeep(context);
invitationsContext.routerPrefix = 'company/invitations';
const crud = invitationsContext.createCrud('invitations.crud-title', 'invitations', InvitationService);
const crudNewRoute = crud.new.getNewRouteName();
const navigation = { new: crudNewRoute };
crud.new.addToMetaProperties('permissions', 'invitations/create', crud.new.getRouterConfig());
crud.new.addToMetaProperties('navigation', navigation, crud.new.getRouterConfig());
crud.new.addToMetaProperties('afterSubmitCallback', () => router.go(-1), crud.new.getRouterConfig());
const grid = invitationsContext.createGrid('invitations.grid-title', 'invitations', InvitationService);
grid.addToMetaProperties('navigation', navigation, grid.getRouterConfig());
grid.addToMetaProperties('permissions', () => hasRole(store.getters['user/user'], 'admin'), grid.getRouterConfig());
const fieldsToFill = config.fieldsToFillProvider();
crud.new.addField(fieldsToFill);
grid.addColumn([
{
title: 'field.email',
key: 'email',
},
{
title: 'field.expires_at',
key: 'expires_at',
render(h, { item }) {
const expiresAt = formatDate(item.expires_at);
return h('span', [expiresAt]);
},
},
]);
grid.addFilter([
{
filterName: 'filter.fields.email',
referenceKey: 'email',
},
]);
grid.addAction([
{
title: 'invite.resend',
actionType: 'primary',
icon: 'icon-refresh-ccw',
onClick: async (router, { item }, context) => {
const invitationService = new InvitationService();
try {
await invitationService.resend(item.id);
context.fetchData();
context.$Message.success(i18n.t('message.success'));
} catch (e) {
//
}
},
},
{
title: 'control.delete',
actionType: 'error',
icon: 'icon-trash-2',
onClick: (router, { item }, context) => {
context.onDelete(item);
},
},
]);
grid.addPageControls([
{
label: 'control.create',
type: 'primary',
icon: 'icon-edit',
onClick: ({ $router }) => {
$router.push({ name: crudNewRoute });
},
},
]);
return {
accessCheck: async () => Vue.prototype.$can('viewAny', 'invitation'),
scope: 'company',
order: 20,
component: Invitations,
route: {
name: 'Invitations.crud.invitations',
path: '/company/invitations',
meta: {
label: 'navigation.invitations',
service: new InvitationService(),
},
children: [
{
...grid.getRouterConfig(),
path: '',
},
...crud.getRouterConfig(),
],
},
};
};

View File

@@ -0,0 +1,24 @@
import ResourceService from '@/services/resource.service';
import axios from 'axios';
export default class InvitationService extends ResourceService {
getAll(config = {}) {
return axios.get('invitations/list', config);
}
save(data, isNew = false) {
return axios.post(`invitations/${isNew ? 'create' : 'edit'}`, data);
}
resend(id) {
return axios.post('invitations/resend', { id });
}
deleteItem(id) {
return axios.post('invitations/remove', { id });
}
getWithFilters(filters, config = {}) {
return axios.post('invitations/list', filters, config);
}
}

View File

@@ -0,0 +1,3 @@
<template>
<router-view></router-view>
</template>