Последние сообщения

Егор Савельев
Егор Савельев
  • Сообщений: 18
  • Последний визит: 20 января 2025 в 23:17

А смысл писать, если там этот компонент выйдет в новой версии, тем более логично что там пишет команда, а тут Вы один будете, проще дождаться уже. 

Владислав Кузнецов
Владислав Кузнецов
  • Сообщений: 16
  • Последний визит: 20 января 2025 в 19:38

Вот общий план, как можно реализовать компонент бронирования в ДСТ Мед:

Backend1. Модель бронирования:

class Booking extends Model {
protected $fillable = ['doctor_id', 'user_id', 'status', 'appointment_time'];
 
public function doctor() {
return $this->belongsTo(Doctor::class);
}
 
public function user() {
return $this->belongsTo(User::class);
}
}

1. Контроллер бронирования:

class BookingController extends Controller {
public function create(Request $request) {
$booking = Booking::create([
'doctor_id' => $request->doctor_id,
'user_id' => $request->user_id,
'status' => 'pending',
'appointment_time' => $request->appointment_time,
]);
 
return response()->json($booking);
}
 
public function updateStatus(Request $request, $id) {
$booking = Booking::find($id);
$booking->status = $request->status;
$booking->save();
 
return response()->json($booking);
}
 
public function index() {
$bookings = Booking::with('doctor', 'user')->get();
return response()->json($bookings);
}
}

1. Маршруты:

Route::post('/bookings', [BookingController::class, 'create']);
Route::put('/bookings/{id}/status', [BookingController::class, 'updateStatus']);
Route::get('/bookings', [BookingController::class, 'index']);

Frontend1. Форма бронирования:

<form id="bookingForm">
<input type="hidden" name="doctor_id" value="{{ doctor.id }}">
<input type="hidden" name="user_id" value="{{ user.id }}">
<input type="datetime-local" name="appointment_time" required>
<button type="submit">Забронировать</button>
</form>
<script>
document.getElementById('bookingForm').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
 
fetch('/bookings', {
method: 'POST',
body: formData
}).then(response => response.json())
.then(data => {
alert('Бронирование успешно создано!');
});
});
</script>

1. Админка для управления бронированиями:

<table id="bookingsTable">
<thead>
<tr>
<th>Врач</th>
<th>Пациент</th>
<th>Время</th>
<th>Статус</th>
<th>Действия</th>
</tr>
</thead>
<tbody>
<!-- Здесь будут строки с бронированиями -->
</tbody>
</table>
<script>
function loadBookings() {
fetch('/bookings')
.then(response => response.json())
.then(data => {
const tableBody = document.querySelector('#bookingsTable tbody');
tableBody.innerHTML = '';
data.forEach(booking => {
const row = document.createElement('tr');
row.innerHTML = `
<td>${booking.doctor.name}</td>
<td>${booking.user.name}</td>
<td>${booking.appointment_time}</td>
<td>${booking.status}</td>
<td>
<select onchange="updateStatus(${booking.id}, this.value)">
<option value="pending" ${booking.status === 'pending' ? 'selected' : ''}>В ожидании</option>
<option value="accepted" ${booking.status === 'accepted' ? 'selected' : ''}>Принято</option>
<option value="rejected" ${booking.status === 'rejected' ? 'selected' : ''}>Отказано</option>
</select>
</td>
`;
tableBody.appendChild(row);
});
});
}
 
function updateStatus(id, status) {
fetch(`/bookings/${id}/status`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ status })
}).then(response => response.json())
.then(data => {
alert('Статус обновлен!');
loadBookings();
});
}
 
loadBookings();
</script>

База данных1. Миграция для таблицы бронирований:

Schema::create('bookings', function (Blueprint $table) {
$table->id();
$table->foreignId('doctor_id')->constrained();
$table->foreignId('user_id')->constrained();
$table->string('status');
$table->timestamp('appointment_time');
$table->timestamps();
});

Этот пример демонстрирует базовую реализацию компонента бронирования. Вы можете адаптировать его под вашу конкретную архитектуру и требования.

