Actual prod

This commit is contained in:
mac 2026-07-04 13:26:50 +03:00
parent e6d644a663
commit 50c70b5a69

View File

@ -747,7 +747,7 @@ $_SESSION['event_id_temp'] *= -1;
<div class="filter-popup-input">
<div class="crm__filter-input">
<input type="text" placeholder="Количество присоединенных заявок" v-model="filtr.total_union" class="text medium-input no-mrg-left" style="width: 382px; height: 18px; font-size: 18px; padding: 9px;">
<input type="text" placeholder="Количество присоединенных заявок" v-model="filtr.total_union" class="text medium-input no-mrg-left" style="width: 382px; height: 18px; font-size: 18px; padding: 9px; box-sizing: content-box;">
</div>
</div>
@ -845,7 +845,7 @@ $_SESSION['event_id_temp'] *= -1;
<div class="filter-popup-input">
<div class="crm__filter-input">
<input @change="checkObjectId" type="text" style="width: 382px; height: 18px; font-size: 18px; padding: 9px;" v-model="filtr.object_id" class="text medium-input no-mrg-left" placeholder="ID объекта по заявке">
<input @change="checkObjectId" type="text" style="width: 382px; height: 18px; font-size: 18px; padding: 9px; box-sizing: content-box;" v-model="filtr.object_id" class="text medium-input no-mrg-left" placeholder="ID объекта по заявке">
</div>
</div>
@ -1017,12 +1017,19 @@ $_SESSION['event_id_temp'] *= -1;
<label for="isPartnerReq">Совместные заявки</label>
</div>
</div>
<?php
$allowed_users_deal = [117, 4];
if (in_array((int)$_SESSION['agency_id'], $allowed_users_deal)) {
?>
<div class="filter-popup-input">
<div class="checkbox">
<input name="is_deal" @change="checkTasks" id="isDealReq" v-model="filtr.is_deal" type="checkbox">
<label for="isDealReq">Есть сделка</label>
</div>
</div>
<?php } ?>
</div>
</div>
</div>
@ -1167,10 +1174,156 @@ $t = $endtime - $starttime;
}*/
?>
<?php
// Воронки для модалки копирования — канонический Funnel::get_funnels('requisitions').
$copyFunnelClass = new Funnel();
$copyFunnelClass->set_agency_id($user->agencyId);
$copyFunnelClass->set_user_id((int)$_SESSION['id']);
$copyFunnelsRaw = $copyFunnelClass->get_funnels('requisitions');
$copyFunnelsListArr = array();
if (is_array($copyFunnelsRaw)) {
foreach ($copyFunnelsRaw as $copyFunnelRow) {
$copyFunnelsListArr[] = array(
'id' => (int)$copyFunnelRow['id'],
'name' => isset($copyFunnelRow['name']) && $copyFunnelRow['name'] !== null
? (string)$copyFunnelRow['name']
: 'Обычные',
);
}
}
// Сотрудники для пикера «Ответственный» — Я + Всё агентство + менеджеры + агенты (как в templates/form_emp.php).
$copySelfId = (int)$_SESSION['id'];
$copyEmployeesList = array(
array('id' => $copySelfId, 'name' => 'Я'),
);
$copyMenuPerms = $user->checkMenuPermissions();
if ($_SESSION['agency'] || $_SESSION['users_admin'] || (isset($copyMenuPerms['menu_can_transfer_to_common']) && $copyMenuPerms['menu_can_transfer_to_common'] == 1)) {
$copyEmployeesList[] = array('id' => 0, 'name' => 'Всё агентство');
}
$copyManagersList = User::getAllManagers($user->agencyId);
if (!empty($copyManagersList)) {
foreach ($copyManagersList as $copyMgr) {
// Себя не дублируем: текущий пользователь уже добавлен как «Я» (иначе дубль :key в Vue-пикере).
if ((int)$copyMgr['id'] === $copySelfId) {
continue;
}
$copyEmployeesList[] = array(
'id' => (int)$copyMgr['id'],
'name' => trim($copyMgr['last_name'] . ' ' . $copyMgr['first_name'] . ' ' . $copyMgr['middle_name']),
'group' => 'Менеджеры',
);
}
}
$copyAgentsList = User::getAllAgents($user->agencyId);
if (!empty($copyAgentsList)) {
foreach ($copyAgentsList as $copyAgnt) {
// Себя не дублируем: текущий пользователь уже добавлен как «Я».
if ((int)$copyAgnt['id'] === $copySelfId) {
continue;
}
$copyEmployeesList[] = array(
'id' => (int)$copyAgnt['id'],
'name' => trim($copyAgnt['last_name'] . ' ' . $copyAgnt['first_name'] . ' ' . $copyAgnt['middle_name']),
'group' => 'Агенты',
);
}
}
?>
<?php // Данные модалки копирования вынесены за пределы #requisitions_list: Vue компилирует содержимое el целиком и не парсит <script> внутри шаблона. ?>
<script>
// Читаются в openCopyRequisitionModal без AJAX.
window.__copyFunnelsList = <?= json_encode($copyFunnelsListArr, JSON_UNESCAPED_UNICODE) ?>;
window.__copyEmployeesList = <?= json_encode($copyEmployeesList, JSON_UNESCAPED_UNICODE) ?>;
</script>
<div id="requisitions_list">
<div v-show="isPreloader===1" style="text-align:center; margin-top: 25px;">
<img src="../images/rocket-spinner.svg" width="96px">
</div>
<?php // Данные модалки копирования вычислены и выведены до #requisitions_list (см. выше), чтобы Vue не парсил <script> внутри шаблона. ?>
<!-- Модалка копирования заявки. display:none на .full_modal-bg защита от сырого {{...}} до старта Vue. -->
<div v-show="copyModal.open" class="full_modal-bg" style="z-index: 100000; display: none">
<div class="full_modal" style="position: relative; max-width: 480px; padding: 0; background: #fff; border-radius: 8px; box-shadow: 0 8px 32px rgba(0,0,0,.2);">
<span class="pseudo-link closer" @click="closeCopyModal" style="position: absolute; top: 10px; right: 14px; font-size: 22px; line-height: 1; cursor: pointer; color: #999; z-index: 10;"><i class="ti-close"></i></span>
<!-- Header -->
<div style="padding: 22px 28px 12px; border-bottom: 1px solid #eee;">
<h3 style="margin: 0; font-size: 18px; font-weight: 600; color: #333;">Создать копию заявки ID {{ copyModal.srcId }}?</h3>
</div>
<!-- Body -->
<div style="padding: 18px 28px;">
<div v-if="copyModal.warnings.indexOf('contract_without_object') !== -1"
style="background: #fff7e6; border: 1px solid #ffd591; padding: 10px 12px; border-radius: 6px; margin-bottom: 14px; color: #92400e; font-size: 13px; line-height: 1.4;">
У этой заявки есть договор продажи, связанный с объектом. По правилам копирования для текущего типа объект в копию не переносится договор будет создан в новой заявке без связи с объектом.
</div>
<div style="margin-bottom: 14px;">
<label style="display: block; margin-bottom: 6px; font-size: 13px; color: #666; font-weight: normal;">Воронка</label>
<select v-model="copyModal.funnelId"
style="width: 100%; height: 36px; padding: 6px 10px; border: 1px solid #ccc; border-radius: 4px; font-size: 14px; color: #333; background: #fff; box-sizing: border-box;">
<option v-for="f in copyModal.funnels" :key="f.id" :value="f.id">{{ f.name }}</option>
</select>
</div>
<!-- Ответственный: имитация fastselect; закрытие по клику вне через onCopyModalDocumentClick. -->
<div ref="copyWhoWorkPicker" @mousedown.stop style="margin-bottom: 14px; position: relative;">
<label style="display: block; margin-bottom: 6px; font-size: 13px; color: #666; font-weight: normal;">Ответственный</label>
<div @click="copyModal.whoWorkOpen = !copyModal.whoWorkOpen"
style="position: relative; height: 36px; border: 1px solid #ccc; border-radius: 4px; background: #fff; cursor: pointer; padding: 6px 38px 6px 10px; display: flex; align-items: center; font-size: 14px; color: #333; box-sizing: border-box;">
<span style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">{{ copyModal.whoWorkLabel || 'Выберите...' }}</span>
<i style="position: absolute; right: 12px; top: 50%; transform: translateY(-50%); width: 16px; height: 12px; display: flex; flex-direction: column; justify-content: space-between;">
<span style="height: 2px; background: #888; display: block;"></span>
<span style="height: 2px; background: #888; display: block;"></span>
<span style="height: 2px; background: #888; display: block;"></span>
</i>
</div>
<div v-show="copyModal.whoWorkOpen"
style="position: absolute; top: calc(100% + 4px); left: 0; right: 0; background: #fff; border: 1px solid #ccc; border-radius: 4px; max-height: 280px; overflow-y: auto; z-index: 20; box-shadow: 0 4px 12px rgba(0,0,0,.1);">
<div style="padding: 8px; border-bottom: 1px solid #eee; background: #fafafa;">
<input type="text" v-model="copyModal.whoWorkSearch" placeholder="Искать..."
@click.stop
ref="copyWhoWorkSearchInput"
style="width: 100%; height: 30px; padding: 4px 8px; border: 1px solid #ccc; border-radius: 3px; font-size: 13px; box-sizing: border-box;">
</div>
<div>
<template v-for="(emp, idx) in copyFilteredEmployees">
<div v-if="emp.group && (idx === 0 || copyFilteredEmployees[idx-1].group !== emp.group)"
:key="'g-' + emp.group + '-' + emp.id"
style="padding: 6px 12px; font-size: 11px; color: #999; text-transform: uppercase; background: #f7f7f7; font-weight: 600;">
{{ emp.group }}
</div>
<div :key="emp.id"
@click="selectCopyWhoWork(emp)"
:style="{padding: '8px 12px', cursor: 'pointer', fontSize: '14px', background: copyModal.whoWorkId === emp.id ? '#e6f4ea' : '#fff', color: '#333'}"
@mouseover="$event.target.style.background = copyModal.whoWorkId === emp.id ? '#e6f4ea' : '#f5f5f5'"
@mouseout="$event.target.style.background = copyModal.whoWorkId === emp.id ? '#e6f4ea' : '#fff'">
{{ emp.name }}
</div>
</template>
<div v-if="copyFilteredEmployees.length === 0" style="padding: 12px; color: #999; font-size: 13px; text-align: center;">
Ничего не найдено
</div>
</div>
</div>
</div>
<div v-if="copyModal.error" style="background: #fdecea; border: 1px solid #f5c2c0; color: #c33; padding: 8px 12px; border-radius: 4px; font-size: 13px; margin-bottom: 14px;">
{{ copyModal.error }}
</div>
</div>
<div style="padding: 0 28px 22px;">
<button @click="submitCopy"
:disabled="copyModal.submitting"
style="width: 100%; height: 40px; background: #43A047; color: #fff; border: none; border-radius: 4px; font-size: 14px; font-weight: 500; cursor: pointer;">
{{ copyModal.submitting ? 'Создаём…' : 'Создать копию' }}
</button>
</div>
</div>
</div>
<template>
<div v-if="isList" v-show="isPreloader===0" class="clients">
@ -1331,14 +1484,35 @@ $t = $endtime - $starttime;
</div>
<div class="actions">
<?php
$allowed_users_deal = [117, 4];
if (in_array((int)$_SESSION['agency_id'], $allowed_users_deal)) {
?>
<a v-if="item.is_deal == 1" href="javascript:{};" class="no-border" title="Сделка"
@click="initEditDealFromList(item.id)">
<span style="color: #43A047 !important;" class="simple-button settings"><i class="fas fa-handshake"></i></span>
</a>
<a v-if="!isEmpty(item.union_req)" href="javascript:{};" :data-id="'req'+item.id"
class="no-border" title="Заявки для объединения" @click="open_union_req_form(item.union_req, item.id)">
<span style="color: #EE6161 !important;" class="simple-button settings"><i class="far fa-clone"></i>
<?php } ?>
<!-- Иконка объединения. fill:none inline т.к. .simple-button svg path { fill: #b7bcbc } перекрывает атрибут. -->
<a v-if="!isEmpty(item.union_req) && item.can_edit==1 && item.deleted==0" href="javascript:{};" :data-id="'req'+item.id"
class="no-border" title="Объединить с другой заявкой" @click="open_union_req_form(item.union_req, item.id)">
<span class="simple-button settings">
<svg width="18" height="18" viewBox="0 0 24 24" style="fill:none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M9.8 14.2a4 4 0 0 1 0-5.66l2.83-2.83a4 4 0 0 1 5.66 5.66l-1.41 1.41" style="fill:none; stroke:#d32f2f"/>
<path d="M14.2 9.8a4 4 0 0 1 0 5.66l-2.83 2.83a4 4 0 0 1-5.66-5.66l1.41-1.41" style="fill:none; stroke:#d32f2f"/>
</svg>
</span>
</a>
<!-- Иконка копирования. inline fill:none обязателен (см. .simple-button svg path). -->
<a v-if="item.can_edit==1 && item.deleted==0" href="javascript:{};" @click="openCopyRequisitionModal(item.id)" class="no-border" title="Скопировать заявку">
<span class="simple-button settings">
<svg width="18" height="18" viewBox="0 0 24 24" style="fill:none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="9" y="9" width="13" height="13" rx="2" style="fill:none"/>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" style="fill:none"/>
</svg>
</span>
</a>
@ -1648,7 +1822,7 @@ $t = $endtime - $starttime;
<i class="ti-pencil"></i><span> Редактировать</span>
</a>
</div>
<div v-if="item.deleted > 0" class="client_row row_line" :class="{hidden: !item.isMainInfo}">
<div v-if="item.deleted > 0 || item.deal_id > 0"" class="client_row row_line" :class="{hidden: !item.isMainInfo}">
<p class="small">Причина закрытия</p>
<p class="desc" v-html="item.reason"></p>
</div>
@ -1862,24 +2036,40 @@ $t = $endtime - $starttime;
</g></g>
</svg>
</div>
<div v-if="item.priority>0" class="kanban__item-icon2" title="Категория клиента">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_2" x="0px" y="0px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve" width="19px" height="19px" class="">
<ellipse cx="256" cy="256" rx="150" ry="150" :class="'priority'+item.priority"/></svg>
</div>
<?php /* Точка приоритета убрана — цветная полоса слева достаточна. */ ?>
<?php if (!should_hide_contacts_for_current_user()): ?>
<div class="kanban__item-icon">
<a class="whatsappBtn_mini" style="padding-left: 6px;" target="_blank" :href="'https://t.me/+'+item.phone">
<!-- Иконка чата (TG + WhatsApp) popup через .chat-icon-combined:hover .chat-popup. -->
<div class="kanban__item-icon chat-icon-combined">
<a class="whatsappBtn_mini" href="javascript:{};" title="Открыть чат" style="color: #9e9e9e;">
<svg width="22" height="22" viewBox="0 0 24 24" style="fill:none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" fill="none"/>
</svg>
</a>
<div class="chat-popup">
<a target="_blank" :href="'https://t.me/+'+item.phone" title="Telegram">
<img style="width:16px" src="/images/telegram.png">
</a>
</div>
<div class="kanban__item-icon">
<a class="whatsappBtn_mini" target="_blank" :href="'https://wa.me/'+item.phone">
<a target="_blank" :href="'https://wa.me/'+item.phone" title="WhatsApp">
<img src="/images/whatsapp_mini.png">
</a>
</div>
</div>
<?php endif; ?>
<div style="margin-right: 7px;" v-if="!isEmpty(item.union_req)" class="kanban__item-icon">
<a style="color: #EE6161 !important;" href="javascript:{};" @click="open_union_req_form(item.union_req, item.id)"><i class="far fa-clone"></i></a>
<div style="margin-right: 7px;" v-if="!isEmpty(item.union_req) && item.can_edit==1 && item.deleted==0" class="kanban__item-icon">
<a href="javascript:{};" title="Объединить с другой заявкой" @click="open_union_req_form(item.union_req, item.id)">
<svg width="22" height="22" viewBox="0 0 24 24" style="fill:none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M9.8 14.2a4 4 0 0 1 0-5.66l2.83-2.83a4 4 0 0 1 5.66 5.66l-1.41 1.41" style="fill:none; stroke:#d32f2f"/>
<path d="M14.2 9.8a4 4 0 0 1 0 5.66l-2.83 2.83a4 4 0 0 1-5.66-5.66l1.41-1.41" style="fill:none; stroke:#d32f2f"/>
</svg>
</a>
</div>
<div v-if="item.can_edit==1 && item.deleted==0" style="margin-right: 7px;" class="kanban__item-icon">
<a class="whatsappBtn_mini" style="color: #9e9e9e;" href="javascript:{};" @click="openCopyRequisitionModal(item.id)" title="Скопировать заявку">
<svg width="22" height="22" viewBox="0 0 24 24" style="fill:none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="9" y="9" width="13" height="13" rx="2" fill="none"/>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" fill="none"/>
</svg>
</a>
</div>
</div>
@ -2123,24 +2313,40 @@ $t = $endtime - $starttime;
</g></g>
</svg>
</div>
<div v-if="item.priority>0" class="kanban__item-icon2" title="Категория клиента">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_2" x="0px" y="0px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve" width="19px" height="19px" class="">
<ellipse cx="256" cy="256" rx="150" ry="150" :class="'priority'+item.priority"/></svg>
</div>
<?php /* Точка приоритета убрана — цветная полоса слева достаточна. */ ?>
<?php if (!should_hide_contacts_for_current_user()): ?>
<div class="kanban__item-icon">
<a class="whatsappBtn_mini" style="padding-left: 6px;" target="_blank" :href="'https://t.me/+'+item.phone">
<!-- Иконка чата (TG + WhatsApp) popup через .chat-icon-combined:hover .chat-popup. -->
<div class="kanban__item-icon chat-icon-combined">
<a class="whatsappBtn_mini" href="javascript:{};" title="Открыть чат" style="color: #9e9e9e;">
<svg width="22" height="22" viewBox="0 0 24 24" style="fill:none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" fill="none"/>
</svg>
</a>
<div class="chat-popup">
<a target="_blank" :href="'https://t.me/+'+item.phone" title="Telegram">
<img style="width:16px" src="/images/telegram.png">
</a>
</div>
<div class="kanban__item-icon">
<a class="whatsappBtn_mini" target="_blank" :href="'https://wa.me/'+item.phone">
<a target="_blank" :href="'https://wa.me/'+item.phone" title="WhatsApp">
<img src="/images/whatsapp_mini.png">
</a>
</div>
</div>
<?php endif; ?>
<div style="margin-right: 7px;" v-if="!isEmpty(item.union_req)" class="kanban__item-icon">
<a class="whatsappBtn_mini" style="color: #EE6161 !important;" @click="open_union_req_form(item.union_req, item.id)" href="javascript:{};"><i class="far fa-clone"></i></a>
<div style="margin-right: 7px;" v-if="!isEmpty(item.union_req) && item.can_edit==1 && item.deleted==0" class="kanban__item-icon">
<a class="whatsappBtn_mini" title="Объединить с другой заявкой" @click="open_union_req_form(item.union_req, item.id)" href="javascript:{};">
<svg width="22" height="22" viewBox="0 0 24 24" style="fill:none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M9.8 14.2a4 4 0 0 1 0-5.66l2.83-2.83a4 4 0 0 1 5.66 5.66l-1.41 1.41" style="fill:none; stroke:#d32f2f"/>
<path d="M14.2 9.8a4 4 0 0 1 0 5.66l-2.83 2.83a4 4 0 0 1-5.66-5.66l1.41-1.41" style="fill:none; stroke:#d32f2f"/>
</svg>
</a>
</div>
<div v-if="item.can_edit==1 && item.deleted==0" style="margin-right: 7px;" class="kanban__item-icon">
<a class="whatsappBtn_mini" style="color: #9e9e9e;" href="javascript:{};" @click="openCopyRequisitionModal(item.id)" title="Скопировать заявку">
<svg width="22" height="22" viewBox="0 0 24 24" style="fill:none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="9" y="9" width="13" height="13" rx="2" fill="none"/>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" fill="none"/>
</svg>
</a>
</div>
<div v-if="item.union_total > 0" class="kanban__item-icon" style="margin-right: 7px;">
<span v-if="item.can_see_joint == 1" @click="open_joint_req(item.id)" class="jw__tab__counter" style="background: #757575;cursor:pointer; padding-bottom:4px">{{ item.union_total }}</span>
@ -2508,6 +2714,7 @@ $t = $endtime - $starttime;
?>
</div>
<div class="f__modal-bg" id="confirm__user_req_bg" style="display: none;">
@ -2721,9 +2928,11 @@ $t = $endtime - $starttime;
</div>
<?php
$allowed_users_deal = [18388];
if (in_array((int)$_SESSION['id'], $allowed_users_deal)) {
$allowed_users_deal = [117, 4];
if (in_array((int)$_SESSION['agency_id'], $allowed_users_deal)) {
echo '<script type="module" src="/deal/assets/app.js"></script>';
echo '<link rel="stylesheet" href="/deal/assets/app.css">';
}