&& apk del .deps
RUN apk --no-cache --update --repository http://dl-cdn.alpinelinux.org/alpine/v$ALPINE_VERSION/main/ add \
- postgresql-dev
+ autoconf dpkg-dev dpkg file g++ gcc libc-dev make pkgconf re2c postgresql-dev
RUN docker-php-ext-install pdo_pgsql
#add composer
"kartik-v/yii2-bootstrap5-dropdown": "@dev",
"kartik-v/yii2-grid": "@dev",
"kartik-v/yii2-widget-datepicker": "dev-master",
- "phpoffice/phpspreadsheet": "^2.2"
+ "phpoffice/phpspreadsheet": "^2.2",
+ "ext-xmlreader": "*"
},
"require-dev": {
"yiisoft/yii2-debug": "~2.1.0",
--- /dev/null
+<?php
+
+namespace app\controllers;
+
+use Yii;
+use yii\helpers\ArrayHelper;
+use yii\helpers\Json;
+use yii\web\Controller;
+use yii\web\UploadedFile;
+use XMLReader;
+use yii_app\records\ProductionCalendar;
+
+class ProductionCalendarController extends Controller
+{
+ public function setCalendarValue($date, $work = null) {
+ $date = date("Y-m-d", strtotime($date));
+ $weekDay = date("N", strtotime($date));
+
+ $productionCalendar = ProductionCalendar::findOne(['date' => $date]);
+ if (!$productionCalendar) {
+ $productionCalendar = new ProductionCalendar;
+ $productionCalendar->date = $date;
+ }
+ $productionCalendar->work = $work ?? ($weekDay < 6 ? 1 : 0);
+ $productionCalendar->save();
+ if ($productionCalendar->getErrors()) {
+ throw new \Exception(Json::encode($productionCalendar->getErrors()));
+ }
+ }
+
+ public function parseXml($xml) {
+ $s = date("Y-01-01 00:00:00");
+ $f = date("Y-12-31 00:00:00");
+ while ($s < $f) {
+ $this->setCalendarValue($s);
+ $s = date("Y-m-d 00:00:00", strtotime("+1 day", strtotime($s)));
+ }
+ $calendarYear = '';
+ while ($xml->read()) {
+ if ($xml->nodeType == XMLReader::ELEMENT && $xml->localName == 'calendar') {
+ $calendarYear = $xml->getAttribute('year');
+ }
+ if ($xml->nodeType == XMLReader::ELEMENT && $xml->localName == 'day') {
+ $date1 = date($calendarYear . '-' . str_replace('.', '-', $xml->getAttribute('d')));
+ $work = $xml->getAttribute('t') > 1 ? 1 : 0;
+ $this->setCalendarValue($date1, $work);
+ }
+ }
+ }
+
+ public function actionIndex($viewYear = null) {
+ if (Yii::$app->request->isPost) {
+ $xml = UploadedFile::getInstanceByName('xmlFile');
+ $path = Yii::getAlias("@uploads") . '/' . $xml->getBaseName() . '.' . $xml->getExtension();
+ $xml->saveAs($path);
+
+ $xml = new XMLReader;
+ $xml->open($path);
+
+ $this->parseXml($xml);
+
+ Yii::$app->session->setFlash('success', 'Календарь успешно загружен.');
+ }
+
+ $months = ['Январь',' Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'];
+ $daysInWeek = ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'];
+
+ $workDaysMap = ArrayHelper::map(ProductionCalendar::find()->where(['between', 'date', '2024-01-01', '2024-12-31'])->all(), 'date', 'work');
+
+ if (!$viewYear) {
+ $viewYear = date('Y');
+ }
+
+ $workDaysInMonthCountMap = [];
+ foreach (range(1,12) as $monthIndex) {
+ if ($monthIndex < 10) {
+ $monthIndex = '0' . $monthIndex;
+ }
+ $date1 = date($viewYear . '-' . $monthIndex . '-01');
+ $date2 = date($viewYear . '-' . $monthIndex . '-t', strtotime($date1));
+ $cnt = 0;
+ while ($date1 <= $date2) {
+ $cnt += $workDaysMap[$date1];
+ $date1 = date('Y-m-d', strtotime('+1 day', strtotime($date1)));
+ }
+ $workDaysInMonthCountMap[$monthIndex] = $cnt;
+ }
+
+ $years = [];
+ foreach (range(2023, date('Y')) as $y) {
+ $years[$y] = $y;
+ }
+
+ return $this->render('index',
+ compact('months', 'daysInWeek', 'workDaysMap', 'viewYear', 'years', 'workDaysInMonthCountMap'));
+ }
+}
\ No newline at end of file
--- /dev/null
+<?php
+
+use yii\db\Migration;
+
+/**
+ * Class m240925_063026_create_table_production_calendar
+ */
+class m240925_063026_create_table_production_calendar extends Migration
+{
+ const TABLE_NAME = 'erp24.production_calendar';
+ /**
+ * {@inheritdoc}
+ */
+ public function safeUp()
+ {
+ $this->createTable(self::TABLE_NAME, [
+ 'id' => $this->primaryKey(),
+ 'date' => $this->string(10)->notNull()->comment('День определяющих рабочее состояние'),
+ 'work' => $this->tinyInteger()->notNull()->comment('1 - будни, 0 - выходной или праздник'),
+ ]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function safeDown()
+ {
+ $this->dropTable(self::TABLE_NAME);
+ }
+}
--- /dev/null
+<?php
+
+namespace yii_app\records;
+
+use Yii;
+
+/**
+ * This is the model class for table "production_calendar".
+ *
+ * @property int $id
+ * @property string $date День определяющих рабочее состояние
+ * @property int $work 1 - будни, 0 - выходной или праздник
+ */
+class ProductionCalendar extends \yii\db\ActiveRecord
+{
+ /**
+ * {@inheritdoc}
+ */
+ public static function tableName()
+ {
+ return 'production_calendar';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function rules()
+ {
+ return [
+ [['date', 'work'], 'required'],
+ [['work'], 'default', 'value' => null],
+ [['work'], 'integer'],
+ [['date'], 'string', 'max' => 10],
+ ];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'id' => 'ID',
+ 'date' => 'Date',
+ 'work' => 'Work',
+ ];
+ }
+}
--- /dev/null
+<?php
+
+use yii\helpers\Html;
+use yii\widgets\ActiveForm;
+
+/** @var $months array */
+/** @var $daysInWeek array */
+/** @var $workDaysMap array */
+/** @var $years array */
+/** @var $viewYear string */
+/** @var $workDaysInMonthCountMap array */
+
+$this->registerCssFile('/css/production-calendar/style.css');
+
+?>
+
+<div class="productionCalendarIndex m-5">
+
+ <?php if (Yii::$app->session->hasFlash('success')): ?>
+ <div class="alert alert-success alert-dismissable">
+ <button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button>
+ <?= Yii::$app->session->getFlash('success') ?>
+ </div>
+ <?php endif; ?>
+
+ <?php ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>
+
+ <?= Html::fileInput('xmlFile', null, ['class' => 'btn btn-success', 'onchange' => 'this.form.submit()', 'accept' => '.xml']) ?>
+
+ Отобразить календарь за <?= Html::dropDownList('year', $viewYear, $years,
+ ['onchange' => 'window.location = "/production-calendar/index?viewYear=" + this.value;']) ?> год.
+ Текущий просматриваемый год: <b><?= $viewYear ?></b>.
+
+ <?php Activeform::end() ?>
+
+
+ <div class="pcal-month-container" style="max-width: 1230px;">
+ <?php foreach ($months as $monthIndex => $month): ?>
+ <div class="pcal-month w-20" style="max-width: 250px;">
+ <div class="pcal-month-name"><?= $month; ?></div>
+ <div class="pcal-days">
+ <table>
+ <tbody>
+ <tr>
+ <?php foreach ($daysInWeek as $dayName): ?>
+ <td class="pcal-day-of-week1"><?= $dayName; ?></td>
+ <?php endforeach; ?>
+ </tr>
+ <?php $padMonth = ($monthIndex + 1) < 10 ? '0' . ($monthIndex + 1) : ($monthIndex + 1); ?>
+ <?php $num = 1 - date('N', strtotime(date($viewYear . "-" . $padMonth . "-01"))); ?>
+ <?php $numMonth = date('t', strtotime(date($viewYear . "-" . $padMonth . "-01"))); ?>
+ <?php foreach (range(1, 6) as $weekNum): ?>
+ <tr>
+ <?php foreach ($daysInWeek as $dayIndexInWeek => $dayName): ?>
+ <?php $num++; ?>
+ <?php $date = $viewYear . '-' . $padMonth . '-' . ($num < 10 ? '0' . $num : $num); ?>
+ <td class="text-center pcal-day <?= ($workDaysMap[$date] ?? -1) == 0 ? 'pcal-day-holiday' : ''?>">
+ <?= $num > 0 && $num <= $numMonth ? $num : ' ' ?></td>
+ <?php endforeach; ?>
+ </tr>
+ <?php endforeach; ?>
+ <tr>
+ <td colspan="7" style="font-size: 1rem;">Число рабочих дней: <?= $workDaysInMonthCountMap[$padMonth] ?></td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ <?php endforeach; ?>
+ </div>
+
+</div>
--- /dev/null
+h1 {
+ text-align: center;
+}
+h2 {
+ text-align: center;
+}
+.text-right {
+ text-align: right;
+}
+.text-left {
+ text-align: left;
+}
+.text-center {
+ text-align: center;
+}
+/*.pcal-month-container, .pcal-norm-container {*/
+/* clear:both;*/
+/* display: block;*/
+/*}*/
+.pcal-norm-container table {
+ width: 100%;
+}
+.pcal-norm-container thead, .pcal-norm-container tfoot {
+ font-weight: bold;
+}
+.pcal-month div, .pcal-month td, thead {
+ font-size: 22px;
+}
+.pcal-month td , td {
+ padding: 3px;
+}
+.pcal-month {
+ width: 230px;
+ float: left;
+ margin: 5px;
+}
+.pcal-day-of-week1 {
+ font-size: 1rem !important;
+}
+.pcal-day-of-week, td.pcal-norm-month, .pcal-norm-container tfoot td{
+ background-color: #DAE8F3;
+ font-weight: bold;
+}
+.pcal-month-name {
+ font-weight: bold;
+ text-align: center;
+}
+.pcal-day {
+ cursor: pointer;
+}
+.pcal-day-hover {
+ background-color: #ffff99;
+}
+.pcal-day-short {
+ font-weight: bold;
+ color: #8EBC51;
+}
+.pcal-day-holiday {
+ font-weight: bold;
+ color: #e20000;
+}
+.pcal-current {
+ /*border: 2px solid red;*/
+ background-color: #FFD4D4;
+}
+.pcal-footer {
+ margin: 20px 5px 5px 5px;
+}
+.pcal-footer-ital {
+ font-style: italic;
+}