Егор Савельев
Егор Савельев
  • Сообщений: 18
  • Последний визит: 20 января 2025 в 23:17

Использовать:

SELECT t.contactid     FROM YOUR_TABLE t    WHERE flag IN ('Volunteer', 'Uploaded') GROUP BY t.contactid   HAVING COUNT(DISTINCT t.flag) = 2 

Главное, чтобы подсчет

t.flag
должно равняться количеству аргументов в
IN
пункт.

Использование

COUNT(DISTINCT t.flag)
в случае, если нет уникального ограничения на комбинацию контактного идентификатора и флага — если нет вероятности дублирования, вы можете опустить DISTINCT из запроса:

SELECT t.contactid     FROM YOUR_TABLE t    WHERE flag IN ('Volunteer', 'Uploaded') GROUP BY t.contactid   HAVING COUNT(t.flag) = 2 
Редактировалось: 1 раз (Последний: 20 января 2025 в 02:14)
Владислав Кузнецов
Владислав Кузнецов
  • Сообщений: 16
  • Последний визит: 20 января 2025 в 19:38

Вы можете использовать

GROUP BY
и
HAVING COUNT(*) = _
:

SELECT contact_id FROM your_table WHERE flag IN ('Volunteer', 'Uploaded', ...) GROUP BY contact_id HAVING COUNT(*) = 2 -- // must match number in the WHERE flag IN (...) list 

(при условии

contact_id, flag
является уникальным).

Или используйте объединения:

SELECT T1.contact_id FROM your_table T1 JOIN your_table T2 ON T1.contact_id = T2.contact_id AND T2.flag = 'Uploaded' -- // more joins if necessary WHERE T1.flag = 'Volunteer' 

Если список флагов очень длинный и много совпадений, первый, вероятно, будет быстрее. Если список флагов короткий и совпадений мало, вы, вероятно, обнаружите, что второй быстрее. Если производительность вызывает беспокойство, попробуйте протестировать оба варианта на своих данных, чтобы определить, какой из них работает лучше всего. 

Редактировалось: 1 раз (Последний: 20 января 2025 в 02:14)
Автотрейд
Автотрейд
  • Сообщений: 14
  • Последний визит: 20 января 2025 в 01:49

Если вы создадите индекс на

table(col1, col2)
, и ты делаешь
WHERE col1 = 'something' AND col2 = 'something'
вы будете использовать индекс; это будет очень избирательно. То же самое с
WHERE col1 = 'something'

Но

WHERE col1 IS NOT NULL
вам придется протестировать.
WHERE col1 IS NULL
будет сканировать таблицу, поскольку в этой ситуации индекс вовсе не является избирательным.

Обновление индекса с помощью INSERT или UPDATE требует небольших накладных расходов. Это не может быть УНИКАЛЬНЫЙ индекс, поэтому рабочая нагрузка немного меньше. Но в большинстве случаев об этом не стоит беспокоиться, если только ваша рабочая нагрузка INSERT/UPDATE не намного тяжелее рабочей нагрузки SELECT. Если вы можете сделать столбцы

COLLATE latin1_bin
вы получите максимально легкие индексы. Но никаких смайлов, китайских иероглифов или нечувствительности к регистру.

Редактировалось: 1 раз (Последний: 20 января 2025 в 01:45)
Автотрейд
Автотрейд
  • Сообщений: 14
  • Последний визит: 20 января 2025 в 01:49
Всё зависит от ваших целей. Если вы стремитесь создать MVP (минимально жизнеспособный продукт), то вам подойдёт CS Cart. Это быстро и недорого.

Если же вы хотите настоящий, эффективно работающий маркетплейс, то лучше выбрать ДСТ. Однако стоит помнить, что никакой движок не может заменить организационную работу. Многие начинающие предприниматели не понимают этого и не учитывают, когда открывают свой бизнес.

