Агаев Даниэл Сейранович 3 年之前
當前提交
bef6630f76
共有 11 個文件被更改,包括 541 次插入0 次删除
  1. 8 0
      .idea/.gitignore
  2. 8 0
      .idea/4.iml
  3. 8 0
      .idea/modules.xml
  4. 169 0
      css/style.css
  5. 26 0
      index.html
  6. 79 0
      js/components/Home.js
  7. 87 0
      js/components/LoginForm.js
  8. 38 0
      js/components/Templates.js
  9. 42 0
      js/libs/helper.js
  10. 55 0
      js/libs/router.js
  11. 21 0
      js/main.js

+ 8 - 0
.idea/.gitignore

@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml

+ 8 - 0
.idea/4.iml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="WEB_MODULE" version="4">
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/4.iml" filepath="$PROJECT_DIR$/.idea/4.iml" />
+    </modules>
+  </component>
+</project>

+ 169 - 0
css/style.css

@@ -0,0 +1,169 @@
+ * {
+     font-family: Bahnschrift, sans-serif;
+ }
+
+ main {
+     display: flex;
+     width: 100%;
+     gap: 1rem;
+ }
+
+ #app {
+     display: flex;
+     flex: 90%;
+     flex-direction: column;
+     gap: 1rem;
+     overflow: hidden;
+     padding: 10vh;
+ }
+
+
+ router-link {
+     cursor: pointer;
+     font-family: Bahnschrift, sans-serif;
+     color: #252525;
+     padding: 1vh;
+     min-width: 100px;
+     transition: .2s;
+     text-align: center;
+     display: flex;
+     align-items: center;
+     justify-content: center;
+     border: #252525 1px solid;
+     position: relative;
+     overflow: hidden;
+     z-index: 0;
+ }
+
+
+ router-link::before {
+     content: "";
+     position: absolute;
+     width: 110px;
+     height: 110px;
+     border-radius: 50%;
+     top: -3vh;
+     left: -1vw;
+     transform: scale(0);
+     background: #0080ff;
+     transition: .4s;
+     z-index:-1;
+ }
+ router-link:hover::before {
+     transform: scale(2);
+ }
+
+
+ router-link:hover {
+     color: #eeeeee;
+ }
+
+ #header {
+     display: flex;
+ }
+
+ .message {
+     padding: 1vh;
+     color: white;
+     margin-bottom: 2vh;
+ }
+
+ input {
+     font-size: 20px;
+ }
+
+ .button {
+     width: 100px;
+     height: 100px;
+     padding: 1vh;
+     background: #0080ff;
+     color: white;
+     text-decoration: none;
+     cursor: pointer;
+ }
+
+ /* Basic Card */
+ .basic-card {
+     width: 100vw;
+     position: relative;
+     overflow: hidden;
+     padding: 1vh;
+ }
+
+ .basic-card .card-content {
+     padding: 10px;
+ }
+
+ .basic-card .card-title {
+     font-size: 15px;
+     font-family: 'Open Sans', sans-serif;
+ }
+
+ .basic-card .card-text {
+     line-height: 1.6;
+ }
+
+ .basic-card .card-link {
+     padding: 15px;
+     width: -webkit-fill-available;
+ }
+
+ .basic-card .card-link a {
+     text-decoration: none;
+     position: relative;
+     padding: 10px 0px;
+ }
+
+ .basic-card .card-link a:after {
+     top: 30px;
+     content: "";
+     display: block;
+     height: 2px;
+     left: 50%;
+     position: absolute;
+     width: 0;
+
+
+ }
+
+ .basic-card .card-link a:hover:after {
+     width: 100%;
+     left: 0;
+ }
+
+ .basic-card-aqua {
+     position: relative;
+     overflow: hidden;
+ }
+
+ .basic-card-aqua::before {
+     background-image: linear-gradient(to bottom right, #26313c, #0080ff);
+     content: "";
+     position: absolute;
+     width: 90vh;
+     height: 90vh;
+
+     z-index: -1;
+ }
+
+ .basic-card-aqua .card-content, .basic-card .card-link a {
+     color: #fff;
+ }
+
+ .basic-card-aqua .card-link {
+     border-top: 1px solid #82c1bb;
+ }
+
+ .basic-card-aqua .card-link a:after {
+     background: #fff;
+ }
+
+ .disabled {
+     pointer-events: none;
+     cursor: default;
+     background: #eeeeee;
+     color: #252525;
+ }
+ .disabled-block {
+     display: none;
+ }

+ 26 - 0
index.html

@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Title</title>
+    <link rel="stylesheet" href="css/style.css">
+    <script defer type="module" src="js/libs/router.js"></script>
+    <script defer type="module" src="js/main.js"></script>
+
+</head>
+<body>
+<div id="app">
+    <div id="header">
+        <router-link to="/login">Вход</router-link>
+        <router-link to="/home">Домашний экран</router-link>
+        <router-link to="/user">Личный кабинет</router-link>
+    </div>
+
+    <hr>
+
+    <router-view></router-view>
+
+</div>
+
+</body>
+</html>

+ 79 - 0
js/components/Home.js

@@ -0,0 +1,79 @@
+import {getTemplateUsers} from "./Templates.js";
+import {bindEvents, dEvent} from "../libs/helper.js";
+import {f} from "../libs/helper.js"
+
+export default class Home extends HTMLElement {
+    constructor() {
+        super();
+        this.user = null;
+        this.registrations = null;
+        this.bind();
+        this.rendered = false;
+        this.data = {
+            service: null
+        }
+    }
+
+    connectedCallback() {
+        if (!this.rendered) {
+            this.render();
+        }
+    }
+
+    bind() {
+        bindEvents("UserHomeLogin", "user-login", (e) => {
+            this.user = e.detail;
+            this.render();
+        })
+        bindEvents("UserHomeOut", "user-logout", (e) => {
+            this.user = null;
+        })
+    }
+
+    async render() {
+        if (!this.user) return;
+        this.rendered = true;
+        let res = (await f("service", "get", this.user.user_token)).data;
+        console.log(res)
+
+        this.registrations = res;
+        for (let reg of this.registrations) {
+            console.log(reg)
+            this.innerHTML +=(getTemplateUsers(reg))
+        }
+        this.attachModel();
+    }
+
+    attachModel() {
+        this.querySelectorAll('.button')
+            .forEach(el=>el.addEventListener('click', e => this.clickButton(e)))
+    }
+
+    clickButton(e) {
+        if (this[e.target.dataset.click]) {
+            this[e.target.dataset.click](e);
+        }
+    }
+
+    async register(e) {
+        this.data.service = e.target.dataset.service
+        let res = await f("servicerecord","post", this.user.user_token,this.data)
+
+        console.log(res)
+        e.target.innerHTML = "Записано"
+        e.target.classList.add("disabled")
+    }
+
+    async restore(e) {
+        let id = e.target.dataset.id;
+        let res = await f(`service/${id}`,"delete", this.user.user_token,null);
+        console.log(res)
+
+
+        let el = document.getElementById(id);
+
+        el.classList.add("disabled-block");
+    }
+
+
+}

+ 87 - 0
js/components/LoginForm.js

@@ -0,0 +1,87 @@
+import {getTemplateLogin} from "./Templates.js";
+import {getTemplateOut} from "./Templates.js";
+import {bindEvents, dEvent} from "../libs/helper.js";
+import {f} from "../libs/helper.js"
+
+export default class LoginForm extends HTMLElement {
+    constructor() {
+        super();
+        this.user= null;
+        this.data = {
+            login: "",
+            password: ""
+        }
+        this.bind();
+    }
+
+    connectedCallback() {
+        if (!this.user) {
+            this.render(getTemplateLogin());
+        }
+    }
+
+    render(template) {
+        this.innerHTML = template;
+        this.attachModel();
+    }
+
+    bind() {
+        bindEvents("LoginFormLogin", "user-login", (e)=> {
+            this.user = e.detail;
+            this.render(getTemplateOut(this.user.login));
+        })
+
+        bindEvents("LoginFormOut", "user-logout", (e)=> {
+            this.render(getTemplateLogin());
+        })
+    }
+
+    attachModel() {
+        this.querySelectorAll("input")
+            .forEach(el=>el.addEventListener("input",e =>this.inputText(e)))
+        this.querySelector('.button')
+            .addEventListener('click', e => this.clickButton(e));
+        // this.querySelectorAll("input")
+        //     .forEach(el=>bindEvents("inputs","input", (el)=> {this.inputText(el)}))
+        // this.querySelectorAll(".button")
+        //     .forEach(el=>bindEvents(el.innerHTML,"click", (el)=> {this.clickButton(el)}))
+    }
+
+    inputText(e) {
+        if (this.data[e.target.dataset.model] !== undefined) {
+            this.data[e.target.dataset.model] = e.target.value;
+        }
+    }
+
+    clickButton(e) {
+        if (this[e.target.dataset.click]) {
+            this[e.target.dataset.click]();
+        }
+    }
+
+    async login() {
+        if (!this.data.login || !this.data.password) return;
+        let res = await f("api-token-auth", "post", null, this.data)
+        console.log(res);
+
+        if (res.error) {
+            this.querySelector('.message').innerHTML = 'Не правильный логин или пароль';
+            this.querySelector('.message').innerHTML+=`<style>.message {background:crimson}</style>`
+            return;
+        }
+
+        dEvent("user-login",{login:this.data.login, user_token:res.data.user_token, role: "admin"});
+
+    }
+
+    async logout() {
+        console.log("work")
+        if (!this.user) return;
+        let res = await f('api-token-logout', 'get', this.user.user_token, null);
+        console.log(res)
+        if (!res.error) {
+            dEvent('user-logout');
+        }
+    }
+
+}

+ 38 - 0
js/components/Templates.js

@@ -0,0 +1,38 @@
+export function getTemplateLogin() {
+    return `
+        <h3>Вход</h3>
+        <div class="message"></div>
+        <label>Логин: <input type="text" data-model="login"></label>
+        <label>Пароль: <input type="text" data-model="password"></label>
+         <a data-click="login" class="button">Вход</a>
+        `
+}
+
+export function getTemplateOut(user) {
+    return `
+        <h3>Вы вошли как ${user}</h3>
+        <div class="message"></div>
+        <a data-click="logout" class="button">Выход</a>
+        `
+}
+
+
+export function getTemplateUsers(registration) {
+    return `
+           <div class="basic-card basic-card-aqua" id="${registration.id}">
+                <div class="card-content">
+                    <span class="card-title"><h3>ID:${registration.id}</h3></span>
+                    <p class="card-text">
+                       Url: ${registration.url}, Service: ${registration.name}, Description: ${registration.description}
+                       City: ${registration.position}
+                       
+                       <div class="buttons">
+                       <a class="button" data-click="register" data-service="${registration.name}">Записаться на услугу</a>   
+                       <a class="button" data-click="put" data-id="${registration.id}" style="background: dodgerblue; color: white">Редактировать услугу</a>     
+                       <a class="button" data-click="restore" data-id="${registration.id}" style="background: firebrick; color: white">Удалить услугу</a>     
+                        </div>
+                    </p>
+                </div>
+                </div>
+            `;
+}

+ 42 - 0
js/libs/helper.js

@@ -0,0 +1,42 @@
+
+let host = "http://localhost/api-wash";
+
+let f = async (url, method="get", token=false, data=[]) => {
+    let options = {
+        method: method.toUpperCase(),
+        headers: {
+            "Content-type": "application/json"
+        }
+    }
+
+    if (token) {
+        options.headers["Authorization"] = `Bearer ${token}`
+    }
+
+    if (["post", "patch", "put"].includes(method)) {
+        options.body = JSON.stringify(data)
+    }
+    return await fetch(`${host}/${url}`, options).then(res=>res.json());
+}
+
+const dEvent = (event, detail, el) => {
+    if (!el) {
+        document.dispatchEvent(new CustomEvent(
+            event, {detail:detail}
+        ))
+    } else {
+        el.dispatchEvent(new CustomEvent(
+            event, {detail:detail}
+        ))
+    }
+}
+
+const bindEvents = (name, type, callback ) => {
+    console.log("BIND EVENT - " + name)
+    document.addEventListener(type,(e) => {
+       callback(e);
+    })
+}
+
+
+export {f, dEvent, bindEvents}

+ 55 - 0
js/libs/router.js

@@ -0,0 +1,55 @@
+import {dEvent} from "./helper.js";
+
+export default class Router {
+    constructor(settings) {
+        this.routes = settings.routes;
+        for (let i = 0; i < this.routes.length;i++) {
+            if (!this.routes[i].element) {
+                const elementName = "template-" +this.routes[i].component.name.toLowerCase();
+                if (!customElements.get(elementName)) customElements.define(elementName, this.routes[i].component);
+                this.routes[i].element = document.createElement(elementName);
+                console.log("CREATE " + elementName);
+            }
+        }
+        this.link = settings.link || "router-link";
+        this.view = settings.view || "router-view";
+        this.home = window.location.toString();
+        customElements.define(this.link, RouterLink);
+        customElements.define(this.view, RouterView);
+        this.bindEvents();
+    }
+    bindEvents() {
+        document.addEventListener("router-click", (e)=> {
+            let route = this.routes.find(route=>route.path === e.detail);
+            if (!route) return;
+            window.history.pushState({},e.path,this.home+String(e.detail));
+            let el = document.querySelector(this.view);
+            dEvent("router-view", route.element, el);
+        })
+    }
+}
+
+class RouterView extends HTMLElement {
+    connectedCallback() {
+        this.bindEvents()
+    }
+    bindEvents() {
+        this.addEventListener("router-view",(e) => {
+            this.innerHTML ="";
+            this.append(e.detail);
+        })
+    }
+
+}
+
+class RouterLink extends HTMLElement {
+    constructor() {
+        super();
+        this.bindEvents()
+    }
+    bindEvents() {
+        this.addEventListener("click",() => {
+            dEvent("router-click", this.getAttribute("to"))
+        })
+    }
+}

+ 21 - 0
js/main.js

@@ -0,0 +1,21 @@
+import {dEvent} from "./libs/helper.js";
+import {f} from "./libs/helper.js";
+import Router from "./libs/router.js";
+import LoginForm from "./components/LoginForm.js";
+import Home from "./components/Home.js";
+
+
+class App {
+
+}
+
+const routes = [
+    {path:"/login", component: LoginForm, name: "Войти"},
+    {path:"/home", component: Home, name: "Домашняя страница"},
+]
+
+const router = new Router(
+    {routes}
+)
+
+new App();