v1.1
This commit is contained in:
parent
3f30854c04
commit
295ed58901
5
.env
5
.env
@ -1 +1,4 @@
|
|||||||
VITE_API_BASE_URL=https://45.146.164.63:8080
|
# VUE_APP_API_URL=http://31.129.106.67:8080
|
||||||
|
# VUE_APP_GEO_URL=http://31.129.106.67:6001
|
||||||
|
VUE_APP_API_URL=http://127.0.0.1:8080
|
||||||
|
VUE_APP_GEO_URL=http://127.0.0.1:6001
|
@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<Main />
|
<Main />
|
||||||
<StopInfo />
|
<StopInfo />
|
||||||
<CarrierInfo />
|
<CarrierInfo @president-appeal-toggle="presidentOpen = $event" />
|
||||||
<WeatherInfo />
|
<WeatherInfo :is-president-address-open="presidentOpen" />
|
||||||
<RouteInfo />
|
<RouteInfo />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -22,6 +22,11 @@ export default {
|
|||||||
WeatherInfo,
|
WeatherInfo,
|
||||||
RouteInfo,
|
RouteInfo,
|
||||||
},
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
presidentOpen: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -18,18 +18,29 @@ body {
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.station-label-no-bg {
|
.station-label-no-bg,
|
||||||
|
.station-name-ru {
|
||||||
background: transparent !important;
|
background: transparent !important;
|
||||||
border: none !important;
|
border: none !important;
|
||||||
box-shadow: none !important;
|
box-shadow: none !important;
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #fff;
|
|
||||||
/* max-width: 200px; */
|
/* max-width: 200px; */
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
/* text-wrap: revert; */
|
/* text-wrap: revert; */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.station-name-ru {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.station-name-en {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #ffffffad;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
.station-label-no-bg:before {
|
.station-label-no-bg:before {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
@ -40,6 +51,7 @@ body {
|
|||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stopinfo .bg {
|
.stopinfo .bg {
|
||||||
@ -48,6 +60,15 @@ body {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stopinfo .bg * {
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stopinfo .container {
|
||||||
|
margin-bottom: 75px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
@ -118,14 +139,22 @@ body {
|
|||||||
top: 18px;
|
top: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.landmarks-container {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.stoparticles {
|
.stoparticles {
|
||||||
|
padding: 0 15px;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
gap: 45px;
|
text-align: center;
|
||||||
|
gap: 15px;
|
||||||
|
justify-content: space-around;
|
||||||
background: rgb(187, 179, 170);
|
background: rgb(187, 179, 170);
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
180deg,
|
180deg,
|
||||||
@ -150,6 +179,7 @@ body {
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin: 0 15px 15px 15px;
|
margin: 0 15px 15px 15px;
|
||||||
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stop-buttons-container {
|
.stop-buttons-container {
|
||||||
@ -167,6 +197,7 @@ body {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.white {
|
.white {
|
||||||
@ -225,6 +256,7 @@ body {
|
|||||||
left: 0;
|
left: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 350px;
|
width: 350px;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.carrierinfo .bg {
|
.carrierinfo .bg {
|
||||||
@ -310,7 +342,7 @@ body {
|
|||||||
.weatherinfo {
|
.weatherinfo {
|
||||||
z-index: 450;
|
z-index: 450;
|
||||||
width: 225px;
|
width: 225px;
|
||||||
padding: 10px 15px;
|
padding: 10px 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -336,8 +368,9 @@ body {
|
|||||||
|
|
||||||
.weatherinfo .date {
|
.weatherinfo .date {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 18px;
|
font-size: 15px;
|
||||||
padding: 2px 0 8px 0;
|
font-weight: lighter;
|
||||||
|
padding: 0 0 8px 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-bottom: 1px solid #ffffff7a;
|
border-bottom: 1px solid #ffffff7a;
|
||||||
}
|
}
|
||||||
@ -346,13 +379,16 @@ body {
|
|||||||
width: 75px;
|
width: 75px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.current-weather {
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.current-weather div {
|
.current-weather div {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: 5px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.temperature-celsius {
|
.temperature-celsius {
|
||||||
font-size: 35px;
|
font-size: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.forecast-day {
|
.forecast-day {
|
||||||
@ -366,7 +402,7 @@ body {
|
|||||||
|
|
||||||
.weather-forecast {
|
.weather-forecast {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0 10px;
|
padding: 0;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -376,15 +412,22 @@ body {
|
|||||||
.forecast {
|
.forecast {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 7px;
|
gap: 10px;
|
||||||
|
width: 90px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forecast-day {
|
||||||
|
font-size: 17px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.additional-forecast {
|
.additional-forecast {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
border-top: 1px solid #ffffff7a;
|
border-top: 1px solid #ffffff7a;
|
||||||
padding: 10px 0 0 7px;
|
padding: 10px 0 0 3px;
|
||||||
gap: 7px;
|
gap: 7px;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.additional-forecast .humidity,
|
.additional-forecast .humidity,
|
||||||
@ -417,7 +460,7 @@ body {
|
|||||||
.route-names {
|
.route-names {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 15px;
|
/* gap: 2px; */
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,7 +521,7 @@ body {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 10px;
|
bottom: 10px;
|
||||||
left: 310px;
|
left: 310px;
|
||||||
background: rgba(0, 0, 0, 0.4);
|
background: rgba(0, 0, 0, 0);
|
||||||
border: none;
|
border: none;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
@ -487,6 +530,7 @@ body {
|
|||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
z-index: 1001;
|
z-index: 1001;
|
||||||
transition: left 0.3s ease;
|
transition: left 0.3s ease;
|
||||||
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.carrierinfo .bg.hidden + .carrier-toggle {
|
.carrierinfo .bg.hidden + .carrier-toggle {
|
||||||
@ -550,21 +594,6 @@ body {
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.carrier-toggle {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 10px;
|
|
||||||
left: 310px;
|
|
||||||
background: rgba(0, 0, 0, 0.4);
|
|
||||||
border: none;
|
|
||||||
color: #fff;
|
|
||||||
font-size: 24px;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 5px 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
z-index: 1001;
|
|
||||||
transition: left 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.carrierinfo .bg.hidden + .carrier-toggle {
|
.carrierinfo .bg.hidden + .carrier-toggle {
|
||||||
left: 10px;
|
left: 10px;
|
||||||
}
|
}
|
||||||
@ -576,6 +605,7 @@ body {
|
|||||||
|
|
||||||
.bg {
|
.bg {
|
||||||
transition: transform 0.3s ease;
|
transition: transform 0.3s ease;
|
||||||
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-name {
|
.dropdown-name {
|
||||||
@ -680,16 +710,6 @@ li.checked {
|
|||||||
|
|
||||||
.stoparticle-option {
|
.stoparticle-option {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stoparticle-option.selected {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stoparticle-option {
|
|
||||||
cursor: pointer;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.stoparticle-option.selected {
|
.stoparticle-option.selected {
|
||||||
@ -958,3 +978,21 @@ li.checked {
|
|||||||
.sight-preview-wrapper {
|
.sight-preview-wrapper {
|
||||||
max-height: 300px;
|
max-height: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.governor-appeal {
|
||||||
|
top: 140px;
|
||||||
|
width: 440px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.governor-appeal p {
|
||||||
|
max-height: 400px;
|
||||||
|
line-height: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.governor-appeal h3 {
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
@ -589,7 +589,6 @@
|
|||||||
clip-rule="evenodd"
|
clip-rule="evenodd"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
<span class="gos-name"
|
<span class="gos-name"
|
||||||
>При поддержке Правительства <br />
|
>При поддержке Правительства <br />
|
||||||
Санкт-Петербурга</span
|
Санкт-Петербурга</span
|
||||||
@ -713,7 +712,7 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="showGovernorAppeal" class="sight-preview-panel">
|
<div v-if="showGovernorAppeal" class="governor-appeal sight-preview-panel">
|
||||||
<img :src="governorAppealImage" v-if="governorAppealImage" />
|
<img :src="governorAppealImage" v-if="governorAppealImage" />
|
||||||
<h3>{{ governorAppealTitle }}</h3>
|
<h3>{{ governorAppealTitle }}</h3>
|
||||||
<p>{{ governorAppealText }}</p>
|
<p>{{ governorAppealText }}</p>
|
||||||
@ -739,16 +738,17 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import "../assets/style/main.css";
|
import "../assets/style/main.css";
|
||||||
|
import { API_URL, GEO_URL } from "../config";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "StopInfo",
|
name: "CarrierInfo",
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
stations: [],
|
stations: [],
|
||||||
showList: false,
|
showList: false,
|
||||||
sights: [],
|
sights: [],
|
||||||
showSightsList: false,
|
showSightsList: false,
|
||||||
routeId: null,
|
routeId: 1,
|
||||||
isHidden: true,
|
isHidden: true,
|
||||||
selectedSightId: null,
|
selectedSightId: null,
|
||||||
selectedSightName: "",
|
selectedSightName: "",
|
||||||
@ -763,6 +763,7 @@ export default {
|
|||||||
governorAppealId: null,
|
governorAppealId: null,
|
||||||
selectedSightWatermarkLU: "",
|
selectedSightWatermarkLU: "",
|
||||||
selectedSightWatermarkRD: "",
|
selectedSightWatermarkRD: "",
|
||||||
|
inactivityTimer: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -778,16 +779,10 @@ export default {
|
|||||||
},
|
},
|
||||||
async fetchStops() {
|
async fetchStops() {
|
||||||
try {
|
try {
|
||||||
const geoResponse = await fetch(
|
const geoResponse = await fetch(`${GEO_URL}/v1/geolocation/context`);
|
||||||
"http://31.129.106.67:6001/v1/geolocation/context"
|
|
||||||
);
|
|
||||||
const geoData = await geoResponse.json();
|
const geoData = await geoResponse.json();
|
||||||
const token = this.getCookie("auth_token");
|
|
||||||
const routeDetailsRes = await fetch(
|
const routeDetailsRes = await fetch(
|
||||||
`https://wn-ts.krbl.ru/route/${geoData.routeId}`,
|
`${API_URL}/route/${geoData.routeId}`
|
||||||
{
|
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
const routeDetails = await routeDetailsRes.json();
|
const routeDetails = await routeDetailsRes.json();
|
||||||
const appealId = routeDetails.governor_appeal;
|
const appealId = routeDetails.governor_appeal;
|
||||||
@ -802,29 +797,18 @@ export default {
|
|||||||
|
|
||||||
if (appealId && appealId !== 0) {
|
if (appealId && appealId !== 0) {
|
||||||
try {
|
try {
|
||||||
const articleRes = await fetch(
|
const articleRes = await fetch(`${API_URL}/article/${appealId}`);
|
||||||
`https://wn-ts.krbl.ru/article/${appealId}`,
|
|
||||||
{
|
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const articleData = await articleRes.json();
|
const articleData = await articleRes.json();
|
||||||
this.governorAppealTitle = articleData.heading;
|
this.governorAppealTitle = articleData.heading;
|
||||||
this.governorAppealText = articleData.body;
|
this.governorAppealText = articleData.body;
|
||||||
|
|
||||||
const mediaRes = await fetch(
|
const mediaRes = await fetch(
|
||||||
`https://wn-ts.krbl.ru/article/${appealId}/media`,
|
`${API_URL}/article/${appealId}/media`
|
||||||
{
|
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
const mediaData = await mediaRes.json();
|
const mediaData = await mediaRes.json();
|
||||||
if (mediaData.length) {
|
if (mediaData.length) {
|
||||||
const imageRes = await fetch(
|
const imageRes = await fetch(
|
||||||
`http://31.129.106.67:8080/media/${mediaData[0].id}/download`,
|
`${API_URL}/media/${mediaData[0].id}/download`
|
||||||
{
|
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
this.governorAppealImage = await imageRes.url;
|
this.governorAppealImage = await imageRes.url;
|
||||||
} else {
|
} else {
|
||||||
@ -846,10 +830,7 @@ export default {
|
|||||||
if (!this.routeId) throw new Error("Route number not found");
|
if (!this.routeId) throw new Error("Route number not found");
|
||||||
|
|
||||||
const stopsResponse = await fetch(
|
const stopsResponse = await fetch(
|
||||||
`https://wn-ts.krbl.ru/route/${this.routeId}/station`,
|
`${API_URL}/route/${this.routeId}/station`
|
||||||
{
|
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
const stopsData = await stopsResponse.json();
|
const stopsData = await stopsResponse.json();
|
||||||
this.stations = stopsData;
|
this.stations = stopsData;
|
||||||
@ -859,22 +840,11 @@ export default {
|
|||||||
},
|
},
|
||||||
async fetchSights() {
|
async fetchSights() {
|
||||||
try {
|
try {
|
||||||
const token = this.getCookie("auth_token");
|
const response = await fetch(`${API_URL}/route/${this.routeId}/sight`);
|
||||||
const response = await fetch(
|
|
||||||
`https://wn-ts.krbl.ru/route/${this.routeId}/sight`,
|
|
||||||
{
|
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const rawSights = await response.json();
|
const rawSights = await response.json();
|
||||||
const detailedSights = await Promise.all(
|
const detailedSights = await Promise.all(
|
||||||
rawSights.map(async (sight) => {
|
rawSights.map(async (sight) => {
|
||||||
const detailRes = await fetch(
|
const detailRes = await fetch(`${API_URL}/sight/${sight.id}`);
|
||||||
`https://wn-ts.krbl.ru/sight/${sight.id}`,
|
|
||||||
{
|
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const detail = await detailRes.json();
|
const detail = await detailRes.json();
|
||||||
return { id: sight.id, name: detail.name };
|
return { id: sight.id, name: detail.name };
|
||||||
})
|
})
|
||||||
@ -886,6 +856,8 @@ export default {
|
|||||||
},
|
},
|
||||||
async toggleSights() {
|
async toggleSights() {
|
||||||
this.showGovernorAppeal = false;
|
this.showGovernorAppeal = false;
|
||||||
|
this.$emit("president-appeal-toggle", this.showGovernorAppeal);
|
||||||
|
|
||||||
if (!this.sights.length) {
|
if (!this.sights.length) {
|
||||||
await this.fetchSights();
|
await this.fetchSights();
|
||||||
}
|
}
|
||||||
@ -899,45 +871,29 @@ export default {
|
|||||||
},
|
},
|
||||||
async selectSight(sightId) {
|
async selectSight(sightId) {
|
||||||
this.selectedSightId = sightId;
|
this.selectedSightId = sightId;
|
||||||
const token = this.getCookie("auth_token");
|
|
||||||
try {
|
try {
|
||||||
const sightRes = await fetch(`https://wn-ts.krbl.ru/sight/${sightId}`, {
|
const sightRes = await fetch(`${API_URL}/sight/${sightId}`);
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
|
||||||
});
|
|
||||||
const sightData = await sightRes.json();
|
const sightData = await sightRes.json();
|
||||||
this.selectedSightName = sightData.name;
|
this.selectedSightName = sightData.name;
|
||||||
|
|
||||||
const articleId = sightData.left_article;
|
const articleId = sightData.left_article;
|
||||||
|
|
||||||
const articleRes = await fetch(
|
const articleRes = await fetch(`${API_URL}/article/${articleId}`);
|
||||||
`https://wn-ts.krbl.ru/article/${articleId}`,
|
|
||||||
{
|
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const articleData = await articleRes.json();
|
const articleData = await articleRes.json();
|
||||||
this.selectedSightText = articleData.body;
|
this.selectedSightText = articleData.body;
|
||||||
|
|
||||||
const mediaRes = await fetch(
|
const mediaRes = await fetch(`${API_URL}/article/${articleId}/media`);
|
||||||
`https://wn-ts.krbl.ru/article/${articleId}/media`,
|
|
||||||
{
|
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const mediaData = await mediaRes.json();
|
const mediaData = await mediaRes.json();
|
||||||
if (mediaData.length) {
|
if (mediaData.length) {
|
||||||
const imageRes = await fetch(
|
const imageRes = await fetch(
|
||||||
`http://31.129.106.67:8080/media/${mediaData[0].id}/download`,
|
`${API_URL}/media/${mediaData[0].id}/download`
|
||||||
{
|
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
this.selectedSightImage = await imageRes.url;
|
this.selectedSightImage = await imageRes.url;
|
||||||
this.selectedSightWatermarkLU = sightData.watermark_lu
|
this.selectedSightWatermarkLU = sightData.watermark_lu
|
||||||
? `http://31.129.106.67:8080/media/${sightData.watermark_lu}/download`
|
? `${API_URL}/media/${sightData.watermark_lu}/download`
|
||||||
: "";
|
: "";
|
||||||
this.selectedSightWatermarkRD = sightData.watermark_rd
|
this.selectedSightWatermarkRD = sightData.watermark_rd
|
||||||
? `http://31.129.106.67:8080/media/${sightData.watermark_rd}/download`
|
? `${API_URL}/media/${sightData.watermark_rd}/download`
|
||||||
: "";
|
: "";
|
||||||
} else {
|
} else {
|
||||||
this.selectedSightImage = "";
|
this.selectedSightImage = "";
|
||||||
@ -950,6 +906,8 @@ export default {
|
|||||||
},
|
},
|
||||||
async toggleList() {
|
async toggleList() {
|
||||||
this.showGovernorAppeal = false;
|
this.showGovernorAppeal = false;
|
||||||
|
this.$emit("president-appeal-toggle", this.showGovernorAppeal);
|
||||||
|
|
||||||
if (!this.stations.length) {
|
if (!this.stations.length) {
|
||||||
await this.fetchStops();
|
await this.fetchStops();
|
||||||
}
|
}
|
||||||
@ -961,6 +919,7 @@ export default {
|
|||||||
this.showSightsList = false;
|
this.showSightsList = false;
|
||||||
this.showSightPreview = false;
|
this.showSightPreview = false;
|
||||||
this.showGovernorAppeal = false;
|
this.showGovernorAppeal = false;
|
||||||
|
this.$emit("president-appeal-toggle", this.showGovernorAppeal);
|
||||||
|
|
||||||
const root = document.documentElement;
|
const root = document.documentElement;
|
||||||
root.style.setProperty(
|
root.style.setProperty(
|
||||||
@ -980,6 +939,7 @@ export default {
|
|||||||
weatherInfo?.classList.remove("shifted-left");
|
weatherInfo?.classList.remove("shifted-left");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
this.resetInactivityTimer();
|
||||||
},
|
},
|
||||||
handleClickOutside() {
|
handleClickOutside() {
|
||||||
// пупупу
|
// пупупу
|
||||||
@ -988,10 +948,28 @@ export default {
|
|||||||
console.log("Кнопка обращения губернатора нажата");
|
console.log("Кнопка обращения губернатора нажата");
|
||||||
this.showGovernorAppeal = !this.showGovernorAppeal;
|
this.showGovernorAppeal = !this.showGovernorAppeal;
|
||||||
this.showSightPreview = false;
|
this.showSightPreview = false;
|
||||||
|
|
||||||
|
this.$emit("president-appeal-toggle", this.showGovernorAppeal);
|
||||||
|
},
|
||||||
|
resetInactivityTimer() {
|
||||||
|
clearTimeout(this.inactivityTimer);
|
||||||
|
this.inactivityTimer = setTimeout(this.hidePanelIfActive, 300000); // 5m
|
||||||
|
},
|
||||||
|
hidePanelIfActive() {
|
||||||
|
if (!this.isHidden) {
|
||||||
|
this.toggleCarrierInfo();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleUserActivity() {
|
||||||
|
this.resetInactivityTimer();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
document.addEventListener("click", this.handleClickOutside);
|
document.addEventListener("click", this.handleClickOutside);
|
||||||
|
["mousemove", "touchstart", "keydown", "click"].forEach((evt) =>
|
||||||
|
document.addEventListener(evt, this.handleUserActivity)
|
||||||
|
);
|
||||||
|
this.resetInactivityTimer();
|
||||||
const root = document.documentElement;
|
const root = document.documentElement;
|
||||||
root.style.setProperty("--panel-offset", "20px");
|
root.style.setProperty("--panel-offset", "20px");
|
||||||
const routeInfo = document.querySelector(".routeinfo");
|
const routeInfo = document.querySelector(".routeinfo");
|
||||||
@ -1003,6 +981,10 @@ export default {
|
|||||||
console.log("hasGovernorAppeal в mounted:", this.hasGovernorAppeal);
|
console.log("hasGovernorAppeal в mounted:", this.hasGovernorAppeal);
|
||||||
},
|
},
|
||||||
beforeUnmount() {
|
beforeUnmount() {
|
||||||
|
["mousemove", "touchstart", "keydown", "click"].forEach((evt) =>
|
||||||
|
document.removeEventListener(evt, this.handleUserActivity)
|
||||||
|
);
|
||||||
|
clearTimeout(this.inactivityTimer);
|
||||||
document.removeEventListener("click", this.handleClickOutside);
|
document.removeEventListener("click", this.handleClickOutside);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
File diff suppressed because one or more lines are too long
@ -2,20 +2,64 @@
|
|||||||
<div class="routeinfo">
|
<div class="routeinfo">
|
||||||
<div class="route-number">{{ routeNumber }}</div>
|
<div class="route-number">{{ routeNumber }}</div>
|
||||||
<div class="route-names">
|
<div class="route-names">
|
||||||
<div class="route-name" v-if="startStopName && endStopName">
|
<!-- Russian names -->
|
||||||
|
<div class="route-name ru">
|
||||||
<div class="scroll-wrapper">
|
<div class="scroll-wrapper">
|
||||||
<div class="scroll-inner">
|
<div :class="isStartScrolling ? 'scroll-inner scrolling' : ''">
|
||||||
<div class="scroll-content">
|
<div class="scroll-content">
|
||||||
<div class="name-block">
|
<div class="name-block">
|
||||||
<span class="name">
|
<span class="name" ref="startStopRuText">
|
||||||
{{ startStopName }} — {{ endStopName }}
|
<template v-if="isStartScrolling">
|
||||||
{{ startStopName }} — {{ endStopName }}
|
{{ startStopName }}
|
||||||
{{ startStopName }} — {{ endStopName }}
|
{{ startStopName }} {{ startStopName }}
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
{{ startStopName }}
|
||||||
|
</template>
|
||||||
</span>
|
</span>
|
||||||
<span class="translate">
|
</div>
|
||||||
{{ startStopNameEn }} — {{ endStopNameEn }}
|
</div>
|
||||||
{{ startStopNameEn }} — {{ endStopNameEn }}
|
</div>
|
||||||
{{ startStopNameEn }} — {{ endStopNameEn }}
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="route-name ru">
|
||||||
|
<div class="scroll-wrapper">
|
||||||
|
<div :class="isEndScrolling ? 'scroll-inner scrolling' : ''">
|
||||||
|
<div class="scroll-content">
|
||||||
|
<div class="name-block">
|
||||||
|
<span class="name" ref="endStopRuText">
|
||||||
|
<template v-if="isEndScrolling">
|
||||||
|
{{ endStopName }}
|
||||||
|
{{ endStopName }} {{ endStopName }}
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
{{ endStopName }}
|
||||||
|
</template>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- English names -->
|
||||||
|
<div class="route-name en">
|
||||||
|
<div class="scroll-wrapper">
|
||||||
|
<div :class="isEnScrolling ? 'scroll-inner scrolling' : ''">
|
||||||
|
<div class="scroll-content">
|
||||||
|
<div class="name-block">
|
||||||
|
<span class="translate" ref="enText">
|
||||||
|
<template v-if="isEnScrolling">
|
||||||
|
{{ startStopNameEn }} —
|
||||||
|
{{ endStopNameEn }}
|
||||||
|
{{ startStopNameEn }} —
|
||||||
|
{{ endStopNameEn }}
|
||||||
|
{{ startStopNameEn }} — {{ endStopNameEn }}
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
{{ startStopNameEn }} — {{ endStopNameEn }}
|
||||||
|
</template>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -27,47 +71,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Cookies from "js-cookie";
|
import { API_URL, GEO_URL } from "../config";
|
||||||
|
|
||||||
async function requestAuth() {
|
|
||||||
const response = await fetch("https://wn-ts.krbl.ru/auth/login", {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
email: "admin",
|
|
||||||
password: "changeme",
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
Cookies.set("auth_token", data.token);
|
|
||||||
return data.token;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function checkAuth() {
|
|
||||||
const token = Cookies.get("auth_token");
|
|
||||||
try {
|
|
||||||
if (!token) {
|
|
||||||
return await requestAuth();
|
|
||||||
} else {
|
|
||||||
const response = await fetch("https://wn-ts.krbl.ru/auth/me", {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.status === 401) {
|
|
||||||
return await requestAuth();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return token;
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Auth check failed:", error);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "RouteInfo",
|
name: "RouteInfo",
|
||||||
@ -78,37 +82,36 @@ export default {
|
|||||||
endStopName: "",
|
endStopName: "",
|
||||||
startStopNameEn: "",
|
startStopNameEn: "",
|
||||||
endStopNameEn: "",
|
endStopNameEn: "",
|
||||||
|
isStartScrolling: false,
|
||||||
|
isEndScrolling: false,
|
||||||
|
isEnScrolling: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
startStopName() {
|
||||||
|
this.$nextTick(this.checkScroll);
|
||||||
|
},
|
||||||
|
endStopName() {
|
||||||
|
this.$nextTick(this.checkScroll);
|
||||||
|
},
|
||||||
|
startStopNameEn() {
|
||||||
|
this.$nextTick(this.checkScroll);
|
||||||
|
},
|
||||||
|
endStopNameEn() {
|
||||||
|
this.$nextTick(this.checkScroll);
|
||||||
|
},
|
||||||
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
const contextRes = await fetch(
|
const contextRes = await fetch(`${GEO_URL}/v1/geolocation/context`);
|
||||||
"http://31.129.106.67:6001/v1/geolocation/context"
|
|
||||||
);
|
|
||||||
const data = await contextRes.json();
|
const data = await contextRes.json();
|
||||||
this.routeNumber = data.routeNumber;
|
this.routeNumber = data.routeNumber;
|
||||||
|
|
||||||
const startStopId = data.startStopId;
|
const startStopId = data.startStopId;
|
||||||
const endStopId = data.endStopId;
|
const endStopId = data.endStopId;
|
||||||
|
|
||||||
const token = await checkAuth();
|
|
||||||
if (!token) {
|
|
||||||
console.error(
|
|
||||||
"No valid token received, skipping wn-ts.krbl.ru requests."
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const [startStopRes, endStopRes] = await Promise.all([
|
const [startStopRes, endStopRes] = await Promise.all([
|
||||||
fetch(`https://wn-ts.krbl.ru/station/${startStopId}`, {
|
fetch(`${API_URL}/station/${startStopId}`),
|
||||||
headers: {
|
fetch(`${API_URL}/station/${endStopId}`),
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
fetch(`https://wn-ts.krbl.ru/station/${endStopId}`, {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const startStopData = await startStopRes.json();
|
const startStopData = await startStopRes.json();
|
||||||
@ -118,16 +121,8 @@ export default {
|
|||||||
this.endStopName = endStopData.name;
|
this.endStopName = endStopData.name;
|
||||||
|
|
||||||
const [startStopEnRes, endStopEnRes] = await Promise.all([
|
const [startStopEnRes, endStopEnRes] = await Promise.all([
|
||||||
fetch(`https://wn-ts.krbl.ru/station/${startStopId}?lang=en`, {
|
fetch(`${API_URL}/station/${startStopId}?lang=en`),
|
||||||
headers: {
|
fetch(`${API_URL}/station/${endStopId}?lang=en`),
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
fetch(`https://wn-ts.krbl.ru/station/${endStopId}?lang=en`, {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const startStopEnData = await startStopEnRes.json();
|
const startStopEnData = await startStopEnRes.json();
|
||||||
@ -135,7 +130,45 @@ export default {
|
|||||||
|
|
||||||
this.startStopNameEn = startStopEnData.name;
|
this.startStopNameEn = startStopEnData.name;
|
||||||
this.endStopNameEn = endStopEnData.name;
|
this.endStopNameEn = endStopEnData.name;
|
||||||
|
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.checkScroll();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
checkScroll() {
|
||||||
|
const threshold = 280;
|
||||||
|
if (this.$refs.startStopRuText) {
|
||||||
|
this.isStartScrolling =
|
||||||
|
this.$refs.startStopRuText.offsetWidth > threshold;
|
||||||
|
}
|
||||||
|
if (this.$refs.endStopRuText) {
|
||||||
|
this.isEndScrolling = this.$refs.endStopRuText.offsetWidth > threshold;
|
||||||
|
}
|
||||||
|
if (this.$refs.enText) {
|
||||||
|
this.isEnScrolling = this.$refs.enText.offsetWidth > threshold;
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {},
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.route-name {
|
||||||
|
overflow: hidden;
|
||||||
|
width: 280px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-inner.scrolling {
|
||||||
|
animation: marquee 12s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes marquee {
|
||||||
|
0% {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -98,7 +98,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
<transition name="expand-collapse-transition">
|
<transition name="expand-collapse-transition">
|
||||||
<div>
|
<div class="landmarks-container">
|
||||||
<div class="landmarks" @click="toggleSightsList">
|
<div class="landmarks" @click="toggleSightsList">
|
||||||
<div class="landmarks-header">
|
<div class="landmarks-header">
|
||||||
<svg
|
<svg
|
||||||
@ -149,10 +149,7 @@
|
|||||||
:key="sight.id"
|
:key="sight.id"
|
||||||
class="sight-card"
|
class="sight-card"
|
||||||
>
|
>
|
||||||
<img
|
<img class="sight-thumbnail" :src="sight.thumbnailUrl" />
|
||||||
class="sight-thumbnail"
|
|
||||||
:src="`http://31.129.106.67:8080/media/${sight.thumbnail}/download`"
|
|
||||||
/>
|
|
||||||
<div class="sight-title">{{ sight.name }}</div>
|
<div class="sight-title">{{ sight.name }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -167,8 +164,9 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import "../assets/style/main.css";
|
import "../assets/style/main.css";
|
||||||
|
import { API_URL, GEO_URL } from "../config";
|
||||||
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import Cookies from "js-cookie";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "StopInfo",
|
name: "StopInfo",
|
||||||
@ -176,6 +174,8 @@ export default {
|
|||||||
return {
|
return {
|
||||||
isModalOpen: false,
|
isModalOpen: false,
|
||||||
autoCloseTimer: null,
|
autoCloseTimer: null,
|
||||||
|
articleInactivityTimer: null,
|
||||||
|
sightsInactivityTimer: null,
|
||||||
imageUrl: "",
|
imageUrl: "",
|
||||||
defaultImageUrl:
|
defaultImageUrl:
|
||||||
"https://lh3.googleusercontent.com/gps-cs-s/AB5caB8lUwofb2NIg6n0-cEl8nIWsySAUc52KNj4XezuOdo-aeqTgQlD1kTVa5MaynL2Yg4ByoTYTKNTR7K59f7kjzU9yzpudstjRiT2F6M_ilxFYFpcvMZz6OwlRFF2MrsCPSwUa7vqew=s680-w680-h510",
|
"https://lh3.googleusercontent.com/gps-cs-s/AB5caB8lUwofb2NIg6n0-cEl8nIWsySAUc52KNj4XezuOdo-aeqTgQlD1kTVa5MaynL2Yg4ByoTYTKNTR7K59f7kjzU9yzpudstjRiT2F6M_ilxFYFpcvMZz6OwlRFF2MrsCPSwUa7vqew=s680-w680-h510",
|
||||||
@ -246,41 +246,6 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async checkAuth() {
|
|
||||||
let token = Cookies.get("auth_token");
|
|
||||||
if (!token) {
|
|
||||||
await this.requestAuth();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
await axios.get("https://wn-ts.krbl.ru/auth/me", {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
await this.requestAuth();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async requestAuth() {
|
|
||||||
const response = await axios.post("https://wn-ts.krbl.ru/auth/login", {
|
|
||||||
email: "admin",
|
|
||||||
password: "changeme",
|
|
||||||
});
|
|
||||||
const token = response.data.token;
|
|
||||||
Cookies.set("auth_token", token);
|
|
||||||
document.cookie = `auth_token=${token}; path=/;`;
|
|
||||||
},
|
|
||||||
getCookie(name) {
|
|
||||||
const matches = document.cookie.match(
|
|
||||||
new RegExp(
|
|
||||||
"(?:^|; )" +
|
|
||||||
name.replace(/([.$?*|{}()[\]\\/+^])/g, "\\$1") +
|
|
||||||
"=([^;]*)"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
return matches ? decodeURIComponent(matches[1]) : undefined;
|
|
||||||
},
|
|
||||||
openModal() {
|
openModal() {
|
||||||
const imageDiv = this.$el.querySelector(".img");
|
const imageDiv = this.$el.querySelector(".img");
|
||||||
if (imageDiv) {
|
if (imageDiv) {
|
||||||
@ -301,74 +266,59 @@ export default {
|
|||||||
},
|
},
|
||||||
async fetchSightInfo() {
|
async fetchSightInfo() {
|
||||||
if (!this.sightId) {
|
if (!this.sightId) {
|
||||||
console.warn("No sightId provided for fetchSightInfo");
|
console.log("No sightId provided for fetchSightInfo");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const token = this.getCookie("auth_token");
|
const response = await axios.get(`${API_URL}/sight/${this.sightId}`);
|
||||||
const response = await axios.get(
|
|
||||||
`https://wn-ts.krbl.ru/sight/${this.sightId}`,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
this.stopName = response.data.name;
|
this.stopName = response.data.name;
|
||||||
this.watermarkLU = response.data.watermark_lu
|
if (response.data.watermark_lu) {
|
||||||
? `http://31.129.106.67:8080/media/${response.data.watermark_lu}/download`
|
this.watermarkLU = await this.getMediaBlobUrl(
|
||||||
: "";
|
response.data.watermark_lu
|
||||||
this.watermarkRD = response.data.watermark_rd
|
);
|
||||||
? `http://31.129.106.67:8080/media/${response.data.watermark_rd}/download`
|
} else {
|
||||||
: "";
|
this.watermarkLU = "";
|
||||||
|
}
|
||||||
|
if (response.data.watermark_rd) {
|
||||||
|
this.watermarkRD = await this.getMediaBlobUrl(
|
||||||
|
response.data.watermark_rd
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.watermarkRD = "";
|
||||||
|
}
|
||||||
},
|
},
|
||||||
async fetchArticles() {
|
async fetchArticles() {
|
||||||
if (!this.sightId) {
|
if (!this.sightId) {
|
||||||
console.warn("No sightId provided for fetchArticles");
|
console.warn("No sightId provided for fetchArticles");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const token = this.getCookie("auth_token");
|
|
||||||
const response = await axios.get(
|
const response = await axios.get(
|
||||||
`https://wn-ts.krbl.ru/sight/${this.sightId}/article`,
|
`${API_URL}/sight/${this.sightId}/article`
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
this.articles = response.data;
|
this.articles = response.data;
|
||||||
if (this.articles.length > 0) {
|
if (this.articles.length > 0) {
|
||||||
this.selectArticle(this.articles[0].id);
|
this.selectArticle(this.articles[0].id);
|
||||||
|
this.resetArticleInactivityTimer();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async fetchSights() {
|
async fetchSights() {
|
||||||
const token = this.getCookie("auth_token");
|
const geoRes = await axios.get(`${GEO_URL}/v1/geolocation/context`);
|
||||||
const geoRes = await axios.get(
|
|
||||||
"http://31.129.106.67:6001/v1/geolocation/context"
|
|
||||||
);
|
|
||||||
const routeId = geoRes.data.routeId;
|
const routeId = geoRes.data.routeId;
|
||||||
if (!routeId) {
|
if (!routeId) {
|
||||||
console.warn("Missing routeId in geo context:", geoRes.data);
|
console.warn("Missing routeId in geo context:", geoRes.data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const sightsRes = await axios.get(
|
const sightsRes = await axios.get(`${API_URL}/route/${routeId}/sight`);
|
||||||
`https://wn-ts.krbl.ru/route/${routeId}/sight`,
|
|
||||||
{
|
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const rawSights = sightsRes.data;
|
const rawSights = sightsRes.data;
|
||||||
const detailedSights = await Promise.all(
|
const detailedSights = await Promise.all(
|
||||||
rawSights.map(async (sight) => {
|
rawSights.map(async (sight) => {
|
||||||
const detailRes = await axios.get(
|
const detailRes = await axios.get(`${API_URL}/sight/${sight.id}`);
|
||||||
`https://wn-ts.krbl.ru/sight/${sight.id}`,
|
const thumbnailUrl = detailRes.data.thumbnail
|
||||||
{
|
? await this.getMediaBlobUrl(detailRes.data.thumbnail)
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
: "";
|
||||||
}
|
|
||||||
);
|
|
||||||
return {
|
return {
|
||||||
id: sight.id,
|
id: sight.id,
|
||||||
name: detailRes.data.name,
|
name: detailRes.data.name,
|
||||||
thumbnail: detailRes.data.thumbnail,
|
thumbnailUrl,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -376,27 +326,63 @@ export default {
|
|||||||
},
|
},
|
||||||
toggleSightsList() {
|
toggleSightsList() {
|
||||||
this.showSightsList = !this.showSightsList;
|
this.showSightsList = !this.showSightsList;
|
||||||
|
if (this.showSightsList) {
|
||||||
|
this.resetSightsInactivityTimer();
|
||||||
|
} else if (this.sightsInactivityTimer) {
|
||||||
|
clearTimeout(this.sightsInactivityTimer);
|
||||||
|
this.sightsInactivityTimer = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resetSightsInactivityTimer() {
|
||||||
|
if (this.articleInactivityTimer) {
|
||||||
|
clearTimeout(this.articleInactivityTimer);
|
||||||
|
}
|
||||||
|
if (this.sightsInactivityTimer) {
|
||||||
|
clearTimeout(this.sightsInactivityTimer);
|
||||||
|
}
|
||||||
|
if (this.showSightsList) {
|
||||||
|
this.sightsInactivityTimer = setTimeout(() => {
|
||||||
|
this.showSightsList = false;
|
||||||
|
this.sightsInactivityTimer = null;
|
||||||
|
}, 300000); // 5 m
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resetArticleInactivityTimer() {
|
||||||
|
if (this.articleInactivityTimer)
|
||||||
|
clearTimeout(this.articleInactivityTimer);
|
||||||
|
|
||||||
|
this.articleInactivityTimer = setTimeout(() => {
|
||||||
|
if (
|
||||||
|
this.articles.length > 0 &&
|
||||||
|
this.selectedArticleId !== this.articles[0].id
|
||||||
|
) {
|
||||||
|
this.selectArticle(this.articles[0].id);
|
||||||
|
}
|
||||||
|
}, 300_000); // 5 m
|
||||||
|
},
|
||||||
|
handleUserActivity() {
|
||||||
|
if (this.showSightsList) this.resetSightsInactivityTimer();
|
||||||
|
this.resetArticleInactivityTimer();
|
||||||
},
|
},
|
||||||
selectArticle(id) {
|
selectArticle(id) {
|
||||||
|
this.resetArticleInactivityTimer();
|
||||||
this.selectedArticleId = id;
|
this.selectedArticleId = id;
|
||||||
const selected = this.articles.find((article) => article.id === id);
|
const selected = this.articles.find((article) => article.id === id);
|
||||||
this.selectedArticleBody = selected ? selected.body : "";
|
this.selectedArticleBody = selected ? selected.body : "";
|
||||||
this.fetchArticleMedia(id);
|
this.fetchArticleMedia(id);
|
||||||
},
|
},
|
||||||
async fetchArticleMedia(articleId) {
|
async fetchArticleMedia(articleId) {
|
||||||
const token = this.getCookie("auth_token");
|
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await axios.get(
|
||||||
`https://wn-ts.krbl.ru/article/${articleId}/media`,
|
`${API_URL}/article/${articleId}/media`
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
if (response.data && response.data.length > 0) {
|
if (response.data && response.data.length > 0) {
|
||||||
const mediaId = response.data[0].id;
|
const mediaId = response.data[0].id;
|
||||||
this.imageUrl = `http://31.129.106.67:8080/media/${mediaId}/download`;
|
try {
|
||||||
|
this.imageUrl = await this.getMediaBlobUrl(mediaId);
|
||||||
|
} catch {
|
||||||
|
this.imageUrl = `${API_URL}/media/${mediaId}/download`;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.imageUrl = "";
|
this.imageUrl = "";
|
||||||
}
|
}
|
||||||
@ -405,39 +391,60 @@ export default {
|
|||||||
this.imageUrl = "";
|
this.imageUrl = "";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async fetchGeolocationContext() {
|
|
||||||
|
async getMediaBlobUrl(mediaId) {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await axios.get(
|
||||||
"http://31.129.106.67:6001/v1/geolocation/context"
|
`${API_URL}/media/${mediaId}/download`,
|
||||||
);
|
|
||||||
this.routeProgress = response.data.routeProgress;
|
|
||||||
console.log("Updated routeProgress:", this.routeProgress);
|
|
||||||
const token = this.getCookie("auth_token");
|
|
||||||
const stopsResponse = await axios.get(
|
|
||||||
`https://wn-ts.krbl.ru/route/${response.data.routeId}/station`,
|
|
||||||
{
|
{
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
responseType: "blob",
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
return URL.createObjectURL(response.data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(
|
||||||
|
`Failed to download media ${mediaId}:`,
|
||||||
|
error?.response?.status,
|
||||||
|
error?.response?.data || error.message
|
||||||
|
);
|
||||||
|
return `${API_URL}/media/${mediaId}/download`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async fetchGeolocationContext() {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`${GEO_URL}/v1/geolocation/context`);
|
||||||
|
this.routeProgress = response.data.routeProgress;
|
||||||
|
const stopsResponse = await axios.get(
|
||||||
|
`${API_URL}/route/${response.data.routeId}/station`
|
||||||
|
);
|
||||||
this.stops = stopsResponse.data;
|
this.stops = stopsResponse.data;
|
||||||
const newSightId = response.data.nearestSightId;
|
let newSightId = response.data.nearestSightId;
|
||||||
|
|
||||||
|
if (!newSightId) {
|
||||||
|
if (!this.sights || this.sights.length === 0) {
|
||||||
|
await this.fetchSights();
|
||||||
|
}
|
||||||
|
if (this.sights && this.sights.length > 0) {
|
||||||
|
newSightId = this.sights[1].id;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (newSightId && newSightId !== this.sightId) {
|
if (newSightId && newSightId !== this.sightId) {
|
||||||
this.sightId = newSightId;
|
this.sightId = newSightId;
|
||||||
await this.fetchSightInfo();
|
await this.fetchSightInfo();
|
||||||
await this.fetchArticles();
|
await this.fetchArticles();
|
||||||
}
|
}
|
||||||
const nextStopId = response.data.routeProgress?.endStopId;
|
const nextStopId = response.data.routeProgress?.endStopId;
|
||||||
console.log("Fetched next stop ID:", nextStopId);
|
// console.log("Fetched next stop ID:", nextStopId);
|
||||||
console.log("Stops:", this.stops);
|
// console.log("Stops:", this.stops);
|
||||||
if (nextStopId && this.stops) {
|
if (nextStopId && this.stops) {
|
||||||
const nextStop = this.stops.find((stop) => stop.id == nextStopId);
|
const nextStop = this.stops.find((stop) => stop.id == nextStopId);
|
||||||
console.log("Fetched next stop ID:", nextStopId);
|
// console.log("Fetched next stop ID:", nextStopId);
|
||||||
console.log("Matching stop:", nextStop);
|
// console.log("Matching stop:", nextStop);
|
||||||
if (nextStop && nextStop.transfers) {
|
if (nextStop && nextStop.transfers) {
|
||||||
console.log("Transfers at next stop:", nextStop.transfers);
|
// console.log("Transfers at next stop:", nextStop.transfers);
|
||||||
this.nextStopTransfers = nextStop.transfers;
|
this.nextStopTransfers = nextStop.transfers;
|
||||||
} else {
|
} else {
|
||||||
console.log("No transfers found at next stop");
|
// console.log("No transfers found at next stop");
|
||||||
this.nextStopTransfers = null;
|
this.nextStopTransfers = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -456,7 +463,7 @@ export default {
|
|||||||
toggleTransfers() {
|
toggleTransfers() {
|
||||||
console.log("Transfer toggle clicked");
|
console.log("Transfer toggle clicked");
|
||||||
this.showTransfers = !this.showTransfers;
|
this.showTransfers = !this.showTransfers;
|
||||||
console.log("showTransfers:", this.showTransfers);
|
// console.log("showTransfers:", this.showTransfers);
|
||||||
|
|
||||||
if (!this.showTransfers) {
|
if (!this.showTransfers) {
|
||||||
return;
|
return;
|
||||||
@ -468,32 +475,46 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const nextStopId = this.routeProgress.endStopId;
|
const nextStopId = this.routeProgress.endStopId;
|
||||||
console.log("Next stop ID from routeProgress:", nextStopId);
|
// console.log("Next stop ID from routeProgress:", nextStopId);
|
||||||
console.log("All stops:", this.stops);
|
// console.log("All stops:", this.stops);
|
||||||
|
|
||||||
const nextStop = this.stops.find((stop) => stop.id === nextStopId);
|
const nextStop = this.stops.find((stop) => stop.id === nextStopId);
|
||||||
console.log("Next stop object:", nextStop);
|
// console.log("Next stop object:", nextStop);
|
||||||
|
|
||||||
if (nextStop && nextStop.transfers) {
|
if (nextStop && nextStop.transfers) {
|
||||||
console.log("Transfers at next stop:", nextStop.transfers);
|
// console.log("Transfers at next stop:", nextStop.transfers);
|
||||||
this.nextStopTransfers = nextStop.transfers;
|
this.nextStopTransfers = nextStop.transfers;
|
||||||
} else {
|
} else {
|
||||||
console.log("No transfers found at next stop");
|
// console.log("No transfers found at next stop");
|
||||||
this.nextStopTransfers = null;
|
this.nextStopTransfers = null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
await this.checkAuth();
|
|
||||||
await this.fetchGeolocationContext();
|
|
||||||
await this.fetchSights();
|
await this.fetchSights();
|
||||||
|
await this.fetchGeolocationContext();
|
||||||
this.geolocationInterval = setInterval(() => {
|
this.geolocationInterval = setInterval(() => {
|
||||||
this.fetchGeolocationContext();
|
this.fetchGeolocationContext();
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
window.addEventListener("mousemove", this.handleUserActivity);
|
||||||
|
window.addEventListener("touchstart", this.handleUserActivity, {
|
||||||
|
passive: true,
|
||||||
|
});
|
||||||
|
window.addEventListener("keydown", this.handleUserActivity);
|
||||||
|
window.addEventListener("click", this.handleUserActivity, true);
|
||||||
// this.fetchSightInfo();
|
// this.fetchSightInfo();
|
||||||
// this.fetchArticles();
|
// this.fetchArticles();
|
||||||
},
|
},
|
||||||
unmounted() {
|
unmounted() {
|
||||||
|
if (this.sightsInactivityTimer) {
|
||||||
|
clearTimeout(this.sightsInactivityTimer);
|
||||||
|
}
|
||||||
|
window.removeEventListener("mousemove", this.handleUserActivity);
|
||||||
|
window.removeEventListener("touchstart", this.handleUserActivity, {
|
||||||
|
passive: true,
|
||||||
|
});
|
||||||
|
window.removeEventListener("keydown", this.handleUserActivity);
|
||||||
|
window.removeEventListener("click", this.handleUserActivity, true);
|
||||||
if (this.autoCloseTimer) {
|
if (this.autoCloseTimer) {
|
||||||
clearTimeout(this.autoCloseTimer);
|
clearTimeout(this.autoCloseTimer);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="weatherinfo">
|
<div class="weatherinfo" :class="{ hidden: isPresidentAddressOpen }">
|
||||||
<div class="time">{{ formattedTime }}</div>
|
<div class="time">{{ formattedTime }}</div>
|
||||||
<div class="date">{{ formattedDate }}, {{ dayOfWeek }}</div>
|
<div class="date">{{ formattedDate }}, {{ dayOfWeek }}</div>
|
||||||
|
|
||||||
@ -10,7 +10,7 @@
|
|||||||
alt="Weather Icon"
|
alt="Weather Icon"
|
||||||
/>
|
/>
|
||||||
<div class="temperature-celsius">
|
<div class="temperature-celsius">
|
||||||
{{ currentWeather.temperatureCelsius }}°C
|
{{ currentWeather.temperatureCelsius }}°
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{{ currentWeather.description }}
|
{{ currentWeather.description }}
|
||||||
@ -27,8 +27,8 @@
|
|||||||
<div class="humidity">
|
<div class="humidity">
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="12"
|
width="13"
|
||||||
height="16"
|
height="18"
|
||||||
fill="none"
|
fill="none"
|
||||||
viewBox="0 0 12 16"
|
viewBox="0 0 12 16"
|
||||||
>
|
>
|
||||||
@ -43,8 +43,8 @@
|
|||||||
<div class="wind">
|
<div class="wind">
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="16"
|
width="18"
|
||||||
height="16"
|
height="18"
|
||||||
fill="none"
|
fill="none"
|
||||||
viewBox="0 0 16 16"
|
viewBox="0 0 16 16"
|
||||||
>
|
>
|
||||||
@ -72,8 +72,9 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import "../assets/style/main.css";
|
import "../assets/style/main.css";
|
||||||
|
import { API_URL } from "../config";
|
||||||
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import Cookies from "js-cookie";
|
|
||||||
import clearIcon from "@/icons/clear-day.svg";
|
import clearIcon from "@/icons/clear-day.svg";
|
||||||
import cloudsIcon from "@/icons/cloudy.svg";
|
import cloudsIcon from "@/icons/cloudy.svg";
|
||||||
import rainIcon from "@/icons/rainy.svg";
|
import rainIcon from "@/icons/rainy.svg";
|
||||||
@ -84,6 +85,12 @@ import fogIcon from "@/icons/fog.svg";
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "WeatherInfo",
|
name: "WeatherInfo",
|
||||||
|
props: {
|
||||||
|
isPresidentAddressOpen: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isModalOpen: false,
|
isModalOpen: false,
|
||||||
@ -101,55 +108,24 @@ export default {
|
|||||||
dayOfWeek: "",
|
dayOfWeek: "",
|
||||||
timerInterval: null,
|
timerInterval: null,
|
||||||
weatherDescriptionMap: {
|
weatherDescriptionMap: {
|
||||||
thunderstorm: "Гроза",
|
thunderstorm: "гроза",
|
||||||
drizzle: "Слабый дождь",
|
drizzle: "слабый дождь",
|
||||||
rain: "Дождь",
|
rain: "дождь",
|
||||||
snow: "Снег",
|
snow: "снег",
|
||||||
atmosphere: "Туман",
|
atmosphere: "туман",
|
||||||
clear: "Ясно",
|
clear: "ясно",
|
||||||
clouds: "Облачно",
|
clouds: "облачно",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async getToken() {
|
|
||||||
let token = Cookies.get("auth_token");
|
|
||||||
try {
|
|
||||||
await axios.get("https://wn-ts.krbl.ru/auth/me", {
|
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
if (error.response && error.response.status === 401) {
|
|
||||||
const response = await axios.post(
|
|
||||||
"https://wn-ts.krbl.ru/auth/login",
|
|
||||||
{
|
|
||||||
email: "admin",
|
|
||||||
password: "changeme",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
token = response.data.token;
|
|
||||||
Cookies.set("auth_token", token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return token;
|
|
||||||
},
|
|
||||||
async fetchSightInfo() {
|
async fetchSightInfo() {
|
||||||
const token = await this.getToken();
|
const response = await axios.get(`${API_URL}/sight/${this.sightId}`);
|
||||||
const response = await axios.get(
|
|
||||||
`https://wn-ts.krbl.ru/sight/${this.sightId}`,
|
|
||||||
{
|
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
|
||||||
}
|
|
||||||
);
|
|
||||||
this.stopName = response.data.name;
|
this.stopName = response.data.name;
|
||||||
},
|
},
|
||||||
async fetchArticles() {
|
async fetchArticles() {
|
||||||
const token = await this.getToken();
|
|
||||||
const response = await axios.get(
|
const response = await axios.get(
|
||||||
`https://wn-ts.krbl.ru/sight/${this.sightId}/article`,
|
`${API_URL}/sight/${this.sightId}/article`
|
||||||
{
|
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
this.articles = response.data;
|
this.articles = response.data;
|
||||||
if (this.articles.length > 0) {
|
if (this.articles.length > 0) {
|
||||||
|
2
src/config.js
Normal file
2
src/config.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export const API_URL = process.env.VUE_APP_API_URL;
|
||||||
|
export const GEO_URL = process.env.VUE_APP_GEO_URL;
|
35
src/icons/tram-bottom-left.svg
Normal file
35
src/icons/tram-bottom-left.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 63 KiB |
35
src/icons/tram-bottom-right.svg
Normal file
35
src/icons/tram-bottom-right.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 63 KiB |
35
src/icons/tram-left.svg
Normal file
35
src/icons/tram-left.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 63 KiB |
35
src/icons/tram-right.svg
Normal file
35
src/icons/tram-right.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 63 KiB |
35
src/icons/tram-top-left.svg
Normal file
35
src/icons/tram-top-left.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 63 KiB |
35
src/icons/tram-top-right.svg
Normal file
35
src/icons/tram-top-right.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 63 KiB |
Loading…
Reference in New Issue
Block a user