Кроме выбора CMS-системы, вам понадобятся качественный бизнес-план, финансовые средства, товары и поставщики, а также соответствующие документы.
Редактировалось: 1 раз (Последний: 19 января 2025 в 19:17)
Автотрейд
Автотрейд
  • Сообщений: 14
  • Последний визит: 20 января 2025 в 01:49
Вы можете использовать тип объединения, который позволяет enforceAdvancedOrder быть логическим значением, если enableAdvancedFeatures установлено на true и в противном случае требует, чтобы enforceAdvancedOrder является неопределенным.

Вот как:
type Options = ({
    settings?: Settings<true>;
    enforceAdvancedOrder?: boolean;
} | {
    settings?: Settings<false | undefined>;
    enforceAdvancedOrder?: never;
});
 
type Settings<B extends boolean | undefined = boolean> = B extends undefined ? {
    enableAdvancedFeature?: B;
} : {
    enableAdvancedFeature: B;
};

Вот несколько образцов для проверки:
const validOption1: Options = {
    settings: { enableAdvancedFeature: true },
    enforceAdvancedOrder: true,
};
 
const validOption2: Options = {
    settings: { enableAdvancedFeature: false },
    enforceAdvancedOrder: undefined, // enforceAdvancedOrder should be undefined
};
 
const validOption3: Options = {
    settings: {},
    enforceAdvancedOrder: undefined, // enforceAdvancedOrder should be undefined
};
 
const invalidOption: Options = {
    settings: { enableAdvancedFeature: false },
    enforceAdvancedOrder: true, // This should cause a TypeScript error
};
 
const invalidOption2: Options = {
    settings: {},
    enforceAdvancedOrder: true, // This should cause a TypeScript error
};
Владимир Соколов
Владимир Соколов
  • Сообщений: 14
  • Последний визит: 20 января 2025 в 01:48
Просто так:
type ConditionalOption =
    | { enforceAdvancedOrder?: boolean, settings?: { enableAdvancedFeature?: true } }
    | { enforceAdvancedOrder?: undefined, settings?: { enableAdvancedFeature?: false | undefined } }

Примеры:
let a: ConditionalOption = {
    settings: {
        enableAdvancedFeature: true
    },
    enforceAdvancedOrder: true
} // okay
 
let b: ConditionalOption = {
    settings: {
        enableAdvancedFeature: false
    },
    enforceAdvancedOrder: true
} // throws error
 
let c: ConditionalOption = {
    settings: {
        enableAdvancedFeature: false
    },
    enforceAdvancedOrder: undefined
} // okay
Технопарк Нобель
Технопарк Нобель
  • Сообщений: 9
  • Последний визит: 20 января 2025 в 01:51
