chore: initial import for test contour with k3s CI
@@ -0,0 +1,52 @@
|
|||||||
|
# In all environments, the following files are loaded if they exist,
|
||||||
|
# the latter taking precedence over the former:
|
||||||
|
#
|
||||||
|
# * .env contains default values for the environment variables needed by the app
|
||||||
|
# * .env.local uncommitted file with local overrides
|
||||||
|
# * .env.$APP_ENV committed environment-specific defaults
|
||||||
|
# * .env.$APP_ENV.local uncommitted environment-specific overrides
|
||||||
|
#
|
||||||
|
# Real environment variables win over .env files.
|
||||||
|
#
|
||||||
|
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
|
||||||
|
#
|
||||||
|
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
|
||||||
|
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
|
||||||
|
|
||||||
|
###> symfony/framework-bundle ###
|
||||||
|
APP_ENV=prod
|
||||||
|
APP_SECRET=60c125f1b185d683df10d02b53c043bc
|
||||||
|
TRUSTED_PROXIES=127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
|
||||||
|
TRUSTED_HEADERS='["x-forwarded-for","x-forwarded-host","x-forwarded-proto","x-forwarded-port","x-forwarded-prefix"]'
|
||||||
|
###< symfony/framework-bundle ###
|
||||||
|
|
||||||
|
###> symfony/mailer ###
|
||||||
|
# MAILER_DSN=smtp://localhost
|
||||||
|
###< symfony/mailer ###
|
||||||
|
|
||||||
|
###> doctrine/doctrine-bundle ###
|
||||||
|
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
|
||||||
|
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
|
||||||
|
#
|
||||||
|
# DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
|
||||||
|
# DATABASE_URL="mysql://cabinet_sova_:rP1bX9dG3sfJ5r@mysql:3306/cabinet_sova_?serverVersion=5.6"
|
||||||
|
DATABASE_BITRIX_URL="mysql://ivan:oE2tM9dI5t@77.106.69.11:3306/sovamed?serverVersion=8.3"
|
||||||
|
DATABASE_URL="postgresql://cabinet:zd3Ry-08Htrf-6ggkn@pgsql:5432/cabinet?serverVersion=13&charset=utf8"
|
||||||
|
###< doctrine/doctrine-bundle ###
|
||||||
|
|
||||||
|
###> Redis ###
|
||||||
|
REDIS_URL="redis://Hgty-Gmmi-7655f-4zSd@redis:6379?timeout=2&dbindex=2"
|
||||||
|
###> Redis ###
|
||||||
|
SMSRU_KEY_API="B58070E1-E89B-95B0-D9BA-37A108868CAF"
|
||||||
|
SMSRU_FROM_SOVAMED="sovamed"
|
||||||
|
SMS4B_TOKEN="1334180305d8462dd9887f981fd3d05635c161c8a1bcda45"
|
||||||
|
SMS4B_FROM_WMTMED="Clinic_WMT"
|
||||||
|
MIS="https://widget.sovamed.ru"
|
||||||
|
BITRIX24_URL="/rest/10998/3hrv38rzo3khchj3/crm.lead.add.json"
|
||||||
|
SMARTCAPTCHA_SERVER_KEY="ysc2_EaQp6z8UPPQAIfHLm8mllruHsN3j42qGAz8VFY5l694a51cc"
|
||||||
|
###> nelmio/cors-bundle ###
|
||||||
|
CORS_ALLOW_ORIGIN='^https?://(localhost|127\.0\.0\.1|.*\.sovamed\.ru|.*\.wmtmed\.ru|sovamed\.ru|wmtmed\.ru)(:[0-9]+)?$'
|
||||||
|
###< nelmio/cors-bundle ###
|
||||||
|
|
||||||
|
# Показ баннера «технические работы» (1/true/on/yes — включено)
|
||||||
|
TECH_MAINTENANCE=true
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# Stub env for Gitea Actions / local CI (no production secrets).
|
||||||
|
|
||||||
|
APP_ENV=dev
|
||||||
|
APP_DEBUG=0
|
||||||
|
APP_SECRET=ci-not-a-real-secret-change-me-32b
|
||||||
|
SYMFONY_DEPRECATIONS_HELPER=999999
|
||||||
|
|
||||||
|
TRUSTED_PROXIES=127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
|
||||||
|
TRUSTED_HEADERS='["x-forwarded-for","x-forwarded-host","x-forwarded-proto","x-forwarded-port","x-forwarded-prefix"]'
|
||||||
|
|
||||||
|
DATABASE_URL="postgresql://ci:ci@127.0.0.1:5432/ci?serverVersion=16&charset=utf8"
|
||||||
|
DATABASE_BITRIX_URL="mysql://ci:ci@127.0.0.1:3306/ci?serverVersion=8.0"
|
||||||
|
REDIS_URL=redis://127.0.0.1:6379
|
||||||
|
|
||||||
|
MAILER_DSN=null://null
|
||||||
|
CORS_ALLOW_ORIGIN='^https?://.*$'
|
||||||
|
TECH_MAINTENANCE=false
|
||||||
|
|
||||||
|
SMSRU_KEY_API=noop
|
||||||
|
SMSRU_FROM_SOVAMED=noop
|
||||||
|
SMS4B_TOKEN=noop
|
||||||
|
SMS4B_FROM_WMTMED=noop
|
||||||
|
MIS=http://localhost
|
||||||
|
BITRIX24_URL=http://localhost
|
||||||
|
SMARTCAPTCHA_SERVER_KEY=noop
|
||||||
|
|
||||||
|
VAR_DUMPER_SERVER=127.0.0.1:9912
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# In all environments, the following files are loaded if they exist,
|
||||||
|
# the latter taking precedence over the former:
|
||||||
|
#
|
||||||
|
# * .env contains default values for the environment variables needed by the app
|
||||||
|
# * .env.local uncommitted file with local overrides
|
||||||
|
# * .env.$APP_ENV committed environment-specific defaults
|
||||||
|
# * .env.$APP_ENV.local uncommitted environment-specific overrides
|
||||||
|
#
|
||||||
|
# Real environment variables win over .env files.
|
||||||
|
#
|
||||||
|
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
|
||||||
|
#
|
||||||
|
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
|
||||||
|
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
|
||||||
|
|
||||||
|
###> symfony/framework-bundle ###
|
||||||
|
APP_ENV=dev
|
||||||
|
APP_SECRET=60c125f1b185d683df10d02b53c043bc
|
||||||
|
###< symfony/framework-bundle ###
|
||||||
|
|
||||||
|
DATABASE_URL="postgresql://cabinet:zd3Ry-08Htrf-6ggkn@host.docker.internal:5433/cabinet?serverVersion=13&charset=utf8"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# define your env variables for the test env here
|
||||||
|
KERNEL_CLASS='App\Kernel'
|
||||||
|
APP_SECRET='$ecretf0rt3st'
|
||||||
|
SYMFONY_DEPRECATIONS_HELPER=999999
|
||||||
|
PANTHER_APP_ENV=panther
|
||||||
|
PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
name: cabinet-ci-cd
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'cabinet-v*'
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY: gitea-http.gitea.svc.cluster.local:3000
|
||||||
|
IMAGE: gitea-http.gitea.svc.cluster.local:3000/sova/cabinet
|
||||||
|
IMAGE_DEPLOY: git.sova.local/sova/cabinet
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Setup PHP
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: '8.2'
|
||||||
|
extensions: pdo_pgsql, pdo_mysql, redis, intl, zip, gd
|
||||||
|
- name: Prepare CI environment
|
||||||
|
run: |
|
||||||
|
cp .env.ci .env.local
|
||||||
|
mkdir -p var
|
||||||
|
- run: composer install --prefer-dist --no-interaction
|
||||||
|
- run: composer phpunit || true
|
||||||
|
- run: composer audit || true
|
||||||
|
|
||||||
|
parse-tag:
|
||||||
|
if: startsWith(github.ref, 'refs/tags/cabinet-v')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
full_tag: ${{ steps.meta.outputs.full_tag }}
|
||||||
|
env: ${{ steps.meta.outputs.env }}
|
||||||
|
version: ${{ steps.meta.outputs.version }}
|
||||||
|
steps:
|
||||||
|
- name: Parse tag
|
||||||
|
id: meta
|
||||||
|
run: |
|
||||||
|
TAG="${GITHUB_REF#refs/tags/}"
|
||||||
|
echo "full_tag=$TAG" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "env=$(echo "$TAG" | sed -E 's/cabinet-v([0-9.]+)-([a-z]+)/\2/')" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "version=$(echo "$TAG" | sed -E 's/cabinet-v([0-9.]+).*/\1/')" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
build-and-push:
|
||||||
|
needs: [test, parse-tag]
|
||||||
|
if: startsWith(github.ref, 'refs/tags/cabinet-v')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Docker login
|
||||||
|
env:
|
||||||
|
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
|
||||||
|
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
||||||
|
run: |
|
||||||
|
echo "${REGISTRY_PASSWORD}" | docker login "$REGISTRY" -u "${REGISTRY_USER}" --password-stdin
|
||||||
|
- name: Build and push
|
||||||
|
run: |
|
||||||
|
TAG="${{ needs.parse-tag.outputs.full_tag }}"
|
||||||
|
docker build -f Dockerfile -t "$IMAGE:${TAG}" -t "$IMAGE:${{ needs.parse-tag.outputs.version }}" .
|
||||||
|
docker push "$IMAGE:${TAG}"
|
||||||
|
docker push "$IMAGE:${{ needs.parse-tag.outputs.version }}"
|
||||||
|
|
||||||
|
deploy-gitops:
|
||||||
|
needs: [build-and-push, parse-tag]
|
||||||
|
if: startsWith(github.ref, 'refs/tags/cabinet-v')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Bump image tag in sova-deploy
|
||||||
|
env:
|
||||||
|
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
|
||||||
|
DEPLOY_USER: ${{ secrets.REGISTRY_USER }}
|
||||||
|
run: |
|
||||||
|
REPO_URL="http://${DEPLOY_USER}:${DEPLOY_TOKEN}@gitea-http.gitea.svc.cluster.local:3000/sova/sova-deploy.git"
|
||||||
|
git clone "${REPO_URL}"
|
||||||
|
cd sova-deploy
|
||||||
|
ENV="${{ needs.parse-tag.outputs.env }}"
|
||||||
|
TAG="${{ needs.parse-tag.outputs.full_tag }}"
|
||||||
|
git config user.email "ci-bot@sova.local"
|
||||||
|
git config user.name "sova-ci"
|
||||||
|
MAX_RETRIES=5
|
||||||
|
case "$(uname -m)" in
|
||||||
|
x86_64|amd64) YQ_ARCH=amd64 ;;
|
||||||
|
aarch64|arm64) YQ_ARCH=arm64 ;;
|
||||||
|
*) echo "Unsupported arch: $(uname -m)"; exit 1 ;;
|
||||||
|
esac
|
||||||
|
curl -sSL -o /usr/local/bin/yq "https://github.com/mikefarah/yq/releases/download/v4.44.3/yq_linux_${YQ_ARCH}"
|
||||||
|
chmod +x /usr/local/bin/yq
|
||||||
|
for attempt in $(seq 1 $MAX_RETRIES); do
|
||||||
|
git pull --rebase "${REPO_URL}" main
|
||||||
|
yq -i ".image.repository = \"${IMAGE_DEPLOY}\"" "apps/cabinet/values-${ENV}.yaml"
|
||||||
|
yq -i ".image.tag = \"${TAG}\"" "apps/cabinet/values-${ENV}.yaml"
|
||||||
|
yq -i ".image.pullPolicy = \"IfNotPresent\"" "apps/cabinet/values-${ENV}.yaml"
|
||||||
|
git add "apps/cabinet/values-${ENV}.yaml"
|
||||||
|
git diff --cached --quiet && { echo "No changes"; exit 0; }
|
||||||
|
git commit -m "chore(cabinet): bump ${ENV} to ${TAG}"
|
||||||
|
if git push "${REPO_URL}" main; then
|
||||||
|
echo "Push OK on attempt ${attempt}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "Push failed, retry ${attempt}/${MAX_RETRIES}..."
|
||||||
|
git reset --hard HEAD~1
|
||||||
|
sleep $((attempt * 2))
|
||||||
|
done
|
||||||
|
echo "Failed to push after ${MAX_RETRIES} attempts"
|
||||||
|
exit 1
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
###> symfony/framework-bundle ###
|
||||||
|
/.env.local
|
||||||
|
/.env.local.php
|
||||||
|
/.env.*.local
|
||||||
|
/config/secrets/prod/prod.decrypt.private.php
|
||||||
|
/src/Bundle/Infoclinica/certificate.rem
|
||||||
|
/public/bundles/
|
||||||
|
/var/
|
||||||
|
/vendor/
|
||||||
|
###< symfony/framework-bundle ###
|
||||||
|
|
||||||
|
###> symfony/phpunit-bridge ###
|
||||||
|
.phpunit
|
||||||
|
.phpunit.result.cache
|
||||||
|
/phpunit.xml
|
||||||
|
###< symfony/phpunit-bridge ###
|
||||||
|
/phpdocker
|
||||||
|
###> symfony/webpack-encore-bundle ###
|
||||||
|
/node_modules/
|
||||||
|
/public/build/
|
||||||
|
/public/banners/*
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
###< symfony/webpack-encore-bundle ###
|
||||||
|
/*.md
|
||||||
|
/*.lock
|
||||||
|
/symfony.lock
|
||||||
|
/yarn.lock
|
||||||
|
/service.sh
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
|
FROM composer:2 AS vendor
|
||||||
|
WORKDIR /app
|
||||||
|
COPY composer.json composer.lock* ./
|
||||||
|
RUN if [ -f composer.lock ]; then composer install --no-dev --no-scripts --prefer-dist --no-interaction --ignore-platform-reqs; \
|
||||||
|
else composer update --no-dev --no-scripts --prefer-dist --no-interaction --ignore-platform-reqs; fi
|
||||||
|
COPY . .
|
||||||
|
RUN composer dump-autoload --classmap-authoritative --no-dev \
|
||||||
|
&& composer run-script --no-dev post-install-cmd || true
|
||||||
|
|
||||||
|
FROM php:8.2-fpm-alpine AS runtime
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
tzdata postgresql-dev postgresql-client libpq libzip-dev \
|
||||||
|
libjpeg-turbo-dev freetype-dev libwebp-dev libpng-dev icu-dev \
|
||||||
|
oniguruma-dev bash autoconf g++ make \
|
||||||
|
&& docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp \
|
||||||
|
&& docker-php-ext-install -j$(nproc) \
|
||||||
|
zip pdo pdo_pgsql pdo_mysql gd intl opcache \
|
||||||
|
&& pecl install redis \
|
||||||
|
&& docker-php-ext-enable redis \
|
||||||
|
&& rm -rf /tmp/pear /var/cache/apk/*
|
||||||
|
|
||||||
|
ENV TZ=Europe/Moscow
|
||||||
|
RUN cp /usr/share/zoneinfo/$TZ /etc/localtime && echo "$TZ" > /etc/timezone
|
||||||
|
|
||||||
|
COPY docker/fpm-pool.conf /usr/local/etc/php-fpm.d/zz-docker.conf
|
||||||
|
COPY --from=vendor /app /app
|
||||||
|
|
||||||
|
RUN mkdir -p var/cache var/log public/uploads public/banners \
|
||||||
|
&& chown -R www-data:www-data var public/uploads public/banners \
|
||||||
|
&& chmod -R 775 var
|
||||||
|
|
||||||
|
ENV APP_ENV=prod APP_DEBUG=0
|
||||||
|
USER www-data
|
||||||
|
RUN APP_SECRET=build-placeholder \
|
||||||
|
DATABASE_URL="postgresql://build:build@127.0.0.1:5432/build" \
|
||||||
|
DATABASE_BITRIX_URL="mysql://build:build@127.0.0.1:3306/build" \
|
||||||
|
REDIS_URL="redis://127.0.0.1:6379" \
|
||||||
|
TRUSTED_PROXIES="127.0.0.1" \
|
||||||
|
CORS_ALLOW_ORIGIN="^https?://.*$" \
|
||||||
|
TECH_MAINTENANCE=false \
|
||||||
|
php bin/console cache:warmup --env=prod || true
|
||||||
|
|
||||||
|
EXPOSE 9000
|
||||||
|
CMD ["php-fpm", "-F"]
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { startStimulusApp } from '@symfony/stimulus-bridge';
|
||||||
|
|
||||||
|
// Registers Stimulus controllers from controllers.json and in the controllers/ directory
|
||||||
|
export const app = startStimulusApp(require.context(
|
||||||
|
'@symfony/stimulus-bridge/lazy-controller-loader!./controllers',
|
||||||
|
true,
|
||||||
|
/\.(j|t)sx?$/
|
||||||
|
));
|
||||||
|
|
||||||
|
// register any custom, 3rd party controllers here
|
||||||
|
// app.register('some_controller_name', SomeImportedController);
|
||||||
@@ -0,0 +1,357 @@
|
|||||||
|
const Cookies = require('js-cookie');
|
||||||
|
|
||||||
|
function serializeFormData(obj, prefix = '') {
|
||||||
|
const str = [];
|
||||||
|
for (const key in obj) {
|
||||||
|
if (obj.hasOwnProperty(key)) {
|
||||||
|
const value = obj[key];
|
||||||
|
const newKey = prefix ? `${prefix}[${key}]` : key;
|
||||||
|
|
||||||
|
if (value !== null && typeof value === 'object' && !Array.isArray(value) && !(value instanceof File) && !(value instanceof Blob)) {
|
||||||
|
// Рекурсивно обрабатываем вложенные объекты
|
||||||
|
str.push(serializeFormData(value, newKey));
|
||||||
|
} else if (Array.isArray(value)) {
|
||||||
|
// Обрабатываем массивы
|
||||||
|
value.forEach((item, index) => {
|
||||||
|
if (typeof item === 'object' && item !== null && !(item instanceof File) && !(item instanceof Blob)) {
|
||||||
|
str.push(serializeFormData(item, `${newKey}[${index}]`));
|
||||||
|
} else {
|
||||||
|
str.push(encodeURIComponent(`${newKey}[${index}]`) + '=' + encodeURIComponent(item));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
str.push(encodeURIComponent(newKey) + '=' + encodeURIComponent(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str.join('&');
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendRequest(data, url, method = "POST", dataType = "json", withCredentials = true, contentType = null) {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
try {
|
||||||
|
const methodUpper = method.toUpperCase();
|
||||||
|
const isGetOrHead = methodUpper === "GET" || methodUpper === "HEAD";
|
||||||
|
|
||||||
|
// Для GET/HEAD перемещаем данные в URL
|
||||||
|
if (isGetOrHead && data) {
|
||||||
|
const params = new URLSearchParams(data);
|
||||||
|
url = `${url}${url.includes('?') ? '&' : '?'}${params}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Автоматическое определение content-type для не-GET запросов
|
||||||
|
let finalContentType = contentType;
|
||||||
|
if (!finalContentType && !isGetOrHead) {
|
||||||
|
finalContentType = "application/x-www-form-urlencoded";
|
||||||
|
if (data && Object.values(data).some(value => value instanceof File || value instanceof Blob)) {
|
||||||
|
finalContentType = "multipart/form-data";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let body = null;
|
||||||
|
let headers = {};
|
||||||
|
|
||||||
|
// Подготовка тела только для не-GET запросов
|
||||||
|
if (!isGetOrHead && data) {
|
||||||
|
switch (finalContentType) {
|
||||||
|
case "application/json":
|
||||||
|
body = JSON.stringify(data);
|
||||||
|
headers["Content-Type"] = "application/json";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "multipart/form-data":
|
||||||
|
body = new FormData();
|
||||||
|
Object.entries(data).forEach(([key, value]) => {
|
||||||
|
body.append(key, value);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Используем правильную сериализацию для вложенных объектов
|
||||||
|
body = serializeFormData(data);
|
||||||
|
headers["Content-Type"] = "application/x-www-form-urlencoded";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: methodUpper,
|
||||||
|
headers: headers,
|
||||||
|
credentials: withCredentials ? "include" : "same-origin",
|
||||||
|
body: body
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const responseData = await response[dataType]();
|
||||||
|
resolve(responseData);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function isMobile() {
|
||||||
|
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|BB|PlayBook|IEMobile|Windows Phone|Kindle|Silk|Opera Mini/i.test(navigator.userAgent)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCityId(address) {
|
||||||
|
const cityMap = new Map([
|
||||||
|
['Волгоград', 96],
|
||||||
|
['Воронеж', 98],
|
||||||
|
['Краснодар', 3018],
|
||||||
|
['Саратов', 94]
|
||||||
|
]);
|
||||||
|
|
||||||
|
for (const [cityName, cityId] of cityMap) {
|
||||||
|
if (address.includes(cityName)) {
|
||||||
|
return cityId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCityCRM(region) {
|
||||||
|
switch (region) {
|
||||||
|
case '92': return 96; // Волгоград
|
||||||
|
case '93': return 98; // Воронеж
|
||||||
|
case '94': return 3018; // Краснодар
|
||||||
|
default: return 94; // Саратов
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLicensePersonLink() {
|
||||||
|
if (/cabinet\.sovamed\.ru/m.test(location.hostname) || /cabinet\.wmtmed\.ru/m.test(location.hostname)) {
|
||||||
|
return 'https://cabinet.sovamed.ru/docs/soglasie-cabinet.pdf';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'https://cabinet.sovamed.ru/docs/soglasie-site.pdf';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLicenseLink(region) {
|
||||||
|
switch (region) {
|
||||||
|
case '92': // Волгоград
|
||||||
|
return 'https://volgograd.sovamed.ru/o-sove/dokumenty-i-licenzii/politika-konfidencialnosti/';
|
||||||
|
|
||||||
|
case '93': // Воронеж
|
||||||
|
return 'https://voronezh.sovamed.ru/o-sove/dokumenty-i-licenzii/politika-konfidencialnosti/';
|
||||||
|
|
||||||
|
case '94': // Краснодар
|
||||||
|
return 'https://wmtmed.ru/about/confidentiality_policy.php';
|
||||||
|
|
||||||
|
case '95': // Совенок
|
||||||
|
return 'https://sovenok.sovamed.ru/o-sove/dokumenty-i-licenzii/politika-konfidencialnosti/';
|
||||||
|
|
||||||
|
case '96': // Комфорт
|
||||||
|
return 'https://sovamed.ru/docs/comfort_politika.pdf';
|
||||||
|
|
||||||
|
default: // Саратов
|
||||||
|
return 'https://sovamed.ru/o-sove/dokumenty-i-licenzii/politika-konfidencialnosti/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderCapcha(wrap) {
|
||||||
|
const elem = document.getElementById('smart-captcha');
|
||||||
|
|
||||||
|
if (elem) {
|
||||||
|
elem.parentNode.removeChild(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
wrap.innerHTML = '';
|
||||||
|
var recaptcha = document.createElement('div');
|
||||||
|
recaptcha.id = "smart-captcha";
|
||||||
|
recaptcha.dataset.controller = "smartCaptcha";
|
||||||
|
wrap.append(recaptcha);
|
||||||
|
|
||||||
|
var validRecaptcha = document.createElement('div');
|
||||||
|
validRecaptcha.classList = "msg-valid valid-captcha";
|
||||||
|
wrap.append(validRecaptcha);
|
||||||
|
|
||||||
|
return recaptcha;
|
||||||
|
}
|
||||||
|
|
||||||
|
function countDown(options) {
|
||||||
|
var timer,
|
||||||
|
instance = this,
|
||||||
|
seconds = options.seconds || 10,
|
||||||
|
updateStatus = options.onUpdateStatus || function () {},
|
||||||
|
counterEnd = options.onCounterEnd || function () {};
|
||||||
|
|
||||||
|
function decrementCounter() {
|
||||||
|
updateStatus(seconds);
|
||||||
|
|
||||||
|
if (seconds === 0) {
|
||||||
|
counterEnd();
|
||||||
|
instance.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
seconds--;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.start = function () {
|
||||||
|
clearInterval(timer);
|
||||||
|
timer = 0;
|
||||||
|
seconds = options.seconds;
|
||||||
|
timer = setInterval(decrementCounter, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.stop = function () {
|
||||||
|
clearInterval(timer);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getApiHostname() {
|
||||||
|
if (/sovamed\.ru/m.test(location.hostname)) {
|
||||||
|
return 'https://api.sovamed.ru';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'https://api.wmtmed.ru';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getHostname() {
|
||||||
|
if (/sovamed\.ru/m.test(location.hostname)) {
|
||||||
|
return 'https://cabinet.sovamed.ru';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'https://cabinet.wmtmed.ru';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRegionIdByHost() {
|
||||||
|
switch (location.host) {
|
||||||
|
case 'volgograd.sovamed.ru':
|
||||||
|
// Волгоград
|
||||||
|
var regionId = 92;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'voronezh.sovamed.ru':
|
||||||
|
// Воронеж
|
||||||
|
var regionId = 93;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'sovenok.sovamed.ru':
|
||||||
|
// Совенок
|
||||||
|
var regionId = 95;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'comfort.sovamed.ru':
|
||||||
|
// Совенок
|
||||||
|
var regionId = 96;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'wmtmed.ru':
|
||||||
|
// Краснодар
|
||||||
|
var regionId = 94;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Саратов
|
||||||
|
var regionId = 91;
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
return regionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SESSION_ID_PARAM = '_ct_session_id';
|
||||||
|
|
||||||
|
function readSessionIdCookie() {
|
||||||
|
if (typeof document === 'undefined') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const v = Cookies.get(SESSION_ID_PARAM);
|
||||||
|
if (v == null || String(v).trim() === '') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return String(v).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Если в query есть sessionId — пишет session-cookie (до закрытия браузера) и убирает параметр из URL.
|
||||||
|
*/
|
||||||
|
function syncSessionIdFromUrl() {
|
||||||
|
if (typeof window === 'undefined' || !window.location) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
const raw = url.searchParams.get(SESSION_ID_PARAM);
|
||||||
|
if (raw === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const value = String(raw).trim();
|
||||||
|
if (!value) {
|
||||||
|
url.searchParams.delete(SESSION_ID_PARAM);
|
||||||
|
const next = url.pathname + url.search + url.hash;
|
||||||
|
if (next !== window.location.pathname + window.location.search + window.location.hash) {
|
||||||
|
window.location.replace(next);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const secure = window.location.protocol === 'https:' ? '; Secure' : '';
|
||||||
|
document.cookie = `${SESSION_ID_PARAM}=${encodeURIComponent(value)}; path=/; SameSite=Lax${secure}`;
|
||||||
|
url.searchParams.delete(SESSION_ID_PARAM);
|
||||||
|
window.location.replace(url.pathname + url.search + url.hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addAlert(msg, alertSystem, id, color = 'alert-danger') {
|
||||||
|
var alert = document.createElement('div');
|
||||||
|
alert.id = id;
|
||||||
|
alert.classList = 'alert alert-dismissible fade show';
|
||||||
|
alert.classList.add(color);
|
||||||
|
alert.setAttribute('role', 'alert');
|
||||||
|
|
||||||
|
var divMsg = document.createElement('div');
|
||||||
|
divMsg.classList = 'alert-msg';
|
||||||
|
divMsg.innerHTML = msg;
|
||||||
|
alert.append(divMsg);
|
||||||
|
|
||||||
|
alertSystem.prepend(alert);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSessionId() {
|
||||||
|
const fromCt = window.ct?.('calltracking_params')?.[0]?.sessionId;
|
||||||
|
if (fromCt != null && String(fromCt).trim() !== '') {
|
||||||
|
return String(fromCt).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
const fromCookie = readSessionIdCookie();
|
||||||
|
if (fromCookie) {
|
||||||
|
return fromCookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addUrlParam(url, param, value) {
|
||||||
|
const urlObj = new URL(url);
|
||||||
|
|
||||||
|
if (!urlObj.searchParams.has(param)) {
|
||||||
|
urlObj.searchParams.set(param, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return urlObj.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
addUrlParam: addUrlParam,
|
||||||
|
getSessionId: getSessionId,
|
||||||
|
syncSessionIdFromUrl: syncSessionIdFromUrl,
|
||||||
|
addAlert: addAlert,
|
||||||
|
getRegionIdByHost: getRegionIdByHost,
|
||||||
|
getApiHostname : getApiHostname,
|
||||||
|
getHostname: getHostname,
|
||||||
|
countDown: countDown,
|
||||||
|
isMobile: isMobile,
|
||||||
|
sendRequest: sendRequest,
|
||||||
|
getLicensePersonLink: getLicensePersonLink,
|
||||||
|
getLicenseLink: getLicenseLink,
|
||||||
|
getCityCRM: getCityCRM,
|
||||||
|
getCityId: getCityId,
|
||||||
|
renderCapcha: renderCapcha
|
||||||
|
};
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
const helper = require("./helper.js");
|
||||||
|
|
||||||
|
function esia() {
|
||||||
|
if (document.location.search == '?esia=true') {
|
||||||
|
const hostName = helper.getHostname();
|
||||||
|
|
||||||
|
window.webSDK.on('init', function() {
|
||||||
|
|
||||||
|
if (!window.webSDK?.data?.user?.authenticated)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const user = window.webSDK?.data?.user;
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
method: "POST",
|
||||||
|
crossDomain: false,
|
||||||
|
url: "/api/authenticated",
|
||||||
|
contentType: "application/x-www-form-urlencoded",
|
||||||
|
dataType: "json",
|
||||||
|
data: {
|
||||||
|
user: user,
|
||||||
|
uid: user.id
|
||||||
|
},
|
||||||
|
xhrFields: {
|
||||||
|
withCredentials: true
|
||||||
|
},
|
||||||
|
success(response) {
|
||||||
|
if (response.data.success == true) {
|
||||||
|
const parser = document.createElement('a');
|
||||||
|
parser.href = response.data.redirect;
|
||||||
|
|
||||||
|
window.location.replace(document.location.origin + parser.pathname + parser.search);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function loadSDK(controller) {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
var script = document.getElementById('sdk-infoclinica');
|
||||||
|
|
||||||
|
if (script == null) {
|
||||||
|
var script = document.createElement('script');
|
||||||
|
|
||||||
|
if (/sovamed\.ru/m.test(location.hostname)) {
|
||||||
|
script.src = 'https://widget.sovamed.ru/assets/javascripts/sdk/sdk.build.min.js';
|
||||||
|
} else {
|
||||||
|
script.src = 'https://widget.wmtmed.ru/assets/javascripts/sdk/sdk.build.min.js';
|
||||||
|
}
|
||||||
|
|
||||||
|
script.id = "sdk-infoclinica";
|
||||||
|
document.head.appendChild(script);
|
||||||
|
|
||||||
|
script.addEventListener('load', function() {
|
||||||
|
console.log(controller + ' - load');
|
||||||
|
window.webSDK = new WrSDK();
|
||||||
|
esia();
|
||||||
|
resolve(window.webSDK);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
script.addEventListener('load', function() {
|
||||||
|
console.log(controller + ' - onload');
|
||||||
|
esia();
|
||||||
|
resolve(window.webSDK);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function btnLoader(btn, disabled = true) {
|
||||||
|
if (disabled) {
|
||||||
|
btn.dataset.name = btn.innerHTML;
|
||||||
|
btn.style.paddingRight = '5px';
|
||||||
|
btn.disabled = disabled;
|
||||||
|
btn.innerHTML = 'Загрузка <img width="20" src="'+ helper.getHostname() +'/images/eclipse.gif">';
|
||||||
|
} else {
|
||||||
|
btn.style.paddingRight = null;
|
||||||
|
btn.disabled = disabled;
|
||||||
|
btn.innerHTML = btn.dataset.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exporting loadSDK function
|
||||||
|
module.exports = {
|
||||||
|
loadSDK: loadSDK,
|
||||||
|
btnLoader: btnLoader
|
||||||
|
};
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
/**
|
||||||
|
* MIS (webSDK / widget.sovamed.ru) session helpers.
|
||||||
|
* Symfony login (ROLE_USER) and MIS session are independent.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function MisSessionError() {
|
||||||
|
this.name = 'MisSessionError';
|
||||||
|
this.message = 'MIS session is not authenticated';
|
||||||
|
}
|
||||||
|
|
||||||
|
function isAuthenticated(webSDK) {
|
||||||
|
return Boolean(webSDK?.data?.user?.authenticated);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureAuthenticated(webSDK) {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
if (isAuthenticated(webSDK)) {
|
||||||
|
resolve(webSDK);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof webSDK?.isLoggedIn === 'function') {
|
||||||
|
webSDK.isLoggedIn(webSDK.sdkOrigin).then(function(result) {
|
||||||
|
if (result?.authenticated) {
|
||||||
|
resolve(webSDK);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
reject(new MisSessionError());
|
||||||
|
}).catch(function() {
|
||||||
|
reject(new MisSessionError());
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reject(new MisSessionError());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeSdkOverlayModals() {
|
||||||
|
document.querySelectorAll('.wr-sdk-widget-modal').forEach(function(modal) {
|
||||||
|
modal.remove();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move #iframeProtocol from SDK overlay into cabinet bootstrap popup.
|
||||||
|
* openConference() must be called without container (SDK applies Guest URL fix).
|
||||||
|
*/
|
||||||
|
function mountConferenceInPopup(popup) {
|
||||||
|
var iframe = document.getElementById('iframeProtocol');
|
||||||
|
var popupBody = popup?.querySelector('#popup-body');
|
||||||
|
|
||||||
|
if (!iframe || !popupBody) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
removeSdkOverlayModals();
|
||||||
|
popupBody.innerHTML = '';
|
||||||
|
popupBody.appendChild(iframe);
|
||||||
|
iframe.style.width = '100%';
|
||||||
|
iframe.style.border = 'none';
|
||||||
|
iframe.style.height = (window.innerHeight - 100) + 'px';
|
||||||
|
|
||||||
|
var fullScreenBtn = popup.querySelector('.full-scren-modal');
|
||||||
|
if (fullScreenBtn) {
|
||||||
|
fullScreenBtn.classList.remove('d-none');
|
||||||
|
}
|
||||||
|
|
||||||
|
popup.querySelector('.modal-dialog').classList = 'modal-dialog';
|
||||||
|
popup.querySelector('.modal-content').classList = 'modal-content';
|
||||||
|
popup.querySelector('.modal-title').innerHTML = 'Онлайн консультация';
|
||||||
|
|
||||||
|
if (typeof $ !== 'undefined' && typeof $(popup).modal === 'function') {
|
||||||
|
$(popup).modal('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showMisSessionExpired(popup) {
|
||||||
|
if (!popup) {
|
||||||
|
window.location.pathname = '/logout';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
popup.querySelector('.modal-dialog').classList = 'modal-dialog';
|
||||||
|
popup.querySelector('.modal-title').innerHTML = 'Сессия виджета истекла';
|
||||||
|
popup.querySelector('#popup-body').innerHTML =
|
||||||
|
'<p class="mb-3">Личный кабинет открыт, но сессия виджета записи (MIS) истекла. ' +
|
||||||
|
'Для оплаты и онлайн-приёма нужно войти снова — повторная авторизация в iframe не требуется.</p>' +
|
||||||
|
'<button type="button" class="btn btn-outline-secondary w-100" id="mis-session-relogin">Войти снова</button>';
|
||||||
|
|
||||||
|
popup.querySelector('#mis-session-relogin').addEventListener('click', function() {
|
||||||
|
window.location.pathname = '/logout';
|
||||||
|
});
|
||||||
|
|
||||||
|
if (typeof $ !== 'undefined' && typeof $(popup).modal === 'function') {
|
||||||
|
$(popup).modal('show');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMisSessionFailure(popup, error, logContext) {
|
||||||
|
if (error instanceof MisSessionError || error?.name === 'MisSessionError') {
|
||||||
|
showMisSessionExpired(popup);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
MisSessionError: MisSessionError,
|
||||||
|
isAuthenticated: isAuthenticated,
|
||||||
|
ensureAuthenticated: ensureAuthenticated,
|
||||||
|
mountConferenceInPopup: mountConferenceInPopup,
|
||||||
|
showMisSessionExpired: showMisSessionExpired,
|
||||||
|
handleMisSessionFailure: handleMisSessionFailure,
|
||||||
|
};
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* Единая нормализация onlineMode для Stimulus/record.js.
|
||||||
|
* dataset и API могут отдавать true/false, "1"/"0", 1/0.
|
||||||
|
*/
|
||||||
|
function isOnlineMode(value) {
|
||||||
|
if (value === true || value === 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value === false || value === 0 || value === null || value === undefined) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalized = String(value).trim().toLowerCase();
|
||||||
|
|
||||||
|
if (normalized === '' || normalized === '0' || normalized === 'false' || normalized === 'no' || normalized === 'off') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normalized === '1' || normalized === 'true' || normalized === 'yes' || normalized === 'on') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toOnlineType(value) {
|
||||||
|
return isOnlineMode(value) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
isOnlineMode,
|
||||||
|
toOnlineType,
|
||||||
|
};
|
||||||
@@ -0,0 +1,209 @@
|
|||||||
|
function checkEmail(input, msg) {
|
||||||
|
if (window.validateEmail(input.value)) {
|
||||||
|
msg.innerHTML = '';
|
||||||
|
input.classList.remove('is-invalid');
|
||||||
|
input.classList.add('is-valid');
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
msg.innerHTML = '<span class="text-danger">поле является обязательным для заполнения</span>';
|
||||||
|
input.classList.remove('is-valid');
|
||||||
|
input.classList.add('is-invalid');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkPhone(input, msg) {
|
||||||
|
if (window.validatePhone(input.value)) {
|
||||||
|
msg.innerHTML = '';
|
||||||
|
input.classList.remove('is-invalid');
|
||||||
|
input.classList.add('is-valid');
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
msg.innerHTML = '<span class="text-danger">поле является обязательным для заполнения</span>';
|
||||||
|
input.classList.remove('is-valid');
|
||||||
|
input.classList.add('is-invalid');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkNotEmpty(input, msg) {
|
||||||
|
var valid = false;
|
||||||
|
|
||||||
|
if (input.value === '') {
|
||||||
|
msg.innerHTML = '<span class="text-danger">поле является обязательным для заполнения</span>';
|
||||||
|
input.classList.add('is-invalid');
|
||||||
|
input.classList.remove('is-valid');
|
||||||
|
valid = true;
|
||||||
|
} else {
|
||||||
|
msg.innerHTML = '';
|
||||||
|
input.classList.add('is-valid');
|
||||||
|
input.classList.remove('is-invalid');
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkTextRu(input, msg) {
|
||||||
|
var valid = false;
|
||||||
|
|
||||||
|
if (input.value === '') {
|
||||||
|
msg.innerHTML = '<span class="text-danger">поле является обязательным для заполнения</span>';
|
||||||
|
input.classList.add('is-invalid');
|
||||||
|
input.classList.remove('is-valid');
|
||||||
|
valid = true;
|
||||||
|
} else {
|
||||||
|
msg.innerHTML = '';
|
||||||
|
input.classList.add('is-valid');
|
||||||
|
input.classList.remove('is-invalid');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/[A-Za-z0-9]/.test(input.value)) {
|
||||||
|
msg.innerHTML = '<span class="text-danger">поле должно заполняться кириллицей</span>';
|
||||||
|
input.classList.add('is-invalid');
|
||||||
|
input.classList.remove('is-valid');
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkAccept(ckeckBox, msg) {
|
||||||
|
var valid = false;
|
||||||
|
|
||||||
|
if (ckeckBox.checked) {
|
||||||
|
msg.innerHTML = '';
|
||||||
|
ckeckBox.classList.add('is-valid');
|
||||||
|
ckeckBox.classList.remove('is-invalid');
|
||||||
|
} else {
|
||||||
|
msg.innerHTML = '<span class="text-danger">укажите согласие, на обработку персональных данных</span>';
|
||||||
|
ckeckBox.classList.add('is-invalid');
|
||||||
|
ckeckBox.classList.remove('is-valid');
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkDate(input, msg, range = false) {
|
||||||
|
var valid = false;
|
||||||
|
|
||||||
|
if (range) {
|
||||||
|
if (/^(0[1-9]|[12][0-9]|3[01])\.(0[1-9]|1[0-2])\.\d{4}.\-.(0[1-9]|[12][0-9]|3[01])\.(0[1-9]|1[0-2])\.\d{4}$/.test(input.value)) {
|
||||||
|
msg.innerHTML = '';
|
||||||
|
input.classList.add('is-valid');
|
||||||
|
input.classList.remove('is-invalid');
|
||||||
|
} else {
|
||||||
|
msg.innerHTML = '<span class="text-danger">поле является обязательным для заполнения</span>';
|
||||||
|
input.classList.add('is-invalid');
|
||||||
|
input.classList.remove('is-valid');
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (/^(0[1-9]|[12][0-9]|3[01])\.(0[1-9]|1[0-2])\.\d{4}$/.test(input.value)) {
|
||||||
|
msg.innerHTML = '';
|
||||||
|
input.classList.add('is-valid');
|
||||||
|
input.classList.remove('is-invalid');
|
||||||
|
} else {
|
||||||
|
msg.innerHTML = '<span class="text-danger">поле является обязательным для заполнения</span>';
|
||||||
|
input.classList.add('is-invalid');
|
||||||
|
input.classList.remove('is-valid');
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkInt(input, msg) {
|
||||||
|
var valid = false;
|
||||||
|
|
||||||
|
if (/^\d+$/.test(input.value)) {
|
||||||
|
msg.innerHTML = '';
|
||||||
|
input.classList.add('is-valid');
|
||||||
|
input.classList.remove('is-invalid');
|
||||||
|
} else {
|
||||||
|
msg.innerHTML = '<span class="text-danger">поле является обязательным для заполнения</span>';
|
||||||
|
input.classList.add('is-invalid');
|
||||||
|
input.classList.remove('is-valid');
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkInn(input, msg) {
|
||||||
|
var valid = false;
|
||||||
|
|
||||||
|
if (input.value === '') {
|
||||||
|
msg.innerHTML = '<span class="text-danger">поле является обязательным для заполнения</span>';
|
||||||
|
input.classList.add('is-invalid');
|
||||||
|
input.classList.remove('is-valid');
|
||||||
|
valid = true;
|
||||||
|
} else {
|
||||||
|
if (is_valid_inn(input.value)) {
|
||||||
|
msg.innerHTML = '';
|
||||||
|
input.classList.add('is-valid');
|
||||||
|
input.classList.remove('is-invalid');
|
||||||
|
} else {
|
||||||
|
msg.innerHTML = '<span class="text-danger">проверьте правильность введённых данных</span>';
|
||||||
|
input.classList.add('is-invalid');
|
||||||
|
input.classList.remove('is-valid');
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_valid_inn(i) {
|
||||||
|
if ( i.match(/\D/) ) return false;
|
||||||
|
|
||||||
|
var inn = i.match(/(\d)/g);
|
||||||
|
|
||||||
|
if ( inn.length == 10 )
|
||||||
|
{
|
||||||
|
return inn[9] == String(((
|
||||||
|
2*inn[0] + 4*inn[1] + 10*inn[2] +
|
||||||
|
3*inn[3] + 5*inn[4] + 9*inn[5] +
|
||||||
|
4*inn[6] + 6*inn[7] + 8*inn[8]
|
||||||
|
) % 11) % 10);
|
||||||
|
}
|
||||||
|
else if ( inn.length == 12 )
|
||||||
|
{
|
||||||
|
return inn[10] == String(((
|
||||||
|
7*inn[0] + 2*inn[1] + 4*inn[2] +
|
||||||
|
10*inn[3] + 3*inn[4] + 5*inn[5] +
|
||||||
|
9*inn[6] + 4*inn[7] + 6*inn[8] +
|
||||||
|
8*inn[9]
|
||||||
|
) % 11) % 10) && inn[11] == String(((
|
||||||
|
3*inn[0] + 7*inn[1] + 2*inn[2] +
|
||||||
|
4*inn[3] + 10*inn[4] + 3*inn[5] +
|
||||||
|
5*inn[6] + 9*inn[7] + 4*inn[8] +
|
||||||
|
6*inn[9] + 8*inn[10]
|
||||||
|
) % 11) % 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkSmartCaptcha(token, msg) {
|
||||||
|
if (token === '') {
|
||||||
|
msg.innerHTML = '<span class="text-danger">Подтвердите, что Вы не робот</span>';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.innerHTML = '';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
checkInt: checkInt,
|
||||||
|
checkNotEmpty: checkNotEmpty,
|
||||||
|
checkDate: checkDate,
|
||||||
|
checkInn: checkInn,
|
||||||
|
checkAccept: checkAccept,
|
||||||
|
checkSmartCaptcha: checkSmartCaptcha,
|
||||||
|
checkTextRu: checkTextRu,
|
||||||
|
checkEmail: checkEmail,
|
||||||
|
checkPhone: checkPhone
|
||||||
|
};
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"controllers": [],
|
||||||
|
"entrypoints": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
const loader = require("./../components/loader.js");
|
||||||
|
const helper = require("./../components/helper.js");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="default" attribute will cause
|
||||||
|
* this controller to be executed. The name "default" comes from the filename:
|
||||||
|
* default_controller.js -> "default"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
const alertSystem = this.element;
|
||||||
|
|
||||||
|
loader.loadSDK('system').then(function(webSDK) {
|
||||||
|
webSDK.on('init', function() {
|
||||||
|
runWebSDK(alertSystem, webSDK);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
if (location.pathname.indexOf('/case-history') != '-1') {
|
||||||
|
if (location.hash == '#error') {
|
||||||
|
var msg = 'Что то пошло не так, повторите попытку позже.';
|
||||||
|
helper.addAlert(msg, alertSystem, 'alert-case-history-error');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (location.hash == '#online') {
|
||||||
|
var msg = 'При отсутствии оплаты в течение 5 мин. онлайн консультация будет автоматически отменена';
|
||||||
|
|
||||||
|
helper.addAlert(msg, alertSystem, 'alert-case-history-online');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (location.hash == '#pay-success') {
|
||||||
|
var msg = 'Спасибо, оплата прошла успешно.';
|
||||||
|
|
||||||
|
helper.addAlert(msg, alertSystem, 'alert-case-history-info', 'alert-success');
|
||||||
|
}
|
||||||
|
if (location.hash == '#doctor-success') {
|
||||||
|
var msg = 'Спасибо, вы успешно записались на прием.';
|
||||||
|
|
||||||
|
helper.addAlert(msg, alertSystem, 'alert-case-history-info', 'alert-success');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.location.href.includes("sovamed")) {
|
||||||
|
|
||||||
|
const osa = `Онлайн консультация проводится через личный кабинет, никаких приложений устанавливать не нужно. Рекомендуем изучить <a href="/docs/online.pdf">инструкцию по онлайн консультированию</a> или <a href="/docs/onlinegos.pdf">инструкцию по онлайн консультированию через Госуслуги</a><br>
|
||||||
|
Возврат средств при несостоявшейся консультации производится в разделе приемы – история записей. <a href="/docs/vozvrat.pdf">Инструкция по возврату средств</a>`;
|
||||||
|
|
||||||
|
if (window.location.href.includes("onlineMode")) {
|
||||||
|
if (alertSystem.dataset.auth === "false") {
|
||||||
|
const onlineSpecialstAlert = `Для онлайн-консультации рекомендуем пройти авторизацию через <a href="/login">Госуслуги</a>.</br>
|
||||||
|
Если Вы уже были в клинике и у Вас есть логин и пароль, при авторизации Вы можете использовать его.
|
||||||
|
Ознакомиться с инструкцией по онлайн-консультированию вы можете, пройдя по <a href="/docs/online.pdf">ссылке</a>.
|
||||||
|
`;
|
||||||
|
|
||||||
|
helper.addAlert(onlineSpecialstAlert, alertSystem, 'alert-online-mode', 'alert-info');
|
||||||
|
} else {
|
||||||
|
helper.addAlert(osa, alertSystem, 'alert-online-mode', 'alert-info');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.location.href.includes("/online-specialists")) {
|
||||||
|
helper.addAlert(osa, alertSystem, 'alert-online-mode', 'alert-info');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alertSystem.dataset.auth === "false") {
|
||||||
|
if (location.pathname.indexOf('/info') != '-1') {
|
||||||
|
var msg = 'Если Вы хотите, чтобы справка была направлена сразу в ФНС, в Ваш кабинет налогоплательщика, то авторизуйтесь через имеющийся логин/пароль или с помощью Госуслуг и заполните данные пациента.';
|
||||||
|
|
||||||
|
helper.addAlert(msg, alertSystem, 'alert-info');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (location.pathname.indexOf('/specialist') != '-1' & !window.location.href.includes("onlineMode")) {
|
||||||
|
var msg = '* вы можете записать себя или другого человека без авторизации, но при этом запись не сохранится в личном кабинете и отменить/перенести ее в случае необходимости будет возможно только по звонку в колл-центр.';
|
||||||
|
|
||||||
|
helper.addAlert(msg, alertSystem, 'alert-not-auth');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let runWebSDK = function (alertSystem, webSDK) {
|
||||||
|
if (alertSystem.dataset.techMaintenance === 'true') {
|
||||||
|
var msg = 'Ведутся технические работы, функционал может быть доступен не полностью';
|
||||||
|
helper.addAlert(msg, alertSystem, 'alert-warning');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (webSDK.data.user.authenticated) {
|
||||||
|
const userAllows = webSDK.data.user.allows;
|
||||||
|
|
||||||
|
if (userAllows.caseHistory == false || userAllows.payments == false || userAllows.reservation == false) {
|
||||||
|
|
||||||
|
var msg = 'Ваша учетная запись имеет статус "Неподтвержденная регистрация", запись на прием через портал работает в ограниченном режиме. Вы можете записаться на прием не более одного раза к одному специалисту. Полный доступ на портал Вам будет предоставлен в регистратуре при следующем посещении клиники.';
|
||||||
|
|
||||||
|
helper.addAlert(msg, alertSystem, 'alert-info');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
import Cookies from 'js-cookie';
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="default" attribute will cause
|
||||||
|
* this controller to be executed. The name "default" comes from the filename:
|
||||||
|
* default_controller.js -> "default"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
var bannerWrap = this.element;
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
dataType: "json",
|
||||||
|
method: 'GET',
|
||||||
|
url: '/api/banner/' + Cookies.get('region'),
|
||||||
|
success(response) {
|
||||||
|
if (response.active == true) {
|
||||||
|
var a = document.createElement('a');
|
||||||
|
a.href = response.href;
|
||||||
|
a.target = "_blank";
|
||||||
|
a.innerHTML = '<img src="/banners/' + response.src + '" alt="баннер">'
|
||||||
|
bannerWrap.append(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="calendar" attribute will cause
|
||||||
|
* this controller to be executed. The name "hello" comes from the filename:
|
||||||
|
* calendar_controller.js -> "calendar"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
var modal = document.getElementById('detail-specialist');
|
||||||
|
|
||||||
|
this.element.addEventListener('click', function (evn) {
|
||||||
|
modal.dataset.specialistid = evn.target.dataset.specialistid;
|
||||||
|
modal.dataset.filialid = evn.target.dataset.filialid;
|
||||||
|
modal.dataset.onlinemode = evn.target.dataset.onlinemode;
|
||||||
|
modal.dataset.docname = (evn.target.dataset.docName ?? evn.target.dataset.docname ?? '').toString();
|
||||||
|
modal.dataset.address = (evn.target.dataset.address ?? '').toString();
|
||||||
|
modal.dataset.comment = (evn.target.dataset.comment ?? '').toString();
|
||||||
|
|
||||||
|
$(modal).modal('show');
|
||||||
|
})
|
||||||
|
// this.element.textContent = 'Hello Stimulus! Edit me in assets/controllers/hello_controller.js';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,451 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
import Cookies from 'js-cookie';
|
||||||
|
const loader = require("./../components/loader.js");
|
||||||
|
const helper = require("./../components/helper.js");
|
||||||
|
const misSession = require("./../components/misSession.js");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="caseHistory" attribute will cause
|
||||||
|
* this controller to be executed. The name "caseHistory" comes from the filename:
|
||||||
|
* caseHistory_controller.js -> "caseHistory"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
async cashBack(evn) {
|
||||||
|
loader.btnLoader(evn.target, true)
|
||||||
|
|
||||||
|
var popup = document.getElementById('popup');
|
||||||
|
popup.querySelector('.modal-title').innerHTML = 'Возврат средств';
|
||||||
|
popup.querySelector('.modal-dialog').classList = 'modal-dialog modal-md';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/refund?filial=' + evn.target.dataset.filial);
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
const text = await response.text();
|
||||||
|
|
||||||
|
popup.querySelector('.modal-body').innerHTML = text;
|
||||||
|
loader.btnLoader(evn.target, false);
|
||||||
|
$(popup).modal('show');
|
||||||
|
|
||||||
|
popup.querySelector('#refund_address').value = window.webSDK.data.user.address;
|
||||||
|
popup.querySelector('#refund_phone').value = window.webSDK.data.user.phone;
|
||||||
|
popup.querySelector('#refund_email').value = window.webSDK.data.user.email;
|
||||||
|
popup.querySelector('#refund_schedident').value = evn.target.dataset.schedident;
|
||||||
|
popup.querySelector('#refund_time').value = evn.target.dataset.time;
|
||||||
|
popup.querySelector('#refund_doc_name').value = evn.target.dataset.docName;
|
||||||
|
|
||||||
|
document.getElementById('refund-form').querySelector('button').addEventListener('click', function() {
|
||||||
|
if ($('#refund-form')[0].checkValidity()) {
|
||||||
|
$(popup).modal('hide');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error);
|
||||||
|
loader.btnLoader(evn.target, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
loader.loadSDK('caseHistory').then(function(webSDK) {
|
||||||
|
webSDK.on('init', function() {
|
||||||
|
if (this.data.user.authenticated) {
|
||||||
|
runWebSDK(webSDK);
|
||||||
|
} else {
|
||||||
|
window.location.pathname = '/logout'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
var securityRecord = this.element;
|
||||||
|
var popup = document.getElementById('popup');
|
||||||
|
|
||||||
|
let runWebSDK = function (webSDK) {
|
||||||
|
scheduleRecordList(webSDK, securityRecord);
|
||||||
|
}
|
||||||
|
|
||||||
|
var securityTabs = document.getElementById('security-tabs');
|
||||||
|
var tabsDecktop = securityTabs.querySelectorAll('a');
|
||||||
|
var alertInfo = document.getElementById('alert-case-history-info');
|
||||||
|
|
||||||
|
if (tabsDecktop.length > 0) {
|
||||||
|
tabsDecktop.forEach(function (el) {
|
||||||
|
el.addEventListener('click', function (evn) {
|
||||||
|
evn.target.classList = 'tab-item tab-item--active';
|
||||||
|
|
||||||
|
if (evn.target.dataset.alert === 'true') alertInfo.classList.remove('d-none');
|
||||||
|
|
||||||
|
securityTabs.querySelectorAll('a').forEach(function (a) {
|
||||||
|
if (evn.target.dataset.allowRemove != a.dataset.allowRemove) {
|
||||||
|
a.classList.remove('tab-item--active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var history = (evn.target.dataset.allowRemove == 'true');
|
||||||
|
filter(history, securityRecord);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
securityTabs.addEventListener('change', function(evn) {
|
||||||
|
if (evn.target.alert === 'true') alertInfo.classList.remove('d-none');
|
||||||
|
|
||||||
|
var history = (evn.target.value == 'true');
|
||||||
|
filter(history, securityRecord);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function filter(history, securityRecord) {
|
||||||
|
var items = securityRecord.querySelectorAll('.item-record');
|
||||||
|
if (items) {
|
||||||
|
var count = 0;
|
||||||
|
items.forEach(function (item) {
|
||||||
|
if (history == true) {
|
||||||
|
item.classList.add('d-none');
|
||||||
|
if (item.dataset.workDate >= window.dateFormat(new Date())) {
|
||||||
|
item.classList.remove('d-none');
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
item.classList.add('d-none');
|
||||||
|
|
||||||
|
if (item.dataset.workDate < window.dateFormat(new Date())) {
|
||||||
|
if (item.dataset.onlinemode == '1') {
|
||||||
|
item.querySelector('.btn-conference').classList.remove('d-inline');
|
||||||
|
item.querySelector('.btn-conference').classList.add('d-none');
|
||||||
|
item.querySelector('.online-warning').classList.remove('d-none');
|
||||||
|
console.log(item.querySelector('.online-warning'));
|
||||||
|
|
||||||
|
var refundBtn = item.querySelector('.btn-cash-back')
|
||||||
|
refundBtn.classList.add('d-inline');
|
||||||
|
refundBtn.dataset.schedident = item.dataset.schedident
|
||||||
|
refundBtn.dataset.filial = item.dataset.filial
|
||||||
|
refundBtn.dataset.time = item.dataset.time
|
||||||
|
refundBtn.dataset.docName = item.dataset.docName
|
||||||
|
}
|
||||||
|
|
||||||
|
item.classList.remove('d-none');
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notItems(count);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function notItems(count) {
|
||||||
|
var load = securityRecord.querySelector('.load');
|
||||||
|
load.classList.add('d-none');
|
||||||
|
|
||||||
|
if (count == 0) {
|
||||||
|
load.innerHTML = 'Записей не найдено';
|
||||||
|
load.classList.remove('d-none');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var renderItems = function(items, securityWrap) {
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
items.forEach(function(data, i) {
|
||||||
|
var blockItem = securityRecord.querySelector('.item-record').cloneNode(true);
|
||||||
|
blockItem.dataset.workDate = data.workDate;
|
||||||
|
blockItem.dataset.onlinemode = data.onlineType ?? 0;
|
||||||
|
blockItem.dataset.docName = data.docName;
|
||||||
|
blockItem.dataset.time = data.startTime+ ' '+ data.endTime;
|
||||||
|
blockItem.dataset.schedident = data.schedident;
|
||||||
|
blockItem.dataset.filial = data.filial;
|
||||||
|
blockItem.dataset.dcode = data.dcode;
|
||||||
|
|
||||||
|
if (blockItem.dataset.dcode) {
|
||||||
|
helper.sendRequest({
|
||||||
|
'sid': blockItem.dataset.dcode,
|
||||||
|
'onlineMode': blockItem.dataset.onlineType ?? 0
|
||||||
|
}, "/api/doctor", "GET").then(function (response) {
|
||||||
|
if (response.data) {
|
||||||
|
blockItem.querySelector('.img-vr').style.background = 'url(' + response.data.img + ') center -5px / cover';
|
||||||
|
blockItem.querySelector('.position').innerHTML = response.data.speciality;
|
||||||
|
|
||||||
|
if (response.data.kinder != null) {
|
||||||
|
var kinder = blockItem.querySelector('.kinder');
|
||||||
|
kinder.classList.remove('d-none');
|
||||||
|
kinder.querySelector('.val').innerHTML = response.data.kinder;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.data.expirience != null) {
|
||||||
|
var kinder = blockItem.querySelector('.expirience');
|
||||||
|
kinder.classList.remove('d-none');
|
||||||
|
kinder.querySelector('.val').innerHTML = response.data.expirience;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockItem.querySelectorAll('.link-specialist').forEach(function (el) {
|
||||||
|
el.href = '/specialist/' + response.data.alias;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
blockItem.querySelector('.img-vr').style.background = 'url(/images/no_img.png) center -5px / cover';
|
||||||
|
blockItem.querySelector('.position').innerHTML = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var date = window.newDate(data.workDate);
|
||||||
|
|
||||||
|
if (Cookies.get('region') == 91) {
|
||||||
|
var timeZona = '<br>время саратовское';
|
||||||
|
} else {
|
||||||
|
var timeZona = '<br>время московское';
|
||||||
|
}
|
||||||
|
|
||||||
|
blockItem.querySelector('.month').innerHTML = getWeekDay(date);
|
||||||
|
blockItem.querySelector('.date').innerHTML = window.dateFormat(date, 'd-m-Y') + ' '
|
||||||
|
+ data.startTime + timeZona;
|
||||||
|
blockItem.querySelector('.address').innerHTML = (data.filialName == 'Онлайн клиника') ? 'Онлайн-консультация' : data.filialName;
|
||||||
|
blockItem.querySelector('.section-favorite').dataset.sid = data.dcode;
|
||||||
|
blockItem.querySelector('.specialist').innerHTML = data.docName;
|
||||||
|
|
||||||
|
var btnClose = blockItem.querySelector('.btn-close');
|
||||||
|
btnClose.classList.add('d-none');
|
||||||
|
|
||||||
|
if (data.allowRemove) {
|
||||||
|
btnClose.classList.remove('d-none');
|
||||||
|
btnClose.dataset.id = data.id;
|
||||||
|
btnClose.dataset.filial = data.filial;
|
||||||
|
btnClose.addEventListener('click', function () {
|
||||||
|
if (confirm("Подтвердите удаление")) {
|
||||||
|
webSDK.scheduleRecRemove({
|
||||||
|
'reserveId': btnClose.dataset.id,
|
||||||
|
'filialId': btnClose.dataset.filial
|
||||||
|
}).then(function (resolve) {
|
||||||
|
document.location.reload();
|
||||||
|
}).catch(function (error) {
|
||||||
|
helper.sendRequest({
|
||||||
|
data: {'error': error, method: 'scheduleRecRemove'}
|
||||||
|
}, helper.getHostname() + '/api/log', "POST", "json", true, "application/json");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var btnConfirence = blockItem.querySelector('.btn-conference');
|
||||||
|
var accept = blockItem.querySelector('.accept');
|
||||||
|
var licenseLink = helper.getLicenseLink(Cookies.get('region'));
|
||||||
|
var license = document.createElement('p');
|
||||||
|
|
||||||
|
if (data.onlineType && data?.payment?.status?.id != 0) {
|
||||||
|
license.innerHTML = `Пожалуйста, не забудете за 5 минут до начала консультации войти в личный кабинет и потом нажать кнопку «Онлайн прием» для начала консультации.`;
|
||||||
|
accept.append(license);
|
||||||
|
|
||||||
|
var warning = document.createElement('p');
|
||||||
|
warning.innerHTML=`<b>Внимание!</b> В начале онлайн-консультации вам будет необходимо подтвердить своё согласие с информированным добровольным согласием на медицинское вмешательство (ИДС).`;
|
||||||
|
accept.append(warning);
|
||||||
|
|
||||||
|
btnConfirence.classList.remove('d-none')
|
||||||
|
btnConfirence.classList.add('d-inline')
|
||||||
|
btnConfirence.setAttribute('data-id' , data.id)
|
||||||
|
btnConfirence.setAttribute('data-filial' , data.filial)
|
||||||
|
btnConfirence.addEventListener('click', function () {
|
||||||
|
popup.querySelector('#popup-body').innerHTML = '';
|
||||||
|
|
||||||
|
misSession.ensureAuthenticated(webSDK).then(function() {
|
||||||
|
return webSDK.openConference({
|
||||||
|
schedid: btnConfirence.dataset.id
|
||||||
|
});
|
||||||
|
}).then(function () {
|
||||||
|
if (!misSession.mountConferenceInPopup(popup)) {
|
||||||
|
throw { data: { message: 'Не удалось открыть окно онлайн-консультации.' } };
|
||||||
|
}
|
||||||
|
}).catch(function (e) {
|
||||||
|
if (misSession.handleMisSessionFailure(popup, e)) {
|
||||||
|
helper.sendRequest({
|
||||||
|
data: {'error': e, method: 'openConference', reason: 'mis_session_expired'}
|
||||||
|
}, helper.getHostname() + '/api/log', "POST", "json", true, "application/json");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof e.data?.message !== 'undefined') {
|
||||||
|
var msg = e.data.message.replace('UTC+3', 'UTC+3 (московское время)');
|
||||||
|
popup.querySelector('#popup-body').innerHTML = msg;
|
||||||
|
popup.querySelector('.modal-dialog').classList = 'modal-dialog';
|
||||||
|
popup.querySelector('.modal-content').classList = 'modal-content';
|
||||||
|
popup.querySelector('.modal-title').innerHTML = 'Уведомление';
|
||||||
|
$(popup).modal('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.sendRequest({
|
||||||
|
data: {'error': e, method: 'openConference'}
|
||||||
|
}, helper.getHostname() + '/api/log', "POST", "json", true, "application/json");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
btnConfirence.classList.add('d-none')
|
||||||
|
}
|
||||||
|
|
||||||
|
var btnPayment = blockItem.querySelector('.btn-pay');
|
||||||
|
|
||||||
|
if (data.payment && data.payment.status.id == 0 && data.allowRemove) {
|
||||||
|
license.innerHTML = `Для получения возможности провести оплату консультации - подтвердите согласие на присоединение к договору оферты:`;
|
||||||
|
accept.append(license);
|
||||||
|
blockItem.querySelector('.online-warning').classList.remove('d-none');
|
||||||
|
console.log(blockItem.querySelector('.online-warning'));
|
||||||
|
|
||||||
|
var politics = document.createElement('div');
|
||||||
|
politics.classList = "form-check";
|
||||||
|
|
||||||
|
var politicsInput = document.createElement('input');
|
||||||
|
politicsInput.type="checkbox";
|
||||||
|
politicsInput.classList="form-check-input";
|
||||||
|
politicsInput.id="accept-btn";
|
||||||
|
politics.append(politicsInput);
|
||||||
|
|
||||||
|
var politicsLabel = document.createElement('label');
|
||||||
|
politicsLabel.classList = "form-check-label";
|
||||||
|
politicsLabel.htmlFor="accept-btn";
|
||||||
|
politics.append(politicsLabel);
|
||||||
|
|
||||||
|
politicsLabel.innerHTML = `Согласен с <a href="${licenseLink}" target="_blank">политикой в отношении обработки персональных данных</a>`;
|
||||||
|
politics.addEventListener('click', function () {
|
||||||
|
console.log('politics', politicsInput.checked, personalInput.checked, ofertaInput.checked);
|
||||||
|
btnPayment.classList.add('disabled');
|
||||||
|
btnPayment.disabled = true;
|
||||||
|
|
||||||
|
if (politicsInput.checked && personalInput.checked && ofertaInput.checked) {
|
||||||
|
btnPayment.classList.remove('disabled');
|
||||||
|
btnPayment.disabled = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
accept.append(politics);
|
||||||
|
|
||||||
|
var personal = document.createElement('div');
|
||||||
|
personal.classList = "form-check";
|
||||||
|
|
||||||
|
var personalInput = document.createElement('input');
|
||||||
|
personalInput.type="checkbox";
|
||||||
|
personalInput.classList="form-check-input";
|
||||||
|
personalInput.id="accept-personal";
|
||||||
|
personal.append(personalInput);
|
||||||
|
|
||||||
|
var personalLabel = document.createElement('label');
|
||||||
|
personalLabel.classList = "form-check-label";
|
||||||
|
personalLabel.htmlFor="accept-personal";
|
||||||
|
personal.append(personalLabel);
|
||||||
|
|
||||||
|
personalLabel.innerHTML = `Согласен с <a href="${licenseLink}" target="_blank">обработкой персональных данных</a>.`;
|
||||||
|
personal.addEventListener('click', function () {
|
||||||
|
btnPayment.classList.add('disabled');
|
||||||
|
btnPayment.disabled = true;
|
||||||
|
|
||||||
|
if (politicsInput.checked && personalInput.checked && ofertaInput.checked) {
|
||||||
|
btnPayment.classList.remove('disabled');
|
||||||
|
btnPayment.disabled = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
accept.append(personal);
|
||||||
|
|
||||||
|
var oferta = document.createElement('div');
|
||||||
|
oferta.classList = "form-check";
|
||||||
|
|
||||||
|
var ofertaInput = document.createElement('input');
|
||||||
|
ofertaInput.type="checkbox";
|
||||||
|
ofertaInput.classList="form-check-input";
|
||||||
|
ofertaInput.id="accept-oferta";
|
||||||
|
oferta.append(ofertaInput);
|
||||||
|
|
||||||
|
var ofertaLabel = document.createElement('label');
|
||||||
|
ofertaLabel.classList = "form-check-label";
|
||||||
|
ofertaLabel.htmlFor="accept-oferta";
|
||||||
|
oferta.append(ofertaLabel);
|
||||||
|
|
||||||
|
ofertaLabel.innerHTML = `Присоединяюсь к договору <a href="/docs/oferta.pdf" target="_blank">оферты</a>`;
|
||||||
|
oferta.addEventListener('click', function () {
|
||||||
|
btnPayment.classList.add('disabled');
|
||||||
|
btnPayment.disabled = true;
|
||||||
|
|
||||||
|
if (politicsInput.checked && personalInput.checked && ofertaInput.checked) {
|
||||||
|
btnPayment.classList.remove('disabled');
|
||||||
|
btnPayment.disabled = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
accept.append(oferta);
|
||||||
|
|
||||||
|
btnPayment.classList.remove('d-none');
|
||||||
|
btnPayment.classList.add('d-inline');
|
||||||
|
btnPayment.querySelector('.amt').innerHTML = data.payment.amt;
|
||||||
|
btnPayment.setAttribute('data-id' , data.payment.id);
|
||||||
|
btnPayment.setAttribute('data-filial' , data.filial);
|
||||||
|
btnPayment.setAttribute('data-amt' , data.payment.amt);
|
||||||
|
btnPayment.setAttribute('data-payprofileid' , data.payment.magazineId);
|
||||||
|
btnPayment.addEventListener('click', function () {
|
||||||
|
var params = {
|
||||||
|
'orderid': Number(btnPayment.dataset.id) ,
|
||||||
|
'payprofileid': btnPayment.dataset.payprofileid,
|
||||||
|
'payamount': btnPayment.dataset.amt,
|
||||||
|
'paymethod': 'AC',
|
||||||
|
'filial': Number(btnPayment.dataset.filial),
|
||||||
|
'pcode': webSDK.data.user.id,
|
||||||
|
'successurl': document.location.origin + '/case-history#pay-success',
|
||||||
|
'errorurl': document.location.origin + '/case-history#error',
|
||||||
|
'containerId': 'popup-body',
|
||||||
|
};
|
||||||
|
|
||||||
|
misSession.ensureAuthenticated(webSDK).then(function() {
|
||||||
|
webSDK.loadPaymentView(params);
|
||||||
|
popup.querySelector('#popup-body').innerHTML = '';
|
||||||
|
popup.querySelector('.modal-title').innerHTML = 'Оплата';
|
||||||
|
$(popup).modal('show');
|
||||||
|
}).catch(function(e) {
|
||||||
|
if (misSession.handleMisSessionFailure(popup, e)) {
|
||||||
|
helper.sendRequest({
|
||||||
|
data: {'error': e, method: 'loadPaymentView', reason: 'mis_session_expired'}
|
||||||
|
}, helper.getHostname() + '/api/log', "POST", "json", true, "application/json");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.sendRequest({
|
||||||
|
data: {'error': e, method: 'loadPaymentView'}
|
||||||
|
}, helper.getHostname() + '/api/log', "POST", "json", true, "application/json");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
btnPayment.classList.add('d-none');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.workDate >= window.dateFormat(new Date())) {
|
||||||
|
blockItem.classList.remove('d-none');
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
securityWrap.append(blockItem);
|
||||||
|
});
|
||||||
|
|
||||||
|
notItems(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleRecordList(webSDK, securityRecord) {
|
||||||
|
// Если страница загружена после создания записи, добавляем небольшую задержку
|
||||||
|
// чтобы дать серверу время обработать новую запись
|
||||||
|
var delay = (location.hash === '#doctor-success' || location.hash === '#online') ? 500 : 0;
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
webSDK.loadScheduleRecList({
|
||||||
|
st: 20170101,
|
||||||
|
en: window.dateFormat(new Date((new Date()).getFullYear(), (new Date()).getMonth() + 6, 0)),
|
||||||
|
start: 0,
|
||||||
|
length: 500
|
||||||
|
}).then(function (resolve) {
|
||||||
|
renderItems(resolve.data, securityRecord.querySelector('.section-wrap'));
|
||||||
|
}).catch(function(e) {
|
||||||
|
helper.sendRequest({
|
||||||
|
data: {'error': e, method: 'loadScheduleRecList'}
|
||||||
|
}, helper.getHostname() + '/api/log', "POST", "json", true, "application/json");
|
||||||
|
securityRecord.querySelector('.load').innerHTML = 'Записей не найдено';
|
||||||
|
});
|
||||||
|
}, delay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
const loader = require("./../components/loader.js");
|
||||||
|
const helper = require("./../components/helper.js");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="default" attribute will cause
|
||||||
|
* this controller to be executed. The name "default" comes from the filename:
|
||||||
|
* default_controller.js -> "default"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
loader.loadSDK('system').then(function(webSDK) {
|
||||||
|
webSDK.on('init', function() {
|
||||||
|
if (this.data.user.authenticated) {
|
||||||
|
runWebSDK(webSDK);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
let runWebSDK = function (webSDK) {
|
||||||
|
this.showNamePatient(webSDK.data.user.fullName);
|
||||||
|
this.element.addEventListener('click', function () {
|
||||||
|
this.changeResponsible(webSDK);
|
||||||
|
}.bind(this))
|
||||||
|
}.bind(this)
|
||||||
|
|
||||||
|
$(popup).on('hidden.bs.modal', function () {
|
||||||
|
this.querySelector('.modal-title').innerHTML = '';
|
||||||
|
this.querySelector('.modal-dialog').classList.add('modal-lg');
|
||||||
|
this.querySelector('.modal-body').innerHTML = '';
|
||||||
|
|
||||||
|
if (this.querySelector('.modal-footer')) {
|
||||||
|
this.querySelector('.modal-footer').remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
showNamePatient(fullName) {
|
||||||
|
document.getElementById('fullName').innerHTML = fullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
changeResponsible(webSDK) {
|
||||||
|
var popup = document.getElementById('popup');
|
||||||
|
popup.querySelector('.modal-title').innerHTML = 'Выбор пациента';
|
||||||
|
popup.querySelector('.modal-dialog').classList.remove('modal-lg');
|
||||||
|
|
||||||
|
var popupBody = document.getElementById('popup-body');
|
||||||
|
popupBody.innerHTML = '';
|
||||||
|
|
||||||
|
webSDK.data.user.represents.forEach(function (represent) {
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.classList = 'form-check';
|
||||||
|
|
||||||
|
var input = document.createElement('input');
|
||||||
|
input.id = represent.pcode;
|
||||||
|
input.classList = 'form-check-input';
|
||||||
|
input.value = represent.pcode;
|
||||||
|
input.type = "radio";
|
||||||
|
input.name = "changePatient";
|
||||||
|
|
||||||
|
if (webSDK.data.user.representId == represent.pcode) {
|
||||||
|
input.checked = 'true';
|
||||||
|
}
|
||||||
|
|
||||||
|
div.append(input);
|
||||||
|
|
||||||
|
var label = document.createElement('label');
|
||||||
|
label.setAttribute('for', represent.pcode);
|
||||||
|
label.classList = 'form-check-label';
|
||||||
|
label.innerHTML = represent.fullName;
|
||||||
|
div.append(label);
|
||||||
|
|
||||||
|
popupBody.append(div);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.classList = 'modal-footer';
|
||||||
|
|
||||||
|
var button = document.createElement('button');
|
||||||
|
button.classList = 'btn btn-outline-secondary';
|
||||||
|
button.innerHTML = 'Выбрать';
|
||||||
|
button.addEventListener('click', function() {
|
||||||
|
loader.btnLoader(this, true);
|
||||||
|
window.webSDK.selectClient({
|
||||||
|
id: document.querySelector('input[name="changePatient"]:checked').value
|
||||||
|
}).then(function (user) {
|
||||||
|
$.ajax({
|
||||||
|
method: "POST",
|
||||||
|
crossDomain: false,
|
||||||
|
url: "/api/authenticated",
|
||||||
|
contentType: "application/x-www-form-urlencoded",
|
||||||
|
dataType: "json",
|
||||||
|
data: {
|
||||||
|
user: user,
|
||||||
|
uid: user.id
|
||||||
|
},
|
||||||
|
success(response) {
|
||||||
|
if (response.data.success == true) {
|
||||||
|
var parser = document.createElement('a');
|
||||||
|
parser.href = response.data.redirect;
|
||||||
|
|
||||||
|
window.location.replace(document.location.origin + parser.pathname + parser.search);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).catch(function (e) {
|
||||||
|
helper.sendRequest({
|
||||||
|
data: {'error': e, method: 'selectClient'}
|
||||||
|
}, helper.getHostname() + '/api/log', "POST", "json", true, "application/json");
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
div.append(button);
|
||||||
|
popup.querySelector('.modal-content').append(div);
|
||||||
|
|
||||||
|
$(popup).modal('show');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
import { Controller } from 'stimulus';
|
||||||
|
import Cookies from 'js-cookie';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="changeRegion" attribute will cause
|
||||||
|
* this controller to be executed. The name "changeRegion" comes from the filename:
|
||||||
|
* changeRegion_controller.js -> "changeRegion"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
var currentUrl = new URL(window.location);
|
||||||
|
|
||||||
|
if (currentUrl.searchParams.get('region') !== null) {
|
||||||
|
Cookies.set('region', currentUrl.searchParams.get('region'), {expires: 1});
|
||||||
|
currentUrl.searchParams.delete('region');
|
||||||
|
location.replace(currentUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
var checkboxes = this.element.querySelectorAll('input');
|
||||||
|
this.element.querySelector('button.submit').addEventListener('click', function() {
|
||||||
|
checkboxes.forEach(function(el) {
|
||||||
|
if (el.checked) {
|
||||||
|
origin = currentUrl.origin.split('.');
|
||||||
|
origin[1] = (el.value == '94')? 'wmtmed' : 'sovamed';
|
||||||
|
currentUrl.search = 'region=' + el.value
|
||||||
|
Cookies.set('region', el.value, {expires: 1});
|
||||||
|
location.replace(origin.join('.') + currentUrl.pathname + currentUrl.search + location.hash);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (/sovamed\.ru/m.test(location.hostname)) {
|
||||||
|
if (typeof Cookies.get('region') === 'undefined' || Cookies.get('region') == '94') {
|
||||||
|
$('#chengeRegion').modal('show');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Cookies.set('region', 94, {expires: 1});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Cookies.get('region')) {
|
||||||
|
var item = this.element.querySelector('#regionItem' + Cookies.get('region'));
|
||||||
|
item.checked = true;
|
||||||
|
|
||||||
|
if (document.getElementById('regionName')) {
|
||||||
|
document.getElementById('regionName').innerText = item.dataset.text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#chengeRegion').on('hide.bs.modal', function (e) {
|
||||||
|
if (!Cookies.get('region')) {
|
||||||
|
if (/sovamed\.ru/m.test(location.hostname)) {
|
||||||
|
Cookies.set('region', 91, {expires: 1});
|
||||||
|
} else {
|
||||||
|
Cookies.set('region', 94, {expires: 1});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
|
||||||
|
const helper = require("./../components/helper.js");
|
||||||
|
const record = require("./../components/record.js");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="checkScheduleBitrix" attribute will cause
|
||||||
|
* this controller to be executed. The name "hello" comes from the filename:
|
||||||
|
* calendar_checkSchedule.js -> "checkScheduleBitrix"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
var popup = document.getElementById('popup');
|
||||||
|
|
||||||
|
if (! popup) {
|
||||||
|
renderModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderModal() {
|
||||||
|
var popup = document.createElement('div');
|
||||||
|
popup.id = 'popup';
|
||||||
|
popup.classList = 'fancybox-content';
|
||||||
|
popup.style = "display: none; width: 700px;"
|
||||||
|
document.body.append(popup);
|
||||||
|
|
||||||
|
var modalDialog = document.createElement('div');
|
||||||
|
modalDialog.classList = 'modal-dialog';
|
||||||
|
modalDialog.setAttribute('role', 'document');
|
||||||
|
popup.append(modalDialog);
|
||||||
|
|
||||||
|
var modalContent = document.createElement('div');
|
||||||
|
modalContent.classList = 'modal-content';
|
||||||
|
modalDialog.append(modalContent);
|
||||||
|
|
||||||
|
var modalHeader = document.createElement('div');
|
||||||
|
modalHeader.classList = 'modal-header';
|
||||||
|
modalContent.append(modalHeader);
|
||||||
|
|
||||||
|
var modalTitle = document.createElement('h5');
|
||||||
|
modalTitle.classList = 'modal-title';
|
||||||
|
modalHeader.append(modalTitle);
|
||||||
|
|
||||||
|
var popupBody = document.createElement('div');
|
||||||
|
popupBody.id = 'popup-body';
|
||||||
|
popupBody.classList = 'modal-body';
|
||||||
|
modalContent.append(popupBody);
|
||||||
|
|
||||||
|
if (location.host == 'sovenok.sovamed.ru') {
|
||||||
|
var modalTitleDesc = document.createElement('p');
|
||||||
|
modalTitleDesc.innerHTML = 'Внимание! Сопровождать ребенка на прием могут только законные представители пациента.';
|
||||||
|
modalHeader.append(modalTitleDesc);
|
||||||
|
|
||||||
|
var modalFooter = document.createElement('div');
|
||||||
|
modalFooter.classList = 'modal-footer';
|
||||||
|
modalFooter.innerHTML = '*При первом посещении клиники не забудьте паспорт и свидетельство о рождении ребенка.';
|
||||||
|
modalContent.append(modalFooter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
show() {
|
||||||
|
const popup = document.getElementById('popup');
|
||||||
|
|
||||||
|
var date = window.newDate(this.element.dataset.workDate.replace(/\D/g, ""));
|
||||||
|
this.element.dataset.workDate = window.dateFormat(date, 'Y-m-d');
|
||||||
|
|
||||||
|
if (record.renderFormRecord(window.userInfo, this.element.dataset, false)) {
|
||||||
|
ym(48780536,'reachGoal','pram-zapis');
|
||||||
|
$.fancybox.open({
|
||||||
|
src : '#popup',
|
||||||
|
type : 'inline',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,345 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
const helper = require("./../components/helper.js");
|
||||||
|
const record = require("./../components/record.js");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="checSchedule" attribute will cause
|
||||||
|
* this controller to be executed. The name "hello" comes from the filename:
|
||||||
|
* calendar_checkSchedule.js -> "checSchedule"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
getClinicPhone() {
|
||||||
|
// primary source: menu_controller.js tel() sets window.clinicPhone
|
||||||
|
if (typeof window !== 'undefined' && window.clinicPhone) {
|
||||||
|
return String(window.clinicPhone).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallback: read what tel() puts into the header button
|
||||||
|
const el = document.getElementById('btn-callback-clinic');
|
||||||
|
const phone = el ? (el.textContent || '').trim() : '';
|
||||||
|
return phone || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
setTitleWithPhone(titleEl) {
|
||||||
|
if (!titleEl) return;
|
||||||
|
|
||||||
|
const phone = this.getClinicPhone();
|
||||||
|
const phoneText = phone ? phone : '______';
|
||||||
|
titleEl.textContent = `К этому специалисту возможна запись по тел.${phoneText} или через кнопку «записаться».`;
|
||||||
|
|
||||||
|
// If phone not ready yet, retry briefly (tel() is async).
|
||||||
|
if (!phone) {
|
||||||
|
let tries = 0;
|
||||||
|
const timer = setInterval(() => {
|
||||||
|
tries++;
|
||||||
|
const p = this.getClinicPhone();
|
||||||
|
if (p) {
|
||||||
|
titleEl.textContent = `К этому специалисту возможна запись по тел.${p} или через кнопку «записаться».`;
|
||||||
|
clearInterval(timer);
|
||||||
|
} else if (tries >= 20) {
|
||||||
|
clearInterval(timer);
|
||||||
|
}
|
||||||
|
}, 250);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
let run = function (intervalBlock, id, filialName) {
|
||||||
|
this.show(intervalBlock, id, filialName)
|
||||||
|
}.bind(this)
|
||||||
|
|
||||||
|
// Функция для получения intervalBlock по текущему data-id
|
||||||
|
const getIntervalBlock = () => {
|
||||||
|
return document.getElementById(this.element.dataset.id);
|
||||||
|
};
|
||||||
|
|
||||||
|
var intervalBlock = getIntervalBlock();
|
||||||
|
if (!intervalBlock) {
|
||||||
|
return; // Если блок не найден, выходим
|
||||||
|
}
|
||||||
|
|
||||||
|
var wrap = intervalBlock.querySelector('.intervals-wrap');
|
||||||
|
|
||||||
|
wrap.classList.remove('grid-list');
|
||||||
|
wrap.classList.add('grid-none');
|
||||||
|
wrap.innerHTML = "Идет загрузка...";
|
||||||
|
|
||||||
|
var select = this.element.querySelector('.select-schedule');
|
||||||
|
|
||||||
|
if (select) {
|
||||||
|
// Получаем значение department из URL параметра specialist_search[department]
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
const departmentParam = urlParams.get('specialist_search[department]') ||
|
||||||
|
urlParams.get('specialist_search%5Bdepartment%5D');
|
||||||
|
|
||||||
|
let optionFound = false;
|
||||||
|
|
||||||
|
// Если есть параметр department в URL, выбираем соответствующую опцию
|
||||||
|
if (departmentParam) {
|
||||||
|
const departmentId = parseInt(departmentParam);
|
||||||
|
for (let i = 0; i < select.options.length; i++) {
|
||||||
|
const optionValue = select.options[i].value;
|
||||||
|
// Формат значения: dcode:filial:department:onlineMode:infoclinica
|
||||||
|
const parts = optionValue.split(':');
|
||||||
|
if (parts.length >= 3 && parseInt(parts[2]) === departmentId) {
|
||||||
|
select.value = optionValue;
|
||||||
|
optionFound = true;
|
||||||
|
// Обновляем data-id родительского элемента в формате dcode:onlineMode:infoclinica
|
||||||
|
if (parts.length >= 5) {
|
||||||
|
this.element.dataset.id = `${parts[0]}:${parts[3]}:${parts[4]}`;
|
||||||
|
// Обновляем ссылку на intervalBlock после изменения data-id
|
||||||
|
intervalBlock = getIntervalBlock();
|
||||||
|
if (intervalBlock) {
|
||||||
|
wrap = intervalBlock.querySelector('.intervals-wrap');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Обновляем bootstrap-select если он используется
|
||||||
|
// Используем setTimeout чтобы дать время bootstrap-select инициализироваться
|
||||||
|
setTimeout(() => {
|
||||||
|
if (typeof $ !== 'undefined' && $(select).data('selectpicker')) {
|
||||||
|
$(select).selectpicker('refresh');
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
// Запускаем загрузку расписания для выбранной опции
|
||||||
|
if (intervalBlock) {
|
||||||
|
run(intervalBlock, optionValue, select.options[i].text);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если параметра нет или опция не найдена, используем дефолтное поведение
|
||||||
|
if (!optionFound) {
|
||||||
|
run(intervalBlock, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const controllerElement = this.element; // Сохраняем ссылку на элемент контроллера
|
||||||
|
select.addEventListener('change', function() {
|
||||||
|
// Обновляем data-id родительского элемента при изменении селекта
|
||||||
|
const optionValue = this.value;
|
||||||
|
const parts = optionValue.split(':');
|
||||||
|
// Формат значения: dcode:filial:department:onlineMode:infoclinica
|
||||||
|
// Формат data-id: dcode:onlineMode:infoclinica
|
||||||
|
if (parts.length >= 5) {
|
||||||
|
controllerElement.dataset.id = `${parts[0]}:${parts[3]}:${parts[4]}`;
|
||||||
|
// Обновляем ссылку на intervalBlock после изменения data-id
|
||||||
|
const newIntervalBlock = document.getElementById(controllerElement.dataset.id);
|
||||||
|
if (newIntervalBlock) {
|
||||||
|
intervalBlock = newIntervalBlock;
|
||||||
|
wrap = intervalBlock.querySelector('.intervals-wrap');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wrap.classList.remove('grid-list');
|
||||||
|
wrap.classList.add('grid-none');
|
||||||
|
wrap.innerHTML = "Идет загрузка...";
|
||||||
|
|
||||||
|
run(intervalBlock, optionValue, select.options[select.selectedIndex].text)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Если селекта нет, используем дефолтное поведение
|
||||||
|
run(intervalBlock, false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
show(intervalBlock, id, filialName) {
|
||||||
|
// Внутри intervalBlock должны быть:
|
||||||
|
// - .intervals-wrap (контейнер для интервалов/кнопки)
|
||||||
|
// - .show-specialist-detail (кнопка "Все даты" с dataset для /api/interval)
|
||||||
|
// Раньше при пустом расписании мы затирали intervalBlock.innerHTML,
|
||||||
|
// из-за чего при смене клиники селектом пропадал btn и падало на btn.dataset.
|
||||||
|
// Теперь никогда не удаляем intervalBlock целиком.
|
||||||
|
let wrap = intervalBlock.querySelector('.intervals-wrap');
|
||||||
|
if (!wrap) {
|
||||||
|
wrap = document.createElement('div');
|
||||||
|
wrap.className = 'intervals-wrap';
|
||||||
|
intervalBlock.prepend(wrap);
|
||||||
|
}
|
||||||
|
|
||||||
|
const btn = intervalBlock.querySelector('.show-specialist-detail');
|
||||||
|
|
||||||
|
// Кешируем dataset на самом intervalBlock, чтобы можно было работать даже если btn временно скрыт
|
||||||
|
// data-docName в HTML даёт dataset.docName (camelCase), читаем оба варианта
|
||||||
|
if (btn) {
|
||||||
|
intervalBlock.dataset.specialistid = btn.dataset.specialistid || intervalBlock.dataset.specialistid || '';
|
||||||
|
intervalBlock.dataset.departmentid = btn.dataset.departmentid || intervalBlock.dataset.departmentid || '';
|
||||||
|
intervalBlock.dataset.filialid = btn.dataset.filialid || intervalBlock.dataset.filialid || '';
|
||||||
|
intervalBlock.dataset.onlinemode = btn.dataset.onlinemode || intervalBlock.dataset.onlinemode || '';
|
||||||
|
intervalBlock.dataset.address = btn.dataset.address || intervalBlock.dataset.address || '';
|
||||||
|
intervalBlock.dataset.company = btn.dataset.company || intervalBlock.dataset.company || '';
|
||||||
|
intervalBlock.dataset.comment = btn.dataset.comment || intervalBlock.dataset.comment || '';
|
||||||
|
intervalBlock.dataset.docname = (btn.dataset.docName || btn.dataset.docname || intervalBlock.dataset.docname || '').toString();
|
||||||
|
}
|
||||||
|
// Ищем элементы заголовка/даты строго внутри текущей карточки,
|
||||||
|
// чтобы не зависеть от хрупких parentElement-цепочек.
|
||||||
|
const timeList = intervalBlock.closest('.time-list');
|
||||||
|
const titleEl = timeList ? timeList.querySelector('.time-list__title') : null;
|
||||||
|
// Если в заголовке ранее был текст для "записаться", возвращаем стандартный вид перед загрузкой расписания
|
||||||
|
if (titleEl && !titleEl.querySelector('.cdate')) {
|
||||||
|
titleEl.innerHTML = 'Удобное время для записи: <span class="cdate">загружается</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
const cdate = titleEl ? titleEl.querySelector('.cdate') : null;
|
||||||
|
const ds = intervalBlock.dataset || {};
|
||||||
|
if (!ds.specialistid || !ds.departmentid || !ds.filialid) {
|
||||||
|
// Нет данных для запроса расписания (защитимся от падения)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = {
|
||||||
|
'update' : true,
|
||||||
|
'doctor': ds.specialistid,
|
||||||
|
'department': ds.departmentid,
|
||||||
|
'filial': ds.filialid,
|
||||||
|
'startInterval': document.querySelector('.specialist-items').dataset.st,
|
||||||
|
'endInterval': document.querySelector('.specialist-items').dataset.en,
|
||||||
|
'onlineMode': ds.onlinemode
|
||||||
|
};
|
||||||
|
|
||||||
|
if (id) {
|
||||||
|
var params = id.split(":");
|
||||||
|
data.doctor = params[0];
|
||||||
|
data.filial = params[1];
|
||||||
|
data.department = params[2];
|
||||||
|
data.onlineMode = params[3];
|
||||||
|
|
||||||
|
if (btn) {
|
||||||
|
btn.dataset.specialistid = params[0];
|
||||||
|
btn.dataset.filialid = params[1];
|
||||||
|
btn.dataset.departmentid = params[2];
|
||||||
|
btn.dataset.onlinemode = params[3];
|
||||||
|
}
|
||||||
|
intervalBlock.dataset.specialistid = params[0];
|
||||||
|
intervalBlock.dataset.filialid = params[1];
|
||||||
|
intervalBlock.dataset.departmentid = params[2];
|
||||||
|
intervalBlock.dataset.onlinemode = params[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filialName) {
|
||||||
|
if (btn) {
|
||||||
|
btn.dataset.address = filialName;
|
||||||
|
}
|
||||||
|
intervalBlock.dataset.address = filialName;
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.sendRequest(data, "/api/interval", "GET").then((resolve) => {
|
||||||
|
var isNotFree = true;
|
||||||
|
// если ранее скрывали кнопку "Все даты" — возвращаем обратно при любом новом запросе
|
||||||
|
if (btn) {
|
||||||
|
btn.classList.remove('d-none');
|
||||||
|
}
|
||||||
|
intervalBlock.classList.remove('space-between');
|
||||||
|
|
||||||
|
wrap.classList.add('grid-list');
|
||||||
|
wrap.classList.remove('grid-none');
|
||||||
|
wrap.innerHTML = "";
|
||||||
|
var i = 0;
|
||||||
|
|
||||||
|
if (cdate && cdate.dataset && cdate.dataset.nearestDate) {
|
||||||
|
delete cdate.dataset.nearestDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверяем, есть ли данные в ответе
|
||||||
|
if (!resolve.data.intervalsData || resolve.data.intervalsData.length === 0) {
|
||||||
|
isNotFree = true;
|
||||||
|
} else {
|
||||||
|
resolve.data.intervalsData.forEach(function(el) {
|
||||||
|
if (el.isFree == true) {
|
||||||
|
var cDate = new Date(el.workDate).toLocaleString('ru', {year: 'numeric',month: 'numeric',day: 'numeric'});
|
||||||
|
var nearestDate = cdate && cdate.dataset ? cdate.dataset.nearestDate : undefined;
|
||||||
|
|
||||||
|
if (i < 6) {
|
||||||
|
isNotFree = false;
|
||||||
|
|
||||||
|
for (let [key, item] of Object.entries(el.intervals)) {
|
||||||
|
if (item.isFree == true && i < 6 && typeof nearestDate === 'undefined') {
|
||||||
|
if (i == 0) {
|
||||||
|
var spanCurrentDate = document.createElement('span');
|
||||||
|
spanCurrentDate.innerText = cDate;
|
||||||
|
if (cdate) {
|
||||||
|
cdate.innerText = cDate;
|
||||||
|
cdate.dataset.nearestDate = item.nearestDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var spanInterval = document.createElement('span');
|
||||||
|
spanInterval.classList = 'time available text-center';
|
||||||
|
spanInterval.innerText = item.startTime;
|
||||||
|
spanInterval.dataset.workDate = item.workDate;
|
||||||
|
spanInterval.dataset.schedident = item.schedident;
|
||||||
|
spanInterval.dataset.time = item.time;
|
||||||
|
spanInterval.dataset.onlinemode = item.onlineMode;
|
||||||
|
spanInterval.dataset.rnum = item.rNum;
|
||||||
|
spanInterval.dataset.specialistid = intervalBlock.dataset.specialistid || btn.dataset.specialistid;
|
||||||
|
spanInterval.dataset.filialid = intervalBlock.dataset.filialid || btn.dataset.filialid;
|
||||||
|
spanInterval.dataset.department = btn.dataset.departmentid;
|
||||||
|
spanInterval.dataset.company = intervalBlock.dataset.company || btn.dataset.company || '';
|
||||||
|
spanInterval.dataset.comment = intervalBlock.dataset.comment || btn.dataset.comment || '';
|
||||||
|
spanInterval.dataset.address = intervalBlock.dataset.address || btn.dataset.address || '';
|
||||||
|
spanInterval.dataset.docname = (intervalBlock.dataset.docname || btn.dataset.docName || btn.dataset.docname || '').toString();
|
||||||
|
spanInterval.addEventListener('click', function (evn) {
|
||||||
|
var popupWrap = document.getElementById('popup');
|
||||||
|
evn.target.dataset.onlinemode = item.onlineMode;
|
||||||
|
|
||||||
|
if (record.renderFormRecord(resolve.data.userInfo, evn.target.dataset)) {
|
||||||
|
if (resolve.data.userInfo) {
|
||||||
|
evn.target.innerHTML = '<img width="20" src="/images/eclipse.gif">';
|
||||||
|
record.sendReserve(popupWrap)
|
||||||
|
} else {
|
||||||
|
$(popupWrap).modal('show');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
wrap.append(spanInterval);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNotFree) {
|
||||||
|
// Если расписание пустое, показываем кнопку "Записаться" как при specialist.infoclinica == false
|
||||||
|
intervalBlock.classList.add('space-between');
|
||||||
|
// прячем "Все даты", но не удаляем (нужно для переключения селекта)
|
||||||
|
if (btn) {
|
||||||
|
btn.classList.add('d-none');
|
||||||
|
}
|
||||||
|
|
||||||
|
var button = document.createElement('button');
|
||||||
|
// Используем правильные имена атрибутов в camelCase для dataset
|
||||||
|
// data-docName -> dataset.docName (не docname!)
|
||||||
|
var docName = btn && btn.dataset.docName ? btn.dataset.docName : '';
|
||||||
|
var address = btn && btn.dataset.address ? btn.dataset.address : 'null';
|
||||||
|
var company = btn && btn.dataset.company ? btn.dataset.company : 'null';
|
||||||
|
var comment = btn && btn.dataset.comment ? btn.dataset.comment : '';
|
||||||
|
|
||||||
|
button.setAttribute('data-docName', docName);
|
||||||
|
button.setAttribute('data-address', address);
|
||||||
|
button.setAttribute('data-company', company);
|
||||||
|
button.setAttribute('data-comment', comment);
|
||||||
|
button.className = 'btn-show-specialist-detail';
|
||||||
|
button.type = 'button';
|
||||||
|
button.setAttribute('data-controller', 'uslugi');
|
||||||
|
button.innerText = 'Записаться';
|
||||||
|
|
||||||
|
// кладём кнопку в wrap, чтобы не ломать структуру блока
|
||||||
|
wrap.classList.remove('grid-list');
|
||||||
|
wrap.classList.add('grid-none');
|
||||||
|
wrap.innerHTML = '';
|
||||||
|
wrap.appendChild(button);
|
||||||
|
|
||||||
|
// И если мы показываем кнопку, то заголовок должен быть с телефоном/подсказкой
|
||||||
|
this.setTitleWithPhone(titleEl);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
if (!this.isCookieAccepted()) {
|
||||||
|
this.element.classList = 'show';
|
||||||
|
} else {
|
||||||
|
this.element.classList = 'd-none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
accept() {
|
||||||
|
// Устанавливаем куку на 1 год
|
||||||
|
const date = new Date();
|
||||||
|
date.setFullYear(date.getFullYear() + 1);
|
||||||
|
document.cookie = `cookie_accepted=true; expires=${date.toUTCString()}; path=/`;
|
||||||
|
|
||||||
|
this.element.classList = 'd-none';
|
||||||
|
}
|
||||||
|
|
||||||
|
isCookieAccepted() {
|
||||||
|
return document.cookie.split(';').some(cookie =>
|
||||||
|
cookie.trim().startsWith('cookie_accepted=true')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,175 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
|
||||||
|
import daterangepicker from 'daterangepicker'
|
||||||
|
import 'daterangepicker/daterangepicker.css'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="datePicker" attribute will cause
|
||||||
|
* this controller to be executed. The name "hello" comes from the filename:
|
||||||
|
* datePicker_controller.js -> "datePicker"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
var locale = {
|
||||||
|
format: 'DD.MM.YYYY',
|
||||||
|
"applyLabel": "Ок",
|
||||||
|
"cancelLabel": "Отмена",
|
||||||
|
"fromLabel": "От",
|
||||||
|
"toLabel": "До",
|
||||||
|
"customRangeLabel": "Произвольный",
|
||||||
|
"daysOfWeek": [
|
||||||
|
"Вс",
|
||||||
|
"Пн",
|
||||||
|
"Вт",
|
||||||
|
"Ср",
|
||||||
|
"Чт",
|
||||||
|
"Пт",
|
||||||
|
"Сб"
|
||||||
|
],
|
||||||
|
"monthNames": [
|
||||||
|
"Январь",
|
||||||
|
"Февраль",
|
||||||
|
"Март",
|
||||||
|
"Апрель",
|
||||||
|
"Май",
|
||||||
|
"Июнь",
|
||||||
|
"Июль",
|
||||||
|
"Август",
|
||||||
|
"Сентябрь",
|
||||||
|
"Октябрь",
|
||||||
|
"Ноябрь",
|
||||||
|
"Декабрь"
|
||||||
|
],
|
||||||
|
firstDay: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
var date = new Date();
|
||||||
|
var lastDate = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 7);
|
||||||
|
|
||||||
|
// Получаем значение даты из URL параметра или из атрибута value элемента
|
||||||
|
let currentDateValue = this.element.value || this.element.getAttribute('value');
|
||||||
|
|
||||||
|
// Если значение не установлено, пробуем получить из URL
|
||||||
|
if (!currentDateValue || currentDateValue.trim() === '') {
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
currentDateValue = urlParams.get('specialist_search[current_date]') ||
|
||||||
|
urlParams.get('specialist_search%5Bcurrent_date%5D') ||
|
||||||
|
decodeURIComponent(urlParams.get('specialist_search%5Bcurrent_date%5D') || '');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.element.getAttribute('range') == 'true') {
|
||||||
|
let startDate = date;
|
||||||
|
let endDate = lastDate;
|
||||||
|
|
||||||
|
// Если есть значение из URL или value, парсим его
|
||||||
|
if (currentDateValue && currentDateValue.trim() !== '') {
|
||||||
|
const dateRange = this.parseDateRange(currentDateValue);
|
||||||
|
if (dateRange && dateRange.start && dateRange.end) {
|
||||||
|
startDate = dateRange.start;
|
||||||
|
endDate = dateRange.end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Форматируем даты для daterangepicker (формат DD.MM.YYYY)
|
||||||
|
const formattedStart = window.dateFormat(startDate, 'd.m.Y');
|
||||||
|
const formattedEnd = window.dateFormat(endDate, 'd.m.Y');
|
||||||
|
|
||||||
|
const picker = jQuery(this.element).daterangepicker({
|
||||||
|
locale: locale,
|
||||||
|
"startDate": formattedStart,
|
||||||
|
"endDate": formattedEnd
|
||||||
|
}, function(start, end, label) {
|
||||||
|
// Callback при изменении даты
|
||||||
|
});
|
||||||
|
|
||||||
|
// Устанавливаем значение в поле после инициализации
|
||||||
|
// daterangepicker автоматически форматирует значение согласно locale.format
|
||||||
|
// Используем setTimeout чтобы дать время daterangepicker инициализироваться
|
||||||
|
setTimeout(() => {
|
||||||
|
if (currentDateValue && currentDateValue.trim() !== '') {
|
||||||
|
this.element.value = currentDateValue.trim();
|
||||||
|
} else {
|
||||||
|
this.element.value = `${formattedStart} - ${formattedEnd}`;
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
} else {
|
||||||
|
let selectedDate = date;
|
||||||
|
|
||||||
|
// Если есть значение, парсим его
|
||||||
|
if (currentDateValue && currentDateValue.trim() !== '') {
|
||||||
|
const parsedDate = this.parseSingleDate(currentDateValue);
|
||||||
|
if (parsedDate) {
|
||||||
|
selectedDate = parsedDate;
|
||||||
|
this.element.value = currentDateValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jQuery(this.element).daterangepicker({
|
||||||
|
singleDatePicker: true,
|
||||||
|
autoApply: true,
|
||||||
|
showDropdowns: true,
|
||||||
|
minYear: 1930,
|
||||||
|
maxYear: new Date(),
|
||||||
|
locale: locale,
|
||||||
|
"startDate": window.dateFormat(selectedDate, 'd-m-Y')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parseDateRange(dateString) {
|
||||||
|
if (!dateString) return null;
|
||||||
|
|
||||||
|
// Парсим формат "13.01.2026 - 20.01.2026" или "13.01.2026+-+20.01.2026"
|
||||||
|
const match = dateString.match(/^(.+?)\s*[-+]\s*(.+)$/);
|
||||||
|
if (!match) return null;
|
||||||
|
|
||||||
|
const startStr = match[1].trim();
|
||||||
|
const endStr = match[2].trim();
|
||||||
|
|
||||||
|
const startDate = this.parseDateString(startStr);
|
||||||
|
const endDate = this.parseDateString(endStr);
|
||||||
|
|
||||||
|
if (!startDate || !endDate) return null;
|
||||||
|
|
||||||
|
return { start: startDate, end: endDate };
|
||||||
|
}
|
||||||
|
|
||||||
|
parseSingleDate(dateString) {
|
||||||
|
if (!dateString) return null;
|
||||||
|
return this.parseDateString(dateString.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
parseDateString(dateStr) {
|
||||||
|
if (!dateStr) return null;
|
||||||
|
|
||||||
|
// Формат "dd.mm.yyyy"
|
||||||
|
const match = dateStr.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})$/);
|
||||||
|
if (match) {
|
||||||
|
const day = parseInt(match[1], 10);
|
||||||
|
const month = parseInt(match[2], 10) - 1; // месяцы в JS начинаются с 0
|
||||||
|
const year = parseInt(match[3], 10);
|
||||||
|
return new Date(year, month, day);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Формат "yyyy-mm-dd"
|
||||||
|
const match2 = dateStr.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/);
|
||||||
|
if (match2) {
|
||||||
|
const year = parseInt(match2[1], 10);
|
||||||
|
const month = parseInt(match2[2], 10) - 1;
|
||||||
|
const day = parseInt(match2[3], 10);
|
||||||
|
return new Date(year, month, day);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Пробуем стандартный парсинг
|
||||||
|
const parsed = new Date(dateStr);
|
||||||
|
if (!isNaN(parsed.getTime())) {
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="default" attribute will cause
|
||||||
|
* this controller to be executed. The name "default" comes from the filename:
|
||||||
|
* default_controller.js -> "default"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
this.element.addEventListener('click', function () {
|
||||||
|
const popupWrap = document.getElementById('popup');
|
||||||
|
popupWrap.querySelector('.modal-title').innerHTML = 'Вызов врача на дом';
|
||||||
|
popupWrap.querySelector('.modal-dialog').classList.remove('modal-lg');
|
||||||
|
const popupBody = popupWrap.querySelector('#popup-body');
|
||||||
|
const iframe = document.createElement('iframe');
|
||||||
|
iframe.src = '/widget/form/2';
|
||||||
|
iframe.frameBorder = 0;
|
||||||
|
iframe.height = "500";
|
||||||
|
iframe.width = "100%";
|
||||||
|
popupBody.append(iframe);
|
||||||
|
|
||||||
|
$(popupWrap).modal('show');
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="default" attribute will cause
|
||||||
|
* this controller to be executed. The name "default" comes from the filename:
|
||||||
|
* default_controller.js -> "default"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
var buttonReferenceModal = this.element.querySelector('button.show-reference-modal');
|
||||||
|
|
||||||
|
buttonReferenceModal.addEventListener('click', function () {
|
||||||
|
$.ajax({
|
||||||
|
dataType: "HTML",
|
||||||
|
method: 'GET',
|
||||||
|
crossDomain: false,
|
||||||
|
url: '/widget/reference',
|
||||||
|
success(response) {
|
||||||
|
var popupWrap = document.getElementById('popup');
|
||||||
|
popupWrap.querySelector('.modal-title').innerHTML = 'Налоговый вычет на лечение';
|
||||||
|
popupWrap.querySelector('.modal-dialog').classList.remove('modal-lg');
|
||||||
|
var popupBody = popupWrap.querySelector('#popup-body');
|
||||||
|
popupBody.innerHTML = response;
|
||||||
|
$(popupWrap).modal('show');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
import Inputmask from "inputmask";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="hello" attribute will cause
|
||||||
|
* this controller to be executed. The name "hello" comes from the filename:
|
||||||
|
* hello_controller.js -> "hello"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
var a = this.element
|
||||||
|
var favorites = localStorage.getItem('favorites');
|
||||||
|
if (favorites) {
|
||||||
|
this.element.href = '/favorites/?q=' + favorites
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
import Inputmask from "inputmask";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="hello" attribute will cause
|
||||||
|
* this controller to be executed. The name "hello" comes from the filename:
|
||||||
|
* hello_controller.js -> "hello"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
var wrap = this.element
|
||||||
|
var favorites = localStorage.getItem('favorites');
|
||||||
|
|
||||||
|
if (typeof favorites === 'object') {
|
||||||
|
var favorites = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (favorites) {
|
||||||
|
var left = 0;
|
||||||
|
|
||||||
|
favorites.split(',').forEach(function(sid, key) {
|
||||||
|
$.ajax({
|
||||||
|
dataType: "json",
|
||||||
|
method: "GET",
|
||||||
|
crossDomain: true,
|
||||||
|
url: "/api/doctor",
|
||||||
|
data: {
|
||||||
|
'sid': sid,
|
||||||
|
},
|
||||||
|
success(response) {
|
||||||
|
console.log(response, wrap.id)
|
||||||
|
|
||||||
|
if (wrap.id == 'favorites-widget' && key < 8) {
|
||||||
|
var a = document.createElement('a');
|
||||||
|
a.classList = 'staff-link';
|
||||||
|
a.href= "/specialist/" + response.data.alias;
|
||||||
|
|
||||||
|
var img = document.createElement('img');
|
||||||
|
img.classList = "staff-block__img";
|
||||||
|
img.style.borderRadius = '100%';
|
||||||
|
img.stylebackgroundRepeat = "no-repeat";
|
||||||
|
img.style.background = "url(" + response.data.img + ")";
|
||||||
|
img.style.backgroundSize = "cover";
|
||||||
|
img.style.backgroundPosition = "center 0px";
|
||||||
|
|
||||||
|
a.append(img);
|
||||||
|
wrap.append(a);
|
||||||
|
} else {
|
||||||
|
if (key < 4) {
|
||||||
|
var a = document.createElement('a');
|
||||||
|
a.classList = 'favorites-link';
|
||||||
|
a.href= "/specialist/" + response.data.alias;
|
||||||
|
|
||||||
|
var div = document.createElement('img');
|
||||||
|
div.classList = "img-vr";
|
||||||
|
div.stylebackgroundRepeat = "no-repeat";
|
||||||
|
div.style.background = "url(" + response.data.img + ")";
|
||||||
|
div.style.backgroundSize = "cover";
|
||||||
|
div.style.backgroundPosition = "center 0px";
|
||||||
|
a.append(div);
|
||||||
|
wrap.append(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
import Inputmask from "inputmask";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="hello" attribute will cause
|
||||||
|
* this controller to be executed. The name "hello" comes from the filename:
|
||||||
|
* hello_controller.js -> "hello"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
function unic(item, colections) {
|
||||||
|
var add = true;
|
||||||
|
var del = false;
|
||||||
|
colections.forEach(function (val, key) {
|
||||||
|
if (val == item) {
|
||||||
|
add = false;
|
||||||
|
del = key;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (add) {
|
||||||
|
colections.push(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
return colections
|
||||||
|
}
|
||||||
|
|
||||||
|
let sid = this.element.dataset.sid;
|
||||||
|
let like = this.element.querySelector('.like');
|
||||||
|
let dislike = this.element.querySelector('.dislike');
|
||||||
|
|
||||||
|
|
||||||
|
var favorites = localStorage.getItem('favorites');
|
||||||
|
|
||||||
|
if (typeof favorites === 'object') {
|
||||||
|
var favorites = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (favorites.split(',').indexOf(sid) !== -1) {
|
||||||
|
like.classList.add('d-none');
|
||||||
|
dislike.classList.remove('d-none');
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
like.addEventListener('click', function(evn) {
|
||||||
|
var favorites = localStorage.getItem('favorites');
|
||||||
|
var container = [];
|
||||||
|
|
||||||
|
if (typeof favorites === 'object') {
|
||||||
|
var favorites = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (favorites) {
|
||||||
|
favorites = favorites.split(',')
|
||||||
|
} else {
|
||||||
|
favorites = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
favorites.push(sid)
|
||||||
|
|
||||||
|
favorites.forEach(function (key) {
|
||||||
|
container = unic(key, container);
|
||||||
|
});
|
||||||
|
|
||||||
|
localStorage.setItem('favorites', container.join());
|
||||||
|
like.classList.add('d-none');
|
||||||
|
dislike.classList.remove('d-none');
|
||||||
|
this.update();
|
||||||
|
alert('врач добавлен');
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
dislike.addEventListener('click', function (evn) {
|
||||||
|
var favorites = localStorage.getItem('favorites');
|
||||||
|
var favorites = favorites.replace( sid + ',', '');
|
||||||
|
var favorites = favorites.replace( ',' + sid, '');
|
||||||
|
var favorites = favorites.replace( sid, '');
|
||||||
|
|
||||||
|
localStorage.setItem('favorites', favorites);
|
||||||
|
like.classList.remove('d-none');
|
||||||
|
dislike.classList.add('d-none');
|
||||||
|
this.update();
|
||||||
|
}.bind(this))
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
var wrap = document.getElementById('favoritesNaw');
|
||||||
|
|
||||||
|
if (wrap == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
wrap.innerHTML = "";
|
||||||
|
|
||||||
|
var favorites = localStorage.getItem('favorites');
|
||||||
|
var favoritesBtn = document.getElementById('favoritesBtn');
|
||||||
|
|
||||||
|
|
||||||
|
if (typeof favorites === 'object') {
|
||||||
|
var favorites = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (favorites) {
|
||||||
|
favoritesBtn.href = '/favorites/?q=' + favorites;
|
||||||
|
|
||||||
|
var left = 0;
|
||||||
|
|
||||||
|
favorites.split(',').forEach(function(sid, key) {
|
||||||
|
$.ajax({
|
||||||
|
dataType: "json",
|
||||||
|
method: "GET",
|
||||||
|
crossDomain: true,
|
||||||
|
url: "/api/doctor",
|
||||||
|
data: {
|
||||||
|
'sid': sid,
|
||||||
|
},
|
||||||
|
success(response) {
|
||||||
|
if (wrap.id == 'favorites-widget' && key < 8) {
|
||||||
|
var a = document.createElement('a');
|
||||||
|
a.classList = 'staff-link';
|
||||||
|
a.href= "/specialist/" + response.data.alias;
|
||||||
|
|
||||||
|
var img = document.createElement('img');
|
||||||
|
img.classList = "staff-block__img";
|
||||||
|
img.style.borderRadius = '100%';
|
||||||
|
img.stylebackgroundRepeat = "no-repeat";
|
||||||
|
img.style.background = "url(" + response.data.img + ")";
|
||||||
|
img.style.backgroundSize = "cover";
|
||||||
|
img.style.backgroundPosition = "center 0px";
|
||||||
|
|
||||||
|
a.append(img);
|
||||||
|
wrap.append(a);
|
||||||
|
} else {
|
||||||
|
if (key < 4) {
|
||||||
|
var a = document.createElement('a');
|
||||||
|
a.classList = 'favorites-link';
|
||||||
|
a.href= "/specialist/" + response.data.alias;
|
||||||
|
|
||||||
|
var div = document.createElement('img');
|
||||||
|
div.classList = "img-vr";
|
||||||
|
div.stylebackgroundRepeat = "no-repeat";
|
||||||
|
div.style.background = "url(" + response.data.img + ")";
|
||||||
|
div.style.backgroundSize = "cover";
|
||||||
|
div.style.backgroundPosition = "center 0px";
|
||||||
|
a.append(div);
|
||||||
|
wrap.append(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
|
||||||
|
$(this.element).on('click', function(e){
|
||||||
|
$('.filter').addClass('active');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.filter__close').on('click', function(){
|
||||||
|
$('.filter').removeClass('active');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
import Inputmask from "inputmask";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="hello" attribute will cause
|
||||||
|
* this controller to be executed. The name "hello" comes from the filename:
|
||||||
|
* hello_controller.js -> "hello"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
var params = {mask: "+7(899)999-99-99", definitions: {'8': {validator: "[9]"}}}
|
||||||
|
|
||||||
|
if (this.element.dataset.mask) {
|
||||||
|
params = {mask: this.element.dataset.mask}
|
||||||
|
}
|
||||||
|
|
||||||
|
var im = new Inputmask(params);
|
||||||
|
im.mask(this.element);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
import Cookies from 'js-cookie';
|
||||||
|
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
try {
|
||||||
|
const region = Cookies.get('region');
|
||||||
|
|
||||||
|
if (!region) {
|
||||||
|
console.warn('Region cookie not found, using default Jivo widget');
|
||||||
|
}
|
||||||
|
|
||||||
|
const widgetUrl = this.getSource(region);
|
||||||
|
|
||||||
|
this.element.src = widgetUrl;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to load Jivo widget:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getSource(region) {
|
||||||
|
const normalizedRegion = region ? String(region).trim() : '';
|
||||||
|
|
||||||
|
switch (normalizedRegion) {
|
||||||
|
case '93': return 'https://code.jivo.ru/widget/EMlWlFXUZB'; // Воронеж
|
||||||
|
case '94': return 'https://code.jivo.ru/widget/adPLvIW8rT'; // Краснодар
|
||||||
|
default: return 'https://code.jivo.ru/widget/IPQcFAX6b5'; // Саратов, Волгоград
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,205 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
const helper = require("./../components/helper.js");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Контроллер для динамического обновления списка специализаций
|
||||||
|
* при изменении фильтра "Детский врач" / "Взрослый врач"
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
const kinderSelect = this.element.querySelector('[id*="kinder"]');
|
||||||
|
const departmentSelect = this.element.querySelector('[id*="department"]');
|
||||||
|
|
||||||
|
if (!kinderSelect || !departmentSelect) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Сохраняем ссылку на departmentSelect для использования в методах
|
||||||
|
this.departmentSelect = departmentSelect;
|
||||||
|
|
||||||
|
// Обработчик изменения поля kinder
|
||||||
|
// Используем событие change от bootstrap-select, если оно доступно
|
||||||
|
const handleKinderChange = () => {
|
||||||
|
// Небольшая задержка, чтобы bootstrap-select успел обновить значение
|
||||||
|
setTimeout(() => {
|
||||||
|
const kinderValue = kinderSelect.value || '';
|
||||||
|
console.log('Kinder changed to:', kinderValue);
|
||||||
|
this.updateDepartments(departmentSelect, kinderValue);
|
||||||
|
}, 100);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Подписываемся на событие change
|
||||||
|
kinderSelect.addEventListener('change', handleKinderChange);
|
||||||
|
|
||||||
|
// Также подписываемся на событие от bootstrap-select, если оно есть
|
||||||
|
if (typeof $ !== 'undefined' && $(kinderSelect).data('selectpicker')) {
|
||||||
|
$(kinderSelect).on('changed.bs.select', handleKinderChange);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDepartments(departmentSelect, kinderValue) {
|
||||||
|
const kinder = kinderValue === '1' ? 1 : null;
|
||||||
|
|
||||||
|
// Сохраняем текущее выбранное значение перед обновлением
|
||||||
|
const selectedValue = departmentSelect.value;
|
||||||
|
|
||||||
|
// Показываем индикатор загрузки
|
||||||
|
const originalHtml = departmentSelect.innerHTML;
|
||||||
|
departmentSelect.disabled = true;
|
||||||
|
|
||||||
|
// Сохраняем состояние bootstrap-select
|
||||||
|
const isSelectpicker = typeof $ !== 'undefined' && $(departmentSelect).data('selectpicker');
|
||||||
|
const hasLiveSearch = departmentSelect.hasAttribute('data-live-search');
|
||||||
|
|
||||||
|
// Уничтожаем selectpicker, если он инициализирован
|
||||||
|
if (isSelectpicker) {
|
||||||
|
try {
|
||||||
|
$(departmentSelect).selectpicker('destroy');
|
||||||
|
// Удаляем data-атрибут, чтобы selectpicker_controller не пытался его инициализировать снова
|
||||||
|
$(departmentSelect).removeData('selectpicker');
|
||||||
|
// Удаляем классы и элементы, которые мог создать selectpicker
|
||||||
|
$(departmentSelect).next('.bootstrap-select').remove();
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Ошибка при уничтожении selectpicker:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
departmentSelect.innerHTML = '<option value="">Загрузка...</option>';
|
||||||
|
|
||||||
|
// Получаем список специализаций через API
|
||||||
|
const data = {
|
||||||
|
kinder: kinder || 0
|
||||||
|
};
|
||||||
|
|
||||||
|
helper.sendRequest(data, "/api/departments", "GET").then((response) => {
|
||||||
|
console.log('API Response:', response);
|
||||||
|
|
||||||
|
// Очищаем текущие опции
|
||||||
|
departmentSelect.innerHTML = '';
|
||||||
|
|
||||||
|
// Добавляем placeholder
|
||||||
|
const placeholderOption = document.createElement('option');
|
||||||
|
placeholderOption.value = '';
|
||||||
|
placeholderOption.textContent = 'Все специализации';
|
||||||
|
departmentSelect.appendChild(placeholderOption);
|
||||||
|
|
||||||
|
// Добавляем новые опции
|
||||||
|
let foundSelected = false;
|
||||||
|
if (response && response.data && Array.isArray(response.data)) {
|
||||||
|
if (response.data.length > 0) {
|
||||||
|
console.log('Добавляем', response.data.length, 'специализаций');
|
||||||
|
response.data.forEach((dept) => {
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.value = String(dept.did);
|
||||||
|
option.textContent = dept.name;
|
||||||
|
|
||||||
|
// Проверяем, есть ли ранее выбранное значение в новом списке
|
||||||
|
if (selectedValue && selectedValue === String(dept.did)) {
|
||||||
|
option.selected = true;
|
||||||
|
foundSelected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
departmentSelect.appendChild(option);
|
||||||
|
});
|
||||||
|
console.log('Опции добавлены, всего опций:', departmentSelect.options.length);
|
||||||
|
} else {
|
||||||
|
console.warn('Нет данных о специализациях - пустой массив');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error('Неверный формат ответа от API:', response);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если ранее выбранное значение не найдено в новом списке, сбрасываем выбор
|
||||||
|
if (selectedValue && !foundSelected) {
|
||||||
|
departmentSelect.value = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверяем, что опции действительно добавлены
|
||||||
|
console.log('Проверка перед инициализацией selectpicker:');
|
||||||
|
console.log('- Количество опций в select:', departmentSelect.options.length);
|
||||||
|
console.log('- HTML select:', departmentSelect.outerHTML.substring(0, 200));
|
||||||
|
|
||||||
|
// Восстанавливаем bootstrap-select
|
||||||
|
// Используем setTimeout для гарантии, что DOM обновлен
|
||||||
|
setTimeout(() => {
|
||||||
|
try {
|
||||||
|
if (typeof $ !== 'undefined' && $(departmentSelect).length > 0) {
|
||||||
|
// Проверяем, что опции все еще есть
|
||||||
|
if (departmentSelect.options.length === 0) {
|
||||||
|
console.error('ОШИБКА: Опции не найдены перед инициализацией selectpicker!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Убеждаемся, что старый selectpicker полностью удален
|
||||||
|
const $select = $(departmentSelect);
|
||||||
|
if ($select.data('selectpicker')) {
|
||||||
|
console.log('Найден старый selectpicker, уничтожаем');
|
||||||
|
try {
|
||||||
|
$select.selectpicker('destroy');
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Ошибка при destroy:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Удаляем все элементы bootstrap-select из DOM
|
||||||
|
$select.next('.bootstrap-select').remove();
|
||||||
|
$select.siblings('.bootstrap-select').remove();
|
||||||
|
|
||||||
|
// Удаляем data-атрибуты
|
||||||
|
$select.removeData('selectpicker');
|
||||||
|
|
||||||
|
// Всегда инициализируем заново
|
||||||
|
const selectpickerOptions = {
|
||||||
|
noneSelectedText: 'Все специализации'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Добавляем liveSearch, если он был изначально
|
||||||
|
if (hasLiveSearch) {
|
||||||
|
selectpickerOptions.liveSearch = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Инициализируем selectpicker с опциями:', selectpickerOptions);
|
||||||
|
console.log('Количество опций перед инициализацией:', departmentSelect.options.length);
|
||||||
|
|
||||||
|
// Инициализируем selectpicker
|
||||||
|
$select.selectpicker(selectpickerOptions);
|
||||||
|
|
||||||
|
// Проверяем, что selectpicker инициализирован
|
||||||
|
if ($select.data('selectpicker')) {
|
||||||
|
console.log('Selectpicker успешно инициализирован');
|
||||||
|
// Принудительно обновляем отображение
|
||||||
|
$select.selectpicker('render');
|
||||||
|
console.log('Selectpicker отрендерен');
|
||||||
|
} else {
|
||||||
|
console.error('ОШИБКА: Selectpicker не инициализирован после вызова!');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error('jQuery не доступен или элемент не найден');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Ошибка при инициализации bootstrap-select:', e);
|
||||||
|
console.error('Stack trace:', e.stack);
|
||||||
|
}
|
||||||
|
}, 200);
|
||||||
|
|
||||||
|
departmentSelect.disabled = false;
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error('Ошибка при загрузке специализаций:', error);
|
||||||
|
departmentSelect.innerHTML = originalHtml;
|
||||||
|
departmentSelect.disabled = false;
|
||||||
|
|
||||||
|
// Восстанавливаем bootstrap-select даже при ошибке
|
||||||
|
setTimeout(() => {
|
||||||
|
if (typeof $ !== 'undefined') {
|
||||||
|
const selectpickerOptions = {
|
||||||
|
noneSelectedText: 'Все специализации'
|
||||||
|
};
|
||||||
|
if (hasLiveSearch) {
|
||||||
|
selectpickerOptions.liveSearch = true;
|
||||||
|
}
|
||||||
|
$(departmentSelect).selectpicker(selectpickerOptions);
|
||||||
|
}
|
||||||
|
}, 150);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
import Cookies from 'js-cookie';
|
||||||
|
|
||||||
|
const loader = require("./../components/loader.js");
|
||||||
|
const helper = require("./../components/helper.js");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
$(document.querySelector('.login-menu')).on('click', function(){
|
||||||
|
$(this).toggleClass('active');
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document.querySelector('.burger')).on('click', function(){
|
||||||
|
$(this).toggleClass('active');
|
||||||
|
$('.left-sidebar').toggleClass('menu-active');
|
||||||
|
});
|
||||||
|
|
||||||
|
loader.loadSDK('menu').then(function(webSDK) {
|
||||||
|
webSDK.on('init', function() {
|
||||||
|
if (this.data.user.authenticated) {
|
||||||
|
runWebSDK(webSDK);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
let runWebSDK = function (webSDK) {
|
||||||
|
this.bonus(webSDK);
|
||||||
|
|
||||||
|
if (location.pathname != '/case-history') {
|
||||||
|
this.caseHistory(webSDK);
|
||||||
|
}
|
||||||
|
}.bind(this)
|
||||||
|
|
||||||
|
this.tel().catch(error => {
|
||||||
|
console.error('Ошибка в tel():', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
caseHistory(webSDK) {
|
||||||
|
let countRecord = document.getElementById('countRecord');
|
||||||
|
|
||||||
|
window.webSDK.loadScheduleRecList({
|
||||||
|
st: 20170101,
|
||||||
|
en: window.dateFormat(new Date((new Date()).getFullYear(), (new Date()).getMonth() + 6, 0)),
|
||||||
|
start: 0,
|
||||||
|
length: 500
|
||||||
|
}).then(function (resolve) {
|
||||||
|
if (countRecord) {
|
||||||
|
if (resolve.data.length > 0) {
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
for (var i = 0; i < resolve.data.length; i++) {
|
||||||
|
if (resolve.data[i].workDate >= window.dateFormat(new Date())) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
countRecord.innerHTML = count;
|
||||||
|
if (count !== 0) {
|
||||||
|
countRecord.classList.remove('d-none');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (location.pathname == '/') {
|
||||||
|
var caseHistoryWidget = document.getElementById('case-history-widget');
|
||||||
|
caseHistoryWidget.innerHTML = '';
|
||||||
|
|
||||||
|
if (resolve.data.length > 0) {
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
for (var i = 0; i < resolve.data.length; i++) {
|
||||||
|
if (resolve.data[i].workDate >= window.dateFormat(new Date()) && count < 4) {
|
||||||
|
var date = window.newDate(resolve.data[i].workDate);
|
||||||
|
var item = document.createElement('span');
|
||||||
|
item.innerHTML = window.getWeekDay(date) + ', ' + window.dateFormat(date, 'd-m-Y') + ' ' + resolve.data[i].startTime;
|
||||||
|
item.classList = 'line-item';
|
||||||
|
caseHistoryWidget.append(item);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == 0) {
|
||||||
|
var item = document.createElement('span');
|
||||||
|
item.innerHTML = 'Записей не найдено';
|
||||||
|
item.classList = 'line-item empty-item';
|
||||||
|
caseHistoryWidget.append(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
var item = document.createElement('span');
|
||||||
|
item.innerHTML = 'Записей не найдено';
|
||||||
|
item.classList = 'line-item empty-item';
|
||||||
|
caseHistoryWidget.append(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bonus() {
|
||||||
|
var bonusWidget = document.getElementById('bonus-widget');
|
||||||
|
var bonusMenu = document.getElementById('bonus-menu');
|
||||||
|
|
||||||
|
window.webSDK.loadBonusList().then(function (resolve) {
|
||||||
|
if (resolve.length > 0) {
|
||||||
|
if (typeof resolve[0]['amountrub'] !== 'undefined') {
|
||||||
|
if (bonusMenu) {
|
||||||
|
bonusMenu.innerHTML = resolve[0]['amountrub'];
|
||||||
|
bonusMenu.classList.remove('d-none');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bonusWidget) {
|
||||||
|
bonusWidget.innerHTML = resolve[0]['amountrub'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
signOut(event) {
|
||||||
|
if (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
const pcode = String(window?.webSDK?.data?.user?.id || '');
|
||||||
|
const body = new URLSearchParams();
|
||||||
|
if (pcode) {
|
||||||
|
body.append('pcode', pcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch('/api/usrlog/logout', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
|
||||||
|
},
|
||||||
|
credentials: 'same-origin',
|
||||||
|
keepalive: true,
|
||||||
|
body: body.toString()
|
||||||
|
}).catch(() => {
|
||||||
|
//
|
||||||
|
}).finally(() => {
|
||||||
|
window.webSDK.logout();
|
||||||
|
window.location.href = '/logout';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async tel() {
|
||||||
|
const apiUrl = helper.getApiHostname();
|
||||||
|
const regionId = parseInt(Cookies.get('region'));
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${apiUrl}/filial/list?regionId=${regionId}`);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Response status: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
const btnCallbackClinic = document.getElementById('btn-callback-clinic');
|
||||||
|
const phone = result.data?.[0]?.phone;
|
||||||
|
|
||||||
|
if (!btnCallbackClinic || !phone) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const digits = String(phone).replace(/\D/g, '');
|
||||||
|
const normalizedDigits = digits.length === 11 && digits.startsWith('8')
|
||||||
|
? `7${digits.slice(1)}`
|
||||||
|
: digits;
|
||||||
|
|
||||||
|
const displayPhone = normalizedDigits.length === 11 && normalizedDigits.startsWith('7')
|
||||||
|
? `+7(${normalizedDigits.slice(1, 4)})${normalizedDigits.slice(4, 7)}-${normalizedDigits.slice(7, 9)}-${normalizedDigits.slice(9, 11)}`
|
||||||
|
: String(phone).trim();
|
||||||
|
|
||||||
|
// Делаем номер доступным для других частей фронта (например, карточки специалистов)
|
||||||
|
window.clinicPhone = displayPhone;
|
||||||
|
window.clinicPhoneRaw = normalizedDigits;
|
||||||
|
|
||||||
|
btnCallbackClinic.innerText = displayPhone;
|
||||||
|
btnCallbackClinic.href = normalizedDigits ? `tel:+${normalizedDigits}` : `tel:${displayPhone}`;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="searchOrderByInput" attribute will cause
|
||||||
|
* this controller to be executed. The name "searchOrderByInput" comes from the filename:
|
||||||
|
* searchOrderByInput_controller.js -> "searchOrderByInput"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
var val = document.getElementById("specialist_search_order_by").value;
|
||||||
|
var tabs = this.element;
|
||||||
|
if (val) {
|
||||||
|
check(val, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
tabs.addEventListener('change', function(evn) {
|
||||||
|
check(evn.target.value, true);
|
||||||
|
})
|
||||||
|
|
||||||
|
function check(index, redirect) {
|
||||||
|
console.log(index)
|
||||||
|
var array = index.split('.');
|
||||||
|
var id = array[0];
|
||||||
|
var sort = array[1];
|
||||||
|
|
||||||
|
tabs.forEach(function(item) {
|
||||||
|
if (item.value == id) {
|
||||||
|
item.selected = 'true';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById("specialist_search_order_by").value = index + '.asc';
|
||||||
|
|
||||||
|
if (redirect) {
|
||||||
|
document.querySelector('.submit-filter').click();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="default" attribute will cause
|
||||||
|
* this controller to be executed. The name "default" comes from the filename:
|
||||||
|
* default_controller.js -> "default"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
this.element.querySelector('.full-scren-modal').classList.add('d-none');
|
||||||
|
|
||||||
|
var popup = this.element;
|
||||||
|
popup.addEventListener('click', function (ev) {
|
||||||
|
var closeBtn = ev.target.closest && ev.target.closest('[data-qa="close-button"]');
|
||||||
|
if (!closeBtn || !popup.contains(closeBtn)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof $ !== 'undefined' && typeof $(popup).modal === 'function') {
|
||||||
|
$(popup).modal('hide');
|
||||||
|
}
|
||||||
|
if (window.location.hash === '#pay-success') {
|
||||||
|
history.replaceState(null, '', window.location.pathname + window.location.search);
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
fullScreen() {
|
||||||
|
var btn = this.element.querySelector('.full-scren-modal')
|
||||||
|
if (btn.classList.contains('fa-window-maximize')) {
|
||||||
|
btn.classList.add('fa-window-minimize');
|
||||||
|
btn.classList.remove('fa-window-maximize');
|
||||||
|
this.element.style.paddingRight = 0;
|
||||||
|
this.element.querySelector('.modal-dialog').style.maxWidth = window.innerWidth + 'px';
|
||||||
|
this.element.querySelector('.modal-dialog').style.height = window.innerHeight + 'px';
|
||||||
|
this.element.querySelector('.modal-dialog').style.margin = 0;
|
||||||
|
} else {
|
||||||
|
btn.classList.remove('fa-window-minimize');
|
||||||
|
btn.classList.add('fa-window-maximize');
|
||||||
|
this.element.style.paddingRight = '';
|
||||||
|
this.element.querySelector('.modal-dialog').style.maxWidth = '';
|
||||||
|
this.element.querySelector('.modal-dialog').style.height = '';
|
||||||
|
this.element.querySelector('.modal-dialog').style.margin = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="default" attribute will cause
|
||||||
|
* this controller to be executed. The name "default" comes from the filename:
|
||||||
|
* default_controller.js -> "default"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
var eye = document.createElement('i');
|
||||||
|
eye.setAttribute('aria-hidden', true);
|
||||||
|
eye.classList = 'fa fa-eye-slash'; //fa-eye
|
||||||
|
eye.style.position = 'absolute';
|
||||||
|
eye.dataset.action = 'click->passwordShow#toggle'
|
||||||
|
eye.style.top = '10px';
|
||||||
|
eye.style.right = '10px';
|
||||||
|
|
||||||
|
this.element.style.position = 'relative';
|
||||||
|
this.element.append(eye);
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle() {
|
||||||
|
var btn = this.element.querySelector('input');
|
||||||
|
var eye = this.element.querySelector('i');
|
||||||
|
|
||||||
|
if (eye.classList.contains('fa-eye-slash')) {
|
||||||
|
eye.classList = 'fa fa-eye';
|
||||||
|
btn.type = 'text';
|
||||||
|
} else {
|
||||||
|
eye.classList = 'fa fa-eye-slash';
|
||||||
|
btn.type = 'password';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
const loader = require("./../components/loader.js");
|
||||||
|
const helper = require("./../components/helper.js");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="payment" attribute will cause
|
||||||
|
* this controller to be executed. The name "payment" comes from the filename:
|
||||||
|
* payment_controller.js -> "payment"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
loader.loadSDK('payment').then(function(webSDK) {
|
||||||
|
webSDK.on('init', function() {
|
||||||
|
if (this.data.user.authenticated) {
|
||||||
|
runWebSDK();
|
||||||
|
} else {
|
||||||
|
window.location.pathname = '/logout'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
let runWebSDK = function () {
|
||||||
|
this.finance();
|
||||||
|
}.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
finance() {
|
||||||
|
var securityPayment = document.getElementById('security-payment');
|
||||||
|
|
||||||
|
webSDK.loadPaymentList({
|
||||||
|
start: 0,
|
||||||
|
length: 50
|
||||||
|
}).then(function (resolve) {
|
||||||
|
var paymentWrap = securityPayment.querySelector('.payment-wrap');
|
||||||
|
|
||||||
|
if (resolve.length > 0) {
|
||||||
|
resolve.forEach(function(item, index) {
|
||||||
|
var paymentShow = securityPayment.querySelector('.payment-item').cloneNode(true);
|
||||||
|
|
||||||
|
paymentShow.querySelector('.pay-id').innerHTML = item.id;
|
||||||
|
paymentShow.querySelector('.address').innerHTML = item.filialName;
|
||||||
|
paymentShow.querySelector('.comment').innerHTML = item.comment;
|
||||||
|
paymentShow.querySelector('.specialist').innerHTML = item.doctor;
|
||||||
|
paymentShow.querySelector('.service').innerHTML = item.service;
|
||||||
|
|
||||||
|
var date = window.newDate(item.date);
|
||||||
|
paymentShow.querySelector('.month').innerHTML = getWeekDay(date);
|
||||||
|
paymentShow.querySelector('.date').innerHTML = window.dateFormat(date, 'd-m-Y')
|
||||||
|
paymentShow.querySelector('.pay-date').innerHTML = window.dateFormat(date, 'd-m-Y')
|
||||||
|
|
||||||
|
paymentShow.querySelectorAll('.amt').forEach(function (el) {
|
||||||
|
el.innerHTML = item.amt;
|
||||||
|
|
||||||
|
if (item.status.id == 0) {
|
||||||
|
paymentShow.querySelector('.pay').querySelector('.button-revers').classList.remove('d-none');
|
||||||
|
} else {
|
||||||
|
paymentShow.querySelector('.pay').querySelector('.button-revers').classList.add('d-none');
|
||||||
|
paymentShow.querySelector('.pay').querySelector('.price').classList.remove('d-none');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
paymentShow.querySelector('.pay').querySelector('.button-revers').dataset.orderId = item.id;
|
||||||
|
paymentShow.querySelector('.pay').querySelector('.button-revers').dataset.filial = item.filial;
|
||||||
|
paymentShow.querySelector('.pay').querySelector('.button-revers').dataset.amt = item.amt;
|
||||||
|
paymentShow.querySelector('.pay').querySelector('.button-revers').dataset.payprofileid = item.magazineId;
|
||||||
|
|
||||||
|
paymentShow.querySelector('.pay').querySelector('.button-revers').addEventListener('click', function (evn) {
|
||||||
|
var popup = document.getElementById('popup');
|
||||||
|
var params = {
|
||||||
|
'orderid': Number(this.dataset.orderId) ,
|
||||||
|
'payprofileid': this.dataset.payprofileid,
|
||||||
|
'payamount': this.dataset.amt,
|
||||||
|
// 'paymethod': 'QW',
|
||||||
|
'filial': Number(this.dataset.filial),
|
||||||
|
'pcode': webSDK.data.user.representId,
|
||||||
|
'successurl': document.location.origin + '/payment?pay=true',
|
||||||
|
'errorurl': document.location.origin + '/payment?pay=false',
|
||||||
|
'containerId': 'popup-body',
|
||||||
|
};
|
||||||
|
|
||||||
|
webSDK.loadPaymentView(params);
|
||||||
|
popup.querySelector('.modal-body').innerHTML = '';
|
||||||
|
popup.querySelector('.modal-title').innerHTML = 'Оплата';
|
||||||
|
|
||||||
|
$(popup).modal('show');
|
||||||
|
})
|
||||||
|
|
||||||
|
paymentShow.classList.add('mt-3')
|
||||||
|
paymentShow.classList.remove('d-none')
|
||||||
|
|
||||||
|
if (index == 0) {
|
||||||
|
paymentWrap.innerHTML = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
paymentWrap.appendChild(paymentShow);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).catch(function (e) {
|
||||||
|
helper.sendRequest({
|
||||||
|
data: {'error': e, method: 'loadPaymentList'}
|
||||||
|
}, helper.getHostname() + '/api/log', "POST", "json", true, "application/json");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
const loader = require("./../components/loader.js");
|
||||||
|
const helper = require("./../components/helper.js");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="priceList" attribute will cause
|
||||||
|
* this controller to be executed. The name "priceList" comes from the filename:
|
||||||
|
* priceList_controller.js -> "priceList"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
var wrap = this.element;
|
||||||
|
var priceListSelect = document.getElementById('price_list_admin_form_groupId');
|
||||||
|
var select = priceListSelect.cloneNode(true);
|
||||||
|
select.id = 'price_list_update_form';
|
||||||
|
select.name = 'groupId';
|
||||||
|
|
||||||
|
var priceList = this.element.querySelector('.group-update');
|
||||||
|
priceList.appendChild(select);
|
||||||
|
|
||||||
|
var btnUpdatePriceList = this.element.querySelector('#update-price-list');
|
||||||
|
|
||||||
|
btnUpdatePriceList.addEventListener('click', function() {
|
||||||
|
if (select.value == '') {
|
||||||
|
select.classList.add('is-invalid');
|
||||||
|
} else {
|
||||||
|
select.classList.remove('is-invalid');
|
||||||
|
var msg = wrap.querySelector('.msg');
|
||||||
|
msg.innerHTML = "Пожалуйста ждите, идет обновление цен!";
|
||||||
|
msg.classList.add('text-danger');
|
||||||
|
|
||||||
|
loader.btnLoader(btnUpdatePriceList, true);
|
||||||
|
helper.sendRequest({groupId: select.value}, '/update/price-list', "POST").then(function (response) {
|
||||||
|
loader.btnLoader(btnUpdatePriceList, false);
|
||||||
|
|
||||||
|
if (response.status == true) {
|
||||||
|
msg.innerHTML = "Обновление успешно завершено! <br> Нажмите на кнопку \"Search\" для отображения в таблице.";
|
||||||
|
msg.classList.remove('text-danger');
|
||||||
|
msg.classList.add('text-success');
|
||||||
|
} else {
|
||||||
|
msg.innerHTML = "Упс, что то пошло не так, попробуйте позже или обратитесь к Администратору.";
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
|
||||||
|
export default class extends Controller {
|
||||||
|
static targets = ['input'];
|
||||||
|
|
||||||
|
today(event) {
|
||||||
|
event?.preventDefault?.();
|
||||||
|
|
||||||
|
const today = this.startOfDay(new Date());
|
||||||
|
this.setRange(today, today);
|
||||||
|
}
|
||||||
|
|
||||||
|
tomorrow(event) {
|
||||||
|
event?.preventDefault?.();
|
||||||
|
|
||||||
|
const tomorrow = this.addDays(this.startOfDay(new Date()), 1);
|
||||||
|
this.setRange(tomorrow, tomorrow);
|
||||||
|
}
|
||||||
|
|
||||||
|
setRange(startDate, endDate) {
|
||||||
|
const input = this.inputTarget;
|
||||||
|
const formattedStart = this.formatDate(startDate);
|
||||||
|
const formattedEnd = this.formatDate(endDate);
|
||||||
|
const value = `${formattedStart} - ${formattedEnd}`;
|
||||||
|
|
||||||
|
// If daterangepicker is attached, keep it in sync.
|
||||||
|
if (typeof $ !== 'undefined') {
|
||||||
|
const picker = $(input).data('daterangepicker');
|
||||||
|
if (picker) {
|
||||||
|
picker.setStartDate(formattedStart);
|
||||||
|
picker.setEndDate(formattedEnd);
|
||||||
|
|
||||||
|
// Ensure UI is refreshed for both calendars & input.
|
||||||
|
if (typeof picker.updateCalendars === 'function') {
|
||||||
|
picker.updateCalendars();
|
||||||
|
}
|
||||||
|
if (typeof picker.updateView === 'function') {
|
||||||
|
picker.updateView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input.value = value;
|
||||||
|
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||||
|
|
||||||
|
const form = this.element.closest('form');
|
||||||
|
if (form) {
|
||||||
|
if (typeof form.requestSubmit === 'function') {
|
||||||
|
form.requestSubmit();
|
||||||
|
} else {
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
startOfDay(date) {
|
||||||
|
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
||||||
|
}
|
||||||
|
|
||||||
|
addDays(date, days) {
|
||||||
|
return new Date(date.getFullYear(), date.getMonth(), date.getDate() + days);
|
||||||
|
}
|
||||||
|
|
||||||
|
formatDate(date) {
|
||||||
|
const dd = String(date.getDate()).padStart(2, '0');
|
||||||
|
const mm = String(date.getMonth() + 1).padStart(2, '0');
|
||||||
|
const yyyy = String(date.getFullYear());
|
||||||
|
return `${dd}.${mm}.${yyyy}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,599 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
const validator = require("./../components/validator.js");
|
||||||
|
const loader = require("./../components/loader.js");
|
||||||
|
const helper = require("./../components/helper.js");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="default" attribute will cause
|
||||||
|
* this controller to be executed. The name "default" comes from the filename:
|
||||||
|
* default_controller.js -> "default"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
var referenceWrapper = this.element;
|
||||||
|
|
||||||
|
window.addEventListener("mousemove",(e) => {
|
||||||
|
window.parent.postMessage({ type: "user_mousemove" }, "*");
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener("input",(e) => {
|
||||||
|
window.parent.postMessage({ type: "user_typing" }, "*");
|
||||||
|
});
|
||||||
|
|
||||||
|
let evnRender = function (responsibleUser, countFilial) {
|
||||||
|
this.renderResponsibleUser(responsibleUser, countFilial);
|
||||||
|
}.bind(this)
|
||||||
|
|
||||||
|
var changeResponsible = function (countFilial, value) {
|
||||||
|
var responsibleFilial = referenceWrapper.querySelector('.responsible_filial_' + countFilial);
|
||||||
|
var responsibleUser = responsibleFilial.querySelector('.responsible_user');
|
||||||
|
|
||||||
|
if (value == 1) {
|
||||||
|
responsibleUser.innerHTML = '';
|
||||||
|
} else {
|
||||||
|
evnRender(responsibleUser, countFilial)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
referenceWrapper.querySelector('.reference-responsible').addEventListener('change', function() {
|
||||||
|
changeResponsible(this.dataset.count, this.value);
|
||||||
|
})
|
||||||
|
|
||||||
|
let evnRenderSending = function (referenceSending) {
|
||||||
|
this.renderSending(referenceSending);
|
||||||
|
}.bind(this)
|
||||||
|
|
||||||
|
const addFilial = referenceWrapper.querySelector('button.add-filial');
|
||||||
|
const referenceFilial = referenceWrapper.querySelector('#reference_filial');
|
||||||
|
const referenceFilialSending = referenceWrapper.querySelector('#reference_filialSending');
|
||||||
|
const referenceSending = referenceWrapper.querySelector('#reference_sending');
|
||||||
|
const filialSendingWrapper = referenceWrapper.querySelector('.filial-sending');
|
||||||
|
|
||||||
|
const syncSendingUi = () => {
|
||||||
|
if (!referenceSending || !filialSendingWrapper) return;
|
||||||
|
|
||||||
|
// Разрешённые варианты:
|
||||||
|
// 1 = "Лично в клинике"
|
||||||
|
// 2 = "Отправка в налоговую инспекцию"
|
||||||
|
// Любое другое/невалидное значение считаем "1".
|
||||||
|
const sendingSafe = (referenceSending.value === '2' || referenceSending.value === 2) ? '2' : '1';
|
||||||
|
|
||||||
|
// "Лично в клинике" => 1 => показываем выбор клиники получения справки
|
||||||
|
filialSendingWrapper.classList.toggle('d-none', sendingSafe !== '1');
|
||||||
|
|
||||||
|
// При "Лично" синхронизируем филиал получения.
|
||||||
|
// Если filialSending ещё не выбран (пустой) — НЕ блокируем, чтобы можно было выбрать вручную.
|
||||||
|
if (sendingSafe === '1') {
|
||||||
|
if (referenceFilial.selectedIndex > 0) {
|
||||||
|
referenceFilialSending.selectedIndex = referenceFilial.selectedIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
referenceFilialSending.disabled = Boolean(referenceFilialSending.value);
|
||||||
|
} else {
|
||||||
|
referenceFilialSending.disabled = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (referenceSending) {
|
||||||
|
referenceSending.addEventListener('change', syncSendingUi);
|
||||||
|
}
|
||||||
|
syncSendingUi();
|
||||||
|
|
||||||
|
referenceFilial.addEventListener('change', function(evn) {
|
||||||
|
// Если выдача "Лично в клинике" — синхронизируем филиал получения
|
||||||
|
const sendingSafe = (referenceSending && (referenceSending.value === '2' || referenceSending.value === 2)) ? '2' : '1';
|
||||||
|
if (sendingSafe === '1') {
|
||||||
|
if (referenceFilial.selectedIndex > 0) {
|
||||||
|
referenceFilialSending.selectedIndex = referenceFilial.selectedIndex;
|
||||||
|
}
|
||||||
|
referenceFilialSending.disabled = Boolean(referenceFilialSending.value);
|
||||||
|
} else {
|
||||||
|
referenceFilialSending.selectedIndex = 0;
|
||||||
|
referenceFilialSending.disabled = false;
|
||||||
|
}
|
||||||
|
addFilial.classList.remove('d-none');
|
||||||
|
});
|
||||||
|
|
||||||
|
addFilial.addEventListener('click', function() {
|
||||||
|
var countFilial = parseInt(this.dataset.count, 10);
|
||||||
|
var responsibleFilial = referenceWrapper.querySelector('.responsible_filial_' + countFilial)
|
||||||
|
var newFilialCount = countFilial + 1
|
||||||
|
this.dataset.count = newFilialCount;
|
||||||
|
var newFilial = referenceWrapper.querySelector('.responsible_filial_' + countFilial).cloneNode(true);
|
||||||
|
newFilial.classList = 'responsible_filials responsible_filial_' + newFilialCount;
|
||||||
|
newFilial.querySelector('.reference-filial').id = 'reference_filial_' + newFilialCount;
|
||||||
|
newFilial.querySelector('.reference-filial').classList = 'reference-filial form-control';
|
||||||
|
newFilial.querySelector('.valid-reference_filial').innerHTML = '';
|
||||||
|
newFilial.querySelector('.responsible_user').innerHTML = '';
|
||||||
|
newFilial.querySelector('.reference-responsible').id = 'reference_responsible_' + newFilialCount;
|
||||||
|
|
||||||
|
newFilial.querySelector('.reference-period-first').id = 'reference_periodFirst_' + newFilialCount;
|
||||||
|
newFilial.querySelector('.reference-period-first').classList = 'reference-period-first form-control';
|
||||||
|
|
||||||
|
newFilial.querySelector('.reference-period-last').id = 'reference_periodLast_' + newFilialCount;
|
||||||
|
newFilial.querySelector('.reference-period-last').classList = 'reference-period-last form-control';
|
||||||
|
|
||||||
|
newFilial.querySelector('.reference-responsible').addEventListener('change', function() {
|
||||||
|
changeResponsible(newFilialCount, this.value);
|
||||||
|
})
|
||||||
|
|
||||||
|
responsibleFilial.parentNode.insertBefore(newFilial, responsibleFilial.nextSibling);
|
||||||
|
})
|
||||||
|
var crmFields = {};
|
||||||
|
|
||||||
|
helper.sendRequest(
|
||||||
|
[],
|
||||||
|
'https://sovamed.bitrix24.ru/rest/10998/3hrv38rzo3khchj3/crm.lead.fields.json',
|
||||||
|
'GET',
|
||||||
|
'json',
|
||||||
|
false,
|
||||||
|
'application/json'
|
||||||
|
).then(function(response) {
|
||||||
|
crmFields = response;
|
||||||
|
});
|
||||||
|
|
||||||
|
var submit = referenceWrapper.querySelector('button.submit');
|
||||||
|
|
||||||
|
submit.addEventListener('click', function() {
|
||||||
|
evnClick(referenceWrapper, crmFields);
|
||||||
|
})
|
||||||
|
|
||||||
|
let evnClick = function (wrapper, crmFields) {
|
||||||
|
var result = this.submit(wrapper);
|
||||||
|
var params = {
|
||||||
|
'fields' : {
|
||||||
|
'TITLE': 'Получение документов для налогового вычета',
|
||||||
|
'NAME': result.options.autorName,
|
||||||
|
'PHONE': [{
|
||||||
|
'VALUE': result.options.phone,
|
||||||
|
'VALUE_TYPE': 'WORK'
|
||||||
|
}],
|
||||||
|
'ASSIGNED_BY_ID' : 506,
|
||||||
|
'UF_CRM_1539951158': helper.getCityId(result.options.filials[0].filial),
|
||||||
|
'UF_CRM_1565783329': result.options.inn,
|
||||||
|
'UF_CRM_1658495790': '',
|
||||||
|
'UF_CRM_1565783428': result.options.filials[0].periodFirst + " - " + result.options.filials[0].periodLast,
|
||||||
|
'UF_CRM_1565783258': result.options.birthDate,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const normalizeFilialValue = (value) => {
|
||||||
|
if (typeof value !== 'string') return '';
|
||||||
|
return value
|
||||||
|
.replaceAll('\u00A0', ' ') // NBSP -> space
|
||||||
|
.replaceAll('.', '') // "г.Саратов" == "г. Саратов", "д. 33" == "д 33"
|
||||||
|
.replace(/\s+/g, ' ')
|
||||||
|
.replace(/\s*,\s*/g, ', ')
|
||||||
|
.trim()
|
||||||
|
.toLowerCase();
|
||||||
|
};
|
||||||
|
|
||||||
|
const filialValue = result.options.filials?.[0]?.filial ?? '';
|
||||||
|
const filialValueNormalized = normalizeFilialValue(filialValue);
|
||||||
|
|
||||||
|
// 1) точное совпадение после нормализации
|
||||||
|
crmFields.result.UF_CRM_1658495790.items.forEach(function (el) {
|
||||||
|
if (params.fields['UF_CRM_1658495790']) return;
|
||||||
|
if (filialValueNormalized && filialValueNormalized === normalizeFilialValue(el.VALUE)) {
|
||||||
|
params.fields['UF_CRM_1658495790'] = el.ID;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2) запасной вариант: если Bitrix хранит VALUE без доп. суффикса "(...)" и т.п.
|
||||||
|
if (!params.fields['UF_CRM_1658495790'] && filialValueNormalized) {
|
||||||
|
const filialValueNoParens = filialValueNormalized.replace(/\s*\([^)]*\)\s*/g, ' ').replace(/\s+/g, ' ').trim();
|
||||||
|
crmFields.result.UF_CRM_1658495790.items.forEach(function (el) {
|
||||||
|
if (params.fields['UF_CRM_1658495790']) return;
|
||||||
|
const bitrixValue = normalizeFilialValue(el.VALUE);
|
||||||
|
if (!bitrixValue) return;
|
||||||
|
if (bitrixValue === filialValueNoParens || filialValueNoParens.includes(bitrixValue) || bitrixValue.includes(filialValueNoParens)) {
|
||||||
|
params.fields['UF_CRM_1658495790'] = el.ID;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.options.filials[0].responsible == 0) {
|
||||||
|
params.fields['UF_CRM_1565784083'] = 400 //[{"ID": "400","VALUE": "за другого пациента"}];
|
||||||
|
params.fields['UF_CRM_1654588779'] = result.options.filials[0].relation;
|
||||||
|
params.fields['UF_CRM_1565784170'] = result.options.filials[0].birthDate;
|
||||||
|
params.fields['UF_CRM_1565784142'] = result.options.filials[0].fio;
|
||||||
|
} else {
|
||||||
|
params.fields['UF_CRM_1565784083'] = 398 //[{"ID": "398","VALUE": "себя"}];
|
||||||
|
params.fields['UF_CRM_1654588779'] = 'за себя';
|
||||||
|
|
||||||
|
params.fields['UF_CRM_1565784170'] = result.options.birthDate;
|
||||||
|
params.fields['UF_CRM_1565784142'] = result.options.autorName;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sendingSafe = (result.options.sending == 2 || result.options.sending === '2') ? 2 : 1;
|
||||||
|
|
||||||
|
if (sendingSafe == 1) {
|
||||||
|
params.fields['UF_CRM_1658499141'] = 2494 //[{"ID": "2494","VALUE": "на руки"}]
|
||||||
|
|
||||||
|
const filialSendingValue = result.options.filialSending ?? '';
|
||||||
|
const filialSendingValueNormalized = normalizeFilialValue(filialSendingValue);
|
||||||
|
|
||||||
|
// 1) точное совпадение после нормализации
|
||||||
|
crmFields.result.UF_CRM_1658497553.items.forEach(function (el) {
|
||||||
|
if (params.fields['UF_CRM_1658497553']) return;
|
||||||
|
if (filialSendingValueNormalized && filialSendingValueNormalized === normalizeFilialValue(el.VALUE)) {
|
||||||
|
params.fields['UF_CRM_1658497553'] = el.ID;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2) запасной вариант: совпадение без суффикса "(...)" и т.п.
|
||||||
|
if (!params.fields['UF_CRM_1658497553'] && filialSendingValueNormalized) {
|
||||||
|
const filialSendingValueNoParens = filialSendingValueNormalized
|
||||||
|
.replace(/\s*\([^)]*\)\s*/g, ' ')
|
||||||
|
.replace(/\s+/g, ' ')
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
crmFields.result.UF_CRM_1658497553.items.forEach(function (el) {
|
||||||
|
if (params.fields['UF_CRM_1658497553']) return;
|
||||||
|
const bitrixValue = normalizeFilialValue(el.VALUE);
|
||||||
|
if (!bitrixValue) return;
|
||||||
|
if (bitrixValue === filialSendingValueNoParens || filialSendingValueNoParens.includes(bitrixValue) || bitrixValue.includes(filialSendingValueNoParens)) {
|
||||||
|
params.fields['UF_CRM_1658497553'] = el.ID;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (sendingSafe == 2) {
|
||||||
|
params.fields['UF_CRM_1658499141'] = 4680 //[{"ID": "4680","VALUE": "отправка в налоговую инспекцию"}]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.keys(result.options.filials).length > 1) {
|
||||||
|
var comment = "";
|
||||||
|
|
||||||
|
for (var index = 0; index < Object.keys(result.options.filials).length; index++) {
|
||||||
|
if (index !== 0) {
|
||||||
|
comment += "Дополнительно:\n\t"
|
||||||
|
if (result.options.filials[index].responsible == 0) {
|
||||||
|
comment += 'Степень родства: ' + result.options.filials[index].relation + "\n\t";
|
||||||
|
comment += 'ФИО: ' + result.options.filials[index].fio + "\n\t";
|
||||||
|
comment += 'Дата рождения: ' + result.options.filials[index].birthDate + "\n\t";
|
||||||
|
} else {
|
||||||
|
comment += "За себя\n\t";
|
||||||
|
comment += 'ФИО: ' + result.options.autorName + "\n\t";
|
||||||
|
comment += 'Дата рождения: ' + result.options.birthDate + "\n\t";
|
||||||
|
}
|
||||||
|
|
||||||
|
comment += 'Филиал: ' + result.options.filials[index].filial + "\n\t";
|
||||||
|
comment += 'За период: ' + result.options.filials[index].periodFirst;
|
||||||
|
comment += ' - ' + result.options.filials[index].periodLast + "\n\t";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
params.fields['UF_CRM_1545895397'] = comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.invalid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
loader.btnLoader(submit, true);
|
||||||
|
|
||||||
|
helper.sendRequest(
|
||||||
|
params,
|
||||||
|
'https://sovamed.bitrix24.ru/rest/10998/3hrv38rzo3khchj3/crm.lead.add.json',
|
||||||
|
'POST',
|
||||||
|
'json',
|
||||||
|
false,
|
||||||
|
'application/json'
|
||||||
|
).then(function(response) {
|
||||||
|
loader.btnLoader(submit, false);
|
||||||
|
|
||||||
|
if (referenceWrapper.dataset.ref == '/') {
|
||||||
|
helper.sendRequest({'reference' : 1, 'phone' : result.options.phone}, '/api/msg');
|
||||||
|
var successAlert = document.createElement('div');
|
||||||
|
successAlert.classList = 'alert alert-success alert-dismissible fade show';
|
||||||
|
successAlert.setAttribute('role', 'alert');
|
||||||
|
|
||||||
|
var divMsg = document.createElement('div');
|
||||||
|
divMsg.classList = 'alert-msg';
|
||||||
|
divMsg.innerHTML = '<p>Заявка успешно подана.</p>';
|
||||||
|
successAlert.append(divMsg);
|
||||||
|
|
||||||
|
var buttonClose = document.createElement('button');
|
||||||
|
buttonClose.classList = 'close';
|
||||||
|
buttonClose.dataset.dismiss ='alert';
|
||||||
|
buttonClose.setAttribute('aria-label', 'Close');
|
||||||
|
buttonClose.innerHTML = '<span aria-hidden="true">×</span>';
|
||||||
|
successAlert.append(buttonClose);
|
||||||
|
document.getElementById('alert-system').prepend(successAlert);
|
||||||
|
|
||||||
|
$(popup).modal('hide');
|
||||||
|
$('html, body').animate({scrollTop:0}, '300');
|
||||||
|
} else {
|
||||||
|
window.parent.postMessage({'message': 'hide.modal', 'phone' : result.options.phone}, atob(referenceWrapper.dataset.ref));
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSending(referenceSending) {
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.classList = 'form-group mb-2';
|
||||||
|
|
||||||
|
var label = document.createElement('label');
|
||||||
|
label.innerHTML = 'Почтовый адрес:';
|
||||||
|
label.classList = 'mb-0';
|
||||||
|
label.setAttribute('for', 'reference_address')
|
||||||
|
div.append(label);
|
||||||
|
|
||||||
|
var input = document.createElement('input');
|
||||||
|
input.id = 'reference_address';
|
||||||
|
input.name = 'reference_address';
|
||||||
|
input.classList = 'form-control';
|
||||||
|
div.append(input);
|
||||||
|
|
||||||
|
var msg = document.createElement('div')
|
||||||
|
msg.classList = 'msg-valid valid-reference_address';
|
||||||
|
div.append(msg);
|
||||||
|
referenceSending.append(div);
|
||||||
|
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.classList = 'form-group mb-2';
|
||||||
|
|
||||||
|
var label = document.createElement('label');
|
||||||
|
label.innerHTML = 'Индекс:';
|
||||||
|
label.classList = 'mb-0';
|
||||||
|
label.setAttribute('for', 'reference_index')
|
||||||
|
div.append(label);
|
||||||
|
|
||||||
|
var input = document.createElement('input');
|
||||||
|
input.id = 'reference_index'
|
||||||
|
input.name = 'reference_index'
|
||||||
|
input.classList = 'form-control';
|
||||||
|
div.append(input);
|
||||||
|
|
||||||
|
var msg = document.createElement('div')
|
||||||
|
msg.classList = 'msg-valid valid-reference_index';
|
||||||
|
div.append(msg);
|
||||||
|
|
||||||
|
referenceSending.append(div);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderResponsibleUser(responsibleUser, countFilial) {
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.classList = 'form-group mb-2';
|
||||||
|
|
||||||
|
var label = document.createElement('label');
|
||||||
|
label.innerHTML = 'ФИО пациента:';
|
||||||
|
label.classList = 'mb-0';
|
||||||
|
label.setAttribute('for', 'reference_patientName_' + countFilial)
|
||||||
|
div.append(label);
|
||||||
|
|
||||||
|
var input = document.createElement('input');
|
||||||
|
input.id = 'reference_patientName_' + countFilial
|
||||||
|
input.name = 'reference_patientName[' + countFilial + ']'
|
||||||
|
input.classList = 'form-control';
|
||||||
|
div.append(input);
|
||||||
|
|
||||||
|
var msg = document.createElement('div')
|
||||||
|
msg.classList = 'msg-valid valid-reference_patientName';
|
||||||
|
div.append(msg);
|
||||||
|
responsibleUser.append(div);
|
||||||
|
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.classList = 'form-group mb-2';
|
||||||
|
|
||||||
|
var label = document.createElement('label');
|
||||||
|
label.innerHTML = 'Дата рождения пациента:';
|
||||||
|
label.classList = 'mb-0';
|
||||||
|
label.setAttribute('for', 'reference_patientBirthDate_' + countFilial)
|
||||||
|
div.append(label);
|
||||||
|
|
||||||
|
var input = document.createElement('input');
|
||||||
|
input.id = 'reference_patientBirthDate_' + countFilial;
|
||||||
|
input.name = 'reference_patientBirthDate[' + countFilial + ']'
|
||||||
|
input.classList = 'form-control';
|
||||||
|
input.dataset.controller = 'datePicker';
|
||||||
|
input.setAttribute('range', false);
|
||||||
|
div.append(input);
|
||||||
|
responsibleUser.append(div);
|
||||||
|
|
||||||
|
var msg = document.createElement('div')
|
||||||
|
msg.classList = 'msg-valid valid-reference_patientBirthDate';
|
||||||
|
div.append(msg);
|
||||||
|
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.classList = 'form-group mb-2';
|
||||||
|
|
||||||
|
var label = document.createElement('label');
|
||||||
|
label.innerHTML = 'Степень родства:';
|
||||||
|
label.classList = 'mb-0';
|
||||||
|
label.setAttribute('for', 'reference_relation_' + countFilial)
|
||||||
|
div.append(label);
|
||||||
|
|
||||||
|
var select = document.createElement('select');
|
||||||
|
select.id = 'reference_relation_' + countFilial;
|
||||||
|
select.name = 'reference_relation_[' + countFilial + ']'
|
||||||
|
select.classList = 'form-control';
|
||||||
|
div.append(select);
|
||||||
|
|
||||||
|
var option = document.createElement('option');
|
||||||
|
option.innerHTML = 'супруг';
|
||||||
|
option.value = 'супруг';
|
||||||
|
select.append(option);
|
||||||
|
|
||||||
|
var option = document.createElement('option');
|
||||||
|
option.innerHTML = 'супруга';
|
||||||
|
option.value = 'супруга';
|
||||||
|
select.append(option);
|
||||||
|
|
||||||
|
var option = document.createElement('option');
|
||||||
|
option.innerHTML = 'мать';
|
||||||
|
option.value = 'мать';
|
||||||
|
select.append(option);
|
||||||
|
|
||||||
|
var option = document.createElement('option');
|
||||||
|
option.innerHTML = 'отец';
|
||||||
|
option.value = 'отeц';
|
||||||
|
select.append(option);
|
||||||
|
|
||||||
|
var option = document.createElement('option');
|
||||||
|
option.innerHTML = 'сын';
|
||||||
|
option.value = 'сын';
|
||||||
|
select.append(option);
|
||||||
|
|
||||||
|
var option = document.createElement('option');
|
||||||
|
option.innerHTML = 'дочь';
|
||||||
|
option.value = 'дочь';
|
||||||
|
select.append(option);
|
||||||
|
|
||||||
|
var msg = document.createElement('div')
|
||||||
|
msg.classList = 'msg-valid valid-reference_relation';
|
||||||
|
div.append(msg);
|
||||||
|
|
||||||
|
responsibleUser.append(div);
|
||||||
|
}
|
||||||
|
|
||||||
|
submit(wrapper) {
|
||||||
|
var valid, invalid = false;
|
||||||
|
var options = {};
|
||||||
|
options.autorName = wrapper.querySelector('#reference_autorName').value;
|
||||||
|
|
||||||
|
valid = validator.checkTextRu(
|
||||||
|
wrapper.querySelector('#reference_autorName'),
|
||||||
|
wrapper.querySelector(`.valid-reference_autorName`)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
invalid = valid
|
||||||
|
}
|
||||||
|
|
||||||
|
options.phone = wrapper.querySelector('#reference_phone').value;
|
||||||
|
|
||||||
|
valid = validator.checkPhone(
|
||||||
|
wrapper.querySelector('#reference_phone'),
|
||||||
|
wrapper.querySelector(`.valid-reference_phone`)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
invalid = valid
|
||||||
|
}
|
||||||
|
|
||||||
|
options.birthDate = wrapper.querySelector('#reference_birthDate').value;
|
||||||
|
|
||||||
|
valid = validator.checkDate(
|
||||||
|
wrapper.querySelector('#reference_birthDate'),
|
||||||
|
wrapper.querySelector(`.valid-reference_birthDate`)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
invalid = valid
|
||||||
|
}
|
||||||
|
|
||||||
|
options.inn = wrapper.querySelector('#reference_inn').value;
|
||||||
|
|
||||||
|
valid = validator.checkInn(
|
||||||
|
wrapper.querySelector('#reference_inn'),
|
||||||
|
wrapper.querySelector(`.valid-reference_inn`)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
invalid = valid
|
||||||
|
}
|
||||||
|
|
||||||
|
options.filials = {};
|
||||||
|
|
||||||
|
wrapper.querySelectorAll('.responsible_filials').forEach(function(el, index) {
|
||||||
|
options.filials[index] = {};
|
||||||
|
|
||||||
|
if (index == 0) {
|
||||||
|
options.filials[index]['filial'] = el.querySelector('#reference_filial').value;
|
||||||
|
|
||||||
|
valid = validator.checkNotEmpty(
|
||||||
|
el.querySelector('#reference_filial'),
|
||||||
|
el.querySelector('.valid-reference_filial')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
invalid = valid
|
||||||
|
}
|
||||||
|
|
||||||
|
options.filials[index]['periodFirst'] = el.querySelector('#reference_periodFirst').value;
|
||||||
|
options.filials[index]['periodLast'] = el.querySelector('#reference_periodLast').value;
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
invalid = valid
|
||||||
|
}
|
||||||
|
|
||||||
|
var reference_responsible = '#reference_responsible';
|
||||||
|
} else {
|
||||||
|
options.filials[index]['filial'] = el.querySelector('#reference_filial_'+ index).value;
|
||||||
|
options.filials[index]['periodFirst'] = document.querySelector('#reference_periodFirst_'+ index).value
|
||||||
|
options.filials[index]['periodLast'] = document.querySelector('#reference_periodLast_'+ index).value
|
||||||
|
|
||||||
|
valid = validator.checkNotEmpty(
|
||||||
|
el.querySelector('#reference_filial_' + index),
|
||||||
|
el.querySelector('.valid-reference_filial')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
invalid = valid
|
||||||
|
}
|
||||||
|
|
||||||
|
var reference_responsible = '#reference_responsible_'+ index
|
||||||
|
}
|
||||||
|
|
||||||
|
options.filials[index]['responsible'] = el.querySelector(reference_responsible).value;
|
||||||
|
|
||||||
|
if (el.querySelector(reference_responsible).value == 0) {
|
||||||
|
|
||||||
|
options.filials[index]['fio'] = el.querySelector('#reference_patientName_'+ index).value;
|
||||||
|
|
||||||
|
valid = validator.checkTextRu(
|
||||||
|
el.querySelector('#reference_patientName_'+ index),
|
||||||
|
el.querySelector(`.valid-reference_patientName`)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
invalid = valid
|
||||||
|
}
|
||||||
|
|
||||||
|
options.filials[index]['birthDate'] = el.querySelector('#reference_patientBirthDate_'+ index).value;
|
||||||
|
|
||||||
|
valid = validator.checkDate(
|
||||||
|
el.querySelector('#reference_patientBirthDate_'+ index),
|
||||||
|
el.querySelector(`.valid-reference_patientBirthDate`)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
invalid = valid
|
||||||
|
}
|
||||||
|
|
||||||
|
options.filials[index]['relation'] = el.querySelector('#reference_relation_'+ index).value;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
options.sending = wrapper.querySelector('#reference_sending')?.value ?? '1';
|
||||||
|
|
||||||
|
// Разрешённые варианты: 1 и 2. Всё остальное считаем "1".
|
||||||
|
const sendingInt = parseInt(options.sending, 10);
|
||||||
|
if (sendingInt !== 1 && sendingInt !== 2) {
|
||||||
|
options.sending = '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.sending == 1 || options.sending === '1') {
|
||||||
|
options.filialSending = wrapper.querySelector('#reference_filialSending').value
|
||||||
|
|
||||||
|
valid = validator.checkNotEmpty(
|
||||||
|
wrapper.querySelector('#reference_filialSending'),
|
||||||
|
wrapper.querySelector('.valid-reference_filialSending')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
invalid = valid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {'options': options, 'invalid': invalid};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,438 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
import Cookies from 'js-cookie';
|
||||||
|
const loader = require("./../components/loader.js");
|
||||||
|
const validator = require("./../components/validator.js");
|
||||||
|
const helper = require("./../components/helper.js");
|
||||||
|
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
loader.loadSDK('registration')
|
||||||
|
var registerWrap = this.element;
|
||||||
|
var licenseLink = helper.getLicenseLink(Cookies.get('region'));
|
||||||
|
helper.renderCapcha(registerWrap.querySelector('.d-capcha-start'));
|
||||||
|
registerWrap.querySelectorAll('.license').forEach(function(el) {
|
||||||
|
/* политика */
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.classList = 'form-group';
|
||||||
|
|
||||||
|
var formCheck = document.createElement('div');
|
||||||
|
formCheck.classList = 'form-check';
|
||||||
|
div.append(formCheck);
|
||||||
|
|
||||||
|
var accept = document.createElement('input');
|
||||||
|
accept.classList = "form-check-input";
|
||||||
|
accept.id = "accept";
|
||||||
|
accept.checked = false;
|
||||||
|
accept.type = "checkbox";
|
||||||
|
formCheck.append(accept);
|
||||||
|
|
||||||
|
var license = helper.getLicenseLink(Cookies.get('region'));
|
||||||
|
var label = document.createElement('label');
|
||||||
|
label.setAttribute('for' , 'accept');
|
||||||
|
label.innerHTML = `ознакомлен(а) <a class="underline" href="${licenseLink}" target="_blank">с условиями политики в отношении обработки персональных данных</a>`;
|
||||||
|
|
||||||
|
formCheck.append(label);
|
||||||
|
|
||||||
|
var validAccept = document.createElement('div');
|
||||||
|
validAccept.classList = 'msg-valid valid-accept';
|
||||||
|
div.append(validAccept);
|
||||||
|
|
||||||
|
el.append(div)
|
||||||
|
|
||||||
|
/* согласие */
|
||||||
|
|
||||||
|
var formCheck = document.createElement('div');
|
||||||
|
formCheck.classList = 'form-check';
|
||||||
|
div.append(formCheck);
|
||||||
|
|
||||||
|
var acceptPerson = document.createElement('input');
|
||||||
|
acceptPerson.classList = "form-check-input";
|
||||||
|
acceptPerson.id = "acceptPerson";
|
||||||
|
acceptPerson.checked = false;
|
||||||
|
acceptPerson.type = "checkbox";
|
||||||
|
formCheck.append(acceptPerson);
|
||||||
|
|
||||||
|
var licensePerson = helper.getLicensePersonLink();
|
||||||
|
var labelPerson = document.createElement('label');
|
||||||
|
labelPerson.setAttribute('for' , 'acceptPerson');
|
||||||
|
labelPerson.innerHTML = `даю согласие <a class="underline" href="${licensePerson}" target="_blank">на обработку персональных данных</a>`;
|
||||||
|
|
||||||
|
formCheck.append(labelPerson);
|
||||||
|
|
||||||
|
var validAcceptPerson = document.createElement('div');
|
||||||
|
validAcceptPerson.classList = 'msg-valid valid-acceptPerson';
|
||||||
|
div.append(validAcceptPerson);
|
||||||
|
|
||||||
|
el.append(div)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
btnBack() {
|
||||||
|
var registerWrap = this.element;
|
||||||
|
registerWrap.querySelector('.register-start').classList.remove('d-none');
|
||||||
|
registerWrap.querySelector('.register-init').classList.add('d-none');
|
||||||
|
registerWrap.querySelector('.register-complete').classList.add('d-none');
|
||||||
|
registerWrap.querySelector('.register-complete').dataset.rToken = null;
|
||||||
|
registerWrap.querySelector('.register-complete').dataset.pwdToken = null;
|
||||||
|
|
||||||
|
registerWrap.querySelector('.alert.msg').classList.add('d-none');
|
||||||
|
registerWrap.querySelector('.alert.msg').innerHTML = 'Поля, обозначенные звездочкой (<span class="text-danger">*</span>), обязательны для заполнения';
|
||||||
|
|
||||||
|
var capchaStart = helper.renderCapcha(registerWrap.querySelector('.d-capcha-start'));
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
window.smartCaptcha.reset(capchaStart.dataset.id)
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
btnStart() {
|
||||||
|
var captchaId = this.element.querySelector('#smart-captcha')?.dataset?.id;
|
||||||
|
var valid, invalid = false;
|
||||||
|
var registerWrap = this.element;
|
||||||
|
|
||||||
|
valid = validator.checkPhone(
|
||||||
|
registerWrap.querySelector('#phone'),
|
||||||
|
registerWrap.querySelector(`.valid-phone`)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
invalid = valid
|
||||||
|
}
|
||||||
|
|
||||||
|
valid = validator.checkSmartCaptcha(
|
||||||
|
window.smartCaptcha.getResponse(captchaId),
|
||||||
|
registerWrap.querySelector('.valid-captcha')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
invalid = valid
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validator.checkAccept(registerWrap.querySelector('#accept'),registerWrap.querySelector('.valid-accept'))) {
|
||||||
|
invalid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validator.checkAccept(registerWrap.querySelector('#acceptPerson'),registerWrap.querySelector('.valid-acceptPerson'))) {
|
||||||
|
invalid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invalid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.webSDK.recoveryInit({
|
||||||
|
'login': registerWrap.querySelector('#phone').value.replace(/[^\w\s!?]/g,''),
|
||||||
|
'captcha': window.smartCaptcha.getResponse(captchaId)
|
||||||
|
}).then(function (resolve) {
|
||||||
|
registerWrap.querySelector('.register-start').classList.add('d-none');
|
||||||
|
registerWrap.querySelector('.register-complete').classList.remove('d-none');
|
||||||
|
registerWrap.querySelector('.register-complete').dataset.pwdToken = resolve.data.pwdToken;
|
||||||
|
|
||||||
|
if (resolve.data.message.indexOf('почтовый ящик') != '-1') {
|
||||||
|
registerWrap.querySelector('.emailCode').classList.remove('d-none');
|
||||||
|
registerWrap.querySelector('.alertEmailView').innerHTML = resolve.data.message;
|
||||||
|
registerWrap.querySelector('.register-complete').dataset.type = 'email';
|
||||||
|
} else {
|
||||||
|
registerWrap.querySelector('.smsCode').classList.remove('d-none');
|
||||||
|
registerWrap.querySelector('.alertSmsCode').innerHTML = resolve.data.message;
|
||||||
|
registerWrap.querySelector('.register-complete').dataset.type = 'sms';
|
||||||
|
}
|
||||||
|
|
||||||
|
}).catch(function (e) {
|
||||||
|
if (e.data?.errors?.captcha) {
|
||||||
|
registerWrap.querySelector('.valid-captcha').innerText = e.data?.errors?.captcha?.[0];
|
||||||
|
window.smartCaptcha.reset(captchaId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.data?.message?.includes("не найден в базе данных")) {
|
||||||
|
registerWrap.querySelector('.register-start').classList.add('d-none');
|
||||||
|
registerWrap.querySelector('.register-init').classList.remove('d-none');
|
||||||
|
helper.renderCapcha(registerWrap.querySelector('.d-capcha-init'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
btnReg() {
|
||||||
|
var captchaId = this.element.querySelector('#smart-captcha')?.dataset?.id;
|
||||||
|
var valid, invalid = false;
|
||||||
|
var registerWrap = this.element;
|
||||||
|
|
||||||
|
registerWrap.querySelectorAll('.alert.alert-danger.alert-dismissible').forEach(function(e) {
|
||||||
|
e.remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
var options = {
|
||||||
|
firstName: registerWrap.querySelector('#firstName').value,
|
||||||
|
lastName: registerWrap.querySelector('#lastName').value,
|
||||||
|
middleName: registerWrap.querySelector('#middleName').value
|
||||||
|
};
|
||||||
|
|
||||||
|
for (var key of Object.keys(options)) {
|
||||||
|
valid = validator.checkTextRu(
|
||||||
|
registerWrap.querySelector(`#${key}`),
|
||||||
|
registerWrap.querySelector(`.valid-${key}`)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
invalid = valid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
options.email = registerWrap.querySelector('#email').value;
|
||||||
|
|
||||||
|
valid = validator.checkEmail(
|
||||||
|
registerWrap.querySelector('#email'),
|
||||||
|
registerWrap.querySelector(`.valid-email`)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
invalid = valid
|
||||||
|
}
|
||||||
|
|
||||||
|
options.phone = registerWrap.querySelector('#phone').value;
|
||||||
|
|
||||||
|
valid = validator.checkPhone(
|
||||||
|
registerWrap.querySelector('#phone'),
|
||||||
|
registerWrap.querySelector(`.valid-phone`)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
invalid = valid
|
||||||
|
}
|
||||||
|
|
||||||
|
valid = validator.checkSmartCaptcha(
|
||||||
|
window.smartCaptcha.getResponse(captchaId),
|
||||||
|
registerWrap.querySelector('.valid-captcha')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
invalid = valid
|
||||||
|
}
|
||||||
|
|
||||||
|
var validGender = false;
|
||||||
|
|
||||||
|
registerWrap.querySelectorAll('.gender').forEach(function (el) {
|
||||||
|
if (el.checked) {
|
||||||
|
registerWrap.querySelector('.valid-gender').innerHTML = '';
|
||||||
|
validGender = true;
|
||||||
|
options.gender = el.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!validGender) {
|
||||||
|
registerWrap.querySelector('.valid-gender').innerHTML = '<span class="text-danger">укажите Ваш пол</span>';
|
||||||
|
invalid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerWrap.querySelectorAll('.msg-valid').forEach(function (el) {
|
||||||
|
el.innerHTML = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
window.webSDK.registerInit({
|
||||||
|
firstName: options.firstName,
|
||||||
|
lastName: options.lastName,
|
||||||
|
middleName: options.middleName,
|
||||||
|
birthDate: registerWrap.querySelector('#birthDate').value,
|
||||||
|
email: options.email,
|
||||||
|
phone: options.phone,
|
||||||
|
gender: options.gender,
|
||||||
|
captcha: window.smartCaptcha.getResponse(captchaId)
|
||||||
|
}).then(function(resolve) {
|
||||||
|
registerWrap.querySelector('.register-init').classList.add('d-none');
|
||||||
|
registerWrap.querySelector('.register-complete').classList.remove('d-none');
|
||||||
|
registerWrap.querySelector('.register-complete').dataset.rToken = resolve.data.rToken;
|
||||||
|
|
||||||
|
if (resolve.data && resolve.data.email == 'true') {
|
||||||
|
registerWrap.querySelector('.emailCode').classList.remove('d-none');
|
||||||
|
registerWrap.querySelector('.emailView').innerHTML = options.email;
|
||||||
|
} else {
|
||||||
|
registerWrap.querySelector('.smsCode').classList.remove('d-none');
|
||||||
|
registerWrap.querySelector('.smsView').innerHTML = options.phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
}).catch(function(error) {
|
||||||
|
window.smartCaptcha.reset(captchaId);
|
||||||
|
helper.sendRequest({
|
||||||
|
data: {'error': error, method: 'registerInit'}
|
||||||
|
}, helper.getHostname() + '/api/log', "POST", "json", true, "application/json");
|
||||||
|
|
||||||
|
var registerAlert = document.getElementById('register-alert');
|
||||||
|
|
||||||
|
if (! registerAlert) {
|
||||||
|
var registerAlert = document.createElement('div');
|
||||||
|
registerAlert.classList = 'alert alert-danger alert-dismissible fade';
|
||||||
|
registerAlert.setAttribute('role', 'alert');
|
||||||
|
|
||||||
|
var divMsg = document.createElement('div');
|
||||||
|
divMsg.classList = 'alert-msg';
|
||||||
|
registerAlert.append(divMsg);
|
||||||
|
|
||||||
|
var buttonClose = document.createElement('button');
|
||||||
|
buttonClose.classList = 'close';
|
||||||
|
buttonClose.dataset.dismiss ='alert';
|
||||||
|
buttonClose.setAttribute('aria-label', 'Close');
|
||||||
|
buttonClose.innerHTML = '<span aria-hidden="true">×</span>';
|
||||||
|
registerAlert.append(buttonClose);
|
||||||
|
registerWrap.prepend(registerAlert);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error.data.message) {
|
||||||
|
registerAlert.classList = 'alert alert-danger alert-dismissible fade show';
|
||||||
|
registerAlert.querySelector('.alert-msg').innerHTML = error.data.message;
|
||||||
|
} else {
|
||||||
|
for (var prop in error.data) {
|
||||||
|
if (error.data[prop]) {
|
||||||
|
var el = registerWrap.querySelector('.valid-' + prop)
|
||||||
|
el.innerHTML = error.data[prop];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
btnComplite() {
|
||||||
|
var registerWrap = this.element;
|
||||||
|
|
||||||
|
if (registerWrap.querySelector('.register-complete').dataset.pwdToken !== "null") {
|
||||||
|
var type = registerWrap.querySelector('.register-complete').dataset.type;
|
||||||
|
var code = registerWrap.querySelector('#emailCode');
|
||||||
|
|
||||||
|
if (type == 'sms') {
|
||||||
|
var code = registerWrap.querySelector('#smsCode');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.recoveryComplite(code, type);
|
||||||
|
} else {
|
||||||
|
this.registerComplete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registerComplete() {
|
||||||
|
var registerWrap = this.element;
|
||||||
|
|
||||||
|
window.webSDK.registerComplete({
|
||||||
|
rToken: registerWrap.querySelector('.register-complete').dataset.rToken,
|
||||||
|
emailCode: registerWrap.querySelector('#emailCode').value,
|
||||||
|
smsCode: registerWrap.querySelector('#smsCode').value,
|
||||||
|
password: registerWrap.querySelector('#password').value
|
||||||
|
}).then(function(response) {
|
||||||
|
registerWrap.querySelector('.alert.filter').classList.add('d-none');
|
||||||
|
|
||||||
|
var successAlert = document.createElement('div');
|
||||||
|
successAlert.classList = 'alert alert-success alert-dismissible fade show';
|
||||||
|
successAlert.setAttribute('role', 'alert');
|
||||||
|
|
||||||
|
var divMsg = document.createElement('div');
|
||||||
|
divMsg.classList = 'alert-msg';
|
||||||
|
divMsg.innerHTML = '<p>Регистрация завершена.</p>'
|
||||||
|
+ '<p>' + response.data.text + '</p>';
|
||||||
|
successAlert.append(divMsg);
|
||||||
|
|
||||||
|
var buttonClose = document.createElement('button');
|
||||||
|
buttonClose.classList = 'close';
|
||||||
|
buttonClose.dataset.dismiss ='alert';
|
||||||
|
buttonClose.setAttribute('aria-label', 'Close');
|
||||||
|
buttonClose.innerHTML = '<span aria-hidden="true">×</span>';
|
||||||
|
successAlert.append(buttonClose);
|
||||||
|
document.getElementById('alert-system').prepend(successAlert);
|
||||||
|
registerWrap.querySelector('.register-complete').classList.add('d-none');
|
||||||
|
}).catch(function(error) {
|
||||||
|
helper.sendRequest({
|
||||||
|
data: {'error': error, method: 'registerComplete'}
|
||||||
|
}, helper.getHostname() + '/api/log', "POST", "json", true, "application/json");
|
||||||
|
for (var prop in error.data) {
|
||||||
|
if (error.data[prop]) {
|
||||||
|
var classValid = prop.split('.')[1];
|
||||||
|
|
||||||
|
if (classValid) {
|
||||||
|
var el = registerWrap.querySelector('.valid-' + prop.split('.')[1]);
|
||||||
|
} else {
|
||||||
|
var el = registerWrap.querySelector('.valid-' + prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
el.innerHTML = error.data[prop];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$('html, body').animate({scrollTop:0}, '300');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
recoveryComplite(inputCode, type) {
|
||||||
|
var registerWrap = this.element;
|
||||||
|
var valid, invalid = false;
|
||||||
|
|
||||||
|
valid = validator.checkNotEmpty(
|
||||||
|
inputCode,
|
||||||
|
registerWrap.querySelector('.valid-' + type + 'Code')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
invalid = valid
|
||||||
|
}
|
||||||
|
|
||||||
|
valid = validator.checkNotEmpty(
|
||||||
|
registerWrap.querySelector('#password'),
|
||||||
|
registerWrap.querySelector('.valid-password')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
invalid = valid
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invalid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.webSDK.recoveryComplete({
|
||||||
|
'pwdToken': registerWrap.querySelector('.register-complete').dataset.pwdToken,
|
||||||
|
'password': registerWrap.querySelector('#password').value,
|
||||||
|
'code': inputCode.value
|
||||||
|
}).then(function (result) {
|
||||||
|
registerWrap.querySelector('.alert.msg').classList.add('d-none');
|
||||||
|
|
||||||
|
var successAlert = document.createElement('div');
|
||||||
|
successAlert.classList = 'alert alert-success alert-dismissible fade show';
|
||||||
|
successAlert.setAttribute('role', 'alert');
|
||||||
|
|
||||||
|
var divMsg = document.createElement('div');
|
||||||
|
divMsg.classList = 'alert-msg';
|
||||||
|
divMsg.innerHTML = result.data.message;
|
||||||
|
successAlert.append(divMsg);
|
||||||
|
|
||||||
|
var buttonClose = document.createElement('button');
|
||||||
|
buttonClose.classList = 'close';
|
||||||
|
buttonClose.dataset.dismiss ='alert';
|
||||||
|
buttonClose.setAttribute('aria-label', 'Close');
|
||||||
|
buttonClose.innerHTML = '<span aria-hidden="true">×</span>';
|
||||||
|
successAlert.append(buttonClose);
|
||||||
|
document.getElementById('alert-system').prepend(successAlert);
|
||||||
|
registerWrap.querySelector('.register-complete').classList.add('d-none');
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
method: "POST",
|
||||||
|
crossDomain: false,
|
||||||
|
url: "/forget",
|
||||||
|
contentType: "application/x-www-form-urlencoded",
|
||||||
|
dataType: "json",
|
||||||
|
data: {
|
||||||
|
token: popupBody.dataset.csrf,
|
||||||
|
uid: forget.data.uid,
|
||||||
|
password: forgetPasswd
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).catch(function (e) {
|
||||||
|
helper.sendRequest({
|
||||||
|
data: {'error': e, method: 'recoveryComplete'}
|
||||||
|
}, helper.getHostname() + '/api/log', "POST", "json", true, "application/json");
|
||||||
|
|
||||||
|
var msg = registerWrap.querySelector('.msg');
|
||||||
|
msg.classList.add('alert-danger');
|
||||||
|
msg.classList.remove('filter');
|
||||||
|
|
||||||
|
if (e.data && e.data.error) {
|
||||||
|
msg.innerHTML = e.data.error
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,377 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
import Inputmask from "inputmask";
|
||||||
|
const loader = require("./../components/loader.js");
|
||||||
|
const validator = require("./../components/validator.js");
|
||||||
|
const helper = require("./../components/helper.js");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="resetPassword" attribute will cause
|
||||||
|
* this controller to be executed. The name "resetPassword" comes from the filename:
|
||||||
|
* resetPassword_controller.js -> "resetPassword"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
loader.loadSDK('resetPassword')
|
||||||
|
let resetPasswordSmsCode = true;
|
||||||
|
var popup = document.getElementById('popup');
|
||||||
|
|
||||||
|
if (location.hash == '#recovery' && popup.dataset.recovery == 'true') {
|
||||||
|
popup.dataset.recovery = false;
|
||||||
|
renderForm(window.webSDK);
|
||||||
|
} else {
|
||||||
|
var element = this.element
|
||||||
|
element.addEventListener('click', function() {
|
||||||
|
renderForm(window.webSDK);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderForm(webSDK) {
|
||||||
|
var popup = document.getElementById('popup');
|
||||||
|
popup.querySelector('.modal-title').innerHTML = "Восстановление пароля";
|
||||||
|
var popupBody = popup.querySelector('#popup-body');
|
||||||
|
popupBody.innerHTML = "";
|
||||||
|
|
||||||
|
if (typeof $(popup).modal !== 'undefined') {
|
||||||
|
$(popup).modal('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.classList = 'form-group';
|
||||||
|
|
||||||
|
if (resetPasswordSmsCode) {
|
||||||
|
var label = document.createElement('label');
|
||||||
|
label.setAttribute('for' , 'login-forget');
|
||||||
|
label.innerHTML = 'Телефон пользователя:';
|
||||||
|
div.append(label);
|
||||||
|
|
||||||
|
var input = document.createElement('input');
|
||||||
|
input.classList = "form-control";
|
||||||
|
input.id = "login-forget";
|
||||||
|
input.type = "phone";
|
||||||
|
input.autocomplete = "phone";
|
||||||
|
div.append(input);
|
||||||
|
|
||||||
|
var im = new Inputmask({mask: "7(899)999-99-99",definitions: {'8': {validator: "[9]"}}});
|
||||||
|
im.mask(input);
|
||||||
|
} else {
|
||||||
|
var label = document.createElement('label');
|
||||||
|
label.setAttribute('for' , 'login-forget');
|
||||||
|
label.innerHTML = 'E-mail пользователя:';
|
||||||
|
div.append(label);
|
||||||
|
|
||||||
|
var input = document.createElement('input');
|
||||||
|
input.classList = "form-control";
|
||||||
|
input.id = "login-forget";
|
||||||
|
input.autocomplete = "email";
|
||||||
|
input.type = "email";
|
||||||
|
div.append(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
var validUsername = document.createElement('div');
|
||||||
|
validUsername.classList = "msg-valid valid-login-forget";
|
||||||
|
div.append(validUsername);
|
||||||
|
|
||||||
|
if (resetPasswordSmsCode) {
|
||||||
|
var p = document.createElement('p');
|
||||||
|
p.innerHTML = "На Ваш номер телефона будет отправлен код для восстановления пароля."
|
||||||
|
popupBody.append(p);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
var p = document.createElement('p');
|
||||||
|
p.innerHTML = "На Вашу электронную почту будет отправлен код для восстановления пароля."
|
||||||
|
popupBody.append(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
var msg = document.createElement('div');
|
||||||
|
msg.classList = 'd-none msg';
|
||||||
|
msg.innerHTML = '';
|
||||||
|
popupBody.append(div);
|
||||||
|
popupBody.append(msg);
|
||||||
|
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.classList = 'form-group';
|
||||||
|
|
||||||
|
var recaptcha = document.createElement('div');
|
||||||
|
recaptcha.id = "smart-captcha";
|
||||||
|
recaptcha.dataset.controller = "smartCaptcha";
|
||||||
|
div.append(recaptcha);
|
||||||
|
|
||||||
|
var validRecaptcha = document.createElement('div');
|
||||||
|
validRecaptcha.classList = "msg-valid valid-captcha";
|
||||||
|
div.append(validRecaptcha);
|
||||||
|
popupBody.append(div);
|
||||||
|
|
||||||
|
var button = document.createElement('button');
|
||||||
|
button.classList = "btn btn-primary";
|
||||||
|
button.innerHTML = "Восстановить"
|
||||||
|
button.addEventListener('click', function () {
|
||||||
|
|
||||||
|
loader.btnLoader(button, true);
|
||||||
|
resetPassword(webSDK, popup)
|
||||||
|
});
|
||||||
|
|
||||||
|
var footer = document.createElement('div');
|
||||||
|
footer.classList = 'modal-footer px-0';
|
||||||
|
|
||||||
|
footer.append(button);
|
||||||
|
popupBody.append(footer);
|
||||||
|
};
|
||||||
|
|
||||||
|
function resetPassword(webSDK, popup) {
|
||||||
|
var popupBody = popup.querySelector('#popup-body');
|
||||||
|
|
||||||
|
var valid, invalid = false;
|
||||||
|
if (resetPasswordSmsCode) {
|
||||||
|
valid = validator.checkPhone(
|
||||||
|
document.getElementById('login-forget'),
|
||||||
|
document.querySelector(`.valid-login-forget`)
|
||||||
|
);
|
||||||
|
|
||||||
|
var login = document.getElementById('login-forget').value.replace(/[^\w\s!?]/g,'');
|
||||||
|
} else {
|
||||||
|
valid = validator.checkEmail(
|
||||||
|
document.getElementById('login-forget'),
|
||||||
|
document.querySelector(`.valid-login-forget`)
|
||||||
|
);
|
||||||
|
|
||||||
|
var login = document.getElementById('login-forget').value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
invalid = valid
|
||||||
|
}
|
||||||
|
|
||||||
|
valid = validator.checkSmartCaptcha(
|
||||||
|
window.smartCaptcha.getResponse(),
|
||||||
|
document.querySelector('.valid-captcha')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
invalid = valid
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invalid) {
|
||||||
|
loader.btnLoader(popupBody.querySelector('button'), false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
async : false,
|
||||||
|
method: "POST",
|
||||||
|
crossDomain: true,
|
||||||
|
url: helper.getHostname() + "/forget",
|
||||||
|
contentType: "application/x-www-form-urlencoded",
|
||||||
|
dataType: "json",
|
||||||
|
data: {
|
||||||
|
token: popupBody.dataset.csrf,
|
||||||
|
login: login
|
||||||
|
},
|
||||||
|
success(response) {
|
||||||
|
window.webSDK.recoveryInit({
|
||||||
|
'login': login,
|
||||||
|
'captcha': window.smartCaptcha.getResponse()
|
||||||
|
}).then(function (resolve) {
|
||||||
|
renderFormConfirm(webSDK, popup, resolve, response);
|
||||||
|
}).catch(function (e) {
|
||||||
|
helper.sendRequest({
|
||||||
|
data: {'error': e, method: 'recoveryInit'}
|
||||||
|
}, helper.getHostname() + '/api/log', "POST");
|
||||||
|
|
||||||
|
window.smartCaptcha.reset();
|
||||||
|
|
||||||
|
if (e.data?.errors?.captcha) {
|
||||||
|
document.querySelector('.valid-captcha').innerText = e.data?.errors?.captcha?.[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
loader.btnLoader(popupBody.querySelector('button'), false);
|
||||||
|
|
||||||
|
if (e.data?.message) {
|
||||||
|
var msg = popupBody.querySelector('.msg');
|
||||||
|
msg.classList = 'alert alert-danger';
|
||||||
|
msg.innerHTML = e.data.message;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function renderFormConfirm(webSDK, popup, resolve, forget) {
|
||||||
|
var popupBody = popup.querySelector('#popup-body');
|
||||||
|
popupBody.innerHTML = "";
|
||||||
|
|
||||||
|
var message = document.createElement('p');
|
||||||
|
message.innerHTML = resolve.data.message;
|
||||||
|
popupBody.append(message);
|
||||||
|
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.classList = 'form-group';
|
||||||
|
|
||||||
|
var label = document.createElement('label');
|
||||||
|
label.setAttribute('for' , 'forget-code');
|
||||||
|
label.innerHTML = 'Код подтверждения:';
|
||||||
|
div.append(label);
|
||||||
|
|
||||||
|
var input = document.createElement('input');
|
||||||
|
input.classList = "form-control";
|
||||||
|
input.id = "forget-code";
|
||||||
|
input.autocomplete = "one-time-code";
|
||||||
|
input.autocorrect = "off";
|
||||||
|
input.spellcheck = "off";
|
||||||
|
input.type = "text";
|
||||||
|
div.append(input);
|
||||||
|
|
||||||
|
var divValidCode = document.createElement('div');
|
||||||
|
divValidCode.classList = "msg-valid valid-code";
|
||||||
|
div.append(divValidCode);
|
||||||
|
popupBody.append(div);
|
||||||
|
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.classList = 'form-group';
|
||||||
|
|
||||||
|
var label = document.createElement('label');
|
||||||
|
label.setAttribute('for' , 'forget-passwd');
|
||||||
|
label.innerHTML = 'Новый пароль:';
|
||||||
|
div.append(label);
|
||||||
|
|
||||||
|
var input = document.createElement('input');
|
||||||
|
input.classList = "form-control";
|
||||||
|
input.id = "forget-passwd";
|
||||||
|
input.autocomplete = "new-password";
|
||||||
|
input.type = "password";
|
||||||
|
div.append(input);
|
||||||
|
|
||||||
|
var divValidPass = document.createElement('div');
|
||||||
|
divValidPass.classList = "msg-valid valid-password";
|
||||||
|
divValidPass.innerHTML = "не менее 7 символов";
|
||||||
|
div.append(divValidPass);
|
||||||
|
popupBody.append(div);
|
||||||
|
|
||||||
|
var msg = document.createElement('div');
|
||||||
|
msg.classList = 'd-none alert alert-danger';
|
||||||
|
msg.innerHTML = '';
|
||||||
|
popupBody.append(msg);
|
||||||
|
|
||||||
|
var button = document.createElement('button');
|
||||||
|
button.classList = "btn btn-primary";
|
||||||
|
button.innerHTML = " Сохранить изменения";
|
||||||
|
button.addEventListener('click', function () {
|
||||||
|
popupBody.querySelectorAll('.msg-valid').forEach(function(el) {
|
||||||
|
el.innerHTML = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
var invalid = false;
|
||||||
|
var forgetCode = document.getElementById('forget-code').value;
|
||||||
|
|
||||||
|
if (forgetCode === '') {
|
||||||
|
popupBody.querySelector('.valid-code')
|
||||||
|
.innerHTML = '<span class="text-danger">поле не может быть пустым</span>';
|
||||||
|
popupBody.querySelector('#forget-code').classList.add('is-invalid');
|
||||||
|
popupBody.querySelector('#forget-code').classList.remove('is-valid');
|
||||||
|
invalid = true;
|
||||||
|
} else {
|
||||||
|
popupBody.querySelector('#forget-code').classList.add('is-valid');
|
||||||
|
popupBody.querySelector('#forget-code').classList.remove('is-invalid');
|
||||||
|
}
|
||||||
|
|
||||||
|
var forgetPasswd = document.getElementById('forget-passwd').value;
|
||||||
|
|
||||||
|
if (forgetPasswd.length < 6 || /^[\u0400-\u04FF]+$/.test(forgetPasswd)) {
|
||||||
|
invalid = true;
|
||||||
|
|
||||||
|
if (/^[\u0400-\u04FF]+$/.test(forgetPasswd)) {
|
||||||
|
popupBody.querySelector('.valid-password')
|
||||||
|
.innerHTML = '<span class="text-danger">поле не должно содержать кириллицы</span>';
|
||||||
|
popupBody.querySelector('#forget-passwd').classList.add('is-invalid');
|
||||||
|
popupBody.querySelector('#forget-passwd').classList.remove('is-valid');
|
||||||
|
} else {
|
||||||
|
popupBody.querySelector('.valid-password')
|
||||||
|
.innerHTML = '<span class="text-danger">не менее 7 символов</span>';
|
||||||
|
popupBody.querySelector('#forget-passwd').classList.add('is-invalid');
|
||||||
|
popupBody.querySelector('#forget-passwd').classList.remove('is-valid');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
popupBody.querySelector('#forget-passwd').classList.add('is-valid');
|
||||||
|
popupBody.querySelector('#forget-passwd').classList.remove('is-invalid');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invalid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.webSDK.recoveryComplete({
|
||||||
|
'pwdToken': resolve.data.pwdToken,
|
||||||
|
'password': forgetPasswd,
|
||||||
|
'code': document.getElementById('forget-code').value
|
||||||
|
}).then(function (result) {
|
||||||
|
if (result.data.errors) {
|
||||||
|
if (result.data.errors.code) {
|
||||||
|
popupBody.querySelector('.valid-code').innerHTML = `<span class="text-danger">
|
||||||
|
${result.data.errors.code}</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
popupBody.innerHTML = '';
|
||||||
|
var msg = document.createElement('div');
|
||||||
|
msg.classList = 'alert alert-success';
|
||||||
|
msg.innerHTML = result.data.message;
|
||||||
|
popupBody.append(msg);
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
method: "POST",
|
||||||
|
crossDomain: true,
|
||||||
|
url: helper.getHostname() + "/forget",
|
||||||
|
contentType: "application/x-www-form-urlencoded",
|
||||||
|
dataType: "json",
|
||||||
|
data: {
|
||||||
|
token: popupBody.dataset.csrf,
|
||||||
|
uid: forget.data.uid,
|
||||||
|
password: forgetPasswd
|
||||||
|
},
|
||||||
|
success(response) {
|
||||||
|
if (response.data.success == true) {
|
||||||
|
var parser = document.createElement('a');
|
||||||
|
parser.href = response.data.redirect;
|
||||||
|
window.location.replace(document.location.origin + parser.pathname + parser.search);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).catch(function (e) {
|
||||||
|
helper.sendRequest({
|
||||||
|
data: {'error': e, method: 'recoveryComplete'}
|
||||||
|
}, helper.getHostname() + '/api/log', "POST");
|
||||||
|
|
||||||
|
if (e.data && e.data.error) {
|
||||||
|
msg.innerHTML = e.data.error
|
||||||
|
msg.classList.remove('d-none');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var footer = document.createElement('div');
|
||||||
|
footer.classList = 'modal-footer';
|
||||||
|
footer.append(button);
|
||||||
|
popupBody.append(footer);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="default" attribute will cause
|
||||||
|
* this controller to be executed. The name "default" comes from the filename:
|
||||||
|
* default_controller.js -> "default"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
var btn = this.element;
|
||||||
|
|
||||||
|
$(window).scroll(function() {
|
||||||
|
if ($(window).scrollTop() > 300) {
|
||||||
|
btn.classList.remove('d-none')
|
||||||
|
} else {
|
||||||
|
btn.classList.add('d-none')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
btn.addEventListener('click', function(e) {
|
||||||
|
$('html, body').animate({scrollTop:0}, '300');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelForm() {
|
||||||
|
const mainSearchInput = document.querySelector('[data-controller="searchNameInput"]');
|
||||||
|
if (mainSearchInput) {
|
||||||
|
mainSearchInput.value = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const showContent = document.querySelector('.show-content');
|
||||||
|
if (showContent) {
|
||||||
|
showContent.classList.add('d-none');
|
||||||
|
showContent.innerHTML = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
searchForm() {
|
||||||
|
// Вызываем глобальную функцию из searchNameInput контроллера
|
||||||
|
if (typeof window.performSearch === 'function') {
|
||||||
|
window.performSearch();
|
||||||
|
} else {
|
||||||
|
// Fallback: делаем редирект вручную
|
||||||
|
const input = document.querySelector('[data-controller="searchNameInput"]');
|
||||||
|
const selectSearch = document.getElementById("select-search").value;
|
||||||
|
const searchValue = input ? input.value.trim() : '';
|
||||||
|
|
||||||
|
if (searchValue) {
|
||||||
|
const encodedValue = encodeURIComponent(searchValue);
|
||||||
|
// Извлекаем alias из текущего URL, если он есть
|
||||||
|
const currentPath = window.location.pathname;
|
||||||
|
const aliasMatch = currentPath.match(/\/specialists\/([^\/]+)/);
|
||||||
|
const alias = aliasMatch ? aliasMatch[1] : null;
|
||||||
|
|
||||||
|
let url;
|
||||||
|
|
||||||
|
if (selectSearch === 'name') {
|
||||||
|
const baseUrl = alias ? `/specialists/${alias}` : '/specialists';
|
||||||
|
url = `${baseUrl}?specialist_search%5Bname%5D=${encodedValue}`;
|
||||||
|
} else if (selectSearch === 'pl') {
|
||||||
|
url = `/stoimost-uslug?price_list_form%5Bschname%5D=${encodedValue}`;
|
||||||
|
} else if (selectSearch === 'department') {
|
||||||
|
const baseUrl = alias ? `/specialists/${alias}` : '/specialists';
|
||||||
|
url = `${baseUrl}?specialist_search%5Bdepartment%5D=${encodedValue}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
window.location.href = url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('searchForm вызван');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
const helper = require("./../components/helper.js");
|
||||||
|
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
let showContent = this.element.parentElement.querySelector('.show-content');
|
||||||
|
const input = this.element;
|
||||||
|
|
||||||
|
const searchConfig = {
|
||||||
|
'name': {
|
||||||
|
url: '/specialists',
|
||||||
|
paramName: 'specialist_search[name]',
|
||||||
|
encodedParam: 'specialist_search%5Bname%5D'
|
||||||
|
},
|
||||||
|
'pl': {
|
||||||
|
url: '/stoimost-uslug',
|
||||||
|
paramName: 'price_list_form[schname]',
|
||||||
|
encodedParam: 'price_list_form%5Bschname%5D'
|
||||||
|
},
|
||||||
|
'dep': {
|
||||||
|
url: '/specialists',
|
||||||
|
paramName: 'specialist_search[depname]',
|
||||||
|
encodedParam: 'specialist_search%5Bdepname%5D'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const performSearch = () => {
|
||||||
|
const selectSearch = document.getElementById("select-search").value;
|
||||||
|
const searchValue = input.value.trim();
|
||||||
|
|
||||||
|
if (!searchValue) return;
|
||||||
|
|
||||||
|
const config = searchConfig[selectSearch];
|
||||||
|
if (!config) return;
|
||||||
|
|
||||||
|
// Извлекаем alias из текущего URL, если он есть
|
||||||
|
const currentPath = window.location.pathname;
|
||||||
|
const aliasMatch = currentPath.match(/\/specialists\/([^\/]+)/);
|
||||||
|
const alias = aliasMatch ? aliasMatch[1] : null;
|
||||||
|
|
||||||
|
// Создаем URL с параметром поиска, сохраняя alias если он есть
|
||||||
|
const encodedValue = encodeURIComponent(searchValue);
|
||||||
|
let baseUrl = config.url;
|
||||||
|
if (alias && (selectSearch === 'name' || selectSearch === 'dep')) {
|
||||||
|
baseUrl = `/specialists/${alias}`;
|
||||||
|
}
|
||||||
|
const searchUrl = `${baseUrl}?${config.encodedParam}=${encodedValue}`;
|
||||||
|
|
||||||
|
console.log('Редирект на:', searchUrl);
|
||||||
|
window.location.href = searchUrl;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Функция для автодополнения (при вводе 3+ символов)
|
||||||
|
const handleAutocomplete = (searchValue, selectSearch) => {
|
||||||
|
const onlineMode = location.pathname.includes('/online-specialists') ? 1 : 0;
|
||||||
|
|
||||||
|
if (searchValue.length >= 3 && selectSearch !== 'pl') {
|
||||||
|
let data = {
|
||||||
|
q: searchValue,
|
||||||
|
type: selectSearch,
|
||||||
|
onlineMode: onlineMode
|
||||||
|
};
|
||||||
|
|
||||||
|
showContent.innerText = '';
|
||||||
|
showContent.classList.add('d-none');
|
||||||
|
|
||||||
|
helper.sendRequest(data, "/api/search", "POST").then(function (response) {
|
||||||
|
showContent.innerHTML = '';
|
||||||
|
const ul = document.createElement('ul');
|
||||||
|
const { data: searchData } = response;
|
||||||
|
|
||||||
|
const listItemsHTML = searchData.map(el => {
|
||||||
|
const { alias, name, speciality } = el;
|
||||||
|
const config = searchConfig[selectSearch];
|
||||||
|
|
||||||
|
let url;
|
||||||
|
// Извлекаем alias из текущего URL, если он есть
|
||||||
|
const currentPath = window.location.pathname;
|
||||||
|
const currentAliasMatch = currentPath.match(/\/specialists\/([^\/]+)/);
|
||||||
|
const currentAlias = currentAliasMatch ? currentAliasMatch[1] : null;
|
||||||
|
|
||||||
|
if (selectSearch === 'name') {
|
||||||
|
url = `/specialist/${alias}?specialist_search[onlineMode]=${onlineMode}`;
|
||||||
|
} else if (selectSearch === 'pl') {
|
||||||
|
url = `/stoimost-uslug?${config.encodedParam}=${encodeURIComponent(name)}`;
|
||||||
|
} else if (selectSearch === 'dep') {
|
||||||
|
// Сохраняем текущий alias при поиске по отделению
|
||||||
|
const depUrl = currentAlias ? `/specialists/${currentAlias}` : '/specialists';
|
||||||
|
url = `${depUrl}?${config.encodedParam}=${encodeURIComponent(name)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `
|
||||||
|
<li>
|
||||||
|
<a href="${url}" class="search-result-link">
|
||||||
|
<span class="result-name">${name}</span>
|
||||||
|
${speciality ? `<span class="result-speciality">, ${speciality}</span>` : ''}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
`;
|
||||||
|
}).join('');
|
||||||
|
|
||||||
|
ul.innerHTML = listItemsHTML;
|
||||||
|
showContent.append(ul);
|
||||||
|
showContent.classList.remove('d-none');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
showContent.classList.add('d-none');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Обработчик ввода в поле поиска
|
||||||
|
input.oninput = function(e) {
|
||||||
|
const selectSearch = document.getElementById("select-search").value;
|
||||||
|
const searchValue = e.target.value;
|
||||||
|
|
||||||
|
handleAutocomplete(searchValue, selectSearch);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Обработчик нажатия Enter
|
||||||
|
input.addEventListener('keyup', function (evn) {
|
||||||
|
if (evn.keyCode == 13) { // Enter
|
||||||
|
evn.preventDefault();
|
||||||
|
performSearch();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Делаем функцию доступной глобально для другого контроллера
|
||||||
|
window.performSearch = performSearch;
|
||||||
|
window.handleAutocomplete = handleAutocomplete;
|
||||||
|
|
||||||
|
// Инициализация значения из текущего параметра URL
|
||||||
|
this.initializeFromUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Метод для инициализации значения поля из параметров URL
|
||||||
|
initializeFromUrl() {
|
||||||
|
const input = this.element;
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
const selectSearch = document.getElementById("select-search").value;
|
||||||
|
|
||||||
|
const searchConfig = {
|
||||||
|
'name': ['specialist_search[name]', 'specialist_search%5Bname%5D'],
|
||||||
|
'pl': ['price_list_form[schname]', 'price_list_form%5Bschname%5D'],
|
||||||
|
'department': ['specialist_search[department]', 'specialist_search%5Bdepartment%5D']
|
||||||
|
};
|
||||||
|
|
||||||
|
const config = searchConfig[selectSearch];
|
||||||
|
if (config) {
|
||||||
|
// Пробуем получить значение из разных вариантов параметра
|
||||||
|
let searchValue = urlParams.get(config[0]) ||
|
||||||
|
urlParams.get(config[1]) ||
|
||||||
|
urlParams.get(decodeURIComponent(config[1]));
|
||||||
|
|
||||||
|
if (searchValue) {
|
||||||
|
input.value = searchValue;
|
||||||
|
|
||||||
|
// Если есть значение, показываем автодополнение
|
||||||
|
setTimeout(() => {
|
||||||
|
window.handleAutocomplete && window.handleAutocomplete(searchValue, selectSearch);
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="searchOrderByInput" attribute will cause
|
||||||
|
* this controller to be executed. The name "searchOrderByInput" comes from the filename:
|
||||||
|
* searchOrderByInput_controller.js -> "searchOrderByInput"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
var val = document.getElementById("specialist_search_order_by").value;
|
||||||
|
var items = this.element.querySelectorAll('span');
|
||||||
|
|
||||||
|
if (val) {
|
||||||
|
check(val, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
items.forEach(function(el) {
|
||||||
|
el.addEventListener('click', function(evn) {
|
||||||
|
check(evn.target.id, true);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
function check(index, redirect) {
|
||||||
|
console.log(index)
|
||||||
|
var array = index.split('.');
|
||||||
|
var id = array[0];
|
||||||
|
var sort = array[1];
|
||||||
|
|
||||||
|
items.forEach(function(item) {
|
||||||
|
var iconASC = item.querySelector('.fa-sort-amount-asc');
|
||||||
|
var iconDESC = item.querySelector('.fa-sort-amount-desc');
|
||||||
|
|
||||||
|
item.classList.remove('sort-line__item--active');
|
||||||
|
|
||||||
|
if (id == item.id) {
|
||||||
|
item.classList.add('sort-line__item--active');
|
||||||
|
|
||||||
|
if (sort == 'desc') {
|
||||||
|
item.classList.remove('asc');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.classList.contains('asc')) {
|
||||||
|
iconASC.classList.remove('d-none');
|
||||||
|
iconDESC.classList.add('d-none');
|
||||||
|
item.classList.remove('asc');
|
||||||
|
document.getElementById("specialist_search_order_by").value = item.id + '.asc';
|
||||||
|
|
||||||
|
if (redirect) {
|
||||||
|
document.querySelector('.submit-filter').click();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
iconDESC.classList.remove('d-none');
|
||||||
|
iconASC.classList.add('d-none');
|
||||||
|
item.classList.add('asc');
|
||||||
|
document.getElementById("specialist_search_order_by").value = item.id + '.desc';
|
||||||
|
|
||||||
|
if (redirect) {
|
||||||
|
document.querySelector('.submit-filter').click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
iconDESC.classList.add('d-none');
|
||||||
|
iconASC.classList.add('d-none');
|
||||||
|
item.classList.add('asc');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,377 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
|
||||||
|
const loader = require("./../components/loader.js");
|
||||||
|
const helper = require("./../components/helper.js");
|
||||||
|
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
loader.loadSDK('securityCard').then(function(webSDK) {
|
||||||
|
webSDK.on('init', function() {
|
||||||
|
if (this.data.user.authenticated) {
|
||||||
|
runWebSDK(webSDK);
|
||||||
|
} else {
|
||||||
|
window.location.pathname = '/logout'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
var securityCard = this.element;
|
||||||
|
var date = new Date();
|
||||||
|
var lastDate = new Date(date.getFullYear(), date.getMonth() + 1, 0);
|
||||||
|
|
||||||
|
let runWebSDK = function (webSDK) {
|
||||||
|
if (document.location.search == '?tab=allTest') {
|
||||||
|
securityCard.querySelector('.load').innerHTML = 'Загрузка данных';
|
||||||
|
|
||||||
|
securityTabs.querySelectorAll('a').forEach(function (el) {
|
||||||
|
if ('allTest' == el.dataset.allowTarget) {
|
||||||
|
el.classList.add('tab-item--active');
|
||||||
|
} else {
|
||||||
|
el.classList.remove('tab-item--active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// allTest
|
||||||
|
treatPlaceList(webSDK, lastDate, securityCard, 'all');
|
||||||
|
} else {
|
||||||
|
treatPlaceList(webSDK, lastDate, securityCard, 'all');
|
||||||
|
}
|
||||||
|
}.bind(this)
|
||||||
|
|
||||||
|
var securityTabs = document.getElementById('security-tabs');
|
||||||
|
|
||||||
|
if (securityTabs) {
|
||||||
|
var tabsDecktop = securityTabs.querySelectorAll('a');
|
||||||
|
|
||||||
|
if (tabsDecktop.length > 0) {
|
||||||
|
tabsDecktop.forEach(function (el) {
|
||||||
|
el.addEventListener('click', function (evn) {
|
||||||
|
evn.target.classList = 'tab-item tab-item--active';
|
||||||
|
securityCard.querySelector('.section-wrap').innerHTML = '';
|
||||||
|
securityCard.querySelector('.load').innerHTML = 'Загрузка данных';
|
||||||
|
|
||||||
|
securityTabs.querySelectorAll('a').forEach(function (a) {
|
||||||
|
if (evn.target.dataset.allowTarget != a.dataset.allowTarget) {
|
||||||
|
a.classList.remove('tab-item--active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (evn.target.dataset.allowTarget == 'allTest') {
|
||||||
|
document.title = 'Результаты анализов';
|
||||||
|
document.getElementById('page-title').innerHTML = 'Результаты анализов';
|
||||||
|
} else {
|
||||||
|
document.title = 'Медицинская карта';
|
||||||
|
document.getElementById('page-title').innerHTML = 'Медицинская карта';
|
||||||
|
}
|
||||||
|
|
||||||
|
treatPlaceList(window.webSDK, lastDate, securityCard, evn.target.dataset.allowTarget);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
securityTabs.addEventListener('change', function(evn) {
|
||||||
|
securityCard.querySelector('.section-wrap').innerHTML = '';
|
||||||
|
treatPlaceList(window.webSDK, lastDate, securityCard, evn.target.value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function treatPlaceList(webSDK, lastDate, securityCard, allowTarget) {
|
||||||
|
var sectionWrap = securityCard.querySelector('.section-wrap');
|
||||||
|
var load = securityCard.querySelector('.load');
|
||||||
|
|
||||||
|
if (allowTarget == 'referrals') {
|
||||||
|
webSDK.loadReferralList({
|
||||||
|
start: 0,
|
||||||
|
length: 50
|
||||||
|
}).then(function (refferals) {
|
||||||
|
|
||||||
|
if (refferals.length == 0) {
|
||||||
|
securityCard.querySelector('.load').innerHTML = 'Записей не найдено';
|
||||||
|
}
|
||||||
|
|
||||||
|
refferals.forEach(function (item) {
|
||||||
|
var row = document.createElement('div');
|
||||||
|
row.classList = 'row';
|
||||||
|
|
||||||
|
var col6 = document.createElement('div');
|
||||||
|
col6.classList = 'col-md-6';
|
||||||
|
|
||||||
|
var dateTag = document.createElement('p');
|
||||||
|
dateTag.innerHTML = '<p><b><span class="month"></span>, <span class="date"></span></b></p><p class="refname"></p><p class="fromfname"></p>';
|
||||||
|
col6.append(dateTag);
|
||||||
|
row.append(col6);
|
||||||
|
|
||||||
|
var col6 = document.createElement('div');
|
||||||
|
col6.classList = 'col-md-6';
|
||||||
|
col6.innerHTML = '<p class="refcomment"></p><p>Специалист: <br><span class="fromdname"></span></p><p class="refstatusname"></p>';
|
||||||
|
row.append(col6);
|
||||||
|
|
||||||
|
var refferalsItem = document.createElement('div');
|
||||||
|
refferalsItem.classList = 'block-item p-2 mt-1';
|
||||||
|
refferalsItem.append(row);
|
||||||
|
|
||||||
|
refferalsItem.classList.remove('d-none');
|
||||||
|
refferalsItem.querySelector('.refname').innerHTML = item.refname;
|
||||||
|
refferalsItem.querySelector('.refcomment').innerHTML = item.refcomment;
|
||||||
|
refferalsItem.querySelector('.fromfname').innerHTML = item.fromfname;
|
||||||
|
refferalsItem.querySelector('.fromdname').innerHTML = item.fromdname;
|
||||||
|
refferalsItem.querySelector('.refstatusname').innerHTML = item.refstatusname;
|
||||||
|
|
||||||
|
var date = window.newDate(item.refdate);
|
||||||
|
refferalsItem.querySelector('.month').innerHTML = getWeekDay(date);
|
||||||
|
refferalsItem.querySelector('.date').innerHTML = window.dateFormat(date, 'd-m-Y')
|
||||||
|
|
||||||
|
sectionWrap.append(refferalsItem);
|
||||||
|
});
|
||||||
|
}).catch(function (e) {
|
||||||
|
helper.sendRequest({
|
||||||
|
data: {'error': e, method: 'loadReferralList'}
|
||||||
|
}, helper.getHostname() + '/api/log', "POST", "json", true, "application/json");
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
webSDK.loadTreatPlaceList({
|
||||||
|
st: 20150101,
|
||||||
|
en: window.dateFormat(lastDate),
|
||||||
|
start: 0,
|
||||||
|
length: 100
|
||||||
|
}).then(function (resolve) {
|
||||||
|
console.log("loadTreatPlaceList")
|
||||||
|
|
||||||
|
if (resolve.data.length > 0) {
|
||||||
|
var count = 0;
|
||||||
|
load.classList.remove('d-none');
|
||||||
|
|
||||||
|
for (var i = 0; i < resolve.data.length; i++) {
|
||||||
|
if (allowTarget == 'allTest') {
|
||||||
|
if (analysis(resolve.data[i].protocolName)) {
|
||||||
|
count++;
|
||||||
|
sectionWrap.classList.remove('d-none');
|
||||||
|
|
||||||
|
addItem(resolve.data[i], sectionWrap, webSDK);
|
||||||
|
}
|
||||||
|
} else if (allowTarget == 'all') {
|
||||||
|
count = resolve.data.length
|
||||||
|
sectionWrap.classList.remove('d-none');
|
||||||
|
|
||||||
|
addItem(resolve.data[i], sectionWrap, webSDK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
load.classList.add('d-none');
|
||||||
|
|
||||||
|
if (count == 0) {
|
||||||
|
load.classList.remove('d-none');
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
securityCard.querySelector('.load').innerHTML = 'Записей не найдено';
|
||||||
|
load.classList.remove('d-none');
|
||||||
|
}
|
||||||
|
}).catch(function (e) {
|
||||||
|
helper.sendRequest({
|
||||||
|
data: {'error': e, method: 'loadTreatPlaceList'}
|
||||||
|
}, helper.getHostname() + '/api/log', "POST", "json", true, "application/json");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function analysis(protocolName) {
|
||||||
|
const regex = /анализ/gm;
|
||||||
|
let m;
|
||||||
|
var result = false;
|
||||||
|
|
||||||
|
while ((m = regex.exec(protocolName)) !== null) {
|
||||||
|
if (m.index === regex.lastIndex) {
|
||||||
|
regex.lastIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
m.some(function(match, groupIndex) {
|
||||||
|
result = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addItem(item, wrap, webSDK) {
|
||||||
|
wrap.insertAdjacentHTML('beforeend', `
|
||||||
|
<div class="col-md-12 mt-3 px-0">
|
||||||
|
<div class="block-title">${getWeekDay(window.newDate(item.date))} ${window.dateFormat(window.newDate(item.date), 'd-m-Y')}</div>
|
||||||
|
<div class="block-content py-3 col-md-12">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-10 col-sm-12">
|
||||||
|
<b>${item.protocolName}</b>
|
||||||
|
<p class="pt-2">Специалист: <br> ${item.doctorName}</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2 col-sm-12">
|
||||||
|
<button type="button"
|
||||||
|
class="card-item__btn button ${helper.isMobile() ? 'w-100' : ''}"
|
||||||
|
data-protocol-id="${item.protocolId}"
|
||||||
|
data-treatcode="${item.treatcode}">
|
||||||
|
${helper.isMobile() ? 'Скачать' : 'Просмотр'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
|
${item.attachments.length > 0 ? `
|
||||||
|
<div class="card-item__doc mt-2">
|
||||||
|
<p>Список изображений (файлов):</p>
|
||||||
|
${item.attachments.map(attachment => `
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8 d-none d-md-block">
|
||||||
|
${attachment.attachmentName}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-2 col-sm-6">
|
||||||
|
<button type="button" class="button ${helper.isMobile() ? 'w-100' : ''}"
|
||||||
|
data-attachment-type="download"
|
||||||
|
data-attachment-id="${attachment.attachmentId}"
|
||||||
|
data-treatcode="${item.treatcode}"
|
||||||
|
data-protocol-id="${item.protocolId}">
|
||||||
|
Скачать
|
||||||
|
</button></br>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-2 d-none d-md-block">
|
||||||
|
<button type="button" class="button ${helper.isMobile() ? 'w-100' : ''}"
|
||||||
|
data-attachment-type="raw"
|
||||||
|
data-attachment-id="${attachment.attachmentId}"
|
||||||
|
data-treatcode="${item.treatcode}"
|
||||||
|
data-protocol-id="${item.protocolId}">
|
||||||
|
Просмотр
|
||||||
|
</button></br>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`).join('')}
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
|
||||||
|
const cardItem = wrap.lastElementChild;
|
||||||
|
|
||||||
|
if (item.attachments.length > 0) {
|
||||||
|
const attachmentLinks = cardItem.querySelectorAll('button[data-attachment-id]');
|
||||||
|
attachmentLinks.forEach(link => {
|
||||||
|
link.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const popup = document.getElementById('popup');
|
||||||
|
const modalBody = popup.querySelector('.modal-body');
|
||||||
|
modalBody.dataset.attachmentType = this.dataset.attachmentType;
|
||||||
|
modalBody.innerHTML = `
|
||||||
|
<div class="text-center py-4">
|
||||||
|
<div class="spinner-border text-primary" role="status">
|
||||||
|
<span class="visually-hidden">Загрузка...</span>
|
||||||
|
</div>
|
||||||
|
<p class="mt-2">Загрузка файла...</p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
webSDK.downloadTreatPlaceAttachment({
|
||||||
|
protocolId: this.dataset.protocolId,
|
||||||
|
treatcode: this.dataset.treatcode,
|
||||||
|
attachmentId: this.dataset.attachmentId,
|
||||||
|
download: this.dataset.attachmentType
|
||||||
|
}).then(function(blob) {
|
||||||
|
if (modalBody.dataset.attachmentType === 'download') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
modalBody.innerHTML = '';
|
||||||
|
|
||||||
|
const objectURL = URL.createObjectURL(blob.result);
|
||||||
|
|
||||||
|
if (blob.result.type === 'application/pdf' ||
|
||||||
|
blob.result.type === 'application/x-pdf') {
|
||||||
|
|
||||||
|
// Для PDF создаем iframe
|
||||||
|
const iframe = document.createElement('iframe');
|
||||||
|
iframe.src = objectURL;
|
||||||
|
iframe.style.width = "100%";
|
||||||
|
iframe.style.height = "500px";
|
||||||
|
iframe.style.border = "none";
|
||||||
|
iframe.title = "PDF документ";
|
||||||
|
iframe.type = 'application/pdf';
|
||||||
|
|
||||||
|
popup.querySelector('.modal-body').appendChild(iframe);
|
||||||
|
|
||||||
|
} else if (blob.result.type.startsWith('image/')) {
|
||||||
|
// Для изображений создаем img
|
||||||
|
const image = document.createElement('img');
|
||||||
|
image.src = objectURL;
|
||||||
|
image.style.width = "100%";
|
||||||
|
image.style.maxHeight = "80vh";
|
||||||
|
image.style.objectFit = "contain";
|
||||||
|
image.alt = "Изображение";
|
||||||
|
|
||||||
|
popup.querySelector('.modal-body').appendChild(image);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Для других типов файлов - кнопка скачивания
|
||||||
|
const downloadLink = document.createElement('a');
|
||||||
|
downloadLink.href = objectURL;
|
||||||
|
downloadLink.download = 'document';
|
||||||
|
downloadLink.className = 'btn btn-primary';
|
||||||
|
downloadLink.textContent = 'Скачать файл';
|
||||||
|
downloadLink.style.margin = '20px auto';
|
||||||
|
downloadLink.style.display = 'block';
|
||||||
|
downloadLink.style.width = '200px';
|
||||||
|
|
||||||
|
popup.querySelector('.modal-body').appendChild(downloadLink);
|
||||||
|
|
||||||
|
// Также показываем информацию о типе файла
|
||||||
|
const info = document.createElement('p');
|
||||||
|
info.textContent = `Тип файла: ${blob.result.type}`;
|
||||||
|
info.style.textAlign = 'center';
|
||||||
|
popup.querySelector('.modal-body').appendChild(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
$(popup).modal('show');
|
||||||
|
|
||||||
|
// Очистка памяти при закрытии модального окна
|
||||||
|
$(popup).on('hidden.bs.modal', function() {
|
||||||
|
URL.revokeObjectURL(objectURL);
|
||||||
|
$(popup).off('hidden.bs.modal');
|
||||||
|
});
|
||||||
|
|
||||||
|
}).catch(function (e) {
|
||||||
|
console.error('Error downloading file:', e);
|
||||||
|
helper.sendRequest({
|
||||||
|
data: {'error': e, method: 'TreatPlaceAttachment'}
|
||||||
|
}, helper.getHostname() + '/api/log', "POST", "json", true, "application/json");
|
||||||
|
|
||||||
|
popup.querySelector('.modal-body').innerHTML = `
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<h5>Ошибка загрузки файла</h5>
|
||||||
|
<p>${e.message || 'Неизвестная ошибка'}</p>
|
||||||
|
<button class="btn btn-secondary" onclick="$(popup).modal('hide')">Закрыть</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
$(popup).modal('show');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const btnInfo = cardItem.querySelector('.card-item__btn');
|
||||||
|
btnInfo.addEventListener('click', function () {
|
||||||
|
const popup = document.getElementById('popup');
|
||||||
|
popup.querySelector('.modal-body').innerHTML = '';
|
||||||
|
webSDK.loadTreatPlaceView({
|
||||||
|
protocolId: this.dataset.protocolId,
|
||||||
|
treatcode: this.dataset.treatcode,
|
||||||
|
container: popup.querySelector('.modal-body')
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!helper.isMobile()) {
|
||||||
|
$(popup).modal('show');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { Controller } from 'stimulus'
|
||||||
|
import selectpicker from 'bootstrap-select'
|
||||||
|
import 'bootstrap-select/dist/css/bootstrap-select.css'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="selectpicker" attribute will cause
|
||||||
|
* this controller to be executed. The name "selectpicker" comes from the filename:
|
||||||
|
* selectpicker_controller.js -> "selectpicker"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
var placeholder = 'ничего не выбрано'
|
||||||
|
|
||||||
|
if (this.element.dataset.placeholder) {
|
||||||
|
placeholder = this.element.dataset.placeholder;
|
||||||
|
}
|
||||||
|
|
||||||
|
jQuery(this.element).selectpicker({
|
||||||
|
noneSelectedText : placeholder
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="default" attribute will cause
|
||||||
|
* this controller to be executed. The name "default" comes from the filename:
|
||||||
|
* default_controller.js -> "default"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
this.element.addEventListener('click', function () {
|
||||||
|
const popupWrap = document.getElementById('popup');
|
||||||
|
popupWrap.querySelector('.modal-title').textContent = 'Техническая поддержка';
|
||||||
|
popupWrap.querySelector('.modal-dialog').classList.remove('modal-lg');
|
||||||
|
|
||||||
|
const popupBody = popupWrap.querySelector('#popup-body');
|
||||||
|
popupBody.innerHTML = '';
|
||||||
|
|
||||||
|
const iframe = document.createElement('iframe');
|
||||||
|
iframe.src = 'https://sovaclinic.okdesk.ru/webform/issues?account_name=sovaclinic';
|
||||||
|
iframe.frameBorder = 0;
|
||||||
|
iframe.height = "450";
|
||||||
|
iframe.width = "100%";
|
||||||
|
popupBody.append(iframe);
|
||||||
|
|
||||||
|
$(popupWrap).modal('show');
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
const loader = require("./../components/loader.js");
|
||||||
|
const helper = require("./../components/helper.js");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="setting" attribute will cause
|
||||||
|
* this controller to be executed. The name "setting" comes from the filename:
|
||||||
|
* setting_controller.js -> "setting"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
loader.loadSDK('setting');
|
||||||
|
}
|
||||||
|
|
||||||
|
submit() {
|
||||||
|
var plainPassword = document.getElementById('setting_plainPassword');
|
||||||
|
var settingToken = document.getElementById('setting__token');
|
||||||
|
|
||||||
|
window.webSDK.clientModify({
|
||||||
|
'password': plainPassword.value
|
||||||
|
}).then(function(resolve) {
|
||||||
|
if (resolve.success) {
|
||||||
|
$.ajax({
|
||||||
|
method: "POST",
|
||||||
|
crossDomain: false,
|
||||||
|
url: "/setting",
|
||||||
|
contentType: "application/x-www-form-urlencoded",
|
||||||
|
dataType: "json",
|
||||||
|
data: {
|
||||||
|
'setting': {
|
||||||
|
'_token': settingToken.value,
|
||||||
|
'plainPassword': plainPassword.value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
success(response) {
|
||||||
|
if (response.data.success == true) {
|
||||||
|
var parser = document.createElement('a');
|
||||||
|
|
||||||
|
parser.href = response.data.redirect;
|
||||||
|
|
||||||
|
window.location.replace(document.location.origin + parser.pathname + parser.search);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).catch(function (error) {
|
||||||
|
helper.sendRequest({
|
||||||
|
data: {'error': error, method: 'clientModify'}
|
||||||
|
}, helper.getHostname() + '/api/log', "POST", "json", true, "application/json");
|
||||||
|
|
||||||
|
console.log(error)
|
||||||
|
var msg = document.getElementById('msg');
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.classList = 'alert alert-danger';
|
||||||
|
msg.innerHTML = '';
|
||||||
|
msg.append(div);
|
||||||
|
|
||||||
|
if (error.data.password) {
|
||||||
|
var p = document.createElement('p');
|
||||||
|
p.innerHTML = error.data.password[0];
|
||||||
|
div.append(p);
|
||||||
|
} else if (error.data['password.password'][0]) {
|
||||||
|
var p = document.createElement('p');
|
||||||
|
p.innerHTML = error.data['password.password'][0];
|
||||||
|
div.append(p);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,513 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
import { sendReserve } from "./../components/record";
|
||||||
|
import Inputmask from "inputmask";
|
||||||
|
|
||||||
|
const validator = require('./../components/validator.js');
|
||||||
|
const helper = require('./../components/helper.js');
|
||||||
|
const loader = require("./../components/loader.js");
|
||||||
|
const Cookies = require('js-cookie');
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="signin" attribute will cause
|
||||||
|
* this controller to be executed. The name "signin" comes from the filename:
|
||||||
|
* signin_controller.js -> "signin"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
loader.loadSDK('signin').then(function (webSDK) {
|
||||||
|
webSDK.on('init', function() {
|
||||||
|
if (location.hash == '#recovery') {
|
||||||
|
const popup = document.getElementById('popup');
|
||||||
|
|
||||||
|
popup.dataset.controller = 'resetPassword';
|
||||||
|
popup.dataset.recovery = true;
|
||||||
|
|
||||||
|
$(popup).modal('show');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
esia() {
|
||||||
|
const element = this.element
|
||||||
|
|
||||||
|
element.addEventListener('click', function() {
|
||||||
|
const currentUrl = window.location.href;
|
||||||
|
const redirectUrl = helper.addUrlParam(currentUrl, 'esia', 'true');
|
||||||
|
|
||||||
|
window.webSDK.loadLoginView({
|
||||||
|
authType: "esia",
|
||||||
|
redirectUrl: redirectUrl,
|
||||||
|
newWindow: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
login() {
|
||||||
|
function renderAuth(msg = false) {
|
||||||
|
var popup = document.getElementById('popup');
|
||||||
|
|
||||||
|
// Сохраняем данные записи перед очисткой popup (если они есть)
|
||||||
|
if (popup && popup.dataset.reserve === 'true') {
|
||||||
|
const reserveData = {
|
||||||
|
specialistid: popup.dataset.specialistid,
|
||||||
|
filialid: popup.dataset.filialid,
|
||||||
|
depnum: popup.dataset.depnum,
|
||||||
|
schedident: popup.dataset.schedident,
|
||||||
|
workDate: popup.dataset.workDate,
|
||||||
|
time: popup.dataset.time,
|
||||||
|
onlinemode: popup.dataset.onlinemode,
|
||||||
|
comment: popup.dataset.comment,
|
||||||
|
docname: popup.dataset.docname,
|
||||||
|
address: popup.dataset.address,
|
||||||
|
company: popup.dataset.company,
|
||||||
|
rnum: popup.dataset.rnum
|
||||||
|
};
|
||||||
|
// Сохраняем только если есть хотя бы одно поле
|
||||||
|
if (reserveData.specialistid || sessionStorage.getItem('reserveData')) {
|
||||||
|
sessionStorage.setItem('reserveData', JSON.stringify(reserveData));
|
||||||
|
sessionStorage.setItem('reserveFlag', 'true');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var popupBody = popup.querySelector('.modal-title');
|
||||||
|
popupBody.innerText = "Авторизация";
|
||||||
|
|
||||||
|
popupBody = popup.querySelector('#popup-body');
|
||||||
|
popupBody.innerHTML = '';
|
||||||
|
popupBody.dataset.controller = 'signin';
|
||||||
|
|
||||||
|
var validMessage = document.createElement('div');
|
||||||
|
validMessage.classList = "msg-valid valid-message alert alert-danger d-none";
|
||||||
|
|
||||||
|
if (msg) {
|
||||||
|
validMessage.innerHTML = msg;
|
||||||
|
validMessage.classList.remove('d-none');
|
||||||
|
}
|
||||||
|
|
||||||
|
popupBody.append(validMessage);
|
||||||
|
|
||||||
|
var username = document.createElement('input');
|
||||||
|
username.type = "text";
|
||||||
|
username.classList = "form-control border-radius";
|
||||||
|
username.required = "true";
|
||||||
|
username.autofocus = "off";
|
||||||
|
username.autocomplete = "off";
|
||||||
|
username.id = "username";
|
||||||
|
|
||||||
|
var groupPrepend = document.createElement('div');
|
||||||
|
groupPrepend.classList = 'input-group-prepend';
|
||||||
|
|
||||||
|
var select = document.createElement('select');
|
||||||
|
select.classList = "input-group-text";
|
||||||
|
|
||||||
|
var optionEmail = document.createElement('option');
|
||||||
|
optionEmail.value = "email";
|
||||||
|
optionEmail.innerText = "Email";
|
||||||
|
select.append(optionEmail);
|
||||||
|
|
||||||
|
var optionPhone = document.createElement('option');
|
||||||
|
optionPhone.value = "phone";
|
||||||
|
optionPhone.innerText = "Телефон";
|
||||||
|
select.append(optionPhone);
|
||||||
|
groupPrepend.append(select);
|
||||||
|
|
||||||
|
select.addEventListener('change', function() {
|
||||||
|
const selectedValue = this.value;
|
||||||
|
|
||||||
|
if (selectedValue === 'email') {
|
||||||
|
username?.inputmask.remove();
|
||||||
|
username.type = "email";
|
||||||
|
} else if (selectedValue === 'phone') {
|
||||||
|
username.type = "text";
|
||||||
|
Inputmask({ mask: '79999999999' }).mask(username);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var inputGroup = document.createElement('div');
|
||||||
|
inputGroup.classList = "input-group";
|
||||||
|
inputGroup.append(groupPrepend);
|
||||||
|
inputGroup.append(username);
|
||||||
|
|
||||||
|
var formGroup = document.createElement('div');
|
||||||
|
formGroup.classList = "form-group";
|
||||||
|
|
||||||
|
var validUsername = document.createElement('div');
|
||||||
|
validUsername.classList = "msg-valid valid-username";
|
||||||
|
formGroup.append(inputGroup);
|
||||||
|
formGroup.append(validUsername);
|
||||||
|
popupBody.append(formGroup);
|
||||||
|
|
||||||
|
var password = document.createElement('input');
|
||||||
|
password.placeholder = "Пароль";
|
||||||
|
password.type = "password";
|
||||||
|
password.classList = "form-control border-radius";
|
||||||
|
password.required = "true";
|
||||||
|
password.id = "password";
|
||||||
|
password.addEventListener('keydown', function(evn) {
|
||||||
|
if (evn.code == 'Enter') {
|
||||||
|
loader.btnLoader(btnSubmit, true);
|
||||||
|
submit(window.webSDK, username, password, popupBody);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var formGroup = document.createElement('div');
|
||||||
|
formGroup.classList = "form-group";
|
||||||
|
formGroup.dataset.controller = 'passwordShow';
|
||||||
|
formGroup.append(password);
|
||||||
|
|
||||||
|
var validPassword = document.createElement('div');
|
||||||
|
validPassword.classList = "msg-valid valid-password";
|
||||||
|
formGroup.append(validPassword);
|
||||||
|
popupBody.append(formGroup);
|
||||||
|
|
||||||
|
|
||||||
|
/* политика */
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.classList = 'form-group';
|
||||||
|
|
||||||
|
var formCheck = document.createElement('div');
|
||||||
|
formCheck.classList = 'form-check';
|
||||||
|
div.append(formCheck);
|
||||||
|
|
||||||
|
var accept = document.createElement('input');
|
||||||
|
accept.classList = "form-check-input";
|
||||||
|
accept.id = "accept";
|
||||||
|
accept.checked = false;
|
||||||
|
accept.type = "checkbox";
|
||||||
|
formCheck.append(accept);
|
||||||
|
|
||||||
|
var license = helper.getLicenseLink(Cookies.get('region'));
|
||||||
|
var label = document.createElement('label');
|
||||||
|
label.setAttribute('for' , 'accept');
|
||||||
|
label.innerHTML = `ознакомлен(а) <a class="underline" href="${license}" target="_blank">с условиями политики в отношении обработки персональных данных</a>`;
|
||||||
|
|
||||||
|
formCheck.append(label);
|
||||||
|
|
||||||
|
var validAccept = document.createElement('div');
|
||||||
|
validAccept.classList = 'msg-valid valid-accept';
|
||||||
|
div.append(validAccept);
|
||||||
|
|
||||||
|
popupBody.append(div)
|
||||||
|
|
||||||
|
/* согласие */
|
||||||
|
|
||||||
|
var formCheck = document.createElement('div');
|
||||||
|
formCheck.classList = 'form-check';
|
||||||
|
div.append(formCheck);
|
||||||
|
|
||||||
|
var acceptPerson = document.createElement('input');
|
||||||
|
acceptPerson.classList = "form-check-input";
|
||||||
|
acceptPerson.id = "acceptPerson";
|
||||||
|
acceptPerson.checked = false;
|
||||||
|
acceptPerson.type = "checkbox";
|
||||||
|
formCheck.append(acceptPerson);
|
||||||
|
|
||||||
|
var licensePerson = helper.getLicensePersonLink();
|
||||||
|
var labelPerson = document.createElement('label');
|
||||||
|
labelPerson.setAttribute('for' , 'acceptPerson');
|
||||||
|
labelPerson.innerHTML = `даю согласие <a class="underline" href="${licensePerson}" target="_blank">на обработку персональных данных</a>`;
|
||||||
|
|
||||||
|
formCheck.append(labelPerson);
|
||||||
|
|
||||||
|
var validAcceptPerson = document.createElement('div');
|
||||||
|
validAcceptPerson.classList = 'msg-valid valid-acceptPerson';
|
||||||
|
div.append(validAcceptPerson);
|
||||||
|
|
||||||
|
popupBody.append(div)
|
||||||
|
|
||||||
|
var btnSubmit = document.createElement('button');
|
||||||
|
btnSubmit.type = "button";
|
||||||
|
btnSubmit.innerHTML = "Войти";
|
||||||
|
btnSubmit.classList = "btn btn-outline-secondary submit";
|
||||||
|
btnSubmit.addEventListener('click', function() {
|
||||||
|
let invalid = false;
|
||||||
|
|
||||||
|
if (validator.checkAccept(accept, validAccept)) {
|
||||||
|
invalid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validator.checkAccept(acceptPerson, validAcceptPerson)) {
|
||||||
|
invalid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invalid == false) {
|
||||||
|
loader.btnLoader(btnSubmit, true);
|
||||||
|
submit(window.webSDK, username, password, popupBody);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var helpLink = document.createElement('a');
|
||||||
|
helpLink.classList = 'btn my-0';
|
||||||
|
helpLink.dataset.controller = 'serviceDesk';
|
||||||
|
helpLink.style = 'font-size: 21px;';
|
||||||
|
helpLink.innerHTML = `<i class="fa fa-info-circle" aria-hidden="true"></i>`;
|
||||||
|
|
||||||
|
var guLink = document.createElement('a');
|
||||||
|
guLink.classList = 'btn my-0';
|
||||||
|
guLink.dataset.action = 'signin#esia';
|
||||||
|
guLink.innerHTML = `<img src="${helper.getHostname()}/images/eisa.jpg" width="30" alt="EISA">`;
|
||||||
|
|
||||||
|
var forgetLink = document.createElement('button');
|
||||||
|
forgetLink.classList = 'btn';
|
||||||
|
forgetLink.dataset.controller = 'resetPassword';
|
||||||
|
forgetLink.innerHTML = 'Забыли пароль?';
|
||||||
|
|
||||||
|
var footer = document.createElement('div');
|
||||||
|
footer.classList = 'modal-footer px-0';
|
||||||
|
|
||||||
|
footer.append(helpLink);
|
||||||
|
footer.append(guLink);
|
||||||
|
footer.append(forgetLink);
|
||||||
|
footer.append(btnSubmit);
|
||||||
|
popupBody.append(footer);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderAuth();
|
||||||
|
|
||||||
|
var popup = document.getElementById('popup');
|
||||||
|
if (popup && typeof $(popup).modal !== 'undefined') {
|
||||||
|
$(popup).modal('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
function submit(webSDK, username, password, popupBody) {
|
||||||
|
popupBody.querySelectorAll('.msg-valid').forEach(function (e) {
|
||||||
|
e.classList.add('d-none');
|
||||||
|
e.innerHTML = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
webSDK.loginClient({
|
||||||
|
login: username.value,
|
||||||
|
pass: password.value
|
||||||
|
}).then(function(user) {
|
||||||
|
|
||||||
|
if (user.result && user.result.checkdata && typeof user.result.checkdata.pToken !== 'undefined') {
|
||||||
|
changeTempPassword(user.result);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = {
|
||||||
|
user: user,
|
||||||
|
uid: user.id
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.location.pathname !== '/login') {
|
||||||
|
data = {
|
||||||
|
user: user,
|
||||||
|
uid: user.id,
|
||||||
|
redirectFrom: window.location.href
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var popup = document.getElementById('popup');
|
||||||
|
|
||||||
|
if (popup.dataset.reserve === "true") {
|
||||||
|
data.redirectFrom = helper.getHostname() + '/case-history#doctor-success';
|
||||||
|
}
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
method: "POST",
|
||||||
|
crossDomain: true,
|
||||||
|
url: "/api/authenticated",
|
||||||
|
contentType: "application/x-www-form-urlencoded",
|
||||||
|
dataType: "json",
|
||||||
|
data: data,
|
||||||
|
success(response) {
|
||||||
|
if (response.data.success == true) {
|
||||||
|
// Восстанавливаем данные записи из sessionStorage если они были сохранены
|
||||||
|
const reserveFlag = popup.dataset.reserve === "true" || sessionStorage.getItem('reserveFlag') === 'true';
|
||||||
|
|
||||||
|
if (reserveFlag) {
|
||||||
|
// Восстанавливаем данные из sessionStorage
|
||||||
|
const reserveDataStr = sessionStorage.getItem('reserveData');
|
||||||
|
if (reserveDataStr) {
|
||||||
|
try {
|
||||||
|
const reserveData = JSON.parse(reserveDataStr);
|
||||||
|
Object.keys(reserveData).forEach(key => {
|
||||||
|
if (reserveData[key] !== undefined && reserveData[key] !== null) {
|
||||||
|
popup.dataset[key] = reserveData[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log('Данные записи восстановлены из sessionStorage:', reserveData);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Ошибка при восстановлении данных из sessionStorage:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Устанавливаем флаг reserve если его нет
|
||||||
|
popup.dataset.reserve = 'true';
|
||||||
|
|
||||||
|
// Проверяем наличие всех необходимых полей перед вызовом sendReserve
|
||||||
|
const requiredFields = ['specialistid', 'filialid', 'depnum', 'schedident', 'workDate', 'time'];
|
||||||
|
const missingFields = requiredFields.filter(field => !popup.dataset[field]);
|
||||||
|
|
||||||
|
if (missingFields.length > 0) {
|
||||||
|
console.error('Отсутствуют необходимые поля для записи:', missingFields);
|
||||||
|
alert('Ошибка: не удалось восстановить данные для записи. Пожалуйста, попробуйте записаться снова.');
|
||||||
|
// Очищаем sessionStorage
|
||||||
|
sessionStorage.removeItem('reserveData');
|
||||||
|
sessionStorage.removeItem('reserveFlag');
|
||||||
|
// Делаем обычный редирект
|
||||||
|
var parser = document.createElement('a');
|
||||||
|
parser.href = response.data.redirect;
|
||||||
|
window.location.replace(helper.getHostname() + parser.pathname + parser.search);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Очищаем sessionStorage после успешного восстановления
|
||||||
|
sessionStorage.removeItem('reserveData');
|
||||||
|
sessionStorage.removeItem('reserveFlag');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.bitrix === true) {
|
||||||
|
if (reserveFlag) {
|
||||||
|
// Для bitrix тоже нужно вызвать sendReserve для создания записи
|
||||||
|
// Сообщение покажет сам sendReserve после успешной записи
|
||||||
|
sendReserve(popup);
|
||||||
|
} else {
|
||||||
|
// Если не было флага reserve, показываем обычное сообщение
|
||||||
|
popup.querySelector('.modal-title').innerHTML = 'Запись на прием';
|
||||||
|
var message = '<p>Спасибо, Вы успешно записались на прием. </br>';
|
||||||
|
message += popup.dataset.comment + ', ';
|
||||||
|
message += popup.dataset.workDate + ' ' + popup.dataset.time + '</br></p>';
|
||||||
|
message += '<p>Вы всегда можете отменить или перенести запись в личном кабинете по ссылке: ';
|
||||||
|
message += '<a href="https://cabinet.sovamed.ru" >https://cabinet.sovamed.ru</a></p>';
|
||||||
|
popup.querySelector('#popup-body').innerHTML = message;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (reserveFlag) {
|
||||||
|
// Если нужно создать запись, вызываем sendReserve, который сам сделает редирект
|
||||||
|
sendReserve(popup);
|
||||||
|
} else {
|
||||||
|
// Иначе делаем обычный редирект
|
||||||
|
var parser = document.createElement('a');
|
||||||
|
parser.href = response.data.redirect;
|
||||||
|
window.location.replace(helper.getHostname() + parser.pathname + parser.search);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).catch(function(error) {
|
||||||
|
|
||||||
|
helper.sendRequest({
|
||||||
|
data: {'error': error, login: username.value, method: 'loginClient'}
|
||||||
|
}, helper.getHostname() + '/api/log', "POST", "json", true, "application/json");
|
||||||
|
|
||||||
|
var btnSubmit = popupBody.querySelector('button.submit');
|
||||||
|
loader.btnLoader(btnSubmit, false);
|
||||||
|
|
||||||
|
for (var prop in error.data) {
|
||||||
|
if (error.data[prop]) {
|
||||||
|
var el = popupBody.querySelector('.valid-' + prop)
|
||||||
|
el.classList.remove('d-none');
|
||||||
|
el.innerHTML = error.data[prop];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function changeTempPassword(response) {
|
||||||
|
var popup = document.getElementById('popup');
|
||||||
|
var popupBody = popup.querySelector('.modal-title')
|
||||||
|
.innerText = "Смена временного пароля";
|
||||||
|
|
||||||
|
var popupBody = popup.querySelector('#popup-body');
|
||||||
|
popupBody.innerHTML = '';
|
||||||
|
|
||||||
|
var validMessage = document.createElement('div');
|
||||||
|
validMessage.classList = "msg-valid valid-message alert alert-warning";
|
||||||
|
validMessage.innerHTML = response.checkdata.msg;
|
||||||
|
popupBody.append(validMessage);
|
||||||
|
|
||||||
|
var password = document.createElement('input');
|
||||||
|
password.placeholder = "Новый пароль";
|
||||||
|
password.type = "password";
|
||||||
|
password.classList = "form-control border-radius";
|
||||||
|
password.required = "true";
|
||||||
|
password.id = "password";
|
||||||
|
|
||||||
|
var formGroup = document.createElement('div');
|
||||||
|
formGroup.classList = "form-group";
|
||||||
|
formGroup.append(password);
|
||||||
|
|
||||||
|
var validPassword = document.createElement('div');
|
||||||
|
validPassword.classList = "msg-valid valid-password";
|
||||||
|
formGroup.append(validPassword);
|
||||||
|
popupBody.append(formGroup);
|
||||||
|
|
||||||
|
var confirm = document.createElement('input');
|
||||||
|
confirm.placeholder = "Подтверждение";
|
||||||
|
confirm.type = "password";
|
||||||
|
confirm.classList = "form-control border-radius";
|
||||||
|
confirm.required = "true";
|
||||||
|
confirm.id = "confirm";
|
||||||
|
|
||||||
|
var formGroup = document.createElement('div');
|
||||||
|
formGroup.classList = "form-group";
|
||||||
|
formGroup.append(confirm);
|
||||||
|
|
||||||
|
var validConfirm = document.createElement('div');
|
||||||
|
validConfirm.classList = "msg-valid valid-confirm";
|
||||||
|
formGroup.append(validConfirm);
|
||||||
|
popupBody.append(formGroup);
|
||||||
|
|
||||||
|
var btnSubmit = document.createElement('button');
|
||||||
|
btnSubmit.type = "button";
|
||||||
|
btnSubmit.innerHTML = "Сменить пароль";
|
||||||
|
btnSubmit.classList = "btn btn-outline-secondary submit";
|
||||||
|
btnSubmit.addEventListener('click', function() {
|
||||||
|
if (/^[\u0400-\u04FF]+$/.test(password.value)) {
|
||||||
|
popupBody.querySelector('.valid-password')
|
||||||
|
.innerHTML = '<span class="text-danger">Поле не должно содержать кириллицы</span>';
|
||||||
|
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
popupBody.querySelector('.valid-password').innerHTML = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password.value !== confirm.value) {
|
||||||
|
popupBody.querySelector('.valid-confirm')
|
||||||
|
.innerHTML = '<span class="text-danger">Подтверждение не совпадает с паролем</span>';
|
||||||
|
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
popupBody.querySelector('.valid-confirm').innerHTML = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
loader.btnLoader(btnSubmit, true);
|
||||||
|
|
||||||
|
window.webSDK.changeTempPassword({
|
||||||
|
pwdToken: response.checkdata.pToken,
|
||||||
|
password: password.value,
|
||||||
|
confirm: confirm.value
|
||||||
|
}).then(function(resolve) {
|
||||||
|
renderAuth(resolve.data.success);
|
||||||
|
}).catch(function(e) {
|
||||||
|
helper.sendRequest({
|
||||||
|
data: {'error': e, method: 'changeTempPassword'}
|
||||||
|
}, helper.getHostname() + '/api/log', "POST", "json", true, "application/json");
|
||||||
|
var btnSubmit = popupBody.querySelector('button.submit');
|
||||||
|
loader.btnLoader(btnSubmit, false);
|
||||||
|
|
||||||
|
for (var prop in e.data.errors) {
|
||||||
|
if (e.data.errors[prop]) {
|
||||||
|
var el = popupBody.querySelector('.valid-' + prop.split('.')[1])
|
||||||
|
el.classList.remove('d-none');
|
||||||
|
el.innerHTML = e.data.errors[prop][0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
var footer = document.createElement('div');
|
||||||
|
footer.classList = 'modal-footer';
|
||||||
|
footer.append(btnSubmit);
|
||||||
|
popupBody.append(footer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
import 'owl.carousel2/dist/assets/owl.carousel.css';
|
||||||
|
import 'owl.carousel2/dist/assets/owl.theme.default.css';
|
||||||
|
import 'owl.carousel2';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="hello" attribute will cause
|
||||||
|
* this controller to be executed. The name "hello" comes from the filename:
|
||||||
|
* hello_controller.js -> "hello"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
static targets = ["showid"];
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
var slideshow = this.element;
|
||||||
|
|
||||||
|
$(slideshow).owlCarousel({
|
||||||
|
nav: true,
|
||||||
|
margin: 15,
|
||||||
|
autoplay: false,
|
||||||
|
autoplayTimeout: 7000,
|
||||||
|
autoplayHoverPause: true,
|
||||||
|
navText : ['<span class="swiper-button-prev"> </span>','<span class="swiper-button-next"> </span>'],
|
||||||
|
responsive: {
|
||||||
|
0: {
|
||||||
|
items: 1,
|
||||||
|
dots: false,
|
||||||
|
},
|
||||||
|
600: {
|
||||||
|
items: 2,
|
||||||
|
dots: false,
|
||||||
|
},
|
||||||
|
1000: {
|
||||||
|
items: 2,
|
||||||
|
dots: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
slideshow.classList.remove('hide');
|
||||||
|
|
||||||
|
slideshow.querySelectorAll('.show-msg').forEach(function (el) {
|
||||||
|
el.addEventListener('click', function (evn) {
|
||||||
|
var showId = evn.target.dataset.showId;
|
||||||
|
var crop = slideshow.querySelector(`#crop-${showId}`);
|
||||||
|
var full = slideshow.querySelector(`#full-${showId}`);
|
||||||
|
|
||||||
|
if (full.classList.contains('d-none')) {
|
||||||
|
crop.classList.add('d-none');
|
||||||
|
full.classList.remove('d-none');
|
||||||
|
evn.target.innerHTML = 'cвернуть';
|
||||||
|
} else {
|
||||||
|
crop.classList.remove('d-none');
|
||||||
|
full.classList.add('d-none');
|
||||||
|
evn.target.innerHTML = 'весь отзыв';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
const helper = require("./../components/helper.js");
|
||||||
|
const loader = require("./../components/loader.js");
|
||||||
|
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
const btn = this.element;
|
||||||
|
|
||||||
|
if (window.smartCaptcha) {
|
||||||
|
const container = document.getElementById('smart-captcha');
|
||||||
|
const widgetId = window.smartCaptcha.render(container, {
|
||||||
|
sitekey: 'ysc1_EaQp6z8UPPQAIfHLm8mlrfFGee54huOrUEgGWgRpcf5c2225',
|
||||||
|
hl: 'ru',
|
||||||
|
});
|
||||||
|
|
||||||
|
container.dataset.id = widgetId;
|
||||||
|
|
||||||
|
window.smartCaptcha.subscribe( widgetId, 'success', function () {
|
||||||
|
btn.disabled = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (btn && btn?.type === 'submit') {
|
||||||
|
btn.disabled = true;
|
||||||
|
btn.addEventListener('click', function(evn) {
|
||||||
|
evn.preventDefault();
|
||||||
|
loader.btnLoader(btn, true);
|
||||||
|
|
||||||
|
if ($('#' + btn.dataset.formId)[0].checkValidity()) {
|
||||||
|
helper.sendRequest({'smart-token' : window.smartCaptcha.getResponse()}, '/api/smart-captcha').then(function (response) {
|
||||||
|
if (response.status != 'ok') {
|
||||||
|
loader.btnLoader(btn, false);
|
||||||
|
window.smartCaptcha.reset();
|
||||||
|
} else {
|
||||||
|
$('#' + btn.dataset.formId).submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
window.smartCaptcha.reset();
|
||||||
|
$('#' + btn.dataset.formId)[0].reportValidity();
|
||||||
|
loader.btnLoader(btn, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addYandexMetrica() {
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.type = 'text/javascript';
|
||||||
|
script.innerHTML = `
|
||||||
|
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
|
||||||
|
m[i].l=1*new Date();k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
|
||||||
|
(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
|
||||||
|
`;
|
||||||
|
|
||||||
|
document.head.appendChild(script);
|
||||||
|
}
|
||||||
|
|
||||||
|
setYm() {
|
||||||
|
const ymNum = document.getElementsByName('ymNum')[0]?.value;
|
||||||
|
const ymId = document.getElementsByName('ymId')[0]?.value;
|
||||||
|
|
||||||
|
if (ymNum && ymId) {
|
||||||
|
this.addYandexMetrica();
|
||||||
|
|
||||||
|
window.ym(ymNum,'reachGoal', ymId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,275 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
import Cookies from 'js-cookie';
|
||||||
|
import { renderFormAnonym, sendReserve, renderFormBitrix } from "./../components/record";
|
||||||
|
|
||||||
|
const helper = require("./../components/helper.js");
|
||||||
|
const record = require("./../components/record.js");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="specialistView" attribute will cause
|
||||||
|
* this controller to be executed. The name "specialistView" comes from the filename:
|
||||||
|
* detailDoctor_controller.js -> "specialistView"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
let currentDate = this.element.dataset.st;
|
||||||
|
let bodyModal = document.getElementById('detail-specialist');
|
||||||
|
var btnNext = bodyModal.querySelector('.btn-next');
|
||||||
|
var btnPrev = bodyModal.querySelector('.btn-prev');
|
||||||
|
|
||||||
|
btnNext.addEventListener('click', function(evn) {
|
||||||
|
if (this.dataset.currentdate) {
|
||||||
|
var date = this.dataset.currentdate;
|
||||||
|
} else {
|
||||||
|
var date = currentDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
btnPrev.dataset.currentdate = new Date(date);
|
||||||
|
btnPrev.classList.remove('d-none');
|
||||||
|
bodyModal.querySelector('.popup-btns').classList.remove('justify-content-end');
|
||||||
|
bodyModal.querySelector('.popup-btns').classList.add('justify-content-between');
|
||||||
|
date = getNextWeek(date);
|
||||||
|
|
||||||
|
this.dataset.currentdate = new Date(date);
|
||||||
|
var departmentId = bodyModal.dataset.departmentid;
|
||||||
|
var specialistId = bodyModal.dataset.specialistid;
|
||||||
|
var filialId = bodyModal.dataset.filialid;
|
||||||
|
var onlineMode = bodyModal.dataset.onlinemode;
|
||||||
|
|
||||||
|
pullInterval(specialistId, departmentId, filialId, date, onlineMode);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
btnPrev.addEventListener('click', function(evn) {
|
||||||
|
if (this.dataset.currentdate) {
|
||||||
|
var date = this.dataset.currentdate;
|
||||||
|
} else {
|
||||||
|
var date = currentDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
var nDate = new Date(currentDate).toLocaleString('ru', {year: 'numeric',month: 'numeric',day: 'numeric'});
|
||||||
|
var cDate = new Date(date).toLocaleString('ru', {year: 'numeric',month: 'numeric',day: 'numeric'});
|
||||||
|
|
||||||
|
if (nDate == cDate) {
|
||||||
|
this.classList.add('d-none');
|
||||||
|
bodyModal.querySelector('.popup-btns').classList.add('justify-content-end');
|
||||||
|
bodyModal.querySelector('.popup-btns').classList.remove('justify-content-between');
|
||||||
|
}
|
||||||
|
|
||||||
|
btnNext.dataset.currentdate = new Date(date);
|
||||||
|
|
||||||
|
var departmentId = bodyModal.dataset.departmentid;
|
||||||
|
var specialistId = bodyModal.dataset.specialistid;
|
||||||
|
var filialId = bodyModal.dataset.filialid;
|
||||||
|
var onlineMode = bodyModal.dataset.onlinemode;
|
||||||
|
|
||||||
|
pullInterval(specialistId, departmentId, filialId, date, onlineMode);
|
||||||
|
|
||||||
|
this.dataset.currentdate = new Date(getPrevWeek(date));
|
||||||
|
});
|
||||||
|
|
||||||
|
this.element.querySelectorAll('.show-specialist-detail').forEach(function(btn) {
|
||||||
|
btn.addEventListener('click', function(evn) {
|
||||||
|
btnPrev.classList.add('d-none');
|
||||||
|
bodyModal.querySelector('.popup-btns').classList.remove('justify-content-between');
|
||||||
|
bodyModal.querySelector('.popup-btns').classList.add('justify-content-end');
|
||||||
|
|
||||||
|
var departmentId = bodyModal.dataset.departmentid = btn.dataset.departmentid;
|
||||||
|
var specialistId = bodyModal.dataset.specialistid = btn.dataset.specialistid;
|
||||||
|
bodyModal.dataset.company = btn.dataset.company;
|
||||||
|
var filialId = bodyModal.dataset.filialid = btn.dataset.filialid;
|
||||||
|
var onlineMode = bodyModal.dataset.onlinemode = btn.dataset.onlinemode;
|
||||||
|
|
||||||
|
pullInterval(specialistId, departmentId, filialId, currentDate, onlineMode);
|
||||||
|
pullDoctor(specialistId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function pullDoctor(doctor) {
|
||||||
|
var modal = bodyModal.querySelector('.popup__content');
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
dataType: "json",
|
||||||
|
method: "GET",
|
||||||
|
crossDomain: true,
|
||||||
|
url: "/api/doctor",
|
||||||
|
data: {
|
||||||
|
'sid': doctor,
|
||||||
|
},
|
||||||
|
beforeSend() {
|
||||||
|
modal.querySelector('.loading').classList.remove('d-none');
|
||||||
|
var aboutSpecialist = modal.querySelector('.about-specialist')
|
||||||
|
aboutSpecialist.classList.add('d-none');
|
||||||
|
|
||||||
|
aboutSpecialist.querySelector('.popup-staff__img').remove();
|
||||||
|
},
|
||||||
|
success(data) {
|
||||||
|
modal.querySelector('.loading').classList.add('d-none');
|
||||||
|
modal.querySelector('.about-specialist').classList.remove('d-none');
|
||||||
|
var content = modal.querySelector('.about-specialist');
|
||||||
|
|
||||||
|
var img = document.createElement('div');
|
||||||
|
img.src = data.data.img;
|
||||||
|
img.classList = 'img-vr popup-staff__img';
|
||||||
|
img.style.background = 'url(' + data.data.img + ') no-repeat';
|
||||||
|
img.style.backgroundSize = 'cover';
|
||||||
|
img.style.backgroundPosition = 'center -5px';
|
||||||
|
|
||||||
|
content.prepend(img);
|
||||||
|
content.querySelector('.popup-staff__name').innerHTML = data.data.name;
|
||||||
|
content.querySelector('.popup-staff__position').innerHTML = '';
|
||||||
|
|
||||||
|
if (data.data.speciality) {
|
||||||
|
content.querySelector('.popup-staff__position').innerHTML = data.data.speciality;
|
||||||
|
}
|
||||||
|
|
||||||
|
content.querySelector('.popup-staff__exp').innerHTML = '';
|
||||||
|
|
||||||
|
if (data.data.experience) {
|
||||||
|
content.querySelector('.popup-staff__exp').innerHTML = 'Стаж:' + data.data.experience;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function pullInterval(doctor, department, filial, date, onlineMode) {
|
||||||
|
let wrap = bodyModal.querySelector('.calendar-wrap');
|
||||||
|
let calendarBody = bodyModal.querySelector('.calendar-body');
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
dataType: "json",
|
||||||
|
method: "GET",
|
||||||
|
crossDomain: true,
|
||||||
|
url: "/api/interval",
|
||||||
|
data: {
|
||||||
|
'update' : true,
|
||||||
|
'doctor': doctor,
|
||||||
|
'department': department,
|
||||||
|
'filial': filial,
|
||||||
|
'startInterval': getMonday(date),
|
||||||
|
'endInterval': getSunday(date),
|
||||||
|
'onlineMode': onlineMode
|
||||||
|
},
|
||||||
|
beforeSend() {
|
||||||
|
bodyModal.querySelector('.current-dates').innerHTML = getMonday(date) + ' - ' + getSunday(date);
|
||||||
|
wrap.innerHTML = "Идет загрузка...";
|
||||||
|
},
|
||||||
|
success(response) {
|
||||||
|
|
||||||
|
var isNotFree = true;
|
||||||
|
|
||||||
|
wrap.innerHTML = "";
|
||||||
|
response.data.intervalsData.forEach(function(el) {
|
||||||
|
if (el.isFree == true) {
|
||||||
|
var date = new Date(el.workDate).toLocaleString('ru', {
|
||||||
|
weekday: 'long',
|
||||||
|
month: 'long',
|
||||||
|
day: 'numeric'
|
||||||
|
});
|
||||||
|
|
||||||
|
var calBody = document.createElement('div');
|
||||||
|
calBody.classList = 'calendar-body popup-inteval__item';
|
||||||
|
|
||||||
|
var timeDiv = document.createElement('div');
|
||||||
|
timeDiv.classList = 'popup-inteval__date';
|
||||||
|
timeDiv.innerHTML = date + ' <i>' + el.startInterval + '—'+ el.endInterval + '</i>';
|
||||||
|
calBody.append(timeDiv);
|
||||||
|
|
||||||
|
|
||||||
|
var intervalTimeDiv = document.createElement('div');
|
||||||
|
intervalTimeDiv.classList = 'time-intervals';
|
||||||
|
|
||||||
|
var intervalDiv = document.createElement('div');
|
||||||
|
intervalDiv.classList = 'interval intervals-wrap';
|
||||||
|
|
||||||
|
intervalTimeDiv.append(intervalDiv);
|
||||||
|
|
||||||
|
for (let [key, item] of Object.entries(el.intervals)) {
|
||||||
|
if (item.isFree == true) {
|
||||||
|
isNotFree = false;
|
||||||
|
|
||||||
|
var spanInterval = document.createElement('span');
|
||||||
|
|
||||||
|
spanInterval.classList = 'time available';
|
||||||
|
spanInterval.innerText = item.startTime;
|
||||||
|
spanInterval.dataset.workDate = item.workDate;
|
||||||
|
spanInterval.dataset.schedident = item.schedident;
|
||||||
|
spanInterval.dataset.time = item.time;
|
||||||
|
spanInterval.dataset.onlinemode = item.onlineMode;
|
||||||
|
spanInterval.dataset.rnum = item.rNum;
|
||||||
|
|
||||||
|
spanInterval.dataset.specialistid = doctor;
|
||||||
|
spanInterval.dataset.filialid = filial;
|
||||||
|
spanInterval.dataset.department = department;
|
||||||
|
|
||||||
|
spanInterval.addEventListener('click', function (evn) {
|
||||||
|
var popupWrap = document.getElementById('popup');
|
||||||
|
evn.target.dataset.onlinemode = item.onlineMode;
|
||||||
|
|
||||||
|
if (record.renderFormRecord(response.data.userInfo, evn.target.dataset)) {
|
||||||
|
if (response.data.userInfo) {
|
||||||
|
evn.target.innerHTML = '<img width="20" src="/images/eclipse.gif">';
|
||||||
|
record.sendReserve(popupWrap)
|
||||||
|
} else {
|
||||||
|
$(popupWrap).modal('show');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
intervalDiv.append(spanInterval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isNotFree) {
|
||||||
|
calBody.append(intervalDiv);
|
||||||
|
wrap.append(calBody);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isNotFree) {
|
||||||
|
wrap.innerHTML = "Всё занято. Выберите другую неделю.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMonday(date) {
|
||||||
|
date = new Date(date);
|
||||||
|
|
||||||
|
return new Date(date.setDate(date.getDate() - date.getDay() + 1))
|
||||||
|
.toLocaleString('ru', {
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'numeric',
|
||||||
|
day: 'numeric',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSunday(date) {
|
||||||
|
date = new Date(date);
|
||||||
|
|
||||||
|
return new Date(date.setDate(date.getDate() - date.getDay() + 7))
|
||||||
|
.toLocaleString('ru', {
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'numeric',
|
||||||
|
day: 'numeric',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNextWeek(date) {
|
||||||
|
date = new Date(date);
|
||||||
|
|
||||||
|
return new Date(date.getFullYear(), date.getMonth(), date.getDate() + 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPrevWeek(date) {
|
||||||
|
date = new Date(date);
|
||||||
|
|
||||||
|
return new Date(date.getFullYear(), date.getMonth(), date.getDate() - 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
import "swagger-ui-dist/swagger-ui.css"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="default" attribute will cause
|
||||||
|
* this controller to be executed. The name "default" comes from the filename:
|
||||||
|
* default_controller.js -> "default"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
var SwaggerUIBundle = require('swagger-ui-dist').SwaggerUIBundle;
|
||||||
|
var wrap = this.element;
|
||||||
|
|
||||||
|
SwaggerUIBundle({
|
||||||
|
url: "/api/swagger.json",
|
||||||
|
dom_id: '#swagger-ui'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
import Inputmask from "inputmask";
|
||||||
|
import { renderFormBitrix } from "./../components/record"
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="uslugi" attribute will cause
|
||||||
|
* this controller to be executed. The name "hello" comes from the filename:
|
||||||
|
* hello_controller.js -> "hello"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
var btn = this.element
|
||||||
|
btn.addEventListener('click', function () {
|
||||||
|
renderFormBitrix(this);
|
||||||
|
$('#popup').modal('show');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
import { Controller } from 'stimulus';
|
||||||
|
|
||||||
|
const loader = require("./../components/loader.js");
|
||||||
|
const helper = require("./../components/helper.js");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an example Stimulus controller!
|
||||||
|
*
|
||||||
|
* Any element with a data-controller="widgets" attribute will cause
|
||||||
|
* this controller to be executed. The name "recaptcha" comes from the filename:
|
||||||
|
* recaptcha_controller.js -> "recaptcha"
|
||||||
|
*
|
||||||
|
* Delete this file or adapt it for your use!
|
||||||
|
*/
|
||||||
|
export default class extends Controller {
|
||||||
|
connect() {
|
||||||
|
loader.loadSDK('widget').then(function(webSDK) {
|
||||||
|
webSDK.on('init', function() {
|
||||||
|
if (this.data.user.authenticated) {
|
||||||
|
runWebSDK();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
let runWebSDK = function () {
|
||||||
|
this.securityCard();
|
||||||
|
this.finance();
|
||||||
|
}.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
finance() {
|
||||||
|
var financeWidget = document.getElementById('finance-widget');
|
||||||
|
|
||||||
|
window.webSDK.loadPaymentList({
|
||||||
|
start: 0,
|
||||||
|
length: 4
|
||||||
|
}).then(function (resolve) {
|
||||||
|
financeWidget.innerHTML = '';
|
||||||
|
|
||||||
|
if (resolve.length > 0) {
|
||||||
|
resolve.forEach(function(item) {
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.classList = 'payment-line';
|
||||||
|
|
||||||
|
var date = window.newDate(item.date);
|
||||||
|
var spanID = document.createElement('span');
|
||||||
|
spanID.classList = 'payment-line__id';
|
||||||
|
spanID.innerHTML = 'Счет № ' + item.id + ' от ' + window.dateFormat(date, 'd-m-Y');
|
||||||
|
div.append(spanID);
|
||||||
|
|
||||||
|
var spanPrice = document.createElement('span');
|
||||||
|
spanPrice.classList = 'payment-line__price';
|
||||||
|
spanPrice.innerHTML = item.amt + ' ₽';
|
||||||
|
div.append(spanPrice);
|
||||||
|
|
||||||
|
financeWidget.append(div);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
var item = document.createElement('span');
|
||||||
|
item.innerHTML = 'Записей не найдено';
|
||||||
|
item.classList = 'line-item';
|
||||||
|
financeWidget.append(item);
|
||||||
|
}
|
||||||
|
}).catch(function (error) {
|
||||||
|
helper.sendRequest({
|
||||||
|
data: {'error': error, method: 'loadPaymentList'}
|
||||||
|
}, helper.getHostname() + '/api/log', "POST", "json", true, "application/json");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
securityCard() {
|
||||||
|
var securityCardWidget = document.getElementById('security-card-widget');
|
||||||
|
var date = new Date();
|
||||||
|
var lastDate = new Date(date.getFullYear(), date.getMonth() + 1, 0);
|
||||||
|
|
||||||
|
if (window.webSDK.data.user.allows.caseHistory == true) {
|
||||||
|
window.webSDK.loadTreatPlaceList({
|
||||||
|
st: 20200101,
|
||||||
|
en: window.dateFormat(lastDate),
|
||||||
|
start: 0,
|
||||||
|
length: 4
|
||||||
|
}).then(function (resolve) {
|
||||||
|
securityCardWidget.innerHTML = '';
|
||||||
|
|
||||||
|
if (resolve.data.length > 0) {
|
||||||
|
resolve.data.forEach(function(el) {
|
||||||
|
var item = document.createElement('span');
|
||||||
|
item.innerHTML = el.protocolName.slice(0,37) + '...';
|
||||||
|
item.classList = 'line-item';
|
||||||
|
|
||||||
|
securityCardWidget.append(item);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
var item = document.createElement('span');
|
||||||
|
item.innerHTML = 'Записей не найдено';
|
||||||
|
item.classList = 'line-item';
|
||||||
|
securityCardWidget.append(item);
|
||||||
|
}
|
||||||
|
}).catch(function (error) {
|
||||||
|
helper.sendRequest({
|
||||||
|
data: {'error': error, method: 'loadTreatPlaceList'}
|
||||||
|
}, helper.getHostname() + '/api/log', "POST", "json", true, "application/json");
|
||||||
|
|
||||||
|
securityCardWidget.innerHTML = '';
|
||||||
|
var item = document.createElement('span');
|
||||||
|
item.innerHTML = 'Записей не найдено';
|
||||||
|
item.classList = 'line-item';
|
||||||
|
securityCardWidget.append(item);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
securityCardWidget.innerHTML = '';
|
||||||
|
var item = document.createElement('span');
|
||||||
|
item.innerHTML = 'Записей не найдено';
|
||||||
|
item.classList = 'line-item';
|
||||||
|
securityCardWidget.append(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,342 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="robots" content="noindex, noarchive">
|
||||||
|
<title>Transfonter demo</title>
|
||||||
|
<link href="stylesheet.css" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
/*
|
||||||
|
http://meyerweb.com/eric/tools/css/reset/
|
||||||
|
v2.0 | 20110126
|
||||||
|
License: none (public domain)
|
||||||
|
*/
|
||||||
|
html, body, div, span, applet, object, iframe,
|
||||||
|
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||||
|
a, abbr, acronym, address, big, cite, code,
|
||||||
|
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||||
|
small, strike, strong, sub, sup, tt, var,
|
||||||
|
b, u, i, center,
|
||||||
|
dl, dt, dd, ol, ul, li,
|
||||||
|
fieldset, form, label, legend,
|
||||||
|
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||||
|
article, aside, canvas, details, embed,
|
||||||
|
figure, figcaption, footer, header, hgroup,
|
||||||
|
menu, nav, output, ruby, section, summary,
|
||||||
|
time, mark, audio, video {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
font: inherit;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
/* HTML5 display-role reset for older browsers */
|
||||||
|
article, aside, details, figcaption, figure,
|
||||||
|
footer, header, hgroup, menu, nav, section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
ol, ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
blockquote, q {
|
||||||
|
quotes: none;
|
||||||
|
}
|
||||||
|
blockquote:before, blockquote:after,
|
||||||
|
q:before, q:after {
|
||||||
|
content: '';
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
/* common styles */
|
||||||
|
body {
|
||||||
|
background: #f1f1f1;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
.page {
|
||||||
|
background: #fff;
|
||||||
|
width: 920px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px 20px 0 20px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.font-container {
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
line-height: 1.3;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
position: relative;
|
||||||
|
background: #444;
|
||||||
|
font-size: 32px;
|
||||||
|
color: #fff;
|
||||||
|
padding: 10px 20px;
|
||||||
|
margin: 0 -20px 12px -20px;
|
||||||
|
}
|
||||||
|
.letters {
|
||||||
|
font-size: 25px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.s10:before {
|
||||||
|
content: '10px';
|
||||||
|
}
|
||||||
|
.s11:before {
|
||||||
|
content: '11px';
|
||||||
|
}
|
||||||
|
.s12:before {
|
||||||
|
content: '12px';
|
||||||
|
}
|
||||||
|
.s14:before {
|
||||||
|
content: '14px';
|
||||||
|
}
|
||||||
|
.s18:before {
|
||||||
|
content: '18px';
|
||||||
|
}
|
||||||
|
.s24:before {
|
||||||
|
content: '24px';
|
||||||
|
}
|
||||||
|
.s30:before {
|
||||||
|
content: '30px';
|
||||||
|
}
|
||||||
|
.s36:before {
|
||||||
|
content: '36px';
|
||||||
|
}
|
||||||
|
.s48:before {
|
||||||
|
content: '48px';
|
||||||
|
}
|
||||||
|
.s60:before {
|
||||||
|
content: '60px';
|
||||||
|
}
|
||||||
|
.s72:before {
|
||||||
|
content: '72px';
|
||||||
|
}
|
||||||
|
.s10:before, .s11:before, .s12:before, .s14:before,
|
||||||
|
.s18:before, .s24:before, .s30:before, .s36:before,
|
||||||
|
.s48:before, .s60:before, .s72:before {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
color: #999;
|
||||||
|
padding-right: 6px;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
padding: 9px;
|
||||||
|
margin: 0 0 10px;
|
||||||
|
font-family: Monaco, Menlo, Consolas, "Courier New", monospace !important;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.428571429;
|
||||||
|
color: #333;
|
||||||
|
font-weight: normal !important;
|
||||||
|
font-style: normal !important;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
overflow-x: auto;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
pre:after {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
content: 'Usage';
|
||||||
|
line-height: 1;
|
||||||
|
padding: 5px 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #767676;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-right: none;
|
||||||
|
border-top: none;
|
||||||
|
border-radius: 0 4px 0 4px;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
/* responsive */
|
||||||
|
@media (max-width: 959px) {
|
||||||
|
.page {
|
||||||
|
width: auto;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="page">
|
||||||
|
<div class="demo" style="font-family: 'Circe'; font-weight: normal; font-style: normal;">
|
||||||
|
<h1>Circe</h1>
|
||||||
|
<pre>.your-style {
|
||||||
|
font-family: 'Circe';
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}</pre>
|
||||||
|
<div class="font-container">
|
||||||
|
<p class="letters">
|
||||||
|
абвгдеёжзийклмнопрстуфхцчшщъыьэюя <br />
|
||||||
|
АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ <br />
|
||||||
|
abcdefghijklmnopqrstuvwxyz <br />
|
||||||
|
ABCDEFGHIJKLMNOPQRSTUVWXYZ <br /> 0123456789.:,;()*!?'@#<>$%&^+-=~
|
||||||
|
</p>
|
||||||
|
<p class="s10" style="font-size: 10px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s11" style="font-size: 11px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s12" style="font-size: 12px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s14" style="font-size: 14px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s18" style="font-size: 18px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s24" style="font-size: 24px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s30" style="font-size: 30px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s36" style="font-size: 36px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s48" style="font-size: 48px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s60" style="font-size: 60px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s72" style="font-size: 72px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="demo" style="font-family: 'Circe'; font-weight: 200; font-style: normal;">
|
||||||
|
<h1>Circe ExtraLight</h1>
|
||||||
|
<pre>.your-style {
|
||||||
|
font-family: 'Circe';
|
||||||
|
font-weight: 200;
|
||||||
|
font-style: normal;
|
||||||
|
}</pre>
|
||||||
|
<div class="font-container">
|
||||||
|
<p class="letters">
|
||||||
|
абвгдеёжзийклмнопрстуфхцчшщъыьэюя <br />
|
||||||
|
АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ <br />
|
||||||
|
abcdefghijklmnopqrstuvwxyz <br />
|
||||||
|
ABCDEFGHIJKLMNOPQRSTUVWXYZ <br /> 0123456789.:,;()*!?'@#<>$%&^+-=~
|
||||||
|
</p>
|
||||||
|
<p class="s10" style="font-size: 10px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s11" style="font-size: 11px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s12" style="font-size: 12px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s14" style="font-size: 14px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s18" style="font-size: 18px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s24" style="font-size: 24px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s30" style="font-size: 30px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s36" style="font-size: 36px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s48" style="font-size: 48px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s60" style="font-size: 60px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s72" style="font-size: 72px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="demo" style="font-family: 'Circe'; font-weight: 100; font-style: normal;">
|
||||||
|
<h1>Circe Thin</h1>
|
||||||
|
<pre>.your-style {
|
||||||
|
font-family: 'Circe';
|
||||||
|
font-weight: 100;
|
||||||
|
font-style: normal;
|
||||||
|
}</pre>
|
||||||
|
<div class="font-container">
|
||||||
|
<p class="letters">
|
||||||
|
абвгдеёжзийклмнопрстуфхцчшщъыьэюя <br />
|
||||||
|
АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ <br />
|
||||||
|
abcdefghijklmnopqrstuvwxyz <br />
|
||||||
|
ABCDEFGHIJKLMNOPQRSTUVWXYZ <br /> 0123456789.:,;()*!?'@#<>$%&^+-=~
|
||||||
|
</p>
|
||||||
|
<p class="s10" style="font-size: 10px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s11" style="font-size: 11px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s12" style="font-size: 12px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s14" style="font-size: 14px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s18" style="font-size: 18px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s24" style="font-size: 24px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s30" style="font-size: 30px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s36" style="font-size: 36px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s48" style="font-size: 48px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s60" style="font-size: 60px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s72" style="font-size: 72px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="demo" style="font-family: 'Circe'; font-weight: 300; font-style: normal;">
|
||||||
|
<h1>Circe Light</h1>
|
||||||
|
<pre>.your-style {
|
||||||
|
font-family: 'Circe';
|
||||||
|
font-weight: 300;
|
||||||
|
font-style: normal;
|
||||||
|
}</pre>
|
||||||
|
<div class="font-container">
|
||||||
|
<p class="letters">
|
||||||
|
абвгдеёжзийклмнопрстуфхцчшщъыьэюя <br />
|
||||||
|
АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ <br />
|
||||||
|
abcdefghijklmnopqrstuvwxyz <br />
|
||||||
|
ABCDEFGHIJKLMNOPQRSTUVWXYZ <br /> 0123456789.:,;()*!?'@#<>$%&^+-=~
|
||||||
|
</p>
|
||||||
|
<p class="s10" style="font-size: 10px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s11" style="font-size: 11px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s12" style="font-size: 12px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s14" style="font-size: 14px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s18" style="font-size: 18px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s24" style="font-size: 24px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s30" style="font-size: 30px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s36" style="font-size: 36px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s48" style="font-size: 48px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s60" style="font-size: 60px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s72" style="font-size: 72px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="demo" style="font-family: 'Circe'; font-weight: bold; font-style: normal;">
|
||||||
|
<h1>Circe Bold</h1>
|
||||||
|
<pre>.your-style {
|
||||||
|
font-family: 'Circe';
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: normal;
|
||||||
|
}</pre>
|
||||||
|
<div class="font-container">
|
||||||
|
<p class="letters">
|
||||||
|
абвгдеёжзийклмнопрстуфхцчшщъыьэюя <br />
|
||||||
|
АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ <br />
|
||||||
|
abcdefghijklmnopqrstuvwxyz <br />
|
||||||
|
ABCDEFGHIJKLMNOPQRSTUVWXYZ <br /> 0123456789.:,;()*!?'@#<>$%&^+-=~
|
||||||
|
</p>
|
||||||
|
<p class="s10" style="font-size: 10px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s11" style="font-size: 11px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s12" style="font-size: 12px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s14" style="font-size: 14px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s18" style="font-size: 18px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s24" style="font-size: 24px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s30" style="font-size: 30px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s36" style="font-size: 36px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s48" style="font-size: 48px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s60" style="font-size: 60px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s72" style="font-size: 72px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="demo" style="font-family: 'Circe'; font-weight: 800; font-style: normal;">
|
||||||
|
<h1>Circe ExtraBold</h1>
|
||||||
|
<pre>.your-style {
|
||||||
|
font-family: 'Circe';
|
||||||
|
font-weight: 800;
|
||||||
|
font-style: normal;
|
||||||
|
}</pre>
|
||||||
|
<div class="font-container">
|
||||||
|
<p class="letters">
|
||||||
|
абвгдеёжзийклмнопрстуфхцчшщъыьэюя <br />
|
||||||
|
АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ <br />
|
||||||
|
abcdefghijklmnopqrstuvwxyz <br />
|
||||||
|
ABCDEFGHIJKLMNOPQRSTUVWXYZ <br /> 0123456789.:,;()*!?'@#<>$%&^+-=~
|
||||||
|
</p>
|
||||||
|
<p class="s10" style="font-size: 10px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s11" style="font-size: 11px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s12" style="font-size: 12px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s14" style="font-size: 14px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s18" style="font-size: 18px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s24" style="font-size: 24px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s30" style="font-size: 30px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s36" style="font-size: 36px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s48" style="font-size: 48px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s60" style="font-size: 60px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
<p class="s72" style="font-size: 72px;">Съешь же ещё этих мягких французских булок, да выпей чаю.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/* This stylesheet generated by Transfonter (https://transfonter.org) on June 26, 2017 11:20 AM */
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Circe';
|
||||||
|
src: url('Circe-Regular.eot');
|
||||||
|
src: local('Circe'), local('Circe-Regular'),
|
||||||
|
url('Circe-Regular.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('Circe-Regular.woff') format('woff'),
|
||||||
|
url('Circe-Regular.ttf') format('truetype');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Circe';
|
||||||
|
src: url('Circe-ExtraLight.eot');
|
||||||
|
src: local('Circe ExtraLight'), local('Circe-ExtraLight'),
|
||||||
|
url('Circe-ExtraLight.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('Circe-ExtraLight.woff') format('woff'),
|
||||||
|
url('Circe-ExtraLight.ttf') format('truetype');
|
||||||
|
font-weight: 200;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Circe';
|
||||||
|
src: url('Circe-Thin.eot');
|
||||||
|
src: local('Circe Thin'), local('Circe-Thin'),
|
||||||
|
url('Circe-Thin.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('Circe-Thin.woff') format('woff'),
|
||||||
|
url('Circe-Thin.ttf') format('truetype');
|
||||||
|
font-weight: 100;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Circe';
|
||||||
|
src: url('Circe-Light.eot');
|
||||||
|
src: local('Circe Light'), local('Circe-Light'),
|
||||||
|
url('Circe-Light.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('Circe-Light.woff') format('woff'),
|
||||||
|
url('Circe-Light.ttf') format('truetype');
|
||||||
|
font-weight: 300;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Circe';
|
||||||
|
src: url('Circe-Bold.eot');
|
||||||
|
src: local('Circe Bold'), local('Circe-Bold'),
|
||||||
|
url('Circe-Bold.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('Circe-Bold.woff') format('woff'),
|
||||||
|
url('Circe-Bold.ttf') format('truetype');
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Circe';
|
||||||
|
src: url('Circe-ExtraBold.eot');
|
||||||
|
src: local('Circe ExtraBold'), local('Circe-ExtraBold'),
|
||||||
|
url('Circe-ExtraBold.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('Circe-ExtraBold.woff') format('woff'),
|
||||||
|
url('Circe-ExtraBold.ttf') format('truetype');
|
||||||
|
font-weight: 800;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<svg width="100" height="40" viewBox="0 0 100 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M20 40C31.0457 40 40 31.0457 40 20C40 8.95431 31.0457 0 20 0C8.95431 0 0 8.95431 0 20C0 31.0457 8.95431 40 20 40Z" fill="#E6F0EC"/>
|
||||||
|
<path d="M25.7161 23.9202V26.8242C27.8601 27.2402 29.5241 29.1922 29.5241 31.4442V33.9322C29.5241 34.4042 29.1681 34.7602 28.7521 34.8802L26.7881 35.2362C26.5481 35.2962 26.3121 35.1162 26.2521 34.8802L26.0721 33.9322C26.0121 33.6962 26.1921 33.4602 26.4281 33.4002L27.6201 33.1642V31.4402C27.6201 27.7682 21.9041 27.5882 21.9041 31.5602V33.1602L23.0361 33.3962C23.2761 33.4562 23.4521 33.6922 23.3921 33.9282L23.2121 34.8762C23.1521 35.1122 22.9161 35.2922 22.6761 35.2322L20.7721 34.9962C20.3561 34.9362 20.0001 34.5202 20.0001 34.0482V31.4402C20.0001 29.1882 21.6081 27.2922 23.8081 26.8202V24.1562C23.7281 24.1802 23.6641 24.1962 23.6041 24.2082C23.5281 24.2242 23.4601 24.2402 23.3921 24.2722C22.3201 24.6282 21.1881 24.8642 20.0001 24.8642C18.8081 24.8642 17.6201 24.6282 16.5481 24.2722C16.1561 24.1042 15.7121 24.0442 15.3161 23.9882C15.2881 23.9842 15.2641 23.9802 15.2361 23.9762V28.7722C16.6041 29.1882 17.6161 30.4322 17.6161 31.9722C17.6161 33.7482 16.1281 35.2882 14.2841 35.2882C12.4401 35.2882 10.9521 33.7482 10.9521 31.9722C10.9521 30.4322 11.9641 29.1882 13.3321 28.7722V24.0362C9.52406 24.6282 6.66406 27.8882 6.66406 31.8562V34.5202C6.66406 34.6602 6.68006 34.8002 6.70406 34.9362C10.2401 38.0842 14.8961 40.0002 20.0001 40.0002C25.1041 40.0002 29.7601 38.0842 33.2921 34.9402C33.3161 34.8042 33.3321 34.6642 33.3321 34.5242V31.8602C33.3321 27.5922 29.9401 24.1562 25.7161 23.9202Z" fill="#8EB7A5"/>
|
||||||
|
<path d="M12.8562 31.9161C12.8562 32.7441 13.4522 33.3361 14.2842 33.3361C15.0562 33.3361 15.7122 32.7441 15.7122 31.9161C15.7122 31.1441 15.0562 30.4961 14.2842 30.4961C13.4522 30.4921 12.8562 31.1441 12.8562 31.9161Z" fill="#8EB7A5"/>
|
||||||
|
<path d="M20.0001 21.96C24.2085 21.96 27.6201 18.5664 27.6201 14.38C27.6201 10.1937 24.2085 6.80005 20.0001 6.80005C15.7917 6.80005 12.3801 10.1937 12.3801 14.38C12.3801 18.5664 15.7917 21.96 20.0001 21.96Z" fill="#8EB7A5"/>
|
||||||
|
<circle cx="20" cy="20" r="19" stroke="white" stroke-width="2"/>
|
||||||
|
<path d="M50 40C61.0457 40 70 31.0457 70 20C70 8.95431 61.0457 0 50 0C38.9543 0 30 8.95431 30 20C30 31.0457 38.9543 40 50 40Z" fill="#E6F0EC"/>
|
||||||
|
<path d="M55.7161 23.9202V26.8242C57.8601 27.2402 59.5241 29.1922 59.5241 31.4442V33.9322C59.5241 34.4042 59.1681 34.7602 58.7521 34.8802L56.7881 35.2362C56.5481 35.2962 56.3121 35.1162 56.2521 34.8802L56.0721 33.9322C56.0121 33.6962 56.1921 33.4602 56.4281 33.4002L57.6201 33.1642V31.4402C57.6201 27.7682 51.9041 27.5882 51.9041 31.5602V33.1602L53.0361 33.3962C53.2761 33.4562 53.4521 33.6922 53.3921 33.9282L53.2121 34.8762C53.1521 35.1122 52.9161 35.2922 52.6761 35.2322L50.7721 34.9962C50.3561 34.9362 50.0001 34.5202 50.0001 34.0482V31.4402C50.0001 29.1882 51.6081 27.2922 53.8081 26.8202V24.1562C53.7281 24.1802 53.6641 24.1962 53.6041 24.2082C53.5281 24.2242 53.4601 24.2402 53.3921 24.2722C52.3201 24.6282 51.1881 24.8642 50.0001 24.8642C48.8081 24.8642 47.6201 24.6282 46.5481 24.2722C46.1561 24.1042 45.7121 24.0442 45.3161 23.9882C45.2881 23.9842 45.2641 23.9802 45.2361 23.9762V28.7722C46.6041 29.1882 47.6161 30.4322 47.6161 31.9722C47.6161 33.7482 46.1281 35.2882 44.2841 35.2882C42.4401 35.2882 40.9521 33.7482 40.9521 31.9722C40.9521 30.4322 41.9641 29.1882 43.3321 28.7722V24.0362C39.5241 24.6282 36.6641 27.8882 36.6641 31.8562V34.5202C36.6641 34.6602 36.6801 34.8002 36.7041 34.9362C40.2401 38.0842 44.8961 40.0002 50.0001 40.0002C55.1041 40.0002 59.7601 38.0842 63.2921 34.9402C63.3161 34.8042 63.3321 34.6642 63.3321 34.5242V31.8602C63.3321 27.5922 59.9401 24.1562 55.7161 23.9202Z" fill="#8EB7A5"/>
|
||||||
|
<path d="M42.8562 31.9161C42.8562 32.7441 43.4522 33.3361 44.2842 33.3361C45.0562 33.3361 45.7122 32.7441 45.7122 31.9161C45.7122 31.1441 45.0562 30.4961 44.2842 30.4961C43.4522 30.4921 42.8562 31.1441 42.8562 31.9161Z" fill="#8EB7A5"/>
|
||||||
|
<path d="M50.0001 21.96C54.2085 21.96 57.6201 18.5664 57.6201 14.38C57.6201 10.1937 54.2085 6.80005 50.0001 6.80005C45.7917 6.80005 42.3801 10.1937 42.3801 14.38C42.3801 18.5664 45.7917 21.96 50.0001 21.96Z" fill="#8EB7A5"/>
|
||||||
|
<circle cx="50" cy="20" r="19" stroke="white" stroke-width="2"/>
|
||||||
|
<path d="M80 40C91.0457 40 100 31.0457 100 20C100 8.95431 91.0457 0 80 0C68.9543 0 60 8.95431 60 20C60 31.0457 68.9543 40 80 40Z" fill="#E6F0EC"/>
|
||||||
|
<path d="M85.7161 23.9202V26.8242C87.8601 27.2402 89.5241 29.1922 89.5241 31.4442V33.9322C89.5241 34.4042 89.1681 34.7602 88.7521 34.8802L86.7881 35.2362C86.5481 35.2962 86.3121 35.1162 86.2521 34.8802L86.0721 33.9322C86.0121 33.6962 86.1921 33.4602 86.4281 33.4002L87.6201 33.1642V31.4402C87.6201 27.7682 81.9041 27.5882 81.9041 31.5602V33.1602L83.0361 33.3962C83.2761 33.4562 83.4521 33.6922 83.3921 33.9282L83.2121 34.8762C83.1521 35.1122 82.9161 35.2922 82.6761 35.2322L80.7721 34.9962C80.3561 34.9362 80.0001 34.5202 80.0001 34.0482V31.4402C80.0001 29.1882 81.6081 27.2922 83.8081 26.8202V24.1562C83.7281 24.1802 83.6641 24.1962 83.6041 24.2082C83.5281 24.2242 83.4601 24.2402 83.3921 24.2722C82.3201 24.6282 81.1881 24.8642 80.0001 24.8642C78.8081 24.8642 77.6201 24.6282 76.5481 24.2722C76.1561 24.1042 75.7121 24.0442 75.3161 23.9882C75.2881 23.9842 75.2641 23.9802 75.2361 23.9762V28.7722C76.6041 29.1882 77.6161 30.4322 77.6161 31.9722C77.6161 33.7482 76.1281 35.2882 74.2841 35.2882C72.4401 35.2882 70.9521 33.7482 70.9521 31.9722C70.9521 30.4322 71.9641 29.1882 73.3321 28.7722V24.0362C69.5241 24.6282 66.6641 27.8882 66.6641 31.8562V34.5202C66.6641 34.6602 66.6801 34.8002 66.7041 34.9362C70.2401 38.0842 74.8961 40.0002 80.0001 40.0002C85.1041 40.0002 89.7601 38.0842 93.2921 34.9402C93.3161 34.8042 93.3321 34.6642 93.3321 34.5242V31.8602C93.3321 27.5922 89.9401 24.1562 85.7161 23.9202Z" fill="#8EB7A5"/>
|
||||||
|
<path d="M72.8562 31.9161C72.8562 32.7441 73.4522 33.3361 74.2842 33.3361C75.0562 33.3361 75.7122 32.7441 75.7122 31.9161C75.7122 31.1441 75.0562 30.4961 74.2842 30.4961C73.4522 30.4921 72.8562 31.1441 72.8562 31.9161Z" fill="#8EB7A5"/>
|
||||||
|
<path d="M80.0001 21.96C84.2085 21.96 87.6201 18.5664 87.6201 14.38C87.6201 10.1937 84.2085 6.80005 80.0001 6.80005C75.7917 6.80005 72.3801 10.1937 72.3801 14.38C72.3801 18.5664 75.7917 21.96 80.0001 21.96Z" fill="#8EB7A5"/>
|
||||||
|
<circle cx="80" cy="20" r="19" stroke="white" stroke-width="2"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 6.2 KiB |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0.833252 1.3335L4.99992 5.50016L9.16658 1.3335" stroke="#005B33" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 244 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="18" viewBox="0 0 16 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M14.6666 9V4.83333C14.6666 3.91286 13.9204 3.16667 12.9999 3.16667H2.99992C2.07944 3.16667 1.33325 3.91286 1.33325 4.83333V14.8333C1.33325 15.7538 2.07944 16.5 2.99992 16.5H4.66658M10.4999 1.5V4.83333M5.49992 1.5V4.83333M1.33325 8.16667H14.6666M14.5476 11.5L9.38099 16.6666L7.16663 14.4523" stroke="#005B33" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 488 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="17" height="18" viewBox="0 0 17 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M14.6666 6.5V4.83333C14.6666 3.91286 13.9204 3.16667 12.9999 3.16667H2.99992C2.07944 3.16667 1.33325 3.91286 1.33325 4.83333V14.8333C1.33325 15.7538 2.07944 16.5 2.99992 16.5H5.49992M10.4999 1.5V4.83333M5.49992 1.5V4.83333M1.33325 8.16667H5.49992M12.1666 9.83333V16.5M8.83325 13.1667H15.4999" stroke="#005B33" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 490 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="11" viewBox="0 0 16 11" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M14.6666 0.833252L5.5 9.99988L1.33325 5.83325" stroke="#005B33" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 244 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="1.32996" y="1.33008" width="13.33" height="13.33" rx="4" stroke="#005B33" stroke-width="1.3"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 207 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M12.6263 5.95954C12.8801 5.7057 12.8801 5.29414 12.6263 5.0403C12.3724 4.78646 11.9609 4.78646 11.707 5.0403L12.6263 5.95954ZM6.3333 11.3333L5.87368 11.7929C6.12752 12.0467 6.53908 12.0467 6.79292 11.7929L6.3333 11.3333ZM4.29288 8.37363C4.03904 8.11979 3.62748 8.11979 3.37364 8.37363C3.1198 8.62748 3.1198 9.03903 3.37364 9.29287L4.29288 8.37363ZM11.707 5.0403L5.87368 10.8736L6.79292 11.7929L12.6263 5.95954L11.707 5.0403ZM3.37364 9.29287L5.87368 11.7929L6.79291 10.8736L4.29288 8.37363L3.37364 9.29287ZM4.66665 1.98325H11.3333V0.683252H4.66665V1.98325ZM14.0166 4.66658V11.3333H15.3166V4.66658H14.0166ZM11.3333 14.0166H4.66665V15.3166H11.3333V14.0166ZM1.98331 11.3333V4.66658H0.683313V11.3333H1.98331ZM4.66665 14.0166C3.18468 14.0166 1.98331 12.8152 1.98331 11.3333H0.683313C0.683313 13.5332 2.46671 15.3166 4.66665 15.3166V14.0166ZM14.0166 11.3333C14.0166 12.8152 12.8153 14.0166 11.3333 14.0166V15.3166C13.5332 15.3166 15.3166 13.5332 15.3166 11.3333H14.0166ZM11.3333 1.98325C12.8153 1.98325 14.0166 3.18462 14.0166 4.66658H15.3166C15.3166 2.46665 13.5332 0.683252 11.3333 0.683252V1.98325ZM4.66665 0.683252C2.46671 0.683252 0.683313 2.46665 0.683313 4.66658H1.98331C1.98331 3.18462 3.18468 1.98325 4.66665 1.98325V0.683252Z" fill="#005B33"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M11.9596 6.95962C12.2134 6.70578 12.2134 6.29422 11.9596 6.04038C11.7057 5.78654 11.2942 5.78654 11.0403 6.04038L11.9596 6.95962ZM6.04033 11.0404C5.78649 11.2942 5.78649 11.7058 6.04033 11.9596C6.29417 12.2135 6.70573 12.2135 6.95957 11.9596L6.04033 11.0404ZM6.95967 6.04038C6.70583 5.78654 6.29428 5.78654 6.04043 6.04038C5.78659 6.29422 5.78659 6.70578 6.04043 6.95962L6.95967 6.04038ZM11.0404 11.9596C11.2943 12.2135 11.7058 12.2135 11.9597 11.9596C12.2135 11.7058 12.2135 11.2942 11.9597 11.0404L11.0404 11.9596ZM11.0403 6.04038L6.04033 11.0404L6.95957 11.9596L11.9596 6.95962L11.0403 6.04038ZM6.04043 6.95962L11.0404 11.9596L11.9597 11.0404L6.95967 6.04038L6.04043 6.95962ZM15.85 9C15.85 12.7832 12.7832 15.85 9 15.85V17.15C13.5011 17.15 17.15 13.5011 17.15 9H15.85ZM9 15.85C5.21685 15.85 2.15 12.7832 2.15 9H0.85C0.85 13.5011 4.49888 17.15 9 17.15V15.85ZM2.15 9C2.15 5.21685 5.21685 2.15 9 2.15V0.85C4.49888 0.85 0.85 4.49888 0.85 9H2.15ZM9 2.15C12.7832 2.15 15.85 5.21685 15.85 9H17.15C17.15 4.49888 13.5011 0.85 9 0.85V2.15Z" fill="#8E8C8C"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="12" height="17" viewBox="0 0 12 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M1 2.99992C1 2.07944 1.74619 1.33325 2.66667 1.33325H9.33333C10.2538 1.33325 11 2.07944 11 2.99992V15.4999L6 10.4999L1 15.4999V2.99992Z" stroke="#005B33" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 334 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M1.3335 1.33325V0.683252C1.0972 0.683252 0.879525 0.811482 0.764979 1.01815C0.650432 1.22482 0.657063 1.47738 0.782297 1.67775L1.3335 1.33325ZM14.6668 1.33325L15.218 1.67775C15.3433 1.47738 15.3499 1.22482 15.2353 1.01815C15.1208 0.811482 14.9031 0.683252 14.6668 0.683252V1.33325ZM5.50016 7.99992H6.15016C6.15016 7.8781 6.11593 7.75872 6.05136 7.65542L5.50016 7.99992ZM10.5002 7.99992L9.94896 7.65542C9.8844 7.75872 9.85016 7.8781 9.85016 7.99992H10.5002ZM5.50016 12.9999H4.85016C4.85016 13.2461 4.98926 13.4712 5.20947 13.5813L5.50016 12.9999ZM10.5002 15.4999L10.2095 16.0813C10.411 16.182 10.6503 16.1713 10.8419 16.0528C11.0335 15.9344 11.1502 15.7252 11.1502 15.4999H10.5002ZM0.782297 1.67775L4.94896 8.34442L6.05136 7.65542L1.88469 0.988753L0.782297 1.67775ZM11.0514 8.34442L15.218 1.67775L14.1156 0.988753L9.94896 7.65542L11.0514 8.34442ZM4.85016 7.99992V12.9999H6.15016V7.99992H4.85016ZM5.20947 13.5813L10.2095 16.0813L10.7909 14.9185L5.79085 12.4185L5.20947 13.5813ZM11.1502 15.4999V7.99992H9.85016V15.4999H11.1502ZM1.3335 1.98325H14.6668V0.683252H1.3335V1.98325Z" fill="#005B33"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,5 @@
|
|||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M10 16.6666V8.33325" stroke="#005B33" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M15 16.6666V3.33325" stroke="#005B33" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M5 16.6666V13.3333" stroke="#005B33" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 447 B |
|
After Width: | Height: | Size: 38 KiB |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="16" height="18" viewBox="0 0 16 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M14.6666 8.16667C14.6666 11.8486 11.6818 14.8333 7.99992 16.5C4.31802 14.8333 1.33325 11.8486 1.33325 8.16667C1.33325 4.48477 4.31802 1.5 7.99992 1.5C11.6818 1.5 14.6666 4.48477 14.6666 8.16667Z" stroke="white" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M10.4999 8.16667C10.4999 9.54738 9.38063 10.6667 7.99992 10.6667C6.61921 10.6667 5.49992 9.54738 5.49992 8.16667C5.49992 6.78595 6.61921 5.66667 7.99992 5.66667C9.38063 5.66667 10.4999 6.78595 10.4999 8.16667Z" stroke="white" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 694 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="14" height="17" viewBox="0 0 14 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M1.1665 1V0.35C0.807519 0.35 0.516504 0.641015 0.516504 1L1.1665 1ZM12.8332 16V16.65C13.1922 16.65 13.4832 16.359 13.4832 16H12.8332ZM1.1665 16H0.516504C0.516504 16.359 0.807519 16.65 1.1665 16.65L1.1665 16ZM8.6665 1L9.12612 0.540381C9.00423 0.418482 8.8389 0.35 8.6665 0.35V1ZM12.8332 5.16667H13.4832C13.4832 4.99428 13.4147 4.82895 13.2928 4.70705L12.8332 5.16667ZM7.64984 7.66667C7.64984 7.30768 7.35882 7.01667 6.99984 7.01667C6.64085 7.01667 6.34984 7.30768 6.34984 7.66667H7.64984ZM6.34984 12.6667C6.34984 13.0257 6.64085 13.3167 6.99984 13.3167C7.35882 13.3167 7.64984 13.0257 7.64984 12.6667H6.34984ZM4.49984 9.51667C4.14085 9.51667 3.84984 9.80768 3.84984 10.1667C3.84984 10.5257 4.14085 10.8167 4.49984 10.8167V9.51667ZM9.49984 10.8167C9.85882 10.8167 10.1498 10.5257 10.1498 10.1667C10.1498 9.80768 9.85882 9.51667 9.49984 9.51667V10.8167ZM12.8332 15.35H1.1665V16.65H12.8332V15.35ZM1.8165 16V1H0.516504V16H1.8165ZM1.1665 1.65H8.6665V0.35H1.1665V1.65ZM12.1832 5.16667V16H13.4832V5.16667H12.1832ZM8.20689 1.45962L12.3736 5.62629L13.2928 4.70705L9.12612 0.540381L8.20689 1.45962ZM7.18317 1V4.33333H8.48317V1H7.18317ZM9.49984 6.65H12.8332V5.35H9.49984V6.65ZM7.18317 4.33333C7.18317 5.61279 8.22038 6.65 9.49984 6.65V5.35C8.93835 5.35 8.48317 4.89482 8.48317 4.33333H7.18317ZM6.34984 7.66667V12.6667H7.64984V7.66667H6.34984ZM4.49984 10.8167H9.49984V9.51667H4.49984V10.8167Z" fill="#005B33"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M15.207 16.1263C15.4609 16.3801 15.8724 16.3801 16.1263 16.1263C16.3801 15.8724 16.3801 15.4609 16.1263 15.207L15.207 16.1263ZM13.35 7.75C13.35 10.8428 10.8428 13.35 7.75 13.35V14.65C11.5608 14.65 14.65 11.5608 14.65 7.75H13.35ZM7.75 13.35C4.65721 13.35 2.15 10.8428 2.15 7.75H0.85C0.85 11.5608 3.93924 14.65 7.75 14.65V13.35ZM2.15 7.75C2.15 4.65721 4.65721 2.15 7.75 2.15V0.85C3.93924 0.85 0.85 3.93924 0.85 7.75H2.15ZM7.75 2.15C10.8428 2.15 13.35 4.65721 13.35 7.75H14.65C14.65 3.93924 11.5608 0.85 7.75 0.85V2.15ZM16.1263 15.207L12.6366 11.7174L11.7174 12.6366L15.207 16.1263L16.1263 15.207Z" fill="#8E8C8C"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 725 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0.833252 1.3335L4.99992 5.50016L9.16658 1.3335" stroke="white" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 242 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M9.16659 5.66667L4.99992 1.5L0.833252 5.66667" stroke="#005B33" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 242 B |
|
After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 3.7 KiB |