Добавьте приведенный ниже код в свой CSS-файл, чтобы импортировать веб-шрифты Google.
@import url(https://fonts.googleapis.com/css?family=Open+Sans);

Замените значение параметра Open+Sans на имя вашего шрифта.

Ваш CSS-файл должен выглядеть так:
@import url(https://fonts.googleapis.com/css?family=Open+Sans);
 
body{
   font-family: 'Open Sans',serif;
}


DST Global
DST Global
  • Сообщений: 6
  • Последний визит: Сегодня в 16:14
Используйте @import метод:
@import url('https://fonts.googleapis.com/css?family=Open+Sans&display=swap');

Очевидно, «Открытый Санс» ( Open+Sans) — это импортируемый шрифт. Так что замените его на свой. Если имя шрифта состоит из нескольких слов, закодируйте его по URL-адресу, добавив + подпишитесь между каждым словом, как это сделал я.

Обязательно поместите @import в самом верху вашего CSS, перед любыми правилами.

Google Fonts может автоматически генерировать @import директива для вас. Выбрав шрифт, нажмите кнопку (+) значок рядом с ним. В левом нижнем углу появится контейнер под названием «Выбрано 1 семейство». Нажмите на нее, и она расширится. Используйте вкладку «Настроить», чтобы выбрать параметры, а затем вернитесь к «Встроить» и нажмите «@import» в разделе «Встроить шрифт». Скопируйте CSS между
Технопарк Нобель
Технопарк Нобель
  • Сообщений: 9
  • Последний визит: 20 января 2025 в 01:51
По моему мнению, поработав с несколькими разными системами, создание маркетплейса на DST Маркетплейс имеет несколько ключевых преимуществ по сравнению с другими популярными платформами, такими как CS Cart и 1С-Битрикс:
1. Битрикс это все таки Интернет-магазин, а маркетплейс это лишь расширение т.е. отдельный модуль, что конечно сразу усложняет всю ситуацию с дальнейшим масштабированием.
2. С Agora не работал, так что тут ничего сказать не могу.
3. На CS Cart нам не хватило функционала, даже купив самую дорогую лицензию ее оказалось меньше чем в базовой DST Маркетплейс.
4. Также попробовали и WordPress с модулем WooCommerce, оказалась вообще игрушкой, нет ни ЛК поставщика, не серьезных инструментов аналитики, ни системы уведомлений, да вообще ничего.
Так что если рассматривать альтернативы, то сейчас на рынке 2 системы для запуска своего маркетплейса это CS Cart и DST Маркетплейс, мы выбрали последнее.

Ну а главные преимущества это конечно огромное количество разного функционала, просто сравните ЛК клиента и ЛК поставщика в DST Маркетплейс и сразу поймете в чем разница.
Автотрейд
Автотрейд
  • Сообщений: 14
  • Последний визит: 20 января 2025 в 01:49

Автотрейд, спасибо за ответ, а не подскажите может у Вас какая то расширенная лицензия — Энтерпрайз, у меня просто лицензия Премиум, а также если не секрет во сколько обходиться содержание сервера?


Владимир Соколов


Все верно у нас Энтерпрайз, но это не важно, все лицензии DST Маркетплейс с нагрузками работают одинаково и не имеют никаких ограничений, это мы уже пробовали т.к. раньше сидели на Премиум.

По поводу сервера, то мы платили примерно 30-40 т.р. в месяц, но затем заказали работы по оптимизации сервера и снизили расходы до 20-25 т.р. в месяц, что при таком объеме считаем очень хорошим показателем.
Редактировалось: 1 раз (Последний: 19 января 2025 в 13:27)
Владимир Соколов
Владимир Соколов
  • Сообщений: 14
  • Последний визит: 20 января 2025 в 01:48
Автотрейд, спасибо за ответ, а не подскажите может у Вас какая то расширенная лицензия — Энтерпрайз, у меня просто лицензия Премиум, а также если не секрет во сколько обходиться содержание сервера?
Автотрейд
Автотрейд
  • Сообщений: 14
  • Последний визит: 20 января 2025 в 01:49
Ну 200К это не так много, у нас маркетплейс автозапчастей и уже более 2 млн. позиций, все работает и летает отлично, единственное что нужно это увеличивать и оптимизировать возможности сервера чтоб ежемесячно меньше выходило платить, так что тут больше не от движка зависит а от конфигурации Вашего сервера
Технопарк Нобель
Технопарк Нобель
  • Сообщений: 9
  • Последний визит: 20 января 2025 в 01:51
У нас VPS на adminvps.ru 5, отличная техподдержка, отвечают мгновенно, помогают решить проблемы, даже те которые по сути лежат на плечах администратора VPS.
Редактировалось: 1 раз (Последний: 19 января 2025 в 12:45)
← Предыдущая Следующая → Первая 3 4 5 6 7 8
Показаны 76-90 из 112

Заявка на услуги DST

Наш специалист свяжется с вами, обсудит оптимальную стратегию сотрудничества,
поможет сформировать бизнес требования и рассчитает стоимость услуг.

Адрес

Ижевск, ул. Воткинское шоссе, д. 170 Е, Технопарк Нобель, офис 1117

8 495 1985800
Заказать звонок

Режим работы: Пн-Пт 10:00-19:00

info@dstglobal.ru

Задать вопрос по почте

Укажите ваше имя
Укажите ваше email
Укажите ваше телефон